1 /* Functions for GUI implemented with (HI)Toolbox on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
25 #include "blockinput.h"
29 #if !TARGET_API_MAC_CARBON
30 #include <Quickdraw.h>
31 #include <ToolUtils.h>
35 #include <Resources.h>
37 #include <TextUtils.h>
42 #if defined (__MRC__) || (__MSL__ >= 0x6000)
43 #include <ControlDefinitions.h>
49 #endif /* not TARGET_API_MAC_CARBON */
54 #include "dispextern.h"
56 #include "termhooks.h"
61 #include <sys/param.h>
68 /************************************************************************
70 ************************************************************************/
72 /* The difference in pixels between the top left corner of the
73 Emacs window (including possible window manager decorations)
74 and FRAME_MAC_WINDOW (f). */
75 #define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff)
76 #define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff)
78 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
81 mac_alert_sound_play ()
83 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
91 /************************************************************************
93 ************************************************************************/
95 extern struct frame
*mac_focus_frame
P_ ((struct mac_display_info
*));
96 extern void do_keystroke
P_ ((EventKind
, unsigned char, UInt32
, UInt32
,
97 unsigned long, struct input_event
*));
98 extern UInt32 mac_mapped_modifiers
P_ ((UInt32
, UInt32
));
99 #if TARGET_API_MAC_CARBON
100 extern int mac_to_emacs_modifiers
P_ ((UInt32
, UInt32
));
102 extern int mac_to_emacs_modifiers
P_ ((EventModifiers
, EventModifiers
));
105 #if TARGET_API_MAC_CARBON
106 /* Points to the variable `inev' in the function XTread_socket. It is
107 used for passing an input event to the function back from
108 Carbon/Apple event handlers. */
109 static struct input_event
*read_socket_inev
= NULL
;
111 extern const unsigned char keycode_to_xkeysym_table
[];
112 extern EMACS_INT extra_keyboard_modifiers
;
114 extern Lisp_Object Qhi_command
;
116 static TSMDocumentID tsm_document_id
;
117 extern Lisp_Object Qtext_input
;
118 extern Lisp_Object Qupdate_active_input_area
, Qunicode_for_key_event
;
119 extern Lisp_Object Vmac_ts_active_input_overlay
, Vmac_ts_active_input_buf
;
120 extern Lisp_Object Qbefore_string
;
123 static int mac_event_to_emacs_modifiers
P_ ((EventRef
));
124 static OSStatus install_menu_target_item_handler
P_ ((void));
126 static OSStatus install_service_handler
P_ ((void));
129 extern OSStatus mac_store_event_ref_as_apple_event
P_ ((AEEventClass
, AEEventID
,
133 const EventParamName
*,
134 const EventParamType
*));
135 extern int fast_find_position
P_ ((struct window
*, int, int *, int *,
136 int *, int *, Lisp_Object
));
137 extern struct glyph
*x_y_to_hpos_vpos
P_ ((struct window
*, int, int,
138 int *, int *, int *, int *, int *));
139 extern void mac_ax_selected_text_range
P_ ((struct frame
*, CFRange
*));
140 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
141 extern unsigned int mac_ax_number_of_characters
P_ ((struct frame
*));
145 extern OSStatus mac_restore_keyboard_input_source
P_ ((void));
146 extern void mac_save_keyboard_input_source
P_ ((void));
153 err
= ActivateTSMDocument (tsm_document_id
);
155 err
= mac_restore_keyboard_input_source ();
165 mac_save_keyboard_input_source ();
166 err
= DeactivateTSMDocument (tsm_document_id
);
175 static InterfaceTypeList types
= {kUnicodeDocument
};
177 static InterfaceTypeList types
= {kTextService
};
180 NewTSMDocument (sizeof (types
) / sizeof (types
[0]), types
,
181 &tsm_document_id
, 0);
183 #endif /* USE_MAC_TSM */
185 static pascal OSStatus
186 mac_handle_keyboard_event (next_handler
, event
, data
)
187 EventHandlerCallRef next_handler
;
191 OSStatus err
, result
= eventNotHandledErr
;
192 UInt32 event_kind
, key_code
, modifiers
;
193 unsigned char char_code
;
195 event_kind
= GetEventKind (event
);
198 case kEventRawKeyDown
:
199 case kEventRawKeyRepeat
:
201 /* When using Carbon Events, we need to pass raw keyboard events
202 to the TSM ourselves. If TSM handles it, it will pass back
203 noErr, otherwise it will pass back "eventNotHandledErr" and
204 we can process it normally. */
205 result
= CallNextEventHandler (next_handler
, event
);
206 if (result
!= eventNotHandledErr
)
209 if (read_socket_inev
== NULL
)
213 if (read_socket_inev
->kind
!= NO_EVENT
)
220 if (event_kind
== kEventRawKeyUp
)
223 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
225 sizeof (char), NULL
, &char_code
);
229 err
= GetEventParameter (event
, kEventParamKeyCode
,
231 sizeof (UInt32
), NULL
, &key_code
);
235 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
237 sizeof (UInt32
), NULL
, &modifiers
);
241 do_keystroke ((event_kind
== kEventRawKeyDown
? keyDown
: autoKey
),
242 char_code
, key_code
, modifiers
,
244 (GetEventTime (event
) / kEventDurationMillisecond
)),
256 static pascal OSStatus
257 mac_handle_command_event (next_handler
, event
, data
)
258 EventHandlerCallRef next_handler
;
262 OSStatus err
, result
= eventNotHandledErr
;
264 static const EventParamName names
[] =
265 {kEventParamDirectObject
, kEventParamKeyModifiers
};
266 static const EventParamType types
[] =
267 {typeHICommand
, typeUInt32
};
268 int num_params
= sizeof (names
) / sizeof (names
[0]);
270 err
= GetEventParameter (event
, kEventParamDirectObject
, typeHICommand
,
271 NULL
, sizeof (HICommand
), NULL
, &command
);
273 return eventNotHandledErr
;
275 switch (GetEventKind (event
))
277 case kEventCommandProcess
:
278 result
= CallNextEventHandler (next_handler
, event
);
279 if (result
!= eventNotHandledErr
)
282 err
= GetEventParameter (event
, kEventParamDirectObject
,
284 sizeof (HICommand
), NULL
, &command
);
286 if (err
!= noErr
|| command
.commandID
== 0)
289 /* A HI command event is mapped to an Apple event whose event
290 class symbol is `hi-command' and event ID is its command
292 err
= mac_store_event_ref_as_apple_event (0, command
.commandID
,
307 static pascal OSStatus
308 mac_handle_mouse_event (next_handler
, event
, data
)
309 EventHandlerCallRef next_handler
;
313 OSStatus err
, result
= eventNotHandledErr
;
315 switch (GetEventKind (event
))
317 case kEventMouseWheelMoved
:
321 EventMouseWheelAxis axis
;
325 result
= CallNextEventHandler (next_handler
, event
);
326 if (result
!= eventNotHandledErr
|| read_socket_inev
== NULL
)
329 f
= mac_focus_frame (&one_mac_display_info
);
331 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
,
332 NULL
, sizeof (WindowRef
), NULL
, &wp
);
334 || wp
!= FRAME_MAC_WINDOW (f
))
337 err
= GetEventParameter (event
, kEventParamMouseWheelAxis
,
338 typeMouseWheelAxis
, NULL
,
339 sizeof (EventMouseWheelAxis
), NULL
, &axis
);
340 if (err
!= noErr
|| axis
!= kEventMouseWheelAxisY
)
343 err
= GetEventParameter (event
, kEventParamMouseLocation
,
344 typeQDPoint
, NULL
, sizeof (Point
),
349 point
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
350 point
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
351 if (point
.h
< 0 || point
.v
< 0
352 || EQ (window_from_coordinates (f
, point
.h
, point
.v
, 0, 0, 0, 1),
356 err
= GetEventParameter (event
, kEventParamMouseWheelDelta
,
357 typeSInt32
, NULL
, sizeof (SInt32
),
362 read_socket_inev
->kind
= WHEEL_EVENT
;
363 read_socket_inev
->code
= 0;
364 read_socket_inev
->modifiers
=
365 (mac_event_to_emacs_modifiers (event
)
366 | ((delta
< 0) ? down_modifier
: up_modifier
));
367 XSETINT (read_socket_inev
->x
, point
.h
);
368 XSETINT (read_socket_inev
->y
, point
.v
);
369 XSETFRAME (read_socket_inev
->frame_or_window
, f
);
383 extern void mac_get_selected_range
P_ ((struct window
*, CFRange
*));
384 extern int mac_store_buffer_text_to_unicode_chars
P_ ((struct buffer
*,
385 int, int, UniChar
*));
387 static pascal OSStatus
388 mac_handle_text_input_event (next_handler
, event
, data
)
389 EventHandlerCallRef next_handler
;
393 OSStatus err
, result
;
394 Lisp_Object id_key
= Qnil
;
396 const EventParamName
*names
;
397 const EventParamType
*types
;
398 static UInt32 seqno_uaia
= 0;
399 static const EventParamName names_uaia
[] =
400 {kEventParamTextInputSendComponentInstance
,
401 kEventParamTextInputSendRefCon
,
402 kEventParamTextInputSendSLRec
,
403 kEventParamTextInputSendFixLen
,
404 kEventParamTextInputSendText
,
405 kEventParamTextInputSendUpdateRng
,
406 kEventParamTextInputSendHiliteRng
,
407 kEventParamTextInputSendClauseRng
,
408 kEventParamTextInputSendPinRng
,
409 kEventParamTextInputSendTextServiceEncoding
,
410 kEventParamTextInputSendTextServiceMacEncoding
,
411 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER
};
412 static const EventParamType types_uaia
[] =
413 {typeComponentInstance
,
429 static const EventParamName names_ufke
[] =
430 {kEventParamTextInputSendComponentInstance
,
431 kEventParamTextInputSendRefCon
,
432 kEventParamTextInputSendSLRec
,
433 kEventParamTextInputSendText
};
434 static const EventParamType types_ufke
[] =
435 {typeComponentInstance
,
440 result
= CallNextEventHandler (next_handler
, event
);
441 if (result
!= eventNotHandledErr
)
444 switch (GetEventKind (event
))
446 case kEventTextInputUpdateActiveInputArea
:
447 id_key
= Qupdate_active_input_area
;
448 num_params
= sizeof (names_uaia
) / sizeof (names_uaia
[0]);
451 SetEventParameter (event
, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER
,
452 typeUInt32
, sizeof (UInt32
), &seqno_uaia
);
457 case kEventTextInputUnicodeForKeyEvent
:
460 UInt32 actual_size
, modifiers
, key_code
;
462 err
= GetEventParameter (event
, kEventParamTextInputSendKeyboardEvent
,
463 typeEventRef
, NULL
, sizeof (EventRef
), NULL
,
466 err
= GetEventParameter (kbd_event
, kEventParamKeyModifiers
,
468 sizeof (UInt32
), NULL
, &modifiers
);
470 err
= GetEventParameter (kbd_event
, kEventParamKeyCode
,
471 typeUInt32
, NULL
, sizeof (UInt32
),
473 if (err
== noErr
&& mac_mapped_modifiers (modifiers
, key_code
))
474 /* There're mapped modifier keys. Process it in
478 err
= GetEventParameter (kbd_event
, kEventParamKeyUnicodes
,
479 typeUnicodeText
, NULL
, 0, &actual_size
,
481 if (err
== noErr
&& actual_size
== sizeof (UniChar
))
485 err
= GetEventParameter (kbd_event
, kEventParamKeyUnicodes
,
486 typeUnicodeText
, NULL
,
487 sizeof (UniChar
), NULL
, &code
);
488 if (err
== noErr
&& code
< 0x80)
490 /* ASCII character. Process it in do_keystroke. */
491 if (read_socket_inev
&& code
>= 0x20 && code
<= 0x7e
492 && !(key_code
<= 0x7f
493 && keycode_to_xkeysym_table
[key_code
]))
495 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
497 read_socket_inev
->kind
= ASCII_KEYSTROKE_EVENT
;
498 read_socket_inev
->code
= code
;
499 read_socket_inev
->modifiers
=
500 mac_to_emacs_modifiers (modifiers
, 0);
501 read_socket_inev
->modifiers
|=
502 (extra_keyboard_modifiers
503 & (meta_modifier
| alt_modifier
504 | hyper_modifier
| super_modifier
));
505 XSETFRAME (read_socket_inev
->frame_or_window
, f
);
512 /* Non-ASCII keystrokes without mapped modifiers are
513 processed at the Lisp level. */
514 id_key
= Qunicode_for_key_event
;
515 num_params
= sizeof (names_ufke
) / sizeof (names_ufke
[0]);
523 case kEventTextInputOffsetToPos
:
530 err
= GetEventParameter (event
, kEventParamTextInputSendTextOffset
,
531 typeLongInteger
, NULL
, sizeof (long), NULL
,
536 if (STRINGP (Vmac_ts_active_input_buf
)
537 && SBYTES (Vmac_ts_active_input_buf
) != 0)
539 if (!OVERLAYP (Vmac_ts_active_input_overlay
))
542 /* Strictly speaking, this is not always correct because
543 previous events may change some states about display. */
544 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay
, Qbefore_string
)))
546 /* Active input area is displayed around the current point. */
547 f
= SELECTED_FRAME ();
548 w
= XWINDOW (f
->selected_window
);
550 else if (WINDOWP (echo_area_window
))
552 /* Active input area is displayed in the echo area. */
553 w
= XWINDOW (echo_area_window
);
554 f
= WINDOW_XFRAME (w
);
559 p
.h
= (WINDOW_TO_FRAME_PIXEL_X (w
, w
->cursor
.x
)
560 + WINDOW_LEFT_FRINGE_WIDTH (w
)
561 + f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
562 p
.v
= (WINDOW_TO_FRAME_PIXEL_Y (w
, w
->cursor
.y
)
563 + FONT_BASE (FRAME_FONT (f
))
564 + f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
573 int hpos
, vpos
, x
, y
;
574 struct glyph_row
*row
;
578 f
= mac_focus_frame (&one_mac_display_info
);
579 w
= XWINDOW (f
->selected_window
);
580 mac_get_selected_range (w
, &sel_range
);
581 charpos
= (BUF_BEGV (XBUFFER (w
->buffer
)) + sel_range
.location
582 + byte_offset
/ (long) sizeof (UniChar
));
584 if (!fast_find_position (w
, charpos
, &hpos
, &vpos
, &x
, &y
, Qnil
))
586 result
= errOffsetInvalid
;
590 row
= MATRIX_ROW (w
->current_matrix
, vpos
);
591 glyph
= row
->glyphs
[TEXT_AREA
] + hpos
;
592 if (glyph
->type
!= CHAR_GLYPH
|| glyph
->glyph_not_available_p
)
595 p
.h
= (WINDOW_TEXT_TO_FRAME_PIXEL_X (w
, x
)
596 + f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
597 p
.v
= (WINDOW_TO_FRAME_PIXEL_Y (w
, y
)
598 + row
->visible_height
599 + f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
601 face
= FACE_FROM_ID (f
, glyph
->face_id
);
602 if (face
&& face
->font
)
604 XFontStruct
*font
= face
->font
;
605 Fixed point_size
= Long2Fix (font
->mac_fontsize
);
606 short height
= row
->visible_height
;
607 short ascent
= row
->ascent
;
609 SetEventParameter (event
,
610 kEventParamTextInputReplyPointSize
,
611 typeFixed
, sizeof (Fixed
), &point_size
);
612 SetEventParameter (event
,
613 kEventParamTextInputReplyLineHeight
,
614 typeShortInteger
, sizeof (short), &height
);
615 SetEventParameter (event
,
616 kEventParamTextInputReplyLineAscent
,
617 typeShortInteger
, sizeof (short), &ascent
);
618 if (font
->mac_fontnum
!= -1)
624 err1
= FMGetFontFromFontFamilyInstance (font
->mac_fontnum
,
628 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
629 typeUInt32
, sizeof (UInt32
), &fm_font
);
632 long qd_font
= font
->mac_fontnum
;
634 SetEventParameter (event
, kEventParamTextInputReplyFont
,
635 typeLongInteger
, sizeof (long),
639 else if (font
->mac_style
)
644 err1
= ATSUGetAttribute (font
->mac_style
, kATSUFontTag
,
645 sizeof (ATSUFontID
), &font_id
,
648 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
649 typeUInt32
, sizeof (UInt32
), &font_id
);
657 err
= SetEventParameter (event
, kEventParamTextInputReplyPoint
,
658 typeQDPoint
, sizeof (Point
), &p
);
665 case kEventTextInputPosToOffset
:
668 Boolean leading_edge_p
= true;
672 enum window_part part
;
673 long region_class
= kTSMOutsideOfBody
, byte_offset
= 0;
675 err
= GetEventParameter (event
, kEventParamTextInputSendCurrentPoint
,
676 typeQDPoint
, NULL
, sizeof (Point
), NULL
,
681 GetEventParameter (event
, kEventParamTextInputReplyLeadingEdge
,
682 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
685 f
= mac_focus_frame (&one_mac_display_info
);
686 x
= point
.h
- (f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
687 y
= point
.v
- (f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
688 window
= window_from_coordinates (f
, x
, y
, &part
, 0, 0, 1);
689 if (WINDOWP (window
) && EQ (window
, f
->selected_window
))
694 /* Convert to window-relative pixel coordinates. */
695 w
= XWINDOW (window
);
696 frame_to_window_pixel_xy (w
, &x
, &y
);
698 /* Are we in a window whose display is up to date?
699 And verify the buffer's text has not changed. */
700 b
= XBUFFER (w
->buffer
);
702 && EQ (w
->window_end_valid
, w
->buffer
)
703 && XINT (w
->last_modified
) == BUF_MODIFF (b
)
704 && XINT (w
->last_overlay_modified
) == BUF_OVERLAY_MODIFF (b
))
706 int hpos
, vpos
, area
;
709 /* Find the glyph under X/Y. */
710 glyph
= x_y_to_hpos_vpos (w
, x
, y
, &hpos
, &vpos
, 0, 0, &area
);
712 if (glyph
!= NULL
&& area
== TEXT_AREA
)
714 byte_offset
= ((glyph
->charpos
- BUF_BEGV (b
))
716 region_class
= kTSMInsideOfBody
;
721 err
= SetEventParameter (event
, kEventParamTextInputReplyRegionClass
,
722 typeLongInteger
, sizeof (long),
725 err
= SetEventParameter (event
, kEventParamTextInputReplyTextOffset
,
726 typeLongInteger
, sizeof (long),
733 case kEventTextInputGetSelectedText
:
735 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
736 struct window
*w
= XWINDOW (f
->selected_window
);
737 struct buffer
*b
= XBUFFER (w
->buffer
);
740 UniChar
*characters
, c
;
742 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
743 /* Don't try to get buffer contents as the gap might be
747 mac_get_selected_range (w
, &sel_range
);
748 if (sel_range
.length
== 0)
750 Boolean leading_edge_p
;
752 err
= GetEventParameter (event
,
753 kEventParamTextInputReplyLeadingEdge
,
754 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
759 start
= BUF_BEGV (b
) + sel_range
.location
;
765 if (start
< BUF_BEGV (b
) || end
> BUF_ZV (b
))
770 start
= BUF_BEGV (b
) + sel_range
.location
;
771 end
= start
+ sel_range
.length
;
772 characters
= xmalloc (sel_range
.length
* sizeof (UniChar
));
775 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
, characters
))
776 err
= SetEventParameter (event
, kEventParamTextInputReplyText
,
778 sel_range
.length
* sizeof (UniChar
),
780 if (characters
!= &c
)
794 err
= mac_store_event_ref_as_apple_event (0, 0, Qtext_input
, id_key
,
800 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
801 static pascal OSStatus
802 mac_handle_document_access_event (next_handler
, event
, data
)
803 EventHandlerCallRef next_handler
;
807 OSStatus err
, result
;
808 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
810 result
= CallNextEventHandler (next_handler
, event
);
811 if (result
!= eventNotHandledErr
)
814 switch (GetEventKind (event
))
816 case kEventTSMDocumentAccessGetLength
:
818 CFIndex count
= mac_ax_number_of_characters (f
);
820 err
= SetEventParameter (event
, kEventParamTSMDocAccessCharacterCount
,
821 typeCFIndex
, sizeof (CFIndex
), &count
);
827 case kEventTSMDocumentAccessGetSelectedRange
:
831 mac_ax_selected_text_range (f
, &sel_range
);
832 err
= SetEventParameter (event
,
833 kEventParamTSMDocAccessReplyCharacterRange
,
834 typeCFRange
, sizeof (CFRange
), &sel_range
);
840 case kEventTSMDocumentAccessGetCharacters
:
842 struct buffer
*b
= XBUFFER (XWINDOW (f
->selected_window
)->buffer
);
847 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
848 /* Don't try to get buffer contents as the gap might be
852 err
= GetEventParameter (event
,
853 kEventParamTSMDocAccessSendCharacterRange
,
854 typeCFRange
, NULL
, sizeof (CFRange
), NULL
,
857 err
= GetEventParameter (event
,
858 kEventParamTSMDocAccessSendCharactersPtr
,
859 typePtr
, NULL
, sizeof (Ptr
), NULL
,
864 start
= BUF_BEGV (b
) + range
.location
;
865 end
= start
+ range
.length
;
866 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
,
867 (UniChar
*) characters
))
882 install_application_handler ()
884 OSStatus err
= noErr
;
888 static const EventTypeSpec specs
[] =
889 {{kEventClassKeyboard
, kEventRawKeyDown
},
890 {kEventClassKeyboard
, kEventRawKeyRepeat
},
891 {kEventClassKeyboard
, kEventRawKeyUp
}};
893 err
= InstallApplicationEventHandler (NewEventHandlerUPP
894 (mac_handle_keyboard_event
),
895 GetEventTypeCount (specs
),
901 static const EventTypeSpec specs
[] =
902 {{kEventClassCommand
, kEventCommandProcess
}};
904 err
= InstallApplicationEventHandler (NewEventHandlerUPP
905 (mac_handle_command_event
),
906 GetEventTypeCount (specs
),
912 static const EventTypeSpec specs
[] =
913 {{kEventClassMouse
, kEventMouseWheelMoved
}};
915 err
= InstallApplicationEventHandler (NewEventHandlerUPP
916 (mac_handle_mouse_event
),
917 GetEventTypeCount (specs
),
924 static const EventTypeSpec specs
[] =
925 {{kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
},
926 {kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
},
927 {kEventClassTextInput
, kEventTextInputOffsetToPos
},
929 {kEventClassTextInput
, kEventTextInputPosToOffset
},
930 {kEventClassTextInput
, kEventTextInputGetSelectedText
}
934 err
= InstallApplicationEventHandler (NewEventHandlerUPP
935 (mac_handle_text_input_event
),
936 GetEventTypeCount (specs
),
940 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
943 static const EventTypeSpec specs
[] =
944 {{kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetLength
},
945 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetSelectedRange
},
946 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetCharacters
}};
948 err
= InstallApplicationEventHandler (mac_handle_document_access_event
,
949 GetEventTypeCount (specs
),
956 err
= install_menu_target_item_handler ();
960 err
= install_service_handler ();
965 #endif /* TARGET_API_MAC_CARBON */
968 /************************************************************************
970 ************************************************************************/
972 #define DEFAULT_NUM_COLS 80
974 #define MIN_DOC_SIZE 64
975 #define MAX_DOC_SIZE 32767
978 static OSErr install_drag_handler
P_ ((WindowRef
));
979 static void remove_drag_handler
P_ ((WindowRef
));
982 static void mac_prepare_for_quickdraw
P_ ((struct frame
*));
985 extern void mac_handle_visibility_change
P_ ((struct frame
*));
986 extern void mac_handle_origin_change
P_ ((struct frame
*));
987 extern void mac_handle_size_change
P_ ((struct frame
*, int, int));
989 #if TARGET_API_MAC_CARBON
991 extern Lisp_Object Qwindow
;
992 extern Lisp_Object Qtoolbar_switch_mode
;
997 do_window_update (WindowRef win
)
999 struct frame
*f
= mac_window_to_frame (win
);
1003 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1005 if (win
!= tip_window
)
1007 if (f
->async_visible
== 0)
1009 /* Update events may occur when a frame gets iconified. */
1011 f
->async_visible
= 1;
1012 f
->async_iconified
= 0;
1013 SET_FRAME_GARBAGED (f
);
1019 #if TARGET_API_MAC_CARBON
1020 RgnHandle region
= NewRgn ();
1022 GetPortVisibleRegion (GetWindowPort (win
), region
);
1023 GetRegionBounds (region
, &r
);
1024 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1026 mac_prepare_for_quickdraw (f
);
1028 UpdateControls (win
, region
);
1029 DisposeRgn (region
);
1031 r
= (*win
->visRgn
)->rgnBBox
;
1032 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1033 UpdateControls (win
, win
->visRgn
);
1042 is_emacs_window (WindowRef win
)
1044 Lisp_Object tail
, frame
;
1049 FOR_EACH_FRAME (tail
, frame
)
1050 if (FRAME_MAC_P (XFRAME (frame
)))
1051 if (FRAME_MAC_WINDOW (XFRAME (frame
)) == win
)
1057 /* Handle drags in size box. Based on code contributed by Ben
1058 Mesander and IM - Window Manager A. */
1061 do_grow_window (w
, e
)
1063 const EventRecord
*e
;
1066 int rows
, columns
, width
, height
;
1067 struct frame
*f
= mac_window_to_frame (w
);
1068 XSizeHints
*size_hints
= FRAME_SIZE_HINTS (f
);
1069 int min_width
= MIN_DOC_SIZE
, min_height
= MIN_DOC_SIZE
;
1070 #if TARGET_API_MAC_CARBON
1076 if (size_hints
->flags
& PMinSize
)
1078 min_width
= size_hints
->min_width
;
1079 min_height
= size_hints
->min_height
;
1081 SetRect (&limit_rect
, min_width
, min_height
, MAX_DOC_SIZE
, MAX_DOC_SIZE
);
1083 #if TARGET_API_MAC_CARBON
1084 if (!ResizeWindow (w
, e
->where
, &limit_rect
, &new_rect
))
1086 height
= new_rect
.bottom
- new_rect
.top
;
1087 width
= new_rect
.right
- new_rect
.left
;
1089 grow_size
= GrowWindow (w
, e
->where
, &limit_rect
);
1090 /* see if it really changed size */
1093 height
= HiWord (grow_size
);
1094 width
= LoWord (grow_size
);
1097 if (width
!= FRAME_PIXEL_WIDTH (f
)
1098 || height
!= FRAME_PIXEL_HEIGHT (f
))
1100 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1101 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1103 x_set_window_size (f
, 0, columns
, rows
);
1107 #if TARGET_API_MAC_CARBON
1109 mac_get_ideal_size (f
)
1112 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1113 WindowRef w
= FRAME_MAC_WINDOW (f
);
1116 int height
, width
, columns
, rows
;
1118 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1119 ideal_size
.v
= dpyinfo
->height
;
1120 IsWindowInStandardState (w
, &ideal_size
, &standard_rect
);
1121 /* Adjust the standard size according to character boundaries. */
1122 width
= standard_rect
.right
- standard_rect
.left
;
1123 height
= standard_rect
.bottom
- standard_rect
.top
;
1124 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1125 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1126 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, columns
);
1127 ideal_size
.v
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1132 static pascal OSStatus
1133 mac_handle_window_event (next_handler
, event
, data
)
1134 EventHandlerCallRef next_handler
;
1139 OSStatus err
, result
= eventNotHandledErr
;
1142 XSizeHints
*size_hints
;
1144 err
= GetEventParameter (event
, kEventParamDirectObject
, typeWindowRef
,
1145 NULL
, sizeof (WindowRef
), NULL
, &wp
);
1147 return eventNotHandledErr
;
1149 f
= mac_window_to_frame (wp
);
1150 switch (GetEventKind (event
))
1152 /* -- window refresh events -- */
1154 case kEventWindowUpdate
:
1155 result
= CallNextEventHandler (next_handler
, event
);
1156 if (result
!= eventNotHandledErr
)
1159 do_window_update (wp
);
1163 /* -- window state change events -- */
1165 case kEventWindowShowing
:
1166 size_hints
= FRAME_SIZE_HINTS (f
);
1167 if (!(size_hints
->flags
& (USPosition
| PPosition
)))
1169 struct frame
*sf
= SELECTED_FRAME ();
1171 if (!(FRAME_MAC_P (sf
) && sf
->async_visible
))
1172 RepositionWindow (wp
, NULL
, kWindowCenterOnMainScreen
);
1175 RepositionWindow (wp
, FRAME_MAC_WINDOW (sf
),
1176 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1177 kWindowCascadeStartAtParentWindowScreen
1179 kWindowCascadeOnParentWindowScreen
1183 /* This is a workaround. RepositionWindow fails to put
1184 a window at the cascading position when its parent
1185 window has a Carbon HIToolbar. */
1186 if ((f
->left_pos
== sf
->left_pos
1187 && f
->top_pos
== sf
->top_pos
)
1188 || (f
->left_pos
== sf
->left_pos
+ 10 * 2
1189 && f
->top_pos
== sf
->top_pos
+ 32 * 2))
1190 MoveWindowStructure (wp
, sf
->left_pos
+ 10, sf
->top_pos
+ 32);
1197 case kEventWindowHiding
:
1198 /* Before unmapping the window, update the WM_SIZE_HINTS
1199 property to claim that the current position of the window is
1200 user-specified, rather than program-specified, so that when
1201 the window is mapped again, it will be placed at the same
1202 location, without forcing the user to position it by hand
1203 again (they have already done that once for this window.) */
1204 x_wm_set_size_hint (f
, (long) 0, 1);
1208 case kEventWindowShown
:
1209 case kEventWindowHidden
:
1210 case kEventWindowCollapsed
:
1211 case kEventWindowExpanded
:
1212 mac_handle_visibility_change (f
);
1216 case kEventWindowBoundsChanging
:
1217 result
= CallNextEventHandler (next_handler
, event
);
1218 if (result
!= eventNotHandledErr
)
1221 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1222 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1226 size_hints
= FRAME_SIZE_HINTS (f
);
1227 if ((attributes
& kWindowBoundsChangeUserResize
)
1228 && ((size_hints
->flags
& (PResizeInc
| PBaseSize
| PMinSize
))
1229 == (PResizeInc
| PBaseSize
| PMinSize
)))
1234 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1235 typeQDRectangle
, NULL
, sizeof (Rect
),
1240 width
= bounds
.right
- bounds
.left
;
1241 height
= bounds
.bottom
- bounds
.top
;
1243 if (width
< size_hints
->min_width
)
1244 width
= size_hints
->min_width
;
1246 width
= size_hints
->base_width
1247 + (int) ((width
- size_hints
->base_width
)
1248 / (float) size_hints
->width_inc
+ .5)
1249 * size_hints
->width_inc
;
1251 if (height
< size_hints
->min_height
)
1252 height
= size_hints
->min_height
;
1254 height
= size_hints
->base_height
1255 + (int) ((height
- size_hints
->base_height
)
1256 / (float) size_hints
->height_inc
+ .5)
1257 * size_hints
->height_inc
;
1259 bounds
.right
= bounds
.left
+ width
;
1260 bounds
.bottom
= bounds
.top
+ height
;
1261 SetEventParameter (event
, kEventParamCurrentBounds
,
1262 typeQDRectangle
, sizeof (Rect
), &bounds
);
1267 case kEventWindowBoundsChanged
:
1268 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1269 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1273 if (attributes
& kWindowBoundsChangeSizeChanged
)
1277 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1278 typeQDRectangle
, NULL
, sizeof (Rect
),
1284 width
= bounds
.right
- bounds
.left
;
1285 height
= bounds
.bottom
- bounds
.top
;
1286 mac_handle_size_change (f
, width
, height
);
1287 mac_wakeup_from_rne ();
1291 if (attributes
& kWindowBoundsChangeOriginChanged
)
1292 mac_handle_origin_change (f
);
1297 /* -- window action events -- */
1299 case kEventWindowClose
:
1301 struct input_event buf
;
1304 buf
.kind
= DELETE_WINDOW_EVENT
;
1305 XSETFRAME (buf
.frame_or_window
, f
);
1307 kbd_buffer_store_event (&buf
);
1312 case kEventWindowGetIdealSize
:
1313 result
= CallNextEventHandler (next_handler
, event
);
1314 if (result
!= eventNotHandledErr
)
1318 Point ideal_size
= mac_get_ideal_size (f
);
1320 err
= SetEventParameter (event
, kEventParamDimensions
,
1321 typeQDPoint
, sizeof (Point
), &ideal_size
);
1328 case kEventWindowToolbarSwitchMode
:
1330 static const EventParamName names
[] = {kEventParamDirectObject
,
1331 kEventParamWindowMouseLocation
,
1332 kEventParamKeyModifiers
,
1333 kEventParamMouseButton
,
1334 kEventParamClickCount
,
1335 kEventParamMouseChord
};
1336 static const EventParamType types
[] = {typeWindowRef
,
1342 int num_params
= sizeof (names
) / sizeof (names
[0]);
1344 err
= mac_store_event_ref_as_apple_event (0, 0,
1346 Qtoolbar_switch_mode
,
1356 /* -- window focus events -- */
1358 case kEventWindowFocusAcquired
:
1359 err
= mac_tsm_resume ();
1364 case kEventWindowFocusRelinquish
:
1365 err
= mac_tsm_suspend ();
1379 /* Handle clicks in zoom box. Calculation of "standard state" based
1380 on code in IM - Window Manager A and code contributed by Ben
1381 Mesander. The standard state of an Emacs window is 80-characters
1382 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1385 do_zoom_window (WindowRef w
, int zoom_in_or_out
)
1387 Rect zoom_rect
, port_rect
;
1389 struct frame
*f
= mac_window_to_frame (w
);
1390 #if TARGET_API_MAC_CARBON
1391 Point ideal_size
= mac_get_ideal_size (f
);
1393 GetWindowBounds (w
, kWindowContentRgn
, &port_rect
);
1394 if (IsWindowInStandardState (w
, &ideal_size
, &zoom_rect
)
1395 && port_rect
.left
== zoom_rect
.left
1396 && port_rect
.top
== zoom_rect
.top
)
1397 zoom_in_or_out
= inZoomIn
;
1399 zoom_in_or_out
= inZoomOut
;
1402 mac_clear_area (f
, 0, 0, port_rect
.right
- port_rect
.left
,
1403 port_rect
.bottom
- port_rect
.top
);
1405 ZoomWindowIdeal (w
, zoom_in_or_out
, &ideal_size
);
1406 #else /* not TARGET_API_MAC_CARBON */
1409 int w_title_height
, rows
;
1410 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1412 GetPort (&save_port
);
1414 SetPortWindowPort (w
);
1416 /* Clear window to avoid flicker. */
1417 EraseRect (&(w
->portRect
));
1418 if (zoom_in_or_out
== inZoomOut
)
1420 SetPt (&top_left
, w
->portRect
.left
, w
->portRect
.top
);
1421 LocalToGlobal (&top_left
);
1423 /* calculate height of window's title bar */
1424 w_title_height
= top_left
.v
- 1
1425 - (**((WindowPeek
) w
)->strucRgn
).rgnBBox
.top
+ GetMBarHeight ();
1427 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1428 zoom_rect
= qd
.screenBits
.bounds
;
1429 zoom_rect
.top
+= w_title_height
;
1430 InsetRect (&zoom_rect
, 8, 4); /* not too tight */
1432 zoom_rect
.right
= zoom_rect
.left
1433 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1435 /* Adjust the standard size according to character boundaries. */
1436 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, zoom_rect
.bottom
- zoom_rect
.top
);
1438 zoom_rect
.top
+ FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1440 (**((WStateDataHandle
) ((WindowPeek
) w
)->dataHandle
)).stdState
1444 ZoomWindow (w
, zoom_in_or_out
, f
== mac_focus_frame (dpyinfo
));
1446 SetPort (save_port
);
1447 #endif /* not TARGET_API_MAC_CARBON */
1449 #if !TARGET_API_MAC_CARBON
1450 /* retrieve window size and update application values */
1451 port_rect
= w
->portRect
;
1452 height
= port_rect
.bottom
- port_rect
.top
;
1453 width
= port_rect
.right
- port_rect
.left
;
1455 mac_handle_size_change (f
, width
, height
);
1456 mac_handle_origin_change (f
);
1461 install_window_handler (window
)
1464 OSStatus err
= noErr
;
1466 #if TARGET_API_MAC_CARBON
1469 static const EventTypeSpec specs
[] =
1471 /* -- window refresh events -- */
1472 {kEventClassWindow
, kEventWindowUpdate
},
1473 /* -- window state change events -- */
1474 {kEventClassWindow
, kEventWindowShowing
},
1475 {kEventClassWindow
, kEventWindowHiding
},
1476 {kEventClassWindow
, kEventWindowShown
},
1477 {kEventClassWindow
, kEventWindowHidden
},
1478 {kEventClassWindow
, kEventWindowCollapsed
},
1479 {kEventClassWindow
, kEventWindowExpanded
},
1480 {kEventClassWindow
, kEventWindowBoundsChanging
},
1481 {kEventClassWindow
, kEventWindowBoundsChanged
},
1482 /* -- window action events -- */
1483 {kEventClassWindow
, kEventWindowClose
},
1484 {kEventClassWindow
, kEventWindowGetIdealSize
},
1486 {kEventClassWindow
, kEventWindowToolbarSwitchMode
},
1489 /* -- window focus events -- */
1490 {kEventClassWindow
, kEventWindowFocusAcquired
},
1491 {kEventClassWindow
, kEventWindowFocusRelinquish
},
1494 static EventHandlerUPP handle_window_eventUPP
= NULL
;
1496 if (handle_window_eventUPP
== NULL
)
1497 handle_window_eventUPP
= NewEventHandlerUPP (mac_handle_window_event
);
1499 err
= InstallWindowEventHandler (window
, handle_window_eventUPP
,
1500 GetEventTypeCount (specs
),
1506 err
= install_drag_handler (window
);
1512 remove_window_handler (window
)
1515 remove_drag_handler (window
);
1519 mac_get_window_bounds (f
, inner
, outer
)
1521 Rect
*inner
, *outer
;
1523 #if TARGET_API_MAC_CARBON
1524 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, inner
);
1525 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, outer
);
1526 #else /* not TARGET_API_MAC_CARBON */
1527 RgnHandle region
= NewRgn ();
1529 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, region
);
1530 *inner
= (*region
)->rgnBBox
;
1531 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, region
);
1532 *outer
= (*region
)->rgnBBox
;
1533 DisposeRgn (region
);
1534 #endif /* not TARGET_API_MAC_CARBON */
1538 mac_get_frame_bounds (f
, r
)
1542 #if TARGET_API_MAC_CARBON
1543 return GetWindowPortBounds (FRAME_MAC_WINDOW (f
), r
);
1545 *r
= FRAME_MAC_WINDOW (f
)->portRect
;
1552 mac_get_frame_mouse (f
, point
)
1556 #if TARGET_API_MAC_CARBON
1557 GetGlobalMouse (point
);
1558 point
->h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1559 point
->v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1561 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1567 mac_convert_frame_point_to_global (f
, x
, y
)
1571 *x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1572 *y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1575 #if TARGET_API_MAC_CARBON
1577 mac_update_proxy_icon (f
)
1581 Lisp_Object file_name
=
1582 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
)->filename
;
1583 Window w
= FRAME_MAC_WINDOW (f
);
1584 AliasHandle alias
= NULL
;
1586 err
= GetWindowProxyAlias (w
, &alias
);
1587 if (err
== errWindowDoesNotHaveProxy
&& !STRINGP (file_name
))
1590 if (STRINGP (file_name
))
1594 FSRef fref
, fref_proxy
;
1596 FSSpec fss
, fss_proxy
;
1599 Lisp_Object encoded_file_name
= ENCODE_FILE (file_name
);
1602 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1603 SBYTES (encoded_file_name
), typeFSRef
, &desc
);
1605 SetPortWindowPort (w
);
1606 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1607 SBYTES (encoded_file_name
), typeFSS
, &desc
);
1612 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
1614 err
= AEGetDescData (&desc
, &fss
, sizeof (FSSpec
));
1616 AEDisposeDesc (&desc
);
1622 /* (FS)ResolveAlias never sets `changed' to true if
1623 `alias' is minimal. */
1625 err
= FSResolveAlias (NULL
, alias
, &fref_proxy
, &changed
);
1627 err
= FSCompareFSRefs (&fref
, &fref_proxy
);
1629 err
= ResolveAlias (NULL
, alias
, &fss_proxy
, &changed
);
1631 err
= !(fss
.vRefNum
== fss_proxy
.vRefNum
1632 && fss
.parID
== fss_proxy
.parID
1633 && EqualString (fss
.name
, fss_proxy
.name
,
1637 if (err
!= noErr
|| alias
== NULL
)
1640 DisposeHandle ((Handle
) alias
);
1642 err
= FSNewAliasMinimal (&fref
, &alias
);
1644 err
= NewAliasMinimal (&fss
, &alias
);
1651 err
= SetWindowProxyAlias (w
, alias
);
1655 DisposeHandle ((Handle
) alias
);
1657 if (err
!= noErr
|| !STRINGP (file_name
))
1658 RemoveWindowProxy (w
);
1662 /* Mac replacement for XSetWindowBackground. */
1665 mac_set_frame_window_background (f
, color
)
1667 unsigned long color
;
1669 WindowRef w
= FRAME_MAC_WINDOW (f
);
1670 #if !TARGET_API_MAC_CARBON
1671 AuxWinHandle aw_handle
;
1672 CTabHandle ctab_handle
;
1673 ColorSpecPtr ct_table
;
1678 bg_color
.red
= RED16_FROM_ULONG (color
);
1679 bg_color
.green
= GREEN16_FROM_ULONG (color
);
1680 bg_color
.blue
= BLUE16_FROM_ULONG (color
);
1682 #if TARGET_API_MAC_CARBON
1683 SetWindowContentColor (w
, &bg_color
);
1685 if (GetAuxWin (w
, &aw_handle
))
1687 ctab_handle
= (*aw_handle
)->awCTable
;
1688 HandToHand ((Handle
*) &ctab_handle
);
1689 ct_table
= (*ctab_handle
)->ctTable
;
1690 ct_size
= (*ctab_handle
)->ctSize
;
1691 while (ct_size
> -1)
1693 if (ct_table
->value
== 0)
1695 ct_table
->rgb
= bg_color
;
1696 CTabChanged (ctab_handle
);
1697 SetWinColor (w
, (WCTabHandle
) ctab_handle
);
1705 /* Flush display of frame F, or of all frames if F is null. */
1711 #if TARGET_API_MAC_CARBON
1714 mac_prepare_for_quickdraw (f
);
1717 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f
)), NULL
);
1719 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL
);
1726 mac_flush_display_optional (f
)
1730 mac_prepare_for_quickdraw (f
);
1736 mac_update_begin (f
)
1739 #if TARGET_API_MAC_CARBON
1740 /* During update of a frame, availability of input events is
1741 periodically checked with ReceiveNextEvent if
1742 redisplay-dont-pause is nil. That normally flushes window buffer
1743 changes for every check, and thus screen update looks waving even
1744 if no input is available. So we disable screen updates during
1745 update of a frame. */
1746 DisableScreenUpdates ();
1754 #if TARGET_API_MAC_CARBON
1755 EnableScreenUpdates ();
1760 mac_frame_up_to_date (f
)
1763 /* Nothing to do. */
1767 mac_create_frame_window (f
, tooltip_p
)
1772 #if TARGET_API_MAC_CARBON
1773 WindowClass window_class
;
1774 WindowAttributes attributes
;
1778 Boolean go_away_flag
;
1783 SetRect (&r
, f
->left_pos
, f
->top_pos
,
1784 f
->left_pos
+ FRAME_PIXEL_WIDTH (f
),
1785 f
->top_pos
+ FRAME_PIXEL_HEIGHT (f
));
1786 #if TARGET_API_MAC_CARBON
1787 window_class
= kDocumentWindowClass
;
1788 attributes
= (kWindowStandardDocumentAttributes
1790 | kWindowToolbarButtonAttribute
1794 proc_id
= zoomDocProc
;
1795 behind
= (WindowRef
) -1;
1796 go_away_flag
= true;
1801 SetRect (&r
, 0, 0, 1, 1);
1802 #if TARGET_API_MAC_CARBON
1803 window_class
= kHelpWindowClass
;
1804 attributes
= (kWindowNoUpdatesAttribute
1805 | kWindowNoActivatesAttribute
1806 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1807 | kWindowIgnoreClicksAttribute
1811 proc_id
= plainDBox
;
1813 go_away_flag
= false;
1817 #if TARGET_API_MAC_CARBON
1818 CreateNewWindow (window_class
, attributes
, &r
, &FRAME_MAC_WINDOW (f
));
1819 if (FRAME_MAC_WINDOW (f
))
1821 SetWRefCon (FRAME_MAC_WINDOW (f
), (long) f
->output_data
.mac
);
1823 if (install_window_handler (FRAME_MAC_WINDOW (f
)) != noErr
)
1825 DisposeWindow (FRAME_MAC_WINDOW (f
));
1826 FRAME_MAC_WINDOW (f
) = NULL
;
1829 #else /* !TARGET_API_MAC_CARBON */
1830 FRAME_MAC_WINDOW (f
)
1831 = NewCWindow (NULL
, &r
, "\p", false, proc_id
, behind
, go_away_flag
,
1832 (long) f
->output_data
.mac
);
1833 #endif /* !TARGET_API_MAC_CARBON */
1834 /* so that update events can find this mac_output struct */
1835 f
->output_data
.mac
->mFP
= f
; /* point back to emacs frame */
1839 if (FRAME_MAC_WINDOW (f
))
1841 ControlRef root_control
;
1843 if (CreateRootControl (FRAME_MAC_WINDOW (f
), &root_control
) != noErr
)
1845 DisposeWindow (FRAME_MAC_WINDOW (f
));
1846 FRAME_MAC_WINDOW (f
) = NULL
;
1852 /* Dispose of the Mac window of the frame F. */
1855 mac_dispose_frame_window (f
)
1858 WindowRef window
= FRAME_MAC_WINDOW (f
);
1860 if (window
!= tip_window
)
1861 remove_window_handler (window
);
1864 mac_prepare_for_quickdraw (f
);
1866 DisposeWindow (window
);
1870 /************************************************************************
1872 ************************************************************************/
1875 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1878 mac_begin_cg_clip (f
, gc
)
1882 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1886 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)), &context
);
1887 FRAME_CG_CONTEXT (f
) = context
;
1890 CGContextSaveGState (context
);
1891 CGContextTranslateCTM (context
, 0, FRAME_PIXEL_HEIGHT (f
));
1892 CGContextScaleCTM (context
, 1, -1);
1893 if (gc
&& gc
->n_clip_rects
)
1894 CGContextClipToRects (context
, gc
->clip_rects
, gc
->n_clip_rects
);
1903 CGContextRestoreGState (FRAME_CG_CONTEXT (f
));
1907 mac_prepare_for_quickdraw (f
)
1912 Lisp_Object rest
, frame
;
1913 FOR_EACH_FRAME (rest
, frame
)
1914 if (FRAME_MAC_P (XFRAME (frame
)))
1915 mac_prepare_for_quickdraw (XFRAME (frame
));
1919 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1923 CGContextSynchronize (context
);
1924 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)),
1925 &FRAME_CG_CONTEXT (f
));
1931 static RgnHandle saved_port_clip_region
= NULL
;
1934 mac_begin_clip (f
, gc
)
1938 static RgnHandle new_region
= NULL
;
1940 if (saved_port_clip_region
== NULL
)
1941 saved_port_clip_region
= NewRgn ();
1942 if (new_region
== NULL
)
1943 new_region
= NewRgn ();
1946 mac_prepare_for_quickdraw (f
);
1948 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1950 if (gc
&& gc
->n_clip_rects
)
1952 GetClip (saved_port_clip_region
);
1953 SectRgn (saved_port_clip_region
, gc
->clip_region
, new_region
);
1954 SetClip (new_region
);
1959 mac_end_clip (f
, gc
)
1963 if (gc
&& gc
->n_clip_rects
)
1964 SetClip (saved_port_clip_region
);
1967 #if TARGET_API_MAC_CARBON
1968 /* Mac replacement for XCopyArea: used only for scrolling. */
1971 mac_scroll_area (f
, gc
, src_x
, src_y
, width
, height
, dest_x
, dest_y
)
1975 unsigned int width
, height
;
1979 RgnHandle dummy
= NewRgn (); /* For avoiding update events. */
1981 SetRect (&src_r
, src_x
, src_y
, src_x
+ width
, src_y
+ height
);
1983 mac_prepare_for_quickdraw (f
);
1985 ScrollWindowRect (FRAME_MAC_WINDOW (f
),
1986 &src_r
, dest_x
- src_x
, dest_y
- src_y
,
1987 kScrollWindowNoOptions
, dummy
);
1993 /************************************************************************
1995 ************************************************************************/
1997 extern struct scroll_bar
*tracked_scroll_bar
;
1998 extern Lisp_Object last_mouse_scroll_bar
;
1999 extern Time last_mouse_movement_time
;
2001 static void x_scroll_bar_handle_click
P_ ((struct scroll_bar
*,
2003 const EventRecord
*,
2004 struct input_event
*));
2005 #ifndef USE_TOOLKIT_SCROLL_BARS
2006 static void x_scroll_bar_note_movement
P_ ((struct scroll_bar
*, int, Time
));
2007 #else /* USE_TOOLKIT_SCROLL_BARS */
2008 static void x_scroll_bar_handle_press
P_ ((struct scroll_bar
*,
2009 ControlPartCode
, Point
,
2010 struct input_event
*));
2011 static void x_scroll_bar_handle_release
P_ ((struct scroll_bar
*,
2012 struct input_event
*));
2013 static void x_scroll_bar_handle_drag
P_ ((WindowRef
, struct scroll_bar
*,
2014 Point
, struct input_event
*));
2015 static pascal void scroll_bar_timer_callback
P_ ((EventLoopTimerRef
, void *));
2016 static OSStatus install_scroll_bar_timer
P_ ((void));
2017 static OSStatus set_scroll_bar_timer
P_ ((EventTimerInterval
));
2018 static int control_part_code_to_scroll_bar_part
P_ ((ControlPartCode
));
2019 static void construct_scroll_bar_click
P_ ((struct scroll_bar
*, int,
2020 struct input_event
*));
2021 static OSStatus get_control_part_bounds
P_ ((ControlRef
, ControlPartCode
,
2023 static void update_scroll_bar_track_info
P_ ((struct scroll_bar
*));
2025 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2027 static int last_scroll_bar_part
;
2029 static EventLoopTimerRef scroll_bar_timer
;
2031 static int scroll_bar_timer_event_posted_p
;
2033 #define SCROLL_BAR_FIRST_DELAY 0.5
2034 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2037 scroll_bar_timer_callback (timer
, data
)
2038 EventLoopTimerRef timer
;
2043 err
= mac_post_mouse_moved_event ();
2045 scroll_bar_timer_event_posted_p
= 1;
2049 install_scroll_bar_timer ()
2051 static EventLoopTimerUPP scroll_bar_timer_callbackUPP
= NULL
;
2053 if (scroll_bar_timer_callbackUPP
== NULL
)
2054 scroll_bar_timer_callbackUPP
=
2055 NewEventLoopTimerUPP (scroll_bar_timer_callback
);
2057 if (scroll_bar_timer
== NULL
)
2058 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2059 kEventDurationForever as delays. */
2061 InstallEventLoopTimer (GetCurrentEventLoop (),
2062 kEventDurationForever
, kEventDurationForever
,
2063 scroll_bar_timer_callbackUPP
, NULL
,
2068 set_scroll_bar_timer (delay
)
2069 EventTimerInterval delay
;
2071 if (scroll_bar_timer
== NULL
)
2072 install_scroll_bar_timer ();
2074 scroll_bar_timer_event_posted_p
= 0;
2076 return SetEventLoopTimerNextFireTime (scroll_bar_timer
, delay
);
2080 control_part_code_to_scroll_bar_part (part_code
)
2081 ControlPartCode part_code
;
2085 case kControlUpButtonPart
: return scroll_bar_up_arrow
;
2086 case kControlDownButtonPart
: return scroll_bar_down_arrow
;
2087 case kControlPageUpPart
: return scroll_bar_above_handle
;
2088 case kControlPageDownPart
: return scroll_bar_below_handle
;
2089 case kControlIndicatorPart
: return scroll_bar_handle
;
2096 construct_scroll_bar_click (bar
, part
, bufp
)
2097 struct scroll_bar
*bar
;
2099 struct input_event
*bufp
;
2101 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2102 bufp
->frame_or_window
= bar
->window
;
2106 XSETINT (bufp
->x
, 0);
2107 XSETINT (bufp
->y
, 0);
2108 bufp
->modifiers
= 0;
2112 get_control_part_bounds (ch
, part_code
, rect
)
2114 ControlPartCode part_code
;
2117 RgnHandle region
= NewRgn ();
2120 err
= GetControlRegion (ch
, part_code
, region
);
2122 GetRegionBounds (region
, rect
);
2123 DisposeRgn (region
);
2129 x_scroll_bar_handle_press (bar
, part_code
, mouse_pos
, bufp
)
2130 struct scroll_bar
*bar
;
2131 ControlPartCode part_code
;
2133 struct input_event
*bufp
;
2135 int part
= control_part_code_to_scroll_bar_part (part_code
);
2140 if (part
!= scroll_bar_handle
)
2142 construct_scroll_bar_click (bar
, part
, bufp
);
2143 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2144 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY
);
2145 bar
->dragging
= Qnil
;
2151 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2152 kControlIndicatorPart
, &r
);
2153 XSETINT (bar
->dragging
, - (mouse_pos
.v
- r
.top
) - 1);
2156 last_scroll_bar_part
= part
;
2157 tracked_scroll_bar
= bar
;
2161 x_scroll_bar_handle_release (bar
, bufp
)
2162 struct scroll_bar
*bar
;
2163 struct input_event
*bufp
;
2165 if (last_scroll_bar_part
!= scroll_bar_handle
2166 || (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) >= 0))
2167 construct_scroll_bar_click (bar
, scroll_bar_end_scroll
, bufp
);
2169 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2170 set_scroll_bar_timer (kEventDurationForever
);
2172 last_scroll_bar_part
= -1;
2173 bar
->dragging
= Qnil
;
2174 tracked_scroll_bar
= NULL
;
2178 x_scroll_bar_handle_drag (win
, bar
, mouse_pos
, bufp
)
2180 struct scroll_bar
*bar
;
2182 struct input_event
*bufp
;
2184 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2186 if (last_scroll_bar_part
== scroll_bar_handle
)
2191 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2192 kControlIndicatorPart
, &r
);
2194 if (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) < 0)
2195 XSETINT (bar
->dragging
, - (XINT (bar
->dragging
) + 1));
2197 top
= mouse_pos
.v
- XINT (bar
->dragging
) - XINT (bar
->track_top
);
2198 top_range
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2202 if (top
> top_range
)
2205 construct_scroll_bar_click (bar
, scroll_bar_handle
, bufp
);
2206 XSETINT (bufp
->x
, top
);
2207 XSETINT (bufp
->y
, top_range
);
2211 ControlPartCode part_code
;
2212 int unhilite_p
= 0, part
;
2214 if (ch
!= FindControlUnderMouse (mouse_pos
, win
, &part_code
))
2218 part
= control_part_code_to_scroll_bar_part (part_code
);
2220 switch (last_scroll_bar_part
)
2222 case scroll_bar_above_handle
:
2223 case scroll_bar_below_handle
:
2224 if (part
!= scroll_bar_above_handle
2225 && part
!= scroll_bar_below_handle
)
2229 case scroll_bar_up_arrow
:
2230 case scroll_bar_down_arrow
:
2231 if (part
!= scroll_bar_up_arrow
2232 && part
!= scroll_bar_down_arrow
)
2239 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2240 else if (part
!= last_scroll_bar_part
2241 || scroll_bar_timer_event_posted_p
)
2243 construct_scroll_bar_click (bar
, part
, bufp
);
2244 last_scroll_bar_part
= part
;
2245 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2246 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY
);
2251 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2252 the scroll bar BAR. This function should be called when the bounds
2253 of the scroll bar is changed. */
2256 update_scroll_bar_track_info (bar
)
2257 struct scroll_bar
*bar
;
2259 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2262 GetControlBounds (ch
, &r0
);
2264 if (r0
.right
- r0
.left
>= r0
.bottom
- r0
.top
2266 || r0
.right
- r0
.left
< MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2270 XSETINT (bar
->track_top
, 0);
2271 XSETINT (bar
->track_height
, 0);
2272 XSETINT (bar
->min_handle
, 0);
2278 SetControl32BitMinimum (ch
, 0);
2279 SetControl32BitMaximum (ch
, 1 << 30);
2280 SetControlViewSize (ch
, 1);
2282 /* Move the scroll bar thumb to the top. */
2283 SetControl32BitValue (ch
, 0);
2284 get_control_part_bounds (ch
, kControlIndicatorPart
, &r0
);
2286 /* Move the scroll bar thumb to the bottom. */
2287 SetControl32BitValue (ch
, 1 << 30);
2288 get_control_part_bounds (ch
, kControlIndicatorPart
, &r1
);
2290 UnionRect (&r0
, &r1
, &r0
);
2291 XSETINT (bar
->track_top
, r0
.top
);
2292 XSETINT (bar
->track_height
, r0
.bottom
- r0
.top
);
2293 XSETINT (bar
->min_handle
, r1
.bottom
- r1
.top
);
2295 /* Don't show the scroll bar if its height is not enough to
2296 display the scroll bar thumb. */
2297 if (r0
.bottom
- r0
.top
> 0)
2304 /* Set the thumb size and position of scroll bar BAR. We are currently
2305 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2308 x_set_toolkit_scroll_bar_thumb (bar
, portion
, position
, whole
)
2309 struct scroll_bar
*bar
;
2310 int portion
, position
, whole
;
2312 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2313 int value
, viewsize
, maximum
;
2315 if (XINT (bar
->track_height
) == 0)
2318 if (whole
<= portion
)
2319 value
= 0, viewsize
= 1, maximum
= 0;
2324 maximum
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2325 scale
= (float) maximum
/ (whole
- portion
);
2326 value
= position
* scale
+ 0.5f
;
2327 viewsize
= (int) (portion
* scale
+ 0.5f
) + XINT (bar
->min_handle
);
2332 if (GetControlViewSize (ch
) != viewsize
2333 || GetControl32BitValue (ch
) != value
2334 || GetControl32BitMaximum (ch
) != maximum
)
2336 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2337 SetControlVisibility (ch
, false, false);
2339 SetControl32BitMaximum (ch
, maximum
);
2340 SetControl32BitValue (ch
, value
);
2341 SetControlViewSize (ch
, viewsize
);
2343 SetControlVisibility (ch
, true, true);
2349 #endif /* USE_TOOLKIT_SCROLL_BARS */
2351 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2352 the initial geometry and visibility, respectively. The created
2353 control is stored in some members of BAR. */
2356 mac_create_scroll_bar (bar
, bounds
, visible
)
2357 struct scroll_bar
*bar
;
2361 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2365 mac_prepare_for_quickdraw (f
);
2367 ch
= NewControl (FRAME_MAC_WINDOW (f
), bounds
, "\p", visible
, 0, 0, 0,
2368 #if TARGET_API_MAC_CARBON
2369 kControlScrollBarProc
,
2374 SET_SCROLL_BAR_CONTROL_REF (bar
, ch
);
2376 XSETINT (bar
->start
, 0);
2377 XSETINT (bar
->end
, 0);
2378 bar
->dragging
= Qnil
;
2380 #ifdef USE_TOOLKIT_SCROLL_BARS
2381 update_scroll_bar_track_info (bar
);
2385 /* Dispose of the scroll bar control stored in some members of
2389 mac_dispose_scroll_bar (bar
)
2390 struct scroll_bar
*bar
;
2393 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2395 mac_prepare_for_quickdraw (f
);
2397 DisposeControl (SCROLL_BAR_CONTROL_REF (bar
));
2400 /* Set bounds of the scroll bar BAR to BOUNDS. */
2403 mac_set_scroll_bar_bounds (bar
, bounds
)
2404 struct scroll_bar
*bar
;
2407 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2408 SInt16 width
, height
;
2410 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2412 mac_prepare_for_quickdraw (f
);
2415 width
= bounds
->right
- bounds
->left
;
2416 height
= bounds
->bottom
- bounds
->top
;
2418 MoveControl (ch
, bounds
->left
, bounds
->top
);
2419 SizeControl (ch
, width
, height
);
2420 #ifdef USE_TOOLKIT_SCROLL_BARS
2421 update_scroll_bar_track_info (bar
);
2428 /* Draw the scroll bar BAR. */
2431 mac_redraw_scroll_bar (bar
)
2432 struct scroll_bar
*bar
;
2435 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2437 mac_prepare_for_quickdraw (f
);
2439 Draw1Control (SCROLL_BAR_CONTROL_REF (bar
));
2442 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2443 is set to something other than NO_EVENT, it is enqueued.
2445 This may be called from a signal handler, so we have to ignore GC
2449 x_scroll_bar_handle_click (bar
, part_code
, er
, bufp
)
2450 struct scroll_bar
*bar
;
2451 ControlPartCode part_code
;
2452 const EventRecord
*er
;
2453 struct input_event
*bufp
;
2455 int win_y
, top_range
;
2457 if (! GC_WINDOWP (bar
->window
))
2460 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2461 bufp
->frame_or_window
= bar
->window
;
2464 bar
->dragging
= Qnil
;
2468 case kControlUpButtonPart
:
2469 bufp
->part
= scroll_bar_up_arrow
;
2471 case kControlDownButtonPart
:
2472 bufp
->part
= scroll_bar_down_arrow
;
2474 case kControlPageUpPart
:
2475 bufp
->part
= scroll_bar_above_handle
;
2477 case kControlPageDownPart
:
2478 bufp
->part
= scroll_bar_below_handle
;
2480 #if TARGET_API_MAC_CARBON
2483 case kControlIndicatorPart
:
2485 if (er
->what
== mouseDown
)
2486 bar
->dragging
= make_number (0);
2487 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2488 bufp
->part
= scroll_bar_handle
;
2492 win_y
= XINT (bufp
->y
) - XINT (bar
->top
);
2493 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar
->height
));
2495 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2499 if (! NILP (bar
->dragging
))
2500 win_y
-= XINT (bar
->dragging
);
2504 if (win_y
> top_range
)
2507 XSETINT (bufp
->x
, win_y
);
2508 XSETINT (bufp
->y
, top_range
);
2511 /* Return information to the user about the current position of the mouse
2512 on the scroll bar. */
2515 x_scroll_bar_report_motion (fp
, bar_window
, part
, x
, y
, time
)
2517 Lisp_Object
*bar_window
;
2518 enum scroll_bar_part
*part
;
2520 unsigned long *time
;
2522 struct scroll_bar
*bar
= XSCROLL_BAR (last_mouse_scroll_bar
);
2523 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2524 #if TARGET_API_MAC_CARBON
2525 WindowRef wp
= GetControlOwner (ch
);
2527 WindowRef wp
= (*ch
)->contrlOwner
;
2530 struct frame
*f
= mac_window_to_frame (wp
);
2531 int win_y
, top_range
;
2533 #if TARGET_API_MAC_CARBON
2534 GetGlobalMouse (&mouse_pos
);
2535 mouse_pos
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
2536 mouse_pos
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2538 SetPortWindowPort (wp
);
2539 GetMouse (&mouse_pos
);
2542 win_y
= mouse_pos
.v
- XINT (bar
->top
);
2543 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2545 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2549 if (! NILP (bar
->dragging
))
2550 win_y
-= XINT (bar
->dragging
);
2554 if (win_y
> top_range
)
2558 *bar_window
= bar
->window
;
2560 if (! NILP (bar
->dragging
))
2561 *part
= scroll_bar_handle
;
2562 else if (win_y
< XINT (bar
->start
))
2563 *part
= scroll_bar_above_handle
;
2564 else if (win_y
< XINT (bar
->end
) + VERTICAL_SCROLL_BAR_MIN_HANDLE
)
2565 *part
= scroll_bar_handle
;
2567 *part
= scroll_bar_below_handle
;
2569 XSETINT (*x
, win_y
);
2570 XSETINT (*y
, top_range
);
2573 last_mouse_scroll_bar
= Qnil
;
2575 *time
= last_mouse_movement_time
;
2578 #ifndef USE_TOOLKIT_SCROLL_BARS
2579 /* Draw BAR's handle in the proper position.
2581 If the handle is already drawn from START to END, don't bother
2582 redrawing it, unless REBUILD is non-zero; in that case, always
2583 redraw it. (REBUILD is handy for drawing the handle after expose
2586 Normally, we want to constrain the start and end of the handle to
2587 fit inside its rectangle, but if the user is dragging the scroll
2588 bar handle, we want to let them drag it down all the way, so that
2589 the bar's top is as far down as it goes; otherwise, there's no way
2590 to move to the very end of the buffer. */
2593 x_scroll_bar_set_handle (bar
, start
, end
, rebuild
)
2594 struct scroll_bar
*bar
;
2598 int dragging
= ! NILP (bar
->dragging
);
2599 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2600 FRAME_PTR f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2601 int top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2602 int length
= end
- start
;
2604 /* If the display is already accurate, do nothing. */
2606 && start
== XINT (bar
->start
)
2607 && end
== XINT (bar
->end
))
2612 /* Make sure the values are reasonable, and try to preserve the
2613 distance between start and end. */
2616 else if (start
> top_range
)
2618 end
= start
+ length
;
2622 else if (end
> top_range
&& ! dragging
)
2625 /* Store the adjusted setting in the scroll bar. */
2626 XSETINT (bar
->start
, start
);
2627 XSETINT (bar
->end
, end
);
2629 /* Clip the end position, just for display. */
2630 if (end
> top_range
)
2633 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2634 top positions, to make sure the handle is always at least that
2635 many pixels tall. */
2636 end
+= VERTICAL_SCROLL_BAR_MIN_HANDLE
;
2638 SetControlMinimum (ch
, 0);
2639 /* Don't inadvertently activate deactivated scroll bars */
2640 if (GetControlMaximum (ch
) != -1)
2641 SetControlMaximum (ch
, top_range
+ VERTICAL_SCROLL_BAR_MIN_HANDLE
2643 SetControlValue (ch
, start
);
2644 #if TARGET_API_MAC_CARBON
2645 SetControlViewSize (ch
, end
- start
);
2651 /* Handle some mouse motion while someone is dragging the scroll bar.
2653 This may be called from a signal handler, so we have to ignore GC
2657 x_scroll_bar_note_movement (bar
, y_pos
, t
)
2658 struct scroll_bar
*bar
;
2662 FRAME_PTR f
= XFRAME (XWINDOW (bar
->window
)->frame
);
2664 last_mouse_movement_time
= t
;
2667 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2669 /* If we're dragging the bar, display it. */
2670 if (! GC_NILP (bar
->dragging
))
2672 /* Where should the handle be now? */
2673 int new_start
= y_pos
- 24;
2675 if (new_start
!= XINT (bar
->start
))
2677 int new_end
= new_start
+ (XINT (bar
->end
) - XINT (bar
->start
));
2679 x_scroll_bar_set_handle (bar
, new_start
, new_end
, 0);
2683 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2686 /***********************************************************************
2688 ***********************************************************************/
2691 /* In identifiers such as function/variable names, Emacs tool bar is
2692 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2694 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2695 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2697 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2698 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2699 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2700 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2701 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2702 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2703 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2705 static OSStatus mac_handle_toolbar_command_event
P_ ((EventHandlerCallRef
,
2708 extern Rect last_mouse_glyph
;
2710 extern void mac_move_window_with_gravity
P_ ((struct frame
*, int,
2712 extern void mac_get_window_origin_with_gravity
P_ ((struct frame
*, int,
2714 extern CGImageRef mac_image_spec_to_cg_image
P_ ((struct frame
*,
2718 mac_handle_toolbar_event (next_handler
, event
, data
)
2719 EventHandlerCallRef next_handler
;
2723 OSStatus result
= eventNotHandledErr
;
2725 switch (GetEventKind (event
))
2727 case kEventToolbarGetDefaultIdentifiers
:
2731 case kEventToolbarGetAllowedIdentifiers
:
2733 CFMutableArrayRef array
;
2735 GetEventParameter (event
, kEventParamMutableArray
,
2736 typeCFMutableArrayRef
, NULL
,
2737 sizeof (CFMutableArrayRef
), NULL
, &array
);
2738 CFArrayAppendValue (array
, TOOLBAR_ICON_ITEM_IDENTIFIER
);
2743 case kEventToolbarCreateItemWithIdentifier
:
2745 CFStringRef identifier
;
2746 HIToolbarItemRef item
= NULL
;
2748 GetEventParameter (event
, kEventParamToolbarItemIdentifier
,
2749 typeCFStringRef
, NULL
,
2750 sizeof (CFStringRef
), NULL
, &identifier
);
2752 if (CFStringCompare (identifier
, TOOLBAR_ICON_ITEM_IDENTIFIER
, 0)
2753 == kCFCompareEqualTo
)
2754 HIToolbarItemCreate (identifier
,
2755 kHIToolbarItemAllowDuplicates
2756 | kHIToolbarItemCantBeRemoved
, &item
);
2760 SetEventParameter (event
, kEventParamToolbarItem
,
2761 typeHIToolbarItemRef
,
2762 sizeof (HIToolbarItemRef
), &item
);
2775 /* Create a tool bar for frame F. */
2778 mac_create_frame_tool_bar (f
)
2782 HIToolbarRef toolbar
;
2784 err
= HIToolbarCreate (TOOLBAR_IDENTIFIER
, kHIToolbarNoAttributes
,
2788 static const EventTypeSpec specs
[] =
2789 {{kEventClassToolbar
, kEventToolbarGetDefaultIdentifiers
},
2790 {kEventClassToolbar
, kEventToolbarGetAllowedIdentifiers
},
2791 {kEventClassToolbar
, kEventToolbarCreateItemWithIdentifier
}};
2793 err
= InstallEventHandler (HIObjectGetEventTarget (toolbar
),
2794 mac_handle_toolbar_event
,
2795 GetEventTypeCount (specs
), specs
,
2800 err
= HIToolbarSetDisplayMode (toolbar
, kHIToolbarDisplayModeIconOnly
);
2803 static const EventTypeSpec specs
[] =
2804 {{kEventClassCommand
, kEventCommandProcess
}};
2806 err
= InstallWindowEventHandler (FRAME_MAC_WINDOW (f
),
2807 mac_handle_toolbar_command_event
,
2808 GetEventTypeCount (specs
),
2812 err
= SetWindowToolbar (FRAME_MAC_WINDOW (f
), toolbar
);
2815 CFRelease (toolbar
);
2820 /* Update the tool bar for frame F. Add new buttons and remove old. */
2823 update_frame_tool_bar (f
)
2826 HIToolbarRef toolbar
= NULL
;
2828 CFArrayRef old_items
= NULL
;
2830 int i
, pos
, win_gravity
= f
->output_data
.mac
->toolbar_win_gravity
;
2831 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2835 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2836 if (toolbar
== NULL
)
2838 mac_create_frame_tool_bar (f
);
2839 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2840 if (toolbar
== NULL
)
2842 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2843 mac_get_window_origin_with_gravity (f
, win_gravity
, &left
, &top
);
2846 HIToolbarCopyItems (toolbar
, &old_items
);
2847 if (old_items
== NULL
)
2850 old_count
= CFArrayGetCount (old_items
);
2852 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
2854 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2856 int enabled_p
= !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
));
2857 int selected_p
= !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P
));
2860 CGImageRef cg_image
;
2862 HIToolbarItemRef item
;
2864 /* If image is a vector, choose the image according to the
2866 image
= PROP (TOOL_BAR_ITEM_IMAGES
);
2867 if (VECTORP (image
))
2871 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2872 : TOOL_BAR_IMAGE_ENABLED_DESELECTED
);
2875 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2876 : TOOL_BAR_IMAGE_DISABLED_DESELECTED
);
2878 xassert (ASIZE (image
) >= idx
);
2879 image
= AREF (image
, idx
);
2884 cg_image
= mac_image_spec_to_cg_image (f
, image
);
2885 /* Ignore invalid image specifications. */
2886 if (cg_image
== NULL
)
2889 label
= cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION
));
2893 if (pos
< old_count
)
2895 CGImageRef old_cg_image
= NULL
;
2896 CFStringRef old_label
= NULL
;
2897 Boolean old_enabled_p
;
2899 item
= (HIToolbarItemRef
) CFArrayGetValueAtIndex (old_items
, pos
);
2901 HIToolbarItemCopyImage (item
, &old_cg_image
);
2902 if (cg_image
!= old_cg_image
)
2903 HIToolbarItemSetImage (item
, cg_image
);
2904 CGImageRelease (old_cg_image
);
2906 HIToolbarItemCopyLabel (item
, &old_label
);
2907 if (CFStringCompare (label
, old_label
, 0) != kCFCompareEqualTo
)
2908 HIToolbarItemSetLabel (item
, label
);
2909 CFRelease (old_label
);
2911 old_enabled_p
= HIToolbarItemIsEnabled (item
);
2912 if ((enabled_p
|| idx
>= 0) != old_enabled_p
)
2913 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2918 HIToolbarCreateItemWithIdentifier (toolbar
,
2919 TOOLBAR_ICON_ITEM_IDENTIFIER
,
2923 HIToolbarItemSetImage (item
, cg_image
);
2924 HIToolbarItemSetLabel (item
, label
);
2925 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2926 HIToolbarAppendItem (toolbar
, item
);
2934 HIToolbarItemSetCommandID (item
, TOOLBAR_ITEM_MAKE_COMMAND_ID (i
));
2939 CFRelease (old_items
);
2941 while (pos
< old_count
)
2942 HIToolbarRemoveItemAtIndex (toolbar
, --old_count
);
2944 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), true,
2945 !win_gravity
&& f
== mac_focus_frame (dpyinfo
));
2946 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2947 toolbar visibility change. */
2948 mac_handle_origin_change (f
);
2949 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2951 mac_move_window_with_gravity (f
, win_gravity
, left
, top
);
2952 /* If the title bar is completely outside the screen, adjust the
2954 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f
), kWindowTitleBarRgn
,
2955 kWindowConstrainMoveRegardlessOfFit
2956 | kWindowConstrainAllowPartial
, NULL
, NULL
);
2957 f
->output_data
.mac
->toolbar_win_gravity
= 0;
2964 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2965 doesn't deallocate the resources. */
2968 free_frame_tool_bar (f
)
2971 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f
)))
2973 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2976 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), false,
2977 (NILP (find_symbol_value
2978 (intern ("frame-notice-user-settings")))
2979 && f
== mac_focus_frame (dpyinfo
)));
2980 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2981 on toolbar visibility change. */
2982 mac_handle_origin_change (f
);
2987 /* Report a mouse movement over toolbar to the mainstream Emacs
2991 mac_tool_bar_note_mouse_movement (f
, event
)
2996 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2999 WindowPartCode part_code
;
3000 HIViewRef item_view
;
3003 mouse_down_p
= (dpyinfo
->grabbed
3004 && f
== last_mouse_frame
3005 && FRAME_LIVE_P (f
));
3009 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
, NULL
,
3010 sizeof (WindowRef
), NULL
, &window
);
3011 if (err
!= noErr
|| window
!= FRAME_MAC_WINDOW (f
))
3014 err
= GetEventParameter (event
, kEventParamWindowPartCode
,
3015 typeWindowPartCode
, NULL
,
3016 sizeof (WindowPartCode
), NULL
, &part_code
);
3017 if (err
!= noErr
|| part_code
!= inStructure
)
3020 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window
), event
, &item_view
);
3021 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3022 toolbar item view seems to have the same command ID with that of
3023 the toolbar item. */
3025 err
= GetControlCommandID (item_view
, &command_id
);
3026 if (err
== noErr
&& TOOLBAR_ITEM_COMMAND_ID_P (command_id
))
3028 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id
);
3030 if (i
< f
->n_tool_bar_items
)
3033 HIViewRef content_view
;
3035 err
= HIViewGetBounds (item_view
, &bounds
);
3037 err
= HIViewFindByID (HIViewGetRoot (window
),
3038 kHIViewWindowContentID
, &content_view
);
3040 err
= HIViewConvertRect (&bounds
, item_view
, content_view
);
3042 SetRect (&last_mouse_glyph
,
3043 CGRectGetMinX (bounds
), CGRectGetMinY (bounds
),
3044 CGRectGetMaxX (bounds
), CGRectGetMaxY (bounds
));
3046 help_echo_object
= help_echo_window
= Qnil
;
3048 help_echo_string
= PROP (TOOL_BAR_ITEM_HELP
);
3049 if (NILP (help_echo_string
))
3050 help_echo_string
= PROP (TOOL_BAR_ITEM_CAPTION
);
3056 mac_handle_toolbar_command_event (next_handler
, event
, data
)
3057 EventHandlerCallRef next_handler
;
3061 OSStatus err
, result
= eventNotHandledErr
;
3062 struct frame
*f
= (struct frame
*) data
;
3065 err
= GetEventParameter (event
, kEventParamDirectObject
,
3066 typeHICommand
, NULL
,
3067 sizeof (HICommand
), NULL
, &command
);
3071 switch (GetEventKind (event
))
3073 case kEventCommandProcess
:
3074 if (!TOOLBAR_ITEM_COMMAND_ID_P (command
.commandID
))
3075 result
= CallNextEventHandler (next_handler
, event
);
3078 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command
.commandID
);
3080 if (i
< f
->n_tool_bar_items
3081 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
)))
3084 struct input_event buf
;
3088 XSETFRAME (frame
, f
);
3089 buf
.kind
= TOOL_BAR_EVENT
;
3090 buf
.frame_or_window
= frame
;
3092 kbd_buffer_store_event (&buf
);
3094 buf
.kind
= TOOL_BAR_EVENT
;
3095 buf
.frame_or_window
= frame
;
3096 buf
.arg
= PROP (TOOL_BAR_ITEM_KEY
);
3097 buf
.modifiers
= mac_event_to_emacs_modifiers (event
);
3098 kbd_buffer_store_event (&buf
);
3112 #endif /* USE_MAC_TOOLBAR */
3115 /***********************************************************************
3117 ***********************************************************************/
3119 #if USE_MAC_FONT_PANEL
3120 /* Whether Font Panel has been shown before. The first call to font
3121 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3122 slow. This variable is used for deferring such a call as much as
3124 static int font_panel_shown_p
= 0;
3126 extern Lisp_Object Qpanel_closed
, Qselection
;
3127 extern Lisp_Object Qfont
;
3129 /* Whether the font panel is currently visible. */
3132 mac_font_panel_visible_p ()
3134 return font_panel_shown_p
&& FPIsFontPanelVisible ();
3137 static pascal OSStatus
3138 mac_handle_font_event (next_handler
, event
, data
)
3139 EventHandlerCallRef next_handler
;
3143 OSStatus result
, err
;
3146 const EventParamName
*names
;
3147 const EventParamType
*types
;
3148 static const EventParamName names_sel
[] = {kEventParamATSUFontID
,
3149 kEventParamATSUFontSize
,
3150 kEventParamFMFontFamily
,
3151 kEventParamFMFontStyle
,
3152 kEventParamFMFontSize
,
3153 kEventParamFontColor
};
3154 static const EventParamType types_sel
[] = {typeATSUFontID
,
3161 result
= CallNextEventHandler (next_handler
, event
);
3162 if (result
!= eventNotHandledErr
)
3165 switch (GetEventKind (event
))
3167 case kEventFontPanelClosed
:
3168 id_key
= Qpanel_closed
;
3174 case kEventFontSelection
:
3175 id_key
= Qselection
;
3176 num_params
= sizeof (names_sel
) / sizeof (names_sel
[0]);
3182 err
= mac_store_event_ref_as_apple_event (0, 0, Qfont
, id_key
,
3191 /* Toggle visiblity of the font panel. */
3194 mac_show_hide_font_panel ()
3196 if (!font_panel_shown_p
)
3200 static const EventTypeSpec specs
[] =
3201 {{kEventClassFont
, kEventFontPanelClosed
},
3202 {kEventClassFont
, kEventFontSelection
}};
3204 err
= InstallApplicationEventHandler (mac_handle_font_event
,
3205 GetEventTypeCount (specs
),
3210 font_panel_shown_p
= 1;
3213 return FPShowHideFontPanel ();
3216 /* Set the font selected in the font panel to the one corresponding to
3217 the face FACE_ID and the charcacter C in the frame F. */
3220 mac_set_font_info_for_selection (f
, face_id
, c
)
3225 EventTargetRef target
= NULL
;
3226 XFontStruct
*font
= NULL
;
3228 if (!mac_font_panel_visible_p ())
3233 target
= GetWindowEventTarget (FRAME_MAC_WINDOW (f
));
3235 if (FRAME_FACE_CACHE (f
) && CHAR_VALID_P (c
, 0))
3239 face_id
= FACE_FOR_CHAR (f
, FACE_FROM_ID (f
, face_id
), c
);
3240 face
= FACE_FROM_ID (f
, face_id
);
3246 err
= SetFontInfoForSelection (kFontSelectionATSUIType
, 0, NULL
, target
);
3249 if (font
->mac_fontnum
!= -1)
3251 FontSelectionQDStyle qd_style
;
3253 qd_style
.version
= kFontSelectionQDStyleVersionZero
;
3254 qd_style
.instance
.fontFamily
= font
->mac_fontnum
;
3255 qd_style
.instance
.fontStyle
= font
->mac_fontface
;
3256 qd_style
.size
= font
->mac_fontsize
;
3257 qd_style
.hasColor
= false;
3259 err
= SetFontInfoForSelection (kFontSelectionQDType
,
3260 1, &qd_style
, target
);
3263 err
= SetFontInfoForSelection (kFontSelectionATSUIType
,
3264 1, &font
->mac_style
, target
);
3269 #endif /* USE_MAC_FONT_PANEL */
3272 /************************************************************************
3274 ************************************************************************/
3276 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3279 static int any_help_event_p
;
3281 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3282 static Lisp_Object last_window
;
3284 static Point saved_menu_event_location
;
3286 extern struct frame
*pending_autoraise_frame
;
3288 extern FRAME_PTR last_mouse_glyph_frame
;
3291 extern int volatile input_signal_count
;
3293 extern int input_signal_count
;
3296 extern int mac_screen_config_changed
;
3298 extern Lisp_Object Vmac_emulate_three_button_mouse
;
3299 #if TARGET_API_MAC_CARBON
3300 extern int mac_wheel_button_is_mouse_2
;
3301 extern int mac_pass_command_to_system
;
3302 extern int mac_pass_control_to_system
;
3303 #endif /* TARGET_API_MAC_CARBON */
3304 extern int mac_ready_for_apple_events
;
3306 extern void mac_focus_changed
P_ ((int, struct mac_display_info
*,
3307 struct frame
*, struct input_event
*));
3308 extern int mac_get_emulated_btn
P_ ((UInt32
));
3309 extern int note_mouse_movement
P_ ((FRAME_PTR
, Point
*));
3310 extern void mac_get_screen_info
P_ ((struct mac_display_info
*));
3312 /* The focus may have changed. Figure out if it is a real focus change,
3313 by checking both FocusIn/Out and Enter/LeaveNotify events.
3315 Returns FOCUS_IN_EVENT event in *BUFP. */
3318 x_detect_focus_change (dpyinfo
, event
, bufp
)
3319 struct mac_display_info
*dpyinfo
;
3320 const EventRecord
*event
;
3321 struct input_event
*bufp
;
3323 struct frame
*frame
;
3325 frame
= mac_window_to_frame ((WindowRef
) event
->message
);
3329 /* On Mac, this is only called from focus events, so no switch needed. */
3330 mac_focus_changed ((event
->modifiers
& activeFlag
),
3331 dpyinfo
, frame
, bufp
);
3334 #if TARGET_API_MAC_CARBON
3335 /* Obtains the event modifiers from the event EVENTREF and then calls
3336 mac_to_emacs_modifiers. */
3339 mac_event_to_emacs_modifiers (EventRef eventRef
)
3341 UInt32 mods
= 0, class;
3343 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3344 sizeof (UInt32
), NULL
, &mods
);
3345 class = GetEventClass (eventRef
);
3346 if (!NILP (Vmac_emulate_three_button_mouse
)
3347 && (class == kEventClassMouse
|| class == kEventClassCommand
))
3349 mods
&= ~(optionKey
| cmdKey
);
3351 return mac_to_emacs_modifiers (mods
, 0);
3354 /* Given an event REF, return the code to use for the mouse button
3355 code in the emacs input_event. */
3358 mac_get_mouse_btn (EventRef ref
)
3360 EventMouseButton result
= kEventMouseButtonPrimary
;
3361 GetEventParameter (ref
, kEventParamMouseButton
, typeMouseButton
, NULL
,
3362 sizeof (EventMouseButton
), NULL
, &result
);
3365 case kEventMouseButtonPrimary
:
3366 if (NILP (Vmac_emulate_three_button_mouse
))
3370 GetEventParameter (ref
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3371 sizeof (UInt32
), NULL
, &mods
);
3372 return mac_get_emulated_btn(mods
);
3374 case kEventMouseButtonSecondary
:
3375 return mac_wheel_button_is_mouse_2
? 2 : 1;
3376 case kEventMouseButtonTertiary
:
3377 case 4: /* 4 is the number for the mouse wheel button */
3378 return mac_wheel_button_is_mouse_2
? 1 : 2;
3384 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3385 events. However the click of the mouse wheel is not converted to a
3386 mouseDown or mouseUp event. Likewise for dead key events. This
3387 calls ConvertEventRefToEventRecord, but then checks to see if it is
3388 a mouse up/down, or a dead key Carbon event that has not been
3389 converted, and if so, converts it by hand (to be picked up in the
3390 XTread_socket loop). */
3391 static Boolean
mac_convert_event_ref (EventRef eventRef
, EventRecord
*eventRec
)
3394 Boolean result
= ConvertEventRefToEventRecord (eventRef
, eventRec
);
3400 switch (GetEventClass (eventRef
))
3402 case kEventClassMouse
:
3403 switch (GetEventKind (eventRef
))
3405 case kEventMouseDown
:
3406 eventRec
->what
= mouseDown
;
3411 eventRec
->what
= mouseUp
;
3420 case kEventClassKeyboard
:
3421 switch (GetEventKind (eventRef
))
3423 case kEventRawKeyDown
:
3425 goto keystroke_common
;
3426 case kEventRawKeyRepeat
:
3428 goto keystroke_common
;
3429 case kEventRawKeyUp
:
3433 unsigned char char_codes
;
3436 err
= GetEventParameter (eventRef
, kEventParamKeyMacCharCodes
,
3437 typeChar
, NULL
, sizeof (char),
3440 err
= GetEventParameter (eventRef
, kEventParamKeyCode
,
3441 typeUInt32
, NULL
, sizeof (UInt32
),
3445 eventRec
->what
= action
;
3446 eventRec
->message
= char_codes
| ((key_code
& 0xff) << 8);
3463 /* Need where and when. */
3466 GetEventParameter (eventRef
, kEventParamMouseLocation
, typeQDPoint
,
3467 NULL
, sizeof (Point
), NULL
, &eventRec
->where
);
3468 /* Use two step process because new event modifiers are 32-bit
3469 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3470 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
,
3471 NULL
, sizeof (UInt32
), NULL
, &mods
);
3472 eventRec
->modifiers
= mods
;
3474 eventRec
->when
= EventTimeToTicks (GetEventTime (eventRef
));
3479 #endif /* TARGET_API_MAC_CARBON */
3481 #if !TARGET_API_MAC_CARBON
3482 static RgnHandle mouse_region
= NULL
;
3485 mac_wait_next_event (er
, sleep_time
, dequeue
)
3490 static EventRecord er_buf
= {nullEvent
};
3491 UInt32 target_tick
, current_tick
;
3492 EventMask event_mask
;
3494 if (mouse_region
== NULL
)
3495 mouse_region
= NewRgn ();
3497 event_mask
= everyEvent
;
3498 if (!mac_ready_for_apple_events
)
3499 event_mask
-= highLevelEventMask
;
3501 current_tick
= TickCount ();
3502 target_tick
= current_tick
+ sleep_time
;
3504 if (er_buf
.what
== nullEvent
)
3505 while (!WaitNextEvent (event_mask
, &er_buf
,
3506 target_tick
- current_tick
, mouse_region
))
3508 current_tick
= TickCount ();
3509 if (target_tick
<= current_tick
)
3515 er_buf
.what
= nullEvent
;
3518 #endif /* not TARGET_API_MAC_CARBON */
3520 #if TARGET_API_MAC_CARBON
3522 mac_post_mouse_moved_event ()
3524 EventRef event
= NULL
;
3527 err
= CreateEvent (NULL
, kEventClassMouse
, kEventMouseMoved
, 0,
3528 kEventAttributeNone
, &event
);
3533 GetGlobalMouse (&mouse_pos
);
3534 err
= SetEventParameter (event
, kEventParamMouseLocation
, typeQDPoint
,
3535 sizeof (Point
), &mouse_pos
);
3539 UInt32 modifiers
= GetCurrentKeyModifiers ();
3541 err
= SetEventParameter (event
, kEventParamKeyModifiers
, typeUInt32
,
3542 sizeof (UInt32
), &modifiers
);
3545 err
= PostEventToQueue (GetCurrentEventQueue (), event
,
3546 kEventPriorityStandard
);
3548 ReleaseEvent (event
);
3555 /* Run the current run loop in the default mode until some input
3556 happens or TIMEOUT seconds passes unless it is negative. Return
3557 true if timeout occurs first. */
3560 mac_run_loop_run_once (timeout
)
3561 EventTimeout timeout
;
3564 mac_prepare_for_quickdraw (NULL
);
3566 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode
,
3567 timeout
>= 0 ? timeout
: 100000, true)
3568 == kCFRunLoopRunTimedOut
);
3572 /* Emacs calls this whenever it wants to read an input event from the
3576 XTread_socket (sd
, expected
, hold_quit
)
3578 struct input_event
*hold_quit
;
3580 struct input_event inev
;
3582 #if TARGET_API_MAC_CARBON
3584 EventTargetRef toolbox_dispatcher
;
3587 struct mac_display_info
*dpyinfo
= &one_mac_display_info
;
3589 if (interrupt_input_blocked
)
3591 interrupt_input_pending
= 1;
3595 interrupt_input_pending
= 0;
3598 /* So people can tell when we have read the available input. */
3599 input_signal_count
++;
3603 #if TARGET_API_MAC_CARBON
3604 toolbox_dispatcher
= GetEventDispatcherTarget ();
3608 mac_prepare_for_quickdraw (NULL
),
3610 !ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
3611 kEventRemoveFromQueue
, &eventRef
))
3612 #else /* !TARGET_API_MAC_CARBON */
3613 while (mac_wait_next_event (&er
, 0, true))
3614 #endif /* !TARGET_API_MAC_CARBON */
3618 unsigned long timestamp
;
3621 inev
.kind
= NO_EVENT
;
3624 #if TARGET_API_MAC_CARBON
3625 timestamp
= GetEventTime (eventRef
) / kEventDurationMillisecond
;
3627 if (!mac_convert_event_ref (eventRef
, &er
))
3629 #else /* !TARGET_API_MAC_CARBON */
3630 timestamp
= er
.when
* (1000 / 60); /* ticks to milliseconds */
3631 #endif /* !TARGET_API_MAC_CARBON */
3638 WindowRef window_ptr
;
3639 ControlPartCode part_code
;
3642 #if TARGET_API_MAC_CARBON
3645 /* This is needed to send mouse events like aqua window
3646 buttons to the correct handler. */
3647 read_socket_inev
= &inev
;
3648 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
3649 read_socket_inev
= NULL
;
3650 if (err
!= eventNotHandledErr
)
3653 last_mouse_glyph_frame
= 0;
3655 if (dpyinfo
->grabbed
&& last_mouse_frame
3656 && FRAME_LIVE_P (last_mouse_frame
))
3658 window_ptr
= FRAME_MAC_WINDOW (last_mouse_frame
);
3659 part_code
= inContent
;
3663 part_code
= FindWindow (er
.where
, &window_ptr
);
3664 if (tip_window
&& window_ptr
== tip_window
)
3666 HideWindow (tip_window
);
3667 part_code
= FindWindow (er
.where
, &window_ptr
);
3671 if (er
.what
!= mouseDown
3672 && (part_code
!= inContent
|| dpyinfo
->grabbed
== 0))
3678 f
= mac_focus_frame (dpyinfo
);
3679 saved_menu_event_location
= er
.where
;
3680 inev
.kind
= MENU_BAR_ACTIVATE_EVENT
;
3681 XSETFRAME (inev
.frame_or_window
, f
);
3686 #if TARGET_API_MAC_CARBON
3687 FrontNonFloatingWindow ()
3692 || (mac_window_to_frame (window_ptr
)
3693 != dpyinfo
->x_focus_frame
))
3694 SelectWindow (window_ptr
);
3697 ControlPartCode control_part_code
;
3701 ControlKind control_kind
;
3704 f
= mac_window_to_frame (window_ptr
);
3705 /* convert to local coordinates of new window */
3706 mouse_loc
.h
= (er
.where
.h
3708 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3709 mouse_loc
.v
= (er
.where
.v
3711 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3712 #if TARGET_API_MAC_CARBON
3713 ch
= FindControlUnderMouse (mouse_loc
, window_ptr
,
3714 &control_part_code
);
3717 GetControlKind (ch
, &control_kind
);
3720 control_part_code
= FindControl (mouse_loc
, window_ptr
,
3724 #if TARGET_API_MAC_CARBON
3725 inev
.code
= mac_get_mouse_btn (eventRef
);
3726 inev
.modifiers
= mac_event_to_emacs_modifiers (eventRef
);
3728 inev
.code
= mac_get_emulated_btn (er
.modifiers
);
3729 inev
.modifiers
= mac_to_emacs_modifiers (er
.modifiers
, 0);
3731 XSETINT (inev
.x
, mouse_loc
.h
);
3732 XSETINT (inev
.y
, mouse_loc
.v
);
3734 if ((dpyinfo
->grabbed
&& tracked_scroll_bar
)
3736 #ifndef USE_TOOLKIT_SCROLL_BARS
3737 /* control_part_code becomes kControlNoPart if
3738 a progress indicator is clicked. */
3739 && control_part_code
!= kControlNoPart
3740 #else /* USE_TOOLKIT_SCROLL_BARS */
3742 && control_kind
.kind
== kControlKindScrollBar
3743 #endif /* MAC_OSX */
3744 #endif /* USE_TOOLKIT_SCROLL_BARS */
3747 struct scroll_bar
*bar
;
3749 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3751 bar
= tracked_scroll_bar
;
3752 #ifndef USE_TOOLKIT_SCROLL_BARS
3753 control_part_code
= kControlIndicatorPart
;
3757 bar
= (struct scroll_bar
*) GetControlReference (ch
);
3758 #ifdef USE_TOOLKIT_SCROLL_BARS
3759 /* Make the "Ctrl-Mouse-2 splits window" work
3760 for toolkit scroll bars. */
3761 if (inev
.modifiers
& ctrl_modifier
)
3762 x_scroll_bar_handle_click (bar
, control_part_code
,
3764 else if (er
.what
== mouseDown
)
3765 x_scroll_bar_handle_press (bar
, control_part_code
,
3768 x_scroll_bar_handle_release (bar
, &inev
);
3769 #else /* not USE_TOOLKIT_SCROLL_BARS */
3770 x_scroll_bar_handle_click (bar
, control_part_code
,
3772 if (er
.what
== mouseDown
3773 && control_part_code
== kControlIndicatorPart
)
3774 tracked_scroll_bar
= bar
;
3776 tracked_scroll_bar
= NULL
;
3777 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3782 int x
= mouse_loc
.h
;
3783 int y
= mouse_loc
.v
;
3785 window
= window_from_coordinates (f
, x
, y
, 0, 0, 0, 1);
3786 if (EQ (window
, f
->tool_bar_window
))
3788 if (er
.what
== mouseDown
)
3789 handle_tool_bar_click (f
, x
, y
, 1, 0);
3791 handle_tool_bar_click (f
, x
, y
, 0,
3797 XSETFRAME (inev
.frame_or_window
, f
);
3798 inev
.kind
= MOUSE_CLICK_EVENT
;
3802 if (er
.what
== mouseDown
)
3804 dpyinfo
->grabbed
|= (1 << inev
.code
);
3805 last_mouse_frame
= f
;
3808 last_tool_bar_item
= -1;
3812 if ((dpyinfo
->grabbed
& (1 << inev
.code
)) == 0)
3813 /* If a button is released though it was not
3814 previously pressed, that would be because
3815 of multi-button emulation. */
3816 dpyinfo
->grabbed
= 0;
3818 dpyinfo
->grabbed
&= ~(1 << inev
.code
);
3821 /* Ignore any mouse motion that happened before
3822 this event; any subsequent mouse-movement Emacs
3823 events should reflect only motion after the
3828 #ifdef USE_TOOLKIT_SCROLL_BARS
3829 if (inev
.kind
== MOUSE_CLICK_EVENT
3830 || (inev
.kind
== SCROLL_BAR_CLICK_EVENT
3831 && (inev
.modifiers
& ctrl_modifier
)))
3836 inev
.modifiers
|= down_modifier
;
3839 inev
.modifiers
|= up_modifier
;
3846 #if TARGET_API_MAC_CARBON
3848 if (IsWindowPathSelectClick (window_ptr
, &er
))
3850 WindowPathSelect (window_ptr
, NULL
, NULL
);
3853 if (part_code
== inProxyIcon
3854 && (TrackWindowProxyDrag (window_ptr
, er
.where
)
3855 != errUserWantsToDragWindow
))
3857 DragWindow (window_ptr
, er
.where
, NULL
);
3858 #else /* not TARGET_API_MAC_CARBON */
3859 DragWindow (window_ptr
, er
.where
, &qd
.screenBits
.bounds
);
3860 /* Update the frame parameters. */
3862 struct frame
*f
= mac_window_to_frame (window_ptr
);
3864 if (f
&& !f
->async_iconified
)
3865 mac_handle_origin_change (f
);
3867 #endif /* not TARGET_API_MAC_CARBON */
3871 if (TrackGoAway (window_ptr
, er
.where
))
3873 inev
.kind
= DELETE_WINDOW_EVENT
;
3874 XSETFRAME (inev
.frame_or_window
,
3875 mac_window_to_frame (window_ptr
));
3879 /* window resize handling added --ben */
3881 do_grow_window (window_ptr
, &er
);
3884 /* window zoom handling added --ben */
3887 if (TrackBox (window_ptr
, er
.where
, part_code
))
3888 do_zoom_window (window_ptr
, part_code
);
3897 if (FrontNonFloatingWindow () != window_ptr
)
3898 SelectWindow (window_ptr
);
3900 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr
),
3902 /* This doesn't work on Mac OS X 10.2. */
3904 HIViewClick (ch
, eventRef
);
3907 #endif /* USE_MAC_TOOLBAR */
3915 #if !TARGET_API_MAC_CARBON
3917 do_window_update ((WindowRef
) er
.message
);
3922 #if TARGET_API_MAC_CARBON
3923 if (SendEventToEventTarget (eventRef
, toolbox_dispatcher
)
3924 != eventNotHandledErr
)
3927 switch ((er
.message
>> 24) & 0x000000FF)
3930 case suspendResumeMessage
:
3931 if (er
.message
& resumeFlag
)
3938 case mouseMovedMessage
:
3939 #if !TARGET_API_MAC_CARBON
3940 SetRectRgn (mouse_region
, er
.where
.h
, er
.where
.v
,
3941 er
.where
.h
+ 1, er
.where
.v
+ 1);
3943 previous_help_echo_string
= help_echo_string
;
3944 help_echo_string
= Qnil
;
3946 if (dpyinfo
->grabbed
&& last_mouse_frame
3947 && FRAME_LIVE_P (last_mouse_frame
))
3948 f
= last_mouse_frame
;
3950 f
= dpyinfo
->x_focus_frame
;
3952 if (dpyinfo
->mouse_face_hidden
)
3954 dpyinfo
->mouse_face_hidden
= 0;
3955 clear_mouse_face (dpyinfo
);
3960 WindowRef wp
= FRAME_MAC_WINDOW (f
);
3963 mouse_pos
.h
= (er
.where
.h
3965 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3966 mouse_pos
.v
= (er
.where
.v
3968 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3969 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3970 #ifdef USE_TOOLKIT_SCROLL_BARS
3971 x_scroll_bar_handle_drag (wp
, tracked_scroll_bar
,
3973 #else /* not USE_TOOLKIT_SCROLL_BARS */
3974 x_scroll_bar_note_movement (tracked_scroll_bar
,
3976 - XINT (tracked_scroll_bar
->top
),
3977 er
.when
* (1000 / 60));
3978 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3981 /* Generate SELECT_WINDOW_EVENTs when needed. */
3982 if (!NILP (Vmouse_autoselect_window
))
3986 window
= window_from_coordinates (f
,
3991 /* Window will be selected only when it is
3992 not selected now and last mouse movement
3993 event was not in it. Minibuffer window
3994 will be selected only when it is active. */
3995 if (WINDOWP (window
)
3996 && !EQ (window
, last_window
)
3997 && !EQ (window
, selected_window
)
3998 /* For click-to-focus window managers
3999 create event iff we don't leave the
4001 && (focus_follows_mouse
4002 || (EQ (XWINDOW (window
)->frame
,
4003 XWINDOW (selected_window
)->frame
))))
4005 inev
.kind
= SELECT_WINDOW_EVENT
;
4006 inev
.frame_or_window
= window
;
4011 if (!note_mouse_movement (f
, &mouse_pos
))
4012 help_echo_string
= previous_help_echo_string
;
4015 mac_tool_bar_note_mouse_movement (f
, eventRef
);
4020 /* If the contents of the global variable
4021 help_echo_string has changed, generate a
4023 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
4031 WindowRef window_ptr
= (WindowRef
) er
.message
;
4033 ControlRef root_control
;
4035 if (window_ptr
== tip_window
)
4037 HideWindow (tip_window
);
4041 if (!is_emacs_window (window_ptr
))
4044 f
= mac_window_to_frame (window_ptr
);
4046 if ((er
.modifiers
& activeFlag
) != 0)
4048 /* A window has been activated */
4051 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4053 ActivateControl (root_control
);
4055 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4057 mouse_loc
.h
= (er
.where
.h
4059 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
4060 mouse_loc
.v
= (er
.where
.v
4062 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
4063 /* Window-activated event counts as mouse movement,
4064 so update things that depend on mouse position. */
4065 note_mouse_movement (f
, &mouse_loc
);
4069 /* A window has been deactivated */
4070 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4072 DeactivateControl (root_control
);
4074 #ifdef USE_TOOLKIT_SCROLL_BARS
4075 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
4077 struct input_event event
;
4080 event
.kind
= NO_EVENT
;
4081 x_scroll_bar_handle_release (tracked_scroll_bar
, &event
);
4082 if (event
.kind
!= NO_EVENT
)
4084 event
.timestamp
= timestamp
;
4085 kbd_buffer_store_event_hold (&event
, hold_quit
);
4090 dpyinfo
->grabbed
= 0;
4092 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4094 if (f
== dpyinfo
->mouse_face_mouse_frame
)
4096 /* If we move outside the frame, then we're
4097 certainly no longer on any text in the
4099 clear_mouse_face (dpyinfo
);
4100 dpyinfo
->mouse_face_mouse_frame
= 0;
4103 /* Generate a nil HELP_EVENT to cancel a help-echo.
4104 Do it only if there's something to cancel.
4105 Otherwise, the startup message is cleared when the
4106 mouse leaves the frame. */
4107 if (any_help_event_p
)
4118 f
= mac_focus_frame (dpyinfo
);
4119 XSETFRAME (inev
.frame_or_window
, f
);
4121 /* If mouse-highlight is an integer, input clears out mouse
4123 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
)
4124 && !EQ (f
->tool_bar_window
, dpyinfo
->mouse_face_window
))
4126 clear_mouse_face (dpyinfo
);
4127 dpyinfo
->mouse_face_hidden
= 1;
4131 UInt32 modifiers
= er
.modifiers
, mapped_modifiers
;
4132 UInt32 key_code
= (er
.message
& keyCodeMask
) >> 8;
4135 GetEventParameter (eventRef
, kEventParamKeyModifiers
,
4137 sizeof (UInt32
), NULL
, &modifiers
);
4139 mapped_modifiers
= mac_mapped_modifiers (modifiers
, key_code
);
4141 #if TARGET_API_MAC_CARBON
4142 if (!(mapped_modifiers
4143 & ~(mac_pass_command_to_system
? cmdKey
: 0)
4144 & ~(mac_pass_control_to_system
? controlKey
: 0)))
4148 if (er
.what
!= keyUp
)
4149 do_keystroke (er
.what
, er
.message
& charCodeMask
,
4150 key_code
, modifiers
, timestamp
, &inev
);
4154 case kHighLevelEvent
:
4155 AEProcessAppleEvent (&er
);
4160 #if TARGET_API_MAC_CARBON
4164 read_socket_inev
= &inev
;
4165 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
4166 read_socket_inev
= NULL
;
4171 #if TARGET_API_MAC_CARBON
4172 ReleaseEvent (eventRef
);
4175 if (inev
.kind
!= NO_EVENT
)
4177 inev
.timestamp
= timestamp
;
4178 kbd_buffer_store_event_hold (&inev
, hold_quit
);
4183 && !(hold_quit
&& hold_quit
->kind
!= NO_EVENT
))
4188 XSETFRAME (frame
, f
);
4194 any_help_event_p
= 1;
4195 gen_help_event (help_echo_string
, frame
, help_echo_window
,
4196 help_echo_object
, help_echo_pos
);
4200 help_echo_string
= Qnil
;
4201 gen_help_event (Qnil
, frame
, Qnil
, Qnil
, 0);
4207 /* If the focus was just given to an autoraising frame,
4209 /* ??? This ought to be able to handle more than one such frame. */
4210 if (pending_autoraise_frame
)
4212 x_raise_frame (pending_autoraise_frame
);
4213 pending_autoraise_frame
= 0;
4216 if (mac_screen_config_changed
)
4218 mac_get_screen_info (dpyinfo
);
4219 mac_screen_config_changed
= 0;
4222 #if !TARGET_API_MAC_CARBON
4223 /* Check which frames are still visible. We do this here because
4224 there doesn't seem to be any direct notification from the Window
4225 Manager that the visibility of a window has changed (at least,
4226 not in all cases). */
4228 Lisp_Object tail
, frame
;
4230 FOR_EACH_FRAME (tail
, frame
)
4232 struct frame
*f
= XFRAME (frame
);
4234 /* The tooltip has been drawn already. Avoid the
4235 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4236 if (EQ (frame
, tip_frame
))
4239 if (FRAME_MAC_P (f
))
4240 mac_handle_visibility_change (f
);
4251 /***********************************************************************
4253 ***********************************************************************/
4255 #if TARGET_API_MAC_CARBON
4256 /* Show the spinning progress indicator for the frame F. Create it if
4257 it doesn't exist yet. */
4260 mac_show_hourglass (f
)
4264 mac_prepare_for_quickdraw (f
);
4266 if (!f
->output_data
.mac
->hourglass_control
)
4268 Window w
= FRAME_MAC_WINDOW (f
);
4272 GetWindowPortBounds (w
, &r
);
4273 r
.left
= r
.right
- HOURGLASS_WIDTH
;
4274 r
.bottom
= r
.top
+ HOURGLASS_HEIGHT
;
4275 if (CreateChasingArrowsControl (w
, &r
, &c
) == noErr
)
4276 f
->output_data
.mac
->hourglass_control
= c
;
4279 if (f
->output_data
.mac
->hourglass_control
)
4280 ShowControl (f
->output_data
.mac
->hourglass_control
);
4283 /* Hide the spinning progress indicator for the frame F. Do nothing
4284 it doesn't exist yet. */
4287 mac_hide_hourglass (f
)
4290 if (f
->output_data
.mac
->hourglass_control
)
4293 mac_prepare_for_quickdraw (f
);
4295 HideControl (f
->output_data
.mac
->hourglass_control
);
4299 /* Reposition the spinning progress indicator for the frame F. Do
4300 nothing it doesn't exist yet. */
4303 mac_reposition_hourglass (f
)
4306 if (f
->output_data
.mac
->hourglass_control
)
4309 mac_prepare_for_quickdraw (f
);
4311 MoveControl (f
->output_data
.mac
->hourglass_control
,
4312 FRAME_PIXEL_WIDTH (f
) - HOURGLASS_WIDTH
, 0);
4315 #endif /* TARGET_API_MAC_CARBON */
4318 /***********************************************************************
4319 File selection dialog
4320 ***********************************************************************/
4322 #if TARGET_API_MAC_CARBON
4323 extern Lisp_Object Qfile_name_history
;
4325 static pascal void mac_nav_event_callback
P_ ((NavEventCallbackMessage
,
4326 NavCBRecPtr
, void *));
4328 /* The actual implementation of Fx_file_dialog. */
4331 mac_file_dialog (prompt
, dir
, default_filename
, mustmatch
, only_dir_p
)
4332 Lisp_Object prompt
, dir
, default_filename
, mustmatch
, only_dir_p
;
4334 Lisp_Object file
= Qnil
;
4335 int count
= SPECPDL_INDEX ();
4336 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
, gcpro5
, gcpro6
;
4337 char filename
[MAXPATHLEN
];
4338 static NavEventUPP mac_nav_event_callbackUPP
= NULL
;
4342 GCPRO6 (prompt
, dir
, default_filename
, mustmatch
, file
, only_dir_p
);
4343 CHECK_STRING (prompt
);
4346 /* Create the dialog with PROMPT as title, using DIR as initial
4347 directory and using "*" as pattern. */
4348 dir
= Fexpand_file_name (dir
, Qnil
);
4352 NavDialogCreationOptions options
;
4353 NavDialogRef dialogRef
;
4354 NavTypeListHandle fileTypes
= NULL
;
4355 NavUserAction userAction
;
4356 CFStringRef message
=NULL
, saveName
= NULL
;
4359 /* No need for a callback function because we are modal */
4360 NavGetDefaultDialogCreationOptions(&options
);
4361 options
.modality
= kWindowModalityAppModal
;
4362 options
.location
.h
= options
.location
.v
= -1;
4363 options
.optionFlags
= kNavDefaultNavDlogOptions
;
4364 options
.optionFlags
|= kNavAllFilesInPopup
; /* All files allowed */
4365 options
.optionFlags
|= kNavSelectAllReadableItem
;
4366 options
.optionFlags
&= ~kNavAllowMultipleFiles
;
4369 message
= cfstring_create_with_string (prompt
);
4370 options
.message
= message
;
4372 /* Don't set the application, let it use default.
4373 options.clientName = CFSTR ("Emacs");
4376 if (mac_nav_event_callbackUPP
== NULL
)
4377 mac_nav_event_callbackUPP
= NewNavEventUPP (mac_nav_event_callback
);
4379 if (!NILP (only_dir_p
))
4380 status
= NavCreateChooseFolderDialog(&options
, mac_nav_event_callbackUPP
,
4381 NULL
, NULL
, &dialogRef
);
4382 else if (NILP (mustmatch
))
4384 /* This is a save dialog */
4385 options
.optionFlags
|= kNavDontConfirmReplacement
;
4386 options
.actionButtonLabel
= CFSTR ("Ok");
4387 options
.windowTitle
= CFSTR ("Enter name");
4389 if (STRINGP (default_filename
))
4391 Lisp_Object utf8
= ENCODE_UTF_8 (default_filename
);
4392 char *begPtr
= SDATA(utf8
);
4393 char *filePtr
= begPtr
+ SBYTES(utf8
);
4394 while (filePtr
!= begPtr
&& !IS_DIRECTORY_SEP(filePtr
[-1]))
4396 saveName
= cfstring_create_with_utf8_cstring (filePtr
);
4397 options
.saveFileName
= saveName
;
4398 options
.optionFlags
|= kNavSelectDefaultLocation
;
4400 status
= NavCreatePutFileDialog(&options
,
4401 'TEXT', kNavGenericSignature
,
4402 mac_nav_event_callbackUPP
, NULL
,
4407 /* This is an open dialog*/
4408 status
= NavCreateChooseFileDialog(&options
, fileTypes
,
4409 mac_nav_event_callbackUPP
, NULL
,
4410 NULL
, NULL
, &dialogRef
);
4413 /* Set the default location and continue*/
4414 if (status
== noErr
)
4416 Lisp_Object encoded_dir
= ENCODE_FILE (dir
);
4419 status
= AECreateDesc (TYPE_FILE_NAME
, SDATA (encoded_dir
),
4420 SBYTES (encoded_dir
), &defLocAed
);
4421 if (status
== noErr
)
4423 NavCustomControl(dialogRef
, kNavCtlSetLocation
, (void*) &defLocAed
);
4424 AEDisposeDesc(&defLocAed
);
4426 status
= NavDialogRun(dialogRef
);
4429 if (saveName
) CFRelease(saveName
);
4430 if (message
) CFRelease(message
);
4432 if (status
== noErr
) {
4433 userAction
= NavDialogGetUserAction(dialogRef
);
4436 case kNavUserActionNone
:
4437 case kNavUserActionCancel
:
4438 break; /* Treat cancel like C-g */
4439 case kNavUserActionOpen
:
4440 case kNavUserActionChoose
:
4441 case kNavUserActionSaveAs
:
4443 NavReplyRecord reply
;
4446 status
= NavDialogGetReply(dialogRef
, &reply
);
4447 if (status
!= noErr
)
4449 status
= AEGetNthPtr (&reply
.selection
, 1, TYPE_FILE_NAME
,
4450 NULL
, NULL
, filename
,
4451 sizeof (filename
) - 1, &len
);
4452 if (status
== noErr
)
4454 len
= min (len
, sizeof (filename
) - 1);
4455 filename
[len
] = '\0';
4456 if (reply
.saveFileName
)
4458 /* If it was a saved file, we need to add the file name */
4459 if (len
&& len
< sizeof (filename
) - 1
4460 && filename
[len
-1] != '/')
4461 filename
[len
++] = '/';
4462 CFStringGetCString(reply
.saveFileName
, filename
+len
,
4463 sizeof (filename
) - len
,
4465 kCFStringEncodingUTF8
4467 CFStringGetSystemEncoding ()
4471 file
= DECODE_FILE (make_unibyte_string (filename
,
4472 strlen (filename
)));
4474 NavDisposeReply(&reply
);
4478 NavDialogDispose(dialogRef
);
4483 /* Fall back on minibuffer if there was a problem */
4484 file
= Fcompleting_read (prompt
, intern ("read-file-name-internal"),
4485 dir
, mustmatch
, dir
, Qfile_name_history
,
4486 default_filename
, Qnil
);
4492 /* Make "Cancel" equivalent to C-g. */
4494 Fsignal (Qquit
, Qnil
);
4496 return unbind_to (count
, file
);
4499 /* Need to register some event callback function for enabling drag and
4500 drop in Navigation Service dialogs. */
4502 mac_nav_event_callback (selector
, parms
, data
)
4503 NavEventCallbackMessage selector
;
4511 /************************************************************************
4513 ************************************************************************/
4515 #if !TARGET_API_MAC_CARBON
4516 #include <MacTypes.h>
4518 #include <Quickdraw.h>
4519 #include <ToolUtils.h>
4521 #include <Controls.h>
4522 #include <Windows.h>
4524 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4525 #include <ControlDefinitions.h>
4527 #endif /* not TARGET_API_MAC_CARBON */
4529 extern int menu_item_selection
;
4530 extern int popup_activated_flag
;
4531 extern int name_is_separator
P_ ((const char *));
4532 extern void find_and_call_menu_selection
P_ ((FRAME_PTR
, int, Lisp_Object
,
4534 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
4536 enum mac_menu_kind
{ /* Menu ID range */
4537 MAC_MENU_APPLE
, /* 0 (Reserved by Apple) */
4538 MAC_MENU_MENU_BAR
, /* 1 .. 233 */
4539 MAC_MENU_M_APPLE
, /* 234 (== M_APPLE) */
4540 MAC_MENU_POPUP
, /* 235 */
4541 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
4542 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
4543 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
4544 MAC_MENU_END
/* 32768 */
4547 static const int min_menu_id
[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4549 static int fill_menu
P_ ((MenuRef
, widget_value
*, enum mac_menu_kind
, int));
4550 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
4552 #if !TARGET_API_MAC_CARBON
4554 do_apple_menu (SInt16 menu_item
)
4557 SInt16 da_driver_refnum
;
4559 if (menu_item
== I_ABOUT
)
4560 NoteAlert (ABOUT_ALERT_ID
, NULL
);
4563 GetMenuItemText (GetMenuRef (M_APPLE
), menu_item
, item_name
);
4564 da_driver_refnum
= OpenDeskAcc (item_name
);
4567 #endif /* !TARGET_API_MAC_CARBON */
4569 /* Activate the menu bar of frame F.
4570 This is called from keyboard.c when it gets the
4571 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4573 To activate the menu bar, we use the button-press event location
4574 that was saved in saved_menu_event_location.
4576 But first we recompute the menu bar contents (the whole tree).
4578 The reason for saving the button event until here, instead of
4579 passing it to the toolkit right away, is that we can safely
4580 execute Lisp code. */
4583 x_activate_menubar (f
)
4587 SInt16 menu_id
, menu_item
;
4589 set_frame_menubar (f
, 0, 1);
4592 popup_activated_flag
= 1;
4593 menu_choice
= MenuSelect (saved_menu_event_location
);
4594 popup_activated_flag
= 0;
4595 menu_id
= HiWord (menu_choice
);
4596 menu_item
= LoWord (menu_choice
);
4598 #if !TARGET_API_MAC_CARBON
4599 if (menu_id
== min_menu_id
[MAC_MENU_M_APPLE
])
4600 do_apple_menu (menu_item
);
4605 MenuRef menu
= GetMenuRef (menu_id
);
4611 GetMenuItemRefCon (menu
, menu_item
, &refcon
);
4612 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
4613 f
->menu_bar_vector
, (void *) refcon
);
4622 #if TARGET_API_MAC_CARBON
4623 extern Lisp_Object Vshow_help_function
;
4626 restore_show_help_function (old_show_help_function
)
4627 Lisp_Object old_show_help_function
;
4629 Vshow_help_function
= old_show_help_function
;
4634 static pascal OSStatus
4635 menu_target_item_handler (next_handler
, event
, data
)
4636 EventHandlerCallRef next_handler
;
4642 MenuItemIndex menu_item
;
4645 int specpdl_count
= SPECPDL_INDEX ();
4647 /* Don't be bothered with the overflowed toolbar items menu. */
4648 if (!popup_activated ())
4649 return eventNotHandledErr
;
4651 err
= GetEventParameter (event
, kEventParamDirectObject
, typeMenuRef
,
4652 NULL
, sizeof (MenuRef
), NULL
, &menu
);
4654 err
= GetEventParameter (event
, kEventParamMenuItemIndex
,
4655 typeMenuItemIndex
, NULL
,
4656 sizeof (MenuItemIndex
), NULL
, &menu_item
);
4658 err
= GetMenuItemProperty (menu
, menu_item
,
4659 MAC_EMACS_CREATOR_CODE
, 'help',
4660 sizeof (Lisp_Object
), NULL
, &help
);
4664 /* Temporarily bind Vshow_help_function to Qnil because we don't
4665 want tooltips during menu tracking. */
4666 record_unwind_protect (restore_show_help_function
, Vshow_help_function
);
4667 Vshow_help_function
= Qnil
;
4669 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
4671 unbind_to (specpdl_count
, Qnil
);
4673 return err
== noErr
? noErr
: eventNotHandledErr
;
4676 /* Showing help echo string during menu tracking. */
4679 install_menu_target_item_handler ()
4681 static const EventTypeSpec specs
[] =
4682 {{kEventClassMenu
, kEventMenuTargetItem
}};
4684 return InstallApplicationEventHandler (NewEventHandlerUPP
4685 (menu_target_item_handler
),
4686 GetEventTypeCount (specs
),
4689 #endif /* TARGET_API_MAC_CARBON */
4691 /* Event handler function that pops down a menu on C-g. We can only pop
4692 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4694 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4695 static pascal OSStatus
4696 menu_quit_handler (nextHandler
, theEvent
, userData
)
4697 EventHandlerCallRef nextHandler
;
4703 UInt32 keyModifiers
;
4705 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
4706 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
4709 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
4710 typeUInt32
, NULL
, sizeof(UInt32
),
4711 NULL
, &keyModifiers
);
4713 if (err
== noErr
&& mac_quit_char_key_p (keyModifiers
, keyCode
))
4715 MenuRef menu
= userData
!= 0
4716 ? (MenuRef
)userData
: AcquireRootMenu ();
4718 CancelMenuTracking (menu
, true, 0);
4719 if (!userData
) ReleaseMenu (menu
);
4723 return CallNextEventHandler (nextHandler
, theEvent
);
4725 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4727 /* Add event handler to all menus that belong to KIND so we can detect
4728 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4729 when C-g is detected. NULL means the menu bar. If
4730 CancelMenuTracking isn't available, do nothing. */
4733 install_menu_quit_handler (kind
, root_menu
)
4734 enum mac_menu_kind kind
;
4737 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4738 static const EventTypeSpec typesList
[] =
4739 {{kEventClassKeyboard
, kEventRawKeyDown
}};
4742 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4743 if (CancelMenuTracking
== NULL
)
4746 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
4748 MenuRef menu
= GetMenuRef (id
);
4752 InstallMenuEventHandler (menu
, menu_quit_handler
,
4753 GetEventTypeCount (typesList
),
4754 typesList
, root_menu
, NULL
);
4756 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4763 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
4764 FRAME_PTR f
= p
->pointer
;
4765 MenuRef menu
= GetMenuRef (min_menu_id
[MAC_MENU_POPUP
]);
4769 /* Must reset this manually because the button release event is not
4770 passed to Emacs event loop. */
4771 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
4773 /* delete all menus */
4774 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
4775 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
4783 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4784 until the menu pops down. Return the selection. */
4787 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
4789 widget_value
*first_wv
;
4795 MenuRef menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
4796 int menu_item_choice
;
4797 int specpdl_count
= SPECPDL_INDEX ();
4799 InsertMenu (menu
, -1);
4800 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
4801 min_menu_id
[MAC_MENU_POPUP_SUB
]);
4803 /* Add event handler so we can detect C-g. */
4804 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
4805 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
4807 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
4809 /* Adjust coordinates to be root-window-relative. */
4810 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
4811 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
4813 /* Display the menu. */
4814 popup_activated_flag
= 1;
4815 menu_item_choice
= PopUpMenuSelect (menu
, y
, x
, 0);
4816 popup_activated_flag
= 0;
4818 /* Get the refcon to find the correct item */
4819 if (menu_item_choice
)
4821 MenuRef sel_menu
= GetMenuRef (HiWord (menu_item_choice
));
4824 GetMenuItemRefCon (sel_menu
, LoWord (menu_item_choice
),
4825 (UInt32
*) &result
);
4828 unbind_to (specpdl_count
, Qnil
);
4830 menu_item_selection
= result
;
4834 add_menu_item (menu
, pos
, wv
)
4839 #if TARGET_API_MAC_CARBON
4840 CFStringRef item_name
;
4845 if (name_is_separator (wv
->name
))
4846 AppendMenu (menu
, "\p-");
4849 AppendMenu (menu
, "\pX");
4851 #if TARGET_API_MAC_CARBON
4852 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
4854 if (wv
->key
!= NULL
)
4856 CFStringRef name
, key
;
4859 key
= cfstring_create_with_utf8_cstring (wv
->key
);
4860 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
4866 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
4867 CFRelease (item_name
);
4870 EnableMenuItem (menu
, pos
);
4872 DisableMenuItem (menu
, pos
);
4874 if (STRINGP (wv
->help
))
4875 SetMenuItemProperty (menu
, pos
, MAC_EMACS_CREATOR_CODE
, 'help',
4876 sizeof (Lisp_Object
), &wv
->help
);
4877 #else /* ! TARGET_API_MAC_CARBON */
4878 item_name
[sizeof (item_name
) - 1] = '\0';
4879 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
4880 if (wv
->key
!= NULL
)
4882 int len
= strlen (item_name
);
4884 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
4885 len
= strlen (item_name
);
4886 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
4889 SetMenuItemText (menu
, pos
, item_name
);
4892 EnableItem (menu
, pos
);
4894 DisableItem (menu
, pos
);
4895 #endif /* ! TARGET_API_MAC_CARBON */
4897 /* Draw radio buttons and tickboxes. */
4898 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
4899 || wv
->button_type
== BUTTON_TYPE_RADIO
))
4900 SetItemMark (menu
, pos
, checkMark
);
4902 SetItemMark (menu
, pos
, noMark
);
4904 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
4908 /* Construct native Mac OS menu based on widget_value tree. */
4911 fill_menu (menu
, wv
, kind
, submenu_id
)
4914 enum mac_menu_kind kind
;
4919 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
4921 add_menu_item (menu
, pos
, wv
);
4922 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
4924 MenuRef submenu
= NewMenu (submenu_id
, "\pX");
4926 InsertMenu (submenu
, -1);
4927 #if TARGET_API_MAC_CARBON
4928 SetMenuItemHierarchicalMenu (menu
, pos
, submenu
);
4930 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
4932 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
4939 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4940 the entire menu trees we supply, rather than just the menu bar item
4944 mac_fill_menubar (wv
, deep_p
)
4949 #if !TARGET_API_MAC_CARBON
4950 int title_changed_p
= 0;
4953 /* Clean up the menu bar when filled by the entire menu trees. */
4956 dispose_menus (MAC_MENU_MENU_BAR
, 0);
4957 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
4958 #if !TARGET_API_MAC_CARBON
4959 title_changed_p
= 1;
4963 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4964 titles as much as possible to minimize redraw (if !deep_p). */
4965 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
4966 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
4967 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
4968 wv
= wv
->next
, id
++)
4970 OSStatus err
= noErr
;
4972 #if TARGET_API_MAC_CARBON
4975 title
= CFStringCreateWithCString (NULL
, wv
->name
,
4976 kCFStringEncodingMacRoman
);
4980 strncpy (title
, wv
->name
, 255);
4985 menu
= GetMenuRef (id
);
4988 #if TARGET_API_MAC_CARBON
4989 CFStringRef old_title
;
4991 err
= CopyMenuTitleAsCFString (menu
, &old_title
);
4994 if (CFStringCompare (title
, old_title
, 0) != kCFCompareEqualTo
)
4997 if (id
+ 1 == min_menu_id
[MAC_MENU_MENU_BAR
+ 1]
4998 || GetMenuRef (id
+ 1) == NULL
)
5000 /* This is a workaround for Mac OS X 10.5 where
5001 just calling SetMenuTitleWithCFString fails
5002 to change the title of the last (Help) menu
5009 #endif /* MAC_OSX */
5010 err
= SetMenuTitleWithCFString (menu
, title
);
5012 CFRelease (old_title
);
5015 err
= SetMenuTitleWithCFString (menu
, title
);
5016 #else /* !TARGET_API_MAC_CARBON */
5017 if (!EqualString (title
, (*menu
)->menuData
, false, false))
5021 menu
= NewMenu (id
, title
);
5022 InsertMenu (menu
, GetMenuRef (id
+ 1) ? id
+ 1 : 0);
5023 title_changed_p
= 1;
5025 #endif /* !TARGET_API_MAC_CARBON */
5030 #if TARGET_API_MAC_CARBON
5031 err
= CreateNewMenu (id
, 0, &menu
);
5033 err
= SetMenuTitleWithCFString (menu
, title
);
5035 menu
= NewMenu (id
, title
);
5039 InsertMenu (menu
, 0);
5040 #if !TARGET_API_MAC_CARBON
5041 title_changed_p
= 1;
5045 #if TARGET_API_MAC_CARBON
5051 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
5055 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuRef (id
))
5057 dispose_menus (MAC_MENU_MENU_BAR
, id
);
5058 #if !TARGET_API_MAC_CARBON
5059 title_changed_p
= 1;
5063 #if !TARGET_API_MAC_CARBON
5064 if (title_changed_p
)
5068 /* Add event handler so we can detect C-g. */
5069 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
5070 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
5073 /* Dispose of menus that belong to KIND, and remove them from the menu
5074 list. ID is the lower bound of menu IDs that will be processed. */
5077 dispose_menus (kind
, id
)
5078 enum mac_menu_kind kind
;
5081 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
5083 MenuRef menu
= GetMenuRef (id
);
5098 MenuItemIndex menu_index
;
5100 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandQuit
, 1,
5101 &menu
, &menu_index
);
5103 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5104 EnableMenuCommand (NULL
, kHICommandPreferences
);
5105 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandPreferences
, 1,
5106 &menu
, &menu_index
);
5109 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5110 InsertMenuItemTextWithCFString (menu
, NULL
,
5111 0, kMenuItemAttrSeparator
, 0);
5112 InsertMenuItemTextWithCFString (menu
, CFSTR ("About Emacs"),
5113 0, 0, kHICommandAbout
);
5115 #else /* !MAC_OSX */
5116 #if TARGET_API_MAC_CARBON
5117 SetMenuItemCommandID (GetMenuRef (M_APPLE
), I_ABOUT
, kHICommandAbout
);
5123 /***********************************************************************
5125 ***********************************************************************/
5127 #if TARGET_API_MAC_CARBON
5128 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5129 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5130 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5131 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5132 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5133 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5134 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5136 extern EMACS_TIME timer_check
P_ ((int));
5137 static int quit_dialog_event_loop
;
5139 static pascal OSStatus
5140 mac_handle_dialog_event (next_handler
, event
, data
)
5141 EventHandlerCallRef next_handler
;
5145 OSStatus err
, result
= eventNotHandledErr
;
5146 WindowRef window
= (WindowRef
) data
;
5148 switch (GetEventClass (event
))
5150 case kEventClassCommand
:
5154 err
= GetEventParameter (event
, kEventParamDirectObject
,
5155 typeHICommand
, NULL
, sizeof (HICommand
),
5158 if (DIALOG_BUTTON_COMMAND_ID_P (command
.commandID
))
5160 SetWRefCon (window
, command
.commandID
);
5161 quit_dialog_event_loop
= 1;
5165 result
= CallNextEventHandler (next_handler
, event
);
5169 case kEventClassKeyboard
:
5174 result
= CallNextEventHandler (next_handler
, event
);
5175 if (result
!= eventNotHandledErr
)
5178 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
5179 typeChar
, NULL
, sizeof (char),
5184 case kEscapeCharCode
:
5185 quit_dialog_event_loop
= 1;
5190 UInt32 modifiers
, key_code
;
5192 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
5193 typeUInt32
, NULL
, sizeof (UInt32
),
5196 err
= GetEventParameter (event
, kEventParamKeyCode
,
5197 typeUInt32
, NULL
, sizeof (UInt32
),
5200 if (mac_quit_char_key_p (modifiers
, key_code
))
5201 quit_dialog_event_loop
= 1;
5212 if (quit_dialog_event_loop
)
5214 err
= QuitEventLoop (GetCurrentEventLoop ());
5223 install_dialog_event_handler (window
)
5226 static const EventTypeSpec specs
[] =
5227 {{kEventClassCommand
, kEventCommandProcess
},
5228 {kEventClassKeyboard
, kEventRawKeyDown
}};
5229 static EventHandlerUPP handle_dialog_eventUPP
= NULL
;
5231 if (handle_dialog_eventUPP
== NULL
)
5232 handle_dialog_eventUPP
= NewEventHandlerUPP (mac_handle_dialog_event
);
5233 return InstallWindowEventHandler (window
, handle_dialog_eventUPP
,
5234 GetEventTypeCount (specs
), specs
,
5239 pop_down_dialog (arg
)
5242 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
5243 WindowRef window
= p
->pointer
;
5247 if (popup_activated_flag
)
5248 EndAppModalStateForWindow (window
);
5249 DisposeWindow (window
);
5250 popup_activated_flag
= 0;
5257 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5259 menu_item_selection will be set to the selection. */
5262 create_and_show_dialog (f
, first_wv
)
5264 widget_value
*first_wv
;
5267 char *dialog_name
, *message
;
5268 int nb_buttons
, first_group_count
, i
, result
= 0;
5270 short buttons_height
, text_height
, inner_width
, inner_height
;
5271 Rect empty_rect
, *rects
;
5272 WindowRef window
= NULL
;
5273 ControlRef
*buttons
, default_button
= NULL
, text
;
5274 int specpdl_count
= SPECPDL_INDEX ();
5276 dialog_name
= first_wv
->name
;
5277 nb_buttons
= dialog_name
[1] - '0';
5278 first_group_count
= nb_buttons
- (dialog_name
[4] - '0');
5280 wv
= first_wv
->contents
;
5281 message
= wv
->value
;
5284 SetRect (&empty_rect
, 0, 0, 0, 0);
5286 /* Create dialog window. */
5287 err
= CreateNewWindow (kMovableModalWindowClass
,
5288 kWindowStandardHandlerAttribute
,
5289 &empty_rect
, &window
);
5292 record_unwind_protect (pop_down_dialog
, make_save_value (window
, 0));
5293 err
= SetThemeWindowBackground (window
, kThemeBrushMovableModalBackground
,
5297 err
= SetWindowTitleWithCFString (window
, (dialog_name
[0] == 'Q'
5298 ? CFSTR ("Question")
5299 : CFSTR ("Information")));
5301 /* Create button controls and measure their optimal bounds. */
5304 buttons
= alloca (sizeof (ControlRef
) * nb_buttons
);
5305 rects
= alloca (sizeof (Rect
) * nb_buttons
);
5306 for (i
= 0; i
< nb_buttons
; i
++)
5308 CFStringRef label
= cfstring_create_with_utf8_cstring (wv
->value
);
5314 err
= CreatePushButtonControl (window
, &empty_rect
,
5315 label
, &buttons
[i
]);
5323 err
= DisableControl (buttons
[i
]);
5325 err
= DeactivateControl (buttons
[i
]);
5328 else if (default_button
== NULL
)
5329 default_button
= buttons
[i
];
5335 rects
[i
] = empty_rect
;
5336 err
= GetBestControlRect (buttons
[i
], &rects
[i
], &unused
);
5342 OffsetRect (&rects
[i
], -rects
[i
].left
, -rects
[i
].top
);
5343 if (rects
[i
].right
< DIALOG_BUTTON_MIN_WIDTH
)
5344 rects
[i
].right
= DIALOG_BUTTON_MIN_WIDTH
;
5345 else if (rects
[i
].right
> DIALOG_MAX_INNER_WIDTH
)
5346 rects
[i
].right
= DIALOG_MAX_INNER_WIDTH
;
5348 command_id
= DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv
->call_data
);
5349 err
= SetControlCommandID (buttons
[i
], command_id
);
5357 /* Layout buttons. rects[i] is set relative to the bottom-right
5358 corner of the inner box. */
5361 short bottom
, right
, max_height
, left_align_shift
;
5363 inner_width
= DIALOG_MIN_INNER_WIDTH
;
5364 bottom
= right
= max_height
= 0;
5365 for (i
= 0; i
< nb_buttons
; i
++)
5367 if (right
- rects
[i
].right
< - inner_width
)
5369 if (i
!= first_group_count
5370 && right
- rects
[i
].right
>= - DIALOG_MAX_INNER_WIDTH
)
5371 inner_width
= - (right
- rects
[i
].right
);
5374 bottom
-= max_height
+ DIALOG_BUTTON_BUTTON_VERTICAL_SPACE
;
5375 right
= max_height
= 0;
5378 if (max_height
< rects
[i
].bottom
)
5379 max_height
= rects
[i
].bottom
;
5380 OffsetRect (&rects
[i
], right
- rects
[i
].right
,
5381 bottom
- rects
[i
].bottom
);
5382 right
= rects
[i
].left
- DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5383 if (i
== first_group_count
- 1)
5384 right
-= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5386 buttons_height
= - (bottom
- max_height
);
5388 left_align_shift
= - (inner_width
+ rects
[nb_buttons
- 1].left
);
5389 for (i
= nb_buttons
- 1; i
>= first_group_count
; i
--)
5391 if (bottom
!= rects
[i
].bottom
)
5393 left_align_shift
= - (inner_width
+ rects
[i
].left
);
5394 bottom
= rects
[i
].bottom
;
5396 OffsetRect (&rects
[i
], left_align_shift
, 0);
5400 /* Create a static text control and measure its bounds. */
5403 CFStringRef message_string
;
5406 message_string
= cfstring_create_with_utf8_cstring (message
);
5407 if (message_string
== NULL
)
5411 ControlFontStyleRec text_style
;
5413 text_style
.flags
= 0;
5414 SetRect (&bounds
, 0, 0, inner_width
, 0);
5415 err
= CreateStaticTextControl (window
, &bounds
, message_string
,
5416 &text_style
, &text
);
5417 CFRelease (message_string
);
5423 bounds
= empty_rect
;
5424 err
= GetBestControlRect (text
, &bounds
, &unused
);
5428 text_height
= bounds
.bottom
- bounds
.top
;
5429 if (text_height
< DIALOG_TEXT_MIN_HEIGHT
)
5430 text_height
= DIALOG_TEXT_MIN_HEIGHT
;
5434 /* Place buttons. */
5437 inner_height
= (text_height
+ DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5440 for (i
= 0; i
< nb_buttons
; i
++)
5442 OffsetRect (&rects
[i
], DIALOG_LEFT_MARGIN
+ inner_width
,
5443 DIALOG_TOP_MARGIN
+ inner_height
);
5444 SetControlBounds (buttons
[i
], &rects
[i
]);
5453 SetRect (&bounds
, DIALOG_LEFT_MARGIN
, DIALOG_TOP_MARGIN
,
5454 DIALOG_LEFT_MARGIN
+ inner_width
,
5455 DIALOG_TOP_MARGIN
+ text_height
);
5456 SetControlBounds (text
, &bounds
);
5459 /* Create the application icon at the upper-left corner. */
5462 ControlButtonContentInfo content
;
5464 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
5468 ProcessInfoRec pinfo
;
5473 content
.contentType
= kControlContentIconRef
;
5475 err
= GetProcessBundleLocation (&psn
, &app_location
);
5477 err
= GetIconRefFromFileInfo (&app_location
, 0, NULL
, 0, NULL
,
5478 kIconServicesNormalUsageFlag
,
5479 &content
.u
.iconRef
, &unused
);
5481 bzero (&pinfo
, sizeof (ProcessInfoRec
));
5482 pinfo
.processInfoLength
= sizeof (ProcessInfoRec
);
5483 pinfo
.processAppSpec
= &app_spec
;
5484 err
= GetProcessInformation (&psn
, &pinfo
);
5486 err
= GetIconRefFromFile (&app_spec
, &content
.u
.iconRef
, &unused
);
5492 SetRect (&bounds
, DIALOG_ICON_LEFT_MARGIN
, DIALOG_ICON_TOP_MARGIN
,
5493 DIALOG_ICON_LEFT_MARGIN
+ DIALOG_ICON_WIDTH
,
5494 DIALOG_ICON_TOP_MARGIN
+ DIALOG_ICON_HEIGHT
);
5495 err
= CreateIconControl (window
, &bounds
, &content
, true, &icon
);
5496 ReleaseIconRef (content
.u
.iconRef
);
5500 /* Show the dialog window and run event loop. */
5503 err
= SetWindowDefaultButton (window
, default_button
);
5505 err
= install_dialog_event_handler (window
);
5509 DIALOG_LEFT_MARGIN
+ inner_width
+ DIALOG_RIGHT_MARGIN
,
5510 DIALOG_TOP_MARGIN
+ inner_height
+ DIALOG_BOTTOM_MARGIN
,
5512 err
= RepositionWindow (window
, FRAME_MAC_WINDOW (f
),
5513 kWindowAlertPositionOnParentWindow
);
5517 SetWRefCon (window
, 0);
5518 ShowWindow (window
);
5519 BringToFront (window
);
5520 popup_activated_flag
= 1;
5521 err
= BeginAppModalStateForWindow (window
);
5525 EventTargetRef toolbox_dispatcher
= GetEventDispatcherTarget ();
5527 quit_dialog_event_loop
= 0;
5530 EMACS_TIME next_time
= timer_check (1);
5531 long secs
= EMACS_SECS (next_time
);
5532 long usecs
= EMACS_USECS (next_time
);
5533 EventTimeout timeout
;
5536 if (secs
< 0 || (secs
== 0 && usecs
== 0))
5538 /* Sometimes timer_check returns -1 (no timers) even if
5539 there are timers. So do a timeout anyway. */
5544 timeout
= (secs
* kEventDurationSecond
5545 + usecs
* kEventDurationMicrosecond
);
5546 err
= ReceiveNextEvent (0, NULL
, timeout
, kEventRemoveFromQueue
,
5550 SendEventToEventTarget (event
, toolbox_dispatcher
);
5551 ReleaseEvent (event
);
5553 #if 0 /* defined (MAC_OSX) */
5554 else if (err
!= eventLoopTimedOutErr
)
5556 if (err
== eventLoopQuitErr
)
5561 /* The return value of ReceiveNextEvent seems to be
5562 unreliable. Use our own global variable instead. */
5563 if (quit_dialog_event_loop
)
5573 UInt32 command_id
= GetWRefCon (window
);
5575 if (DIALOG_BUTTON_COMMAND_ID_P (command_id
))
5576 result
= DIALOG_BUTTON_COMMAND_ID_VALUE (command_id
);
5579 unbind_to (specpdl_count
, Qnil
);
5581 menu_item_selection
= result
;
5583 #else /* not TARGET_API_MAC_CARBON */
5584 #define DIALOG_WINDOW_RESOURCE 130
5587 mac_dialog (widget_value
*wv
)
5591 char **button_labels
;
5598 WindowRef window_ptr
;
5601 EventRecord event_record
;
5603 int control_part_code
;
5606 dialog_name
= wv
->name
;
5607 nb_buttons
= dialog_name
[1] - '0';
5608 left_count
= nb_buttons
- (dialog_name
[4] - '0');
5609 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
5610 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
5613 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
5614 strcpy (prompt
, wv
->value
);
5618 for (i
= 0; i
< nb_buttons
; i
++)
5620 button_labels
[i
] = wv
->value
;
5621 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
5622 strcpy (button_labels
[i
], wv
->value
);
5623 c2pstr (button_labels
[i
]);
5624 ref_cons
[i
] = (UInt32
) wv
->call_data
;
5628 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowRef
) -1);
5630 SetPortWindowPort (window_ptr
);
5633 /* Left and right margins in the dialog are 13 pixels each.*/
5635 /* Calculate width of dialog box: 8 pixels on each side of the text
5636 label in each button, 12 pixels between buttons. */
5637 for (i
= 0; i
< nb_buttons
; i
++)
5638 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
5640 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
5643 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
5645 SizeWindow (window_ptr
, dialog_width
, 78, 0);
5646 ShowWindow (window_ptr
);
5648 SetPortWindowPort (window_ptr
);
5653 DrawString (prompt
);
5656 for (i
= 0; i
< nb_buttons
; i
++)
5658 int button_width
= StringWidth (button_labels
[i
]) + 16;
5659 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
5660 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
5661 kControlPushButtonProc
, ref_cons
[i
]);
5662 left
+= button_width
+ 12;
5663 if (i
== left_count
- 1)
5670 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
5671 if (event_record
.what
== mouseDown
)
5673 part_code
= FindWindow (event_record
.where
, &window_ptr
);
5674 if (part_code
== inContent
)
5676 mouse
= event_record
.where
;
5677 GlobalToLocal (&mouse
);
5678 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
5679 if (control_part_code
== kControlButtonPart
)
5680 if (TrackControl (ch
, mouse
, NULL
))
5681 i
= GetControlReference (ch
);
5686 DisposeWindow (window_ptr
);
5690 #endif /* not TARGET_API_MAC_CARBON */
5693 /***********************************************************************
5695 ***********************************************************************/
5697 #if !TARGET_API_MAC_CARBON
5702 extern Lisp_Object Vselection_converter_alist
;
5703 extern Lisp_Object Qmac_scrap_name
, Qmac_ostype
;
5705 static ScrapFlavorType get_flavor_type_from_symbol
P_ ((Lisp_Object
,
5708 /* Get a reference to the selection corresponding to the symbol SYM.
5709 The reference is set to *SEL, and it becomes NULL if there's no
5710 corresponding selection. Clear the selection if CLEAR_P is
5714 mac_get_selection_from_symbol (sym
, clear_p
, sel
)
5719 OSStatus err
= noErr
;
5720 Lisp_Object str
= Fget (sym
, Qmac_scrap_name
);
5726 #if TARGET_API_MAC_CARBON
5728 CFStringRef scrap_name
= cfstring_create_with_string (str
);
5729 OptionBits options
= (clear_p
? kScrapClearNamedScrap
5730 : kScrapGetNamedScrap
);
5732 err
= GetScrapByName (scrap_name
, options
, sel
);
5733 CFRelease (scrap_name
);
5734 #else /* !MAC_OSX */
5736 err
= ClearCurrentScrap ();
5738 err
= GetCurrentScrap (sel
);
5739 #endif /* !MAC_OSX */
5740 #else /* !TARGET_API_MAC_CARBON */
5745 #endif /* !TARGET_API_MAC_CARBON */
5751 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5752 corresponding flavor type. If SEL is non-zero, the return value is
5753 non-zero only when the SEL has the flavor type. */
5755 static ScrapFlavorType
5756 get_flavor_type_from_symbol (sym
, sel
)
5760 Lisp_Object str
= Fget (sym
, Qmac_ostype
);
5761 ScrapFlavorType flavor_type
;
5763 if (STRINGP (str
) && SBYTES (str
) == 4)
5764 flavor_type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
5768 if (flavor_type
&& sel
)
5770 #if TARGET_API_MAC_CARBON
5772 ScrapFlavorFlags flags
;
5774 err
= GetScrapFlavorFlags (sel
, flavor_type
, &flags
);
5777 #else /* !TARGET_API_MAC_CARBON */
5778 SInt32 size
, offset
;
5780 size
= GetScrap (NULL
, flavor_type
, &offset
);
5783 #endif /* !TARGET_API_MAC_CARBON */
5789 /* Check if the symbol SYM has a corresponding selection target type. */
5792 mac_valid_selection_target_p (sym
)
5795 return get_flavor_type_from_symbol (sym
, 0) != 0;
5798 /* Clear the selection whose reference is *SEL. */
5801 mac_clear_selection (sel
)
5804 #if TARGET_API_MAC_CARBON
5806 return ClearScrap (sel
);
5810 err
= ClearCurrentScrap ();
5812 err
= GetCurrentScrap (sel
);
5815 #else /* !TARGET_API_MAC_CARBON */
5816 return ZeroScrap ();
5817 #endif /* !TARGET_API_MAC_CARBON */
5820 /* Get ownership information for SEL. Emacs can detect a change of
5821 the ownership by comparing saved and current values of the
5822 ownership information. */
5825 mac_get_selection_ownership_info (sel
)
5828 #if TARGET_API_MAC_CARBON
5829 return long_to_cons ((unsigned long) sel
);
5830 #else /* !TARGET_API_MAC_CARBON */
5831 ScrapStuffPtr scrap_info
= InfoScrap ();
5833 return make_number (scrap_info
->scrapCount
);
5834 #endif /* !TARGET_API_MAC_CARBON */
5837 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5840 mac_valid_selection_value_p (value
, target
)
5841 Lisp_Object value
, target
;
5843 return STRINGP (value
);
5846 /* Put Lisp object VALUE to the selection SEL. The target type is
5847 specified by TARGET. */
5850 mac_put_selection_value (sel
, target
, value
)
5852 Lisp_Object target
, value
;
5854 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, 0);
5856 if (flavor_type
== 0 || !STRINGP (value
))
5859 #if TARGET_API_MAC_CARBON
5860 return PutScrapFlavor (sel
, flavor_type
, kScrapFlavorMaskNone
,
5861 SBYTES (value
), SDATA (value
));
5862 #else /* !TARGET_API_MAC_CARBON */
5863 return PutScrap (SBYTES (value
), flavor_type
, SDATA (value
));
5864 #endif /* !TARGET_API_MAC_CARBON */
5867 /* Check if data for the target type TARGET is available in SEL. */
5870 mac_selection_has_target_p (sel
, target
)
5874 return get_flavor_type_from_symbol (target
, sel
) != 0;
5877 /* Get data for the target type TARGET from SEL and create a Lisp
5878 string. Return nil if failed to get data. */
5881 mac_get_selection_value (sel
, target
)
5886 Lisp_Object result
= Qnil
;
5887 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, sel
);
5888 #if TARGET_API_MAC_CARBON
5893 err
= GetScrapFlavorSize (sel
, flavor_type
, &size
);
5898 result
= make_uninit_string (size
);
5899 err
= GetScrapFlavorData (sel
, flavor_type
,
5900 &size
, SDATA (result
));
5903 else if (size
< SBYTES (result
))
5904 result
= make_unibyte_string (SDATA (result
), size
);
5906 while (STRINGP (result
) && size
> SBYTES (result
));
5911 SInt32 size
, offset
;
5914 size
= GetScrap (NULL
, flavor_type
, &offset
);
5917 handle
= NewHandle (size
);
5919 size
= GetScrap (handle
, flavor_type
, &offset
);
5921 result
= make_unibyte_string (*handle
, size
);
5922 DisposeHandle (handle
);
5929 /* Get the list of target types in SEL. The return value is a list of
5930 target type symbols possibly followed by scrap flavor type
5934 mac_get_selection_target_list (sel
)
5937 Lisp_Object result
= Qnil
, rest
, target
;
5938 #if TARGET_API_MAC_CARBON
5940 UInt32 count
, i
, type
;
5941 ScrapFlavorInfo
*flavor_info
= NULL
;
5942 Lisp_Object strings
= Qnil
;
5944 err
= GetScrapFlavorCount (sel
, &count
);
5946 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
5947 err
= GetScrapFlavorInfoList (sel
, &count
, flavor_info
);
5950 xfree (flavor_info
);
5953 if (flavor_info
== NULL
)
5956 for (rest
= Vselection_converter_alist
; CONSP (rest
); rest
= XCDR (rest
))
5958 ScrapFlavorType flavor_type
= 0;
5960 if (CONSP (XCAR (rest
))
5961 && (target
= XCAR (XCAR (rest
)),
5963 && (flavor_type
= get_flavor_type_from_symbol (target
, sel
)))
5965 result
= Fcons (target
, result
);
5966 #if TARGET_API_MAC_CARBON
5967 for (i
= 0; i
< count
; i
++)
5968 if (flavor_info
[i
].flavorType
== flavor_type
)
5970 flavor_info
[i
].flavorType
= 0;
5976 #if TARGET_API_MAC_CARBON
5979 for (i
= 0; i
< count
; i
++)
5980 if (flavor_info
[i
].flavorType
)
5982 type
= EndianU32_NtoB (flavor_info
[i
].flavorType
);
5983 strings
= Fcons (make_unibyte_string ((char *) &type
, 4), strings
);
5985 result
= nconc2 (result
, strings
);
5986 xfree (flavor_info
);
5994 /***********************************************************************
5996 ***********************************************************************/
5998 extern pascal OSErr mac_handle_apple_event
P_ ((const AppleEvent
*,
5999 AppleEvent
*, SInt32
));
6000 extern void cleanup_all_suspended_apple_events
P_ ((void));
6003 init_apple_event_handler ()
6008 /* Make sure we have Apple events before starting. */
6009 err
= Gestalt (gestaltAppleEventsAttr
, &result
);
6013 if (!(result
& (1 << gestaltAppleEventsPresent
)))
6016 err
= AEInstallEventHandler (typeWildCard
, typeWildCard
,
6017 #if TARGET_API_MAC_CARBON
6018 NewAEEventHandlerUPP (mac_handle_apple_event
),
6020 NewAEEventHandlerProc (mac_handle_apple_event
),
6026 atexit (cleanup_all_suspended_apple_events
);
6030 /***********************************************************************
6031 Drag and drop support
6032 ***********************************************************************/
6034 #if TARGET_API_MAC_CARBON
6035 extern Lisp_Object Vmac_dnd_known_types
;
6037 static pascal OSErr mac_do_track_drag
P_ ((DragTrackingMessage
, WindowRef
,
6039 static pascal OSErr mac_do_receive_drag
P_ ((WindowRef
, void *, DragRef
));
6040 static DragTrackingHandlerUPP mac_do_track_dragUPP
= NULL
;
6041 static DragReceiveHandlerUPP mac_do_receive_dragUPP
= NULL
;
6044 create_apple_event_from_drag_ref (drag
, num_types
, types
, result
)
6047 const FlavorType
*types
;
6056 err
= CountDragItems (drag
, &num_items
);
6059 err
= AECreateList (NULL
, 0, false, &items
);
6063 for (index
= 1; index
<= num_items
; index
++)
6066 DescType desc_type
= typeNull
;
6069 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6074 for (i
= 0; i
< num_types
; i
++)
6076 err
= GetFlavorDataSize (drag
, item
, types
[i
], &size
);
6079 buf
= xrealloc (buf
, size
);
6080 err
= GetFlavorData (drag
, item
, types
[i
], buf
, &size
, 0);
6084 desc_type
= types
[i
];
6089 err
= AEPutPtr (&items
, index
, desc_type
,
6090 desc_type
!= typeNull
? buf
: NULL
,
6091 desc_type
!= typeNull
? size
: 0);
6099 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
6101 err
= AEPutParamDesc (result
, keyDirectObject
, &items
);
6103 AEDisposeDesc (result
);
6106 AEDisposeDesc (&items
);
6112 mac_store_drag_event (window
, mouse_pos
, modifiers
, desc
)
6118 struct input_event buf
;
6122 buf
.kind
= DRAG_N_DROP_EVENT
;
6123 buf
.modifiers
= mac_to_emacs_modifiers (modifiers
, 0);
6124 buf
.timestamp
= TickCount () * (1000 / 60);
6125 XSETINT (buf
.x
, mouse_pos
.h
);
6126 XSETINT (buf
.y
, mouse_pos
.v
);
6127 XSETFRAME (buf
.frame_or_window
, mac_window_to_frame (window
));
6128 buf
.arg
= mac_aedesc_to_lisp (desc
);
6129 kbd_buffer_store_event (&buf
);
6133 mac_do_track_drag (message
, window
, refcon
, drag
)
6134 DragTrackingMessage message
;
6140 static int can_accept
;
6141 UInt16 num_items
, index
;
6143 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6144 return dragNotAcceptedErr
;
6148 case kDragTrackingEnterHandler
:
6149 err
= CountDragItems (drag
, &num_items
);
6153 for (index
= 1; index
<= num_items
; index
++)
6159 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6162 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6168 if (!(STRINGP (str
) && SBYTES (str
) == 4))
6170 type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6172 err
= GetFlavorFlags (drag
, item
, type
, &flags
);
6182 case kDragTrackingEnterWindow
:
6185 RgnHandle hilite_rgn
= NewRgn ();
6191 GetWindowPortBounds (window
, &r
);
6192 OffsetRect (&r
, -r
.left
, -r
.top
);
6193 RectRgn (hilite_rgn
, &r
);
6194 ShowDragHilite (drag
, hilite_rgn
, true);
6195 DisposeRgn (hilite_rgn
);
6197 SetThemeCursor (kThemeCopyArrowCursor
);
6201 case kDragTrackingInWindow
:
6204 case kDragTrackingLeaveWindow
:
6207 HideDragHilite (drag
);
6208 SetThemeCursor (kThemeArrowCursor
);
6212 case kDragTrackingLeaveHandler
:
6217 return dragNotAcceptedErr
;
6222 mac_do_receive_drag (window
, refcon
, drag
)
6229 Lisp_Object rest
, str
;
6231 AppleEvent apple_event
;
6235 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6236 return dragNotAcceptedErr
;
6239 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6242 if (STRINGP (str
) && SBYTES (str
) == 4)
6246 types
= xmalloc (sizeof (FlavorType
) * num_types
);
6248 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6251 if (STRINGP (str
) && SBYTES (str
) == 4)
6252 types
[i
++] = EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6255 err
= create_apple_event_from_drag_ref (drag
, num_types
, types
,
6260 err
= GetDragMouse (drag
, &mouse_pos
, NULL
);
6263 GlobalToLocal (&mouse_pos
);
6264 err
= GetDragModifiers (drag
, NULL
, NULL
, &modifiers
);
6268 UInt32 key_modifiers
= modifiers
;
6270 err
= AEPutParamPtr (&apple_event
, kEventParamKeyModifiers
,
6271 typeUInt32
, &key_modifiers
, sizeof (UInt32
));
6276 mac_store_drag_event (window
, mouse_pos
, 0, &apple_event
);
6277 AEDisposeDesc (&apple_event
);
6278 mac_wakeup_from_rne ();
6282 return dragNotAcceptedErr
;
6284 #endif /* TARGET_API_MAC_CARBON */
6287 install_drag_handler (window
)
6292 #if TARGET_API_MAC_CARBON
6293 if (mac_do_track_dragUPP
== NULL
)
6294 mac_do_track_dragUPP
= NewDragTrackingHandlerUPP (mac_do_track_drag
);
6295 if (mac_do_receive_dragUPP
== NULL
)
6296 mac_do_receive_dragUPP
= NewDragReceiveHandlerUPP (mac_do_receive_drag
);
6298 err
= InstallTrackingHandler (mac_do_track_dragUPP
, window
, NULL
);
6300 err
= InstallReceiveHandler (mac_do_receive_dragUPP
, window
, NULL
);
6307 remove_drag_handler (window
)
6310 #if TARGET_API_MAC_CARBON
6311 if (mac_do_track_dragUPP
)
6312 RemoveTrackingHandler (mac_do_track_dragUPP
, window
);
6313 if (mac_do_receive_dragUPP
)
6314 RemoveReceiveHandler (mac_do_receive_dragUPP
, window
);
6318 #if TARGET_API_MAC_CARBON
6319 /* Return default value for mac-dnd-known-types. */
6322 mac_dnd_default_known_types ()
6324 Lisp_Object result
= list4 (build_string ("hfs "), build_string ("utxt"),
6325 build_string ("TEXT"), build_string ("TIFF"));
6328 result
= Fcons (build_string ("furl"), result
);
6336 /***********************************************************************
6337 Services menu support
6338 ***********************************************************************/
6341 extern Lisp_Object Qservice
, Qpaste
, Qperform
;
6342 extern Lisp_Object Vmac_service_selection
;
6345 mac_store_service_event (event
)
6351 const EventParamName
*names
;
6352 const EventParamType
*types
;
6353 static const EventParamName names_pfm
[] =
6354 {kEventParamServiceMessageName
, kEventParamServiceUserData
};
6355 static const EventParamType types_pfm
[] =
6356 {typeCFStringRef
, typeCFStringRef
};
6358 switch (GetEventKind (event
))
6360 case kEventServicePaste
:
6367 case kEventServicePerform
:
6369 num_params
= sizeof (names_pfm
) / sizeof (names_pfm
[0]);
6378 err
= mac_store_event_ref_as_apple_event (0, 0, Qservice
, id_key
,
6386 copy_scrap_flavor_data (from_scrap
, to_scrap
, flavor_type
)
6387 ScrapRef from_scrap
, to_scrap
;
6388 ScrapFlavorType flavor_type
;
6391 Size size
, size_allocated
;
6394 err
= GetScrapFlavorSize (from_scrap
, flavor_type
, &size
);
6396 buf
= xmalloc (size
);
6399 size_allocated
= size
;
6400 err
= GetScrapFlavorData (from_scrap
, flavor_type
, &size
, buf
);
6406 else if (size_allocated
< size
)
6407 buf
= xrealloc (buf
, size
);
6417 err
= PutScrapFlavor (to_scrap
, flavor_type
, kScrapFlavorMaskNone
,
6427 mac_handle_service_event (call_ref
, event
, data
)
6428 EventHandlerCallRef call_ref
;
6432 OSStatus err
= noErr
;
6433 ScrapRef cur_scrap
, specific_scrap
;
6434 UInt32 event_kind
= GetEventKind (event
);
6435 CFMutableArrayRef copy_types
, paste_types
;
6438 ScrapFlavorType flavor_type
;
6440 /* Check if Vmac_service_selection is a valid selection that has a
6441 corresponding scrap. */
6442 if (!SYMBOLP (Vmac_service_selection
))
6443 err
= eventNotHandledErr
;
6445 err
= mac_get_selection_from_symbol (Vmac_service_selection
, 0, &cur_scrap
);
6446 if (!(err
== noErr
&& cur_scrap
))
6447 return eventNotHandledErr
;
6451 case kEventServiceGetTypes
:
6452 /* Set paste types. */
6453 err
= GetEventParameter (event
, kEventParamServicePasteTypes
,
6454 typeCFMutableArrayRef
, NULL
,
6455 sizeof (CFMutableArrayRef
), NULL
,
6460 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6462 if (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))
6464 get_flavor_type_from_symbol (XCAR (XCAR (rest
)), 0)))
6466 type
= CreateTypeStringWithOSType (flavor_type
);
6469 CFArrayAppendValue (paste_types
, type
);
6474 /* Set copy types. */
6475 err
= GetEventParameter (event
, kEventParamServiceCopyTypes
,
6476 typeCFMutableArrayRef
, NULL
,
6477 sizeof (CFMutableArrayRef
), NULL
,
6482 if (NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6485 goto copy_all_flavors
;
6487 case kEventServiceCopy
:
6488 err
= GetEventParameter (event
, kEventParamScrapRef
,
6490 sizeof (ScrapRef
), NULL
, &specific_scrap
);
6492 || NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6494 err
= eventNotHandledErr
;
6501 ScrapFlavorInfo
*flavor_info
= NULL
;
6502 ScrapFlavorFlags flags
;
6504 err
= GetScrapFlavorCount (cur_scrap
, &count
);
6506 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
6507 err
= GetScrapFlavorInfoList (cur_scrap
, &count
, flavor_info
);
6510 xfree (flavor_info
);
6513 if (flavor_info
== NULL
)
6516 for (i
= 0; i
< count
; i
++)
6518 flavor_type
= flavor_info
[i
].flavorType
;
6519 err
= GetScrapFlavorFlags (cur_scrap
, flavor_type
, &flags
);
6520 if (err
== noErr
&& !(flags
& kScrapFlavorMaskSenderOnly
))
6522 if (event_kind
== kEventServiceCopy
)
6523 err
= copy_scrap_flavor_data (cur_scrap
, specific_scrap
,
6525 else /* event_kind == kEventServiceGetTypes */
6527 type
= CreateTypeStringWithOSType (flavor_type
);
6530 CFArrayAppendValue (copy_types
, type
);
6536 xfree (flavor_info
);
6540 case kEventServicePaste
:
6541 case kEventServicePerform
:
6543 int data_exists_p
= 0;
6545 err
= GetEventParameter (event
, kEventParamScrapRef
, typeScrapRef
,
6546 NULL
, sizeof (ScrapRef
), NULL
,
6549 err
= mac_clear_selection (&cur_scrap
);
6551 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6554 if (! (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))))
6556 flavor_type
= get_flavor_type_from_symbol (XCAR (XCAR (rest
)),
6558 if (flavor_type
== 0)
6560 err
= copy_scrap_flavor_data (specific_scrap
, cur_scrap
,
6566 err
= eventNotHandledErr
;
6568 err
= mac_store_service_event (event
);
6574 err
= eventNotHandledErr
;
6579 install_service_handler ()
6581 static const EventTypeSpec specs
[] =
6582 {{kEventClassService
, kEventServiceGetTypes
},
6583 {kEventClassService
, kEventServiceCopy
},
6584 {kEventClassService
, kEventServicePaste
},
6585 {kEventClassService
, kEventServicePerform
}};
6587 return InstallApplicationEventHandler (NewEventHandlerUPP
6588 (mac_handle_service_event
),
6589 GetEventTypeCount (specs
),
6592 #endif /* MAC_OSX */
6595 /***********************************************************************
6597 ***********************************************************************/
6600 mac_toolbox_initialize ()
6602 any_help_event_p
= 0;
6607 init_apple_event_handler ();
6614 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6615 (do not change this comment) */