1 /* Functions for GUI implemented with (HI)Toolbox on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
27 #include "blockinput.h"
31 #if !TARGET_API_MAC_CARBON
32 #include <Quickdraw.h>
33 #include <ToolUtils.h>
37 #include <Resources.h>
39 #include <TextUtils.h>
44 #if defined (__MRC__) || (__MSL__ >= 0x6000)
45 #include <ControlDefinitions.h>
51 #endif /* not TARGET_API_MAC_CARBON */
56 #include "dispextern.h"
58 #include "termhooks.h"
63 #include <sys/param.h>
70 /************************************************************************
72 ************************************************************************/
74 /* The difference in pixels between the top left corner of the
75 Emacs window (including possible window manager decorations)
76 and FRAME_MAC_WINDOW (f). */
77 #define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff)
78 #define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff)
80 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
83 mac_alert_sound_play ()
85 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
93 /************************************************************************
95 ************************************************************************/
97 extern struct frame
*mac_focus_frame
P_ ((struct mac_display_info
*));
98 extern void do_keystroke
P_ ((EventKind
, unsigned char, UInt32
, UInt32
,
99 unsigned long, struct input_event
*));
100 extern UInt32 mac_mapped_modifiers
P_ ((UInt32
, UInt32
));
101 #if TARGET_API_MAC_CARBON
102 extern int mac_to_emacs_modifiers
P_ ((UInt32
, UInt32
));
104 extern int mac_to_emacs_modifiers
P_ ((EventModifiers
, EventModifiers
));
107 #if TARGET_API_MAC_CARBON
108 /* Points to the variable `inev' in the function XTread_socket. It is
109 used for passing an input event to the function back from
110 Carbon/Apple event handlers. */
111 static struct input_event
*read_socket_inev
= NULL
;
113 extern const unsigned char keycode_to_xkeysym_table
[];
114 extern EMACS_INT extra_keyboard_modifiers
;
116 extern Lisp_Object Qhi_command
;
118 static TSMDocumentID tsm_document_id
;
119 extern Lisp_Object Qtext_input
;
120 extern Lisp_Object Qupdate_active_input_area
, Qunicode_for_key_event
;
121 extern Lisp_Object Vmac_ts_active_input_overlay
, Vmac_ts_active_input_buf
;
122 extern Lisp_Object Qbefore_string
;
125 static int mac_event_to_emacs_modifiers
P_ ((EventRef
));
126 static OSStatus install_menu_target_item_handler
P_ ((void));
128 static OSStatus install_service_handler
P_ ((void));
131 extern OSStatus mac_store_event_ref_as_apple_event
P_ ((AEEventClass
, AEEventID
,
135 const EventParamName
*,
136 const EventParamType
*));
137 extern int fast_find_position
P_ ((struct window
*, int, int *, int *,
138 int *, int *, Lisp_Object
));
139 extern struct glyph
*x_y_to_hpos_vpos
P_ ((struct window
*, int, int,
140 int *, int *, int *, int *, int *));
141 extern void mac_ax_selected_text_range
P_ ((struct frame
*, CFRange
*));
142 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
143 extern unsigned int mac_ax_number_of_characters
P_ ((struct frame
*));
147 extern OSStatus mac_restore_keyboard_input_source
P_ ((void));
148 extern void mac_save_keyboard_input_source
P_ ((void));
155 err
= ActivateTSMDocument (tsm_document_id
);
157 err
= mac_restore_keyboard_input_source ();
167 mac_save_keyboard_input_source ();
168 err
= DeactivateTSMDocument (tsm_document_id
);
177 static InterfaceTypeList types
= {kUnicodeDocument
};
179 static InterfaceTypeList types
= {kTextService
};
182 NewTSMDocument (sizeof (types
) / sizeof (types
[0]), types
,
183 &tsm_document_id
, 0);
185 #endif /* USE_MAC_TSM */
187 static pascal OSStatus
188 mac_handle_keyboard_event (next_handler
, event
, data
)
189 EventHandlerCallRef next_handler
;
193 OSStatus err
, result
= eventNotHandledErr
;
194 UInt32 event_kind
, key_code
, modifiers
;
195 unsigned char char_code
;
197 event_kind
= GetEventKind (event
);
200 case kEventRawKeyDown
:
201 case kEventRawKeyRepeat
:
203 /* When using Carbon Events, we need to pass raw keyboard events
204 to the TSM ourselves. If TSM handles it, it will pass back
205 noErr, otherwise it will pass back "eventNotHandledErr" and
206 we can process it normally. */
207 result
= CallNextEventHandler (next_handler
, event
);
208 if (result
!= eventNotHandledErr
)
211 if (read_socket_inev
== NULL
)
215 if (read_socket_inev
->kind
!= NO_EVENT
)
222 if (event_kind
== kEventRawKeyUp
)
225 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
227 sizeof (char), NULL
, &char_code
);
231 err
= GetEventParameter (event
, kEventParamKeyCode
,
233 sizeof (UInt32
), NULL
, &key_code
);
237 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
239 sizeof (UInt32
), NULL
, &modifiers
);
243 do_keystroke ((event_kind
== kEventRawKeyDown
? keyDown
: autoKey
),
244 char_code
, key_code
, modifiers
,
246 (GetEventTime (event
) / kEventDurationMillisecond
)),
258 static pascal OSStatus
259 mac_handle_command_event (next_handler
, event
, data
)
260 EventHandlerCallRef next_handler
;
264 OSStatus err
, result
= eventNotHandledErr
;
266 static const EventParamName names
[] =
267 {kEventParamDirectObject
, kEventParamKeyModifiers
};
268 static const EventParamType types
[] =
269 {typeHICommand
, typeUInt32
};
270 int num_params
= sizeof (names
) / sizeof (names
[0]);
272 err
= GetEventParameter (event
, kEventParamDirectObject
, typeHICommand
,
273 NULL
, sizeof (HICommand
), NULL
, &command
);
275 return eventNotHandledErr
;
277 switch (GetEventKind (event
))
279 case kEventCommandProcess
:
280 result
= CallNextEventHandler (next_handler
, event
);
281 if (result
!= eventNotHandledErr
)
284 err
= GetEventParameter (event
, kEventParamDirectObject
,
286 sizeof (HICommand
), NULL
, &command
);
288 if (err
!= noErr
|| command
.commandID
== 0)
291 /* A HI command event is mapped to an Apple event whose event
292 class symbol is `hi-command' and event ID is its command
294 err
= mac_store_event_ref_as_apple_event (0, command
.commandID
,
309 static pascal OSStatus
310 mac_handle_mouse_event (next_handler
, event
, data
)
311 EventHandlerCallRef next_handler
;
315 OSStatus err
, result
= eventNotHandledErr
;
317 switch (GetEventKind (event
))
319 case kEventMouseWheelMoved
:
323 EventMouseWheelAxis axis
;
327 result
= CallNextEventHandler (next_handler
, event
);
328 if (result
!= eventNotHandledErr
|| read_socket_inev
== NULL
)
331 f
= mac_focus_frame (&one_mac_display_info
);
333 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
,
334 NULL
, sizeof (WindowRef
), NULL
, &wp
);
336 || wp
!= FRAME_MAC_WINDOW (f
))
339 err
= GetEventParameter (event
, kEventParamMouseWheelAxis
,
340 typeMouseWheelAxis
, NULL
,
341 sizeof (EventMouseWheelAxis
), NULL
, &axis
);
342 if (err
!= noErr
|| axis
!= kEventMouseWheelAxisY
)
345 err
= GetEventParameter (event
, kEventParamMouseLocation
,
346 typeQDPoint
, NULL
, sizeof (Point
),
351 point
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
352 point
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
353 if (point
.h
< 0 || point
.v
< 0
354 || EQ (window_from_coordinates (f
, point
.h
, point
.v
, 0, 0, 0, 1),
358 err
= GetEventParameter (event
, kEventParamMouseWheelDelta
,
359 typeSInt32
, NULL
, sizeof (SInt32
),
364 read_socket_inev
->kind
= WHEEL_EVENT
;
365 read_socket_inev
->code
= 0;
366 read_socket_inev
->modifiers
=
367 (mac_event_to_emacs_modifiers (event
)
368 | ((delta
< 0) ? down_modifier
: up_modifier
));
369 XSETINT (read_socket_inev
->x
, point
.h
);
370 XSETINT (read_socket_inev
->y
, point
.v
);
371 XSETFRAME (read_socket_inev
->frame_or_window
, f
);
385 extern void mac_get_selected_range
P_ ((struct window
*, CFRange
*));
386 extern int mac_store_buffer_text_to_unicode_chars
P_ ((struct buffer
*,
387 int, int, UniChar
*));
389 static pascal OSStatus
390 mac_handle_text_input_event (next_handler
, event
, data
)
391 EventHandlerCallRef next_handler
;
395 OSStatus err
, result
;
396 Lisp_Object id_key
= Qnil
;
398 const EventParamName
*names
;
399 const EventParamType
*types
;
400 static UInt32 seqno_uaia
= 0;
401 static const EventParamName names_uaia
[] =
402 {kEventParamTextInputSendComponentInstance
,
403 kEventParamTextInputSendRefCon
,
404 kEventParamTextInputSendSLRec
,
405 kEventParamTextInputSendFixLen
,
406 kEventParamTextInputSendText
,
407 kEventParamTextInputSendUpdateRng
,
408 kEventParamTextInputSendHiliteRng
,
409 kEventParamTextInputSendClauseRng
,
410 kEventParamTextInputSendPinRng
,
411 kEventParamTextInputSendTextServiceEncoding
,
412 kEventParamTextInputSendTextServiceMacEncoding
,
413 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER
};
414 static const EventParamType types_uaia
[] =
415 {typeComponentInstance
,
431 static const EventParamName names_ufke
[] =
432 {kEventParamTextInputSendComponentInstance
,
433 kEventParamTextInputSendRefCon
,
434 kEventParamTextInputSendSLRec
,
435 kEventParamTextInputSendText
};
436 static const EventParamType types_ufke
[] =
437 {typeComponentInstance
,
442 result
= CallNextEventHandler (next_handler
, event
);
443 if (result
!= eventNotHandledErr
)
446 switch (GetEventKind (event
))
448 case kEventTextInputUpdateActiveInputArea
:
449 id_key
= Qupdate_active_input_area
;
450 num_params
= sizeof (names_uaia
) / sizeof (names_uaia
[0]);
453 SetEventParameter (event
, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER
,
454 typeUInt32
, sizeof (UInt32
), &seqno_uaia
);
459 case kEventTextInputUnicodeForKeyEvent
:
462 UInt32 actual_size
, modifiers
, key_code
;
464 err
= GetEventParameter (event
, kEventParamTextInputSendKeyboardEvent
,
465 typeEventRef
, NULL
, sizeof (EventRef
), NULL
,
468 err
= GetEventParameter (kbd_event
, kEventParamKeyModifiers
,
470 sizeof (UInt32
), NULL
, &modifiers
);
472 err
= GetEventParameter (kbd_event
, kEventParamKeyCode
,
473 typeUInt32
, NULL
, sizeof (UInt32
),
475 if (err
== noErr
&& mac_mapped_modifiers (modifiers
, key_code
))
476 /* There're mapped modifier keys. Process it in
480 err
= GetEventParameter (kbd_event
, kEventParamKeyUnicodes
,
481 typeUnicodeText
, NULL
, 0, &actual_size
,
483 if (err
== noErr
&& actual_size
== sizeof (UniChar
))
487 err
= GetEventParameter (kbd_event
, kEventParamKeyUnicodes
,
488 typeUnicodeText
, NULL
,
489 sizeof (UniChar
), NULL
, &code
);
490 if (err
== noErr
&& code
< 0x80)
492 /* ASCII character. Process it in do_keystroke. */
493 if (read_socket_inev
&& code
>= 0x20 && code
<= 0x7e
494 && !(key_code
<= 0x7f
495 && keycode_to_xkeysym_table
[key_code
]))
497 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
499 read_socket_inev
->kind
= ASCII_KEYSTROKE_EVENT
;
500 read_socket_inev
->code
= code
;
501 read_socket_inev
->modifiers
=
502 mac_to_emacs_modifiers (modifiers
, 0);
503 read_socket_inev
->modifiers
|=
504 (extra_keyboard_modifiers
505 & (meta_modifier
| alt_modifier
506 | hyper_modifier
| super_modifier
));
507 XSETFRAME (read_socket_inev
->frame_or_window
, f
);
514 /* Non-ASCII keystrokes without mapped modifiers are
515 processed at the Lisp level. */
516 id_key
= Qunicode_for_key_event
;
517 num_params
= sizeof (names_ufke
) / sizeof (names_ufke
[0]);
525 case kEventTextInputOffsetToPos
:
532 err
= GetEventParameter (event
, kEventParamTextInputSendTextOffset
,
533 typeLongInteger
, NULL
, sizeof (long), NULL
,
538 if (STRINGP (Vmac_ts_active_input_buf
)
539 && SBYTES (Vmac_ts_active_input_buf
) != 0)
541 if (!OVERLAYP (Vmac_ts_active_input_overlay
))
544 /* Strictly speaking, this is not always correct because
545 previous events may change some states about display. */
546 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay
, Qbefore_string
)))
548 /* Active input area is displayed around the current point. */
549 f
= SELECTED_FRAME ();
550 w
= XWINDOW (f
->selected_window
);
552 else if (WINDOWP (echo_area_window
))
554 /* Active input area is displayed in the echo area. */
555 w
= XWINDOW (echo_area_window
);
556 f
= WINDOW_XFRAME (w
);
561 p
.h
= (WINDOW_TO_FRAME_PIXEL_X (w
, w
->cursor
.x
)
562 + WINDOW_LEFT_FRINGE_WIDTH (w
)
563 + f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
564 p
.v
= (WINDOW_TO_FRAME_PIXEL_Y (w
, w
->cursor
.y
)
565 + FONT_BASE (FRAME_FONT (f
))
566 + f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
575 int hpos
, vpos
, x
, y
;
576 struct glyph_row
*row
;
580 f
= mac_focus_frame (&one_mac_display_info
);
581 w
= XWINDOW (f
->selected_window
);
582 mac_get_selected_range (w
, &sel_range
);
583 charpos
= (BUF_BEGV (XBUFFER (w
->buffer
)) + sel_range
.location
584 + byte_offset
/ (long) sizeof (UniChar
));
586 if (!fast_find_position (w
, charpos
, &hpos
, &vpos
, &x
, &y
, Qnil
))
588 result
= errOffsetInvalid
;
592 row
= MATRIX_ROW (w
->current_matrix
, vpos
);
593 glyph
= row
->glyphs
[TEXT_AREA
] + hpos
;
594 if (glyph
->type
!= CHAR_GLYPH
|| glyph
->glyph_not_available_p
)
597 p
.h
= (WINDOW_TEXT_TO_FRAME_PIXEL_X (w
, x
)
598 + f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
599 p
.v
= (WINDOW_TO_FRAME_PIXEL_Y (w
, y
)
600 + row
->visible_height
601 + f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
603 face
= FACE_FROM_ID (f
, glyph
->face_id
);
604 if (face
&& face
->font
)
606 XFontStruct
*font
= face
->font
;
607 Fixed point_size
= Long2Fix (font
->mac_fontsize
);
608 short height
= row
->visible_height
;
609 short ascent
= row
->ascent
;
611 SetEventParameter (event
,
612 kEventParamTextInputReplyPointSize
,
613 typeFixed
, sizeof (Fixed
), &point_size
);
614 SetEventParameter (event
,
615 kEventParamTextInputReplyLineHeight
,
616 typeShortInteger
, sizeof (short), &height
);
617 SetEventParameter (event
,
618 kEventParamTextInputReplyLineAscent
,
619 typeShortInteger
, sizeof (short), &ascent
);
620 if (font
->mac_fontnum
!= -1)
626 err1
= FMGetFontFromFontFamilyInstance (font
->mac_fontnum
,
630 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
631 typeUInt32
, sizeof (UInt32
), &fm_font
);
634 long qd_font
= font
->mac_fontnum
;
636 SetEventParameter (event
, kEventParamTextInputReplyFont
,
637 typeLongInteger
, sizeof (long),
641 else if (font
->mac_style
)
646 err1
= ATSUGetAttribute (font
->mac_style
, kATSUFontTag
,
647 sizeof (ATSUFontID
), &font_id
,
650 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
651 typeUInt32
, sizeof (UInt32
), &font_id
);
659 err
= SetEventParameter (event
, kEventParamTextInputReplyPoint
,
660 typeQDPoint
, sizeof (Point
), &p
);
667 case kEventTextInputPosToOffset
:
670 Boolean leading_edge_p
= true;
674 enum window_part part
;
675 long region_class
= kTSMOutsideOfBody
, byte_offset
= 0;
677 err
= GetEventParameter (event
, kEventParamTextInputSendCurrentPoint
,
678 typeQDPoint
, NULL
, sizeof (Point
), NULL
,
683 GetEventParameter (event
, kEventParamTextInputReplyLeadingEdge
,
684 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
687 f
= mac_focus_frame (&one_mac_display_info
);
688 x
= point
.h
- (f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
689 y
= point
.v
- (f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
690 window
= window_from_coordinates (f
, x
, y
, &part
, 0, 0, 1);
691 if (WINDOWP (window
) && EQ (window
, f
->selected_window
))
696 /* Convert to window-relative pixel coordinates. */
697 w
= XWINDOW (window
);
698 frame_to_window_pixel_xy (w
, &x
, &y
);
700 /* Are we in a window whose display is up to date?
701 And verify the buffer's text has not changed. */
702 b
= XBUFFER (w
->buffer
);
704 && EQ (w
->window_end_valid
, w
->buffer
)
705 && XINT (w
->last_modified
) == BUF_MODIFF (b
)
706 && XINT (w
->last_overlay_modified
) == BUF_OVERLAY_MODIFF (b
))
708 int hpos
, vpos
, area
;
711 /* Find the glyph under X/Y. */
712 glyph
= x_y_to_hpos_vpos (w
, x
, y
, &hpos
, &vpos
, 0, 0, &area
);
714 if (glyph
!= NULL
&& area
== TEXT_AREA
)
716 byte_offset
= ((glyph
->charpos
- BUF_BEGV (b
))
718 region_class
= kTSMInsideOfBody
;
723 err
= SetEventParameter (event
, kEventParamTextInputReplyRegionClass
,
724 typeLongInteger
, sizeof (long),
727 err
= SetEventParameter (event
, kEventParamTextInputReplyTextOffset
,
728 typeLongInteger
, sizeof (long),
735 case kEventTextInputGetSelectedText
:
737 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
738 struct window
*w
= XWINDOW (f
->selected_window
);
739 struct buffer
*b
= XBUFFER (w
->buffer
);
742 UniChar
*characters
, c
;
744 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
745 /* Don't try to get buffer contents as the gap might be
749 mac_get_selected_range (w
, &sel_range
);
750 if (sel_range
.length
== 0)
752 Boolean leading_edge_p
;
754 err
= GetEventParameter (event
,
755 kEventParamTextInputReplyLeadingEdge
,
756 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
761 start
= BUF_BEGV (b
) + sel_range
.location
;
767 if (start
< BUF_BEGV (b
) || end
> BUF_ZV (b
))
772 start
= BUF_BEGV (b
) + sel_range
.location
;
773 end
= start
+ sel_range
.length
;
774 characters
= xmalloc (sel_range
.length
* sizeof (UniChar
));
777 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
, characters
))
778 err
= SetEventParameter (event
, kEventParamTextInputReplyText
,
780 sel_range
.length
* sizeof (UniChar
),
782 if (characters
!= &c
)
796 err
= mac_store_event_ref_as_apple_event (0, 0, Qtext_input
, id_key
,
802 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
803 static pascal OSStatus
804 mac_handle_document_access_event (next_handler
, event
, data
)
805 EventHandlerCallRef next_handler
;
809 OSStatus err
, result
;
810 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
812 result
= CallNextEventHandler (next_handler
, event
);
813 if (result
!= eventNotHandledErr
)
816 switch (GetEventKind (event
))
818 case kEventTSMDocumentAccessGetLength
:
820 CFIndex count
= mac_ax_number_of_characters (f
);
822 err
= SetEventParameter (event
, kEventParamTSMDocAccessCharacterCount
,
823 typeCFIndex
, sizeof (CFIndex
), &count
);
829 case kEventTSMDocumentAccessGetSelectedRange
:
833 mac_ax_selected_text_range (f
, &sel_range
);
834 err
= SetEventParameter (event
,
835 kEventParamTSMDocAccessReplyCharacterRange
,
836 typeCFRange
, sizeof (CFRange
), &sel_range
);
842 case kEventTSMDocumentAccessGetCharacters
:
844 struct buffer
*b
= XBUFFER (XWINDOW (f
->selected_window
)->buffer
);
849 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
850 /* Don't try to get buffer contents as the gap might be
854 err
= GetEventParameter (event
,
855 kEventParamTSMDocAccessSendCharacterRange
,
856 typeCFRange
, NULL
, sizeof (CFRange
), NULL
,
859 err
= GetEventParameter (event
,
860 kEventParamTSMDocAccessSendCharactersPtr
,
861 typePtr
, NULL
, sizeof (Ptr
), NULL
,
866 start
= BUF_BEGV (b
) + range
.location
;
867 end
= start
+ range
.length
;
868 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
,
869 (UniChar
*) characters
))
884 install_application_handler ()
886 OSStatus err
= noErr
;
890 static const EventTypeSpec specs
[] =
891 {{kEventClassKeyboard
, kEventRawKeyDown
},
892 {kEventClassKeyboard
, kEventRawKeyRepeat
},
893 {kEventClassKeyboard
, kEventRawKeyUp
}};
895 err
= InstallApplicationEventHandler (NewEventHandlerUPP
896 (mac_handle_keyboard_event
),
897 GetEventTypeCount (specs
),
903 static const EventTypeSpec specs
[] =
904 {{kEventClassCommand
, kEventCommandProcess
}};
906 err
= InstallApplicationEventHandler (NewEventHandlerUPP
907 (mac_handle_command_event
),
908 GetEventTypeCount (specs
),
914 static const EventTypeSpec specs
[] =
915 {{kEventClassMouse
, kEventMouseWheelMoved
}};
917 err
= InstallApplicationEventHandler (NewEventHandlerUPP
918 (mac_handle_mouse_event
),
919 GetEventTypeCount (specs
),
926 static const EventTypeSpec specs
[] =
927 {{kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
},
928 {kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
},
929 {kEventClassTextInput
, kEventTextInputOffsetToPos
},
931 {kEventClassTextInput
, kEventTextInputPosToOffset
},
932 {kEventClassTextInput
, kEventTextInputGetSelectedText
}
936 err
= InstallApplicationEventHandler (NewEventHandlerUPP
937 (mac_handle_text_input_event
),
938 GetEventTypeCount (specs
),
942 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
945 static const EventTypeSpec specs
[] =
946 {{kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetLength
},
947 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetSelectedRange
},
948 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetCharacters
}};
950 err
= InstallApplicationEventHandler (mac_handle_document_access_event
,
951 GetEventTypeCount (specs
),
958 err
= install_menu_target_item_handler ();
962 err
= install_service_handler ();
967 #endif /* TARGET_API_MAC_CARBON */
970 /************************************************************************
972 ************************************************************************/
974 #define DEFAULT_NUM_COLS 80
976 #define MIN_DOC_SIZE 64
977 #define MAX_DOC_SIZE 32767
980 static OSErr install_drag_handler
P_ ((WindowRef
));
981 static void remove_drag_handler
P_ ((WindowRef
));
984 static void mac_prepare_for_quickdraw
P_ ((struct frame
*));
987 extern void mac_handle_visibility_change
P_ ((struct frame
*));
988 extern void mac_handle_origin_change
P_ ((struct frame
*));
989 extern void mac_handle_size_change
P_ ((struct frame
*, int, int));
991 #if TARGET_API_MAC_CARBON
993 extern Lisp_Object Qwindow
;
994 extern Lisp_Object Qtoolbar_switch_mode
;
999 do_window_update (WindowRef win
)
1001 struct frame
*f
= mac_window_to_frame (win
);
1005 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1007 if (win
!= tip_window
)
1009 if (f
->async_visible
== 0)
1011 /* Update events may occur when a frame gets iconified. */
1013 f
->async_visible
= 1;
1014 f
->async_iconified
= 0;
1015 SET_FRAME_GARBAGED (f
);
1021 #if TARGET_API_MAC_CARBON
1022 RgnHandle region
= NewRgn ();
1024 GetPortVisibleRegion (GetWindowPort (win
), region
);
1025 GetRegionBounds (region
, &r
);
1026 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1028 mac_prepare_for_quickdraw (f
);
1030 UpdateControls (win
, region
);
1031 DisposeRgn (region
);
1033 r
= (*win
->visRgn
)->rgnBBox
;
1034 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1035 UpdateControls (win
, win
->visRgn
);
1044 is_emacs_window (WindowRef win
)
1046 Lisp_Object tail
, frame
;
1051 FOR_EACH_FRAME (tail
, frame
)
1052 if (FRAME_MAC_P (XFRAME (frame
)))
1053 if (FRAME_MAC_WINDOW (XFRAME (frame
)) == win
)
1059 /* Handle drags in size box. Based on code contributed by Ben
1060 Mesander and IM - Window Manager A. */
1063 do_grow_window (w
, e
)
1065 const EventRecord
*e
;
1068 int rows
, columns
, width
, height
;
1069 struct frame
*f
= mac_window_to_frame (w
);
1070 XSizeHints
*size_hints
= FRAME_SIZE_HINTS (f
);
1071 int min_width
= MIN_DOC_SIZE
, min_height
= MIN_DOC_SIZE
;
1072 #if TARGET_API_MAC_CARBON
1078 if (size_hints
->flags
& PMinSize
)
1080 min_width
= size_hints
->min_width
;
1081 min_height
= size_hints
->min_height
;
1083 SetRect (&limit_rect
, min_width
, min_height
, MAX_DOC_SIZE
, MAX_DOC_SIZE
);
1085 #if TARGET_API_MAC_CARBON
1086 if (!ResizeWindow (w
, e
->where
, &limit_rect
, &new_rect
))
1088 height
= new_rect
.bottom
- new_rect
.top
;
1089 width
= new_rect
.right
- new_rect
.left
;
1091 grow_size
= GrowWindow (w
, e
->where
, &limit_rect
);
1092 /* see if it really changed size */
1095 height
= HiWord (grow_size
);
1096 width
= LoWord (grow_size
);
1099 if (width
!= FRAME_PIXEL_WIDTH (f
)
1100 || height
!= FRAME_PIXEL_HEIGHT (f
))
1102 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1103 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1105 x_set_window_size (f
, 0, columns
, rows
);
1109 #if TARGET_API_MAC_CARBON
1111 mac_get_ideal_size (f
)
1114 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1115 WindowRef w
= FRAME_MAC_WINDOW (f
);
1118 int height
, width
, columns
, rows
;
1120 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1121 ideal_size
.v
= dpyinfo
->height
;
1122 IsWindowInStandardState (w
, &ideal_size
, &standard_rect
);
1123 /* Adjust the standard size according to character boundaries. */
1124 width
= standard_rect
.right
- standard_rect
.left
;
1125 height
= standard_rect
.bottom
- standard_rect
.top
;
1126 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1127 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1128 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, columns
);
1129 ideal_size
.v
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1134 static pascal OSStatus
1135 mac_handle_window_event (next_handler
, event
, data
)
1136 EventHandlerCallRef next_handler
;
1141 OSStatus err
, result
= eventNotHandledErr
;
1144 XSizeHints
*size_hints
;
1146 err
= GetEventParameter (event
, kEventParamDirectObject
, typeWindowRef
,
1147 NULL
, sizeof (WindowRef
), NULL
, &wp
);
1149 return eventNotHandledErr
;
1151 f
= mac_window_to_frame (wp
);
1152 switch (GetEventKind (event
))
1154 /* -- window refresh events -- */
1156 case kEventWindowUpdate
:
1157 result
= CallNextEventHandler (next_handler
, event
);
1158 if (result
!= eventNotHandledErr
)
1161 do_window_update (wp
);
1165 /* -- window state change events -- */
1167 case kEventWindowShowing
:
1168 size_hints
= FRAME_SIZE_HINTS (f
);
1169 if (!(size_hints
->flags
& (USPosition
| PPosition
)))
1171 struct frame
*sf
= SELECTED_FRAME ();
1173 if (!(FRAME_MAC_P (sf
) && sf
->async_visible
))
1174 RepositionWindow (wp
, NULL
, kWindowCenterOnMainScreen
);
1177 RepositionWindow (wp
, FRAME_MAC_WINDOW (sf
),
1178 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1179 kWindowCascadeStartAtParentWindowScreen
1181 kWindowCascadeOnParentWindowScreen
1185 /* This is a workaround. RepositionWindow fails to put
1186 a window at the cascading position when its parent
1187 window has a Carbon HIToolbar. */
1188 if ((f
->left_pos
== sf
->left_pos
1189 && f
->top_pos
== sf
->top_pos
)
1190 || (f
->left_pos
== sf
->left_pos
+ 10 * 2
1191 && f
->top_pos
== sf
->top_pos
+ 32 * 2))
1192 MoveWindowStructure (wp
, sf
->left_pos
+ 10, sf
->top_pos
+ 32);
1199 case kEventWindowHiding
:
1200 /* Before unmapping the window, update the WM_SIZE_HINTS
1201 property to claim that the current position of the window is
1202 user-specified, rather than program-specified, so that when
1203 the window is mapped again, it will be placed at the same
1204 location, without forcing the user to position it by hand
1205 again (they have already done that once for this window.) */
1206 x_wm_set_size_hint (f
, (long) 0, 1);
1210 case kEventWindowShown
:
1211 case kEventWindowHidden
:
1212 case kEventWindowCollapsed
:
1213 case kEventWindowExpanded
:
1214 mac_handle_visibility_change (f
);
1218 case kEventWindowBoundsChanging
:
1219 result
= CallNextEventHandler (next_handler
, event
);
1220 if (result
!= eventNotHandledErr
)
1223 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1224 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1228 size_hints
= FRAME_SIZE_HINTS (f
);
1229 if ((attributes
& kWindowBoundsChangeUserResize
)
1230 && ((size_hints
->flags
& (PResizeInc
| PBaseSize
| PMinSize
))
1231 == (PResizeInc
| PBaseSize
| PMinSize
)))
1236 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1237 typeQDRectangle
, NULL
, sizeof (Rect
),
1242 width
= bounds
.right
- bounds
.left
;
1243 height
= bounds
.bottom
- bounds
.top
;
1245 if (width
< size_hints
->min_width
)
1246 width
= size_hints
->min_width
;
1248 width
= size_hints
->base_width
1249 + (int) ((width
- size_hints
->base_width
)
1250 / (float) size_hints
->width_inc
+ .5)
1251 * size_hints
->width_inc
;
1253 if (height
< size_hints
->min_height
)
1254 height
= size_hints
->min_height
;
1256 height
= size_hints
->base_height
1257 + (int) ((height
- size_hints
->base_height
)
1258 / (float) size_hints
->height_inc
+ .5)
1259 * size_hints
->height_inc
;
1261 bounds
.right
= bounds
.left
+ width
;
1262 bounds
.bottom
= bounds
.top
+ height
;
1263 SetEventParameter (event
, kEventParamCurrentBounds
,
1264 typeQDRectangle
, sizeof (Rect
), &bounds
);
1269 case kEventWindowBoundsChanged
:
1270 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1271 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1275 if (attributes
& kWindowBoundsChangeSizeChanged
)
1279 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1280 typeQDRectangle
, NULL
, sizeof (Rect
),
1286 width
= bounds
.right
- bounds
.left
;
1287 height
= bounds
.bottom
- bounds
.top
;
1288 mac_handle_size_change (f
, width
, height
);
1289 mac_wakeup_from_rne ();
1293 if (attributes
& kWindowBoundsChangeOriginChanged
)
1294 mac_handle_origin_change (f
);
1299 /* -- window action events -- */
1301 case kEventWindowClose
:
1303 struct input_event buf
;
1306 buf
.kind
= DELETE_WINDOW_EVENT
;
1307 XSETFRAME (buf
.frame_or_window
, f
);
1309 kbd_buffer_store_event (&buf
);
1314 case kEventWindowGetIdealSize
:
1315 result
= CallNextEventHandler (next_handler
, event
);
1316 if (result
!= eventNotHandledErr
)
1320 Point ideal_size
= mac_get_ideal_size (f
);
1322 err
= SetEventParameter (event
, kEventParamDimensions
,
1323 typeQDPoint
, sizeof (Point
), &ideal_size
);
1330 case kEventWindowToolbarSwitchMode
:
1332 static const EventParamName names
[] = {kEventParamDirectObject
,
1333 kEventParamWindowMouseLocation
,
1334 kEventParamKeyModifiers
,
1335 kEventParamMouseButton
,
1336 kEventParamClickCount
,
1337 kEventParamMouseChord
};
1338 static const EventParamType types
[] = {typeWindowRef
,
1344 int num_params
= sizeof (names
) / sizeof (names
[0]);
1346 err
= mac_store_event_ref_as_apple_event (0, 0,
1348 Qtoolbar_switch_mode
,
1358 /* -- window focus events -- */
1360 case kEventWindowFocusAcquired
:
1361 err
= mac_tsm_resume ();
1366 case kEventWindowFocusRelinquish
:
1367 err
= mac_tsm_suspend ();
1381 /* Handle clicks in zoom box. Calculation of "standard state" based
1382 on code in IM - Window Manager A and code contributed by Ben
1383 Mesander. The standard state of an Emacs window is 80-characters
1384 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1387 do_zoom_window (WindowRef w
, int zoom_in_or_out
)
1389 Rect zoom_rect
, port_rect
;
1391 struct frame
*f
= mac_window_to_frame (w
);
1392 #if TARGET_API_MAC_CARBON
1393 Point ideal_size
= mac_get_ideal_size (f
);
1395 GetWindowBounds (w
, kWindowContentRgn
, &port_rect
);
1396 if (IsWindowInStandardState (w
, &ideal_size
, &zoom_rect
)
1397 && port_rect
.left
== zoom_rect
.left
1398 && port_rect
.top
== zoom_rect
.top
)
1399 zoom_in_or_out
= inZoomIn
;
1401 zoom_in_or_out
= inZoomOut
;
1404 mac_clear_area (f
, 0, 0, port_rect
.right
- port_rect
.left
,
1405 port_rect
.bottom
- port_rect
.top
);
1407 ZoomWindowIdeal (w
, zoom_in_or_out
, &ideal_size
);
1408 #else /* not TARGET_API_MAC_CARBON */
1411 int w_title_height
, rows
;
1412 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1414 GetPort (&save_port
);
1416 SetPortWindowPort (w
);
1418 /* Clear window to avoid flicker. */
1419 EraseRect (&(w
->portRect
));
1420 if (zoom_in_or_out
== inZoomOut
)
1422 SetPt (&top_left
, w
->portRect
.left
, w
->portRect
.top
);
1423 LocalToGlobal (&top_left
);
1425 /* calculate height of window's title bar */
1426 w_title_height
= top_left
.v
- 1
1427 - (**((WindowPeek
) w
)->strucRgn
).rgnBBox
.top
+ GetMBarHeight ();
1429 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1430 zoom_rect
= qd
.screenBits
.bounds
;
1431 zoom_rect
.top
+= w_title_height
;
1432 InsetRect (&zoom_rect
, 8, 4); /* not too tight */
1434 zoom_rect
.right
= zoom_rect
.left
1435 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1437 /* Adjust the standard size according to character boundaries. */
1438 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, zoom_rect
.bottom
- zoom_rect
.top
);
1440 zoom_rect
.top
+ FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1442 (**((WStateDataHandle
) ((WindowPeek
) w
)->dataHandle
)).stdState
1446 ZoomWindow (w
, zoom_in_or_out
, f
== mac_focus_frame (dpyinfo
));
1448 SetPort (save_port
);
1449 #endif /* not TARGET_API_MAC_CARBON */
1451 #if !TARGET_API_MAC_CARBON
1452 /* retrieve window size and update application values */
1453 port_rect
= w
->portRect
;
1454 height
= port_rect
.bottom
- port_rect
.top
;
1455 width
= port_rect
.right
- port_rect
.left
;
1457 mac_handle_size_change (f
, width
, height
);
1458 mac_handle_origin_change (f
);
1463 install_window_handler (window
)
1466 OSStatus err
= noErr
;
1468 #if TARGET_API_MAC_CARBON
1471 static const EventTypeSpec specs
[] =
1473 /* -- window refresh events -- */
1474 {kEventClassWindow
, kEventWindowUpdate
},
1475 /* -- window state change events -- */
1476 {kEventClassWindow
, kEventWindowShowing
},
1477 {kEventClassWindow
, kEventWindowHiding
},
1478 {kEventClassWindow
, kEventWindowShown
},
1479 {kEventClassWindow
, kEventWindowHidden
},
1480 {kEventClassWindow
, kEventWindowCollapsed
},
1481 {kEventClassWindow
, kEventWindowExpanded
},
1482 {kEventClassWindow
, kEventWindowBoundsChanging
},
1483 {kEventClassWindow
, kEventWindowBoundsChanged
},
1484 /* -- window action events -- */
1485 {kEventClassWindow
, kEventWindowClose
},
1486 {kEventClassWindow
, kEventWindowGetIdealSize
},
1488 {kEventClassWindow
, kEventWindowToolbarSwitchMode
},
1491 /* -- window focus events -- */
1492 {kEventClassWindow
, kEventWindowFocusAcquired
},
1493 {kEventClassWindow
, kEventWindowFocusRelinquish
},
1496 static EventHandlerUPP handle_window_eventUPP
= NULL
;
1498 if (handle_window_eventUPP
== NULL
)
1499 handle_window_eventUPP
= NewEventHandlerUPP (mac_handle_window_event
);
1501 err
= InstallWindowEventHandler (window
, handle_window_eventUPP
,
1502 GetEventTypeCount (specs
),
1508 err
= install_drag_handler (window
);
1514 remove_window_handler (window
)
1517 remove_drag_handler (window
);
1521 mac_get_window_bounds (f
, inner
, outer
)
1523 Rect
*inner
, *outer
;
1525 #if TARGET_API_MAC_CARBON
1526 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, inner
);
1527 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, outer
);
1528 #else /* not TARGET_API_MAC_CARBON */
1529 RgnHandle region
= NewRgn ();
1531 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, region
);
1532 *inner
= (*region
)->rgnBBox
;
1533 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, region
);
1534 *outer
= (*region
)->rgnBBox
;
1535 DisposeRgn (region
);
1536 #endif /* not TARGET_API_MAC_CARBON */
1540 mac_get_frame_bounds (f
, r
)
1544 #if TARGET_API_MAC_CARBON
1545 return GetWindowPortBounds (FRAME_MAC_WINDOW (f
), r
);
1547 *r
= FRAME_MAC_WINDOW (f
)->portRect
;
1554 mac_get_frame_mouse (f
, point
)
1558 #if TARGET_API_MAC_CARBON
1559 GetGlobalMouse (point
);
1560 point
->h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1561 point
->v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1563 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1569 mac_convert_frame_point_to_global (f
, x
, y
)
1573 *x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1574 *y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1577 #if TARGET_API_MAC_CARBON
1579 mac_update_proxy_icon (f
)
1583 Lisp_Object file_name
=
1584 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
)->filename
;
1585 Window w
= FRAME_MAC_WINDOW (f
);
1586 AliasHandle alias
= NULL
;
1588 err
= GetWindowProxyAlias (w
, &alias
);
1589 if (err
== errWindowDoesNotHaveProxy
&& !STRINGP (file_name
))
1592 if (STRINGP (file_name
))
1596 FSRef fref
, fref_proxy
;
1598 FSSpec fss
, fss_proxy
;
1601 Lisp_Object encoded_file_name
= ENCODE_FILE (file_name
);
1604 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1605 SBYTES (encoded_file_name
), typeFSRef
, &desc
);
1607 SetPortWindowPort (w
);
1608 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1609 SBYTES (encoded_file_name
), typeFSS
, &desc
);
1614 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
1616 err
= AEGetDescData (&desc
, &fss
, sizeof (FSSpec
));
1618 AEDisposeDesc (&desc
);
1624 /* (FS)ResolveAlias never sets `changed' to true if
1625 `alias' is minimal. */
1627 err
= FSResolveAlias (NULL
, alias
, &fref_proxy
, &changed
);
1629 err
= FSCompareFSRefs (&fref
, &fref_proxy
);
1631 err
= ResolveAlias (NULL
, alias
, &fss_proxy
, &changed
);
1633 err
= !(fss
.vRefNum
== fss_proxy
.vRefNum
1634 && fss
.parID
== fss_proxy
.parID
1635 && EqualString (fss
.name
, fss_proxy
.name
,
1639 if (err
!= noErr
|| alias
== NULL
)
1642 DisposeHandle ((Handle
) alias
);
1644 err
= FSNewAliasMinimal (&fref
, &alias
);
1646 err
= NewAliasMinimal (&fss
, &alias
);
1653 err
= SetWindowProxyAlias (w
, alias
);
1657 DisposeHandle ((Handle
) alias
);
1659 if (err
!= noErr
|| !STRINGP (file_name
))
1660 RemoveWindowProxy (w
);
1664 /* Mac replacement for XSetWindowBackground. */
1667 mac_set_frame_window_background (f
, color
)
1669 unsigned long color
;
1671 WindowRef w
= FRAME_MAC_WINDOW (f
);
1672 #if !TARGET_API_MAC_CARBON
1673 AuxWinHandle aw_handle
;
1674 CTabHandle ctab_handle
;
1675 ColorSpecPtr ct_table
;
1680 bg_color
.red
= RED16_FROM_ULONG (color
);
1681 bg_color
.green
= GREEN16_FROM_ULONG (color
);
1682 bg_color
.blue
= BLUE16_FROM_ULONG (color
);
1684 #if TARGET_API_MAC_CARBON
1685 SetWindowContentColor (w
, &bg_color
);
1687 if (GetAuxWin (w
, &aw_handle
))
1689 ctab_handle
= (*aw_handle
)->awCTable
;
1690 HandToHand ((Handle
*) &ctab_handle
);
1691 ct_table
= (*ctab_handle
)->ctTable
;
1692 ct_size
= (*ctab_handle
)->ctSize
;
1693 while (ct_size
> -1)
1695 if (ct_table
->value
== 0)
1697 ct_table
->rgb
= bg_color
;
1698 CTabChanged (ctab_handle
);
1699 SetWinColor (w
, (WCTabHandle
) ctab_handle
);
1707 /* Flush display of frame F, or of all frames if F is null. */
1713 #if TARGET_API_MAC_CARBON
1716 mac_prepare_for_quickdraw (f
);
1719 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f
)), NULL
);
1721 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL
);
1728 mac_flush_display_optional (f
)
1732 mac_prepare_for_quickdraw (f
);
1738 mac_update_begin (f
)
1741 #if TARGET_API_MAC_CARBON
1742 /* During update of a frame, availability of input events is
1743 periodically checked with ReceiveNextEvent if
1744 redisplay-dont-pause is nil. That normally flushes window buffer
1745 changes for every check, and thus screen update looks waving even
1746 if no input is available. So we disable screen updates during
1747 update of a frame. */
1748 DisableScreenUpdates ();
1756 #if TARGET_API_MAC_CARBON
1757 EnableScreenUpdates ();
1762 mac_frame_up_to_date (f
)
1765 /* Nothing to do. */
1769 mac_create_frame_window (f
, tooltip_p
)
1774 #if TARGET_API_MAC_CARBON
1775 WindowClass window_class
;
1776 WindowAttributes attributes
;
1780 Boolean go_away_flag
;
1785 SetRect (&r
, f
->left_pos
, f
->top_pos
,
1786 f
->left_pos
+ FRAME_PIXEL_WIDTH (f
),
1787 f
->top_pos
+ FRAME_PIXEL_HEIGHT (f
));
1788 #if TARGET_API_MAC_CARBON
1789 window_class
= kDocumentWindowClass
;
1790 attributes
= (kWindowStandardDocumentAttributes
1792 | kWindowToolbarButtonAttribute
1796 proc_id
= zoomDocProc
;
1797 behind
= (WindowRef
) -1;
1798 go_away_flag
= true;
1803 SetRect (&r
, 0, 0, 1, 1);
1804 #if TARGET_API_MAC_CARBON
1805 window_class
= kHelpWindowClass
;
1806 attributes
= (kWindowNoUpdatesAttribute
1807 | kWindowNoActivatesAttribute
1808 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1809 | kWindowIgnoreClicksAttribute
1813 proc_id
= plainDBox
;
1815 go_away_flag
= false;
1819 #if TARGET_API_MAC_CARBON
1820 CreateNewWindow (window_class
, attributes
, &r
, &FRAME_MAC_WINDOW (f
));
1821 if (FRAME_MAC_WINDOW (f
))
1823 SetWRefCon (FRAME_MAC_WINDOW (f
), (long) f
->output_data
.mac
);
1825 if (install_window_handler (FRAME_MAC_WINDOW (f
)) != noErr
)
1827 DisposeWindow (FRAME_MAC_WINDOW (f
));
1828 FRAME_MAC_WINDOW (f
) = NULL
;
1831 #else /* !TARGET_API_MAC_CARBON */
1832 FRAME_MAC_WINDOW (f
)
1833 = NewCWindow (NULL
, &r
, "\p", false, proc_id
, behind
, go_away_flag
,
1834 (long) f
->output_data
.mac
);
1835 #endif /* !TARGET_API_MAC_CARBON */
1836 /* so that update events can find this mac_output struct */
1837 f
->output_data
.mac
->mFP
= f
; /* point back to emacs frame */
1841 if (FRAME_MAC_WINDOW (f
))
1843 ControlRef root_control
;
1845 if (CreateRootControl (FRAME_MAC_WINDOW (f
), &root_control
) != noErr
)
1847 DisposeWindow (FRAME_MAC_WINDOW (f
));
1848 FRAME_MAC_WINDOW (f
) = NULL
;
1854 /* Dispose of the Mac window of the frame F. */
1857 mac_dispose_frame_window (f
)
1860 WindowRef window
= FRAME_MAC_WINDOW (f
);
1862 if (window
!= tip_window
)
1863 remove_window_handler (window
);
1866 mac_prepare_for_quickdraw (f
);
1868 DisposeWindow (window
);
1872 /************************************************************************
1874 ************************************************************************/
1877 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1880 mac_begin_cg_clip (f
, gc
)
1884 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1888 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)), &context
);
1889 FRAME_CG_CONTEXT (f
) = context
;
1892 CGContextSaveGState (context
);
1893 CGContextTranslateCTM (context
, 0, FRAME_PIXEL_HEIGHT (f
));
1894 CGContextScaleCTM (context
, 1, -1);
1895 if (gc
&& gc
->n_clip_rects
)
1896 CGContextClipToRects (context
, gc
->clip_rects
, gc
->n_clip_rects
);
1905 CGContextRestoreGState (FRAME_CG_CONTEXT (f
));
1909 mac_prepare_for_quickdraw (f
)
1914 Lisp_Object rest
, frame
;
1915 FOR_EACH_FRAME (rest
, frame
)
1916 if (FRAME_MAC_P (XFRAME (frame
)))
1917 mac_prepare_for_quickdraw (XFRAME (frame
));
1921 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1925 CGContextSynchronize (context
);
1926 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)),
1927 &FRAME_CG_CONTEXT (f
));
1933 static RgnHandle saved_port_clip_region
= NULL
;
1936 mac_begin_clip (f
, gc
)
1940 static RgnHandle new_region
= NULL
;
1942 if (saved_port_clip_region
== NULL
)
1943 saved_port_clip_region
= NewRgn ();
1944 if (new_region
== NULL
)
1945 new_region
= NewRgn ();
1948 mac_prepare_for_quickdraw (f
);
1950 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1952 if (gc
&& gc
->n_clip_rects
)
1954 GetClip (saved_port_clip_region
);
1955 SectRgn (saved_port_clip_region
, gc
->clip_region
, new_region
);
1956 SetClip (new_region
);
1961 mac_end_clip (f
, gc
)
1965 if (gc
&& gc
->n_clip_rects
)
1966 SetClip (saved_port_clip_region
);
1969 #if TARGET_API_MAC_CARBON
1970 /* Mac replacement for XCopyArea: used only for scrolling. */
1973 mac_scroll_area (f
, gc
, src_x
, src_y
, width
, height
, dest_x
, dest_y
)
1977 unsigned int width
, height
;
1981 RgnHandle dummy
= NewRgn (); /* For avoiding update events. */
1983 SetRect (&src_r
, src_x
, src_y
, src_x
+ width
, src_y
+ height
);
1985 mac_prepare_for_quickdraw (f
);
1987 ScrollWindowRect (FRAME_MAC_WINDOW (f
),
1988 &src_r
, dest_x
- src_x
, dest_y
- src_y
,
1989 kScrollWindowNoOptions
, dummy
);
1995 /************************************************************************
1997 ************************************************************************/
1999 extern struct scroll_bar
*tracked_scroll_bar
;
2000 extern Lisp_Object last_mouse_scroll_bar
;
2001 extern Time last_mouse_movement_time
;
2003 static void x_scroll_bar_handle_click
P_ ((struct scroll_bar
*,
2005 const EventRecord
*,
2006 struct input_event
*));
2007 #ifndef USE_TOOLKIT_SCROLL_BARS
2008 static void x_scroll_bar_note_movement
P_ ((struct scroll_bar
*, int, Time
));
2009 #else /* USE_TOOLKIT_SCROLL_BARS */
2010 static void x_scroll_bar_handle_press
P_ ((struct scroll_bar
*,
2011 ControlPartCode
, Point
,
2012 struct input_event
*));
2013 static void x_scroll_bar_handle_release
P_ ((struct scroll_bar
*,
2014 struct input_event
*));
2015 static void x_scroll_bar_handle_drag
P_ ((WindowRef
, struct scroll_bar
*,
2016 Point
, struct input_event
*));
2017 static pascal void scroll_bar_timer_callback
P_ ((EventLoopTimerRef
, void *));
2018 static OSStatus install_scroll_bar_timer
P_ ((void));
2019 static OSStatus set_scroll_bar_timer
P_ ((EventTimerInterval
));
2020 static int control_part_code_to_scroll_bar_part
P_ ((ControlPartCode
));
2021 static void construct_scroll_bar_click
P_ ((struct scroll_bar
*, int,
2022 struct input_event
*));
2023 static OSStatus get_control_part_bounds
P_ ((ControlRef
, ControlPartCode
,
2025 static void update_scroll_bar_track_info
P_ ((struct scroll_bar
*));
2027 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2029 static int last_scroll_bar_part
;
2031 static EventLoopTimerRef scroll_bar_timer
;
2033 static int scroll_bar_timer_event_posted_p
;
2035 #define SCROLL_BAR_FIRST_DELAY 0.5
2036 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2039 scroll_bar_timer_callback (timer
, data
)
2040 EventLoopTimerRef timer
;
2045 err
= mac_post_mouse_moved_event ();
2047 scroll_bar_timer_event_posted_p
= 1;
2051 install_scroll_bar_timer ()
2053 static EventLoopTimerUPP scroll_bar_timer_callbackUPP
= NULL
;
2055 if (scroll_bar_timer_callbackUPP
== NULL
)
2056 scroll_bar_timer_callbackUPP
=
2057 NewEventLoopTimerUPP (scroll_bar_timer_callback
);
2059 if (scroll_bar_timer
== NULL
)
2060 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2061 kEventDurationForever as delays. */
2063 InstallEventLoopTimer (GetCurrentEventLoop (),
2064 kEventDurationForever
, kEventDurationForever
,
2065 scroll_bar_timer_callbackUPP
, NULL
,
2070 set_scroll_bar_timer (delay
)
2071 EventTimerInterval delay
;
2073 if (scroll_bar_timer
== NULL
)
2074 install_scroll_bar_timer ();
2076 scroll_bar_timer_event_posted_p
= 0;
2078 return SetEventLoopTimerNextFireTime (scroll_bar_timer
, delay
);
2082 control_part_code_to_scroll_bar_part (part_code
)
2083 ControlPartCode part_code
;
2087 case kControlUpButtonPart
: return scroll_bar_up_arrow
;
2088 case kControlDownButtonPart
: return scroll_bar_down_arrow
;
2089 case kControlPageUpPart
: return scroll_bar_above_handle
;
2090 case kControlPageDownPart
: return scroll_bar_below_handle
;
2091 case kControlIndicatorPart
: return scroll_bar_handle
;
2098 construct_scroll_bar_click (bar
, part
, bufp
)
2099 struct scroll_bar
*bar
;
2101 struct input_event
*bufp
;
2103 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2104 bufp
->frame_or_window
= bar
->window
;
2108 XSETINT (bufp
->x
, 0);
2109 XSETINT (bufp
->y
, 0);
2110 bufp
->modifiers
= 0;
2114 get_control_part_bounds (ch
, part_code
, rect
)
2116 ControlPartCode part_code
;
2119 RgnHandle region
= NewRgn ();
2122 err
= GetControlRegion (ch
, part_code
, region
);
2124 GetRegionBounds (region
, rect
);
2125 DisposeRgn (region
);
2131 x_scroll_bar_handle_press (bar
, part_code
, mouse_pos
, bufp
)
2132 struct scroll_bar
*bar
;
2133 ControlPartCode part_code
;
2135 struct input_event
*bufp
;
2137 int part
= control_part_code_to_scroll_bar_part (part_code
);
2142 if (part
!= scroll_bar_handle
)
2144 construct_scroll_bar_click (bar
, part
, bufp
);
2145 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2146 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY
);
2147 bar
->dragging
= Qnil
;
2153 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2154 kControlIndicatorPart
, &r
);
2155 XSETINT (bar
->dragging
, - (mouse_pos
.v
- r
.top
) - 1);
2158 last_scroll_bar_part
= part
;
2159 tracked_scroll_bar
= bar
;
2163 x_scroll_bar_handle_release (bar
, bufp
)
2164 struct scroll_bar
*bar
;
2165 struct input_event
*bufp
;
2167 if (last_scroll_bar_part
!= scroll_bar_handle
2168 || (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) >= 0))
2169 construct_scroll_bar_click (bar
, scroll_bar_end_scroll
, bufp
);
2171 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2172 set_scroll_bar_timer (kEventDurationForever
);
2174 last_scroll_bar_part
= -1;
2175 bar
->dragging
= Qnil
;
2176 tracked_scroll_bar
= NULL
;
2180 x_scroll_bar_handle_drag (win
, bar
, mouse_pos
, bufp
)
2182 struct scroll_bar
*bar
;
2184 struct input_event
*bufp
;
2186 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2188 if (last_scroll_bar_part
== scroll_bar_handle
)
2193 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2194 kControlIndicatorPart
, &r
);
2196 if (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) < 0)
2197 XSETINT (bar
->dragging
, - (XINT (bar
->dragging
) + 1));
2199 top
= mouse_pos
.v
- XINT (bar
->dragging
) - XINT (bar
->track_top
);
2200 top_range
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2204 if (top
> top_range
)
2207 construct_scroll_bar_click (bar
, scroll_bar_handle
, bufp
);
2208 XSETINT (bufp
->x
, top
);
2209 XSETINT (bufp
->y
, top_range
);
2213 ControlPartCode part_code
;
2214 int unhilite_p
= 0, part
;
2216 if (ch
!= FindControlUnderMouse (mouse_pos
, win
, &part_code
))
2220 part
= control_part_code_to_scroll_bar_part (part_code
);
2222 switch (last_scroll_bar_part
)
2224 case scroll_bar_above_handle
:
2225 case scroll_bar_below_handle
:
2226 if (part
!= scroll_bar_above_handle
2227 && part
!= scroll_bar_below_handle
)
2231 case scroll_bar_up_arrow
:
2232 case scroll_bar_down_arrow
:
2233 if (part
!= scroll_bar_up_arrow
2234 && part
!= scroll_bar_down_arrow
)
2241 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2242 else if (part
!= last_scroll_bar_part
2243 || scroll_bar_timer_event_posted_p
)
2245 construct_scroll_bar_click (bar
, part
, bufp
);
2246 last_scroll_bar_part
= part
;
2247 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2248 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY
);
2253 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2254 the scroll bar BAR. This function should be called when the bounds
2255 of the scroll bar is changed. */
2258 update_scroll_bar_track_info (bar
)
2259 struct scroll_bar
*bar
;
2261 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2264 GetControlBounds (ch
, &r0
);
2266 if (r0
.right
- r0
.left
>= r0
.bottom
- r0
.top
2268 || r0
.right
- r0
.left
< MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2272 XSETINT (bar
->track_top
, 0);
2273 XSETINT (bar
->track_height
, 0);
2274 XSETINT (bar
->min_handle
, 0);
2280 SetControl32BitMinimum (ch
, 0);
2281 SetControl32BitMaximum (ch
, 1 << 30);
2282 SetControlViewSize (ch
, 1);
2284 /* Move the scroll bar thumb to the top. */
2285 SetControl32BitValue (ch
, 0);
2286 get_control_part_bounds (ch
, kControlIndicatorPart
, &r0
);
2288 /* Move the scroll bar thumb to the bottom. */
2289 SetControl32BitValue (ch
, 1 << 30);
2290 get_control_part_bounds (ch
, kControlIndicatorPart
, &r1
);
2292 UnionRect (&r0
, &r1
, &r0
);
2293 XSETINT (bar
->track_top
, r0
.top
);
2294 XSETINT (bar
->track_height
, r0
.bottom
- r0
.top
);
2295 XSETINT (bar
->min_handle
, r1
.bottom
- r1
.top
);
2297 /* Don't show the scroll bar if its height is not enough to
2298 display the scroll bar thumb. */
2299 if (r0
.bottom
- r0
.top
> 0)
2306 /* Set the thumb size and position of scroll bar BAR. We are currently
2307 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2310 x_set_toolkit_scroll_bar_thumb (bar
, portion
, position
, whole
)
2311 struct scroll_bar
*bar
;
2312 int portion
, position
, whole
;
2314 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2315 int value
, viewsize
, maximum
;
2317 if (XINT (bar
->track_height
) == 0)
2320 if (whole
<= portion
)
2321 value
= 0, viewsize
= 1, maximum
= 0;
2326 maximum
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2327 scale
= (float) maximum
/ (whole
- portion
);
2328 value
= position
* scale
+ 0.5f
;
2329 viewsize
= (int) (portion
* scale
+ 0.5f
) + XINT (bar
->min_handle
);
2334 if (GetControlViewSize (ch
) != viewsize
2335 || GetControl32BitValue (ch
) != value
2336 || GetControl32BitMaximum (ch
) != maximum
)
2338 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2339 SetControlVisibility (ch
, false, false);
2341 SetControl32BitMaximum (ch
, maximum
);
2342 SetControl32BitValue (ch
, value
);
2343 SetControlViewSize (ch
, viewsize
);
2345 SetControlVisibility (ch
, true, true);
2351 #endif /* USE_TOOLKIT_SCROLL_BARS */
2353 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2354 the initial geometry and visibility, respectively. The created
2355 control is stored in some members of BAR. */
2358 mac_create_scroll_bar (bar
, bounds
, visible
)
2359 struct scroll_bar
*bar
;
2363 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2367 mac_prepare_for_quickdraw (f
);
2369 ch
= NewControl (FRAME_MAC_WINDOW (f
), bounds
, "\p", visible
, 0, 0, 0,
2370 #if TARGET_API_MAC_CARBON
2371 kControlScrollBarProc
,
2376 SET_SCROLL_BAR_CONTROL_REF (bar
, ch
);
2378 XSETINT (bar
->start
, 0);
2379 XSETINT (bar
->end
, 0);
2380 bar
->dragging
= Qnil
;
2382 #ifdef USE_TOOLKIT_SCROLL_BARS
2383 update_scroll_bar_track_info (bar
);
2387 /* Dispose of the scroll bar control stored in some members of
2391 mac_dispose_scroll_bar (bar
)
2392 struct scroll_bar
*bar
;
2395 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2397 mac_prepare_for_quickdraw (f
);
2399 DisposeControl (SCROLL_BAR_CONTROL_REF (bar
));
2402 /* Set bounds of the scroll bar BAR to BOUNDS. */
2405 mac_set_scroll_bar_bounds (bar
, bounds
)
2406 struct scroll_bar
*bar
;
2409 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2410 SInt16 width
, height
;
2412 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2414 mac_prepare_for_quickdraw (f
);
2417 width
= bounds
->right
- bounds
->left
;
2418 height
= bounds
->bottom
- bounds
->top
;
2420 MoveControl (ch
, bounds
->left
, bounds
->top
);
2421 SizeControl (ch
, width
, height
);
2422 #ifdef USE_TOOLKIT_SCROLL_BARS
2423 update_scroll_bar_track_info (bar
);
2430 /* Draw the scroll bar BAR. */
2433 mac_redraw_scroll_bar (bar
)
2434 struct scroll_bar
*bar
;
2437 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2439 mac_prepare_for_quickdraw (f
);
2441 Draw1Control (SCROLL_BAR_CONTROL_REF (bar
));
2444 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2445 is set to something other than NO_EVENT, it is enqueued.
2447 This may be called from a signal handler, so we have to ignore GC
2451 x_scroll_bar_handle_click (bar
, part_code
, er
, bufp
)
2452 struct scroll_bar
*bar
;
2453 ControlPartCode part_code
;
2454 const EventRecord
*er
;
2455 struct input_event
*bufp
;
2457 int win_y
, top_range
;
2459 if (! GC_WINDOWP (bar
->window
))
2462 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2463 bufp
->frame_or_window
= bar
->window
;
2466 bar
->dragging
= Qnil
;
2470 case kControlUpButtonPart
:
2471 bufp
->part
= scroll_bar_up_arrow
;
2473 case kControlDownButtonPart
:
2474 bufp
->part
= scroll_bar_down_arrow
;
2476 case kControlPageUpPart
:
2477 bufp
->part
= scroll_bar_above_handle
;
2479 case kControlPageDownPart
:
2480 bufp
->part
= scroll_bar_below_handle
;
2482 #if TARGET_API_MAC_CARBON
2485 case kControlIndicatorPart
:
2487 if (er
->what
== mouseDown
)
2488 bar
->dragging
= make_number (0);
2489 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2490 bufp
->part
= scroll_bar_handle
;
2494 win_y
= XINT (bufp
->y
) - XINT (bar
->top
);
2495 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar
->height
));
2497 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2501 if (! NILP (bar
->dragging
))
2502 win_y
-= XINT (bar
->dragging
);
2506 if (win_y
> top_range
)
2509 XSETINT (bufp
->x
, win_y
);
2510 XSETINT (bufp
->y
, top_range
);
2513 /* Return information to the user about the current position of the mouse
2514 on the scroll bar. */
2517 x_scroll_bar_report_motion (fp
, bar_window
, part
, x
, y
, time
)
2519 Lisp_Object
*bar_window
;
2520 enum scroll_bar_part
*part
;
2522 unsigned long *time
;
2524 struct scroll_bar
*bar
= XSCROLL_BAR (last_mouse_scroll_bar
);
2525 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2526 #if TARGET_API_MAC_CARBON
2527 WindowRef wp
= GetControlOwner (ch
);
2529 WindowRef wp
= (*ch
)->contrlOwner
;
2532 struct frame
*f
= mac_window_to_frame (wp
);
2533 int win_y
, top_range
;
2535 #if TARGET_API_MAC_CARBON
2536 GetGlobalMouse (&mouse_pos
);
2537 mouse_pos
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
2538 mouse_pos
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2540 SetPortWindowPort (wp
);
2541 GetMouse (&mouse_pos
);
2544 win_y
= mouse_pos
.v
- XINT (bar
->top
);
2545 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2547 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2551 if (! NILP (bar
->dragging
))
2552 win_y
-= XINT (bar
->dragging
);
2556 if (win_y
> top_range
)
2560 *bar_window
= bar
->window
;
2562 if (! NILP (bar
->dragging
))
2563 *part
= scroll_bar_handle
;
2564 else if (win_y
< XINT (bar
->start
))
2565 *part
= scroll_bar_above_handle
;
2566 else if (win_y
< XINT (bar
->end
) + VERTICAL_SCROLL_BAR_MIN_HANDLE
)
2567 *part
= scroll_bar_handle
;
2569 *part
= scroll_bar_below_handle
;
2571 XSETINT (*x
, win_y
);
2572 XSETINT (*y
, top_range
);
2575 last_mouse_scroll_bar
= Qnil
;
2577 *time
= last_mouse_movement_time
;
2580 #ifndef USE_TOOLKIT_SCROLL_BARS
2581 /* Draw BAR's handle in the proper position.
2583 If the handle is already drawn from START to END, don't bother
2584 redrawing it, unless REBUILD is non-zero; in that case, always
2585 redraw it. (REBUILD is handy for drawing the handle after expose
2588 Normally, we want to constrain the start and end of the handle to
2589 fit inside its rectangle, but if the user is dragging the scroll
2590 bar handle, we want to let them drag it down all the way, so that
2591 the bar's top is as far down as it goes; otherwise, there's no way
2592 to move to the very end of the buffer. */
2595 x_scroll_bar_set_handle (bar
, start
, end
, rebuild
)
2596 struct scroll_bar
*bar
;
2600 int dragging
= ! NILP (bar
->dragging
);
2601 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2602 FRAME_PTR f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2603 int top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2604 int length
= end
- start
;
2606 /* If the display is already accurate, do nothing. */
2608 && start
== XINT (bar
->start
)
2609 && end
== XINT (bar
->end
))
2614 /* Make sure the values are reasonable, and try to preserve the
2615 distance between start and end. */
2618 else if (start
> top_range
)
2620 end
= start
+ length
;
2624 else if (end
> top_range
&& ! dragging
)
2627 /* Store the adjusted setting in the scroll bar. */
2628 XSETINT (bar
->start
, start
);
2629 XSETINT (bar
->end
, end
);
2631 /* Clip the end position, just for display. */
2632 if (end
> top_range
)
2635 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2636 top positions, to make sure the handle is always at least that
2637 many pixels tall. */
2638 end
+= VERTICAL_SCROLL_BAR_MIN_HANDLE
;
2640 SetControlMinimum (ch
, 0);
2641 /* Don't inadvertently activate deactivated scroll bars */
2642 if (GetControlMaximum (ch
) != -1)
2643 SetControlMaximum (ch
, top_range
+ VERTICAL_SCROLL_BAR_MIN_HANDLE
2645 SetControlValue (ch
, start
);
2646 #if TARGET_API_MAC_CARBON
2647 SetControlViewSize (ch
, end
- start
);
2653 /* Handle some mouse motion while someone is dragging the scroll bar.
2655 This may be called from a signal handler, so we have to ignore GC
2659 x_scroll_bar_note_movement (bar
, y_pos
, t
)
2660 struct scroll_bar
*bar
;
2664 FRAME_PTR f
= XFRAME (XWINDOW (bar
->window
)->frame
);
2666 last_mouse_movement_time
= t
;
2669 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2671 /* If we're dragging the bar, display it. */
2672 if (! GC_NILP (bar
->dragging
))
2674 /* Where should the handle be now? */
2675 int new_start
= y_pos
- 24;
2677 if (new_start
!= XINT (bar
->start
))
2679 int new_end
= new_start
+ (XINT (bar
->end
) - XINT (bar
->start
));
2681 x_scroll_bar_set_handle (bar
, new_start
, new_end
, 0);
2685 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2688 /***********************************************************************
2690 ***********************************************************************/
2693 /* In identifiers such as function/variable names, Emacs tool bar is
2694 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2696 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2697 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2699 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2700 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2701 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2702 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2703 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2704 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2705 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2707 static OSStatus mac_handle_toolbar_command_event
P_ ((EventHandlerCallRef
,
2710 extern Rect last_mouse_glyph
;
2712 extern void mac_move_window_with_gravity
P_ ((struct frame
*, int,
2714 extern void mac_get_window_origin_with_gravity
P_ ((struct frame
*, int,
2716 extern CGImageRef mac_image_spec_to_cg_image
P_ ((struct frame
*,
2720 mac_handle_toolbar_event (next_handler
, event
, data
)
2721 EventHandlerCallRef next_handler
;
2725 OSStatus result
= eventNotHandledErr
;
2727 switch (GetEventKind (event
))
2729 case kEventToolbarGetDefaultIdentifiers
:
2733 case kEventToolbarGetAllowedIdentifiers
:
2735 CFMutableArrayRef array
;
2737 GetEventParameter (event
, kEventParamMutableArray
,
2738 typeCFMutableArrayRef
, NULL
,
2739 sizeof (CFMutableArrayRef
), NULL
, &array
);
2740 CFArrayAppendValue (array
, TOOLBAR_ICON_ITEM_IDENTIFIER
);
2745 case kEventToolbarCreateItemWithIdentifier
:
2747 CFStringRef identifier
;
2748 HIToolbarItemRef item
= NULL
;
2750 GetEventParameter (event
, kEventParamToolbarItemIdentifier
,
2751 typeCFStringRef
, NULL
,
2752 sizeof (CFStringRef
), NULL
, &identifier
);
2754 if (CFStringCompare (identifier
, TOOLBAR_ICON_ITEM_IDENTIFIER
, 0)
2755 == kCFCompareEqualTo
)
2756 HIToolbarItemCreate (identifier
,
2757 kHIToolbarItemAllowDuplicates
2758 | kHIToolbarItemCantBeRemoved
, &item
);
2762 SetEventParameter (event
, kEventParamToolbarItem
,
2763 typeHIToolbarItemRef
,
2764 sizeof (HIToolbarItemRef
), &item
);
2777 /* Create a tool bar for frame F. */
2780 mac_create_frame_tool_bar (f
)
2784 HIToolbarRef toolbar
;
2786 err
= HIToolbarCreate (TOOLBAR_IDENTIFIER
, kHIToolbarNoAttributes
,
2790 static const EventTypeSpec specs
[] =
2791 {{kEventClassToolbar
, kEventToolbarGetDefaultIdentifiers
},
2792 {kEventClassToolbar
, kEventToolbarGetAllowedIdentifiers
},
2793 {kEventClassToolbar
, kEventToolbarCreateItemWithIdentifier
}};
2795 err
= InstallEventHandler (HIObjectGetEventTarget (toolbar
),
2796 mac_handle_toolbar_event
,
2797 GetEventTypeCount (specs
), specs
,
2802 err
= HIToolbarSetDisplayMode (toolbar
, kHIToolbarDisplayModeIconOnly
);
2805 static const EventTypeSpec specs
[] =
2806 {{kEventClassCommand
, kEventCommandProcess
}};
2808 err
= InstallWindowEventHandler (FRAME_MAC_WINDOW (f
),
2809 mac_handle_toolbar_command_event
,
2810 GetEventTypeCount (specs
),
2814 err
= SetWindowToolbar (FRAME_MAC_WINDOW (f
), toolbar
);
2817 CFRelease (toolbar
);
2822 /* Update the tool bar for frame F. Add new buttons and remove old. */
2825 update_frame_tool_bar (f
)
2828 HIToolbarRef toolbar
= NULL
;
2830 CFArrayRef old_items
= NULL
;
2832 int i
, pos
, win_gravity
= f
->output_data
.mac
->toolbar_win_gravity
;
2833 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2837 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2838 if (toolbar
== NULL
)
2840 mac_create_frame_tool_bar (f
);
2841 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2842 if (toolbar
== NULL
)
2844 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2845 mac_get_window_origin_with_gravity (f
, win_gravity
, &left
, &top
);
2848 HIToolbarCopyItems (toolbar
, &old_items
);
2849 if (old_items
== NULL
)
2852 old_count
= CFArrayGetCount (old_items
);
2854 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
2856 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2858 int enabled_p
= !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
));
2859 int selected_p
= !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P
));
2862 CGImageRef cg_image
;
2864 HIToolbarItemRef item
;
2866 /* If image is a vector, choose the image according to the
2868 image
= PROP (TOOL_BAR_ITEM_IMAGES
);
2869 if (VECTORP (image
))
2873 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2874 : TOOL_BAR_IMAGE_ENABLED_DESELECTED
);
2877 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2878 : TOOL_BAR_IMAGE_DISABLED_DESELECTED
);
2880 xassert (ASIZE (image
) >= idx
);
2881 image
= AREF (image
, idx
);
2886 cg_image
= mac_image_spec_to_cg_image (f
, image
);
2887 /* Ignore invalid image specifications. */
2888 if (cg_image
== NULL
)
2891 label
= cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION
));
2895 if (pos
< old_count
)
2897 CGImageRef old_cg_image
= NULL
;
2898 CFStringRef old_label
= NULL
;
2899 Boolean old_enabled_p
;
2901 item
= (HIToolbarItemRef
) CFArrayGetValueAtIndex (old_items
, pos
);
2903 HIToolbarItemCopyImage (item
, &old_cg_image
);
2904 if (cg_image
!= old_cg_image
)
2905 HIToolbarItemSetImage (item
, cg_image
);
2906 CGImageRelease (old_cg_image
);
2908 HIToolbarItemCopyLabel (item
, &old_label
);
2909 if (CFStringCompare (label
, old_label
, 0) != kCFCompareEqualTo
)
2910 HIToolbarItemSetLabel (item
, label
);
2911 CFRelease (old_label
);
2913 old_enabled_p
= HIToolbarItemIsEnabled (item
);
2914 if ((enabled_p
|| idx
>= 0) != old_enabled_p
)
2915 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2920 HIToolbarCreateItemWithIdentifier (toolbar
,
2921 TOOLBAR_ICON_ITEM_IDENTIFIER
,
2925 HIToolbarItemSetImage (item
, cg_image
);
2926 HIToolbarItemSetLabel (item
, label
);
2927 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2928 HIToolbarAppendItem (toolbar
, item
);
2936 HIToolbarItemSetCommandID (item
, TOOLBAR_ITEM_MAKE_COMMAND_ID (i
));
2941 CFRelease (old_items
);
2943 while (pos
< old_count
)
2944 HIToolbarRemoveItemAtIndex (toolbar
, --old_count
);
2946 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), true,
2947 !win_gravity
&& f
== mac_focus_frame (dpyinfo
));
2948 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2949 toolbar visibility change. */
2950 mac_handle_origin_change (f
);
2951 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2953 mac_move_window_with_gravity (f
, win_gravity
, left
, top
);
2954 /* If the title bar is completely outside the screen, adjust the
2956 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f
), kWindowTitleBarRgn
,
2957 kWindowConstrainMoveRegardlessOfFit
2958 | kWindowConstrainAllowPartial
, NULL
, NULL
);
2959 f
->output_data
.mac
->toolbar_win_gravity
= 0;
2966 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2967 doesn't deallocate the resources. */
2970 free_frame_tool_bar (f
)
2973 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f
)))
2975 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2978 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), false,
2979 (NILP (find_symbol_value
2980 (intern ("frame-notice-user-settings")))
2981 && f
== mac_focus_frame (dpyinfo
)));
2982 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2983 on toolbar visibility change. */
2984 mac_handle_origin_change (f
);
2989 /* Report a mouse movement over toolbar to the mainstream Emacs
2993 mac_tool_bar_note_mouse_movement (f
, event
)
2998 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
3001 WindowPartCode part_code
;
3002 HIViewRef item_view
;
3005 mouse_down_p
= (dpyinfo
->grabbed
3006 && f
== last_mouse_frame
3007 && FRAME_LIVE_P (f
));
3011 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
, NULL
,
3012 sizeof (WindowRef
), NULL
, &window
);
3013 if (err
!= noErr
|| window
!= FRAME_MAC_WINDOW (f
))
3016 err
= GetEventParameter (event
, kEventParamWindowPartCode
,
3017 typeWindowPartCode
, NULL
,
3018 sizeof (WindowPartCode
), NULL
, &part_code
);
3019 if (err
!= noErr
|| part_code
!= inStructure
)
3022 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window
), event
, &item_view
);
3023 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3024 toolbar item view seems to have the same command ID with that of
3025 the toolbar item. */
3027 err
= GetControlCommandID (item_view
, &command_id
);
3028 if (err
== noErr
&& TOOLBAR_ITEM_COMMAND_ID_P (command_id
))
3030 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id
);
3032 if (i
< f
->n_tool_bar_items
)
3035 HIViewRef content_view
;
3037 err
= HIViewGetBounds (item_view
, &bounds
);
3039 err
= HIViewFindByID (HIViewGetRoot (window
),
3040 kHIViewWindowContentID
, &content_view
);
3042 err
= HIViewConvertRect (&bounds
, item_view
, content_view
);
3044 SetRect (&last_mouse_glyph
,
3045 CGRectGetMinX (bounds
), CGRectGetMinY (bounds
),
3046 CGRectGetMaxX (bounds
), CGRectGetMaxY (bounds
));
3048 help_echo_object
= help_echo_window
= Qnil
;
3050 help_echo_string
= PROP (TOOL_BAR_ITEM_HELP
);
3051 if (NILP (help_echo_string
))
3052 help_echo_string
= PROP (TOOL_BAR_ITEM_CAPTION
);
3058 mac_handle_toolbar_command_event (next_handler
, event
, data
)
3059 EventHandlerCallRef next_handler
;
3063 OSStatus err
, result
= eventNotHandledErr
;
3064 struct frame
*f
= (struct frame
*) data
;
3067 err
= GetEventParameter (event
, kEventParamDirectObject
,
3068 typeHICommand
, NULL
,
3069 sizeof (HICommand
), NULL
, &command
);
3073 switch (GetEventKind (event
))
3075 case kEventCommandProcess
:
3076 if (!TOOLBAR_ITEM_COMMAND_ID_P (command
.commandID
))
3077 result
= CallNextEventHandler (next_handler
, event
);
3080 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command
.commandID
);
3082 if (i
< f
->n_tool_bar_items
3083 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
)))
3086 struct input_event buf
;
3090 XSETFRAME (frame
, f
);
3091 buf
.kind
= TOOL_BAR_EVENT
;
3092 buf
.frame_or_window
= frame
;
3094 kbd_buffer_store_event (&buf
);
3096 buf
.kind
= TOOL_BAR_EVENT
;
3097 buf
.frame_or_window
= frame
;
3098 buf
.arg
= PROP (TOOL_BAR_ITEM_KEY
);
3099 buf
.modifiers
= mac_event_to_emacs_modifiers (event
);
3100 kbd_buffer_store_event (&buf
);
3114 #endif /* USE_MAC_TOOLBAR */
3117 /***********************************************************************
3119 ***********************************************************************/
3121 #if USE_MAC_FONT_PANEL
3122 /* Whether Font Panel has been shown before. The first call to font
3123 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3124 slow. This variable is used for deferring such a call as much as
3126 static int font_panel_shown_p
= 0;
3128 extern Lisp_Object Qpanel_closed
, Qselection
;
3129 extern Lisp_Object Qfont
;
3131 /* Whether the font panel is currently visible. */
3134 mac_font_panel_visible_p ()
3136 return font_panel_shown_p
&& FPIsFontPanelVisible ();
3139 static pascal OSStatus
3140 mac_handle_font_event (next_handler
, event
, data
)
3141 EventHandlerCallRef next_handler
;
3145 OSStatus result
, err
;
3148 const EventParamName
*names
;
3149 const EventParamType
*types
;
3150 static const EventParamName names_sel
[] = {kEventParamATSUFontID
,
3151 kEventParamATSUFontSize
,
3152 kEventParamFMFontFamily
,
3153 kEventParamFMFontStyle
,
3154 kEventParamFMFontSize
,
3155 kEventParamFontColor
};
3156 static const EventParamType types_sel
[] = {typeATSUFontID
,
3163 result
= CallNextEventHandler (next_handler
, event
);
3164 if (result
!= eventNotHandledErr
)
3167 switch (GetEventKind (event
))
3169 case kEventFontPanelClosed
:
3170 id_key
= Qpanel_closed
;
3176 case kEventFontSelection
:
3177 id_key
= Qselection
;
3178 num_params
= sizeof (names_sel
) / sizeof (names_sel
[0]);
3184 err
= mac_store_event_ref_as_apple_event (0, 0, Qfont
, id_key
,
3193 /* Toggle visiblity of the font panel. */
3196 mac_show_hide_font_panel ()
3198 if (!font_panel_shown_p
)
3202 static const EventTypeSpec specs
[] =
3203 {{kEventClassFont
, kEventFontPanelClosed
},
3204 {kEventClassFont
, kEventFontSelection
}};
3206 err
= InstallApplicationEventHandler (mac_handle_font_event
,
3207 GetEventTypeCount (specs
),
3212 font_panel_shown_p
= 1;
3215 return FPShowHideFontPanel ();
3218 /* Set the font selected in the font panel to the one corresponding to
3219 the face FACE_ID and the charcacter C in the frame F. */
3222 mac_set_font_info_for_selection (f
, face_id
, c
)
3227 EventTargetRef target
= NULL
;
3228 XFontStruct
*font
= NULL
;
3230 if (!mac_font_panel_visible_p ())
3235 target
= GetWindowEventTarget (FRAME_MAC_WINDOW (f
));
3237 if (FRAME_FACE_CACHE (f
) && CHAR_VALID_P (c
, 0))
3241 face_id
= FACE_FOR_CHAR (f
, FACE_FROM_ID (f
, face_id
), c
);
3242 face
= FACE_FROM_ID (f
, face_id
);
3248 err
= SetFontInfoForSelection (kFontSelectionATSUIType
, 0, NULL
, target
);
3251 if (font
->mac_fontnum
!= -1)
3253 FontSelectionQDStyle qd_style
;
3255 qd_style
.version
= kFontSelectionQDStyleVersionZero
;
3256 qd_style
.instance
.fontFamily
= font
->mac_fontnum
;
3257 qd_style
.instance
.fontStyle
= font
->mac_fontface
;
3258 qd_style
.size
= font
->mac_fontsize
;
3259 qd_style
.hasColor
= false;
3261 err
= SetFontInfoForSelection (kFontSelectionQDType
,
3262 1, &qd_style
, target
);
3265 err
= SetFontInfoForSelection (kFontSelectionATSUIType
,
3266 1, &font
->mac_style
, target
);
3271 #endif /* USE_MAC_FONT_PANEL */
3274 /************************************************************************
3276 ************************************************************************/
3278 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3281 static int any_help_event_p
;
3283 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3284 static Lisp_Object last_window
;
3286 static Point saved_menu_event_location
;
3288 extern struct frame
*pending_autoraise_frame
;
3290 extern FRAME_PTR last_mouse_glyph_frame
;
3293 extern int volatile input_signal_count
;
3295 extern int input_signal_count
;
3298 extern int mac_screen_config_changed
;
3300 extern Lisp_Object Vmac_emulate_three_button_mouse
;
3301 #if TARGET_API_MAC_CARBON
3302 extern int mac_wheel_button_is_mouse_2
;
3303 extern int mac_pass_command_to_system
;
3304 extern int mac_pass_control_to_system
;
3305 #endif /* TARGET_API_MAC_CARBON */
3306 extern int mac_ready_for_apple_events
;
3308 extern void mac_focus_changed
P_ ((int, struct mac_display_info
*,
3309 struct frame
*, struct input_event
*));
3310 extern int mac_get_emulated_btn
P_ ((UInt32
));
3311 extern int note_mouse_movement
P_ ((FRAME_PTR
, Point
*));
3312 extern void mac_get_screen_info
P_ ((struct mac_display_info
*));
3314 /* The focus may have changed. Figure out if it is a real focus change,
3315 by checking both FocusIn/Out and Enter/LeaveNotify events.
3317 Returns FOCUS_IN_EVENT event in *BUFP. */
3320 x_detect_focus_change (dpyinfo
, event
, bufp
)
3321 struct mac_display_info
*dpyinfo
;
3322 const EventRecord
*event
;
3323 struct input_event
*bufp
;
3325 struct frame
*frame
;
3327 frame
= mac_window_to_frame ((WindowRef
) event
->message
);
3331 /* On Mac, this is only called from focus events, so no switch needed. */
3332 mac_focus_changed ((event
->modifiers
& activeFlag
),
3333 dpyinfo
, frame
, bufp
);
3336 #if TARGET_API_MAC_CARBON
3337 /* Obtains the event modifiers from the event EVENTREF and then calls
3338 mac_to_emacs_modifiers. */
3341 mac_event_to_emacs_modifiers (EventRef eventRef
)
3343 UInt32 mods
= 0, class;
3345 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3346 sizeof (UInt32
), NULL
, &mods
);
3347 class = GetEventClass (eventRef
);
3348 if (!NILP (Vmac_emulate_three_button_mouse
)
3349 && (class == kEventClassMouse
|| class == kEventClassCommand
))
3351 mods
&= ~(optionKey
| cmdKey
);
3353 return mac_to_emacs_modifiers (mods
, 0);
3356 /* Given an event REF, return the code to use for the mouse button
3357 code in the emacs input_event. */
3360 mac_get_mouse_btn (EventRef ref
)
3362 EventMouseButton result
= kEventMouseButtonPrimary
;
3363 GetEventParameter (ref
, kEventParamMouseButton
, typeMouseButton
, NULL
,
3364 sizeof (EventMouseButton
), NULL
, &result
);
3367 case kEventMouseButtonPrimary
:
3368 if (NILP (Vmac_emulate_three_button_mouse
))
3372 GetEventParameter (ref
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3373 sizeof (UInt32
), NULL
, &mods
);
3374 return mac_get_emulated_btn(mods
);
3376 case kEventMouseButtonSecondary
:
3377 return mac_wheel_button_is_mouse_2
? 2 : 1;
3378 case kEventMouseButtonTertiary
:
3379 case 4: /* 4 is the number for the mouse wheel button */
3380 return mac_wheel_button_is_mouse_2
? 1 : 2;
3386 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3387 events. However the click of the mouse wheel is not converted to a
3388 mouseDown or mouseUp event. Likewise for dead key events. This
3389 calls ConvertEventRefToEventRecord, but then checks to see if it is
3390 a mouse up/down, or a dead key Carbon event that has not been
3391 converted, and if so, converts it by hand (to be picked up in the
3392 XTread_socket loop). */
3393 static Boolean
mac_convert_event_ref (EventRef eventRef
, EventRecord
*eventRec
)
3396 Boolean result
= ConvertEventRefToEventRecord (eventRef
, eventRec
);
3402 switch (GetEventClass (eventRef
))
3404 case kEventClassMouse
:
3405 switch (GetEventKind (eventRef
))
3407 case kEventMouseDown
:
3408 eventRec
->what
= mouseDown
;
3413 eventRec
->what
= mouseUp
;
3422 case kEventClassKeyboard
:
3423 switch (GetEventKind (eventRef
))
3425 case kEventRawKeyDown
:
3427 goto keystroke_common
;
3428 case kEventRawKeyRepeat
:
3430 goto keystroke_common
;
3431 case kEventRawKeyUp
:
3435 unsigned char char_codes
;
3438 err
= GetEventParameter (eventRef
, kEventParamKeyMacCharCodes
,
3439 typeChar
, NULL
, sizeof (char),
3442 err
= GetEventParameter (eventRef
, kEventParamKeyCode
,
3443 typeUInt32
, NULL
, sizeof (UInt32
),
3447 eventRec
->what
= action
;
3448 eventRec
->message
= char_codes
| ((key_code
& 0xff) << 8);
3465 /* Need where and when. */
3468 GetEventParameter (eventRef
, kEventParamMouseLocation
, typeQDPoint
,
3469 NULL
, sizeof (Point
), NULL
, &eventRec
->where
);
3470 /* Use two step process because new event modifiers are 32-bit
3471 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3472 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
,
3473 NULL
, sizeof (UInt32
), NULL
, &mods
);
3474 eventRec
->modifiers
= mods
;
3476 eventRec
->when
= EventTimeToTicks (GetEventTime (eventRef
));
3481 #endif /* TARGET_API_MAC_CARBON */
3483 #if !TARGET_API_MAC_CARBON
3484 static RgnHandle mouse_region
= NULL
;
3487 mac_wait_next_event (er
, sleep_time
, dequeue
)
3492 static EventRecord er_buf
= {nullEvent
};
3493 UInt32 target_tick
, current_tick
;
3494 EventMask event_mask
;
3496 if (mouse_region
== NULL
)
3497 mouse_region
= NewRgn ();
3499 event_mask
= everyEvent
;
3500 if (!mac_ready_for_apple_events
)
3501 event_mask
-= highLevelEventMask
;
3503 current_tick
= TickCount ();
3504 target_tick
= current_tick
+ sleep_time
;
3506 if (er_buf
.what
== nullEvent
)
3507 while (!WaitNextEvent (event_mask
, &er_buf
,
3508 target_tick
- current_tick
, mouse_region
))
3510 current_tick
= TickCount ();
3511 if (target_tick
<= current_tick
)
3517 er_buf
.what
= nullEvent
;
3520 #endif /* not TARGET_API_MAC_CARBON */
3522 #if TARGET_API_MAC_CARBON
3524 mac_post_mouse_moved_event ()
3526 EventRef event
= NULL
;
3529 err
= CreateEvent (NULL
, kEventClassMouse
, kEventMouseMoved
, 0,
3530 kEventAttributeNone
, &event
);
3535 GetGlobalMouse (&mouse_pos
);
3536 err
= SetEventParameter (event
, kEventParamMouseLocation
, typeQDPoint
,
3537 sizeof (Point
), &mouse_pos
);
3541 UInt32 modifiers
= GetCurrentKeyModifiers ();
3543 err
= SetEventParameter (event
, kEventParamKeyModifiers
, typeUInt32
,
3544 sizeof (UInt32
), &modifiers
);
3547 err
= PostEventToQueue (GetCurrentEventQueue (), event
,
3548 kEventPriorityStandard
);
3550 ReleaseEvent (event
);
3557 /* Run the current run loop in the default mode until some input
3558 happens or TIMEOUT seconds passes unless it is negative. Return
3559 true if timeout occurs first. */
3562 mac_run_loop_run_once (timeout
)
3563 EventTimeout timeout
;
3566 mac_prepare_for_quickdraw (NULL
);
3568 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode
,
3569 timeout
>= 0 ? timeout
: 100000, true)
3570 == kCFRunLoopRunTimedOut
);
3574 /* Emacs calls this whenever it wants to read an input event from the
3578 XTread_socket (sd
, expected
, hold_quit
)
3580 struct input_event
*hold_quit
;
3582 struct input_event inev
;
3584 #if TARGET_API_MAC_CARBON
3586 EventTargetRef toolbox_dispatcher
;
3589 struct mac_display_info
*dpyinfo
= &one_mac_display_info
;
3591 if (interrupt_input_blocked
)
3593 interrupt_input_pending
= 1;
3597 interrupt_input_pending
= 0;
3600 /* So people can tell when we have read the available input. */
3601 input_signal_count
++;
3605 #if TARGET_API_MAC_CARBON
3606 toolbox_dispatcher
= GetEventDispatcherTarget ();
3610 mac_prepare_for_quickdraw (NULL
),
3612 !ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
3613 kEventRemoveFromQueue
, &eventRef
))
3614 #else /* !TARGET_API_MAC_CARBON */
3615 while (mac_wait_next_event (&er
, 0, true))
3616 #endif /* !TARGET_API_MAC_CARBON */
3620 unsigned long timestamp
;
3623 inev
.kind
= NO_EVENT
;
3626 #if TARGET_API_MAC_CARBON
3627 timestamp
= GetEventTime (eventRef
) / kEventDurationMillisecond
;
3629 if (!mac_convert_event_ref (eventRef
, &er
))
3631 #else /* !TARGET_API_MAC_CARBON */
3632 timestamp
= er
.when
* (1000 / 60); /* ticks to milliseconds */
3633 #endif /* !TARGET_API_MAC_CARBON */
3640 WindowRef window_ptr
;
3641 ControlPartCode part_code
;
3644 #if TARGET_API_MAC_CARBON
3647 /* This is needed to send mouse events like aqua window
3648 buttons to the correct handler. */
3649 read_socket_inev
= &inev
;
3650 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
3651 read_socket_inev
= NULL
;
3652 if (err
!= eventNotHandledErr
)
3655 last_mouse_glyph_frame
= 0;
3657 if (dpyinfo
->grabbed
&& last_mouse_frame
3658 && FRAME_LIVE_P (last_mouse_frame
))
3660 window_ptr
= FRAME_MAC_WINDOW (last_mouse_frame
);
3661 part_code
= inContent
;
3665 part_code
= FindWindow (er
.where
, &window_ptr
);
3666 if (tip_window
&& window_ptr
== tip_window
)
3668 HideWindow (tip_window
);
3669 part_code
= FindWindow (er
.where
, &window_ptr
);
3673 if (er
.what
!= mouseDown
3674 && (part_code
!= inContent
|| dpyinfo
->grabbed
== 0))
3680 f
= mac_focus_frame (dpyinfo
);
3681 saved_menu_event_location
= er
.where
;
3682 inev
.kind
= MENU_BAR_ACTIVATE_EVENT
;
3683 XSETFRAME (inev
.frame_or_window
, f
);
3688 #if TARGET_API_MAC_CARBON
3689 FrontNonFloatingWindow ()
3694 || (mac_window_to_frame (window_ptr
)
3695 != dpyinfo
->x_focus_frame
))
3696 SelectWindow (window_ptr
);
3699 ControlPartCode control_part_code
;
3703 ControlKind control_kind
;
3706 f
= mac_window_to_frame (window_ptr
);
3707 /* convert to local coordinates of new window */
3708 mouse_loc
.h
= (er
.where
.h
3710 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3711 mouse_loc
.v
= (er
.where
.v
3713 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3714 #if TARGET_API_MAC_CARBON
3715 ch
= FindControlUnderMouse (mouse_loc
, window_ptr
,
3716 &control_part_code
);
3719 GetControlKind (ch
, &control_kind
);
3722 control_part_code
= FindControl (mouse_loc
, window_ptr
,
3726 #if TARGET_API_MAC_CARBON
3727 inev
.code
= mac_get_mouse_btn (eventRef
);
3728 inev
.modifiers
= mac_event_to_emacs_modifiers (eventRef
);
3730 inev
.code
= mac_get_emulated_btn (er
.modifiers
);
3731 inev
.modifiers
= mac_to_emacs_modifiers (er
.modifiers
, 0);
3733 XSETINT (inev
.x
, mouse_loc
.h
);
3734 XSETINT (inev
.y
, mouse_loc
.v
);
3736 if ((dpyinfo
->grabbed
&& tracked_scroll_bar
)
3738 #ifndef USE_TOOLKIT_SCROLL_BARS
3739 /* control_part_code becomes kControlNoPart if
3740 a progress indicator is clicked. */
3741 && control_part_code
!= kControlNoPart
3742 #else /* USE_TOOLKIT_SCROLL_BARS */
3744 && control_kind
.kind
== kControlKindScrollBar
3745 #endif /* MAC_OSX */
3746 #endif /* USE_TOOLKIT_SCROLL_BARS */
3749 struct scroll_bar
*bar
;
3751 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3753 bar
= tracked_scroll_bar
;
3754 #ifndef USE_TOOLKIT_SCROLL_BARS
3755 control_part_code
= kControlIndicatorPart
;
3759 bar
= (struct scroll_bar
*) GetControlReference (ch
);
3760 #ifdef USE_TOOLKIT_SCROLL_BARS
3761 /* Make the "Ctrl-Mouse-2 splits window" work
3762 for toolkit scroll bars. */
3763 if (inev
.modifiers
& ctrl_modifier
)
3764 x_scroll_bar_handle_click (bar
, control_part_code
,
3766 else if (er
.what
== mouseDown
)
3767 x_scroll_bar_handle_press (bar
, control_part_code
,
3770 x_scroll_bar_handle_release (bar
, &inev
);
3771 #else /* not USE_TOOLKIT_SCROLL_BARS */
3772 x_scroll_bar_handle_click (bar
, control_part_code
,
3774 if (er
.what
== mouseDown
3775 && control_part_code
== kControlIndicatorPart
)
3776 tracked_scroll_bar
= bar
;
3778 tracked_scroll_bar
= NULL
;
3779 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3784 int x
= mouse_loc
.h
;
3785 int y
= mouse_loc
.v
;
3787 window
= window_from_coordinates (f
, x
, y
, 0, 0, 0, 1);
3788 if (EQ (window
, f
->tool_bar_window
))
3790 if (er
.what
== mouseDown
)
3791 handle_tool_bar_click (f
, x
, y
, 1, 0);
3793 handle_tool_bar_click (f
, x
, y
, 0,
3799 XSETFRAME (inev
.frame_or_window
, f
);
3800 inev
.kind
= MOUSE_CLICK_EVENT
;
3804 if (er
.what
== mouseDown
)
3806 dpyinfo
->grabbed
|= (1 << inev
.code
);
3807 last_mouse_frame
= f
;
3810 last_tool_bar_item
= -1;
3814 if ((dpyinfo
->grabbed
& (1 << inev
.code
)) == 0)
3815 /* If a button is released though it was not
3816 previously pressed, that would be because
3817 of multi-button emulation. */
3818 dpyinfo
->grabbed
= 0;
3820 dpyinfo
->grabbed
&= ~(1 << inev
.code
);
3823 /* Ignore any mouse motion that happened before
3824 this event; any subsequent mouse-movement Emacs
3825 events should reflect only motion after the
3830 #ifdef USE_TOOLKIT_SCROLL_BARS
3831 if (inev
.kind
== MOUSE_CLICK_EVENT
3832 || (inev
.kind
== SCROLL_BAR_CLICK_EVENT
3833 && (inev
.modifiers
& ctrl_modifier
)))
3838 inev
.modifiers
|= down_modifier
;
3841 inev
.modifiers
|= up_modifier
;
3848 #if TARGET_API_MAC_CARBON
3850 if (IsWindowPathSelectClick (window_ptr
, &er
))
3852 WindowPathSelect (window_ptr
, NULL
, NULL
);
3855 if (part_code
== inProxyIcon
3856 && (TrackWindowProxyDrag (window_ptr
, er
.where
)
3857 != errUserWantsToDragWindow
))
3859 DragWindow (window_ptr
, er
.where
, NULL
);
3860 #else /* not TARGET_API_MAC_CARBON */
3861 DragWindow (window_ptr
, er
.where
, &qd
.screenBits
.bounds
);
3862 /* Update the frame parameters. */
3864 struct frame
*f
= mac_window_to_frame (window_ptr
);
3866 if (f
&& !f
->async_iconified
)
3867 mac_handle_origin_change (f
);
3869 #endif /* not TARGET_API_MAC_CARBON */
3873 if (TrackGoAway (window_ptr
, er
.where
))
3875 inev
.kind
= DELETE_WINDOW_EVENT
;
3876 XSETFRAME (inev
.frame_or_window
,
3877 mac_window_to_frame (window_ptr
));
3881 /* window resize handling added --ben */
3883 do_grow_window (window_ptr
, &er
);
3886 /* window zoom handling added --ben */
3889 if (TrackBox (window_ptr
, er
.where
, part_code
))
3890 do_zoom_window (window_ptr
, part_code
);
3899 if (FrontNonFloatingWindow () != window_ptr
)
3900 SelectWindow (window_ptr
);
3902 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr
),
3904 /* This doesn't work on Mac OS X 10.2. */
3906 HIViewClick (ch
, eventRef
);
3909 #endif /* USE_MAC_TOOLBAR */
3917 #if !TARGET_API_MAC_CARBON
3919 do_window_update ((WindowRef
) er
.message
);
3924 #if TARGET_API_MAC_CARBON
3925 if (SendEventToEventTarget (eventRef
, toolbox_dispatcher
)
3926 != eventNotHandledErr
)
3929 switch ((er
.message
>> 24) & 0x000000FF)
3932 case suspendResumeMessage
:
3933 if (er
.message
& resumeFlag
)
3940 case mouseMovedMessage
:
3941 #if !TARGET_API_MAC_CARBON
3942 SetRectRgn (mouse_region
, er
.where
.h
, er
.where
.v
,
3943 er
.where
.h
+ 1, er
.where
.v
+ 1);
3945 previous_help_echo_string
= help_echo_string
;
3946 help_echo_string
= Qnil
;
3948 if (dpyinfo
->grabbed
&& last_mouse_frame
3949 && FRAME_LIVE_P (last_mouse_frame
))
3950 f
= last_mouse_frame
;
3952 f
= dpyinfo
->x_focus_frame
;
3954 if (dpyinfo
->mouse_face_hidden
)
3956 dpyinfo
->mouse_face_hidden
= 0;
3957 clear_mouse_face (dpyinfo
);
3962 WindowRef wp
= FRAME_MAC_WINDOW (f
);
3965 mouse_pos
.h
= (er
.where
.h
3967 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3968 mouse_pos
.v
= (er
.where
.v
3970 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3971 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3972 #ifdef USE_TOOLKIT_SCROLL_BARS
3973 x_scroll_bar_handle_drag (wp
, tracked_scroll_bar
,
3975 #else /* not USE_TOOLKIT_SCROLL_BARS */
3976 x_scroll_bar_note_movement (tracked_scroll_bar
,
3978 - XINT (tracked_scroll_bar
->top
),
3979 er
.when
* (1000 / 60));
3980 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3983 /* Generate SELECT_WINDOW_EVENTs when needed. */
3984 if (!NILP (Vmouse_autoselect_window
))
3988 window
= window_from_coordinates (f
,
3993 /* Window will be selected only when it is
3994 not selected now and last mouse movement
3995 event was not in it. Minibuffer window
3996 will be selected only when it is active. */
3997 if (WINDOWP (window
)
3998 && !EQ (window
, last_window
)
3999 && !EQ (window
, selected_window
)
4000 /* For click-to-focus window managers
4001 create event iff we don't leave the
4003 && (focus_follows_mouse
4004 || (EQ (XWINDOW (window
)->frame
,
4005 XWINDOW (selected_window
)->frame
))))
4007 inev
.kind
= SELECT_WINDOW_EVENT
;
4008 inev
.frame_or_window
= window
;
4013 if (!note_mouse_movement (f
, &mouse_pos
))
4014 help_echo_string
= previous_help_echo_string
;
4017 mac_tool_bar_note_mouse_movement (f
, eventRef
);
4022 /* If the contents of the global variable
4023 help_echo_string has changed, generate a
4025 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
4033 WindowRef window_ptr
= (WindowRef
) er
.message
;
4035 ControlRef root_control
;
4037 if (window_ptr
== tip_window
)
4039 HideWindow (tip_window
);
4043 if (!is_emacs_window (window_ptr
))
4046 f
= mac_window_to_frame (window_ptr
);
4048 if ((er
.modifiers
& activeFlag
) != 0)
4050 /* A window has been activated */
4053 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4055 ActivateControl (root_control
);
4057 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4059 mouse_loc
.h
= (er
.where
.h
4061 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
4062 mouse_loc
.v
= (er
.where
.v
4064 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
4065 /* Window-activated event counts as mouse movement,
4066 so update things that depend on mouse position. */
4067 note_mouse_movement (f
, &mouse_loc
);
4071 /* A window has been deactivated */
4072 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4074 DeactivateControl (root_control
);
4076 #ifdef USE_TOOLKIT_SCROLL_BARS
4077 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
4079 struct input_event event
;
4082 event
.kind
= NO_EVENT
;
4083 x_scroll_bar_handle_release (tracked_scroll_bar
, &event
);
4084 if (event
.kind
!= NO_EVENT
)
4086 event
.timestamp
= timestamp
;
4087 kbd_buffer_store_event_hold (&event
, hold_quit
);
4092 dpyinfo
->grabbed
= 0;
4094 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4096 if (f
== dpyinfo
->mouse_face_mouse_frame
)
4098 /* If we move outside the frame, then we're
4099 certainly no longer on any text in the
4101 clear_mouse_face (dpyinfo
);
4102 dpyinfo
->mouse_face_mouse_frame
= 0;
4105 /* Generate a nil HELP_EVENT to cancel a help-echo.
4106 Do it only if there's something to cancel.
4107 Otherwise, the startup message is cleared when the
4108 mouse leaves the frame. */
4109 if (any_help_event_p
)
4120 f
= mac_focus_frame (dpyinfo
);
4121 XSETFRAME (inev
.frame_or_window
, f
);
4123 /* If mouse-highlight is an integer, input clears out mouse
4125 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
)
4126 && !EQ (f
->tool_bar_window
, dpyinfo
->mouse_face_window
))
4128 clear_mouse_face (dpyinfo
);
4129 dpyinfo
->mouse_face_hidden
= 1;
4133 UInt32 modifiers
= er
.modifiers
, mapped_modifiers
;
4134 UInt32 key_code
= (er
.message
& keyCodeMask
) >> 8;
4137 GetEventParameter (eventRef
, kEventParamKeyModifiers
,
4139 sizeof (UInt32
), NULL
, &modifiers
);
4141 mapped_modifiers
= mac_mapped_modifiers (modifiers
, key_code
);
4143 #if TARGET_API_MAC_CARBON
4144 if (!(mapped_modifiers
4145 & ~(mac_pass_command_to_system
? cmdKey
: 0)
4146 & ~(mac_pass_control_to_system
? controlKey
: 0)))
4150 if (er
.what
!= keyUp
)
4151 do_keystroke (er
.what
, er
.message
& charCodeMask
,
4152 key_code
, modifiers
, timestamp
, &inev
);
4156 case kHighLevelEvent
:
4157 AEProcessAppleEvent (&er
);
4162 #if TARGET_API_MAC_CARBON
4166 read_socket_inev
= &inev
;
4167 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
4168 read_socket_inev
= NULL
;
4173 #if TARGET_API_MAC_CARBON
4174 ReleaseEvent (eventRef
);
4177 if (inev
.kind
!= NO_EVENT
)
4179 inev
.timestamp
= timestamp
;
4180 kbd_buffer_store_event_hold (&inev
, hold_quit
);
4185 && !(hold_quit
&& hold_quit
->kind
!= NO_EVENT
))
4190 XSETFRAME (frame
, f
);
4196 any_help_event_p
= 1;
4197 gen_help_event (help_echo_string
, frame
, help_echo_window
,
4198 help_echo_object
, help_echo_pos
);
4202 help_echo_string
= Qnil
;
4203 gen_help_event (Qnil
, frame
, Qnil
, Qnil
, 0);
4209 /* If the focus was just given to an autoraising frame,
4211 /* ??? This ought to be able to handle more than one such frame. */
4212 if (pending_autoraise_frame
)
4214 x_raise_frame (pending_autoraise_frame
);
4215 pending_autoraise_frame
= 0;
4218 if (mac_screen_config_changed
)
4220 mac_get_screen_info (dpyinfo
);
4221 mac_screen_config_changed
= 0;
4224 #if !TARGET_API_MAC_CARBON
4225 /* Check which frames are still visible. We do this here because
4226 there doesn't seem to be any direct notification from the Window
4227 Manager that the visibility of a window has changed (at least,
4228 not in all cases). */
4230 Lisp_Object tail
, frame
;
4232 FOR_EACH_FRAME (tail
, frame
)
4234 struct frame
*f
= XFRAME (frame
);
4236 /* The tooltip has been drawn already. Avoid the
4237 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4238 if (EQ (frame
, tip_frame
))
4241 if (FRAME_MAC_P (f
))
4242 mac_handle_visibility_change (f
);
4253 /***********************************************************************
4255 ***********************************************************************/
4257 #if TARGET_API_MAC_CARBON
4258 /* Show the spinning progress indicator for the frame F. Create it if
4259 it doesn't exist yet. */
4262 mac_show_hourglass (f
)
4266 mac_prepare_for_quickdraw (f
);
4268 if (!f
->output_data
.mac
->hourglass_control
)
4270 Window w
= FRAME_MAC_WINDOW (f
);
4274 GetWindowPortBounds (w
, &r
);
4275 r
.left
= r
.right
- HOURGLASS_WIDTH
;
4276 r
.bottom
= r
.top
+ HOURGLASS_HEIGHT
;
4277 if (CreateChasingArrowsControl (w
, &r
, &c
) == noErr
)
4278 f
->output_data
.mac
->hourglass_control
= c
;
4281 if (f
->output_data
.mac
->hourglass_control
)
4282 ShowControl (f
->output_data
.mac
->hourglass_control
);
4285 /* Hide the spinning progress indicator for the frame F. Do nothing
4286 it doesn't exist yet. */
4289 mac_hide_hourglass (f
)
4292 if (f
->output_data
.mac
->hourglass_control
)
4295 mac_prepare_for_quickdraw (f
);
4297 HideControl (f
->output_data
.mac
->hourglass_control
);
4301 /* Reposition the spinning progress indicator for the frame F. Do
4302 nothing it doesn't exist yet. */
4305 mac_reposition_hourglass (f
)
4308 if (f
->output_data
.mac
->hourglass_control
)
4311 mac_prepare_for_quickdraw (f
);
4313 MoveControl (f
->output_data
.mac
->hourglass_control
,
4314 FRAME_PIXEL_WIDTH (f
) - HOURGLASS_WIDTH
, 0);
4317 #endif /* TARGET_API_MAC_CARBON */
4320 /***********************************************************************
4321 File selection dialog
4322 ***********************************************************************/
4324 #if TARGET_API_MAC_CARBON
4325 extern Lisp_Object Qfile_name_history
;
4327 static pascal void mac_nav_event_callback
P_ ((NavEventCallbackMessage
,
4328 NavCBRecPtr
, void *));
4330 /* The actual implementation of Fx_file_dialog. */
4333 mac_file_dialog (prompt
, dir
, default_filename
, mustmatch
, only_dir_p
)
4334 Lisp_Object prompt
, dir
, default_filename
, mustmatch
, only_dir_p
;
4336 Lisp_Object file
= Qnil
;
4337 int count
= SPECPDL_INDEX ();
4338 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
, gcpro5
, gcpro6
;
4339 char filename
[MAXPATHLEN
];
4340 static NavEventUPP mac_nav_event_callbackUPP
= NULL
;
4344 GCPRO6 (prompt
, dir
, default_filename
, mustmatch
, file
, only_dir_p
);
4345 CHECK_STRING (prompt
);
4348 /* Create the dialog with PROMPT as title, using DIR as initial
4349 directory and using "*" as pattern. */
4350 dir
= Fexpand_file_name (dir
, Qnil
);
4354 NavDialogCreationOptions options
;
4355 NavDialogRef dialogRef
;
4356 NavTypeListHandle fileTypes
= NULL
;
4357 NavUserAction userAction
;
4358 CFStringRef message
=NULL
, saveName
= NULL
;
4361 /* No need for a callback function because we are modal */
4362 NavGetDefaultDialogCreationOptions(&options
);
4363 options
.modality
= kWindowModalityAppModal
;
4364 options
.location
.h
= options
.location
.v
= -1;
4365 options
.optionFlags
= kNavDefaultNavDlogOptions
;
4366 options
.optionFlags
|= kNavAllFilesInPopup
; /* All files allowed */
4367 options
.optionFlags
|= kNavSelectAllReadableItem
;
4368 options
.optionFlags
&= ~kNavAllowMultipleFiles
;
4371 message
= cfstring_create_with_string (prompt
);
4372 options
.message
= message
;
4374 /* Don't set the application, let it use default.
4375 options.clientName = CFSTR ("Emacs");
4378 if (mac_nav_event_callbackUPP
== NULL
)
4379 mac_nav_event_callbackUPP
= NewNavEventUPP (mac_nav_event_callback
);
4381 if (!NILP (only_dir_p
))
4382 status
= NavCreateChooseFolderDialog(&options
, mac_nav_event_callbackUPP
,
4383 NULL
, NULL
, &dialogRef
);
4384 else if (NILP (mustmatch
))
4386 /* This is a save dialog */
4387 options
.optionFlags
|= kNavDontConfirmReplacement
;
4388 options
.actionButtonLabel
= CFSTR ("Ok");
4389 options
.windowTitle
= CFSTR ("Enter name");
4391 if (STRINGP (default_filename
))
4393 Lisp_Object utf8
= ENCODE_UTF_8 (default_filename
);
4394 char *begPtr
= SDATA(utf8
);
4395 char *filePtr
= begPtr
+ SBYTES(utf8
);
4396 while (filePtr
!= begPtr
&& !IS_DIRECTORY_SEP(filePtr
[-1]))
4398 saveName
= cfstring_create_with_utf8_cstring (filePtr
);
4399 options
.saveFileName
= saveName
;
4400 options
.optionFlags
|= kNavSelectDefaultLocation
;
4402 status
= NavCreatePutFileDialog(&options
,
4403 'TEXT', kNavGenericSignature
,
4404 mac_nav_event_callbackUPP
, NULL
,
4409 /* This is an open dialog*/
4410 status
= NavCreateChooseFileDialog(&options
, fileTypes
,
4411 mac_nav_event_callbackUPP
, NULL
,
4412 NULL
, NULL
, &dialogRef
);
4415 /* Set the default location and continue*/
4416 if (status
== noErr
)
4418 Lisp_Object encoded_dir
= ENCODE_FILE (dir
);
4421 status
= AECreateDesc (TYPE_FILE_NAME
, SDATA (encoded_dir
),
4422 SBYTES (encoded_dir
), &defLocAed
);
4423 if (status
== noErr
)
4425 NavCustomControl(dialogRef
, kNavCtlSetLocation
, (void*) &defLocAed
);
4426 AEDisposeDesc(&defLocAed
);
4428 status
= NavDialogRun(dialogRef
);
4431 if (saveName
) CFRelease(saveName
);
4432 if (message
) CFRelease(message
);
4434 if (status
== noErr
) {
4435 userAction
= NavDialogGetUserAction(dialogRef
);
4438 case kNavUserActionNone
:
4439 case kNavUserActionCancel
:
4440 break; /* Treat cancel like C-g */
4441 case kNavUserActionOpen
:
4442 case kNavUserActionChoose
:
4443 case kNavUserActionSaveAs
:
4445 NavReplyRecord reply
;
4448 status
= NavDialogGetReply(dialogRef
, &reply
);
4449 if (status
!= noErr
)
4451 status
= AEGetNthPtr (&reply
.selection
, 1, TYPE_FILE_NAME
,
4452 NULL
, NULL
, filename
,
4453 sizeof (filename
) - 1, &len
);
4454 if (status
== noErr
)
4456 len
= min (len
, sizeof (filename
) - 1);
4457 filename
[len
] = '\0';
4458 if (reply
.saveFileName
)
4460 /* If it was a saved file, we need to add the file name */
4461 if (len
&& len
< sizeof (filename
) - 1
4462 && filename
[len
-1] != '/')
4463 filename
[len
++] = '/';
4464 CFStringGetCString(reply
.saveFileName
, filename
+len
,
4465 sizeof (filename
) - len
,
4467 kCFStringEncodingUTF8
4469 CFStringGetSystemEncoding ()
4473 file
= DECODE_FILE (make_unibyte_string (filename
,
4474 strlen (filename
)));
4476 NavDisposeReply(&reply
);
4480 NavDialogDispose(dialogRef
);
4485 /* Fall back on minibuffer if there was a problem */
4486 file
= Fcompleting_read (prompt
, intern ("read-file-name-internal"),
4487 dir
, mustmatch
, dir
, Qfile_name_history
,
4488 default_filename
, Qnil
);
4494 /* Make "Cancel" equivalent to C-g. */
4496 Fsignal (Qquit
, Qnil
);
4498 return unbind_to (count
, file
);
4501 /* Need to register some event callback function for enabling drag and
4502 drop in Navigation Service dialogs. */
4504 mac_nav_event_callback (selector
, parms
, data
)
4505 NavEventCallbackMessage selector
;
4513 /************************************************************************
4515 ************************************************************************/
4517 #if !TARGET_API_MAC_CARBON
4518 #include <MacTypes.h>
4520 #include <Quickdraw.h>
4521 #include <ToolUtils.h>
4523 #include <Controls.h>
4524 #include <Windows.h>
4526 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4527 #include <ControlDefinitions.h>
4529 #endif /* not TARGET_API_MAC_CARBON */
4531 extern int menu_item_selection
;
4532 extern int popup_activated_flag
;
4533 extern int name_is_separator
P_ ((const char *));
4534 extern void find_and_call_menu_selection
P_ ((FRAME_PTR
, int, Lisp_Object
,
4536 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
4538 enum mac_menu_kind
{ /* Menu ID range */
4539 MAC_MENU_APPLE
, /* 0 (Reserved by Apple) */
4540 MAC_MENU_MENU_BAR
, /* 1 .. 233 */
4541 MAC_MENU_M_APPLE
, /* 234 (== M_APPLE) */
4542 MAC_MENU_POPUP
, /* 235 */
4543 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
4544 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
4545 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
4546 MAC_MENU_END
/* 32768 */
4549 static const int min_menu_id
[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4551 static int fill_menu
P_ ((MenuRef
, widget_value
*, enum mac_menu_kind
, int));
4552 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
4554 #if !TARGET_API_MAC_CARBON
4556 do_apple_menu (SInt16 menu_item
)
4559 SInt16 da_driver_refnum
;
4561 if (menu_item
== I_ABOUT
)
4562 NoteAlert (ABOUT_ALERT_ID
, NULL
);
4565 GetMenuItemText (GetMenuRef (M_APPLE
), menu_item
, item_name
);
4566 da_driver_refnum
= OpenDeskAcc (item_name
);
4569 #endif /* !TARGET_API_MAC_CARBON */
4571 /* Activate the menu bar of frame F.
4572 This is called from keyboard.c when it gets the
4573 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4575 To activate the menu bar, we use the button-press event location
4576 that was saved in saved_menu_event_location.
4578 But first we recompute the menu bar contents (the whole tree).
4580 The reason for saving the button event until here, instead of
4581 passing it to the toolkit right away, is that we can safely
4582 execute Lisp code. */
4585 x_activate_menubar (f
)
4589 SInt16 menu_id
, menu_item
;
4591 set_frame_menubar (f
, 0, 1);
4594 popup_activated_flag
= 1;
4595 menu_choice
= MenuSelect (saved_menu_event_location
);
4596 popup_activated_flag
= 0;
4597 menu_id
= HiWord (menu_choice
);
4598 menu_item
= LoWord (menu_choice
);
4600 #if !TARGET_API_MAC_CARBON
4601 if (menu_id
== min_menu_id
[MAC_MENU_M_APPLE
])
4602 do_apple_menu (menu_item
);
4607 MenuRef menu
= GetMenuRef (menu_id
);
4613 GetMenuItemRefCon (menu
, menu_item
, &refcon
);
4614 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
4615 f
->menu_bar_vector
, (void *) refcon
);
4624 #if TARGET_API_MAC_CARBON
4625 extern Lisp_Object Vshow_help_function
;
4628 restore_show_help_function (old_show_help_function
)
4629 Lisp_Object old_show_help_function
;
4631 Vshow_help_function
= old_show_help_function
;
4636 static pascal OSStatus
4637 menu_target_item_handler (next_handler
, event
, data
)
4638 EventHandlerCallRef next_handler
;
4644 MenuItemIndex menu_item
;
4647 int specpdl_count
= SPECPDL_INDEX ();
4649 /* Don't be bothered with the overflowed toolbar items menu. */
4650 if (!popup_activated ())
4651 return eventNotHandledErr
;
4653 err
= GetEventParameter (event
, kEventParamDirectObject
, typeMenuRef
,
4654 NULL
, sizeof (MenuRef
), NULL
, &menu
);
4656 err
= GetEventParameter (event
, kEventParamMenuItemIndex
,
4657 typeMenuItemIndex
, NULL
,
4658 sizeof (MenuItemIndex
), NULL
, &menu_item
);
4660 err
= GetMenuItemProperty (menu
, menu_item
,
4661 MAC_EMACS_CREATOR_CODE
, 'help',
4662 sizeof (Lisp_Object
), NULL
, &help
);
4666 /* Temporarily bind Vshow_help_function to Qnil because we don't
4667 want tooltips during menu tracking. */
4668 record_unwind_protect (restore_show_help_function
, Vshow_help_function
);
4669 Vshow_help_function
= Qnil
;
4671 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
4673 unbind_to (specpdl_count
, Qnil
);
4675 return err
== noErr
? noErr
: eventNotHandledErr
;
4678 /* Showing help echo string during menu tracking. */
4681 install_menu_target_item_handler ()
4683 static const EventTypeSpec specs
[] =
4684 {{kEventClassMenu
, kEventMenuTargetItem
}};
4686 return InstallApplicationEventHandler (NewEventHandlerUPP
4687 (menu_target_item_handler
),
4688 GetEventTypeCount (specs
),
4691 #endif /* TARGET_API_MAC_CARBON */
4693 /* Event handler function that pops down a menu on C-g. We can only pop
4694 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4696 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4697 static pascal OSStatus
4698 menu_quit_handler (nextHandler
, theEvent
, userData
)
4699 EventHandlerCallRef nextHandler
;
4705 UInt32 keyModifiers
;
4707 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
4708 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
4711 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
4712 typeUInt32
, NULL
, sizeof(UInt32
),
4713 NULL
, &keyModifiers
);
4715 if (err
== noErr
&& mac_quit_char_key_p (keyModifiers
, keyCode
))
4717 MenuRef menu
= userData
!= 0
4718 ? (MenuRef
)userData
: AcquireRootMenu ();
4720 CancelMenuTracking (menu
, true, 0);
4721 if (!userData
) ReleaseMenu (menu
);
4725 return CallNextEventHandler (nextHandler
, theEvent
);
4727 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4729 /* Add event handler to all menus that belong to KIND so we can detect
4730 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4731 when C-g is detected. NULL means the menu bar. If
4732 CancelMenuTracking isn't available, do nothing. */
4735 install_menu_quit_handler (kind
, root_menu
)
4736 enum mac_menu_kind kind
;
4739 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4740 static const EventTypeSpec typesList
[] =
4741 {{kEventClassKeyboard
, kEventRawKeyDown
}};
4744 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4745 if (CancelMenuTracking
== NULL
)
4748 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
4750 MenuRef menu
= GetMenuRef (id
);
4754 InstallMenuEventHandler (menu
, menu_quit_handler
,
4755 GetEventTypeCount (typesList
),
4756 typesList
, root_menu
, NULL
);
4758 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4765 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
4766 FRAME_PTR f
= p
->pointer
;
4767 MenuRef menu
= GetMenuRef (min_menu_id
[MAC_MENU_POPUP
]);
4771 /* Must reset this manually because the button release event is not
4772 passed to Emacs event loop. */
4773 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
4775 /* delete all menus */
4776 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
4777 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
4785 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4786 until the menu pops down. Return the selection. */
4789 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
4791 widget_value
*first_wv
;
4797 MenuRef menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
4798 int menu_item_choice
;
4799 int specpdl_count
= SPECPDL_INDEX ();
4801 InsertMenu (menu
, -1);
4802 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
4803 min_menu_id
[MAC_MENU_POPUP_SUB
]);
4805 /* Add event handler so we can detect C-g. */
4806 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
4807 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
4809 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
4811 /* Adjust coordinates to be root-window-relative. */
4812 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
4813 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
4815 /* Display the menu. */
4816 popup_activated_flag
= 1;
4817 menu_item_choice
= PopUpMenuSelect (menu
, y
, x
, 0);
4818 popup_activated_flag
= 0;
4820 /* Get the refcon to find the correct item */
4821 if (menu_item_choice
)
4823 MenuRef sel_menu
= GetMenuRef (HiWord (menu_item_choice
));
4826 GetMenuItemRefCon (sel_menu
, LoWord (menu_item_choice
),
4827 (UInt32
*) &result
);
4830 unbind_to (specpdl_count
, Qnil
);
4832 menu_item_selection
= result
;
4836 add_menu_item (menu
, pos
, wv
)
4841 #if TARGET_API_MAC_CARBON
4842 CFStringRef item_name
;
4847 if (name_is_separator (wv
->name
))
4848 AppendMenu (menu
, "\p-");
4851 AppendMenu (menu
, "\pX");
4853 #if TARGET_API_MAC_CARBON
4854 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
4856 if (wv
->key
!= NULL
)
4858 CFStringRef name
, key
;
4861 key
= cfstring_create_with_utf8_cstring (wv
->key
);
4862 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
4868 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
4869 CFRelease (item_name
);
4872 EnableMenuItem (menu
, pos
);
4874 DisableMenuItem (menu
, pos
);
4876 if (STRINGP (wv
->help
))
4877 SetMenuItemProperty (menu
, pos
, MAC_EMACS_CREATOR_CODE
, 'help',
4878 sizeof (Lisp_Object
), &wv
->help
);
4879 #else /* ! TARGET_API_MAC_CARBON */
4880 item_name
[sizeof (item_name
) - 1] = '\0';
4881 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
4882 if (wv
->key
!= NULL
)
4884 int len
= strlen (item_name
);
4886 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
4887 len
= strlen (item_name
);
4888 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
4891 SetMenuItemText (menu
, pos
, item_name
);
4894 EnableItem (menu
, pos
);
4896 DisableItem (menu
, pos
);
4897 #endif /* ! TARGET_API_MAC_CARBON */
4899 /* Draw radio buttons and tickboxes. */
4900 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
4901 || wv
->button_type
== BUTTON_TYPE_RADIO
))
4902 SetItemMark (menu
, pos
, checkMark
);
4904 SetItemMark (menu
, pos
, noMark
);
4906 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
4910 /* Construct native Mac OS menu based on widget_value tree. */
4913 fill_menu (menu
, wv
, kind
, submenu_id
)
4916 enum mac_menu_kind kind
;
4921 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
4923 add_menu_item (menu
, pos
, wv
);
4924 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
4926 MenuRef submenu
= NewMenu (submenu_id
, "\pX");
4928 InsertMenu (submenu
, -1);
4929 #if TARGET_API_MAC_CARBON
4930 SetMenuItemHierarchicalMenu (menu
, pos
, submenu
);
4932 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
4934 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
4941 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4942 the entire menu trees we supply, rather than just the menu bar item
4946 mac_fill_menubar (wv
, deep_p
)
4951 #if !TARGET_API_MAC_CARBON
4952 int title_changed_p
= 0;
4955 /* Clean up the menu bar when filled by the entire menu trees. */
4958 dispose_menus (MAC_MENU_MENU_BAR
, 0);
4959 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
4960 #if !TARGET_API_MAC_CARBON
4961 title_changed_p
= 1;
4965 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4966 titles as much as possible to minimize redraw (if !deep_p). */
4967 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
4968 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
4969 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
4970 wv
= wv
->next
, id
++)
4972 OSStatus err
= noErr
;
4974 #if TARGET_API_MAC_CARBON
4977 title
= CFStringCreateWithCString (NULL
, wv
->name
,
4978 kCFStringEncodingMacRoman
);
4982 strncpy (title
, wv
->name
, 255);
4987 menu
= GetMenuRef (id
);
4990 #if TARGET_API_MAC_CARBON
4991 CFStringRef old_title
;
4993 err
= CopyMenuTitleAsCFString (menu
, &old_title
);
4996 if (CFStringCompare (title
, old_title
, 0) != kCFCompareEqualTo
)
4999 if (id
+ 1 == min_menu_id
[MAC_MENU_MENU_BAR
+ 1]
5000 || GetMenuRef (id
+ 1) == NULL
)
5002 /* This is a workaround for Mac OS X 10.5 where
5003 just calling SetMenuTitleWithCFString fails
5004 to change the title of the last (Help) menu
5011 #endif /* MAC_OSX */
5012 err
= SetMenuTitleWithCFString (menu
, title
);
5014 CFRelease (old_title
);
5017 err
= SetMenuTitleWithCFString (menu
, title
);
5018 #else /* !TARGET_API_MAC_CARBON */
5019 if (!EqualString (title
, (*menu
)->menuData
, false, false))
5023 menu
= NewMenu (id
, title
);
5024 InsertMenu (menu
, GetMenuRef (id
+ 1) ? id
+ 1 : 0);
5025 title_changed_p
= 1;
5027 #endif /* !TARGET_API_MAC_CARBON */
5032 #if TARGET_API_MAC_CARBON
5033 err
= CreateNewMenu (id
, 0, &menu
);
5035 err
= SetMenuTitleWithCFString (menu
, title
);
5037 menu
= NewMenu (id
, title
);
5041 InsertMenu (menu
, 0);
5042 #if !TARGET_API_MAC_CARBON
5043 title_changed_p
= 1;
5047 #if TARGET_API_MAC_CARBON
5053 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
5057 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuRef (id
))
5059 dispose_menus (MAC_MENU_MENU_BAR
, id
);
5060 #if !TARGET_API_MAC_CARBON
5061 title_changed_p
= 1;
5065 #if !TARGET_API_MAC_CARBON
5066 if (title_changed_p
)
5070 /* Add event handler so we can detect C-g. */
5071 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
5072 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
5075 /* Dispose of menus that belong to KIND, and remove them from the menu
5076 list. ID is the lower bound of menu IDs that will be processed. */
5079 dispose_menus (kind
, id
)
5080 enum mac_menu_kind kind
;
5083 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
5085 MenuRef menu
= GetMenuRef (id
);
5100 MenuItemIndex menu_index
;
5102 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandQuit
, 1,
5103 &menu
, &menu_index
);
5105 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5106 EnableMenuCommand (NULL
, kHICommandPreferences
);
5107 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandPreferences
, 1,
5108 &menu
, &menu_index
);
5111 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5112 InsertMenuItemTextWithCFString (menu
, NULL
,
5113 0, kMenuItemAttrSeparator
, 0);
5114 InsertMenuItemTextWithCFString (menu
, CFSTR ("About Emacs"),
5115 0, 0, kHICommandAbout
);
5117 #else /* !MAC_OSX */
5118 #if TARGET_API_MAC_CARBON
5119 SetMenuItemCommandID (GetMenuRef (M_APPLE
), I_ABOUT
, kHICommandAbout
);
5125 /***********************************************************************
5127 ***********************************************************************/
5129 #if TARGET_API_MAC_CARBON
5130 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5131 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5132 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5133 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5134 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5135 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5136 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5138 extern EMACS_TIME timer_check
P_ ((int));
5139 static int quit_dialog_event_loop
;
5141 static pascal OSStatus
5142 mac_handle_dialog_event (next_handler
, event
, data
)
5143 EventHandlerCallRef next_handler
;
5147 OSStatus err
, result
= eventNotHandledErr
;
5148 WindowRef window
= (WindowRef
) data
;
5150 switch (GetEventClass (event
))
5152 case kEventClassCommand
:
5156 err
= GetEventParameter (event
, kEventParamDirectObject
,
5157 typeHICommand
, NULL
, sizeof (HICommand
),
5160 if (DIALOG_BUTTON_COMMAND_ID_P (command
.commandID
))
5162 SetWRefCon (window
, command
.commandID
);
5163 quit_dialog_event_loop
= 1;
5167 result
= CallNextEventHandler (next_handler
, event
);
5171 case kEventClassKeyboard
:
5176 result
= CallNextEventHandler (next_handler
, event
);
5177 if (result
!= eventNotHandledErr
)
5180 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
5181 typeChar
, NULL
, sizeof (char),
5186 case kEscapeCharCode
:
5187 quit_dialog_event_loop
= 1;
5192 UInt32 modifiers
, key_code
;
5194 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
5195 typeUInt32
, NULL
, sizeof (UInt32
),
5198 err
= GetEventParameter (event
, kEventParamKeyCode
,
5199 typeUInt32
, NULL
, sizeof (UInt32
),
5202 if (mac_quit_char_key_p (modifiers
, key_code
))
5203 quit_dialog_event_loop
= 1;
5214 if (quit_dialog_event_loop
)
5216 err
= QuitEventLoop (GetCurrentEventLoop ());
5225 install_dialog_event_handler (window
)
5228 static const EventTypeSpec specs
[] =
5229 {{kEventClassCommand
, kEventCommandProcess
},
5230 {kEventClassKeyboard
, kEventRawKeyDown
}};
5231 static EventHandlerUPP handle_dialog_eventUPP
= NULL
;
5233 if (handle_dialog_eventUPP
== NULL
)
5234 handle_dialog_eventUPP
= NewEventHandlerUPP (mac_handle_dialog_event
);
5235 return InstallWindowEventHandler (window
, handle_dialog_eventUPP
,
5236 GetEventTypeCount (specs
), specs
,
5241 pop_down_dialog (arg
)
5244 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
5245 WindowRef window
= p
->pointer
;
5249 if (popup_activated_flag
)
5250 EndAppModalStateForWindow (window
);
5251 DisposeWindow (window
);
5252 popup_activated_flag
= 0;
5259 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5261 menu_item_selection will be set to the selection. */
5264 create_and_show_dialog (f
, first_wv
)
5266 widget_value
*first_wv
;
5269 char *dialog_name
, *message
;
5270 int nb_buttons
, first_group_count
, i
, result
= 0;
5272 short buttons_height
, text_height
, inner_width
, inner_height
;
5273 Rect empty_rect
, *rects
;
5274 WindowRef window
= NULL
;
5275 ControlRef
*buttons
, default_button
= NULL
, text
;
5276 int specpdl_count
= SPECPDL_INDEX ();
5278 dialog_name
= first_wv
->name
;
5279 nb_buttons
= dialog_name
[1] - '0';
5280 first_group_count
= nb_buttons
- (dialog_name
[4] - '0');
5282 wv
= first_wv
->contents
;
5283 message
= wv
->value
;
5286 SetRect (&empty_rect
, 0, 0, 0, 0);
5288 /* Create dialog window. */
5289 err
= CreateNewWindow (kMovableModalWindowClass
,
5290 kWindowStandardHandlerAttribute
,
5291 &empty_rect
, &window
);
5294 record_unwind_protect (pop_down_dialog
, make_save_value (window
, 0));
5295 err
= SetThemeWindowBackground (window
, kThemeBrushMovableModalBackground
,
5299 err
= SetWindowTitleWithCFString (window
, (dialog_name
[0] == 'Q'
5300 ? CFSTR ("Question")
5301 : CFSTR ("Information")));
5303 /* Create button controls and measure their optimal bounds. */
5306 buttons
= alloca (sizeof (ControlRef
) * nb_buttons
);
5307 rects
= alloca (sizeof (Rect
) * nb_buttons
);
5308 for (i
= 0; i
< nb_buttons
; i
++)
5310 CFStringRef label
= cfstring_create_with_utf8_cstring (wv
->value
);
5316 err
= CreatePushButtonControl (window
, &empty_rect
,
5317 label
, &buttons
[i
]);
5325 err
= DisableControl (buttons
[i
]);
5327 err
= DeactivateControl (buttons
[i
]);
5330 else if (default_button
== NULL
)
5331 default_button
= buttons
[i
];
5337 rects
[i
] = empty_rect
;
5338 err
= GetBestControlRect (buttons
[i
], &rects
[i
], &unused
);
5344 OffsetRect (&rects
[i
], -rects
[i
].left
, -rects
[i
].top
);
5345 if (rects
[i
].right
< DIALOG_BUTTON_MIN_WIDTH
)
5346 rects
[i
].right
= DIALOG_BUTTON_MIN_WIDTH
;
5347 else if (rects
[i
].right
> DIALOG_MAX_INNER_WIDTH
)
5348 rects
[i
].right
= DIALOG_MAX_INNER_WIDTH
;
5350 command_id
= DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv
->call_data
);
5351 err
= SetControlCommandID (buttons
[i
], command_id
);
5359 /* Layout buttons. rects[i] is set relative to the bottom-right
5360 corner of the inner box. */
5363 short bottom
, right
, max_height
, left_align_shift
;
5365 inner_width
= DIALOG_MIN_INNER_WIDTH
;
5366 bottom
= right
= max_height
= 0;
5367 for (i
= 0; i
< nb_buttons
; i
++)
5369 if (right
- rects
[i
].right
< - inner_width
)
5371 if (i
!= first_group_count
5372 && right
- rects
[i
].right
>= - DIALOG_MAX_INNER_WIDTH
)
5373 inner_width
= - (right
- rects
[i
].right
);
5376 bottom
-= max_height
+ DIALOG_BUTTON_BUTTON_VERTICAL_SPACE
;
5377 right
= max_height
= 0;
5380 if (max_height
< rects
[i
].bottom
)
5381 max_height
= rects
[i
].bottom
;
5382 OffsetRect (&rects
[i
], right
- rects
[i
].right
,
5383 bottom
- rects
[i
].bottom
);
5384 right
= rects
[i
].left
- DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5385 if (i
== first_group_count
- 1)
5386 right
-= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5388 buttons_height
= - (bottom
- max_height
);
5390 left_align_shift
= - (inner_width
+ rects
[nb_buttons
- 1].left
);
5391 for (i
= nb_buttons
- 1; i
>= first_group_count
; i
--)
5393 if (bottom
!= rects
[i
].bottom
)
5395 left_align_shift
= - (inner_width
+ rects
[i
].left
);
5396 bottom
= rects
[i
].bottom
;
5398 OffsetRect (&rects
[i
], left_align_shift
, 0);
5402 /* Create a static text control and measure its bounds. */
5405 CFStringRef message_string
;
5408 message_string
= cfstring_create_with_utf8_cstring (message
);
5409 if (message_string
== NULL
)
5413 ControlFontStyleRec text_style
;
5415 text_style
.flags
= 0;
5416 SetRect (&bounds
, 0, 0, inner_width
, 0);
5417 err
= CreateStaticTextControl (window
, &bounds
, message_string
,
5418 &text_style
, &text
);
5419 CFRelease (message_string
);
5425 bounds
= empty_rect
;
5426 err
= GetBestControlRect (text
, &bounds
, &unused
);
5430 text_height
= bounds
.bottom
- bounds
.top
;
5431 if (text_height
< DIALOG_TEXT_MIN_HEIGHT
)
5432 text_height
= DIALOG_TEXT_MIN_HEIGHT
;
5436 /* Place buttons. */
5439 inner_height
= (text_height
+ DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5442 for (i
= 0; i
< nb_buttons
; i
++)
5444 OffsetRect (&rects
[i
], DIALOG_LEFT_MARGIN
+ inner_width
,
5445 DIALOG_TOP_MARGIN
+ inner_height
);
5446 SetControlBounds (buttons
[i
], &rects
[i
]);
5455 SetRect (&bounds
, DIALOG_LEFT_MARGIN
, DIALOG_TOP_MARGIN
,
5456 DIALOG_LEFT_MARGIN
+ inner_width
,
5457 DIALOG_TOP_MARGIN
+ text_height
);
5458 SetControlBounds (text
, &bounds
);
5461 /* Create the application icon at the upper-left corner. */
5464 ControlButtonContentInfo content
;
5466 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
5470 ProcessInfoRec pinfo
;
5475 content
.contentType
= kControlContentIconRef
;
5477 err
= GetProcessBundleLocation (&psn
, &app_location
);
5479 err
= GetIconRefFromFileInfo (&app_location
, 0, NULL
, 0, NULL
,
5480 kIconServicesNormalUsageFlag
,
5481 &content
.u
.iconRef
, &unused
);
5483 bzero (&pinfo
, sizeof (ProcessInfoRec
));
5484 pinfo
.processInfoLength
= sizeof (ProcessInfoRec
);
5485 pinfo
.processAppSpec
= &app_spec
;
5486 err
= GetProcessInformation (&psn
, &pinfo
);
5488 err
= GetIconRefFromFile (&app_spec
, &content
.u
.iconRef
, &unused
);
5494 SetRect (&bounds
, DIALOG_ICON_LEFT_MARGIN
, DIALOG_ICON_TOP_MARGIN
,
5495 DIALOG_ICON_LEFT_MARGIN
+ DIALOG_ICON_WIDTH
,
5496 DIALOG_ICON_TOP_MARGIN
+ DIALOG_ICON_HEIGHT
);
5497 err
= CreateIconControl (window
, &bounds
, &content
, true, &icon
);
5498 ReleaseIconRef (content
.u
.iconRef
);
5502 /* Show the dialog window and run event loop. */
5505 err
= SetWindowDefaultButton (window
, default_button
);
5507 err
= install_dialog_event_handler (window
);
5511 DIALOG_LEFT_MARGIN
+ inner_width
+ DIALOG_RIGHT_MARGIN
,
5512 DIALOG_TOP_MARGIN
+ inner_height
+ DIALOG_BOTTOM_MARGIN
,
5514 err
= RepositionWindow (window
, FRAME_MAC_WINDOW (f
),
5515 kWindowAlertPositionOnParentWindow
);
5519 SetWRefCon (window
, 0);
5520 ShowWindow (window
);
5521 BringToFront (window
);
5522 popup_activated_flag
= 1;
5523 err
= BeginAppModalStateForWindow (window
);
5527 EventTargetRef toolbox_dispatcher
= GetEventDispatcherTarget ();
5529 quit_dialog_event_loop
= 0;
5532 EMACS_TIME next_time
= timer_check (1);
5533 long secs
= EMACS_SECS (next_time
);
5534 long usecs
= EMACS_USECS (next_time
);
5535 EventTimeout timeout
;
5538 if (secs
< 0 || (secs
== 0 && usecs
== 0))
5540 /* Sometimes timer_check returns -1 (no timers) even if
5541 there are timers. So do a timeout anyway. */
5546 timeout
= (secs
* kEventDurationSecond
5547 + usecs
* kEventDurationMicrosecond
);
5548 err
= ReceiveNextEvent (0, NULL
, timeout
, kEventRemoveFromQueue
,
5552 SendEventToEventTarget (event
, toolbox_dispatcher
);
5553 ReleaseEvent (event
);
5555 #if 0 /* defined (MAC_OSX) */
5556 else if (err
!= eventLoopTimedOutErr
)
5558 if (err
== eventLoopQuitErr
)
5563 /* The return value of ReceiveNextEvent seems to be
5564 unreliable. Use our own global variable instead. */
5565 if (quit_dialog_event_loop
)
5575 UInt32 command_id
= GetWRefCon (window
);
5577 if (DIALOG_BUTTON_COMMAND_ID_P (command_id
))
5578 result
= DIALOG_BUTTON_COMMAND_ID_VALUE (command_id
);
5581 unbind_to (specpdl_count
, Qnil
);
5583 menu_item_selection
= result
;
5585 #else /* not TARGET_API_MAC_CARBON */
5586 #define DIALOG_WINDOW_RESOURCE 130
5589 mac_dialog (widget_value
*wv
)
5593 char **button_labels
;
5600 WindowRef window_ptr
;
5603 EventRecord event_record
;
5605 int control_part_code
;
5608 dialog_name
= wv
->name
;
5609 nb_buttons
= dialog_name
[1] - '0';
5610 left_count
= nb_buttons
- (dialog_name
[4] - '0');
5611 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
5612 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
5615 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
5616 strcpy (prompt
, wv
->value
);
5620 for (i
= 0; i
< nb_buttons
; i
++)
5622 button_labels
[i
] = wv
->value
;
5623 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
5624 strcpy (button_labels
[i
], wv
->value
);
5625 c2pstr (button_labels
[i
]);
5626 ref_cons
[i
] = (UInt32
) wv
->call_data
;
5630 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowRef
) -1);
5632 SetPortWindowPort (window_ptr
);
5635 /* Left and right margins in the dialog are 13 pixels each.*/
5637 /* Calculate width of dialog box: 8 pixels on each side of the text
5638 label in each button, 12 pixels between buttons. */
5639 for (i
= 0; i
< nb_buttons
; i
++)
5640 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
5642 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
5645 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
5647 SizeWindow (window_ptr
, dialog_width
, 78, 0);
5648 ShowWindow (window_ptr
);
5650 SetPortWindowPort (window_ptr
);
5655 DrawString (prompt
);
5658 for (i
= 0; i
< nb_buttons
; i
++)
5660 int button_width
= StringWidth (button_labels
[i
]) + 16;
5661 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
5662 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
5663 kControlPushButtonProc
, ref_cons
[i
]);
5664 left
+= button_width
+ 12;
5665 if (i
== left_count
- 1)
5672 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
5673 if (event_record
.what
== mouseDown
)
5675 part_code
= FindWindow (event_record
.where
, &window_ptr
);
5676 if (part_code
== inContent
)
5678 mouse
= event_record
.where
;
5679 GlobalToLocal (&mouse
);
5680 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
5681 if (control_part_code
== kControlButtonPart
)
5682 if (TrackControl (ch
, mouse
, NULL
))
5683 i
= GetControlReference (ch
);
5688 DisposeWindow (window_ptr
);
5692 #endif /* not TARGET_API_MAC_CARBON */
5695 /***********************************************************************
5697 ***********************************************************************/
5699 #if !TARGET_API_MAC_CARBON
5704 extern Lisp_Object Vselection_converter_alist
;
5705 extern Lisp_Object Qmac_scrap_name
, Qmac_ostype
;
5707 static ScrapFlavorType get_flavor_type_from_symbol
P_ ((Lisp_Object
,
5710 /* Get a reference to the selection corresponding to the symbol SYM.
5711 The reference is set to *SEL, and it becomes NULL if there's no
5712 corresponding selection. Clear the selection if CLEAR_P is
5716 mac_get_selection_from_symbol (sym
, clear_p
, sel
)
5721 OSStatus err
= noErr
;
5722 Lisp_Object str
= Fget (sym
, Qmac_scrap_name
);
5728 #if TARGET_API_MAC_CARBON
5730 CFStringRef scrap_name
= cfstring_create_with_string (str
);
5731 OptionBits options
= (clear_p
? kScrapClearNamedScrap
5732 : kScrapGetNamedScrap
);
5734 err
= GetScrapByName (scrap_name
, options
, sel
);
5735 CFRelease (scrap_name
);
5736 #else /* !MAC_OSX */
5738 err
= ClearCurrentScrap ();
5740 err
= GetCurrentScrap (sel
);
5741 #endif /* !MAC_OSX */
5742 #else /* !TARGET_API_MAC_CARBON */
5747 #endif /* !TARGET_API_MAC_CARBON */
5753 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5754 corresponding flavor type. If SEL is non-zero, the return value is
5755 non-zero only when the SEL has the flavor type. */
5757 static ScrapFlavorType
5758 get_flavor_type_from_symbol (sym
, sel
)
5762 Lisp_Object str
= Fget (sym
, Qmac_ostype
);
5763 ScrapFlavorType flavor_type
;
5765 if (STRINGP (str
) && SBYTES (str
) == 4)
5766 flavor_type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
5770 if (flavor_type
&& sel
)
5772 #if TARGET_API_MAC_CARBON
5774 ScrapFlavorFlags flags
;
5776 err
= GetScrapFlavorFlags (sel
, flavor_type
, &flags
);
5779 #else /* !TARGET_API_MAC_CARBON */
5780 SInt32 size
, offset
;
5782 size
= GetScrap (NULL
, flavor_type
, &offset
);
5785 #endif /* !TARGET_API_MAC_CARBON */
5791 /* Check if the symbol SYM has a corresponding selection target type. */
5794 mac_valid_selection_target_p (sym
)
5797 return get_flavor_type_from_symbol (sym
, 0) != 0;
5800 /* Clear the selection whose reference is *SEL. */
5803 mac_clear_selection (sel
)
5806 #if TARGET_API_MAC_CARBON
5808 return ClearScrap (sel
);
5812 err
= ClearCurrentScrap ();
5814 err
= GetCurrentScrap (sel
);
5817 #else /* !TARGET_API_MAC_CARBON */
5818 return ZeroScrap ();
5819 #endif /* !TARGET_API_MAC_CARBON */
5822 /* Get ownership information for SEL. Emacs can detect a change of
5823 the ownership by comparing saved and current values of the
5824 ownership information. */
5827 mac_get_selection_ownership_info (sel
)
5830 #if TARGET_API_MAC_CARBON
5831 return long_to_cons ((unsigned long) sel
);
5832 #else /* !TARGET_API_MAC_CARBON */
5833 ScrapStuffPtr scrap_info
= InfoScrap ();
5835 return make_number (scrap_info
->scrapCount
);
5836 #endif /* !TARGET_API_MAC_CARBON */
5839 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5842 mac_valid_selection_value_p (value
, target
)
5843 Lisp_Object value
, target
;
5845 return STRINGP (value
);
5848 /* Put Lisp object VALUE to the selection SEL. The target type is
5849 specified by TARGET. */
5852 mac_put_selection_value (sel
, target
, value
)
5854 Lisp_Object target
, value
;
5856 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, 0);
5858 if (flavor_type
== 0 || !STRINGP (value
))
5861 #if TARGET_API_MAC_CARBON
5862 return PutScrapFlavor (sel
, flavor_type
, kScrapFlavorMaskNone
,
5863 SBYTES (value
), SDATA (value
));
5864 #else /* !TARGET_API_MAC_CARBON */
5865 return PutScrap (SBYTES (value
), flavor_type
, SDATA (value
));
5866 #endif /* !TARGET_API_MAC_CARBON */
5869 /* Check if data for the target type TARGET is available in SEL. */
5872 mac_selection_has_target_p (sel
, target
)
5876 return get_flavor_type_from_symbol (target
, sel
) != 0;
5879 /* Get data for the target type TARGET from SEL and create a Lisp
5880 string. Return nil if failed to get data. */
5883 mac_get_selection_value (sel
, target
)
5888 Lisp_Object result
= Qnil
;
5889 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, sel
);
5890 #if TARGET_API_MAC_CARBON
5895 err
= GetScrapFlavorSize (sel
, flavor_type
, &size
);
5900 result
= make_uninit_string (size
);
5901 err
= GetScrapFlavorData (sel
, flavor_type
,
5902 &size
, SDATA (result
));
5905 else if (size
< SBYTES (result
))
5906 result
= make_unibyte_string (SDATA (result
), size
);
5908 while (STRINGP (result
) && size
> SBYTES (result
));
5913 SInt32 size
, offset
;
5916 size
= GetScrap (NULL
, flavor_type
, &offset
);
5919 handle
= NewHandle (size
);
5921 size
= GetScrap (handle
, flavor_type
, &offset
);
5923 result
= make_unibyte_string (*handle
, size
);
5924 DisposeHandle (handle
);
5931 /* Get the list of target types in SEL. The return value is a list of
5932 target type symbols possibly followed by scrap flavor type
5936 mac_get_selection_target_list (sel
)
5939 Lisp_Object result
= Qnil
, rest
, target
;
5940 #if TARGET_API_MAC_CARBON
5942 UInt32 count
, i
, type
;
5943 ScrapFlavorInfo
*flavor_info
= NULL
;
5944 Lisp_Object strings
= Qnil
;
5946 err
= GetScrapFlavorCount (sel
, &count
);
5948 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
5949 err
= GetScrapFlavorInfoList (sel
, &count
, flavor_info
);
5952 xfree (flavor_info
);
5955 if (flavor_info
== NULL
)
5958 for (rest
= Vselection_converter_alist
; CONSP (rest
); rest
= XCDR (rest
))
5960 ScrapFlavorType flavor_type
= 0;
5962 if (CONSP (XCAR (rest
))
5963 && (target
= XCAR (XCAR (rest
)),
5965 && (flavor_type
= get_flavor_type_from_symbol (target
, sel
)))
5967 result
= Fcons (target
, result
);
5968 #if TARGET_API_MAC_CARBON
5969 for (i
= 0; i
< count
; i
++)
5970 if (flavor_info
[i
].flavorType
== flavor_type
)
5972 flavor_info
[i
].flavorType
= 0;
5978 #if TARGET_API_MAC_CARBON
5981 for (i
= 0; i
< count
; i
++)
5982 if (flavor_info
[i
].flavorType
)
5984 type
= EndianU32_NtoB (flavor_info
[i
].flavorType
);
5985 strings
= Fcons (make_unibyte_string ((char *) &type
, 4), strings
);
5987 result
= nconc2 (result
, strings
);
5988 xfree (flavor_info
);
5996 /***********************************************************************
5998 ***********************************************************************/
6000 extern pascal OSErr mac_handle_apple_event
P_ ((const AppleEvent
*,
6001 AppleEvent
*, SInt32
));
6002 extern void cleanup_all_suspended_apple_events
P_ ((void));
6005 init_apple_event_handler ()
6010 /* Make sure we have Apple events before starting. */
6011 err
= Gestalt (gestaltAppleEventsAttr
, &result
);
6015 if (!(result
& (1 << gestaltAppleEventsPresent
)))
6018 err
= AEInstallEventHandler (typeWildCard
, typeWildCard
,
6019 #if TARGET_API_MAC_CARBON
6020 NewAEEventHandlerUPP (mac_handle_apple_event
),
6022 NewAEEventHandlerProc (mac_handle_apple_event
),
6028 atexit (cleanup_all_suspended_apple_events
);
6032 /***********************************************************************
6033 Drag and drop support
6034 ***********************************************************************/
6036 #if TARGET_API_MAC_CARBON
6037 extern Lisp_Object Vmac_dnd_known_types
;
6039 static pascal OSErr mac_do_track_drag
P_ ((DragTrackingMessage
, WindowRef
,
6041 static pascal OSErr mac_do_receive_drag
P_ ((WindowRef
, void *, DragRef
));
6042 static DragTrackingHandlerUPP mac_do_track_dragUPP
= NULL
;
6043 static DragReceiveHandlerUPP mac_do_receive_dragUPP
= NULL
;
6046 create_apple_event_from_drag_ref (drag
, num_types
, types
, result
)
6049 const FlavorType
*types
;
6058 err
= CountDragItems (drag
, &num_items
);
6061 err
= AECreateList (NULL
, 0, false, &items
);
6065 for (index
= 1; index
<= num_items
; index
++)
6068 DescType desc_type
= typeNull
;
6071 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6076 for (i
= 0; i
< num_types
; i
++)
6078 err
= GetFlavorDataSize (drag
, item
, types
[i
], &size
);
6081 buf
= xrealloc (buf
, size
);
6082 err
= GetFlavorData (drag
, item
, types
[i
], buf
, &size
, 0);
6086 desc_type
= types
[i
];
6091 err
= AEPutPtr (&items
, index
, desc_type
,
6092 desc_type
!= typeNull
? buf
: NULL
,
6093 desc_type
!= typeNull
? size
: 0);
6102 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
6104 err
= AEPutParamDesc (result
, keyDirectObject
, &items
);
6106 AEDisposeDesc (result
);
6109 AEDisposeDesc (&items
);
6115 mac_store_drag_event (window
, mouse_pos
, modifiers
, desc
)
6121 struct input_event buf
;
6125 buf
.kind
= DRAG_N_DROP_EVENT
;
6126 buf
.modifiers
= mac_to_emacs_modifiers (modifiers
, 0);
6127 buf
.timestamp
= TickCount () * (1000 / 60);
6128 XSETINT (buf
.x
, mouse_pos
.h
);
6129 XSETINT (buf
.y
, mouse_pos
.v
);
6130 XSETFRAME (buf
.frame_or_window
, mac_window_to_frame (window
));
6131 buf
.arg
= mac_aedesc_to_lisp (desc
);
6132 kbd_buffer_store_event (&buf
);
6136 mac_do_track_drag (message
, window
, refcon
, drag
)
6137 DragTrackingMessage message
;
6143 static int can_accept
;
6144 UInt16 num_items
, index
;
6146 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6147 return dragNotAcceptedErr
;
6151 case kDragTrackingEnterHandler
:
6152 err
= CountDragItems (drag
, &num_items
);
6156 for (index
= 1; index
<= num_items
; index
++)
6162 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6165 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6171 if (!(STRINGP (str
) && SBYTES (str
) == 4))
6173 type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6175 err
= GetFlavorFlags (drag
, item
, type
, &flags
);
6185 case kDragTrackingEnterWindow
:
6188 RgnHandle hilite_rgn
= NewRgn ();
6194 GetWindowPortBounds (window
, &r
);
6195 OffsetRect (&r
, -r
.left
, -r
.top
);
6196 RectRgn (hilite_rgn
, &r
);
6197 ShowDragHilite (drag
, hilite_rgn
, true);
6198 DisposeRgn (hilite_rgn
);
6200 SetThemeCursor (kThemeCopyArrowCursor
);
6204 case kDragTrackingInWindow
:
6207 case kDragTrackingLeaveWindow
:
6210 HideDragHilite (drag
);
6211 SetThemeCursor (kThemeArrowCursor
);
6215 case kDragTrackingLeaveHandler
:
6220 return dragNotAcceptedErr
;
6225 mac_do_receive_drag (window
, refcon
, drag
)
6232 Lisp_Object rest
, str
;
6234 AppleEvent apple_event
;
6238 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6239 return dragNotAcceptedErr
;
6242 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6245 if (STRINGP (str
) && SBYTES (str
) == 4)
6249 types
= xmalloc (sizeof (FlavorType
) * num_types
);
6251 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6254 if (STRINGP (str
) && SBYTES (str
) == 4)
6255 types
[i
++] = EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6258 err
= create_apple_event_from_drag_ref (drag
, num_types
, types
,
6263 err
= GetDragMouse (drag
, &mouse_pos
, NULL
);
6266 GlobalToLocal (&mouse_pos
);
6267 err
= GetDragModifiers (drag
, NULL
, NULL
, &modifiers
);
6271 UInt32 key_modifiers
= modifiers
;
6273 err
= AEPutParamPtr (&apple_event
, kEventParamKeyModifiers
,
6274 typeUInt32
, &key_modifiers
, sizeof (UInt32
));
6279 mac_store_drag_event (window
, mouse_pos
, 0, &apple_event
);
6280 AEDisposeDesc (&apple_event
);
6281 mac_wakeup_from_rne ();
6285 return dragNotAcceptedErr
;
6287 #endif /* TARGET_API_MAC_CARBON */
6290 install_drag_handler (window
)
6295 #if TARGET_API_MAC_CARBON
6296 if (mac_do_track_dragUPP
== NULL
)
6297 mac_do_track_dragUPP
= NewDragTrackingHandlerUPP (mac_do_track_drag
);
6298 if (mac_do_receive_dragUPP
== NULL
)
6299 mac_do_receive_dragUPP
= NewDragReceiveHandlerUPP (mac_do_receive_drag
);
6301 err
= InstallTrackingHandler (mac_do_track_dragUPP
, window
, NULL
);
6303 err
= InstallReceiveHandler (mac_do_receive_dragUPP
, window
, NULL
);
6310 remove_drag_handler (window
)
6313 #if TARGET_API_MAC_CARBON
6314 if (mac_do_track_dragUPP
)
6315 RemoveTrackingHandler (mac_do_track_dragUPP
, window
);
6316 if (mac_do_receive_dragUPP
)
6317 RemoveReceiveHandler (mac_do_receive_dragUPP
, window
);
6321 #if TARGET_API_MAC_CARBON
6322 /* Return default value for mac-dnd-known-types. */
6325 mac_dnd_default_known_types ()
6327 Lisp_Object result
= list4 (build_string ("hfs "), build_string ("utxt"),
6328 build_string ("TEXT"), build_string ("TIFF"));
6331 result
= Fcons (build_string ("furl"), result
);
6339 /***********************************************************************
6340 Services menu support
6341 ***********************************************************************/
6344 extern Lisp_Object Qservice
, Qpaste
, Qperform
;
6345 extern Lisp_Object Vmac_service_selection
;
6348 mac_store_service_event (event
)
6354 const EventParamName
*names
;
6355 const EventParamType
*types
;
6356 static const EventParamName names_pfm
[] =
6357 {kEventParamServiceMessageName
, kEventParamServiceUserData
};
6358 static const EventParamType types_pfm
[] =
6359 {typeCFStringRef
, typeCFStringRef
};
6361 switch (GetEventKind (event
))
6363 case kEventServicePaste
:
6370 case kEventServicePerform
:
6372 num_params
= sizeof (names_pfm
) / sizeof (names_pfm
[0]);
6381 err
= mac_store_event_ref_as_apple_event (0, 0, Qservice
, id_key
,
6389 copy_scrap_flavor_data (from_scrap
, to_scrap
, flavor_type
)
6390 ScrapRef from_scrap
, to_scrap
;
6391 ScrapFlavorType flavor_type
;
6394 Size size
, size_allocated
;
6397 err
= GetScrapFlavorSize (from_scrap
, flavor_type
, &size
);
6399 buf
= xmalloc (size
);
6402 size_allocated
= size
;
6403 err
= GetScrapFlavorData (from_scrap
, flavor_type
, &size
, buf
);
6409 else if (size_allocated
< size
)
6410 buf
= xrealloc (buf
, size
);
6420 err
= PutScrapFlavor (to_scrap
, flavor_type
, kScrapFlavorMaskNone
,
6430 mac_handle_service_event (call_ref
, event
, data
)
6431 EventHandlerCallRef call_ref
;
6435 OSStatus err
= noErr
;
6436 ScrapRef cur_scrap
, specific_scrap
;
6437 UInt32 event_kind
= GetEventKind (event
);
6438 CFMutableArrayRef copy_types
, paste_types
;
6441 ScrapFlavorType flavor_type
;
6443 /* Check if Vmac_service_selection is a valid selection that has a
6444 corresponding scrap. */
6445 if (!SYMBOLP (Vmac_service_selection
))
6446 err
= eventNotHandledErr
;
6448 err
= mac_get_selection_from_symbol (Vmac_service_selection
, 0, &cur_scrap
);
6449 if (!(err
== noErr
&& cur_scrap
))
6450 return eventNotHandledErr
;
6454 case kEventServiceGetTypes
:
6455 /* Set paste types. */
6456 err
= GetEventParameter (event
, kEventParamServicePasteTypes
,
6457 typeCFMutableArrayRef
, NULL
,
6458 sizeof (CFMutableArrayRef
), NULL
,
6463 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6465 if (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))
6467 get_flavor_type_from_symbol (XCAR (XCAR (rest
)), 0)))
6469 type
= CreateTypeStringWithOSType (flavor_type
);
6472 CFArrayAppendValue (paste_types
, type
);
6477 /* Set copy types. */
6478 err
= GetEventParameter (event
, kEventParamServiceCopyTypes
,
6479 typeCFMutableArrayRef
, NULL
,
6480 sizeof (CFMutableArrayRef
), NULL
,
6485 if (NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6488 goto copy_all_flavors
;
6490 case kEventServiceCopy
:
6491 err
= GetEventParameter (event
, kEventParamScrapRef
,
6493 sizeof (ScrapRef
), NULL
, &specific_scrap
);
6495 || NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6497 err
= eventNotHandledErr
;
6504 ScrapFlavorInfo
*flavor_info
= NULL
;
6505 ScrapFlavorFlags flags
;
6507 err
= GetScrapFlavorCount (cur_scrap
, &count
);
6509 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
6510 err
= GetScrapFlavorInfoList (cur_scrap
, &count
, flavor_info
);
6513 xfree (flavor_info
);
6516 if (flavor_info
== NULL
)
6519 for (i
= 0; i
< count
; i
++)
6521 flavor_type
= flavor_info
[i
].flavorType
;
6522 err
= GetScrapFlavorFlags (cur_scrap
, flavor_type
, &flags
);
6523 if (err
== noErr
&& !(flags
& kScrapFlavorMaskSenderOnly
))
6525 if (event_kind
== kEventServiceCopy
)
6526 err
= copy_scrap_flavor_data (cur_scrap
, specific_scrap
,
6528 else /* event_kind == kEventServiceGetTypes */
6530 type
= CreateTypeStringWithOSType (flavor_type
);
6533 CFArrayAppendValue (copy_types
, type
);
6539 xfree (flavor_info
);
6543 case kEventServicePaste
:
6544 case kEventServicePerform
:
6546 int data_exists_p
= 0;
6548 err
= GetEventParameter (event
, kEventParamScrapRef
, typeScrapRef
,
6549 NULL
, sizeof (ScrapRef
), NULL
,
6552 err
= mac_clear_selection (&cur_scrap
);
6554 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6557 if (! (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))))
6559 flavor_type
= get_flavor_type_from_symbol (XCAR (XCAR (rest
)),
6561 if (flavor_type
== 0)
6563 err
= copy_scrap_flavor_data (specific_scrap
, cur_scrap
,
6569 err
= eventNotHandledErr
;
6571 err
= mac_store_service_event (event
);
6577 err
= eventNotHandledErr
;
6582 install_service_handler ()
6584 static const EventTypeSpec specs
[] =
6585 {{kEventClassService
, kEventServiceGetTypes
},
6586 {kEventClassService
, kEventServiceCopy
},
6587 {kEventClassService
, kEventServicePaste
},
6588 {kEventClassService
, kEventServicePerform
}};
6590 return InstallApplicationEventHandler (NewEventHandlerUPP
6591 (mac_handle_service_event
),
6592 GetEventTypeCount (specs
),
6595 #endif /* MAC_OSX */
6598 /***********************************************************************
6600 ***********************************************************************/
6603 mac_toolbox_initialize ()
6605 any_help_event_p
= 0;
6610 init_apple_event_handler ();
6617 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6618 (do not change this comment) */