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 font
= FACE_FROM_ID (f
, glyph
->face_id
)->font
;
604 Fixed point_size
= Long2Fix (font
->mac_fontsize
);
605 short height
= row
->visible_height
;
606 short ascent
= row
->ascent
;
608 SetEventParameter (event
,
609 kEventParamTextInputReplyPointSize
,
610 typeFixed
, sizeof (Fixed
), &point_size
);
611 SetEventParameter (event
,
612 kEventParamTextInputReplyLineHeight
,
613 typeShortInteger
, sizeof (short), &height
);
614 SetEventParameter (event
,
615 kEventParamTextInputReplyLineAscent
,
616 typeShortInteger
, sizeof (short), &ascent
);
617 if (font
->mac_fontnum
!= -1)
623 err1
= FMGetFontFromFontFamilyInstance (font
->mac_fontnum
,
627 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
628 typeUInt32
, sizeof (UInt32
), &fm_font
);
631 long qd_font
= font
->mac_fontnum
;
633 SetEventParameter (event
, kEventParamTextInputReplyFont
,
634 typeLongInteger
, sizeof (long),
638 else if (font
->mac_style
)
643 err1
= ATSUGetAttribute (font
->mac_style
, kATSUFontTag
,
644 sizeof (ATSUFontID
), &font_id
,
647 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
648 typeUInt32
, sizeof (UInt32
), &font_id
);
656 err
= SetEventParameter (event
, kEventParamTextInputReplyPoint
,
657 typeQDPoint
, sizeof (Point
), &p
);
664 case kEventTextInputPosToOffset
:
667 Boolean leading_edge_p
= true;
671 enum window_part part
;
672 long region_class
= kTSMOutsideOfBody
, byte_offset
= 0;
674 err
= GetEventParameter (event
, kEventParamTextInputSendCurrentPoint
,
675 typeQDPoint
, NULL
, sizeof (Point
), NULL
,
680 GetEventParameter (event
, kEventParamTextInputReplyLeadingEdge
,
681 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
684 f
= mac_focus_frame (&one_mac_display_info
);
685 x
= point
.h
- (f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
686 y
= point
.v
- (f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
687 window
= window_from_coordinates (f
, x
, y
, &part
, 0, 0, 1);
688 if (WINDOWP (window
) && EQ (window
, f
->selected_window
))
693 /* Convert to window-relative pixel coordinates. */
694 w
= XWINDOW (window
);
695 frame_to_window_pixel_xy (w
, &x
, &y
);
697 /* Are we in a window whose display is up to date?
698 And verify the buffer's text has not changed. */
699 b
= XBUFFER (w
->buffer
);
701 && EQ (w
->window_end_valid
, w
->buffer
)
702 && XINT (w
->last_modified
) == BUF_MODIFF (b
)
703 && XINT (w
->last_overlay_modified
) == BUF_OVERLAY_MODIFF (b
))
705 int hpos
, vpos
, area
;
708 /* Find the glyph under X/Y. */
709 glyph
= x_y_to_hpos_vpos (w
, x
, y
, &hpos
, &vpos
, 0, 0, &area
);
711 if (glyph
!= NULL
&& area
== TEXT_AREA
)
713 byte_offset
= ((glyph
->charpos
- BUF_BEGV (b
))
715 region_class
= kTSMInsideOfBody
;
720 err
= SetEventParameter (event
, kEventParamTextInputReplyRegionClass
,
721 typeLongInteger
, sizeof (long),
724 err
= SetEventParameter (event
, kEventParamTextInputReplyTextOffset
,
725 typeLongInteger
, sizeof (long),
732 case kEventTextInputGetSelectedText
:
734 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
735 struct window
*w
= XWINDOW (f
->selected_window
);
736 struct buffer
*b
= XBUFFER (w
->buffer
);
739 UniChar
*characters
, c
;
741 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
742 /* Don't try to get buffer contents as the gap might be
746 mac_get_selected_range (w
, &sel_range
);
747 if (sel_range
.length
== 0)
749 Boolean leading_edge_p
;
751 err
= GetEventParameter (event
,
752 kEventParamTextInputReplyLeadingEdge
,
753 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
758 start
= BUF_BEGV (b
) + sel_range
.location
;
764 if (start
< BUF_BEGV (b
) || end
> BUF_ZV (b
))
769 start
= BUF_BEGV (b
) + sel_range
.location
;
770 end
= start
+ sel_range
.length
;
771 characters
= xmalloc (sel_range
.length
* sizeof (UniChar
));
774 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
, characters
))
775 err
= SetEventParameter (event
, kEventParamTextInputReplyText
,
777 sel_range
.length
* sizeof (UniChar
),
779 if (characters
!= &c
)
793 err
= mac_store_event_ref_as_apple_event (0, 0, Qtext_input
, id_key
,
799 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
800 static pascal OSStatus
801 mac_handle_document_access_event (next_handler
, event
, data
)
802 EventHandlerCallRef next_handler
;
806 OSStatus err
, result
;
807 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
809 result
= CallNextEventHandler (next_handler
, event
);
810 if (result
!= eventNotHandledErr
)
813 switch (GetEventKind (event
))
815 case kEventTSMDocumentAccessGetLength
:
817 CFIndex count
= mac_ax_number_of_characters (f
);
819 err
= SetEventParameter (event
, kEventParamTSMDocAccessCharacterCount
,
820 typeCFIndex
, sizeof (CFIndex
), &count
);
826 case kEventTSMDocumentAccessGetSelectedRange
:
830 mac_ax_selected_text_range (f
, &sel_range
);
831 err
= SetEventParameter (event
,
832 kEventParamTSMDocAccessReplyCharacterRange
,
833 typeCFRange
, sizeof (CFRange
), &sel_range
);
839 case kEventTSMDocumentAccessGetCharacters
:
841 struct buffer
*b
= XBUFFER (XWINDOW (f
->selected_window
)->buffer
);
846 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
847 /* Don't try to get buffer contents as the gap might be
851 err
= GetEventParameter (event
,
852 kEventParamTSMDocAccessSendCharacterRange
,
853 typeCFRange
, NULL
, sizeof (CFRange
), NULL
,
856 err
= GetEventParameter (event
,
857 kEventParamTSMDocAccessSendCharactersPtr
,
858 typePtr
, NULL
, sizeof (Ptr
), NULL
,
863 start
= BUF_BEGV (b
) + range
.location
;
864 end
= start
+ range
.length
;
865 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
,
866 (UniChar
*) characters
))
881 install_application_handler ()
883 OSStatus err
= noErr
;
887 static const EventTypeSpec specs
[] =
888 {{kEventClassKeyboard
, kEventRawKeyDown
},
889 {kEventClassKeyboard
, kEventRawKeyRepeat
},
890 {kEventClassKeyboard
, kEventRawKeyUp
}};
892 err
= InstallApplicationEventHandler (NewEventHandlerUPP
893 (mac_handle_keyboard_event
),
894 GetEventTypeCount (specs
),
900 static const EventTypeSpec specs
[] =
901 {{kEventClassCommand
, kEventCommandProcess
}};
903 err
= InstallApplicationEventHandler (NewEventHandlerUPP
904 (mac_handle_command_event
),
905 GetEventTypeCount (specs
),
911 static const EventTypeSpec specs
[] =
912 {{kEventClassMouse
, kEventMouseWheelMoved
}};
914 err
= InstallApplicationEventHandler (NewEventHandlerUPP
915 (mac_handle_mouse_event
),
916 GetEventTypeCount (specs
),
923 static const EventTypeSpec specs
[] =
924 {{kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
},
925 {kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
},
926 {kEventClassTextInput
, kEventTextInputOffsetToPos
},
928 {kEventClassTextInput
, kEventTextInputPosToOffset
},
929 {kEventClassTextInput
, kEventTextInputGetSelectedText
}
933 err
= InstallApplicationEventHandler (NewEventHandlerUPP
934 (mac_handle_text_input_event
),
935 GetEventTypeCount (specs
),
939 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
942 static const EventTypeSpec specs
[] =
943 {{kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetLength
},
944 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetSelectedRange
},
945 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetCharacters
}};
947 err
= InstallApplicationEventHandler (mac_handle_document_access_event
,
948 GetEventTypeCount (specs
),
955 err
= install_menu_target_item_handler ();
959 err
= install_service_handler ();
964 #endif /* TARGET_API_MAC_CARBON */
967 /************************************************************************
969 ************************************************************************/
971 #define DEFAULT_NUM_COLS 80
973 #define MIN_DOC_SIZE 64
974 #define MAX_DOC_SIZE 32767
977 static OSErr install_drag_handler
P_ ((WindowRef
));
978 static void remove_drag_handler
P_ ((WindowRef
));
981 static void mac_prepare_for_quickdraw
P_ ((struct frame
*));
984 extern void mac_handle_visibility_change
P_ ((struct frame
*));
985 extern void mac_handle_origin_change
P_ ((struct frame
*));
986 extern void mac_handle_size_change
P_ ((struct frame
*, int, int));
988 #if TARGET_API_MAC_CARBON
990 extern Lisp_Object Qwindow
;
991 extern Lisp_Object Qtoolbar_switch_mode
;
996 do_window_update (WindowRef win
)
998 struct frame
*f
= mac_window_to_frame (win
);
1002 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1004 if (win
!= tip_window
)
1006 if (f
->async_visible
== 0)
1008 /* Update events may occur when a frame gets iconified. */
1010 f
->async_visible
= 1;
1011 f
->async_iconified
= 0;
1012 SET_FRAME_GARBAGED (f
);
1018 #if TARGET_API_MAC_CARBON
1019 RgnHandle region
= NewRgn ();
1021 GetPortVisibleRegion (GetWindowPort (win
), region
);
1022 GetRegionBounds (region
, &r
);
1023 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1025 mac_prepare_for_quickdraw (f
);
1027 UpdateControls (win
, region
);
1028 DisposeRgn (region
);
1030 r
= (*win
->visRgn
)->rgnBBox
;
1031 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1032 UpdateControls (win
, win
->visRgn
);
1041 is_emacs_window (WindowRef win
)
1043 Lisp_Object tail
, frame
;
1048 FOR_EACH_FRAME (tail
, frame
)
1049 if (FRAME_MAC_P (XFRAME (frame
)))
1050 if (FRAME_MAC_WINDOW (XFRAME (frame
)) == win
)
1056 /* Handle drags in size box. Based on code contributed by Ben
1057 Mesander and IM - Window Manager A. */
1060 do_grow_window (w
, e
)
1062 const EventRecord
*e
;
1065 int rows
, columns
, width
, height
;
1066 struct frame
*f
= mac_window_to_frame (w
);
1067 XSizeHints
*size_hints
= FRAME_SIZE_HINTS (f
);
1068 int min_width
= MIN_DOC_SIZE
, min_height
= MIN_DOC_SIZE
;
1069 #if TARGET_API_MAC_CARBON
1075 if (size_hints
->flags
& PMinSize
)
1077 min_width
= size_hints
->min_width
;
1078 min_height
= size_hints
->min_height
;
1080 SetRect (&limit_rect
, min_width
, min_height
, MAX_DOC_SIZE
, MAX_DOC_SIZE
);
1082 #if TARGET_API_MAC_CARBON
1083 if (!ResizeWindow (w
, e
->where
, &limit_rect
, &new_rect
))
1085 height
= new_rect
.bottom
- new_rect
.top
;
1086 width
= new_rect
.right
- new_rect
.left
;
1088 grow_size
= GrowWindow (w
, e
->where
, &limit_rect
);
1089 /* see if it really changed size */
1092 height
= HiWord (grow_size
);
1093 width
= LoWord (grow_size
);
1096 if (width
!= FRAME_PIXEL_WIDTH (f
)
1097 || height
!= FRAME_PIXEL_HEIGHT (f
))
1099 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1100 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1102 x_set_window_size (f
, 0, columns
, rows
);
1106 #if TARGET_API_MAC_CARBON
1108 mac_get_ideal_size (f
)
1111 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1112 WindowRef w
= FRAME_MAC_WINDOW (f
);
1115 int height
, width
, columns
, rows
;
1117 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1118 ideal_size
.v
= dpyinfo
->height
;
1119 IsWindowInStandardState (w
, &ideal_size
, &standard_rect
);
1120 /* Adjust the standard size according to character boundaries. */
1121 width
= standard_rect
.right
- standard_rect
.left
;
1122 height
= standard_rect
.bottom
- standard_rect
.top
;
1123 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1124 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1125 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, columns
);
1126 ideal_size
.v
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1131 static pascal OSStatus
1132 mac_handle_window_event (next_handler
, event
, data
)
1133 EventHandlerCallRef next_handler
;
1138 OSStatus err
, result
= eventNotHandledErr
;
1141 XSizeHints
*size_hints
;
1143 err
= GetEventParameter (event
, kEventParamDirectObject
, typeWindowRef
,
1144 NULL
, sizeof (WindowRef
), NULL
, &wp
);
1146 return eventNotHandledErr
;
1148 f
= mac_window_to_frame (wp
);
1149 switch (GetEventKind (event
))
1151 /* -- window refresh events -- */
1153 case kEventWindowUpdate
:
1154 result
= CallNextEventHandler (next_handler
, event
);
1155 if (result
!= eventNotHandledErr
)
1158 do_window_update (wp
);
1162 /* -- window state change events -- */
1164 case kEventWindowShowing
:
1165 size_hints
= FRAME_SIZE_HINTS (f
);
1166 if (!(size_hints
->flags
& (USPosition
| PPosition
)))
1168 struct frame
*sf
= SELECTED_FRAME ();
1170 if (!(FRAME_MAC_P (sf
) && sf
->async_visible
))
1171 RepositionWindow (wp
, NULL
, kWindowCenterOnMainScreen
);
1174 RepositionWindow (wp
, FRAME_MAC_WINDOW (sf
),
1175 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1176 kWindowCascadeStartAtParentWindowScreen
1178 kWindowCascadeOnParentWindowScreen
1182 /* This is a workaround. RepositionWindow fails to put
1183 a window at the cascading position when its parent
1184 window has a Carbon HIToolbar. */
1185 if ((f
->left_pos
== sf
->left_pos
1186 && f
->top_pos
== sf
->top_pos
)
1187 || (f
->left_pos
== sf
->left_pos
+ 10 * 2
1188 && f
->top_pos
== sf
->top_pos
+ 32 * 2))
1189 MoveWindowStructure (wp
, sf
->left_pos
+ 10, sf
->top_pos
+ 32);
1196 case kEventWindowHiding
:
1197 /* Before unmapping the window, update the WM_SIZE_HINTS
1198 property to claim that the current position of the window is
1199 user-specified, rather than program-specified, so that when
1200 the window is mapped again, it will be placed at the same
1201 location, without forcing the user to position it by hand
1202 again (they have already done that once for this window.) */
1203 x_wm_set_size_hint (f
, (long) 0, 1);
1207 case kEventWindowShown
:
1208 case kEventWindowHidden
:
1209 case kEventWindowCollapsed
:
1210 case kEventWindowExpanded
:
1211 mac_handle_visibility_change (f
);
1215 case kEventWindowBoundsChanging
:
1216 result
= CallNextEventHandler (next_handler
, event
);
1217 if (result
!= eventNotHandledErr
)
1220 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1221 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1225 size_hints
= FRAME_SIZE_HINTS (f
);
1226 if ((attributes
& kWindowBoundsChangeUserResize
)
1227 && ((size_hints
->flags
& (PResizeInc
| PBaseSize
| PMinSize
))
1228 == (PResizeInc
| PBaseSize
| PMinSize
)))
1233 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1234 typeQDRectangle
, NULL
, sizeof (Rect
),
1239 width
= bounds
.right
- bounds
.left
;
1240 height
= bounds
.bottom
- bounds
.top
;
1242 if (width
< size_hints
->min_width
)
1243 width
= size_hints
->min_width
;
1245 width
= size_hints
->base_width
1246 + (int) ((width
- size_hints
->base_width
)
1247 / (float) size_hints
->width_inc
+ .5)
1248 * size_hints
->width_inc
;
1250 if (height
< size_hints
->min_height
)
1251 height
= size_hints
->min_height
;
1253 height
= size_hints
->base_height
1254 + (int) ((height
- size_hints
->base_height
)
1255 / (float) size_hints
->height_inc
+ .5)
1256 * size_hints
->height_inc
;
1258 bounds
.right
= bounds
.left
+ width
;
1259 bounds
.bottom
= bounds
.top
+ height
;
1260 SetEventParameter (event
, kEventParamCurrentBounds
,
1261 typeQDRectangle
, sizeof (Rect
), &bounds
);
1266 case kEventWindowBoundsChanged
:
1267 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1268 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1272 if (attributes
& kWindowBoundsChangeSizeChanged
)
1276 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1277 typeQDRectangle
, NULL
, sizeof (Rect
),
1283 width
= bounds
.right
- bounds
.left
;
1284 height
= bounds
.bottom
- bounds
.top
;
1285 mac_handle_size_change (f
, width
, height
);
1286 mac_wakeup_from_rne ();
1290 if (attributes
& kWindowBoundsChangeOriginChanged
)
1291 mac_handle_origin_change (f
);
1296 /* -- window action events -- */
1298 case kEventWindowClose
:
1300 struct input_event buf
;
1303 buf
.kind
= DELETE_WINDOW_EVENT
;
1304 XSETFRAME (buf
.frame_or_window
, f
);
1306 kbd_buffer_store_event (&buf
);
1311 case kEventWindowGetIdealSize
:
1312 result
= CallNextEventHandler (next_handler
, event
);
1313 if (result
!= eventNotHandledErr
)
1317 Point ideal_size
= mac_get_ideal_size (f
);
1319 err
= SetEventParameter (event
, kEventParamDimensions
,
1320 typeQDPoint
, sizeof (Point
), &ideal_size
);
1327 case kEventWindowToolbarSwitchMode
:
1329 static const EventParamName names
[] = {kEventParamDirectObject
,
1330 kEventParamWindowMouseLocation
,
1331 kEventParamKeyModifiers
,
1332 kEventParamMouseButton
,
1333 kEventParamClickCount
,
1334 kEventParamMouseChord
};
1335 static const EventParamType types
[] = {typeWindowRef
,
1341 int num_params
= sizeof (names
) / sizeof (names
[0]);
1343 err
= mac_store_event_ref_as_apple_event (0, 0,
1345 Qtoolbar_switch_mode
,
1355 /* -- window focus events -- */
1357 case kEventWindowFocusAcquired
:
1358 err
= mac_tsm_resume ();
1363 case kEventWindowFocusRelinquish
:
1364 err
= mac_tsm_suspend ();
1378 /* Handle clicks in zoom box. Calculation of "standard state" based
1379 on code in IM - Window Manager A and code contributed by Ben
1380 Mesander. The standard state of an Emacs window is 80-characters
1381 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1384 do_zoom_window (WindowRef w
, int zoom_in_or_out
)
1386 Rect zoom_rect
, port_rect
;
1388 struct frame
*f
= mac_window_to_frame (w
);
1389 #if TARGET_API_MAC_CARBON
1390 Point ideal_size
= mac_get_ideal_size (f
);
1392 GetWindowBounds (w
, kWindowContentRgn
, &port_rect
);
1393 if (IsWindowInStandardState (w
, &ideal_size
, &zoom_rect
)
1394 && port_rect
.left
== zoom_rect
.left
1395 && port_rect
.top
== zoom_rect
.top
)
1396 zoom_in_or_out
= inZoomIn
;
1398 zoom_in_or_out
= inZoomOut
;
1401 mac_clear_area (f
, 0, 0, port_rect
.right
- port_rect
.left
,
1402 port_rect
.bottom
- port_rect
.top
);
1404 ZoomWindowIdeal (w
, zoom_in_or_out
, &ideal_size
);
1405 #else /* not TARGET_API_MAC_CARBON */
1408 int w_title_height
, rows
;
1409 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1411 GetPort (&save_port
);
1413 SetPortWindowPort (w
);
1415 /* Clear window to avoid flicker. */
1416 EraseRect (&(w
->portRect
));
1417 if (zoom_in_or_out
== inZoomOut
)
1419 SetPt (&top_left
, w
->portRect
.left
, w
->portRect
.top
);
1420 LocalToGlobal (&top_left
);
1422 /* calculate height of window's title bar */
1423 w_title_height
= top_left
.v
- 1
1424 - (**((WindowPeek
) w
)->strucRgn
).rgnBBox
.top
+ GetMBarHeight ();
1426 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1427 zoom_rect
= qd
.screenBits
.bounds
;
1428 zoom_rect
.top
+= w_title_height
;
1429 InsetRect (&zoom_rect
, 8, 4); /* not too tight */
1431 zoom_rect
.right
= zoom_rect
.left
1432 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1434 /* Adjust the standard size according to character boundaries. */
1435 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, zoom_rect
.bottom
- zoom_rect
.top
);
1437 zoom_rect
.top
+ FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1439 (**((WStateDataHandle
) ((WindowPeek
) w
)->dataHandle
)).stdState
1443 ZoomWindow (w
, zoom_in_or_out
, f
== mac_focus_frame (dpyinfo
));
1445 SetPort (save_port
);
1446 #endif /* not TARGET_API_MAC_CARBON */
1448 #if !TARGET_API_MAC_CARBON
1449 /* retrieve window size and update application values */
1450 port_rect
= w
->portRect
;
1451 height
= port_rect
.bottom
- port_rect
.top
;
1452 width
= port_rect
.right
- port_rect
.left
;
1454 mac_handle_size_change (f
, width
, height
);
1455 mac_handle_origin_change (f
);
1460 install_window_handler (window
)
1463 OSStatus err
= noErr
;
1465 #if TARGET_API_MAC_CARBON
1468 static const EventTypeSpec specs
[] =
1470 /* -- window refresh events -- */
1471 {kEventClassWindow
, kEventWindowUpdate
},
1472 /* -- window state change events -- */
1473 {kEventClassWindow
, kEventWindowShowing
},
1474 {kEventClassWindow
, kEventWindowHiding
},
1475 {kEventClassWindow
, kEventWindowShown
},
1476 {kEventClassWindow
, kEventWindowHidden
},
1477 {kEventClassWindow
, kEventWindowCollapsed
},
1478 {kEventClassWindow
, kEventWindowExpanded
},
1479 {kEventClassWindow
, kEventWindowBoundsChanging
},
1480 {kEventClassWindow
, kEventWindowBoundsChanged
},
1481 /* -- window action events -- */
1482 {kEventClassWindow
, kEventWindowClose
},
1483 {kEventClassWindow
, kEventWindowGetIdealSize
},
1485 {kEventClassWindow
, kEventWindowToolbarSwitchMode
},
1488 /* -- window focus events -- */
1489 {kEventClassWindow
, kEventWindowFocusAcquired
},
1490 {kEventClassWindow
, kEventWindowFocusRelinquish
},
1493 static EventHandlerUPP handle_window_eventUPP
= NULL
;
1495 if (handle_window_eventUPP
== NULL
)
1496 handle_window_eventUPP
= NewEventHandlerUPP (mac_handle_window_event
);
1498 err
= InstallWindowEventHandler (window
, handle_window_eventUPP
,
1499 GetEventTypeCount (specs
),
1505 err
= install_drag_handler (window
);
1511 remove_window_handler (window
)
1514 remove_drag_handler (window
);
1518 mac_get_window_bounds (f
, inner
, outer
)
1520 Rect
*inner
, *outer
;
1522 #if TARGET_API_MAC_CARBON
1523 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, inner
);
1524 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, outer
);
1525 #else /* not TARGET_API_MAC_CARBON */
1526 RgnHandle region
= NewRgn ();
1528 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, region
);
1529 *inner
= (*region
)->rgnBBox
;
1530 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, region
);
1531 *outer
= (*region
)->rgnBBox
;
1532 DisposeRgn (region
);
1533 #endif /* not TARGET_API_MAC_CARBON */
1537 mac_get_frame_bounds (f
, r
)
1541 #if TARGET_API_MAC_CARBON
1542 return GetWindowPortBounds (FRAME_MAC_WINDOW (f
), r
);
1544 *r
= FRAME_MAC_WINDOW (f
)->portRect
;
1551 mac_get_frame_mouse (f
, point
)
1555 #if TARGET_API_MAC_CARBON
1556 GetGlobalMouse (point
);
1557 point
->h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1558 point
->v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1560 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1566 mac_convert_frame_point_to_global (f
, x
, y
)
1570 *x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1571 *y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1574 #if TARGET_API_MAC_CARBON
1576 mac_update_proxy_icon (f
)
1580 Lisp_Object file_name
=
1581 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
)->filename
;
1582 Window w
= FRAME_MAC_WINDOW (f
);
1583 AliasHandle alias
= NULL
;
1585 err
= GetWindowProxyAlias (w
, &alias
);
1586 if (err
== errWindowDoesNotHaveProxy
&& !STRINGP (file_name
))
1589 if (STRINGP (file_name
))
1593 FSRef fref
, fref_proxy
;
1595 FSSpec fss
, fss_proxy
;
1598 Lisp_Object encoded_file_name
= ENCODE_FILE (file_name
);
1601 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1602 SBYTES (encoded_file_name
), typeFSRef
, &desc
);
1604 SetPortWindowPort (w
);
1605 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1606 SBYTES (encoded_file_name
), typeFSS
, &desc
);
1611 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
1613 err
= AEGetDescData (&desc
, &fss
, sizeof (FSSpec
));
1615 AEDisposeDesc (&desc
);
1621 /* (FS)ResolveAlias never sets `changed' to true if
1622 `alias' is minimal. */
1624 err
= FSResolveAlias (NULL
, alias
, &fref_proxy
, &changed
);
1626 err
= FSCompareFSRefs (&fref
, &fref_proxy
);
1628 err
= ResolveAlias (NULL
, alias
, &fss_proxy
, &changed
);
1630 err
= !(fss
.vRefNum
== fss_proxy
.vRefNum
1631 && fss
.parID
== fss_proxy
.parID
1632 && EqualString (fss
.name
, fss_proxy
.name
,
1636 if (err
!= noErr
|| alias
== NULL
)
1639 DisposeHandle ((Handle
) alias
);
1641 err
= FSNewAliasMinimal (&fref
, &alias
);
1643 err
= NewAliasMinimal (&fss
, &alias
);
1650 err
= SetWindowProxyAlias (w
, alias
);
1654 DisposeHandle ((Handle
) alias
);
1656 if (err
!= noErr
|| !STRINGP (file_name
))
1657 RemoveWindowProxy (w
);
1661 /* Mac replacement for XSetWindowBackground. */
1664 mac_set_frame_window_background (f
, color
)
1666 unsigned long color
;
1668 WindowRef w
= FRAME_MAC_WINDOW (f
);
1669 #if !TARGET_API_MAC_CARBON
1670 AuxWinHandle aw_handle
;
1671 CTabHandle ctab_handle
;
1672 ColorSpecPtr ct_table
;
1677 bg_color
.red
= RED16_FROM_ULONG (color
);
1678 bg_color
.green
= GREEN16_FROM_ULONG (color
);
1679 bg_color
.blue
= BLUE16_FROM_ULONG (color
);
1681 #if TARGET_API_MAC_CARBON
1682 SetWindowContentColor (w
, &bg_color
);
1684 if (GetAuxWin (w
, &aw_handle
))
1686 ctab_handle
= (*aw_handle
)->awCTable
;
1687 HandToHand ((Handle
*) &ctab_handle
);
1688 ct_table
= (*ctab_handle
)->ctTable
;
1689 ct_size
= (*ctab_handle
)->ctSize
;
1690 while (ct_size
> -1)
1692 if (ct_table
->value
== 0)
1694 ct_table
->rgb
= bg_color
;
1695 CTabChanged (ctab_handle
);
1696 SetWinColor (w
, (WCTabHandle
) ctab_handle
);
1704 /* Flush display of frame F, or of all frames if F is null. */
1710 #if TARGET_API_MAC_CARBON
1713 mac_prepare_for_quickdraw (f
);
1716 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f
)), NULL
);
1718 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL
);
1725 mac_flush_display_optional (f
)
1729 mac_prepare_for_quickdraw (f
);
1735 mac_update_begin (f
)
1738 #if TARGET_API_MAC_CARBON
1739 /* During update of a frame, availability of input events is
1740 periodically checked with ReceiveNextEvent if
1741 redisplay-dont-pause is nil. That normally flushes window buffer
1742 changes for every check, and thus screen update looks waving even
1743 if no input is available. So we disable screen updates during
1744 update of a frame. */
1745 DisableScreenUpdates ();
1753 #if TARGET_API_MAC_CARBON
1754 EnableScreenUpdates ();
1759 mac_frame_up_to_date (f
)
1762 /* Nothing to do. */
1766 mac_create_frame_window (f
, tooltip_p
)
1771 #if TARGET_API_MAC_CARBON
1772 WindowClass window_class
;
1773 WindowAttributes attributes
;
1777 Boolean go_away_flag
;
1782 SetRect (&r
, f
->left_pos
, f
->top_pos
,
1783 f
->left_pos
+ FRAME_PIXEL_WIDTH (f
),
1784 f
->top_pos
+ FRAME_PIXEL_HEIGHT (f
));
1785 #if TARGET_API_MAC_CARBON
1786 window_class
= kDocumentWindowClass
;
1787 attributes
= (kWindowStandardDocumentAttributes
1789 | kWindowToolbarButtonAttribute
1793 proc_id
= zoomDocProc
;
1794 behind
= (WindowRef
) -1;
1795 go_away_flag
= true;
1800 SetRect (&r
, 0, 0, 1, 1);
1801 #if TARGET_API_MAC_CARBON
1802 window_class
= kHelpWindowClass
;
1803 attributes
= (kWindowNoUpdatesAttribute
1804 | kWindowNoActivatesAttribute
1805 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1806 | kWindowIgnoreClicksAttribute
1810 proc_id
= plainDBox
;
1812 go_away_flag
= false;
1816 #if TARGET_API_MAC_CARBON
1817 CreateNewWindow (window_class
, attributes
, &r
, &FRAME_MAC_WINDOW (f
));
1818 if (FRAME_MAC_WINDOW (f
))
1820 SetWRefCon (FRAME_MAC_WINDOW (f
), (long) f
->output_data
.mac
);
1822 if (install_window_handler (FRAME_MAC_WINDOW (f
)) != noErr
)
1824 DisposeWindow (FRAME_MAC_WINDOW (f
));
1825 FRAME_MAC_WINDOW (f
) = NULL
;
1828 #else /* !TARGET_API_MAC_CARBON */
1829 FRAME_MAC_WINDOW (f
)
1830 = NewCWindow (NULL
, &r
, "\p", false, proc_id
, behind
, go_away_flag
,
1831 (long) f
->output_data
.mac
);
1832 #endif /* !TARGET_API_MAC_CARBON */
1833 /* so that update events can find this mac_output struct */
1834 f
->output_data
.mac
->mFP
= f
; /* point back to emacs frame */
1838 if (FRAME_MAC_WINDOW (f
))
1840 ControlRef root_control
;
1842 if (CreateRootControl (FRAME_MAC_WINDOW (f
), &root_control
) != noErr
)
1844 DisposeWindow (FRAME_MAC_WINDOW (f
));
1845 FRAME_MAC_WINDOW (f
) = NULL
;
1851 /* Dispose of the Mac window of the frame F. */
1854 mac_dispose_frame_window (f
)
1857 WindowRef window
= FRAME_MAC_WINDOW (f
);
1859 if (window
!= tip_window
)
1860 remove_window_handler (window
);
1863 mac_prepare_for_quickdraw (f
);
1865 DisposeWindow (window
);
1869 /************************************************************************
1871 ************************************************************************/
1874 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1877 mac_begin_cg_clip (f
, gc
)
1881 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1885 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)), &context
);
1886 FRAME_CG_CONTEXT (f
) = context
;
1889 CGContextSaveGState (context
);
1890 CGContextTranslateCTM (context
, 0, FRAME_PIXEL_HEIGHT (f
));
1891 CGContextScaleCTM (context
, 1, -1);
1892 if (gc
&& gc
->n_clip_rects
)
1893 CGContextClipToRects (context
, gc
->clip_rects
, gc
->n_clip_rects
);
1902 CGContextRestoreGState (FRAME_CG_CONTEXT (f
));
1906 mac_prepare_for_quickdraw (f
)
1911 Lisp_Object rest
, frame
;
1912 FOR_EACH_FRAME (rest
, frame
)
1913 if (FRAME_MAC_P (XFRAME (frame
)))
1914 mac_prepare_for_quickdraw (XFRAME (frame
));
1918 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1922 CGContextSynchronize (context
);
1923 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)),
1924 &FRAME_CG_CONTEXT (f
));
1930 static RgnHandle saved_port_clip_region
= NULL
;
1933 mac_begin_clip (f
, gc
)
1937 static RgnHandle new_region
= NULL
;
1939 if (saved_port_clip_region
== NULL
)
1940 saved_port_clip_region
= NewRgn ();
1941 if (new_region
== NULL
)
1942 new_region
= NewRgn ();
1945 mac_prepare_for_quickdraw (f
);
1947 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1949 if (gc
&& gc
->n_clip_rects
)
1951 GetClip (saved_port_clip_region
);
1952 SectRgn (saved_port_clip_region
, gc
->clip_region
, new_region
);
1953 SetClip (new_region
);
1958 mac_end_clip (f
, gc
)
1962 if (gc
&& gc
->n_clip_rects
)
1963 SetClip (saved_port_clip_region
);
1966 #if TARGET_API_MAC_CARBON
1967 /* Mac replacement for XCopyArea: used only for scrolling. */
1970 mac_scroll_area (f
, gc
, src_x
, src_y
, width
, height
, dest_x
, dest_y
)
1974 unsigned int width
, height
;
1978 RgnHandle dummy
= NewRgn (); /* For avoiding update events. */
1980 SetRect (&src_r
, src_x
, src_y
, src_x
+ width
, src_y
+ height
);
1982 mac_prepare_for_quickdraw (f
);
1984 ScrollWindowRect (FRAME_MAC_WINDOW (f
),
1985 &src_r
, dest_x
- src_x
, dest_y
- src_y
,
1986 kScrollWindowNoOptions
, dummy
);
1992 /************************************************************************
1994 ************************************************************************/
1996 extern struct scroll_bar
*tracked_scroll_bar
;
1997 extern Lisp_Object last_mouse_scroll_bar
;
1998 extern Time last_mouse_movement_time
;
2000 static void x_scroll_bar_handle_click
P_ ((struct scroll_bar
*,
2002 const EventRecord
*,
2003 struct input_event
*));
2004 #ifndef USE_TOOLKIT_SCROLL_BARS
2005 static void x_scroll_bar_note_movement
P_ ((struct scroll_bar
*, int, Time
));
2006 #else /* USE_TOOLKIT_SCROLL_BARS */
2007 static void x_scroll_bar_handle_press
P_ ((struct scroll_bar
*,
2008 ControlPartCode
, Point
,
2009 struct input_event
*));
2010 static void x_scroll_bar_handle_release
P_ ((struct scroll_bar
*,
2011 struct input_event
*));
2012 static void x_scroll_bar_handle_drag
P_ ((WindowRef
, struct scroll_bar
*,
2013 Point
, struct input_event
*));
2014 static pascal void scroll_bar_timer_callback
P_ ((EventLoopTimerRef
, void *));
2015 static OSStatus install_scroll_bar_timer
P_ ((void));
2016 static OSStatus set_scroll_bar_timer
P_ ((EventTimerInterval
));
2017 static int control_part_code_to_scroll_bar_part
P_ ((ControlPartCode
));
2018 static void construct_scroll_bar_click
P_ ((struct scroll_bar
*, int,
2019 struct input_event
*));
2020 static OSStatus get_control_part_bounds
P_ ((ControlRef
, ControlPartCode
,
2022 static void update_scroll_bar_track_info
P_ ((struct scroll_bar
*));
2024 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2026 static int last_scroll_bar_part
;
2028 static EventLoopTimerRef scroll_bar_timer
;
2030 static int scroll_bar_timer_event_posted_p
;
2032 #define SCROLL_BAR_FIRST_DELAY 0.5
2033 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2036 scroll_bar_timer_callback (timer
, data
)
2037 EventLoopTimerRef timer
;
2042 err
= mac_post_mouse_moved_event ();
2044 scroll_bar_timer_event_posted_p
= 1;
2048 install_scroll_bar_timer ()
2050 static EventLoopTimerUPP scroll_bar_timer_callbackUPP
= NULL
;
2052 if (scroll_bar_timer_callbackUPP
== NULL
)
2053 scroll_bar_timer_callbackUPP
=
2054 NewEventLoopTimerUPP (scroll_bar_timer_callback
);
2056 if (scroll_bar_timer
== NULL
)
2057 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2058 kEventDurationForever as delays. */
2060 InstallEventLoopTimer (GetCurrentEventLoop (),
2061 kEventDurationForever
, kEventDurationForever
,
2062 scroll_bar_timer_callbackUPP
, NULL
,
2067 set_scroll_bar_timer (delay
)
2068 EventTimerInterval delay
;
2070 if (scroll_bar_timer
== NULL
)
2071 install_scroll_bar_timer ();
2073 scroll_bar_timer_event_posted_p
= 0;
2075 return SetEventLoopTimerNextFireTime (scroll_bar_timer
, delay
);
2079 control_part_code_to_scroll_bar_part (part_code
)
2080 ControlPartCode part_code
;
2084 case kControlUpButtonPart
: return scroll_bar_up_arrow
;
2085 case kControlDownButtonPart
: return scroll_bar_down_arrow
;
2086 case kControlPageUpPart
: return scroll_bar_above_handle
;
2087 case kControlPageDownPart
: return scroll_bar_below_handle
;
2088 case kControlIndicatorPart
: return scroll_bar_handle
;
2095 construct_scroll_bar_click (bar
, part
, bufp
)
2096 struct scroll_bar
*bar
;
2098 struct input_event
*bufp
;
2100 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2101 bufp
->frame_or_window
= bar
->window
;
2105 XSETINT (bufp
->x
, 0);
2106 XSETINT (bufp
->y
, 0);
2107 bufp
->modifiers
= 0;
2111 get_control_part_bounds (ch
, part_code
, rect
)
2113 ControlPartCode part_code
;
2116 RgnHandle region
= NewRgn ();
2119 err
= GetControlRegion (ch
, part_code
, region
);
2121 GetRegionBounds (region
, rect
);
2122 DisposeRgn (region
);
2128 x_scroll_bar_handle_press (bar
, part_code
, mouse_pos
, bufp
)
2129 struct scroll_bar
*bar
;
2130 ControlPartCode part_code
;
2132 struct input_event
*bufp
;
2134 int part
= control_part_code_to_scroll_bar_part (part_code
);
2139 if (part
!= scroll_bar_handle
)
2141 construct_scroll_bar_click (bar
, part
, bufp
);
2142 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2143 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY
);
2144 bar
->dragging
= Qnil
;
2150 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2151 kControlIndicatorPart
, &r
);
2152 XSETINT (bar
->dragging
, - (mouse_pos
.v
- r
.top
) - 1);
2155 last_scroll_bar_part
= part
;
2156 tracked_scroll_bar
= bar
;
2160 x_scroll_bar_handle_release (bar
, bufp
)
2161 struct scroll_bar
*bar
;
2162 struct input_event
*bufp
;
2164 if (last_scroll_bar_part
!= scroll_bar_handle
2165 || (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) >= 0))
2166 construct_scroll_bar_click (bar
, scroll_bar_end_scroll
, bufp
);
2168 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2169 set_scroll_bar_timer (kEventDurationForever
);
2171 last_scroll_bar_part
= -1;
2172 bar
->dragging
= Qnil
;
2173 tracked_scroll_bar
= NULL
;
2177 x_scroll_bar_handle_drag (win
, bar
, mouse_pos
, bufp
)
2179 struct scroll_bar
*bar
;
2181 struct input_event
*bufp
;
2183 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2185 if (last_scroll_bar_part
== scroll_bar_handle
)
2190 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2191 kControlIndicatorPart
, &r
);
2193 if (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) < 0)
2194 XSETINT (bar
->dragging
, - (XINT (bar
->dragging
) + 1));
2196 top
= mouse_pos
.v
- XINT (bar
->dragging
) - XINT (bar
->track_top
);
2197 top_range
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2201 if (top
> top_range
)
2204 construct_scroll_bar_click (bar
, scroll_bar_handle
, bufp
);
2205 XSETINT (bufp
->x
, top
);
2206 XSETINT (bufp
->y
, top_range
);
2210 ControlPartCode part_code
;
2211 int unhilite_p
= 0, part
;
2213 if (ch
!= FindControlUnderMouse (mouse_pos
, win
, &part_code
))
2217 part
= control_part_code_to_scroll_bar_part (part_code
);
2219 switch (last_scroll_bar_part
)
2221 case scroll_bar_above_handle
:
2222 case scroll_bar_below_handle
:
2223 if (part
!= scroll_bar_above_handle
2224 && part
!= scroll_bar_below_handle
)
2228 case scroll_bar_up_arrow
:
2229 case scroll_bar_down_arrow
:
2230 if (part
!= scroll_bar_up_arrow
2231 && part
!= scroll_bar_down_arrow
)
2238 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2239 else if (part
!= last_scroll_bar_part
2240 || scroll_bar_timer_event_posted_p
)
2242 construct_scroll_bar_click (bar
, part
, bufp
);
2243 last_scroll_bar_part
= part
;
2244 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2245 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY
);
2250 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2251 the scroll bar BAR. This function should be called when the bounds
2252 of the scroll bar is changed. */
2255 update_scroll_bar_track_info (bar
)
2256 struct scroll_bar
*bar
;
2258 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2261 GetControlBounds (ch
, &r0
);
2263 if (r0
.right
- r0
.left
>= r0
.bottom
- r0
.top
2265 || r0
.right
- r0
.left
< MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2269 XSETINT (bar
->track_top
, 0);
2270 XSETINT (bar
->track_height
, 0);
2271 XSETINT (bar
->min_handle
, 0);
2277 SetControl32BitMinimum (ch
, 0);
2278 SetControl32BitMaximum (ch
, 1 << 30);
2279 SetControlViewSize (ch
, 1);
2281 /* Move the scroll bar thumb to the top. */
2282 SetControl32BitValue (ch
, 0);
2283 get_control_part_bounds (ch
, kControlIndicatorPart
, &r0
);
2285 /* Move the scroll bar thumb to the bottom. */
2286 SetControl32BitValue (ch
, 1 << 30);
2287 get_control_part_bounds (ch
, kControlIndicatorPart
, &r1
);
2289 UnionRect (&r0
, &r1
, &r0
);
2290 XSETINT (bar
->track_top
, r0
.top
);
2291 XSETINT (bar
->track_height
, r0
.bottom
- r0
.top
);
2292 XSETINT (bar
->min_handle
, r1
.bottom
- r1
.top
);
2294 /* Don't show the scroll bar if its height is not enough to
2295 display the scroll bar thumb. */
2296 if (r0
.bottom
- r0
.top
> 0)
2303 /* Set the thumb size and position of scroll bar BAR. We are currently
2304 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2307 x_set_toolkit_scroll_bar_thumb (bar
, portion
, position
, whole
)
2308 struct scroll_bar
*bar
;
2309 int portion
, position
, whole
;
2311 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2312 int value
, viewsize
, maximum
;
2314 if (XINT (bar
->track_height
) == 0)
2317 if (whole
<= portion
)
2318 value
= 0, viewsize
= 1, maximum
= 0;
2323 maximum
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2324 scale
= (float) maximum
/ (whole
- portion
);
2325 value
= position
* scale
+ 0.5f
;
2326 viewsize
= (int) (portion
* scale
+ 0.5f
) + XINT (bar
->min_handle
);
2331 if (GetControlViewSize (ch
) != viewsize
2332 || GetControl32BitValue (ch
) != value
2333 || GetControl32BitMaximum (ch
) != maximum
)
2335 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2336 SetControlVisibility (ch
, false, false);
2338 SetControl32BitMaximum (ch
, maximum
);
2339 SetControl32BitValue (ch
, value
);
2340 SetControlViewSize (ch
, viewsize
);
2342 SetControlVisibility (ch
, true, true);
2348 #endif /* USE_TOOLKIT_SCROLL_BARS */
2350 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2351 the initial geometry and visibility, respectively. The created
2352 control is stored in some members of BAR. */
2355 mac_create_scroll_bar (bar
, bounds
, visible
)
2356 struct scroll_bar
*bar
;
2360 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2364 mac_prepare_for_quickdraw (f
);
2366 ch
= NewControl (FRAME_MAC_WINDOW (f
), bounds
, "\p", visible
, 0, 0, 0,
2367 #if TARGET_API_MAC_CARBON
2368 kControlScrollBarProc
,
2373 SET_SCROLL_BAR_CONTROL_REF (bar
, ch
);
2375 XSETINT (bar
->start
, 0);
2376 XSETINT (bar
->end
, 0);
2377 bar
->dragging
= Qnil
;
2379 #ifdef USE_TOOLKIT_SCROLL_BARS
2380 update_scroll_bar_track_info (bar
);
2384 /* Dispose of the scroll bar control stored in some members of
2388 mac_dispose_scroll_bar (bar
)
2389 struct scroll_bar
*bar
;
2392 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2394 mac_prepare_for_quickdraw (f
);
2396 DisposeControl (SCROLL_BAR_CONTROL_REF (bar
));
2399 /* Set bounds of the scroll bar BAR to BOUNDS. */
2402 mac_set_scroll_bar_bounds (bar
, bounds
)
2403 struct scroll_bar
*bar
;
2406 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2407 SInt16 width
, height
;
2409 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2411 mac_prepare_for_quickdraw (f
);
2414 width
= bounds
->right
- bounds
->left
;
2415 height
= bounds
->bottom
- bounds
->top
;
2417 MoveControl (ch
, bounds
->left
, bounds
->top
);
2418 SizeControl (ch
, width
, height
);
2419 #ifdef USE_TOOLKIT_SCROLL_BARS
2420 update_scroll_bar_track_info (bar
);
2427 /* Draw the scroll bar BAR. */
2430 mac_redraw_scroll_bar (bar
)
2431 struct scroll_bar
*bar
;
2434 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2436 mac_prepare_for_quickdraw (f
);
2438 Draw1Control (SCROLL_BAR_CONTROL_REF (bar
));
2441 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2442 is set to something other than NO_EVENT, it is enqueued.
2444 This may be called from a signal handler, so we have to ignore GC
2448 x_scroll_bar_handle_click (bar
, part_code
, er
, bufp
)
2449 struct scroll_bar
*bar
;
2450 ControlPartCode part_code
;
2451 const EventRecord
*er
;
2452 struct input_event
*bufp
;
2454 int win_y
, top_range
;
2456 if (! GC_WINDOWP (bar
->window
))
2459 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2460 bufp
->frame_or_window
= bar
->window
;
2463 bar
->dragging
= Qnil
;
2467 case kControlUpButtonPart
:
2468 bufp
->part
= scroll_bar_up_arrow
;
2470 case kControlDownButtonPart
:
2471 bufp
->part
= scroll_bar_down_arrow
;
2473 case kControlPageUpPart
:
2474 bufp
->part
= scroll_bar_above_handle
;
2476 case kControlPageDownPart
:
2477 bufp
->part
= scroll_bar_below_handle
;
2479 #if TARGET_API_MAC_CARBON
2482 case kControlIndicatorPart
:
2484 if (er
->what
== mouseDown
)
2485 bar
->dragging
= make_number (0);
2486 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2487 bufp
->part
= scroll_bar_handle
;
2491 win_y
= XINT (bufp
->y
) - XINT (bar
->top
);
2492 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar
->height
));
2494 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2498 if (! NILP (bar
->dragging
))
2499 win_y
-= XINT (bar
->dragging
);
2503 if (win_y
> top_range
)
2506 XSETINT (bufp
->x
, win_y
);
2507 XSETINT (bufp
->y
, top_range
);
2510 /* Return information to the user about the current position of the mouse
2511 on the scroll bar. */
2514 x_scroll_bar_report_motion (fp
, bar_window
, part
, x
, y
, time
)
2516 Lisp_Object
*bar_window
;
2517 enum scroll_bar_part
*part
;
2519 unsigned long *time
;
2521 struct scroll_bar
*bar
= XSCROLL_BAR (last_mouse_scroll_bar
);
2522 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2523 #if TARGET_API_MAC_CARBON
2524 WindowRef wp
= GetControlOwner (ch
);
2526 WindowRef wp
= (*ch
)->contrlOwner
;
2529 struct frame
*f
= mac_window_to_frame (wp
);
2530 int win_y
, top_range
;
2532 #if TARGET_API_MAC_CARBON
2533 GetGlobalMouse (&mouse_pos
);
2534 mouse_pos
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
2535 mouse_pos
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2537 SetPortWindowPort (wp
);
2538 GetMouse (&mouse_pos
);
2541 win_y
= mouse_pos
.v
- XINT (bar
->top
);
2542 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2544 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2548 if (! NILP (bar
->dragging
))
2549 win_y
-= XINT (bar
->dragging
);
2553 if (win_y
> top_range
)
2557 *bar_window
= bar
->window
;
2559 if (! NILP (bar
->dragging
))
2560 *part
= scroll_bar_handle
;
2561 else if (win_y
< XINT (bar
->start
))
2562 *part
= scroll_bar_above_handle
;
2563 else if (win_y
< XINT (bar
->end
) + VERTICAL_SCROLL_BAR_MIN_HANDLE
)
2564 *part
= scroll_bar_handle
;
2566 *part
= scroll_bar_below_handle
;
2568 XSETINT (*x
, win_y
);
2569 XSETINT (*y
, top_range
);
2572 last_mouse_scroll_bar
= Qnil
;
2574 *time
= last_mouse_movement_time
;
2577 #ifndef USE_TOOLKIT_SCROLL_BARS
2578 /* Draw BAR's handle in the proper position.
2580 If the handle is already drawn from START to END, don't bother
2581 redrawing it, unless REBUILD is non-zero; in that case, always
2582 redraw it. (REBUILD is handy for drawing the handle after expose
2585 Normally, we want to constrain the start and end of the handle to
2586 fit inside its rectangle, but if the user is dragging the scroll
2587 bar handle, we want to let them drag it down all the way, so that
2588 the bar's top is as far down as it goes; otherwise, there's no way
2589 to move to the very end of the buffer. */
2592 x_scroll_bar_set_handle (bar
, start
, end
, rebuild
)
2593 struct scroll_bar
*bar
;
2597 int dragging
= ! NILP (bar
->dragging
);
2598 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2599 FRAME_PTR f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2600 int top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2601 int length
= end
- start
;
2603 /* If the display is already accurate, do nothing. */
2605 && start
== XINT (bar
->start
)
2606 && end
== XINT (bar
->end
))
2611 /* Make sure the values are reasonable, and try to preserve the
2612 distance between start and end. */
2615 else if (start
> top_range
)
2617 end
= start
+ length
;
2621 else if (end
> top_range
&& ! dragging
)
2624 /* Store the adjusted setting in the scroll bar. */
2625 XSETINT (bar
->start
, start
);
2626 XSETINT (bar
->end
, end
);
2628 /* Clip the end position, just for display. */
2629 if (end
> top_range
)
2632 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2633 top positions, to make sure the handle is always at least that
2634 many pixels tall. */
2635 end
+= VERTICAL_SCROLL_BAR_MIN_HANDLE
;
2637 SetControlMinimum (ch
, 0);
2638 /* Don't inadvertently activate deactivated scroll bars */
2639 if (GetControlMaximum (ch
) != -1)
2640 SetControlMaximum (ch
, top_range
+ VERTICAL_SCROLL_BAR_MIN_HANDLE
2642 SetControlValue (ch
, start
);
2643 #if TARGET_API_MAC_CARBON
2644 SetControlViewSize (ch
, end
- start
);
2650 /* Handle some mouse motion while someone is dragging the scroll bar.
2652 This may be called from a signal handler, so we have to ignore GC
2656 x_scroll_bar_note_movement (bar
, y_pos
, t
)
2657 struct scroll_bar
*bar
;
2661 FRAME_PTR f
= XFRAME (XWINDOW (bar
->window
)->frame
);
2663 last_mouse_movement_time
= t
;
2666 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2668 /* If we're dragging the bar, display it. */
2669 if (! GC_NILP (bar
->dragging
))
2671 /* Where should the handle be now? */
2672 int new_start
= y_pos
- 24;
2674 if (new_start
!= XINT (bar
->start
))
2676 int new_end
= new_start
+ (XINT (bar
->end
) - XINT (bar
->start
));
2678 x_scroll_bar_set_handle (bar
, new_start
, new_end
, 0);
2682 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2685 /***********************************************************************
2687 ***********************************************************************/
2690 /* In identifiers such as function/variable names, Emacs tool bar is
2691 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2693 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2694 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2696 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2697 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2698 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2699 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2700 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2701 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2702 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2704 static OSStatus mac_handle_toolbar_command_event
P_ ((EventHandlerCallRef
,
2707 extern Rect last_mouse_glyph
;
2709 extern void mac_move_window_with_gravity
P_ ((struct frame
*, int,
2711 extern void mac_get_window_origin_with_gravity
P_ ((struct frame
*, int,
2713 extern CGImageRef mac_image_spec_to_cg_image
P_ ((struct frame
*,
2717 mac_handle_toolbar_event (next_handler
, event
, data
)
2718 EventHandlerCallRef next_handler
;
2722 OSStatus result
= eventNotHandledErr
;
2724 switch (GetEventKind (event
))
2726 case kEventToolbarGetDefaultIdentifiers
:
2730 case kEventToolbarGetAllowedIdentifiers
:
2732 CFMutableArrayRef array
;
2734 GetEventParameter (event
, kEventParamMutableArray
,
2735 typeCFMutableArrayRef
, NULL
,
2736 sizeof (CFMutableArrayRef
), NULL
, &array
);
2737 CFArrayAppendValue (array
, TOOLBAR_ICON_ITEM_IDENTIFIER
);
2742 case kEventToolbarCreateItemWithIdentifier
:
2744 CFStringRef identifier
;
2745 HIToolbarItemRef item
= NULL
;
2747 GetEventParameter (event
, kEventParamToolbarItemIdentifier
,
2748 typeCFStringRef
, NULL
,
2749 sizeof (CFStringRef
), NULL
, &identifier
);
2751 if (CFStringCompare (identifier
, TOOLBAR_ICON_ITEM_IDENTIFIER
, 0)
2752 == kCFCompareEqualTo
)
2753 HIToolbarItemCreate (identifier
,
2754 kHIToolbarItemAllowDuplicates
2755 | kHIToolbarItemCantBeRemoved
, &item
);
2759 SetEventParameter (event
, kEventParamToolbarItem
,
2760 typeHIToolbarItemRef
,
2761 sizeof (HIToolbarItemRef
), &item
);
2774 /* Create a tool bar for frame F. */
2777 mac_create_frame_tool_bar (f
)
2781 HIToolbarRef toolbar
;
2783 err
= HIToolbarCreate (TOOLBAR_IDENTIFIER
, kHIToolbarNoAttributes
,
2787 static const EventTypeSpec specs
[] =
2788 {{kEventClassToolbar
, kEventToolbarGetDefaultIdentifiers
},
2789 {kEventClassToolbar
, kEventToolbarGetAllowedIdentifiers
},
2790 {kEventClassToolbar
, kEventToolbarCreateItemWithIdentifier
}};
2792 err
= InstallEventHandler (HIObjectGetEventTarget (toolbar
),
2793 mac_handle_toolbar_event
,
2794 GetEventTypeCount (specs
), specs
,
2799 err
= HIToolbarSetDisplayMode (toolbar
, kHIToolbarDisplayModeIconOnly
);
2802 static const EventTypeSpec specs
[] =
2803 {{kEventClassCommand
, kEventCommandProcess
}};
2805 err
= InstallWindowEventHandler (FRAME_MAC_WINDOW (f
),
2806 mac_handle_toolbar_command_event
,
2807 GetEventTypeCount (specs
),
2811 err
= SetWindowToolbar (FRAME_MAC_WINDOW (f
), toolbar
);
2814 CFRelease (toolbar
);
2819 /* Update the tool bar for frame F. Add new buttons and remove old. */
2822 update_frame_tool_bar (f
)
2825 HIToolbarRef toolbar
= NULL
;
2827 CFArrayRef old_items
= NULL
;
2829 int i
, pos
, win_gravity
= f
->output_data
.mac
->toolbar_win_gravity
;
2830 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2834 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2835 if (toolbar
== NULL
)
2837 mac_create_frame_tool_bar (f
);
2838 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2839 if (toolbar
== NULL
)
2841 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2842 mac_get_window_origin_with_gravity (f
, win_gravity
, &left
, &top
);
2845 HIToolbarCopyItems (toolbar
, &old_items
);
2846 if (old_items
== NULL
)
2849 old_count
= CFArrayGetCount (old_items
);
2851 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
2853 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2855 int enabled_p
= !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
));
2856 int selected_p
= !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P
));
2859 CGImageRef cg_image
;
2861 HIToolbarItemRef item
;
2863 /* If image is a vector, choose the image according to the
2865 image
= PROP (TOOL_BAR_ITEM_IMAGES
);
2866 if (VECTORP (image
))
2870 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2871 : TOOL_BAR_IMAGE_ENABLED_DESELECTED
);
2874 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2875 : TOOL_BAR_IMAGE_DISABLED_DESELECTED
);
2877 xassert (ASIZE (image
) >= idx
);
2878 image
= AREF (image
, idx
);
2883 cg_image
= mac_image_spec_to_cg_image (f
, image
);
2884 /* Ignore invalid image specifications. */
2885 if (cg_image
== NULL
)
2888 label
= cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION
));
2892 if (pos
< old_count
)
2894 CGImageRef old_cg_image
= NULL
;
2895 CFStringRef old_label
= NULL
;
2896 Boolean old_enabled_p
;
2898 item
= (HIToolbarItemRef
) CFArrayGetValueAtIndex (old_items
, pos
);
2900 HIToolbarItemCopyImage (item
, &old_cg_image
);
2901 if (cg_image
!= old_cg_image
)
2902 HIToolbarItemSetImage (item
, cg_image
);
2903 CGImageRelease (old_cg_image
);
2905 HIToolbarItemCopyLabel (item
, &old_label
);
2906 if (CFStringCompare (label
, old_label
, 0) != kCFCompareEqualTo
)
2907 HIToolbarItemSetLabel (item
, label
);
2908 CFRelease (old_label
);
2910 old_enabled_p
= HIToolbarItemIsEnabled (item
);
2911 if ((enabled_p
|| idx
>= 0) != old_enabled_p
)
2912 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2917 HIToolbarCreateItemWithIdentifier (toolbar
,
2918 TOOLBAR_ICON_ITEM_IDENTIFIER
,
2922 HIToolbarItemSetImage (item
, cg_image
);
2923 HIToolbarItemSetLabel (item
, label
);
2924 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2925 HIToolbarAppendItem (toolbar
, item
);
2933 HIToolbarItemSetCommandID (item
, TOOLBAR_ITEM_MAKE_COMMAND_ID (i
));
2938 CFRelease (old_items
);
2940 while (pos
< old_count
)
2941 HIToolbarRemoveItemAtIndex (toolbar
, --old_count
);
2943 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), true,
2944 !win_gravity
&& f
== mac_focus_frame (dpyinfo
));
2945 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2946 toolbar visibility change. */
2947 mac_handle_origin_change (f
);
2948 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2950 mac_move_window_with_gravity (f
, win_gravity
, left
, top
);
2951 /* If the title bar is completely outside the screen, adjust the
2953 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f
), kWindowTitleBarRgn
,
2954 kWindowConstrainMoveRegardlessOfFit
2955 | kWindowConstrainAllowPartial
, NULL
, NULL
);
2956 f
->output_data
.mac
->toolbar_win_gravity
= 0;
2963 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2964 doesn't deallocate the resources. */
2967 free_frame_tool_bar (f
)
2970 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f
)))
2972 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2975 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), false,
2976 (NILP (find_symbol_value
2977 (intern ("frame-notice-user-settings")))
2978 && f
== mac_focus_frame (dpyinfo
)));
2979 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2980 on toolbar visibility change. */
2981 mac_handle_origin_change (f
);
2986 /* Report a mouse movement over toolbar to the mainstream Emacs
2990 mac_tool_bar_note_mouse_movement (f
, event
)
2995 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2998 WindowPartCode part_code
;
2999 HIViewRef item_view
;
3002 mouse_down_p
= (dpyinfo
->grabbed
3003 && f
== last_mouse_frame
3004 && FRAME_LIVE_P (f
));
3008 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
, NULL
,
3009 sizeof (WindowRef
), NULL
, &window
);
3010 if (err
!= noErr
|| window
!= FRAME_MAC_WINDOW (f
))
3013 err
= GetEventParameter (event
, kEventParamWindowPartCode
,
3014 typeWindowPartCode
, NULL
,
3015 sizeof (WindowPartCode
), NULL
, &part_code
);
3016 if (err
!= noErr
|| part_code
!= inStructure
)
3019 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window
), event
, &item_view
);
3020 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3021 toolbar item view seems to have the same command ID with that of
3022 the toolbar item. */
3024 err
= GetControlCommandID (item_view
, &command_id
);
3025 if (err
== noErr
&& TOOLBAR_ITEM_COMMAND_ID_P (command_id
))
3027 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id
);
3029 if (i
< f
->n_tool_bar_items
)
3032 HIViewRef content_view
;
3034 err
= HIViewGetBounds (item_view
, &bounds
);
3036 err
= HIViewFindByID (HIViewGetRoot (window
),
3037 kHIViewWindowContentID
, &content_view
);
3039 err
= HIViewConvertRect (&bounds
, item_view
, content_view
);
3041 SetRect (&last_mouse_glyph
,
3042 CGRectGetMinX (bounds
), CGRectGetMinY (bounds
),
3043 CGRectGetMaxX (bounds
), CGRectGetMaxY (bounds
));
3045 help_echo_object
= help_echo_window
= Qnil
;
3047 help_echo_string
= PROP (TOOL_BAR_ITEM_HELP
);
3048 if (NILP (help_echo_string
))
3049 help_echo_string
= PROP (TOOL_BAR_ITEM_CAPTION
);
3055 mac_handle_toolbar_command_event (next_handler
, event
, data
)
3056 EventHandlerCallRef next_handler
;
3060 OSStatus err
, result
= eventNotHandledErr
;
3061 struct frame
*f
= (struct frame
*) data
;
3064 err
= GetEventParameter (event
, kEventParamDirectObject
,
3065 typeHICommand
, NULL
,
3066 sizeof (HICommand
), NULL
, &command
);
3070 switch (GetEventKind (event
))
3072 case kEventCommandProcess
:
3073 if (!TOOLBAR_ITEM_COMMAND_ID_P (command
.commandID
))
3074 result
= CallNextEventHandler (next_handler
, event
);
3077 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command
.commandID
);
3079 if (i
< f
->n_tool_bar_items
3080 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
)))
3083 struct input_event buf
;
3087 XSETFRAME (frame
, f
);
3088 buf
.kind
= TOOL_BAR_EVENT
;
3089 buf
.frame_or_window
= frame
;
3091 kbd_buffer_store_event (&buf
);
3093 buf
.kind
= TOOL_BAR_EVENT
;
3094 buf
.frame_or_window
= frame
;
3095 buf
.arg
= PROP (TOOL_BAR_ITEM_KEY
);
3096 buf
.modifiers
= mac_event_to_emacs_modifiers (event
);
3097 kbd_buffer_store_event (&buf
);
3111 #endif /* USE_MAC_TOOLBAR */
3114 /***********************************************************************
3116 ***********************************************************************/
3118 #if USE_MAC_FONT_PANEL
3119 /* Whether Font Panel has been shown before. The first call to font
3120 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3121 slow. This variable is used for deferring such a call as much as
3123 static int font_panel_shown_p
= 0;
3125 extern Lisp_Object Qpanel_closed
, Qselection
;
3126 extern Lisp_Object Qfont
;
3128 /* Whether the font panel is currently visible. */
3131 mac_font_panel_visible_p ()
3133 return font_panel_shown_p
&& FPIsFontPanelVisible ();
3136 static pascal OSStatus
3137 mac_handle_font_event (next_handler
, event
, data
)
3138 EventHandlerCallRef next_handler
;
3142 OSStatus result
, err
;
3145 const EventParamName
*names
;
3146 const EventParamType
*types
;
3147 static const EventParamName names_sel
[] = {kEventParamATSUFontID
,
3148 kEventParamATSUFontSize
,
3149 kEventParamFMFontFamily
,
3150 kEventParamFMFontStyle
,
3151 kEventParamFMFontSize
,
3152 kEventParamFontColor
};
3153 static const EventParamType types_sel
[] = {typeATSUFontID
,
3160 result
= CallNextEventHandler (next_handler
, event
);
3161 if (result
!= eventNotHandledErr
)
3164 switch (GetEventKind (event
))
3166 case kEventFontPanelClosed
:
3167 id_key
= Qpanel_closed
;
3173 case kEventFontSelection
:
3174 id_key
= Qselection
;
3175 num_params
= sizeof (names_sel
) / sizeof (names_sel
[0]);
3181 err
= mac_store_event_ref_as_apple_event (0, 0, Qfont
, id_key
,
3190 /* Toggle visiblity of the font panel. */
3193 mac_show_hide_font_panel ()
3195 if (!font_panel_shown_p
)
3199 static const EventTypeSpec specs
[] =
3200 {{kEventClassFont
, kEventFontPanelClosed
},
3201 {kEventClassFont
, kEventFontSelection
}};
3203 err
= InstallApplicationEventHandler (mac_handle_font_event
,
3204 GetEventTypeCount (specs
),
3209 font_panel_shown_p
= 1;
3212 return FPShowHideFontPanel ();
3215 /* Set the font selected in the font panel to the one corresponding to
3216 the face FACE_ID and the charcacter C in the frame F. */
3219 mac_set_font_info_for_selection (f
, face_id
, c
)
3224 EventTargetRef target
= NULL
;
3225 XFontStruct
*font
= NULL
;
3227 if (!mac_font_panel_visible_p ())
3232 target
= GetWindowEventTarget (FRAME_MAC_WINDOW (f
));
3234 if (FRAME_FACE_CACHE (f
) && CHAR_VALID_P (c
, 0))
3238 face_id
= FACE_FOR_CHAR (f
, FACE_FROM_ID (f
, face_id
), c
);
3239 face
= FACE_FROM_ID (f
, face_id
);
3245 err
= SetFontInfoForSelection (kFontSelectionATSUIType
, 0, NULL
, target
);
3248 if (font
->mac_fontnum
!= -1)
3250 FontSelectionQDStyle qd_style
;
3252 qd_style
.version
= kFontSelectionQDStyleVersionZero
;
3253 qd_style
.instance
.fontFamily
= font
->mac_fontnum
;
3254 qd_style
.instance
.fontStyle
= font
->mac_fontface
;
3255 qd_style
.size
= font
->mac_fontsize
;
3256 qd_style
.hasColor
= false;
3258 err
= SetFontInfoForSelection (kFontSelectionQDType
,
3259 1, &qd_style
, target
);
3262 err
= SetFontInfoForSelection (kFontSelectionATSUIType
,
3263 1, &font
->mac_style
, target
);
3268 #endif /* USE_MAC_FONT_PANEL */
3271 /************************************************************************
3273 ************************************************************************/
3275 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3278 static int any_help_event_p
;
3280 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3281 static Lisp_Object last_window
;
3283 static Point saved_menu_event_location
;
3285 extern struct frame
*pending_autoraise_frame
;
3287 extern FRAME_PTR last_mouse_glyph_frame
;
3290 extern int volatile input_signal_count
;
3292 extern int input_signal_count
;
3295 extern int mac_screen_config_changed
;
3297 extern Lisp_Object Vmac_emulate_three_button_mouse
;
3298 #if TARGET_API_MAC_CARBON
3299 extern int mac_wheel_button_is_mouse_2
;
3300 extern int mac_pass_command_to_system
;
3301 extern int mac_pass_control_to_system
;
3302 #endif /* TARGET_API_MAC_CARBON */
3303 extern int mac_ready_for_apple_events
;
3305 extern void mac_focus_changed
P_ ((int, struct mac_display_info
*,
3306 struct frame
*, struct input_event
*));
3307 extern int mac_get_emulated_btn
P_ ((UInt32
));
3308 extern int note_mouse_movement
P_ ((FRAME_PTR
, Point
*));
3309 extern void mac_get_screen_info
P_ ((struct mac_display_info
*));
3311 /* The focus may have changed. Figure out if it is a real focus change,
3312 by checking both FocusIn/Out and Enter/LeaveNotify events.
3314 Returns FOCUS_IN_EVENT event in *BUFP. */
3317 x_detect_focus_change (dpyinfo
, event
, bufp
)
3318 struct mac_display_info
*dpyinfo
;
3319 const EventRecord
*event
;
3320 struct input_event
*bufp
;
3322 struct frame
*frame
;
3324 frame
= mac_window_to_frame ((WindowRef
) event
->message
);
3328 /* On Mac, this is only called from focus events, so no switch needed. */
3329 mac_focus_changed ((event
->modifiers
& activeFlag
),
3330 dpyinfo
, frame
, bufp
);
3333 #if TARGET_API_MAC_CARBON
3334 /* Obtains the event modifiers from the event EVENTREF and then calls
3335 mac_to_emacs_modifiers. */
3338 mac_event_to_emacs_modifiers (EventRef eventRef
)
3340 UInt32 mods
= 0, class;
3342 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3343 sizeof (UInt32
), NULL
, &mods
);
3344 class = GetEventClass (eventRef
);
3345 if (!NILP (Vmac_emulate_three_button_mouse
)
3346 && (class == kEventClassMouse
|| class == kEventClassCommand
))
3348 mods
&= ~(optionKey
| cmdKey
);
3350 return mac_to_emacs_modifiers (mods
, 0);
3353 /* Given an event REF, return the code to use for the mouse button
3354 code in the emacs input_event. */
3357 mac_get_mouse_btn (EventRef ref
)
3359 EventMouseButton result
= kEventMouseButtonPrimary
;
3360 GetEventParameter (ref
, kEventParamMouseButton
, typeMouseButton
, NULL
,
3361 sizeof (EventMouseButton
), NULL
, &result
);
3364 case kEventMouseButtonPrimary
:
3365 if (NILP (Vmac_emulate_three_button_mouse
))
3369 GetEventParameter (ref
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3370 sizeof (UInt32
), NULL
, &mods
);
3371 return mac_get_emulated_btn(mods
);
3373 case kEventMouseButtonSecondary
:
3374 return mac_wheel_button_is_mouse_2
? 2 : 1;
3375 case kEventMouseButtonTertiary
:
3376 case 4: /* 4 is the number for the mouse wheel button */
3377 return mac_wheel_button_is_mouse_2
? 1 : 2;
3383 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3384 events. However the click of the mouse wheel is not converted to a
3385 mouseDown or mouseUp event. Likewise for dead key events. This
3386 calls ConvertEventRefToEventRecord, but then checks to see if it is
3387 a mouse up/down, or a dead key Carbon event that has not been
3388 converted, and if so, converts it by hand (to be picked up in the
3389 XTread_socket loop). */
3390 static Boolean
mac_convert_event_ref (EventRef eventRef
, EventRecord
*eventRec
)
3393 Boolean result
= ConvertEventRefToEventRecord (eventRef
, eventRec
);
3399 switch (GetEventClass (eventRef
))
3401 case kEventClassMouse
:
3402 switch (GetEventKind (eventRef
))
3404 case kEventMouseDown
:
3405 eventRec
->what
= mouseDown
;
3410 eventRec
->what
= mouseUp
;
3419 case kEventClassKeyboard
:
3420 switch (GetEventKind (eventRef
))
3422 case kEventRawKeyDown
:
3424 goto keystroke_common
;
3425 case kEventRawKeyRepeat
:
3427 goto keystroke_common
;
3428 case kEventRawKeyUp
:
3432 unsigned char char_codes
;
3435 err
= GetEventParameter (eventRef
, kEventParamKeyMacCharCodes
,
3436 typeChar
, NULL
, sizeof (char),
3439 err
= GetEventParameter (eventRef
, kEventParamKeyCode
,
3440 typeUInt32
, NULL
, sizeof (UInt32
),
3444 eventRec
->what
= action
;
3445 eventRec
->message
= char_codes
| ((key_code
& 0xff) << 8);
3462 /* Need where and when. */
3465 GetEventParameter (eventRef
, kEventParamMouseLocation
, typeQDPoint
,
3466 NULL
, sizeof (Point
), NULL
, &eventRec
->where
);
3467 /* Use two step process because new event modifiers are 32-bit
3468 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3469 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
,
3470 NULL
, sizeof (UInt32
), NULL
, &mods
);
3471 eventRec
->modifiers
= mods
;
3473 eventRec
->when
= EventTimeToTicks (GetEventTime (eventRef
));
3478 #endif /* TARGET_API_MAC_CARBON */
3480 #if !TARGET_API_MAC_CARBON
3481 static RgnHandle mouse_region
= NULL
;
3484 mac_wait_next_event (er
, sleep_time
, dequeue
)
3489 static EventRecord er_buf
= {nullEvent
};
3490 UInt32 target_tick
, current_tick
;
3491 EventMask event_mask
;
3493 if (mouse_region
== NULL
)
3494 mouse_region
= NewRgn ();
3496 event_mask
= everyEvent
;
3497 if (!mac_ready_for_apple_events
)
3498 event_mask
-= highLevelEventMask
;
3500 current_tick
= TickCount ();
3501 target_tick
= current_tick
+ sleep_time
;
3503 if (er_buf
.what
== nullEvent
)
3504 while (!WaitNextEvent (event_mask
, &er_buf
,
3505 target_tick
- current_tick
, mouse_region
))
3507 current_tick
= TickCount ();
3508 if (target_tick
<= current_tick
)
3514 er_buf
.what
= nullEvent
;
3517 #endif /* not TARGET_API_MAC_CARBON */
3519 #if TARGET_API_MAC_CARBON
3521 mac_post_mouse_moved_event ()
3523 EventRef event
= NULL
;
3526 err
= CreateEvent (NULL
, kEventClassMouse
, kEventMouseMoved
, 0,
3527 kEventAttributeNone
, &event
);
3532 GetGlobalMouse (&mouse_pos
);
3533 err
= SetEventParameter (event
, kEventParamMouseLocation
, typeQDPoint
,
3534 sizeof (Point
), &mouse_pos
);
3538 UInt32 modifiers
= GetCurrentKeyModifiers ();
3540 err
= SetEventParameter (event
, kEventParamKeyModifiers
, typeUInt32
,
3541 sizeof (UInt32
), &modifiers
);
3544 err
= PostEventToQueue (GetCurrentEventQueue (), event
,
3545 kEventPriorityStandard
);
3547 ReleaseEvent (event
);
3554 /* Run the current run loop in the default mode until some input
3555 happens or TIMEOUT seconds passes unless it is negative. Return
3556 true if timeout occurs first. */
3559 mac_run_loop_run_once (timeout
)
3560 EventTimeout timeout
;
3563 mac_prepare_for_quickdraw (NULL
);
3565 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode
,
3566 timeout
>= 0 ? timeout
: 100000, true)
3567 == kCFRunLoopRunTimedOut
);
3571 /* Emacs calls this whenever it wants to read an input event from the
3575 XTread_socket (sd
, expected
, hold_quit
)
3577 struct input_event
*hold_quit
;
3579 struct input_event inev
;
3581 #if TARGET_API_MAC_CARBON
3583 EventTargetRef toolbox_dispatcher
;
3586 struct mac_display_info
*dpyinfo
= &one_mac_display_info
;
3588 if (interrupt_input_blocked
)
3590 interrupt_input_pending
= 1;
3594 interrupt_input_pending
= 0;
3597 /* So people can tell when we have read the available input. */
3598 input_signal_count
++;
3602 #if TARGET_API_MAC_CARBON
3603 toolbox_dispatcher
= GetEventDispatcherTarget ();
3607 mac_prepare_for_quickdraw (NULL
),
3609 !ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
3610 kEventRemoveFromQueue
, &eventRef
))
3611 #else /* !TARGET_API_MAC_CARBON */
3612 while (mac_wait_next_event (&er
, 0, true))
3613 #endif /* !TARGET_API_MAC_CARBON */
3617 unsigned long timestamp
;
3620 inev
.kind
= NO_EVENT
;
3623 #if TARGET_API_MAC_CARBON
3624 timestamp
= GetEventTime (eventRef
) / kEventDurationMillisecond
;
3626 if (!mac_convert_event_ref (eventRef
, &er
))
3628 #else /* !TARGET_API_MAC_CARBON */
3629 timestamp
= er
.when
* (1000 / 60); /* ticks to milliseconds */
3630 #endif /* !TARGET_API_MAC_CARBON */
3637 WindowRef window_ptr
;
3638 ControlPartCode part_code
;
3641 #if TARGET_API_MAC_CARBON
3644 /* This is needed to send mouse events like aqua window
3645 buttons to the correct handler. */
3646 read_socket_inev
= &inev
;
3647 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
3648 read_socket_inev
= NULL
;
3649 if (err
!= eventNotHandledErr
)
3652 last_mouse_glyph_frame
= 0;
3654 if (dpyinfo
->grabbed
&& last_mouse_frame
3655 && FRAME_LIVE_P (last_mouse_frame
))
3657 window_ptr
= FRAME_MAC_WINDOW (last_mouse_frame
);
3658 part_code
= inContent
;
3662 part_code
= FindWindow (er
.where
, &window_ptr
);
3663 if (tip_window
&& window_ptr
== tip_window
)
3665 HideWindow (tip_window
);
3666 part_code
= FindWindow (er
.where
, &window_ptr
);
3670 if (er
.what
!= mouseDown
3671 && (part_code
!= inContent
|| dpyinfo
->grabbed
== 0))
3677 f
= mac_focus_frame (dpyinfo
);
3678 saved_menu_event_location
= er
.where
;
3679 inev
.kind
= MENU_BAR_ACTIVATE_EVENT
;
3680 XSETFRAME (inev
.frame_or_window
, f
);
3685 #if TARGET_API_MAC_CARBON
3686 FrontNonFloatingWindow ()
3691 || (mac_window_to_frame (window_ptr
)
3692 != dpyinfo
->x_focus_frame
))
3693 SelectWindow (window_ptr
);
3696 ControlPartCode control_part_code
;
3700 ControlKind control_kind
;
3703 f
= mac_window_to_frame (window_ptr
);
3704 /* convert to local coordinates of new window */
3705 mouse_loc
.h
= (er
.where
.h
3707 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3708 mouse_loc
.v
= (er
.where
.v
3710 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3711 #if TARGET_API_MAC_CARBON
3712 ch
= FindControlUnderMouse (mouse_loc
, window_ptr
,
3713 &control_part_code
);
3716 GetControlKind (ch
, &control_kind
);
3719 control_part_code
= FindControl (mouse_loc
, window_ptr
,
3723 #if TARGET_API_MAC_CARBON
3724 inev
.code
= mac_get_mouse_btn (eventRef
);
3725 inev
.modifiers
= mac_event_to_emacs_modifiers (eventRef
);
3727 inev
.code
= mac_get_emulated_btn (er
.modifiers
);
3728 inev
.modifiers
= mac_to_emacs_modifiers (er
.modifiers
, 0);
3730 XSETINT (inev
.x
, mouse_loc
.h
);
3731 XSETINT (inev
.y
, mouse_loc
.v
);
3733 if ((dpyinfo
->grabbed
&& tracked_scroll_bar
)
3735 #ifndef USE_TOOLKIT_SCROLL_BARS
3736 /* control_part_code becomes kControlNoPart if
3737 a progress indicator is clicked. */
3738 && control_part_code
!= kControlNoPart
3739 #else /* USE_TOOLKIT_SCROLL_BARS */
3741 && control_kind
.kind
== kControlKindScrollBar
3742 #endif /* MAC_OSX */
3743 #endif /* USE_TOOLKIT_SCROLL_BARS */
3746 struct scroll_bar
*bar
;
3748 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3750 bar
= tracked_scroll_bar
;
3751 #ifndef USE_TOOLKIT_SCROLL_BARS
3752 control_part_code
= kControlIndicatorPart
;
3756 bar
= (struct scroll_bar
*) GetControlReference (ch
);
3757 #ifdef USE_TOOLKIT_SCROLL_BARS
3758 /* Make the "Ctrl-Mouse-2 splits window" work
3759 for toolkit scroll bars. */
3760 if (inev
.modifiers
& ctrl_modifier
)
3761 x_scroll_bar_handle_click (bar
, control_part_code
,
3763 else if (er
.what
== mouseDown
)
3764 x_scroll_bar_handle_press (bar
, control_part_code
,
3767 x_scroll_bar_handle_release (bar
, &inev
);
3768 #else /* not USE_TOOLKIT_SCROLL_BARS */
3769 x_scroll_bar_handle_click (bar
, control_part_code
,
3771 if (er
.what
== mouseDown
3772 && control_part_code
== kControlIndicatorPart
)
3773 tracked_scroll_bar
= bar
;
3775 tracked_scroll_bar
= NULL
;
3776 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3781 int x
= mouse_loc
.h
;
3782 int y
= mouse_loc
.v
;
3784 window
= window_from_coordinates (f
, x
, y
, 0, 0, 0, 1);
3785 if (EQ (window
, f
->tool_bar_window
))
3787 if (er
.what
== mouseDown
)
3788 handle_tool_bar_click (f
, x
, y
, 1, 0);
3790 handle_tool_bar_click (f
, x
, y
, 0,
3796 XSETFRAME (inev
.frame_or_window
, f
);
3797 inev
.kind
= MOUSE_CLICK_EVENT
;
3801 if (er
.what
== mouseDown
)
3803 dpyinfo
->grabbed
|= (1 << inev
.code
);
3804 last_mouse_frame
= f
;
3807 last_tool_bar_item
= -1;
3811 if ((dpyinfo
->grabbed
& (1 << inev
.code
)) == 0)
3812 /* If a button is released though it was not
3813 previously pressed, that would be because
3814 of multi-button emulation. */
3815 dpyinfo
->grabbed
= 0;
3817 dpyinfo
->grabbed
&= ~(1 << inev
.code
);
3820 /* Ignore any mouse motion that happened before
3821 this event; any subsequent mouse-movement Emacs
3822 events should reflect only motion after the
3827 #ifdef USE_TOOLKIT_SCROLL_BARS
3828 if (inev
.kind
== MOUSE_CLICK_EVENT
3829 || (inev
.kind
== SCROLL_BAR_CLICK_EVENT
3830 && (inev
.modifiers
& ctrl_modifier
)))
3835 inev
.modifiers
|= down_modifier
;
3838 inev
.modifiers
|= up_modifier
;
3845 #if TARGET_API_MAC_CARBON
3847 if (IsWindowPathSelectClick (window_ptr
, &er
))
3849 WindowPathSelect (window_ptr
, NULL
, NULL
);
3852 if (part_code
== inProxyIcon
3853 && (TrackWindowProxyDrag (window_ptr
, er
.where
)
3854 != errUserWantsToDragWindow
))
3856 DragWindow (window_ptr
, er
.where
, NULL
);
3857 #else /* not TARGET_API_MAC_CARBON */
3858 DragWindow (window_ptr
, er
.where
, &qd
.screenBits
.bounds
);
3859 /* Update the frame parameters. */
3861 struct frame
*f
= mac_window_to_frame (window_ptr
);
3863 if (f
&& !f
->async_iconified
)
3864 mac_handle_origin_change (f
);
3866 #endif /* not TARGET_API_MAC_CARBON */
3870 if (TrackGoAway (window_ptr
, er
.where
))
3872 inev
.kind
= DELETE_WINDOW_EVENT
;
3873 XSETFRAME (inev
.frame_or_window
,
3874 mac_window_to_frame (window_ptr
));
3878 /* window resize handling added --ben */
3880 do_grow_window (window_ptr
, &er
);
3883 /* window zoom handling added --ben */
3886 if (TrackBox (window_ptr
, er
.where
, part_code
))
3887 do_zoom_window (window_ptr
, part_code
);
3896 if (FrontNonFloatingWindow () != window_ptr
)
3897 SelectWindow (window_ptr
);
3899 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr
),
3901 /* This doesn't work on Mac OS X 10.2. */
3903 HIViewClick (ch
, eventRef
);
3906 #endif /* USE_MAC_TOOLBAR */
3914 #if !TARGET_API_MAC_CARBON
3916 do_window_update ((WindowRef
) er
.message
);
3921 #if TARGET_API_MAC_CARBON
3922 if (SendEventToEventTarget (eventRef
, toolbox_dispatcher
)
3923 != eventNotHandledErr
)
3926 switch ((er
.message
>> 24) & 0x000000FF)
3929 case suspendResumeMessage
:
3930 if (er
.message
& resumeFlag
)
3937 case mouseMovedMessage
:
3938 #if !TARGET_API_MAC_CARBON
3939 SetRectRgn (mouse_region
, er
.where
.h
, er
.where
.v
,
3940 er
.where
.h
+ 1, er
.where
.v
+ 1);
3942 previous_help_echo_string
= help_echo_string
;
3943 help_echo_string
= Qnil
;
3945 if (dpyinfo
->grabbed
&& last_mouse_frame
3946 && FRAME_LIVE_P (last_mouse_frame
))
3947 f
= last_mouse_frame
;
3949 f
= dpyinfo
->x_focus_frame
;
3951 if (dpyinfo
->mouse_face_hidden
)
3953 dpyinfo
->mouse_face_hidden
= 0;
3954 clear_mouse_face (dpyinfo
);
3959 WindowRef wp
= FRAME_MAC_WINDOW (f
);
3962 mouse_pos
.h
= (er
.where
.h
3964 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3965 mouse_pos
.v
= (er
.where
.v
3967 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3968 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3969 #ifdef USE_TOOLKIT_SCROLL_BARS
3970 x_scroll_bar_handle_drag (wp
, tracked_scroll_bar
,
3972 #else /* not USE_TOOLKIT_SCROLL_BARS */
3973 x_scroll_bar_note_movement (tracked_scroll_bar
,
3975 - XINT (tracked_scroll_bar
->top
),
3976 er
.when
* (1000 / 60));
3977 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3980 /* Generate SELECT_WINDOW_EVENTs when needed. */
3981 if (!NILP (Vmouse_autoselect_window
))
3985 window
= window_from_coordinates (f
,
3990 /* Window will be selected only when it is
3991 not selected now and last mouse movement
3992 event was not in it. Minibuffer window
3993 will be selected only when it is active. */
3994 if (WINDOWP (window
)
3995 && !EQ (window
, last_window
)
3996 && !EQ (window
, selected_window
)
3997 /* For click-to-focus window managers
3998 create event iff we don't leave the
4000 && (focus_follows_mouse
4001 || (EQ (XWINDOW (window
)->frame
,
4002 XWINDOW (selected_window
)->frame
))))
4004 inev
.kind
= SELECT_WINDOW_EVENT
;
4005 inev
.frame_or_window
= window
;
4010 if (!note_mouse_movement (f
, &mouse_pos
))
4011 help_echo_string
= previous_help_echo_string
;
4014 mac_tool_bar_note_mouse_movement (f
, eventRef
);
4019 /* If the contents of the global variable
4020 help_echo_string has changed, generate a
4022 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
4030 WindowRef window_ptr
= (WindowRef
) er
.message
;
4032 ControlRef root_control
;
4034 if (window_ptr
== tip_window
)
4036 HideWindow (tip_window
);
4040 if (!is_emacs_window (window_ptr
))
4043 f
= mac_window_to_frame (window_ptr
);
4045 if ((er
.modifiers
& activeFlag
) != 0)
4047 /* A window has been activated */
4050 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4052 ActivateControl (root_control
);
4054 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4056 mouse_loc
.h
= (er
.where
.h
4058 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
4059 mouse_loc
.v
= (er
.where
.v
4061 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
4062 /* Window-activated event counts as mouse movement,
4063 so update things that depend on mouse position. */
4064 note_mouse_movement (f
, &mouse_loc
);
4068 /* A window has been deactivated */
4069 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4071 DeactivateControl (root_control
);
4073 #ifdef USE_TOOLKIT_SCROLL_BARS
4074 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
4076 struct input_event event
;
4079 event
.kind
= NO_EVENT
;
4080 x_scroll_bar_handle_release (tracked_scroll_bar
, &event
);
4081 if (event
.kind
!= NO_EVENT
)
4083 event
.timestamp
= timestamp
;
4084 kbd_buffer_store_event_hold (&event
, hold_quit
);
4089 dpyinfo
->grabbed
= 0;
4091 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4093 if (f
== dpyinfo
->mouse_face_mouse_frame
)
4095 /* If we move outside the frame, then we're
4096 certainly no longer on any text in the
4098 clear_mouse_face (dpyinfo
);
4099 dpyinfo
->mouse_face_mouse_frame
= 0;
4102 /* Generate a nil HELP_EVENT to cancel a help-echo.
4103 Do it only if there's something to cancel.
4104 Otherwise, the startup message is cleared when the
4105 mouse leaves the frame. */
4106 if (any_help_event_p
)
4117 f
= mac_focus_frame (dpyinfo
);
4118 XSETFRAME (inev
.frame_or_window
, f
);
4120 /* If mouse-highlight is an integer, input clears out mouse
4122 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
)
4123 && !EQ (f
->tool_bar_window
, dpyinfo
->mouse_face_window
))
4125 clear_mouse_face (dpyinfo
);
4126 dpyinfo
->mouse_face_hidden
= 1;
4130 UInt32 modifiers
= er
.modifiers
, mapped_modifiers
;
4131 UInt32 key_code
= (er
.message
& keyCodeMask
) >> 8;
4134 GetEventParameter (eventRef
, kEventParamKeyModifiers
,
4136 sizeof (UInt32
), NULL
, &modifiers
);
4138 mapped_modifiers
= mac_mapped_modifiers (modifiers
, key_code
);
4140 #if TARGET_API_MAC_CARBON
4141 if (!(mapped_modifiers
4142 & ~(mac_pass_command_to_system
? cmdKey
: 0)
4143 & ~(mac_pass_control_to_system
? controlKey
: 0)))
4147 if (er
.what
!= keyUp
)
4148 do_keystroke (er
.what
, er
.message
& charCodeMask
,
4149 key_code
, modifiers
, timestamp
, &inev
);
4153 case kHighLevelEvent
:
4154 AEProcessAppleEvent (&er
);
4159 #if TARGET_API_MAC_CARBON
4163 read_socket_inev
= &inev
;
4164 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
4165 read_socket_inev
= NULL
;
4170 #if TARGET_API_MAC_CARBON
4171 ReleaseEvent (eventRef
);
4174 if (inev
.kind
!= NO_EVENT
)
4176 inev
.timestamp
= timestamp
;
4177 kbd_buffer_store_event_hold (&inev
, hold_quit
);
4182 && !(hold_quit
&& hold_quit
->kind
!= NO_EVENT
))
4187 XSETFRAME (frame
, f
);
4193 any_help_event_p
= 1;
4194 gen_help_event (help_echo_string
, frame
, help_echo_window
,
4195 help_echo_object
, help_echo_pos
);
4199 help_echo_string
= Qnil
;
4200 gen_help_event (Qnil
, frame
, Qnil
, Qnil
, 0);
4206 /* If the focus was just given to an autoraising frame,
4208 /* ??? This ought to be able to handle more than one such frame. */
4209 if (pending_autoraise_frame
)
4211 x_raise_frame (pending_autoraise_frame
);
4212 pending_autoraise_frame
= 0;
4215 if (mac_screen_config_changed
)
4217 mac_get_screen_info (dpyinfo
);
4218 mac_screen_config_changed
= 0;
4221 #if !TARGET_API_MAC_CARBON
4222 /* Check which frames are still visible. We do this here because
4223 there doesn't seem to be any direct notification from the Window
4224 Manager that the visibility of a window has changed (at least,
4225 not in all cases). */
4227 Lisp_Object tail
, frame
;
4229 FOR_EACH_FRAME (tail
, frame
)
4231 struct frame
*f
= XFRAME (frame
);
4233 /* The tooltip has been drawn already. Avoid the
4234 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4235 if (EQ (frame
, tip_frame
))
4238 if (FRAME_MAC_P (f
))
4239 mac_handle_visibility_change (f
);
4250 /***********************************************************************
4252 ***********************************************************************/
4254 #if TARGET_API_MAC_CARBON
4255 /* Show the spinning progress indicator for the frame F. Create it if
4256 it doesn't exist yet. */
4259 mac_show_hourglass (f
)
4263 mac_prepare_for_quickdraw (f
);
4265 if (!f
->output_data
.mac
->hourglass_control
)
4267 Window w
= FRAME_MAC_WINDOW (f
);
4271 GetWindowPortBounds (w
, &r
);
4272 r
.left
= r
.right
- HOURGLASS_WIDTH
;
4273 r
.bottom
= r
.top
+ HOURGLASS_HEIGHT
;
4274 if (CreateChasingArrowsControl (w
, &r
, &c
) == noErr
)
4275 f
->output_data
.mac
->hourglass_control
= c
;
4278 if (f
->output_data
.mac
->hourglass_control
)
4279 ShowControl (f
->output_data
.mac
->hourglass_control
);
4282 /* Hide the spinning progress indicator for the frame F. Do nothing
4283 it doesn't exist yet. */
4286 mac_hide_hourglass (f
)
4289 if (f
->output_data
.mac
->hourglass_control
)
4292 mac_prepare_for_quickdraw (f
);
4294 HideControl (f
->output_data
.mac
->hourglass_control
);
4298 /* Reposition the spinning progress indicator for the frame F. Do
4299 nothing it doesn't exist yet. */
4302 mac_reposition_hourglass (f
)
4305 if (f
->output_data
.mac
->hourglass_control
)
4308 mac_prepare_for_quickdraw (f
);
4310 MoveControl (f
->output_data
.mac
->hourglass_control
,
4311 FRAME_PIXEL_WIDTH (f
) - HOURGLASS_WIDTH
, 0);
4314 #endif /* TARGET_API_MAC_CARBON */
4317 /***********************************************************************
4318 File selection dialog
4319 ***********************************************************************/
4321 #if TARGET_API_MAC_CARBON
4322 extern Lisp_Object Qfile_name_history
;
4324 static pascal void mac_nav_event_callback
P_ ((NavEventCallbackMessage
,
4325 NavCBRecPtr
, void *));
4327 /* The actual implementation of Fx_file_dialog. */
4330 mac_file_dialog (prompt
, dir
, default_filename
, mustmatch
, only_dir_p
)
4331 Lisp_Object prompt
, dir
, default_filename
, mustmatch
, only_dir_p
;
4333 Lisp_Object file
= Qnil
;
4334 int count
= SPECPDL_INDEX ();
4335 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
, gcpro5
, gcpro6
;
4336 char filename
[MAXPATHLEN
];
4337 static NavEventUPP mac_nav_event_callbackUPP
= NULL
;
4341 GCPRO6 (prompt
, dir
, default_filename
, mustmatch
, file
, only_dir_p
);
4342 CHECK_STRING (prompt
);
4345 /* Create the dialog with PROMPT as title, using DIR as initial
4346 directory and using "*" as pattern. */
4347 dir
= Fexpand_file_name (dir
, Qnil
);
4351 NavDialogCreationOptions options
;
4352 NavDialogRef dialogRef
;
4353 NavTypeListHandle fileTypes
= NULL
;
4354 NavUserAction userAction
;
4355 CFStringRef message
=NULL
, saveName
= NULL
;
4358 /* No need for a callback function because we are modal */
4359 NavGetDefaultDialogCreationOptions(&options
);
4360 options
.modality
= kWindowModalityAppModal
;
4361 options
.location
.h
= options
.location
.v
= -1;
4362 options
.optionFlags
= kNavDefaultNavDlogOptions
;
4363 options
.optionFlags
|= kNavAllFilesInPopup
; /* All files allowed */
4364 options
.optionFlags
|= kNavSelectAllReadableItem
;
4365 options
.optionFlags
&= ~kNavAllowMultipleFiles
;
4368 message
= cfstring_create_with_string (prompt
);
4369 options
.message
= message
;
4371 /* Don't set the application, let it use default.
4372 options.clientName = CFSTR ("Emacs");
4375 if (mac_nav_event_callbackUPP
== NULL
)
4376 mac_nav_event_callbackUPP
= NewNavEventUPP (mac_nav_event_callback
);
4378 if (!NILP (only_dir_p
))
4379 status
= NavCreateChooseFolderDialog(&options
, mac_nav_event_callbackUPP
,
4380 NULL
, NULL
, &dialogRef
);
4381 else if (NILP (mustmatch
))
4383 /* This is a save dialog */
4384 options
.optionFlags
|= kNavDontConfirmReplacement
;
4385 options
.actionButtonLabel
= CFSTR ("Ok");
4386 options
.windowTitle
= CFSTR ("Enter name");
4388 if (STRINGP (default_filename
))
4390 Lisp_Object utf8
= ENCODE_UTF_8 (default_filename
);
4391 char *begPtr
= SDATA(utf8
);
4392 char *filePtr
= begPtr
+ SBYTES(utf8
);
4393 while (filePtr
!= begPtr
&& !IS_DIRECTORY_SEP(filePtr
[-1]))
4395 saveName
= cfstring_create_with_utf8_cstring (filePtr
);
4396 options
.saveFileName
= saveName
;
4397 options
.optionFlags
|= kNavSelectDefaultLocation
;
4399 status
= NavCreatePutFileDialog(&options
,
4400 'TEXT', kNavGenericSignature
,
4401 mac_nav_event_callbackUPP
, NULL
,
4406 /* This is an open dialog*/
4407 status
= NavCreateChooseFileDialog(&options
, fileTypes
,
4408 mac_nav_event_callbackUPP
, NULL
,
4409 NULL
, NULL
, &dialogRef
);
4412 /* Set the default location and continue*/
4413 if (status
== noErr
)
4415 Lisp_Object encoded_dir
= ENCODE_FILE (dir
);
4418 status
= AECreateDesc (TYPE_FILE_NAME
, SDATA (encoded_dir
),
4419 SBYTES (encoded_dir
), &defLocAed
);
4420 if (status
== noErr
)
4422 NavCustomControl(dialogRef
, kNavCtlSetLocation
, (void*) &defLocAed
);
4423 AEDisposeDesc(&defLocAed
);
4425 status
= NavDialogRun(dialogRef
);
4428 if (saveName
) CFRelease(saveName
);
4429 if (message
) CFRelease(message
);
4431 if (status
== noErr
) {
4432 userAction
= NavDialogGetUserAction(dialogRef
);
4435 case kNavUserActionNone
:
4436 case kNavUserActionCancel
:
4437 break; /* Treat cancel like C-g */
4438 case kNavUserActionOpen
:
4439 case kNavUserActionChoose
:
4440 case kNavUserActionSaveAs
:
4442 NavReplyRecord reply
;
4445 status
= NavDialogGetReply(dialogRef
, &reply
);
4446 if (status
!= noErr
)
4448 status
= AEGetNthPtr (&reply
.selection
, 1, TYPE_FILE_NAME
,
4449 NULL
, NULL
, filename
,
4450 sizeof (filename
) - 1, &len
);
4451 if (status
== noErr
)
4453 len
= min (len
, sizeof (filename
) - 1);
4454 filename
[len
] = '\0';
4455 if (reply
.saveFileName
)
4457 /* If it was a saved file, we need to add the file name */
4458 if (len
&& len
< sizeof (filename
) - 1
4459 && filename
[len
-1] != '/')
4460 filename
[len
++] = '/';
4461 CFStringGetCString(reply
.saveFileName
, filename
+len
,
4462 sizeof (filename
) - len
,
4464 kCFStringEncodingUTF8
4466 CFStringGetSystemEncoding ()
4470 file
= DECODE_FILE (make_unibyte_string (filename
,
4471 strlen (filename
)));
4473 NavDisposeReply(&reply
);
4477 NavDialogDispose(dialogRef
);
4482 /* Fall back on minibuffer if there was a problem */
4483 file
= Fcompleting_read (prompt
, intern ("read-file-name-internal"),
4484 dir
, mustmatch
, dir
, Qfile_name_history
,
4485 default_filename
, Qnil
);
4491 /* Make "Cancel" equivalent to C-g. */
4493 Fsignal (Qquit
, Qnil
);
4495 return unbind_to (count
, file
);
4498 /* Need to register some event callback function for enabling drag and
4499 drop in Navigation Service dialogs. */
4501 mac_nav_event_callback (selector
, parms
, data
)
4502 NavEventCallbackMessage selector
;
4510 /************************************************************************
4512 ************************************************************************/
4514 #if !TARGET_API_MAC_CARBON
4515 #include <MacTypes.h>
4517 #include <Quickdraw.h>
4518 #include <ToolUtils.h>
4520 #include <Controls.h>
4521 #include <Windows.h>
4523 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4524 #include <ControlDefinitions.h>
4526 #endif /* not TARGET_API_MAC_CARBON */
4528 extern int menu_item_selection
;
4529 extern int popup_activated_flag
;
4530 extern int name_is_separator
P_ ((const char *));
4531 extern void find_and_call_menu_selection
P_ ((FRAME_PTR
, int, Lisp_Object
,
4533 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
4535 enum mac_menu_kind
{ /* Menu ID range */
4536 MAC_MENU_APPLE
, /* 0 (Reserved by Apple) */
4537 MAC_MENU_MENU_BAR
, /* 1 .. 233 */
4538 MAC_MENU_M_APPLE
, /* 234 (== M_APPLE) */
4539 MAC_MENU_POPUP
, /* 235 */
4540 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
4541 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
4542 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
4543 MAC_MENU_END
/* 32768 */
4546 static const int min_menu_id
[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4548 static int fill_menu
P_ ((MenuRef
, widget_value
*, enum mac_menu_kind
, int));
4549 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
4551 #if !TARGET_API_MAC_CARBON
4553 do_apple_menu (SInt16 menu_item
)
4556 SInt16 da_driver_refnum
;
4558 if (menu_item
== I_ABOUT
)
4559 NoteAlert (ABOUT_ALERT_ID
, NULL
);
4562 GetMenuItemText (GetMenuRef (M_APPLE
), menu_item
, item_name
);
4563 da_driver_refnum
= OpenDeskAcc (item_name
);
4566 #endif /* !TARGET_API_MAC_CARBON */
4568 /* Activate the menu bar of frame F.
4569 This is called from keyboard.c when it gets the
4570 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4572 To activate the menu bar, we use the button-press event location
4573 that was saved in saved_menu_event_location.
4575 But first we recompute the menu bar contents (the whole tree).
4577 The reason for saving the button event until here, instead of
4578 passing it to the toolkit right away, is that we can safely
4579 execute Lisp code. */
4582 x_activate_menubar (f
)
4586 SInt16 menu_id
, menu_item
;
4588 set_frame_menubar (f
, 0, 1);
4591 popup_activated_flag
= 1;
4592 menu_choice
= MenuSelect (saved_menu_event_location
);
4593 popup_activated_flag
= 0;
4594 menu_id
= HiWord (menu_choice
);
4595 menu_item
= LoWord (menu_choice
);
4597 #if !TARGET_API_MAC_CARBON
4598 if (menu_id
== min_menu_id
[MAC_MENU_M_APPLE
])
4599 do_apple_menu (menu_item
);
4604 MenuRef menu
= GetMenuRef (menu_id
);
4610 GetMenuItemRefCon (menu
, menu_item
, &refcon
);
4611 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
4612 f
->menu_bar_vector
, (void *) refcon
);
4621 #if TARGET_API_MAC_CARBON
4622 extern Lisp_Object Vshow_help_function
;
4625 restore_show_help_function (old_show_help_function
)
4626 Lisp_Object old_show_help_function
;
4628 Vshow_help_function
= old_show_help_function
;
4633 static pascal OSStatus
4634 menu_target_item_handler (next_handler
, event
, data
)
4635 EventHandlerCallRef next_handler
;
4641 MenuItemIndex menu_item
;
4644 int specpdl_count
= SPECPDL_INDEX ();
4646 /* Don't be bothered with the overflowed toolbar items menu. */
4647 if (!popup_activated ())
4648 return eventNotHandledErr
;
4650 err
= GetEventParameter (event
, kEventParamDirectObject
, typeMenuRef
,
4651 NULL
, sizeof (MenuRef
), NULL
, &menu
);
4653 err
= GetEventParameter (event
, kEventParamMenuItemIndex
,
4654 typeMenuItemIndex
, NULL
,
4655 sizeof (MenuItemIndex
), NULL
, &menu_item
);
4657 err
= GetMenuItemProperty (menu
, menu_item
,
4658 MAC_EMACS_CREATOR_CODE
, 'help',
4659 sizeof (Lisp_Object
), NULL
, &help
);
4663 /* Temporarily bind Vshow_help_function to Qnil because we don't
4664 want tooltips during menu tracking. */
4665 record_unwind_protect (restore_show_help_function
, Vshow_help_function
);
4666 Vshow_help_function
= Qnil
;
4668 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
4670 unbind_to (specpdl_count
, Qnil
);
4672 return err
== noErr
? noErr
: eventNotHandledErr
;
4675 /* Showing help echo string during menu tracking. */
4678 install_menu_target_item_handler ()
4680 static const EventTypeSpec specs
[] =
4681 {{kEventClassMenu
, kEventMenuTargetItem
}};
4683 return InstallApplicationEventHandler (NewEventHandlerUPP
4684 (menu_target_item_handler
),
4685 GetEventTypeCount (specs
),
4688 #endif /* TARGET_API_MAC_CARBON */
4690 /* Event handler function that pops down a menu on C-g. We can only pop
4691 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4693 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4694 static pascal OSStatus
4695 menu_quit_handler (nextHandler
, theEvent
, userData
)
4696 EventHandlerCallRef nextHandler
;
4702 UInt32 keyModifiers
;
4704 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
4705 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
4708 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
4709 typeUInt32
, NULL
, sizeof(UInt32
),
4710 NULL
, &keyModifiers
);
4712 if (err
== noErr
&& mac_quit_char_key_p (keyModifiers
, keyCode
))
4714 MenuRef menu
= userData
!= 0
4715 ? (MenuRef
)userData
: AcquireRootMenu ();
4717 CancelMenuTracking (menu
, true, 0);
4718 if (!userData
) ReleaseMenu (menu
);
4722 return CallNextEventHandler (nextHandler
, theEvent
);
4724 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4726 /* Add event handler to all menus that belong to KIND so we can detect
4727 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4728 when C-g is detected. NULL means the menu bar. If
4729 CancelMenuTracking isn't available, do nothing. */
4732 install_menu_quit_handler (kind
, root_menu
)
4733 enum mac_menu_kind kind
;
4736 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4737 static const EventTypeSpec typesList
[] =
4738 {{kEventClassKeyboard
, kEventRawKeyDown
}};
4741 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4742 if (CancelMenuTracking
== NULL
)
4745 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
4747 MenuRef menu
= GetMenuRef (id
);
4751 InstallMenuEventHandler (menu
, menu_quit_handler
,
4752 GetEventTypeCount (typesList
),
4753 typesList
, root_menu
, NULL
);
4755 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4762 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
4763 FRAME_PTR f
= p
->pointer
;
4764 MenuRef menu
= GetMenuRef (min_menu_id
[MAC_MENU_POPUP
]);
4768 /* Must reset this manually because the button release event is not
4769 passed to Emacs event loop. */
4770 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
4772 /* delete all menus */
4773 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
4774 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
4782 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4783 until the menu pops down. Return the selection. */
4786 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
4788 widget_value
*first_wv
;
4794 MenuRef menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
4795 int menu_item_choice
;
4796 int specpdl_count
= SPECPDL_INDEX ();
4798 InsertMenu (menu
, -1);
4799 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
4800 min_menu_id
[MAC_MENU_POPUP_SUB
]);
4802 /* Add event handler so we can detect C-g. */
4803 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
4804 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
4806 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
4808 /* Adjust coordinates to be root-window-relative. */
4809 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
4810 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
4812 /* Display the menu. */
4813 popup_activated_flag
= 1;
4814 menu_item_choice
= PopUpMenuSelect (menu
, y
, x
, 0);
4815 popup_activated_flag
= 0;
4817 /* Get the refcon to find the correct item */
4818 if (menu_item_choice
)
4820 MenuRef sel_menu
= GetMenuRef (HiWord (menu_item_choice
));
4823 GetMenuItemRefCon (sel_menu
, LoWord (menu_item_choice
),
4824 (UInt32
*) &result
);
4827 unbind_to (specpdl_count
, Qnil
);
4829 menu_item_selection
= result
;
4833 add_menu_item (menu
, pos
, wv
)
4838 #if TARGET_API_MAC_CARBON
4839 CFStringRef item_name
;
4844 if (name_is_separator (wv
->name
))
4845 AppendMenu (menu
, "\p-");
4848 AppendMenu (menu
, "\pX");
4850 #if TARGET_API_MAC_CARBON
4851 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
4853 if (wv
->key
!= NULL
)
4855 CFStringRef name
, key
;
4858 key
= cfstring_create_with_utf8_cstring (wv
->key
);
4859 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
4865 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
4866 CFRelease (item_name
);
4869 EnableMenuItem (menu
, pos
);
4871 DisableMenuItem (menu
, pos
);
4873 if (STRINGP (wv
->help
))
4874 SetMenuItemProperty (menu
, pos
, MAC_EMACS_CREATOR_CODE
, 'help',
4875 sizeof (Lisp_Object
), &wv
->help
);
4876 #else /* ! TARGET_API_MAC_CARBON */
4877 item_name
[sizeof (item_name
) - 1] = '\0';
4878 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
4879 if (wv
->key
!= NULL
)
4881 int len
= strlen (item_name
);
4883 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
4884 len
= strlen (item_name
);
4885 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
4888 SetMenuItemText (menu
, pos
, item_name
);
4891 EnableItem (menu
, pos
);
4893 DisableItem (menu
, pos
);
4894 #endif /* ! TARGET_API_MAC_CARBON */
4896 /* Draw radio buttons and tickboxes. */
4897 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
4898 || wv
->button_type
== BUTTON_TYPE_RADIO
))
4899 SetItemMark (menu
, pos
, checkMark
);
4901 SetItemMark (menu
, pos
, noMark
);
4903 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
4907 /* Construct native Mac OS menu based on widget_value tree. */
4910 fill_menu (menu
, wv
, kind
, submenu_id
)
4913 enum mac_menu_kind kind
;
4918 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
4920 add_menu_item (menu
, pos
, wv
);
4921 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
4923 MenuRef submenu
= NewMenu (submenu_id
, "\pX");
4925 InsertMenu (submenu
, -1);
4926 #if TARGET_API_MAC_CARBON
4927 SetMenuItemHierarchicalMenu (menu
, pos
, submenu
);
4929 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
4931 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
4938 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4939 the entire menu trees we supply, rather than just the menu bar item
4943 mac_fill_menubar (wv
, deep_p
)
4948 #if !TARGET_API_MAC_CARBON
4949 int title_changed_p
= 0;
4952 /* Clean up the menu bar when filled by the entire menu trees. */
4955 dispose_menus (MAC_MENU_MENU_BAR
, 0);
4956 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
4957 #if !TARGET_API_MAC_CARBON
4958 title_changed_p
= 1;
4962 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4963 titles as much as possible to minimize redraw (if !deep_p). */
4964 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
4965 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
4966 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
4967 wv
= wv
->next
, id
++)
4969 OSStatus err
= noErr
;
4971 #if TARGET_API_MAC_CARBON
4974 title
= CFStringCreateWithCString (NULL
, wv
->name
,
4975 kCFStringEncodingMacRoman
);
4979 strncpy (title
, wv
->name
, 255);
4984 menu
= GetMenuRef (id
);
4987 #if TARGET_API_MAC_CARBON
4988 CFStringRef old_title
;
4990 err
= CopyMenuTitleAsCFString (menu
, &old_title
);
4993 if (CFStringCompare (title
, old_title
, 0) != kCFCompareEqualTo
)
4996 if (id
+ 1 == min_menu_id
[MAC_MENU_MENU_BAR
+ 1]
4997 || GetMenuRef (id
+ 1) == NULL
)
4999 /* This is a workaround for Mac OS X 10.5 where
5000 just calling SetMenuTitleWithCFString fails
5001 to change the title of the last (Help) menu
5008 #endif /* MAC_OSX */
5009 err
= SetMenuTitleWithCFString (menu
, title
);
5011 CFRelease (old_title
);
5014 err
= SetMenuTitleWithCFString (menu
, title
);
5015 #else /* !TARGET_API_MAC_CARBON */
5016 if (!EqualString (title
, (*menu
)->menuData
, false, false))
5020 menu
= NewMenu (id
, title
);
5021 InsertMenu (menu
, GetMenuRef (id
+ 1) ? id
+ 1 : 0);
5022 title_changed_p
= 1;
5024 #endif /* !TARGET_API_MAC_CARBON */
5029 #if TARGET_API_MAC_CARBON
5030 err
= CreateNewMenu (id
, 0, &menu
);
5032 err
= SetMenuTitleWithCFString (menu
, title
);
5034 menu
= NewMenu (id
, title
);
5038 InsertMenu (menu
, 0);
5039 #if !TARGET_API_MAC_CARBON
5040 title_changed_p
= 1;
5044 #if TARGET_API_MAC_CARBON
5050 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
5054 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuRef (id
))
5056 dispose_menus (MAC_MENU_MENU_BAR
, id
);
5057 #if !TARGET_API_MAC_CARBON
5058 title_changed_p
= 1;
5062 #if !TARGET_API_MAC_CARBON
5063 if (title_changed_p
)
5067 /* Add event handler so we can detect C-g. */
5068 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
5069 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
5072 /* Dispose of menus that belong to KIND, and remove them from the menu
5073 list. ID is the lower bound of menu IDs that will be processed. */
5076 dispose_menus (kind
, id
)
5077 enum mac_menu_kind kind
;
5080 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
5082 MenuRef menu
= GetMenuRef (id
);
5097 MenuItemIndex menu_index
;
5099 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandQuit
, 1,
5100 &menu
, &menu_index
);
5102 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5103 EnableMenuCommand (NULL
, kHICommandPreferences
);
5104 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandPreferences
, 1,
5105 &menu
, &menu_index
);
5108 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5109 InsertMenuItemTextWithCFString (menu
, NULL
,
5110 0, kMenuItemAttrSeparator
, 0);
5111 InsertMenuItemTextWithCFString (menu
, CFSTR ("About Emacs"),
5112 0, 0, kHICommandAbout
);
5114 #else /* !MAC_OSX */
5115 #if TARGET_API_MAC_CARBON
5116 SetMenuItemCommandID (GetMenuRef (M_APPLE
), I_ABOUT
, kHICommandAbout
);
5122 /***********************************************************************
5124 ***********************************************************************/
5126 #if TARGET_API_MAC_CARBON
5127 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5128 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5129 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5130 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5131 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5132 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5133 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5135 extern EMACS_TIME timer_check
P_ ((int));
5136 static int quit_dialog_event_loop
;
5138 static pascal OSStatus
5139 mac_handle_dialog_event (next_handler
, event
, data
)
5140 EventHandlerCallRef next_handler
;
5144 OSStatus err
, result
= eventNotHandledErr
;
5145 WindowRef window
= (WindowRef
) data
;
5147 switch (GetEventClass (event
))
5149 case kEventClassCommand
:
5153 err
= GetEventParameter (event
, kEventParamDirectObject
,
5154 typeHICommand
, NULL
, sizeof (HICommand
),
5157 if (DIALOG_BUTTON_COMMAND_ID_P (command
.commandID
))
5159 SetWRefCon (window
, command
.commandID
);
5160 quit_dialog_event_loop
= 1;
5164 result
= CallNextEventHandler (next_handler
, event
);
5168 case kEventClassKeyboard
:
5173 result
= CallNextEventHandler (next_handler
, event
);
5174 if (result
!= eventNotHandledErr
)
5177 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
5178 typeChar
, NULL
, sizeof (char),
5183 case kEscapeCharCode
:
5184 quit_dialog_event_loop
= 1;
5189 UInt32 modifiers
, key_code
;
5191 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
5192 typeUInt32
, NULL
, sizeof (UInt32
),
5195 err
= GetEventParameter (event
, kEventParamKeyCode
,
5196 typeUInt32
, NULL
, sizeof (UInt32
),
5199 if (mac_quit_char_key_p (modifiers
, key_code
))
5200 quit_dialog_event_loop
= 1;
5211 if (quit_dialog_event_loop
)
5213 err
= QuitEventLoop (GetCurrentEventLoop ());
5222 install_dialog_event_handler (window
)
5225 static const EventTypeSpec specs
[] =
5226 {{kEventClassCommand
, kEventCommandProcess
},
5227 {kEventClassKeyboard
, kEventRawKeyDown
}};
5228 static EventHandlerUPP handle_dialog_eventUPP
= NULL
;
5230 if (handle_dialog_eventUPP
== NULL
)
5231 handle_dialog_eventUPP
= NewEventHandlerUPP (mac_handle_dialog_event
);
5232 return InstallWindowEventHandler (window
, handle_dialog_eventUPP
,
5233 GetEventTypeCount (specs
), specs
,
5238 pop_down_dialog (arg
)
5241 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
5242 WindowRef window
= p
->pointer
;
5246 if (popup_activated_flag
)
5247 EndAppModalStateForWindow (window
);
5248 DisposeWindow (window
);
5249 popup_activated_flag
= 0;
5256 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5258 menu_item_selection will be set to the selection. */
5261 create_and_show_dialog (f
, first_wv
)
5263 widget_value
*first_wv
;
5266 char *dialog_name
, *message
;
5267 int nb_buttons
, first_group_count
, i
, result
= 0;
5269 short buttons_height
, text_height
, inner_width
, inner_height
;
5270 Rect empty_rect
, *rects
;
5271 WindowRef window
= NULL
;
5272 ControlRef
*buttons
, default_button
= NULL
, text
;
5273 int specpdl_count
= SPECPDL_INDEX ();
5275 dialog_name
= first_wv
->name
;
5276 nb_buttons
= dialog_name
[1] - '0';
5277 first_group_count
= nb_buttons
- (dialog_name
[4] - '0');
5279 wv
= first_wv
->contents
;
5280 message
= wv
->value
;
5283 SetRect (&empty_rect
, 0, 0, 0, 0);
5285 /* Create dialog window. */
5286 err
= CreateNewWindow (kMovableModalWindowClass
,
5287 kWindowStandardHandlerAttribute
,
5288 &empty_rect
, &window
);
5291 record_unwind_protect (pop_down_dialog
, make_save_value (window
, 0));
5292 err
= SetThemeWindowBackground (window
, kThemeBrushMovableModalBackground
,
5296 err
= SetWindowTitleWithCFString (window
, (dialog_name
[0] == 'Q'
5297 ? CFSTR ("Question")
5298 : CFSTR ("Information")));
5300 /* Create button controls and measure their optimal bounds. */
5303 buttons
= alloca (sizeof (ControlRef
) * nb_buttons
);
5304 rects
= alloca (sizeof (Rect
) * nb_buttons
);
5305 for (i
= 0; i
< nb_buttons
; i
++)
5307 CFStringRef label
= cfstring_create_with_utf8_cstring (wv
->value
);
5313 err
= CreatePushButtonControl (window
, &empty_rect
,
5314 label
, &buttons
[i
]);
5322 err
= DisableControl (buttons
[i
]);
5324 err
= DeactivateControl (buttons
[i
]);
5327 else if (default_button
== NULL
)
5328 default_button
= buttons
[i
];
5334 rects
[i
] = empty_rect
;
5335 err
= GetBestControlRect (buttons
[i
], &rects
[i
], &unused
);
5341 OffsetRect (&rects
[i
], -rects
[i
].left
, -rects
[i
].top
);
5342 if (rects
[i
].right
< DIALOG_BUTTON_MIN_WIDTH
)
5343 rects
[i
].right
= DIALOG_BUTTON_MIN_WIDTH
;
5344 else if (rects
[i
].right
> DIALOG_MAX_INNER_WIDTH
)
5345 rects
[i
].right
= DIALOG_MAX_INNER_WIDTH
;
5347 command_id
= DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv
->call_data
);
5348 err
= SetControlCommandID (buttons
[i
], command_id
);
5356 /* Layout buttons. rects[i] is set relative to the bottom-right
5357 corner of the inner box. */
5360 short bottom
, right
, max_height
, left_align_shift
;
5362 inner_width
= DIALOG_MIN_INNER_WIDTH
;
5363 bottom
= right
= max_height
= 0;
5364 for (i
= 0; i
< nb_buttons
; i
++)
5366 if (right
- rects
[i
].right
< - inner_width
)
5368 if (i
!= first_group_count
5369 && right
- rects
[i
].right
>= - DIALOG_MAX_INNER_WIDTH
)
5370 inner_width
= - (right
- rects
[i
].right
);
5373 bottom
-= max_height
+ DIALOG_BUTTON_BUTTON_VERTICAL_SPACE
;
5374 right
= max_height
= 0;
5377 if (max_height
< rects
[i
].bottom
)
5378 max_height
= rects
[i
].bottom
;
5379 OffsetRect (&rects
[i
], right
- rects
[i
].right
,
5380 bottom
- rects
[i
].bottom
);
5381 right
= rects
[i
].left
- DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5382 if (i
== first_group_count
- 1)
5383 right
-= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5385 buttons_height
= - (bottom
- max_height
);
5387 left_align_shift
= - (inner_width
+ rects
[nb_buttons
- 1].left
);
5388 for (i
= nb_buttons
- 1; i
>= first_group_count
; i
--)
5390 if (bottom
!= rects
[i
].bottom
)
5392 left_align_shift
= - (inner_width
+ rects
[i
].left
);
5393 bottom
= rects
[i
].bottom
;
5395 OffsetRect (&rects
[i
], left_align_shift
, 0);
5399 /* Create a static text control and measure its bounds. */
5402 CFStringRef message_string
;
5405 message_string
= cfstring_create_with_utf8_cstring (message
);
5406 if (message_string
== NULL
)
5410 ControlFontStyleRec text_style
;
5412 text_style
.flags
= 0;
5413 SetRect (&bounds
, 0, 0, inner_width
, 0);
5414 err
= CreateStaticTextControl (window
, &bounds
, message_string
,
5415 &text_style
, &text
);
5416 CFRelease (message_string
);
5422 bounds
= empty_rect
;
5423 err
= GetBestControlRect (text
, &bounds
, &unused
);
5427 text_height
= bounds
.bottom
- bounds
.top
;
5428 if (text_height
< DIALOG_TEXT_MIN_HEIGHT
)
5429 text_height
= DIALOG_TEXT_MIN_HEIGHT
;
5433 /* Place buttons. */
5436 inner_height
= (text_height
+ DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5439 for (i
= 0; i
< nb_buttons
; i
++)
5441 OffsetRect (&rects
[i
], DIALOG_LEFT_MARGIN
+ inner_width
,
5442 DIALOG_TOP_MARGIN
+ inner_height
);
5443 SetControlBounds (buttons
[i
], &rects
[i
]);
5452 SetRect (&bounds
, DIALOG_LEFT_MARGIN
, DIALOG_TOP_MARGIN
,
5453 DIALOG_LEFT_MARGIN
+ inner_width
,
5454 DIALOG_TOP_MARGIN
+ text_height
);
5455 SetControlBounds (text
, &bounds
);
5458 /* Create the application icon at the upper-left corner. */
5461 ControlButtonContentInfo content
;
5463 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
5467 ProcessInfoRec pinfo
;
5472 content
.contentType
= kControlContentIconRef
;
5474 err
= GetProcessBundleLocation (&psn
, &app_location
);
5476 err
= GetIconRefFromFileInfo (&app_location
, 0, NULL
, 0, NULL
,
5477 kIconServicesNormalUsageFlag
,
5478 &content
.u
.iconRef
, &unused
);
5480 bzero (&pinfo
, sizeof (ProcessInfoRec
));
5481 pinfo
.processInfoLength
= sizeof (ProcessInfoRec
);
5482 pinfo
.processAppSpec
= &app_spec
;
5483 err
= GetProcessInformation (&psn
, &pinfo
);
5485 err
= GetIconRefFromFile (&app_spec
, &content
.u
.iconRef
, &unused
);
5491 SetRect (&bounds
, DIALOG_ICON_LEFT_MARGIN
, DIALOG_ICON_TOP_MARGIN
,
5492 DIALOG_ICON_LEFT_MARGIN
+ DIALOG_ICON_WIDTH
,
5493 DIALOG_ICON_TOP_MARGIN
+ DIALOG_ICON_HEIGHT
);
5494 err
= CreateIconControl (window
, &bounds
, &content
, true, &icon
);
5495 ReleaseIconRef (content
.u
.iconRef
);
5499 /* Show the dialog window and run event loop. */
5502 err
= SetWindowDefaultButton (window
, default_button
);
5504 err
= install_dialog_event_handler (window
);
5508 DIALOG_LEFT_MARGIN
+ inner_width
+ DIALOG_RIGHT_MARGIN
,
5509 DIALOG_TOP_MARGIN
+ inner_height
+ DIALOG_BOTTOM_MARGIN
,
5511 err
= RepositionWindow (window
, FRAME_MAC_WINDOW (f
),
5512 kWindowAlertPositionOnParentWindow
);
5516 SetWRefCon (window
, 0);
5517 ShowWindow (window
);
5518 BringToFront (window
);
5519 popup_activated_flag
= 1;
5520 err
= BeginAppModalStateForWindow (window
);
5524 EventTargetRef toolbox_dispatcher
= GetEventDispatcherTarget ();
5526 quit_dialog_event_loop
= 0;
5529 EMACS_TIME next_time
= timer_check (1);
5530 long secs
= EMACS_SECS (next_time
);
5531 long usecs
= EMACS_USECS (next_time
);
5532 EventTimeout timeout
;
5535 if (secs
< 0 || (secs
== 0 && usecs
== 0))
5537 /* Sometimes timer_check returns -1 (no timers) even if
5538 there are timers. So do a timeout anyway. */
5543 timeout
= (secs
* kEventDurationSecond
5544 + usecs
* kEventDurationMicrosecond
);
5545 err
= ReceiveNextEvent (0, NULL
, timeout
, kEventRemoveFromQueue
,
5549 SendEventToEventTarget (event
, toolbox_dispatcher
);
5550 ReleaseEvent (event
);
5552 #if 0 /* defined (MAC_OSX) */
5553 else if (err
!= eventLoopTimedOutErr
)
5555 if (err
== eventLoopQuitErr
)
5560 /* The return value of ReceiveNextEvent seems to be
5561 unreliable. Use our own global variable instead. */
5562 if (quit_dialog_event_loop
)
5572 UInt32 command_id
= GetWRefCon (window
);
5574 if (DIALOG_BUTTON_COMMAND_ID_P (command_id
))
5575 result
= DIALOG_BUTTON_COMMAND_ID_VALUE (command_id
);
5578 unbind_to (specpdl_count
, Qnil
);
5580 menu_item_selection
= result
;
5582 #else /* not TARGET_API_MAC_CARBON */
5583 #define DIALOG_WINDOW_RESOURCE 130
5586 mac_dialog (widget_value
*wv
)
5590 char **button_labels
;
5597 WindowRef window_ptr
;
5600 EventRecord event_record
;
5602 int control_part_code
;
5605 dialog_name
= wv
->name
;
5606 nb_buttons
= dialog_name
[1] - '0';
5607 left_count
= nb_buttons
- (dialog_name
[4] - '0');
5608 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
5609 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
5612 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
5613 strcpy (prompt
, wv
->value
);
5617 for (i
= 0; i
< nb_buttons
; i
++)
5619 button_labels
[i
] = wv
->value
;
5620 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
5621 strcpy (button_labels
[i
], wv
->value
);
5622 c2pstr (button_labels
[i
]);
5623 ref_cons
[i
] = (UInt32
) wv
->call_data
;
5627 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowRef
) -1);
5629 SetPortWindowPort (window_ptr
);
5632 /* Left and right margins in the dialog are 13 pixels each.*/
5634 /* Calculate width of dialog box: 8 pixels on each side of the text
5635 label in each button, 12 pixels between buttons. */
5636 for (i
= 0; i
< nb_buttons
; i
++)
5637 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
5639 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
5642 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
5644 SizeWindow (window_ptr
, dialog_width
, 78, 0);
5645 ShowWindow (window_ptr
);
5647 SetPortWindowPort (window_ptr
);
5652 DrawString (prompt
);
5655 for (i
= 0; i
< nb_buttons
; i
++)
5657 int button_width
= StringWidth (button_labels
[i
]) + 16;
5658 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
5659 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
5660 kControlPushButtonProc
, ref_cons
[i
]);
5661 left
+= button_width
+ 12;
5662 if (i
== left_count
- 1)
5669 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
5670 if (event_record
.what
== mouseDown
)
5672 part_code
= FindWindow (event_record
.where
, &window_ptr
);
5673 if (part_code
== inContent
)
5675 mouse
= event_record
.where
;
5676 GlobalToLocal (&mouse
);
5677 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
5678 if (control_part_code
== kControlButtonPart
)
5679 if (TrackControl (ch
, mouse
, NULL
))
5680 i
= GetControlReference (ch
);
5685 DisposeWindow (window_ptr
);
5689 #endif /* not TARGET_API_MAC_CARBON */
5692 /***********************************************************************
5694 ***********************************************************************/
5696 #if !TARGET_API_MAC_CARBON
5701 extern Lisp_Object Vselection_converter_alist
;
5702 extern Lisp_Object Qmac_scrap_name
, Qmac_ostype
;
5704 static ScrapFlavorType get_flavor_type_from_symbol
P_ ((Lisp_Object
,
5707 /* Get a reference to the selection corresponding to the symbol SYM.
5708 The reference is set to *SEL, and it becomes NULL if there's no
5709 corresponding selection. Clear the selection if CLEAR_P is
5713 mac_get_selection_from_symbol (sym
, clear_p
, sel
)
5718 OSStatus err
= noErr
;
5719 Lisp_Object str
= Fget (sym
, Qmac_scrap_name
);
5725 #if TARGET_API_MAC_CARBON
5727 CFStringRef scrap_name
= cfstring_create_with_string (str
);
5728 OptionBits options
= (clear_p
? kScrapClearNamedScrap
5729 : kScrapGetNamedScrap
);
5731 err
= GetScrapByName (scrap_name
, options
, sel
);
5732 CFRelease (scrap_name
);
5733 #else /* !MAC_OSX */
5735 err
= ClearCurrentScrap ();
5737 err
= GetCurrentScrap (sel
);
5738 #endif /* !MAC_OSX */
5739 #else /* !TARGET_API_MAC_CARBON */
5744 #endif /* !TARGET_API_MAC_CARBON */
5750 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5751 corresponding flavor type. If SEL is non-zero, the return value is
5752 non-zero only when the SEL has the flavor type. */
5754 static ScrapFlavorType
5755 get_flavor_type_from_symbol (sym
, sel
)
5759 Lisp_Object str
= Fget (sym
, Qmac_ostype
);
5760 ScrapFlavorType flavor_type
;
5762 if (STRINGP (str
) && SBYTES (str
) == 4)
5763 flavor_type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
5767 if (flavor_type
&& sel
)
5769 #if TARGET_API_MAC_CARBON
5771 ScrapFlavorFlags flags
;
5773 err
= GetScrapFlavorFlags (sel
, flavor_type
, &flags
);
5776 #else /* !TARGET_API_MAC_CARBON */
5777 SInt32 size
, offset
;
5779 size
= GetScrap (NULL
, flavor_type
, &offset
);
5782 #endif /* !TARGET_API_MAC_CARBON */
5788 /* Check if the symbol SYM has a corresponding selection target type. */
5791 mac_valid_selection_target_p (sym
)
5794 return get_flavor_type_from_symbol (sym
, 0) != 0;
5797 /* Clear the selection whose reference is *SEL. */
5800 mac_clear_selection (sel
)
5803 #if TARGET_API_MAC_CARBON
5805 return ClearScrap (sel
);
5809 err
= ClearCurrentScrap ();
5811 err
= GetCurrentScrap (sel
);
5814 #else /* !TARGET_API_MAC_CARBON */
5815 return ZeroScrap ();
5816 #endif /* !TARGET_API_MAC_CARBON */
5819 /* Get ownership information for SEL. Emacs can detect a change of
5820 the ownership by comparing saved and current values of the
5821 ownership information. */
5824 mac_get_selection_ownership_info (sel
)
5827 #if TARGET_API_MAC_CARBON
5828 return long_to_cons ((unsigned long) sel
);
5829 #else /* !TARGET_API_MAC_CARBON */
5830 ScrapStuffPtr scrap_info
= InfoScrap ();
5832 return make_number (scrap_info
->scrapCount
);
5833 #endif /* !TARGET_API_MAC_CARBON */
5836 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5839 mac_valid_selection_value_p (value
, target
)
5840 Lisp_Object value
, target
;
5842 return STRINGP (value
);
5845 /* Put Lisp object VALUE to the selection SEL. The target type is
5846 specified by TARGET. */
5849 mac_put_selection_value (sel
, target
, value
)
5851 Lisp_Object target
, value
;
5853 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, 0);
5855 if (flavor_type
== 0 || !STRINGP (value
))
5858 #if TARGET_API_MAC_CARBON
5859 return PutScrapFlavor (sel
, flavor_type
, kScrapFlavorMaskNone
,
5860 SBYTES (value
), SDATA (value
));
5861 #else /* !TARGET_API_MAC_CARBON */
5862 return PutScrap (SBYTES (value
), flavor_type
, SDATA (value
));
5863 #endif /* !TARGET_API_MAC_CARBON */
5866 /* Check if data for the target type TARGET is available in SEL. */
5869 mac_selection_has_target_p (sel
, target
)
5873 return get_flavor_type_from_symbol (target
, sel
) != 0;
5876 /* Get data for the target type TARGET from SEL and create a Lisp
5877 string. Return nil if failed to get data. */
5880 mac_get_selection_value (sel
, target
)
5885 Lisp_Object result
= Qnil
;
5886 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, sel
);
5887 #if TARGET_API_MAC_CARBON
5892 err
= GetScrapFlavorSize (sel
, flavor_type
, &size
);
5897 result
= make_uninit_string (size
);
5898 err
= GetScrapFlavorData (sel
, flavor_type
,
5899 &size
, SDATA (result
));
5902 else if (size
< SBYTES (result
))
5903 result
= make_unibyte_string (SDATA (result
), size
);
5905 while (STRINGP (result
) && size
> SBYTES (result
));
5910 SInt32 size
, offset
;
5913 size
= GetScrap (NULL
, flavor_type
, &offset
);
5916 handle
= NewHandle (size
);
5918 size
= GetScrap (handle
, flavor_type
, &offset
);
5920 result
= make_unibyte_string (*handle
, size
);
5921 DisposeHandle (handle
);
5928 /* Get the list of target types in SEL. The return value is a list of
5929 target type symbols possibly followed by scrap flavor type
5933 mac_get_selection_target_list (sel
)
5936 Lisp_Object result
= Qnil
, rest
, target
;
5937 #if TARGET_API_MAC_CARBON
5939 UInt32 count
, i
, type
;
5940 ScrapFlavorInfo
*flavor_info
= NULL
;
5941 Lisp_Object strings
= Qnil
;
5943 err
= GetScrapFlavorCount (sel
, &count
);
5945 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
5946 err
= GetScrapFlavorInfoList (sel
, &count
, flavor_info
);
5949 xfree (flavor_info
);
5952 if (flavor_info
== NULL
)
5955 for (rest
= Vselection_converter_alist
; CONSP (rest
); rest
= XCDR (rest
))
5957 ScrapFlavorType flavor_type
= 0;
5959 if (CONSP (XCAR (rest
))
5960 && (target
= XCAR (XCAR (rest
)),
5962 && (flavor_type
= get_flavor_type_from_symbol (target
, sel
)))
5964 result
= Fcons (target
, result
);
5965 #if TARGET_API_MAC_CARBON
5966 for (i
= 0; i
< count
; i
++)
5967 if (flavor_info
[i
].flavorType
== flavor_type
)
5969 flavor_info
[i
].flavorType
= 0;
5975 #if TARGET_API_MAC_CARBON
5978 for (i
= 0; i
< count
; i
++)
5979 if (flavor_info
[i
].flavorType
)
5981 type
= EndianU32_NtoB (flavor_info
[i
].flavorType
);
5982 strings
= Fcons (make_unibyte_string ((char *) &type
, 4), strings
);
5984 result
= nconc2 (result
, strings
);
5985 xfree (flavor_info
);
5993 /***********************************************************************
5995 ***********************************************************************/
5997 extern pascal OSErr mac_handle_apple_event
P_ ((const AppleEvent
*,
5998 AppleEvent
*, SInt32
));
5999 extern void cleanup_all_suspended_apple_events
P_ ((void));
6002 init_apple_event_handler ()
6007 /* Make sure we have Apple events before starting. */
6008 err
= Gestalt (gestaltAppleEventsAttr
, &result
);
6012 if (!(result
& (1 << gestaltAppleEventsPresent
)))
6015 err
= AEInstallEventHandler (typeWildCard
, typeWildCard
,
6016 #if TARGET_API_MAC_CARBON
6017 NewAEEventHandlerUPP (mac_handle_apple_event
),
6019 NewAEEventHandlerProc (mac_handle_apple_event
),
6025 atexit (cleanup_all_suspended_apple_events
);
6029 /***********************************************************************
6030 Drag and drop support
6031 ***********************************************************************/
6033 #if TARGET_API_MAC_CARBON
6034 extern Lisp_Object Vmac_dnd_known_types
;
6036 static pascal OSErr mac_do_track_drag
P_ ((DragTrackingMessage
, WindowRef
,
6038 static pascal OSErr mac_do_receive_drag
P_ ((WindowRef
, void *, DragRef
));
6039 static DragTrackingHandlerUPP mac_do_track_dragUPP
= NULL
;
6040 static DragReceiveHandlerUPP mac_do_receive_dragUPP
= NULL
;
6043 create_apple_event_from_drag_ref (drag
, num_types
, types
, result
)
6046 const FlavorType
*types
;
6055 err
= CountDragItems (drag
, &num_items
);
6058 err
= AECreateList (NULL
, 0, false, &items
);
6062 for (index
= 1; index
<= num_items
; index
++)
6065 DescType desc_type
= typeNull
;
6068 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6073 for (i
= 0; i
< num_types
; i
++)
6075 err
= GetFlavorDataSize (drag
, item
, types
[i
], &size
);
6078 buf
= xrealloc (buf
, size
);
6079 err
= GetFlavorData (drag
, item
, types
[i
], buf
, &size
, 0);
6083 desc_type
= types
[i
];
6088 err
= AEPutPtr (&items
, index
, desc_type
,
6089 desc_type
!= typeNull
? buf
: NULL
,
6090 desc_type
!= typeNull
? size
: 0);
6098 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
6100 err
= AEPutParamDesc (result
, keyDirectObject
, &items
);
6102 AEDisposeDesc (result
);
6105 AEDisposeDesc (&items
);
6111 mac_store_drag_event (window
, mouse_pos
, modifiers
, desc
)
6117 struct input_event buf
;
6121 buf
.kind
= DRAG_N_DROP_EVENT
;
6122 buf
.modifiers
= mac_to_emacs_modifiers (modifiers
, 0);
6123 buf
.timestamp
= TickCount () * (1000 / 60);
6124 XSETINT (buf
.x
, mouse_pos
.h
);
6125 XSETINT (buf
.y
, mouse_pos
.v
);
6126 XSETFRAME (buf
.frame_or_window
, mac_window_to_frame (window
));
6127 buf
.arg
= mac_aedesc_to_lisp (desc
);
6128 kbd_buffer_store_event (&buf
);
6132 mac_do_track_drag (message
, window
, refcon
, drag
)
6133 DragTrackingMessage message
;
6139 static int can_accept
;
6140 UInt16 num_items
, index
;
6142 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6143 return dragNotAcceptedErr
;
6147 case kDragTrackingEnterHandler
:
6148 err
= CountDragItems (drag
, &num_items
);
6152 for (index
= 1; index
<= num_items
; index
++)
6158 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6161 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6167 if (!(STRINGP (str
) && SBYTES (str
) == 4))
6169 type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6171 err
= GetFlavorFlags (drag
, item
, type
, &flags
);
6181 case kDragTrackingEnterWindow
:
6184 RgnHandle hilite_rgn
= NewRgn ();
6190 GetWindowPortBounds (window
, &r
);
6191 OffsetRect (&r
, -r
.left
, -r
.top
);
6192 RectRgn (hilite_rgn
, &r
);
6193 ShowDragHilite (drag
, hilite_rgn
, true);
6194 DisposeRgn (hilite_rgn
);
6196 SetThemeCursor (kThemeCopyArrowCursor
);
6200 case kDragTrackingInWindow
:
6203 case kDragTrackingLeaveWindow
:
6206 HideDragHilite (drag
);
6207 SetThemeCursor (kThemeArrowCursor
);
6211 case kDragTrackingLeaveHandler
:
6216 return dragNotAcceptedErr
;
6221 mac_do_receive_drag (window
, refcon
, drag
)
6228 Lisp_Object rest
, str
;
6230 AppleEvent apple_event
;
6234 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6235 return dragNotAcceptedErr
;
6238 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6241 if (STRINGP (str
) && SBYTES (str
) == 4)
6245 types
= xmalloc (sizeof (FlavorType
) * num_types
);
6247 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6250 if (STRINGP (str
) && SBYTES (str
) == 4)
6251 types
[i
++] = EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6254 err
= create_apple_event_from_drag_ref (drag
, num_types
, types
,
6259 err
= GetDragMouse (drag
, &mouse_pos
, NULL
);
6262 GlobalToLocal (&mouse_pos
);
6263 err
= GetDragModifiers (drag
, NULL
, NULL
, &modifiers
);
6267 UInt32 key_modifiers
= modifiers
;
6269 err
= AEPutParamPtr (&apple_event
, kEventParamKeyModifiers
,
6270 typeUInt32
, &key_modifiers
, sizeof (UInt32
));
6275 mac_store_drag_event (window
, mouse_pos
, 0, &apple_event
);
6276 AEDisposeDesc (&apple_event
);
6277 mac_wakeup_from_rne ();
6281 return dragNotAcceptedErr
;
6283 #endif /* TARGET_API_MAC_CARBON */
6286 install_drag_handler (window
)
6291 #if TARGET_API_MAC_CARBON
6292 if (mac_do_track_dragUPP
== NULL
)
6293 mac_do_track_dragUPP
= NewDragTrackingHandlerUPP (mac_do_track_drag
);
6294 if (mac_do_receive_dragUPP
== NULL
)
6295 mac_do_receive_dragUPP
= NewDragReceiveHandlerUPP (mac_do_receive_drag
);
6297 err
= InstallTrackingHandler (mac_do_track_dragUPP
, window
, NULL
);
6299 err
= InstallReceiveHandler (mac_do_receive_dragUPP
, window
, NULL
);
6306 remove_drag_handler (window
)
6309 #if TARGET_API_MAC_CARBON
6310 if (mac_do_track_dragUPP
)
6311 RemoveTrackingHandler (mac_do_track_dragUPP
, window
);
6312 if (mac_do_receive_dragUPP
)
6313 RemoveReceiveHandler (mac_do_receive_dragUPP
, window
);
6317 #if TARGET_API_MAC_CARBON
6318 /* Return default value for mac-dnd-known-types. */
6321 mac_dnd_default_known_types ()
6323 Lisp_Object result
= list4 (build_string ("hfs "), build_string ("utxt"),
6324 build_string ("TEXT"), build_string ("TIFF"));
6327 result
= Fcons (build_string ("furl"), result
);
6335 /***********************************************************************
6336 Services menu support
6337 ***********************************************************************/
6340 extern Lisp_Object Qservice
, Qpaste
, Qperform
;
6341 extern Lisp_Object Vmac_service_selection
;
6344 mac_store_service_event (event
)
6350 const EventParamName
*names
;
6351 const EventParamType
*types
;
6352 static const EventParamName names_pfm
[] =
6353 {kEventParamServiceMessageName
, kEventParamServiceUserData
};
6354 static const EventParamType types_pfm
[] =
6355 {typeCFStringRef
, typeCFStringRef
};
6357 switch (GetEventKind (event
))
6359 case kEventServicePaste
:
6366 case kEventServicePerform
:
6368 num_params
= sizeof (names_pfm
) / sizeof (names_pfm
[0]);
6377 err
= mac_store_event_ref_as_apple_event (0, 0, Qservice
, id_key
,
6385 copy_scrap_flavor_data (from_scrap
, to_scrap
, flavor_type
)
6386 ScrapRef from_scrap
, to_scrap
;
6387 ScrapFlavorType flavor_type
;
6390 Size size
, size_allocated
;
6393 err
= GetScrapFlavorSize (from_scrap
, flavor_type
, &size
);
6395 buf
= xmalloc (size
);
6398 size_allocated
= size
;
6399 err
= GetScrapFlavorData (from_scrap
, flavor_type
, &size
, buf
);
6405 else if (size_allocated
< size
)
6406 buf
= xrealloc (buf
, size
);
6416 err
= PutScrapFlavor (to_scrap
, flavor_type
, kScrapFlavorMaskNone
,
6426 mac_handle_service_event (call_ref
, event
, data
)
6427 EventHandlerCallRef call_ref
;
6431 OSStatus err
= noErr
;
6432 ScrapRef cur_scrap
, specific_scrap
;
6433 UInt32 event_kind
= GetEventKind (event
);
6434 CFMutableArrayRef copy_types
, paste_types
;
6437 ScrapFlavorType flavor_type
;
6439 /* Check if Vmac_service_selection is a valid selection that has a
6440 corresponding scrap. */
6441 if (!SYMBOLP (Vmac_service_selection
))
6442 err
= eventNotHandledErr
;
6444 err
= mac_get_selection_from_symbol (Vmac_service_selection
, 0, &cur_scrap
);
6445 if (!(err
== noErr
&& cur_scrap
))
6446 return eventNotHandledErr
;
6450 case kEventServiceGetTypes
:
6451 /* Set paste types. */
6452 err
= GetEventParameter (event
, kEventParamServicePasteTypes
,
6453 typeCFMutableArrayRef
, NULL
,
6454 sizeof (CFMutableArrayRef
), NULL
,
6459 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6461 if (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))
6463 get_flavor_type_from_symbol (XCAR (XCAR (rest
)), 0)))
6465 type
= CreateTypeStringWithOSType (flavor_type
);
6468 CFArrayAppendValue (paste_types
, type
);
6473 /* Set copy types. */
6474 err
= GetEventParameter (event
, kEventParamServiceCopyTypes
,
6475 typeCFMutableArrayRef
, NULL
,
6476 sizeof (CFMutableArrayRef
), NULL
,
6481 if (NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6484 goto copy_all_flavors
;
6486 case kEventServiceCopy
:
6487 err
= GetEventParameter (event
, kEventParamScrapRef
,
6489 sizeof (ScrapRef
), NULL
, &specific_scrap
);
6491 || NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6493 err
= eventNotHandledErr
;
6500 ScrapFlavorInfo
*flavor_info
= NULL
;
6501 ScrapFlavorFlags flags
;
6503 err
= GetScrapFlavorCount (cur_scrap
, &count
);
6505 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
6506 err
= GetScrapFlavorInfoList (cur_scrap
, &count
, flavor_info
);
6509 xfree (flavor_info
);
6512 if (flavor_info
== NULL
)
6515 for (i
= 0; i
< count
; i
++)
6517 flavor_type
= flavor_info
[i
].flavorType
;
6518 err
= GetScrapFlavorFlags (cur_scrap
, flavor_type
, &flags
);
6519 if (err
== noErr
&& !(flags
& kScrapFlavorMaskSenderOnly
))
6521 if (event_kind
== kEventServiceCopy
)
6522 err
= copy_scrap_flavor_data (cur_scrap
, specific_scrap
,
6524 else /* event_kind == kEventServiceGetTypes */
6526 type
= CreateTypeStringWithOSType (flavor_type
);
6529 CFArrayAppendValue (copy_types
, type
);
6535 xfree (flavor_info
);
6539 case kEventServicePaste
:
6540 case kEventServicePerform
:
6542 int data_exists_p
= 0;
6544 err
= GetEventParameter (event
, kEventParamScrapRef
, typeScrapRef
,
6545 NULL
, sizeof (ScrapRef
), NULL
,
6548 err
= mac_clear_selection (&cur_scrap
);
6550 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6553 if (! (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))))
6555 flavor_type
= get_flavor_type_from_symbol (XCAR (XCAR (rest
)),
6557 if (flavor_type
== 0)
6559 err
= copy_scrap_flavor_data (specific_scrap
, cur_scrap
,
6565 err
= eventNotHandledErr
;
6567 err
= mac_store_service_event (event
);
6573 err
= eventNotHandledErr
;
6578 install_service_handler ()
6580 static const EventTypeSpec specs
[] =
6581 {{kEventClassService
, kEventServiceGetTypes
},
6582 {kEventClassService
, kEventServiceCopy
},
6583 {kEventClassService
, kEventServicePaste
},
6584 {kEventClassService
, kEventServicePerform
}};
6586 return InstallApplicationEventHandler (NewEventHandlerUPP
6587 (mac_handle_service_event
),
6588 GetEventTypeCount (specs
),
6591 #endif /* MAC_OSX */
6594 /***********************************************************************
6596 ***********************************************************************/
6599 mac_toolbox_initialize ()
6601 any_help_event_p
= 0;
6606 init_apple_event_handler ();
6613 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6614 (do not change this comment) */