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 font
= FACE_FROM_ID (f
, glyph
->face_id
)->font
;
606 Fixed point_size
= Long2Fix (font
->mac_fontsize
);
607 short height
= row
->visible_height
;
608 short ascent
= row
->ascent
;
610 SetEventParameter (event
,
611 kEventParamTextInputReplyPointSize
,
612 typeFixed
, sizeof (Fixed
), &point_size
);
613 SetEventParameter (event
,
614 kEventParamTextInputReplyLineHeight
,
615 typeShortInteger
, sizeof (short), &height
);
616 SetEventParameter (event
,
617 kEventParamTextInputReplyLineAscent
,
618 typeShortInteger
, sizeof (short), &ascent
);
619 if (font
->mac_fontnum
!= -1)
625 err1
= FMGetFontFromFontFamilyInstance (font
->mac_fontnum
,
629 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
630 typeUInt32
, sizeof (UInt32
), &fm_font
);
633 long qd_font
= font
->mac_fontnum
;
635 SetEventParameter (event
, kEventParamTextInputReplyFont
,
636 typeLongInteger
, sizeof (long),
640 else if (font
->mac_style
)
645 err1
= ATSUGetAttribute (font
->mac_style
, kATSUFontTag
,
646 sizeof (ATSUFontID
), &font_id
,
649 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
650 typeUInt32
, sizeof (UInt32
), &font_id
);
658 err
= SetEventParameter (event
, kEventParamTextInputReplyPoint
,
659 typeQDPoint
, sizeof (Point
), &p
);
666 case kEventTextInputPosToOffset
:
669 Boolean leading_edge_p
= true;
673 enum window_part part
;
674 long region_class
= kTSMOutsideOfBody
, byte_offset
= 0;
676 err
= GetEventParameter (event
, kEventParamTextInputSendCurrentPoint
,
677 typeQDPoint
, NULL
, sizeof (Point
), NULL
,
682 GetEventParameter (event
, kEventParamTextInputReplyLeadingEdge
,
683 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
686 f
= mac_focus_frame (&one_mac_display_info
);
687 x
= point
.h
- (f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
688 y
= point
.v
- (f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
689 window
= window_from_coordinates (f
, x
, y
, &part
, 0, 0, 1);
690 if (WINDOWP (window
) && EQ (window
, f
->selected_window
))
695 /* Convert to window-relative pixel coordinates. */
696 w
= XWINDOW (window
);
697 frame_to_window_pixel_xy (w
, &x
, &y
);
699 /* Are we in a window whose display is up to date?
700 And verify the buffer's text has not changed. */
701 b
= XBUFFER (w
->buffer
);
703 && EQ (w
->window_end_valid
, w
->buffer
)
704 && XINT (w
->last_modified
) == BUF_MODIFF (b
)
705 && XINT (w
->last_overlay_modified
) == BUF_OVERLAY_MODIFF (b
))
707 int hpos
, vpos
, area
;
710 /* Find the glyph under X/Y. */
711 glyph
= x_y_to_hpos_vpos (w
, x
, y
, &hpos
, &vpos
, 0, 0, &area
);
713 if (glyph
!= NULL
&& area
== TEXT_AREA
)
715 byte_offset
= ((glyph
->charpos
- BUF_BEGV (b
))
717 region_class
= kTSMInsideOfBody
;
722 err
= SetEventParameter (event
, kEventParamTextInputReplyRegionClass
,
723 typeLongInteger
, sizeof (long),
726 err
= SetEventParameter (event
, kEventParamTextInputReplyTextOffset
,
727 typeLongInteger
, sizeof (long),
734 case kEventTextInputGetSelectedText
:
736 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
737 struct window
*w
= XWINDOW (f
->selected_window
);
738 struct buffer
*b
= XBUFFER (w
->buffer
);
741 UniChar
*characters
, c
;
743 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
744 /* Don't try to get buffer contents as the gap might be
748 mac_get_selected_range (w
, &sel_range
);
749 if (sel_range
.length
== 0)
751 Boolean leading_edge_p
;
753 err
= GetEventParameter (event
,
754 kEventParamTextInputReplyLeadingEdge
,
755 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
760 start
= BUF_BEGV (b
) + sel_range
.location
;
766 if (start
< BUF_BEGV (b
) || end
> BUF_ZV (b
))
771 start
= BUF_BEGV (b
) + sel_range
.location
;
772 end
= start
+ sel_range
.length
;
773 characters
= xmalloc (sel_range
.length
* sizeof (UniChar
));
776 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
, characters
))
777 err
= SetEventParameter (event
, kEventParamTextInputReplyText
,
779 sel_range
.length
* sizeof (UniChar
),
781 if (characters
!= &c
)
795 err
= mac_store_event_ref_as_apple_event (0, 0, Qtext_input
, id_key
,
801 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
802 static pascal OSStatus
803 mac_handle_document_access_event (next_handler
, event
, data
)
804 EventHandlerCallRef next_handler
;
808 OSStatus err
, result
;
809 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
811 result
= CallNextEventHandler (next_handler
, event
);
812 if (result
!= eventNotHandledErr
)
815 switch (GetEventKind (event
))
817 case kEventTSMDocumentAccessGetLength
:
819 CFIndex count
= mac_ax_number_of_characters (f
);
821 err
= SetEventParameter (event
, kEventParamTSMDocAccessCharacterCount
,
822 typeCFIndex
, sizeof (CFIndex
), &count
);
828 case kEventTSMDocumentAccessGetSelectedRange
:
832 mac_ax_selected_text_range (f
, &sel_range
);
833 err
= SetEventParameter (event
,
834 kEventParamTSMDocAccessReplyCharacterRange
,
835 typeCFRange
, sizeof (CFRange
), &sel_range
);
841 case kEventTSMDocumentAccessGetCharacters
:
843 struct buffer
*b
= XBUFFER (XWINDOW (f
->selected_window
)->buffer
);
848 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
849 /* Don't try to get buffer contents as the gap might be
853 err
= GetEventParameter (event
,
854 kEventParamTSMDocAccessSendCharacterRange
,
855 typeCFRange
, NULL
, sizeof (CFRange
), NULL
,
858 err
= GetEventParameter (event
,
859 kEventParamTSMDocAccessSendCharactersPtr
,
860 typePtr
, NULL
, sizeof (Ptr
), NULL
,
865 start
= BUF_BEGV (b
) + range
.location
;
866 end
= start
+ range
.length
;
867 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
,
868 (UniChar
*) characters
))
883 install_application_handler ()
885 OSStatus err
= noErr
;
889 static const EventTypeSpec specs
[] =
890 {{kEventClassKeyboard
, kEventRawKeyDown
},
891 {kEventClassKeyboard
, kEventRawKeyRepeat
},
892 {kEventClassKeyboard
, kEventRawKeyUp
}};
894 err
= InstallApplicationEventHandler (NewEventHandlerUPP
895 (mac_handle_keyboard_event
),
896 GetEventTypeCount (specs
),
902 static const EventTypeSpec specs
[] =
903 {{kEventClassCommand
, kEventCommandProcess
}};
905 err
= InstallApplicationEventHandler (NewEventHandlerUPP
906 (mac_handle_command_event
),
907 GetEventTypeCount (specs
),
913 static const EventTypeSpec specs
[] =
914 {{kEventClassMouse
, kEventMouseWheelMoved
}};
916 err
= InstallApplicationEventHandler (NewEventHandlerUPP
917 (mac_handle_mouse_event
),
918 GetEventTypeCount (specs
),
925 static const EventTypeSpec specs
[] =
926 {{kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
},
927 {kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
},
928 {kEventClassTextInput
, kEventTextInputOffsetToPos
},
930 {kEventClassTextInput
, kEventTextInputPosToOffset
},
931 {kEventClassTextInput
, kEventTextInputGetSelectedText
}
935 err
= InstallApplicationEventHandler (NewEventHandlerUPP
936 (mac_handle_text_input_event
),
937 GetEventTypeCount (specs
),
941 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
944 static const EventTypeSpec specs
[] =
945 {{kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetLength
},
946 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetSelectedRange
},
947 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetCharacters
}};
949 err
= InstallApplicationEventHandler (mac_handle_document_access_event
,
950 GetEventTypeCount (specs
),
957 err
= install_menu_target_item_handler ();
961 err
= install_service_handler ();
966 #endif /* TARGET_API_MAC_CARBON */
969 /************************************************************************
971 ************************************************************************/
973 #define DEFAULT_NUM_COLS 80
975 #define MIN_DOC_SIZE 64
976 #define MAX_DOC_SIZE 32767
979 static OSErr install_drag_handler
P_ ((WindowRef
));
980 static void remove_drag_handler
P_ ((WindowRef
));
983 static void mac_prepare_for_quickdraw
P_ ((struct frame
*));
986 extern void mac_handle_visibility_change
P_ ((struct frame
*));
987 extern void mac_handle_origin_change
P_ ((struct frame
*));
988 extern void mac_handle_size_change
P_ ((struct frame
*, int, int));
990 #if TARGET_API_MAC_CARBON
992 extern Lisp_Object Qwindow
;
993 extern Lisp_Object Qtoolbar_switch_mode
;
998 do_window_update (WindowRef win
)
1000 struct frame
*f
= mac_window_to_frame (win
);
1004 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1006 if (win
!= tip_window
)
1008 if (f
->async_visible
== 0)
1010 /* Update events may occur when a frame gets iconified. */
1012 f
->async_visible
= 1;
1013 f
->async_iconified
= 0;
1014 SET_FRAME_GARBAGED (f
);
1020 #if TARGET_API_MAC_CARBON
1021 RgnHandle region
= NewRgn ();
1023 GetPortVisibleRegion (GetWindowPort (win
), region
);
1024 GetRegionBounds (region
, &r
);
1025 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1027 mac_prepare_for_quickdraw (f
);
1029 UpdateControls (win
, region
);
1030 DisposeRgn (region
);
1032 r
= (*win
->visRgn
)->rgnBBox
;
1033 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1034 UpdateControls (win
, win
->visRgn
);
1043 is_emacs_window (WindowRef win
)
1045 Lisp_Object tail
, frame
;
1050 FOR_EACH_FRAME (tail
, frame
)
1051 if (FRAME_MAC_P (XFRAME (frame
)))
1052 if (FRAME_MAC_WINDOW (XFRAME (frame
)) == win
)
1058 /* Handle drags in size box. Based on code contributed by Ben
1059 Mesander and IM - Window Manager A. */
1062 do_grow_window (w
, e
)
1064 const EventRecord
*e
;
1067 int rows
, columns
, width
, height
;
1068 struct frame
*f
= mac_window_to_frame (w
);
1069 XSizeHints
*size_hints
= FRAME_SIZE_HINTS (f
);
1070 int min_width
= MIN_DOC_SIZE
, min_height
= MIN_DOC_SIZE
;
1071 #if TARGET_API_MAC_CARBON
1077 if (size_hints
->flags
& PMinSize
)
1079 min_width
= size_hints
->min_width
;
1080 min_height
= size_hints
->min_height
;
1082 SetRect (&limit_rect
, min_width
, min_height
, MAX_DOC_SIZE
, MAX_DOC_SIZE
);
1084 #if TARGET_API_MAC_CARBON
1085 if (!ResizeWindow (w
, e
->where
, &limit_rect
, &new_rect
))
1087 height
= new_rect
.bottom
- new_rect
.top
;
1088 width
= new_rect
.right
- new_rect
.left
;
1090 grow_size
= GrowWindow (w
, e
->where
, &limit_rect
);
1091 /* see if it really changed size */
1094 height
= HiWord (grow_size
);
1095 width
= LoWord (grow_size
);
1098 if (width
!= FRAME_PIXEL_WIDTH (f
)
1099 || height
!= FRAME_PIXEL_HEIGHT (f
))
1101 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1102 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1104 x_set_window_size (f
, 0, columns
, rows
);
1108 #if TARGET_API_MAC_CARBON
1110 mac_get_ideal_size (f
)
1113 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1114 WindowRef w
= FRAME_MAC_WINDOW (f
);
1117 int height
, width
, columns
, rows
;
1119 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1120 ideal_size
.v
= dpyinfo
->height
;
1121 IsWindowInStandardState (w
, &ideal_size
, &standard_rect
);
1122 /* Adjust the standard size according to character boundaries. */
1123 width
= standard_rect
.right
- standard_rect
.left
;
1124 height
= standard_rect
.bottom
- standard_rect
.top
;
1125 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1126 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1127 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, columns
);
1128 ideal_size
.v
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1133 static pascal OSStatus
1134 mac_handle_window_event (next_handler
, event
, data
)
1135 EventHandlerCallRef next_handler
;
1140 OSStatus err
, result
= eventNotHandledErr
;
1143 XSizeHints
*size_hints
;
1145 err
= GetEventParameter (event
, kEventParamDirectObject
, typeWindowRef
,
1146 NULL
, sizeof (WindowRef
), NULL
, &wp
);
1148 return eventNotHandledErr
;
1150 f
= mac_window_to_frame (wp
);
1151 switch (GetEventKind (event
))
1153 /* -- window refresh events -- */
1155 case kEventWindowUpdate
:
1156 result
= CallNextEventHandler (next_handler
, event
);
1157 if (result
!= eventNotHandledErr
)
1160 do_window_update (wp
);
1164 /* -- window state change events -- */
1166 case kEventWindowShowing
:
1167 size_hints
= FRAME_SIZE_HINTS (f
);
1168 if (!(size_hints
->flags
& (USPosition
| PPosition
)))
1170 struct frame
*sf
= SELECTED_FRAME ();
1172 if (!(FRAME_MAC_P (sf
) && sf
->async_visible
))
1173 RepositionWindow (wp
, NULL
, kWindowCenterOnMainScreen
);
1176 RepositionWindow (wp
, FRAME_MAC_WINDOW (sf
),
1177 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1178 kWindowCascadeStartAtParentWindowScreen
1180 kWindowCascadeOnParentWindowScreen
1184 /* This is a workaround. RepositionWindow fails to put
1185 a window at the cascading position when its parent
1186 window has a Carbon HIToolbar. */
1187 if ((f
->left_pos
== sf
->left_pos
1188 && f
->top_pos
== sf
->top_pos
)
1189 || (f
->left_pos
== sf
->left_pos
+ 10 * 2
1190 && f
->top_pos
== sf
->top_pos
+ 32 * 2))
1191 MoveWindowStructure (wp
, sf
->left_pos
+ 10, sf
->top_pos
+ 32);
1198 case kEventWindowHiding
:
1199 /* Before unmapping the window, update the WM_SIZE_HINTS
1200 property to claim that the current position of the window is
1201 user-specified, rather than program-specified, so that when
1202 the window is mapped again, it will be placed at the same
1203 location, without forcing the user to position it by hand
1204 again (they have already done that once for this window.) */
1205 x_wm_set_size_hint (f
, (long) 0, 1);
1209 case kEventWindowShown
:
1210 case kEventWindowHidden
:
1211 case kEventWindowCollapsed
:
1212 case kEventWindowExpanded
:
1213 mac_handle_visibility_change (f
);
1217 case kEventWindowBoundsChanging
:
1218 result
= CallNextEventHandler (next_handler
, event
);
1219 if (result
!= eventNotHandledErr
)
1222 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1223 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1227 size_hints
= FRAME_SIZE_HINTS (f
);
1228 if ((attributes
& kWindowBoundsChangeUserResize
)
1229 && ((size_hints
->flags
& (PResizeInc
| PBaseSize
| PMinSize
))
1230 == (PResizeInc
| PBaseSize
| PMinSize
)))
1235 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1236 typeQDRectangle
, NULL
, sizeof (Rect
),
1241 width
= bounds
.right
- bounds
.left
;
1242 height
= bounds
.bottom
- bounds
.top
;
1244 if (width
< size_hints
->min_width
)
1245 width
= size_hints
->min_width
;
1247 width
= size_hints
->base_width
1248 + (int) ((width
- size_hints
->base_width
)
1249 / (float) size_hints
->width_inc
+ .5)
1250 * size_hints
->width_inc
;
1252 if (height
< size_hints
->min_height
)
1253 height
= size_hints
->min_height
;
1255 height
= size_hints
->base_height
1256 + (int) ((height
- size_hints
->base_height
)
1257 / (float) size_hints
->height_inc
+ .5)
1258 * size_hints
->height_inc
;
1260 bounds
.right
= bounds
.left
+ width
;
1261 bounds
.bottom
= bounds
.top
+ height
;
1262 SetEventParameter (event
, kEventParamCurrentBounds
,
1263 typeQDRectangle
, sizeof (Rect
), &bounds
);
1268 case kEventWindowBoundsChanged
:
1269 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1270 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1274 if (attributes
& kWindowBoundsChangeSizeChanged
)
1278 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1279 typeQDRectangle
, NULL
, sizeof (Rect
),
1285 width
= bounds
.right
- bounds
.left
;
1286 height
= bounds
.bottom
- bounds
.top
;
1287 mac_handle_size_change (f
, width
, height
);
1288 mac_wakeup_from_rne ();
1292 if (attributes
& kWindowBoundsChangeOriginChanged
)
1293 mac_handle_origin_change (f
);
1298 /* -- window action events -- */
1300 case kEventWindowClose
:
1302 struct input_event buf
;
1305 buf
.kind
= DELETE_WINDOW_EVENT
;
1306 XSETFRAME (buf
.frame_or_window
, f
);
1308 kbd_buffer_store_event (&buf
);
1313 case kEventWindowGetIdealSize
:
1314 result
= CallNextEventHandler (next_handler
, event
);
1315 if (result
!= eventNotHandledErr
)
1319 Point ideal_size
= mac_get_ideal_size (f
);
1321 err
= SetEventParameter (event
, kEventParamDimensions
,
1322 typeQDPoint
, sizeof (Point
), &ideal_size
);
1329 case kEventWindowToolbarSwitchMode
:
1331 static const EventParamName names
[] = {kEventParamDirectObject
,
1332 kEventParamWindowMouseLocation
,
1333 kEventParamKeyModifiers
,
1334 kEventParamMouseButton
,
1335 kEventParamClickCount
,
1336 kEventParamMouseChord
};
1337 static const EventParamType types
[] = {typeWindowRef
,
1343 int num_params
= sizeof (names
) / sizeof (names
[0]);
1345 err
= mac_store_event_ref_as_apple_event (0, 0,
1347 Qtoolbar_switch_mode
,
1357 /* -- window focus events -- */
1359 case kEventWindowFocusAcquired
:
1360 err
= mac_tsm_resume ();
1365 case kEventWindowFocusRelinquish
:
1366 err
= mac_tsm_suspend ();
1380 /* Handle clicks in zoom box. Calculation of "standard state" based
1381 on code in IM - Window Manager A and code contributed by Ben
1382 Mesander. The standard state of an Emacs window is 80-characters
1383 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1386 do_zoom_window (WindowRef w
, int zoom_in_or_out
)
1388 Rect zoom_rect
, port_rect
;
1390 struct frame
*f
= mac_window_to_frame (w
);
1391 #if TARGET_API_MAC_CARBON
1392 Point ideal_size
= mac_get_ideal_size (f
);
1394 GetWindowBounds (w
, kWindowContentRgn
, &port_rect
);
1395 if (IsWindowInStandardState (w
, &ideal_size
, &zoom_rect
)
1396 && port_rect
.left
== zoom_rect
.left
1397 && port_rect
.top
== zoom_rect
.top
)
1398 zoom_in_or_out
= inZoomIn
;
1400 zoom_in_or_out
= inZoomOut
;
1403 mac_clear_area (f
, 0, 0, port_rect
.right
- port_rect
.left
,
1404 port_rect
.bottom
- port_rect
.top
);
1406 ZoomWindowIdeal (w
, zoom_in_or_out
, &ideal_size
);
1407 #else /* not TARGET_API_MAC_CARBON */
1410 int w_title_height
, rows
;
1411 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1413 GetPort (&save_port
);
1415 SetPortWindowPort (w
);
1417 /* Clear window to avoid flicker. */
1418 EraseRect (&(w
->portRect
));
1419 if (zoom_in_or_out
== inZoomOut
)
1421 SetPt (&top_left
, w
->portRect
.left
, w
->portRect
.top
);
1422 LocalToGlobal (&top_left
);
1424 /* calculate height of window's title bar */
1425 w_title_height
= top_left
.v
- 1
1426 - (**((WindowPeek
) w
)->strucRgn
).rgnBBox
.top
+ GetMBarHeight ();
1428 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1429 zoom_rect
= qd
.screenBits
.bounds
;
1430 zoom_rect
.top
+= w_title_height
;
1431 InsetRect (&zoom_rect
, 8, 4); /* not too tight */
1433 zoom_rect
.right
= zoom_rect
.left
1434 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1436 /* Adjust the standard size according to character boundaries. */
1437 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, zoom_rect
.bottom
- zoom_rect
.top
);
1439 zoom_rect
.top
+ FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1441 (**((WStateDataHandle
) ((WindowPeek
) w
)->dataHandle
)).stdState
1445 ZoomWindow (w
, zoom_in_or_out
, f
== mac_focus_frame (dpyinfo
));
1447 SetPort (save_port
);
1448 #endif /* not TARGET_API_MAC_CARBON */
1450 #if !TARGET_API_MAC_CARBON
1451 /* retrieve window size and update application values */
1452 port_rect
= w
->portRect
;
1453 height
= port_rect
.bottom
- port_rect
.top
;
1454 width
= port_rect
.right
- port_rect
.left
;
1456 mac_handle_size_change (f
, width
, height
);
1457 mac_handle_origin_change (f
);
1462 install_window_handler (window
)
1465 OSStatus err
= noErr
;
1467 #if TARGET_API_MAC_CARBON
1470 static const EventTypeSpec specs
[] =
1472 /* -- window refresh events -- */
1473 {kEventClassWindow
, kEventWindowUpdate
},
1474 /* -- window state change events -- */
1475 {kEventClassWindow
, kEventWindowShowing
},
1476 {kEventClassWindow
, kEventWindowHiding
},
1477 {kEventClassWindow
, kEventWindowShown
},
1478 {kEventClassWindow
, kEventWindowHidden
},
1479 {kEventClassWindow
, kEventWindowCollapsed
},
1480 {kEventClassWindow
, kEventWindowExpanded
},
1481 {kEventClassWindow
, kEventWindowBoundsChanging
},
1482 {kEventClassWindow
, kEventWindowBoundsChanged
},
1483 /* -- window action events -- */
1484 {kEventClassWindow
, kEventWindowClose
},
1485 {kEventClassWindow
, kEventWindowGetIdealSize
},
1487 {kEventClassWindow
, kEventWindowToolbarSwitchMode
},
1490 /* -- window focus events -- */
1491 {kEventClassWindow
, kEventWindowFocusAcquired
},
1492 {kEventClassWindow
, kEventWindowFocusRelinquish
},
1495 static EventHandlerUPP handle_window_eventUPP
= NULL
;
1497 if (handle_window_eventUPP
== NULL
)
1498 handle_window_eventUPP
= NewEventHandlerUPP (mac_handle_window_event
);
1500 err
= InstallWindowEventHandler (window
, handle_window_eventUPP
,
1501 GetEventTypeCount (specs
),
1507 err
= install_drag_handler (window
);
1513 remove_window_handler (window
)
1516 remove_drag_handler (window
);
1520 mac_get_window_bounds (f
, inner
, outer
)
1522 Rect
*inner
, *outer
;
1524 #if TARGET_API_MAC_CARBON
1525 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, inner
);
1526 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, outer
);
1527 #else /* not TARGET_API_MAC_CARBON */
1528 RgnHandle region
= NewRgn ();
1530 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, region
);
1531 *inner
= (*region
)->rgnBBox
;
1532 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, region
);
1533 *outer
= (*region
)->rgnBBox
;
1534 DisposeRgn (region
);
1535 #endif /* not TARGET_API_MAC_CARBON */
1539 mac_get_frame_bounds (f
, r
)
1543 #if TARGET_API_MAC_CARBON
1544 return GetWindowPortBounds (FRAME_MAC_WINDOW (f
), r
);
1546 *r
= FRAME_MAC_WINDOW (f
)->portRect
;
1553 mac_get_frame_mouse (f
, point
)
1557 #if TARGET_API_MAC_CARBON
1558 GetGlobalMouse (point
);
1559 point
->h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1560 point
->v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1562 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1568 mac_convert_frame_point_to_global (f
, x
, y
)
1572 *x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1573 *y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1576 #if TARGET_API_MAC_CARBON
1578 mac_update_proxy_icon (f
)
1582 Lisp_Object file_name
=
1583 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
)->filename
;
1584 Window w
= FRAME_MAC_WINDOW (f
);
1585 AliasHandle alias
= NULL
;
1587 err
= GetWindowProxyAlias (w
, &alias
);
1588 if (err
== errWindowDoesNotHaveProxy
&& !STRINGP (file_name
))
1591 if (STRINGP (file_name
))
1595 FSRef fref
, fref_proxy
;
1597 FSSpec fss
, fss_proxy
;
1600 Lisp_Object encoded_file_name
= ENCODE_FILE (file_name
);
1603 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1604 SBYTES (encoded_file_name
), typeFSRef
, &desc
);
1606 SetPortWindowPort (w
);
1607 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1608 SBYTES (encoded_file_name
), typeFSS
, &desc
);
1613 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
1615 err
= AEGetDescData (&desc
, &fss
, sizeof (FSSpec
));
1617 AEDisposeDesc (&desc
);
1623 /* (FS)ResolveAlias never sets `changed' to true if
1624 `alias' is minimal. */
1626 err
= FSResolveAlias (NULL
, alias
, &fref_proxy
, &changed
);
1628 err
= FSCompareFSRefs (&fref
, &fref_proxy
);
1630 err
= ResolveAlias (NULL
, alias
, &fss_proxy
, &changed
);
1632 err
= !(fss
.vRefNum
== fss_proxy
.vRefNum
1633 && fss
.parID
== fss_proxy
.parID
1634 && EqualString (fss
.name
, fss_proxy
.name
,
1638 if (err
!= noErr
|| alias
== NULL
)
1641 DisposeHandle ((Handle
) alias
);
1643 err
= FSNewAliasMinimal (&fref
, &alias
);
1645 err
= NewAliasMinimal (&fss
, &alias
);
1652 err
= SetWindowProxyAlias (w
, alias
);
1656 DisposeHandle ((Handle
) alias
);
1658 if (err
!= noErr
|| !STRINGP (file_name
))
1659 RemoveWindowProxy (w
);
1663 /* Mac replacement for XSetWindowBackground. */
1666 mac_set_frame_window_background (f
, color
)
1668 unsigned long color
;
1670 WindowRef w
= FRAME_MAC_WINDOW (f
);
1671 #if !TARGET_API_MAC_CARBON
1672 AuxWinHandle aw_handle
;
1673 CTabHandle ctab_handle
;
1674 ColorSpecPtr ct_table
;
1679 bg_color
.red
= RED16_FROM_ULONG (color
);
1680 bg_color
.green
= GREEN16_FROM_ULONG (color
);
1681 bg_color
.blue
= BLUE16_FROM_ULONG (color
);
1683 #if TARGET_API_MAC_CARBON
1684 SetWindowContentColor (w
, &bg_color
);
1686 if (GetAuxWin (w
, &aw_handle
))
1688 ctab_handle
= (*aw_handle
)->awCTable
;
1689 HandToHand ((Handle
*) &ctab_handle
);
1690 ct_table
= (*ctab_handle
)->ctTable
;
1691 ct_size
= (*ctab_handle
)->ctSize
;
1692 while (ct_size
> -1)
1694 if (ct_table
->value
== 0)
1696 ct_table
->rgb
= bg_color
;
1697 CTabChanged (ctab_handle
);
1698 SetWinColor (w
, (WCTabHandle
) ctab_handle
);
1706 /* Flush display of frame F, or of all frames if F is null. */
1712 #if TARGET_API_MAC_CARBON
1715 mac_prepare_for_quickdraw (f
);
1718 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f
)), NULL
);
1720 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL
);
1727 mac_flush_display_optional (f
)
1731 mac_prepare_for_quickdraw (f
);
1737 mac_update_begin (f
)
1740 #if TARGET_API_MAC_CARBON
1741 /* During update of a frame, availability of input events is
1742 periodically checked with ReceiveNextEvent if
1743 redisplay-dont-pause is nil. That normally flushes window buffer
1744 changes for every check, and thus screen update looks waving even
1745 if no input is available. So we disable screen updates during
1746 update of a frame. */
1747 DisableScreenUpdates ();
1755 #if TARGET_API_MAC_CARBON
1756 EnableScreenUpdates ();
1761 mac_frame_up_to_date (f
)
1764 /* Nothing to do. */
1768 mac_create_frame_window (f
, tooltip_p
)
1773 #if TARGET_API_MAC_CARBON
1774 WindowClass window_class
;
1775 WindowAttributes attributes
;
1779 Boolean go_away_flag
;
1784 SetRect (&r
, f
->left_pos
, f
->top_pos
,
1785 f
->left_pos
+ FRAME_PIXEL_WIDTH (f
),
1786 f
->top_pos
+ FRAME_PIXEL_HEIGHT (f
));
1787 #if TARGET_API_MAC_CARBON
1788 window_class
= kDocumentWindowClass
;
1789 attributes
= (kWindowStandardDocumentAttributes
1791 | kWindowToolbarButtonAttribute
1795 proc_id
= zoomDocProc
;
1796 behind
= (WindowRef
) -1;
1797 go_away_flag
= true;
1802 SetRect (&r
, 0, 0, 1, 1);
1803 #if TARGET_API_MAC_CARBON
1804 window_class
= kHelpWindowClass
;
1805 attributes
= (kWindowNoUpdatesAttribute
1806 | kWindowNoActivatesAttribute
1807 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1808 | kWindowIgnoreClicksAttribute
1812 proc_id
= plainDBox
;
1814 go_away_flag
= false;
1818 #if TARGET_API_MAC_CARBON
1819 CreateNewWindow (window_class
, attributes
, &r
, &FRAME_MAC_WINDOW (f
));
1820 if (FRAME_MAC_WINDOW (f
))
1822 SetWRefCon (FRAME_MAC_WINDOW (f
), (long) f
->output_data
.mac
);
1824 if (install_window_handler (FRAME_MAC_WINDOW (f
)) != noErr
)
1826 DisposeWindow (FRAME_MAC_WINDOW (f
));
1827 FRAME_MAC_WINDOW (f
) = NULL
;
1830 #else /* !TARGET_API_MAC_CARBON */
1831 FRAME_MAC_WINDOW (f
)
1832 = NewCWindow (NULL
, &r
, "\p", false, proc_id
, behind
, go_away_flag
,
1833 (long) f
->output_data
.mac
);
1834 #endif /* !TARGET_API_MAC_CARBON */
1835 /* so that update events can find this mac_output struct */
1836 f
->output_data
.mac
->mFP
= f
; /* point back to emacs frame */
1840 if (FRAME_MAC_WINDOW (f
))
1842 ControlRef root_control
;
1844 if (CreateRootControl (FRAME_MAC_WINDOW (f
), &root_control
) != noErr
)
1846 DisposeWindow (FRAME_MAC_WINDOW (f
));
1847 FRAME_MAC_WINDOW (f
) = NULL
;
1853 /* Dispose of the Mac window of the frame F. */
1856 mac_dispose_frame_window (f
)
1859 WindowRef window
= FRAME_MAC_WINDOW (f
);
1861 if (window
!= tip_window
)
1862 remove_window_handler (window
);
1865 mac_prepare_for_quickdraw (f
);
1867 DisposeWindow (window
);
1871 /************************************************************************
1873 ************************************************************************/
1876 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1879 mac_begin_cg_clip (f
, gc
)
1883 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1887 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)), &context
);
1888 FRAME_CG_CONTEXT (f
) = context
;
1891 CGContextSaveGState (context
);
1892 CGContextTranslateCTM (context
, 0, FRAME_PIXEL_HEIGHT (f
));
1893 CGContextScaleCTM (context
, 1, -1);
1894 if (gc
&& gc
->n_clip_rects
)
1895 CGContextClipToRects (context
, gc
->clip_rects
, gc
->n_clip_rects
);
1904 CGContextRestoreGState (FRAME_CG_CONTEXT (f
));
1908 mac_prepare_for_quickdraw (f
)
1913 Lisp_Object rest
, frame
;
1914 FOR_EACH_FRAME (rest
, frame
)
1915 if (FRAME_MAC_P (XFRAME (frame
)))
1916 mac_prepare_for_quickdraw (XFRAME (frame
));
1920 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1924 CGContextSynchronize (context
);
1925 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)),
1926 &FRAME_CG_CONTEXT (f
));
1932 static RgnHandle saved_port_clip_region
= NULL
;
1935 mac_begin_clip (f
, gc
)
1939 static RgnHandle new_region
= NULL
;
1941 if (saved_port_clip_region
== NULL
)
1942 saved_port_clip_region
= NewRgn ();
1943 if (new_region
== NULL
)
1944 new_region
= NewRgn ();
1947 mac_prepare_for_quickdraw (f
);
1949 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1951 if (gc
&& gc
->n_clip_rects
)
1953 GetClip (saved_port_clip_region
);
1954 SectRgn (saved_port_clip_region
, gc
->clip_region
, new_region
);
1955 SetClip (new_region
);
1960 mac_end_clip (f
, gc
)
1964 if (gc
&& gc
->n_clip_rects
)
1965 SetClip (saved_port_clip_region
);
1968 #if TARGET_API_MAC_CARBON
1969 /* Mac replacement for XCopyArea: used only for scrolling. */
1972 mac_scroll_area (f
, gc
, src_x
, src_y
, width
, height
, dest_x
, dest_y
)
1976 unsigned int width
, height
;
1980 RgnHandle dummy
= NewRgn (); /* For avoiding update events. */
1982 SetRect (&src_r
, src_x
, src_y
, src_x
+ width
, src_y
+ height
);
1984 mac_prepare_for_quickdraw (f
);
1986 ScrollWindowRect (FRAME_MAC_WINDOW (f
),
1987 &src_r
, dest_x
- src_x
, dest_y
- src_y
,
1988 kScrollWindowNoOptions
, dummy
);
1994 /************************************************************************
1996 ************************************************************************/
1998 extern struct scroll_bar
*tracked_scroll_bar
;
1999 extern Lisp_Object last_mouse_scroll_bar
;
2000 extern Time last_mouse_movement_time
;
2002 static void x_scroll_bar_handle_click
P_ ((struct scroll_bar
*,
2004 const EventRecord
*,
2005 struct input_event
*));
2006 #ifndef USE_TOOLKIT_SCROLL_BARS
2007 static void x_scroll_bar_note_movement
P_ ((struct scroll_bar
*, int, Time
));
2008 #else /* USE_TOOLKIT_SCROLL_BARS */
2009 static void x_scroll_bar_handle_press
P_ ((struct scroll_bar
*,
2010 ControlPartCode
, Point
,
2011 struct input_event
*));
2012 static void x_scroll_bar_handle_release
P_ ((struct scroll_bar
*,
2013 struct input_event
*));
2014 static void x_scroll_bar_handle_drag
P_ ((WindowRef
, struct scroll_bar
*,
2015 Point
, struct input_event
*));
2016 static pascal void scroll_bar_timer_callback
P_ ((EventLoopTimerRef
, void *));
2017 static OSStatus install_scroll_bar_timer
P_ ((void));
2018 static OSStatus set_scroll_bar_timer
P_ ((EventTimerInterval
));
2019 static int control_part_code_to_scroll_bar_part
P_ ((ControlPartCode
));
2020 static void construct_scroll_bar_click
P_ ((struct scroll_bar
*, int,
2021 struct input_event
*));
2022 static OSStatus get_control_part_bounds
P_ ((ControlRef
, ControlPartCode
,
2024 static void update_scroll_bar_track_info
P_ ((struct scroll_bar
*));
2026 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2028 static int last_scroll_bar_part
;
2030 static EventLoopTimerRef scroll_bar_timer
;
2032 static int scroll_bar_timer_event_posted_p
;
2034 #define SCROLL_BAR_FIRST_DELAY 0.5
2035 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2038 scroll_bar_timer_callback (timer
, data
)
2039 EventLoopTimerRef timer
;
2044 err
= mac_post_mouse_moved_event ();
2046 scroll_bar_timer_event_posted_p
= 1;
2050 install_scroll_bar_timer ()
2052 static EventLoopTimerUPP scroll_bar_timer_callbackUPP
= NULL
;
2054 if (scroll_bar_timer_callbackUPP
== NULL
)
2055 scroll_bar_timer_callbackUPP
=
2056 NewEventLoopTimerUPP (scroll_bar_timer_callback
);
2058 if (scroll_bar_timer
== NULL
)
2059 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2060 kEventDurationForever as delays. */
2062 InstallEventLoopTimer (GetCurrentEventLoop (),
2063 kEventDurationForever
, kEventDurationForever
,
2064 scroll_bar_timer_callbackUPP
, NULL
,
2069 set_scroll_bar_timer (delay
)
2070 EventTimerInterval delay
;
2072 if (scroll_bar_timer
== NULL
)
2073 install_scroll_bar_timer ();
2075 scroll_bar_timer_event_posted_p
= 0;
2077 return SetEventLoopTimerNextFireTime (scroll_bar_timer
, delay
);
2081 control_part_code_to_scroll_bar_part (part_code
)
2082 ControlPartCode part_code
;
2086 case kControlUpButtonPart
: return scroll_bar_up_arrow
;
2087 case kControlDownButtonPart
: return scroll_bar_down_arrow
;
2088 case kControlPageUpPart
: return scroll_bar_above_handle
;
2089 case kControlPageDownPart
: return scroll_bar_below_handle
;
2090 case kControlIndicatorPart
: return scroll_bar_handle
;
2097 construct_scroll_bar_click (bar
, part
, bufp
)
2098 struct scroll_bar
*bar
;
2100 struct input_event
*bufp
;
2102 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2103 bufp
->frame_or_window
= bar
->window
;
2107 XSETINT (bufp
->x
, 0);
2108 XSETINT (bufp
->y
, 0);
2109 bufp
->modifiers
= 0;
2113 get_control_part_bounds (ch
, part_code
, rect
)
2115 ControlPartCode part_code
;
2118 RgnHandle region
= NewRgn ();
2121 err
= GetControlRegion (ch
, part_code
, region
);
2123 GetRegionBounds (region
, rect
);
2124 DisposeRgn (region
);
2130 x_scroll_bar_handle_press (bar
, part_code
, mouse_pos
, bufp
)
2131 struct scroll_bar
*bar
;
2132 ControlPartCode part_code
;
2134 struct input_event
*bufp
;
2136 int part
= control_part_code_to_scroll_bar_part (part_code
);
2141 if (part
!= scroll_bar_handle
)
2143 construct_scroll_bar_click (bar
, part
, bufp
);
2144 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2145 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY
);
2146 bar
->dragging
= Qnil
;
2152 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2153 kControlIndicatorPart
, &r
);
2154 XSETINT (bar
->dragging
, - (mouse_pos
.v
- r
.top
) - 1);
2157 last_scroll_bar_part
= part
;
2158 tracked_scroll_bar
= bar
;
2162 x_scroll_bar_handle_release (bar
, bufp
)
2163 struct scroll_bar
*bar
;
2164 struct input_event
*bufp
;
2166 if (last_scroll_bar_part
!= scroll_bar_handle
2167 || (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) >= 0))
2168 construct_scroll_bar_click (bar
, scroll_bar_end_scroll
, bufp
);
2170 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2171 set_scroll_bar_timer (kEventDurationForever
);
2173 last_scroll_bar_part
= -1;
2174 bar
->dragging
= Qnil
;
2175 tracked_scroll_bar
= NULL
;
2179 x_scroll_bar_handle_drag (win
, bar
, mouse_pos
, bufp
)
2181 struct scroll_bar
*bar
;
2183 struct input_event
*bufp
;
2185 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2187 if (last_scroll_bar_part
== scroll_bar_handle
)
2192 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2193 kControlIndicatorPart
, &r
);
2195 if (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) < 0)
2196 XSETINT (bar
->dragging
, - (XINT (bar
->dragging
) + 1));
2198 top
= mouse_pos
.v
- XINT (bar
->dragging
) - XINT (bar
->track_top
);
2199 top_range
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2203 if (top
> top_range
)
2206 construct_scroll_bar_click (bar
, scroll_bar_handle
, bufp
);
2207 XSETINT (bufp
->x
, top
);
2208 XSETINT (bufp
->y
, top_range
);
2212 ControlPartCode part_code
;
2213 int unhilite_p
= 0, part
;
2215 if (ch
!= FindControlUnderMouse (mouse_pos
, win
, &part_code
))
2219 part
= control_part_code_to_scroll_bar_part (part_code
);
2221 switch (last_scroll_bar_part
)
2223 case scroll_bar_above_handle
:
2224 case scroll_bar_below_handle
:
2225 if (part
!= scroll_bar_above_handle
2226 && part
!= scroll_bar_below_handle
)
2230 case scroll_bar_up_arrow
:
2231 case scroll_bar_down_arrow
:
2232 if (part
!= scroll_bar_up_arrow
2233 && part
!= scroll_bar_down_arrow
)
2240 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2241 else if (part
!= last_scroll_bar_part
2242 || scroll_bar_timer_event_posted_p
)
2244 construct_scroll_bar_click (bar
, part
, bufp
);
2245 last_scroll_bar_part
= part
;
2246 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2247 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY
);
2252 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2253 the scroll bar BAR. This function should be called when the bounds
2254 of the scroll bar is changed. */
2257 update_scroll_bar_track_info (bar
)
2258 struct scroll_bar
*bar
;
2260 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2263 GetControlBounds (ch
, &r0
);
2265 if (r0
.right
- r0
.left
>= r0
.bottom
- r0
.top
2267 || r0
.right
- r0
.left
< MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2271 XSETINT (bar
->track_top
, 0);
2272 XSETINT (bar
->track_height
, 0);
2273 XSETINT (bar
->min_handle
, 0);
2279 SetControl32BitMinimum (ch
, 0);
2280 SetControl32BitMaximum (ch
, 1 << 30);
2281 SetControlViewSize (ch
, 1);
2283 /* Move the scroll bar thumb to the top. */
2284 SetControl32BitValue (ch
, 0);
2285 get_control_part_bounds (ch
, kControlIndicatorPart
, &r0
);
2287 /* Move the scroll bar thumb to the bottom. */
2288 SetControl32BitValue (ch
, 1 << 30);
2289 get_control_part_bounds (ch
, kControlIndicatorPart
, &r1
);
2291 UnionRect (&r0
, &r1
, &r0
);
2292 XSETINT (bar
->track_top
, r0
.top
);
2293 XSETINT (bar
->track_height
, r0
.bottom
- r0
.top
);
2294 XSETINT (bar
->min_handle
, r1
.bottom
- r1
.top
);
2296 /* Don't show the scroll bar if its height is not enough to
2297 display the scroll bar thumb. */
2298 if (r0
.bottom
- r0
.top
> 0)
2305 /* Set the thumb size and position of scroll bar BAR. We are currently
2306 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2309 x_set_toolkit_scroll_bar_thumb (bar
, portion
, position
, whole
)
2310 struct scroll_bar
*bar
;
2311 int portion
, position
, whole
;
2313 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2314 int value
, viewsize
, maximum
;
2316 if (XINT (bar
->track_height
) == 0)
2319 if (whole
<= portion
)
2320 value
= 0, viewsize
= 1, maximum
= 0;
2325 maximum
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2326 scale
= (float) maximum
/ (whole
- portion
);
2327 value
= position
* scale
+ 0.5f
;
2328 viewsize
= (int) (portion
* scale
+ 0.5f
) + XINT (bar
->min_handle
);
2333 if (GetControlViewSize (ch
) != viewsize
2334 || GetControl32BitValue (ch
) != value
2335 || GetControl32BitMaximum (ch
) != maximum
)
2337 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2338 SetControlVisibility (ch
, false, false);
2340 SetControl32BitMaximum (ch
, maximum
);
2341 SetControl32BitValue (ch
, value
);
2342 SetControlViewSize (ch
, viewsize
);
2344 SetControlVisibility (ch
, true, true);
2350 #endif /* USE_TOOLKIT_SCROLL_BARS */
2352 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2353 the initial geometry and visibility, respectively. The created
2354 control is stored in some members of BAR. */
2357 mac_create_scroll_bar (bar
, bounds
, visible
)
2358 struct scroll_bar
*bar
;
2362 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2366 mac_prepare_for_quickdraw (f
);
2368 ch
= NewControl (FRAME_MAC_WINDOW (f
), bounds
, "\p", visible
, 0, 0, 0,
2369 #if TARGET_API_MAC_CARBON
2370 kControlScrollBarProc
,
2375 SET_SCROLL_BAR_CONTROL_REF (bar
, ch
);
2377 XSETINT (bar
->start
, 0);
2378 XSETINT (bar
->end
, 0);
2379 bar
->dragging
= Qnil
;
2381 #ifdef USE_TOOLKIT_SCROLL_BARS
2382 update_scroll_bar_track_info (bar
);
2386 /* Dispose of the scroll bar control stored in some members of
2390 mac_dispose_scroll_bar (bar
)
2391 struct scroll_bar
*bar
;
2394 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2396 mac_prepare_for_quickdraw (f
);
2398 DisposeControl (SCROLL_BAR_CONTROL_REF (bar
));
2401 /* Set bounds of the scroll bar BAR to BOUNDS. */
2404 mac_set_scroll_bar_bounds (bar
, bounds
)
2405 struct scroll_bar
*bar
;
2408 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2409 SInt16 width
, height
;
2411 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2413 mac_prepare_for_quickdraw (f
);
2416 width
= bounds
->right
- bounds
->left
;
2417 height
= bounds
->bottom
- bounds
->top
;
2419 MoveControl (ch
, bounds
->left
, bounds
->top
);
2420 SizeControl (ch
, width
, height
);
2421 #ifdef USE_TOOLKIT_SCROLL_BARS
2422 update_scroll_bar_track_info (bar
);
2429 /* Draw the scroll bar BAR. */
2432 mac_redraw_scroll_bar (bar
)
2433 struct scroll_bar
*bar
;
2436 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2438 mac_prepare_for_quickdraw (f
);
2440 Draw1Control (SCROLL_BAR_CONTROL_REF (bar
));
2443 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2444 is set to something other than NO_EVENT, it is enqueued.
2446 This may be called from a signal handler, so we have to ignore GC
2450 x_scroll_bar_handle_click (bar
, part_code
, er
, bufp
)
2451 struct scroll_bar
*bar
;
2452 ControlPartCode part_code
;
2453 const EventRecord
*er
;
2454 struct input_event
*bufp
;
2456 int win_y
, top_range
;
2458 if (! GC_WINDOWP (bar
->window
))
2461 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2462 bufp
->frame_or_window
= bar
->window
;
2465 bar
->dragging
= Qnil
;
2469 case kControlUpButtonPart
:
2470 bufp
->part
= scroll_bar_up_arrow
;
2472 case kControlDownButtonPart
:
2473 bufp
->part
= scroll_bar_down_arrow
;
2475 case kControlPageUpPart
:
2476 bufp
->part
= scroll_bar_above_handle
;
2478 case kControlPageDownPart
:
2479 bufp
->part
= scroll_bar_below_handle
;
2481 #if TARGET_API_MAC_CARBON
2484 case kControlIndicatorPart
:
2486 if (er
->what
== mouseDown
)
2487 bar
->dragging
= make_number (0);
2488 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2489 bufp
->part
= scroll_bar_handle
;
2493 win_y
= XINT (bufp
->y
) - XINT (bar
->top
);
2494 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar
->height
));
2496 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2500 if (! NILP (bar
->dragging
))
2501 win_y
-= XINT (bar
->dragging
);
2505 if (win_y
> top_range
)
2508 XSETINT (bufp
->x
, win_y
);
2509 XSETINT (bufp
->y
, top_range
);
2512 /* Return information to the user about the current position of the mouse
2513 on the scroll bar. */
2516 x_scroll_bar_report_motion (fp
, bar_window
, part
, x
, y
, time
)
2518 Lisp_Object
*bar_window
;
2519 enum scroll_bar_part
*part
;
2521 unsigned long *time
;
2523 struct scroll_bar
*bar
= XSCROLL_BAR (last_mouse_scroll_bar
);
2524 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2525 #if TARGET_API_MAC_CARBON
2526 WindowRef wp
= GetControlOwner (ch
);
2528 WindowRef wp
= (*ch
)->contrlOwner
;
2531 struct frame
*f
= mac_window_to_frame (wp
);
2532 int win_y
, top_range
;
2534 #if TARGET_API_MAC_CARBON
2535 GetGlobalMouse (&mouse_pos
);
2536 mouse_pos
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
2537 mouse_pos
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2539 SetPortWindowPort (wp
);
2540 GetMouse (&mouse_pos
);
2543 win_y
= mouse_pos
.v
- XINT (bar
->top
);
2544 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2546 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2550 if (! NILP (bar
->dragging
))
2551 win_y
-= XINT (bar
->dragging
);
2555 if (win_y
> top_range
)
2559 *bar_window
= bar
->window
;
2561 if (! NILP (bar
->dragging
))
2562 *part
= scroll_bar_handle
;
2563 else if (win_y
< XINT (bar
->start
))
2564 *part
= scroll_bar_above_handle
;
2565 else if (win_y
< XINT (bar
->end
) + VERTICAL_SCROLL_BAR_MIN_HANDLE
)
2566 *part
= scroll_bar_handle
;
2568 *part
= scroll_bar_below_handle
;
2570 XSETINT (*x
, win_y
);
2571 XSETINT (*y
, top_range
);
2574 last_mouse_scroll_bar
= Qnil
;
2576 *time
= last_mouse_movement_time
;
2579 #ifndef USE_TOOLKIT_SCROLL_BARS
2580 /* Draw BAR's handle in the proper position.
2582 If the handle is already drawn from START to END, don't bother
2583 redrawing it, unless REBUILD is non-zero; in that case, always
2584 redraw it. (REBUILD is handy for drawing the handle after expose
2587 Normally, we want to constrain the start and end of the handle to
2588 fit inside its rectangle, but if the user is dragging the scroll
2589 bar handle, we want to let them drag it down all the way, so that
2590 the bar's top is as far down as it goes; otherwise, there's no way
2591 to move to the very end of the buffer. */
2594 x_scroll_bar_set_handle (bar
, start
, end
, rebuild
)
2595 struct scroll_bar
*bar
;
2599 int dragging
= ! NILP (bar
->dragging
);
2600 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2601 FRAME_PTR f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2602 int top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2603 int length
= end
- start
;
2605 /* If the display is already accurate, do nothing. */
2607 && start
== XINT (bar
->start
)
2608 && end
== XINT (bar
->end
))
2613 /* Make sure the values are reasonable, and try to preserve the
2614 distance between start and end. */
2617 else if (start
> top_range
)
2619 end
= start
+ length
;
2623 else if (end
> top_range
&& ! dragging
)
2626 /* Store the adjusted setting in the scroll bar. */
2627 XSETINT (bar
->start
, start
);
2628 XSETINT (bar
->end
, end
);
2630 /* Clip the end position, just for display. */
2631 if (end
> top_range
)
2634 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2635 top positions, to make sure the handle is always at least that
2636 many pixels tall. */
2637 end
+= VERTICAL_SCROLL_BAR_MIN_HANDLE
;
2639 SetControlMinimum (ch
, 0);
2640 /* Don't inadvertently activate deactivated scroll bars */
2641 if (GetControlMaximum (ch
) != -1)
2642 SetControlMaximum (ch
, top_range
+ VERTICAL_SCROLL_BAR_MIN_HANDLE
2644 SetControlValue (ch
, start
);
2645 #if TARGET_API_MAC_CARBON
2646 SetControlViewSize (ch
, end
- start
);
2652 /* Handle some mouse motion while someone is dragging the scroll bar.
2654 This may be called from a signal handler, so we have to ignore GC
2658 x_scroll_bar_note_movement (bar
, y_pos
, t
)
2659 struct scroll_bar
*bar
;
2663 FRAME_PTR f
= XFRAME (XWINDOW (bar
->window
)->frame
);
2665 last_mouse_movement_time
= t
;
2668 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2670 /* If we're dragging the bar, display it. */
2671 if (! GC_NILP (bar
->dragging
))
2673 /* Where should the handle be now? */
2674 int new_start
= y_pos
- 24;
2676 if (new_start
!= XINT (bar
->start
))
2678 int new_end
= new_start
+ (XINT (bar
->end
) - XINT (bar
->start
));
2680 x_scroll_bar_set_handle (bar
, new_start
, new_end
, 0);
2684 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2687 /***********************************************************************
2689 ***********************************************************************/
2692 /* In identifiers such as function/variable names, Emacs tool bar is
2693 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2695 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2696 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2698 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2699 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2700 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2701 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2702 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2703 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2704 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2706 static OSStatus mac_handle_toolbar_command_event
P_ ((EventHandlerCallRef
,
2709 extern Rect last_mouse_glyph
;
2711 extern void mac_move_window_with_gravity
P_ ((struct frame
*, int,
2713 extern void mac_get_window_origin_with_gravity
P_ ((struct frame
*, int,
2715 extern CGImageRef mac_image_spec_to_cg_image
P_ ((struct frame
*,
2719 mac_handle_toolbar_event (next_handler
, event
, data
)
2720 EventHandlerCallRef next_handler
;
2724 OSStatus result
= eventNotHandledErr
;
2726 switch (GetEventKind (event
))
2728 case kEventToolbarGetDefaultIdentifiers
:
2732 case kEventToolbarGetAllowedIdentifiers
:
2734 CFMutableArrayRef array
;
2736 GetEventParameter (event
, kEventParamMutableArray
,
2737 typeCFMutableArrayRef
, NULL
,
2738 sizeof (CFMutableArrayRef
), NULL
, &array
);
2739 CFArrayAppendValue (array
, TOOLBAR_ICON_ITEM_IDENTIFIER
);
2744 case kEventToolbarCreateItemWithIdentifier
:
2746 CFStringRef identifier
;
2747 HIToolbarItemRef item
= NULL
;
2749 GetEventParameter (event
, kEventParamToolbarItemIdentifier
,
2750 typeCFStringRef
, NULL
,
2751 sizeof (CFStringRef
), NULL
, &identifier
);
2753 if (CFStringCompare (identifier
, TOOLBAR_ICON_ITEM_IDENTIFIER
, 0)
2754 == kCFCompareEqualTo
)
2755 HIToolbarItemCreate (identifier
,
2756 kHIToolbarItemAllowDuplicates
2757 | kHIToolbarItemCantBeRemoved
, &item
);
2761 SetEventParameter (event
, kEventParamToolbarItem
,
2762 typeHIToolbarItemRef
,
2763 sizeof (HIToolbarItemRef
), &item
);
2776 /* Create a tool bar for frame F. */
2779 mac_create_frame_tool_bar (f
)
2783 HIToolbarRef toolbar
;
2785 err
= HIToolbarCreate (TOOLBAR_IDENTIFIER
, kHIToolbarNoAttributes
,
2789 static const EventTypeSpec specs
[] =
2790 {{kEventClassToolbar
, kEventToolbarGetDefaultIdentifiers
},
2791 {kEventClassToolbar
, kEventToolbarGetAllowedIdentifiers
},
2792 {kEventClassToolbar
, kEventToolbarCreateItemWithIdentifier
}};
2794 err
= InstallEventHandler (HIObjectGetEventTarget (toolbar
),
2795 mac_handle_toolbar_event
,
2796 GetEventTypeCount (specs
), specs
,
2801 err
= HIToolbarSetDisplayMode (toolbar
, kHIToolbarDisplayModeIconOnly
);
2804 static const EventTypeSpec specs
[] =
2805 {{kEventClassCommand
, kEventCommandProcess
}};
2807 err
= InstallWindowEventHandler (FRAME_MAC_WINDOW (f
),
2808 mac_handle_toolbar_command_event
,
2809 GetEventTypeCount (specs
),
2813 err
= SetWindowToolbar (FRAME_MAC_WINDOW (f
), toolbar
);
2816 CFRelease (toolbar
);
2821 /* Update the tool bar for frame F. Add new buttons and remove old. */
2824 update_frame_tool_bar (f
)
2827 HIToolbarRef toolbar
= NULL
;
2829 CFArrayRef old_items
= NULL
;
2831 int i
, pos
, win_gravity
= f
->output_data
.mac
->toolbar_win_gravity
;
2832 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2836 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2837 if (toolbar
== NULL
)
2839 mac_create_frame_tool_bar (f
);
2840 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2841 if (toolbar
== NULL
)
2843 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2844 mac_get_window_origin_with_gravity (f
, win_gravity
, &left
, &top
);
2847 HIToolbarCopyItems (toolbar
, &old_items
);
2848 if (old_items
== NULL
)
2851 old_count
= CFArrayGetCount (old_items
);
2853 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
2855 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2857 int enabled_p
= !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
));
2858 int selected_p
= !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P
));
2861 CGImageRef cg_image
;
2863 HIToolbarItemRef item
;
2865 /* If image is a vector, choose the image according to the
2867 image
= PROP (TOOL_BAR_ITEM_IMAGES
);
2868 if (VECTORP (image
))
2872 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2873 : TOOL_BAR_IMAGE_ENABLED_DESELECTED
);
2876 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2877 : TOOL_BAR_IMAGE_DISABLED_DESELECTED
);
2879 xassert (ASIZE (image
) >= idx
);
2880 image
= AREF (image
, idx
);
2885 cg_image
= mac_image_spec_to_cg_image (f
, image
);
2886 /* Ignore invalid image specifications. */
2887 if (cg_image
== NULL
)
2890 label
= cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION
));
2894 if (pos
< old_count
)
2896 CGImageRef old_cg_image
= NULL
;
2897 CFStringRef old_label
= NULL
;
2898 Boolean old_enabled_p
;
2900 item
= (HIToolbarItemRef
) CFArrayGetValueAtIndex (old_items
, pos
);
2902 HIToolbarItemCopyImage (item
, &old_cg_image
);
2903 if (cg_image
!= old_cg_image
)
2904 HIToolbarItemSetImage (item
, cg_image
);
2905 CGImageRelease (old_cg_image
);
2907 HIToolbarItemCopyLabel (item
, &old_label
);
2908 if (CFStringCompare (label
, old_label
, 0) != kCFCompareEqualTo
)
2909 HIToolbarItemSetLabel (item
, label
);
2910 CFRelease (old_label
);
2912 old_enabled_p
= HIToolbarItemIsEnabled (item
);
2913 if ((enabled_p
|| idx
>= 0) != old_enabled_p
)
2914 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2919 HIToolbarCreateItemWithIdentifier (toolbar
,
2920 TOOLBAR_ICON_ITEM_IDENTIFIER
,
2924 HIToolbarItemSetImage (item
, cg_image
);
2925 HIToolbarItemSetLabel (item
, label
);
2926 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2927 HIToolbarAppendItem (toolbar
, item
);
2935 HIToolbarItemSetCommandID (item
, TOOLBAR_ITEM_MAKE_COMMAND_ID (i
));
2940 CFRelease (old_items
);
2942 while (pos
< old_count
)
2943 HIToolbarRemoveItemAtIndex (toolbar
, --old_count
);
2945 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), true,
2946 !win_gravity
&& f
== mac_focus_frame (dpyinfo
));
2947 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2948 toolbar visibility change. */
2949 mac_handle_origin_change (f
);
2950 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2952 mac_move_window_with_gravity (f
, win_gravity
, left
, top
);
2953 /* If the title bar is completely outside the screen, adjust the
2955 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f
), kWindowTitleBarRgn
,
2956 kWindowConstrainMoveRegardlessOfFit
2957 | kWindowConstrainAllowPartial
, NULL
, NULL
);
2958 f
->output_data
.mac
->toolbar_win_gravity
= 0;
2965 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2966 doesn't deallocate the resources. */
2969 free_frame_tool_bar (f
)
2972 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f
)))
2974 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2977 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), false,
2978 (NILP (find_symbol_value
2979 (intern ("frame-notice-user-settings")))
2980 && f
== mac_focus_frame (dpyinfo
)));
2981 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2982 on toolbar visibility change. */
2983 mac_handle_origin_change (f
);
2988 /* Report a mouse movement over toolbar to the mainstream Emacs
2992 mac_tool_bar_note_mouse_movement (f
, event
)
2997 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
3000 WindowPartCode part_code
;
3001 HIViewRef item_view
;
3004 mouse_down_p
= (dpyinfo
->grabbed
3005 && f
== last_mouse_frame
3006 && FRAME_LIVE_P (f
));
3010 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
, NULL
,
3011 sizeof (WindowRef
), NULL
, &window
);
3012 if (err
!= noErr
|| window
!= FRAME_MAC_WINDOW (f
))
3015 err
= GetEventParameter (event
, kEventParamWindowPartCode
,
3016 typeWindowPartCode
, NULL
,
3017 sizeof (WindowPartCode
), NULL
, &part_code
);
3018 if (err
!= noErr
|| part_code
!= inStructure
)
3021 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window
), event
, &item_view
);
3022 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3023 toolbar item view seems to have the same command ID with that of
3024 the toolbar item. */
3026 err
= GetControlCommandID (item_view
, &command_id
);
3027 if (err
== noErr
&& TOOLBAR_ITEM_COMMAND_ID_P (command_id
))
3029 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id
);
3031 if (i
< f
->n_tool_bar_items
)
3034 HIViewRef content_view
;
3036 err
= HIViewGetBounds (item_view
, &bounds
);
3038 err
= HIViewFindByID (HIViewGetRoot (window
),
3039 kHIViewWindowContentID
, &content_view
);
3041 err
= HIViewConvertRect (&bounds
, item_view
, content_view
);
3043 SetRect (&last_mouse_glyph
,
3044 CGRectGetMinX (bounds
), CGRectGetMinY (bounds
),
3045 CGRectGetMaxX (bounds
), CGRectGetMaxY (bounds
));
3047 help_echo_object
= help_echo_window
= Qnil
;
3049 help_echo_string
= PROP (TOOL_BAR_ITEM_HELP
);
3050 if (NILP (help_echo_string
))
3051 help_echo_string
= PROP (TOOL_BAR_ITEM_CAPTION
);
3057 mac_handle_toolbar_command_event (next_handler
, event
, data
)
3058 EventHandlerCallRef next_handler
;
3062 OSStatus err
, result
= eventNotHandledErr
;
3063 struct frame
*f
= (struct frame
*) data
;
3066 err
= GetEventParameter (event
, kEventParamDirectObject
,
3067 typeHICommand
, NULL
,
3068 sizeof (HICommand
), NULL
, &command
);
3072 switch (GetEventKind (event
))
3074 case kEventCommandProcess
:
3075 if (!TOOLBAR_ITEM_COMMAND_ID_P (command
.commandID
))
3076 result
= CallNextEventHandler (next_handler
, event
);
3079 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command
.commandID
);
3081 if (i
< f
->n_tool_bar_items
3082 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
)))
3085 struct input_event buf
;
3089 XSETFRAME (frame
, f
);
3090 buf
.kind
= TOOL_BAR_EVENT
;
3091 buf
.frame_or_window
= frame
;
3093 kbd_buffer_store_event (&buf
);
3095 buf
.kind
= TOOL_BAR_EVENT
;
3096 buf
.frame_or_window
= frame
;
3097 buf
.arg
= PROP (TOOL_BAR_ITEM_KEY
);
3098 buf
.modifiers
= mac_event_to_emacs_modifiers (event
);
3099 kbd_buffer_store_event (&buf
);
3113 #endif /* USE_MAC_TOOLBAR */
3116 /***********************************************************************
3118 ***********************************************************************/
3120 #if USE_MAC_FONT_PANEL
3121 /* Whether Font Panel has been shown before. The first call to font
3122 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3123 slow. This variable is used for deferring such a call as much as
3125 static int font_panel_shown_p
= 0;
3127 extern Lisp_Object Qpanel_closed
, Qselection
;
3128 extern Lisp_Object Qfont
;
3130 /* Whether the font panel is currently visible. */
3133 mac_font_panel_visible_p ()
3135 return font_panel_shown_p
&& FPIsFontPanelVisible ();
3138 static pascal OSStatus
3139 mac_handle_font_event (next_handler
, event
, data
)
3140 EventHandlerCallRef next_handler
;
3144 OSStatus result
, err
;
3147 const EventParamName
*names
;
3148 const EventParamType
*types
;
3149 static const EventParamName names_sel
[] = {kEventParamATSUFontID
,
3150 kEventParamATSUFontSize
,
3151 kEventParamFMFontFamily
,
3152 kEventParamFMFontStyle
,
3153 kEventParamFMFontSize
,
3154 kEventParamFontColor
};
3155 static const EventParamType types_sel
[] = {typeATSUFontID
,
3162 result
= CallNextEventHandler (next_handler
, event
);
3163 if (result
!= eventNotHandledErr
)
3166 switch (GetEventKind (event
))
3168 case kEventFontPanelClosed
:
3169 id_key
= Qpanel_closed
;
3175 case kEventFontSelection
:
3176 id_key
= Qselection
;
3177 num_params
= sizeof (names_sel
) / sizeof (names_sel
[0]);
3183 err
= mac_store_event_ref_as_apple_event (0, 0, Qfont
, id_key
,
3192 /* Toggle visiblity of the font panel. */
3195 mac_show_hide_font_panel ()
3197 if (!font_panel_shown_p
)
3201 static const EventTypeSpec specs
[] =
3202 {{kEventClassFont
, kEventFontPanelClosed
},
3203 {kEventClassFont
, kEventFontSelection
}};
3205 err
= InstallApplicationEventHandler (mac_handle_font_event
,
3206 GetEventTypeCount (specs
),
3211 font_panel_shown_p
= 1;
3214 return FPShowHideFontPanel ();
3217 /* Set the font selected in the font panel to the one corresponding to
3218 the face FACE_ID and the charcacter C in the frame F. */
3221 mac_set_font_info_for_selection (f
, face_id
, c
)
3226 EventTargetRef target
= NULL
;
3227 XFontStruct
*font
= NULL
;
3229 if (!mac_font_panel_visible_p ())
3234 target
= GetWindowEventTarget (FRAME_MAC_WINDOW (f
));
3236 if (FRAME_FACE_CACHE (f
) && CHAR_VALID_P (c
, 0))
3240 face_id
= FACE_FOR_CHAR (f
, FACE_FROM_ID (f
, face_id
), c
);
3241 face
= FACE_FROM_ID (f
, face_id
);
3247 err
= SetFontInfoForSelection (kFontSelectionATSUIType
, 0, NULL
, target
);
3250 if (font
->mac_fontnum
!= -1)
3252 FontSelectionQDStyle qd_style
;
3254 qd_style
.version
= kFontSelectionQDStyleVersionZero
;
3255 qd_style
.instance
.fontFamily
= font
->mac_fontnum
;
3256 qd_style
.instance
.fontStyle
= font
->mac_fontface
;
3257 qd_style
.size
= font
->mac_fontsize
;
3258 qd_style
.hasColor
= false;
3260 err
= SetFontInfoForSelection (kFontSelectionQDType
,
3261 1, &qd_style
, target
);
3264 err
= SetFontInfoForSelection (kFontSelectionATSUIType
,
3265 1, &font
->mac_style
, target
);
3270 #endif /* USE_MAC_FONT_PANEL */
3273 /************************************************************************
3275 ************************************************************************/
3277 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3280 static int any_help_event_p
;
3282 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3283 static Lisp_Object last_window
;
3285 static Point saved_menu_event_location
;
3287 extern struct frame
*pending_autoraise_frame
;
3289 extern FRAME_PTR last_mouse_glyph_frame
;
3292 extern int volatile input_signal_count
;
3294 extern int input_signal_count
;
3297 extern int mac_screen_config_changed
;
3299 extern Lisp_Object Vmac_emulate_three_button_mouse
;
3300 #if TARGET_API_MAC_CARBON
3301 extern int mac_wheel_button_is_mouse_2
;
3302 extern int mac_pass_command_to_system
;
3303 extern int mac_pass_control_to_system
;
3304 #endif /* TARGET_API_MAC_CARBON */
3305 extern int mac_ready_for_apple_events
;
3307 extern void mac_focus_changed
P_ ((int, struct mac_display_info
*,
3308 struct frame
*, struct input_event
*));
3309 extern int mac_get_emulated_btn
P_ ((UInt32
));
3310 extern int note_mouse_movement
P_ ((FRAME_PTR
, Point
*));
3311 extern void mac_get_screen_info
P_ ((struct mac_display_info
*));
3313 /* The focus may have changed. Figure out if it is a real focus change,
3314 by checking both FocusIn/Out and Enter/LeaveNotify events.
3316 Returns FOCUS_IN_EVENT event in *BUFP. */
3319 x_detect_focus_change (dpyinfo
, event
, bufp
)
3320 struct mac_display_info
*dpyinfo
;
3321 const EventRecord
*event
;
3322 struct input_event
*bufp
;
3324 struct frame
*frame
;
3326 frame
= mac_window_to_frame ((WindowRef
) event
->message
);
3330 /* On Mac, this is only called from focus events, so no switch needed. */
3331 mac_focus_changed ((event
->modifiers
& activeFlag
),
3332 dpyinfo
, frame
, bufp
);
3335 #if TARGET_API_MAC_CARBON
3336 /* Obtains the event modifiers from the event EVENTREF and then calls
3337 mac_to_emacs_modifiers. */
3340 mac_event_to_emacs_modifiers (EventRef eventRef
)
3342 UInt32 mods
= 0, class;
3344 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3345 sizeof (UInt32
), NULL
, &mods
);
3346 class = GetEventClass (eventRef
);
3347 if (!NILP (Vmac_emulate_three_button_mouse
)
3348 && (class == kEventClassMouse
|| class == kEventClassCommand
))
3350 mods
&= ~(optionKey
| cmdKey
);
3352 return mac_to_emacs_modifiers (mods
, 0);
3355 /* Given an event REF, return the code to use for the mouse button
3356 code in the emacs input_event. */
3359 mac_get_mouse_btn (EventRef ref
)
3361 EventMouseButton result
= kEventMouseButtonPrimary
;
3362 GetEventParameter (ref
, kEventParamMouseButton
, typeMouseButton
, NULL
,
3363 sizeof (EventMouseButton
), NULL
, &result
);
3366 case kEventMouseButtonPrimary
:
3367 if (NILP (Vmac_emulate_three_button_mouse
))
3371 GetEventParameter (ref
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3372 sizeof (UInt32
), NULL
, &mods
);
3373 return mac_get_emulated_btn(mods
);
3375 case kEventMouseButtonSecondary
:
3376 return mac_wheel_button_is_mouse_2
? 2 : 1;
3377 case kEventMouseButtonTertiary
:
3378 case 4: /* 4 is the number for the mouse wheel button */
3379 return mac_wheel_button_is_mouse_2
? 1 : 2;
3385 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3386 events. However the click of the mouse wheel is not converted to a
3387 mouseDown or mouseUp event. Likewise for dead key events. This
3388 calls ConvertEventRefToEventRecord, but then checks to see if it is
3389 a mouse up/down, or a dead key Carbon event that has not been
3390 converted, and if so, converts it by hand (to be picked up in the
3391 XTread_socket loop). */
3392 static Boolean
mac_convert_event_ref (EventRef eventRef
, EventRecord
*eventRec
)
3395 Boolean result
= ConvertEventRefToEventRecord (eventRef
, eventRec
);
3401 switch (GetEventClass (eventRef
))
3403 case kEventClassMouse
:
3404 switch (GetEventKind (eventRef
))
3406 case kEventMouseDown
:
3407 eventRec
->what
= mouseDown
;
3412 eventRec
->what
= mouseUp
;
3421 case kEventClassKeyboard
:
3422 switch (GetEventKind (eventRef
))
3424 case kEventRawKeyDown
:
3426 goto keystroke_common
;
3427 case kEventRawKeyRepeat
:
3429 goto keystroke_common
;
3430 case kEventRawKeyUp
:
3434 unsigned char char_codes
;
3437 err
= GetEventParameter (eventRef
, kEventParamKeyMacCharCodes
,
3438 typeChar
, NULL
, sizeof (char),
3441 err
= GetEventParameter (eventRef
, kEventParamKeyCode
,
3442 typeUInt32
, NULL
, sizeof (UInt32
),
3446 eventRec
->what
= action
;
3447 eventRec
->message
= char_codes
| ((key_code
& 0xff) << 8);
3464 /* Need where and when. */
3467 GetEventParameter (eventRef
, kEventParamMouseLocation
, typeQDPoint
,
3468 NULL
, sizeof (Point
), NULL
, &eventRec
->where
);
3469 /* Use two step process because new event modifiers are 32-bit
3470 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3471 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
,
3472 NULL
, sizeof (UInt32
), NULL
, &mods
);
3473 eventRec
->modifiers
= mods
;
3475 eventRec
->when
= EventTimeToTicks (GetEventTime (eventRef
));
3480 #endif /* TARGET_API_MAC_CARBON */
3482 #if !TARGET_API_MAC_CARBON
3483 static RgnHandle mouse_region
= NULL
;
3486 mac_wait_next_event (er
, sleep_time
, dequeue
)
3491 static EventRecord er_buf
= {nullEvent
};
3492 UInt32 target_tick
, current_tick
;
3493 EventMask event_mask
;
3495 if (mouse_region
== NULL
)
3496 mouse_region
= NewRgn ();
3498 event_mask
= everyEvent
;
3499 if (!mac_ready_for_apple_events
)
3500 event_mask
-= highLevelEventMask
;
3502 current_tick
= TickCount ();
3503 target_tick
= current_tick
+ sleep_time
;
3505 if (er_buf
.what
== nullEvent
)
3506 while (!WaitNextEvent (event_mask
, &er_buf
,
3507 target_tick
- current_tick
, mouse_region
))
3509 current_tick
= TickCount ();
3510 if (target_tick
<= current_tick
)
3516 er_buf
.what
= nullEvent
;
3519 #endif /* not TARGET_API_MAC_CARBON */
3521 #if TARGET_API_MAC_CARBON
3523 mac_post_mouse_moved_event ()
3525 EventRef event
= NULL
;
3528 err
= CreateEvent (NULL
, kEventClassMouse
, kEventMouseMoved
, 0,
3529 kEventAttributeNone
, &event
);
3534 GetGlobalMouse (&mouse_pos
);
3535 err
= SetEventParameter (event
, kEventParamMouseLocation
, typeQDPoint
,
3536 sizeof (Point
), &mouse_pos
);
3540 UInt32 modifiers
= GetCurrentKeyModifiers ();
3542 err
= SetEventParameter (event
, kEventParamKeyModifiers
, typeUInt32
,
3543 sizeof (UInt32
), &modifiers
);
3546 err
= PostEventToQueue (GetCurrentEventQueue (), event
,
3547 kEventPriorityStandard
);
3549 ReleaseEvent (event
);
3556 /* Run the current run loop in the default mode until some input
3557 happens or TIMEOUT seconds passes unless it is negative. Return
3558 true if timeout occurs first. */
3561 mac_run_loop_run_once (timeout
)
3562 EventTimeout timeout
;
3565 mac_prepare_for_quickdraw (NULL
);
3567 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode
,
3568 timeout
>= 0 ? timeout
: 100000, true)
3569 == kCFRunLoopRunTimedOut
);
3573 /* Emacs calls this whenever it wants to read an input event from the
3577 XTread_socket (sd
, expected
, hold_quit
)
3579 struct input_event
*hold_quit
;
3581 struct input_event inev
;
3583 #if TARGET_API_MAC_CARBON
3585 EventTargetRef toolbox_dispatcher
;
3588 struct mac_display_info
*dpyinfo
= &one_mac_display_info
;
3590 if (interrupt_input_blocked
)
3592 interrupt_input_pending
= 1;
3596 interrupt_input_pending
= 0;
3599 /* So people can tell when we have read the available input. */
3600 input_signal_count
++;
3604 #if TARGET_API_MAC_CARBON
3605 toolbox_dispatcher
= GetEventDispatcherTarget ();
3609 mac_prepare_for_quickdraw (NULL
),
3611 !ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
3612 kEventRemoveFromQueue
, &eventRef
))
3613 #else /* !TARGET_API_MAC_CARBON */
3614 while (mac_wait_next_event (&er
, 0, true))
3615 #endif /* !TARGET_API_MAC_CARBON */
3619 unsigned long timestamp
;
3622 inev
.kind
= NO_EVENT
;
3625 #if TARGET_API_MAC_CARBON
3626 timestamp
= GetEventTime (eventRef
) / kEventDurationMillisecond
;
3628 if (!mac_convert_event_ref (eventRef
, &er
))
3630 #else /* !TARGET_API_MAC_CARBON */
3631 timestamp
= er
.when
* (1000 / 60); /* ticks to milliseconds */
3632 #endif /* !TARGET_API_MAC_CARBON */
3639 WindowRef window_ptr
;
3640 ControlPartCode part_code
;
3643 #if TARGET_API_MAC_CARBON
3646 /* This is needed to send mouse events like aqua window
3647 buttons to the correct handler. */
3648 read_socket_inev
= &inev
;
3649 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
3650 read_socket_inev
= NULL
;
3651 if (err
!= eventNotHandledErr
)
3654 last_mouse_glyph_frame
= 0;
3656 if (dpyinfo
->grabbed
&& last_mouse_frame
3657 && FRAME_LIVE_P (last_mouse_frame
))
3659 window_ptr
= FRAME_MAC_WINDOW (last_mouse_frame
);
3660 part_code
= inContent
;
3664 part_code
= FindWindow (er
.where
, &window_ptr
);
3665 if (tip_window
&& window_ptr
== tip_window
)
3667 HideWindow (tip_window
);
3668 part_code
= FindWindow (er
.where
, &window_ptr
);
3672 if (er
.what
!= mouseDown
3673 && (part_code
!= inContent
|| dpyinfo
->grabbed
== 0))
3679 f
= mac_focus_frame (dpyinfo
);
3680 saved_menu_event_location
= er
.where
;
3681 inev
.kind
= MENU_BAR_ACTIVATE_EVENT
;
3682 XSETFRAME (inev
.frame_or_window
, f
);
3687 #if TARGET_API_MAC_CARBON
3688 FrontNonFloatingWindow ()
3693 || (mac_window_to_frame (window_ptr
)
3694 != dpyinfo
->x_focus_frame
))
3695 SelectWindow (window_ptr
);
3698 ControlPartCode control_part_code
;
3702 ControlKind control_kind
;
3705 f
= mac_window_to_frame (window_ptr
);
3706 /* convert to local coordinates of new window */
3707 mouse_loc
.h
= (er
.where
.h
3709 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3710 mouse_loc
.v
= (er
.where
.v
3712 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3713 #if TARGET_API_MAC_CARBON
3714 ch
= FindControlUnderMouse (mouse_loc
, window_ptr
,
3715 &control_part_code
);
3718 GetControlKind (ch
, &control_kind
);
3721 control_part_code
= FindControl (mouse_loc
, window_ptr
,
3725 #if TARGET_API_MAC_CARBON
3726 inev
.code
= mac_get_mouse_btn (eventRef
);
3727 inev
.modifiers
= mac_event_to_emacs_modifiers (eventRef
);
3729 inev
.code
= mac_get_emulated_btn (er
.modifiers
);
3730 inev
.modifiers
= mac_to_emacs_modifiers (er
.modifiers
, 0);
3732 XSETINT (inev
.x
, mouse_loc
.h
);
3733 XSETINT (inev
.y
, mouse_loc
.v
);
3735 if ((dpyinfo
->grabbed
&& tracked_scroll_bar
)
3737 #ifndef USE_TOOLKIT_SCROLL_BARS
3738 /* control_part_code becomes kControlNoPart if
3739 a progress indicator is clicked. */
3740 && control_part_code
!= kControlNoPart
3741 #else /* USE_TOOLKIT_SCROLL_BARS */
3743 && control_kind
.kind
== kControlKindScrollBar
3744 #endif /* MAC_OSX */
3745 #endif /* USE_TOOLKIT_SCROLL_BARS */
3748 struct scroll_bar
*bar
;
3750 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3752 bar
= tracked_scroll_bar
;
3753 #ifndef USE_TOOLKIT_SCROLL_BARS
3754 control_part_code
= kControlIndicatorPart
;
3758 bar
= (struct scroll_bar
*) GetControlReference (ch
);
3759 #ifdef USE_TOOLKIT_SCROLL_BARS
3760 /* Make the "Ctrl-Mouse-2 splits window" work
3761 for toolkit scroll bars. */
3762 if (inev
.modifiers
& ctrl_modifier
)
3763 x_scroll_bar_handle_click (bar
, control_part_code
,
3765 else if (er
.what
== mouseDown
)
3766 x_scroll_bar_handle_press (bar
, control_part_code
,
3769 x_scroll_bar_handle_release (bar
, &inev
);
3770 #else /* not USE_TOOLKIT_SCROLL_BARS */
3771 x_scroll_bar_handle_click (bar
, control_part_code
,
3773 if (er
.what
== mouseDown
3774 && control_part_code
== kControlIndicatorPart
)
3775 tracked_scroll_bar
= bar
;
3777 tracked_scroll_bar
= NULL
;
3778 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3783 int x
= mouse_loc
.h
;
3784 int y
= mouse_loc
.v
;
3786 window
= window_from_coordinates (f
, x
, y
, 0, 0, 0, 1);
3787 if (EQ (window
, f
->tool_bar_window
))
3789 if (er
.what
== mouseDown
)
3790 handle_tool_bar_click (f
, x
, y
, 1, 0);
3792 handle_tool_bar_click (f
, x
, y
, 0,
3798 XSETFRAME (inev
.frame_or_window
, f
);
3799 inev
.kind
= MOUSE_CLICK_EVENT
;
3803 if (er
.what
== mouseDown
)
3805 dpyinfo
->grabbed
|= (1 << inev
.code
);
3806 last_mouse_frame
= f
;
3809 last_tool_bar_item
= -1;
3813 if ((dpyinfo
->grabbed
& (1 << inev
.code
)) == 0)
3814 /* If a button is released though it was not
3815 previously pressed, that would be because
3816 of multi-button emulation. */
3817 dpyinfo
->grabbed
= 0;
3819 dpyinfo
->grabbed
&= ~(1 << inev
.code
);
3822 /* Ignore any mouse motion that happened before
3823 this event; any subsequent mouse-movement Emacs
3824 events should reflect only motion after the
3829 #ifdef USE_TOOLKIT_SCROLL_BARS
3830 if (inev
.kind
== MOUSE_CLICK_EVENT
3831 || (inev
.kind
== SCROLL_BAR_CLICK_EVENT
3832 && (inev
.modifiers
& ctrl_modifier
)))
3837 inev
.modifiers
|= down_modifier
;
3840 inev
.modifiers
|= up_modifier
;
3847 #if TARGET_API_MAC_CARBON
3849 if (IsWindowPathSelectClick (window_ptr
, &er
))
3851 WindowPathSelect (window_ptr
, NULL
, NULL
);
3854 if (part_code
== inProxyIcon
3855 && (TrackWindowProxyDrag (window_ptr
, er
.where
)
3856 != errUserWantsToDragWindow
))
3858 DragWindow (window_ptr
, er
.where
, NULL
);
3859 #else /* not TARGET_API_MAC_CARBON */
3860 DragWindow (window_ptr
, er
.where
, &qd
.screenBits
.bounds
);
3861 /* Update the frame parameters. */
3863 struct frame
*f
= mac_window_to_frame (window_ptr
);
3865 if (f
&& !f
->async_iconified
)
3866 mac_handle_origin_change (f
);
3868 #endif /* not TARGET_API_MAC_CARBON */
3872 if (TrackGoAway (window_ptr
, er
.where
))
3874 inev
.kind
= DELETE_WINDOW_EVENT
;
3875 XSETFRAME (inev
.frame_or_window
,
3876 mac_window_to_frame (window_ptr
));
3880 /* window resize handling added --ben */
3882 do_grow_window (window_ptr
, &er
);
3885 /* window zoom handling added --ben */
3888 if (TrackBox (window_ptr
, er
.where
, part_code
))
3889 do_zoom_window (window_ptr
, part_code
);
3898 if (FrontNonFloatingWindow () != window_ptr
)
3899 SelectWindow (window_ptr
);
3901 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr
),
3903 /* This doesn't work on Mac OS X 10.2. */
3905 HIViewClick (ch
, eventRef
);
3908 #endif /* USE_MAC_TOOLBAR */
3916 #if !TARGET_API_MAC_CARBON
3918 do_window_update ((WindowRef
) er
.message
);
3923 #if TARGET_API_MAC_CARBON
3924 if (SendEventToEventTarget (eventRef
, toolbox_dispatcher
)
3925 != eventNotHandledErr
)
3928 switch ((er
.message
>> 24) & 0x000000FF)
3931 case suspendResumeMessage
:
3932 if (er
.message
& resumeFlag
)
3939 case mouseMovedMessage
:
3940 #if !TARGET_API_MAC_CARBON
3941 SetRectRgn (mouse_region
, er
.where
.h
, er
.where
.v
,
3942 er
.where
.h
+ 1, er
.where
.v
+ 1);
3944 previous_help_echo_string
= help_echo_string
;
3945 help_echo_string
= Qnil
;
3947 if (dpyinfo
->grabbed
&& last_mouse_frame
3948 && FRAME_LIVE_P (last_mouse_frame
))
3949 f
= last_mouse_frame
;
3951 f
= dpyinfo
->x_focus_frame
;
3953 if (dpyinfo
->mouse_face_hidden
)
3955 dpyinfo
->mouse_face_hidden
= 0;
3956 clear_mouse_face (dpyinfo
);
3961 WindowRef wp
= FRAME_MAC_WINDOW (f
);
3964 mouse_pos
.h
= (er
.where
.h
3966 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3967 mouse_pos
.v
= (er
.where
.v
3969 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3970 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3971 #ifdef USE_TOOLKIT_SCROLL_BARS
3972 x_scroll_bar_handle_drag (wp
, tracked_scroll_bar
,
3974 #else /* not USE_TOOLKIT_SCROLL_BARS */
3975 x_scroll_bar_note_movement (tracked_scroll_bar
,
3977 - XINT (tracked_scroll_bar
->top
),
3978 er
.when
* (1000 / 60));
3979 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3982 /* Generate SELECT_WINDOW_EVENTs when needed. */
3983 if (!NILP (Vmouse_autoselect_window
))
3987 window
= window_from_coordinates (f
,
3992 /* Window will be selected only when it is
3993 not selected now and last mouse movement
3994 event was not in it. Minibuffer window
3995 will be selected only when it is active. */
3996 if (WINDOWP (window
)
3997 && !EQ (window
, last_window
)
3998 && !EQ (window
, selected_window
)
3999 /* For click-to-focus window managers
4000 create event iff we don't leave the
4002 && (focus_follows_mouse
4003 || (EQ (XWINDOW (window
)->frame
,
4004 XWINDOW (selected_window
)->frame
))))
4006 inev
.kind
= SELECT_WINDOW_EVENT
;
4007 inev
.frame_or_window
= window
;
4012 if (!note_mouse_movement (f
, &mouse_pos
))
4013 help_echo_string
= previous_help_echo_string
;
4016 mac_tool_bar_note_mouse_movement (f
, eventRef
);
4021 /* If the contents of the global variable
4022 help_echo_string has changed, generate a
4024 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
4032 WindowRef window_ptr
= (WindowRef
) er
.message
;
4034 ControlRef root_control
;
4036 if (window_ptr
== tip_window
)
4038 HideWindow (tip_window
);
4042 if (!is_emacs_window (window_ptr
))
4045 f
= mac_window_to_frame (window_ptr
);
4047 if ((er
.modifiers
& activeFlag
) != 0)
4049 /* A window has been activated */
4052 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4054 ActivateControl (root_control
);
4056 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4058 mouse_loc
.h
= (er
.where
.h
4060 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
4061 mouse_loc
.v
= (er
.where
.v
4063 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
4064 /* Window-activated event counts as mouse movement,
4065 so update things that depend on mouse position. */
4066 note_mouse_movement (f
, &mouse_loc
);
4070 /* A window has been deactivated */
4071 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4073 DeactivateControl (root_control
);
4075 #ifdef USE_TOOLKIT_SCROLL_BARS
4076 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
4078 struct input_event event
;
4081 event
.kind
= NO_EVENT
;
4082 x_scroll_bar_handle_release (tracked_scroll_bar
, &event
);
4083 if (event
.kind
!= NO_EVENT
)
4085 event
.timestamp
= timestamp
;
4086 kbd_buffer_store_event_hold (&event
, hold_quit
);
4091 dpyinfo
->grabbed
= 0;
4093 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4095 if (f
== dpyinfo
->mouse_face_mouse_frame
)
4097 /* If we move outside the frame, then we're
4098 certainly no longer on any text in the
4100 clear_mouse_face (dpyinfo
);
4101 dpyinfo
->mouse_face_mouse_frame
= 0;
4104 /* Generate a nil HELP_EVENT to cancel a help-echo.
4105 Do it only if there's something to cancel.
4106 Otherwise, the startup message is cleared when the
4107 mouse leaves the frame. */
4108 if (any_help_event_p
)
4119 f
= mac_focus_frame (dpyinfo
);
4120 XSETFRAME (inev
.frame_or_window
, f
);
4122 /* If mouse-highlight is an integer, input clears out mouse
4124 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
)
4125 && !EQ (f
->tool_bar_window
, dpyinfo
->mouse_face_window
))
4127 clear_mouse_face (dpyinfo
);
4128 dpyinfo
->mouse_face_hidden
= 1;
4132 UInt32 modifiers
= er
.modifiers
, mapped_modifiers
;
4133 UInt32 key_code
= (er
.message
& keyCodeMask
) >> 8;
4136 GetEventParameter (eventRef
, kEventParamKeyModifiers
,
4138 sizeof (UInt32
), NULL
, &modifiers
);
4140 mapped_modifiers
= mac_mapped_modifiers (modifiers
, key_code
);
4142 #if TARGET_API_MAC_CARBON
4143 if (!(mapped_modifiers
4144 & ~(mac_pass_command_to_system
? cmdKey
: 0)
4145 & ~(mac_pass_control_to_system
? controlKey
: 0)))
4149 if (er
.what
!= keyUp
)
4150 do_keystroke (er
.what
, er
.message
& charCodeMask
,
4151 key_code
, modifiers
, timestamp
, &inev
);
4155 case kHighLevelEvent
:
4156 AEProcessAppleEvent (&er
);
4161 #if TARGET_API_MAC_CARBON
4165 read_socket_inev
= &inev
;
4166 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
4167 read_socket_inev
= NULL
;
4172 #if TARGET_API_MAC_CARBON
4173 ReleaseEvent (eventRef
);
4176 if (inev
.kind
!= NO_EVENT
)
4178 inev
.timestamp
= timestamp
;
4179 kbd_buffer_store_event_hold (&inev
, hold_quit
);
4184 && !(hold_quit
&& hold_quit
->kind
!= NO_EVENT
))
4189 XSETFRAME (frame
, f
);
4195 any_help_event_p
= 1;
4196 gen_help_event (help_echo_string
, frame
, help_echo_window
,
4197 help_echo_object
, help_echo_pos
);
4201 help_echo_string
= Qnil
;
4202 gen_help_event (Qnil
, frame
, Qnil
, Qnil
, 0);
4208 /* If the focus was just given to an autoraising frame,
4210 /* ??? This ought to be able to handle more than one such frame. */
4211 if (pending_autoraise_frame
)
4213 x_raise_frame (pending_autoraise_frame
);
4214 pending_autoraise_frame
= 0;
4217 if (mac_screen_config_changed
)
4219 mac_get_screen_info (dpyinfo
);
4220 mac_screen_config_changed
= 0;
4223 #if !TARGET_API_MAC_CARBON
4224 /* Check which frames are still visible. We do this here because
4225 there doesn't seem to be any direct notification from the Window
4226 Manager that the visibility of a window has changed (at least,
4227 not in all cases). */
4229 Lisp_Object tail
, frame
;
4231 FOR_EACH_FRAME (tail
, frame
)
4233 struct frame
*f
= XFRAME (frame
);
4235 /* The tooltip has been drawn already. Avoid the
4236 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4237 if (EQ (frame
, tip_frame
))
4240 if (FRAME_MAC_P (f
))
4241 mac_handle_visibility_change (f
);
4252 /***********************************************************************
4254 ***********************************************************************/
4256 #if TARGET_API_MAC_CARBON
4257 /* Show the spinning progress indicator for the frame F. Create it if
4258 it doesn't exist yet. */
4261 mac_show_hourglass (f
)
4265 mac_prepare_for_quickdraw (f
);
4267 if (!f
->output_data
.mac
->hourglass_control
)
4269 Window w
= FRAME_MAC_WINDOW (f
);
4273 GetWindowPortBounds (w
, &r
);
4274 r
.left
= r
.right
- HOURGLASS_WIDTH
;
4275 r
.bottom
= r
.top
+ HOURGLASS_HEIGHT
;
4276 if (CreateChasingArrowsControl (w
, &r
, &c
) == noErr
)
4277 f
->output_data
.mac
->hourglass_control
= c
;
4280 if (f
->output_data
.mac
->hourglass_control
)
4281 ShowControl (f
->output_data
.mac
->hourglass_control
);
4284 /* Hide the spinning progress indicator for the frame F. Do nothing
4285 it doesn't exist yet. */
4288 mac_hide_hourglass (f
)
4291 if (f
->output_data
.mac
->hourglass_control
)
4294 mac_prepare_for_quickdraw (f
);
4296 HideControl (f
->output_data
.mac
->hourglass_control
);
4300 /* Reposition the spinning progress indicator for the frame F. Do
4301 nothing it doesn't exist yet. */
4304 mac_reposition_hourglass (f
)
4307 if (f
->output_data
.mac
->hourglass_control
)
4310 mac_prepare_for_quickdraw (f
);
4312 MoveControl (f
->output_data
.mac
->hourglass_control
,
4313 FRAME_PIXEL_WIDTH (f
) - HOURGLASS_WIDTH
, 0);
4316 #endif /* TARGET_API_MAC_CARBON */
4319 /***********************************************************************
4320 File selection dialog
4321 ***********************************************************************/
4323 #if TARGET_API_MAC_CARBON
4324 extern Lisp_Object Qfile_name_history
;
4326 static pascal void mac_nav_event_callback
P_ ((NavEventCallbackMessage
,
4327 NavCBRecPtr
, void *));
4329 /* The actual implementation of Fx_file_dialog. */
4332 mac_file_dialog (prompt
, dir
, default_filename
, mustmatch
, only_dir_p
)
4333 Lisp_Object prompt
, dir
, default_filename
, mustmatch
, only_dir_p
;
4335 Lisp_Object file
= Qnil
;
4336 int count
= SPECPDL_INDEX ();
4337 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
, gcpro5
, gcpro6
;
4338 char filename
[MAXPATHLEN
];
4339 static NavEventUPP mac_nav_event_callbackUPP
= NULL
;
4343 GCPRO6 (prompt
, dir
, default_filename
, mustmatch
, file
, only_dir_p
);
4344 CHECK_STRING (prompt
);
4347 /* Create the dialog with PROMPT as title, using DIR as initial
4348 directory and using "*" as pattern. */
4349 dir
= Fexpand_file_name (dir
, Qnil
);
4353 NavDialogCreationOptions options
;
4354 NavDialogRef dialogRef
;
4355 NavTypeListHandle fileTypes
= NULL
;
4356 NavUserAction userAction
;
4357 CFStringRef message
=NULL
, saveName
= NULL
;
4360 /* No need for a callback function because we are modal */
4361 NavGetDefaultDialogCreationOptions(&options
);
4362 options
.modality
= kWindowModalityAppModal
;
4363 options
.location
.h
= options
.location
.v
= -1;
4364 options
.optionFlags
= kNavDefaultNavDlogOptions
;
4365 options
.optionFlags
|= kNavAllFilesInPopup
; /* All files allowed */
4366 options
.optionFlags
|= kNavSelectAllReadableItem
;
4367 options
.optionFlags
&= ~kNavAllowMultipleFiles
;
4370 message
= cfstring_create_with_string (prompt
);
4371 options
.message
= message
;
4373 /* Don't set the application, let it use default.
4374 options.clientName = CFSTR ("Emacs");
4377 if (mac_nav_event_callbackUPP
== NULL
)
4378 mac_nav_event_callbackUPP
= NewNavEventUPP (mac_nav_event_callback
);
4380 if (!NILP (only_dir_p
))
4381 status
= NavCreateChooseFolderDialog(&options
, mac_nav_event_callbackUPP
,
4382 NULL
, NULL
, &dialogRef
);
4383 else if (NILP (mustmatch
))
4385 /* This is a save dialog */
4386 options
.optionFlags
|= kNavDontConfirmReplacement
;
4387 options
.actionButtonLabel
= CFSTR ("Ok");
4388 options
.windowTitle
= CFSTR ("Enter name");
4390 if (STRINGP (default_filename
))
4392 Lisp_Object utf8
= ENCODE_UTF_8 (default_filename
);
4393 char *begPtr
= SDATA(utf8
);
4394 char *filePtr
= begPtr
+ SBYTES(utf8
);
4395 while (filePtr
!= begPtr
&& !IS_DIRECTORY_SEP(filePtr
[-1]))
4397 saveName
= cfstring_create_with_utf8_cstring (filePtr
);
4398 options
.saveFileName
= saveName
;
4399 options
.optionFlags
|= kNavSelectDefaultLocation
;
4401 status
= NavCreatePutFileDialog(&options
,
4402 'TEXT', kNavGenericSignature
,
4403 mac_nav_event_callbackUPP
, NULL
,
4408 /* This is an open dialog*/
4409 status
= NavCreateChooseFileDialog(&options
, fileTypes
,
4410 mac_nav_event_callbackUPP
, NULL
,
4411 NULL
, NULL
, &dialogRef
);
4414 /* Set the default location and continue*/
4415 if (status
== noErr
)
4417 Lisp_Object encoded_dir
= ENCODE_FILE (dir
);
4420 status
= AECreateDesc (TYPE_FILE_NAME
, SDATA (encoded_dir
),
4421 SBYTES (encoded_dir
), &defLocAed
);
4422 if (status
== noErr
)
4424 NavCustomControl(dialogRef
, kNavCtlSetLocation
, (void*) &defLocAed
);
4425 AEDisposeDesc(&defLocAed
);
4427 status
= NavDialogRun(dialogRef
);
4430 if (saveName
) CFRelease(saveName
);
4431 if (message
) CFRelease(message
);
4433 if (status
== noErr
) {
4434 userAction
= NavDialogGetUserAction(dialogRef
);
4437 case kNavUserActionNone
:
4438 case kNavUserActionCancel
:
4439 break; /* Treat cancel like C-g */
4440 case kNavUserActionOpen
:
4441 case kNavUserActionChoose
:
4442 case kNavUserActionSaveAs
:
4444 NavReplyRecord reply
;
4447 status
= NavDialogGetReply(dialogRef
, &reply
);
4448 if (status
!= noErr
)
4450 status
= AEGetNthPtr (&reply
.selection
, 1, TYPE_FILE_NAME
,
4451 NULL
, NULL
, filename
,
4452 sizeof (filename
) - 1, &len
);
4453 if (status
== noErr
)
4455 len
= min (len
, sizeof (filename
) - 1);
4456 filename
[len
] = '\0';
4457 if (reply
.saveFileName
)
4459 /* If it was a saved file, we need to add the file name */
4460 if (len
&& len
< sizeof (filename
) - 1
4461 && filename
[len
-1] != '/')
4462 filename
[len
++] = '/';
4463 CFStringGetCString(reply
.saveFileName
, filename
+len
,
4464 sizeof (filename
) - len
,
4466 kCFStringEncodingUTF8
4468 CFStringGetSystemEncoding ()
4472 file
= DECODE_FILE (make_unibyte_string (filename
,
4473 strlen (filename
)));
4475 NavDisposeReply(&reply
);
4479 NavDialogDispose(dialogRef
);
4484 /* Fall back on minibuffer if there was a problem */
4485 file
= Fcompleting_read (prompt
, intern ("read-file-name-internal"),
4486 dir
, mustmatch
, dir
, Qfile_name_history
,
4487 default_filename
, Qnil
);
4493 /* Make "Cancel" equivalent to C-g. */
4495 Fsignal (Qquit
, Qnil
);
4497 return unbind_to (count
, file
);
4500 /* Need to register some event callback function for enabling drag and
4501 drop in Navigation Service dialogs. */
4503 mac_nav_event_callback (selector
, parms
, data
)
4504 NavEventCallbackMessage selector
;
4512 /************************************************************************
4514 ************************************************************************/
4516 #if !TARGET_API_MAC_CARBON
4517 #include <MacTypes.h>
4519 #include <Quickdraw.h>
4520 #include <ToolUtils.h>
4522 #include <Controls.h>
4523 #include <Windows.h>
4525 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4526 #include <ControlDefinitions.h>
4528 #endif /* not TARGET_API_MAC_CARBON */
4530 extern int menu_item_selection
;
4531 extern int popup_activated_flag
;
4532 extern int name_is_separator
P_ ((const char *));
4533 extern void find_and_call_menu_selection
P_ ((FRAME_PTR
, int, Lisp_Object
,
4535 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
4537 enum mac_menu_kind
{ /* Menu ID range */
4538 MAC_MENU_APPLE
, /* 0 (Reserved by Apple) */
4539 MAC_MENU_MENU_BAR
, /* 1 .. 233 */
4540 MAC_MENU_M_APPLE
, /* 234 (== M_APPLE) */
4541 MAC_MENU_POPUP
, /* 235 */
4542 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
4543 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
4544 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
4545 MAC_MENU_END
/* 32768 */
4548 static const int min_menu_id
[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4550 static int fill_menu
P_ ((MenuRef
, widget_value
*, enum mac_menu_kind
, int));
4551 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
4553 #if !TARGET_API_MAC_CARBON
4555 do_apple_menu (SInt16 menu_item
)
4558 SInt16 da_driver_refnum
;
4560 if (menu_item
== I_ABOUT
)
4561 NoteAlert (ABOUT_ALERT_ID
, NULL
);
4564 GetMenuItemText (GetMenuRef (M_APPLE
), menu_item
, item_name
);
4565 da_driver_refnum
= OpenDeskAcc (item_name
);
4568 #endif /* !TARGET_API_MAC_CARBON */
4570 /* Activate the menu bar of frame F.
4571 This is called from keyboard.c when it gets the
4572 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4574 To activate the menu bar, we use the button-press event location
4575 that was saved in saved_menu_event_location.
4577 But first we recompute the menu bar contents (the whole tree).
4579 The reason for saving the button event until here, instead of
4580 passing it to the toolkit right away, is that we can safely
4581 execute Lisp code. */
4584 x_activate_menubar (f
)
4588 SInt16 menu_id
, menu_item
;
4590 set_frame_menubar (f
, 0, 1);
4593 popup_activated_flag
= 1;
4594 menu_choice
= MenuSelect (saved_menu_event_location
);
4595 popup_activated_flag
= 0;
4596 menu_id
= HiWord (menu_choice
);
4597 menu_item
= LoWord (menu_choice
);
4599 #if !TARGET_API_MAC_CARBON
4600 if (menu_id
== min_menu_id
[MAC_MENU_M_APPLE
])
4601 do_apple_menu (menu_item
);
4606 MenuRef menu
= GetMenuRef (menu_id
);
4612 GetMenuItemRefCon (menu
, menu_item
, &refcon
);
4613 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
4614 f
->menu_bar_vector
, (void *) refcon
);
4623 #if TARGET_API_MAC_CARBON
4624 extern Lisp_Object Vshow_help_function
;
4627 restore_show_help_function (old_show_help_function
)
4628 Lisp_Object old_show_help_function
;
4630 Vshow_help_function
= old_show_help_function
;
4635 static pascal OSStatus
4636 menu_target_item_handler (next_handler
, event
, data
)
4637 EventHandlerCallRef next_handler
;
4643 MenuItemIndex menu_item
;
4646 int specpdl_count
= SPECPDL_INDEX ();
4648 /* Don't be bothered with the overflowed toolbar items menu. */
4649 if (!popup_activated ())
4650 return eventNotHandledErr
;
4652 err
= GetEventParameter (event
, kEventParamDirectObject
, typeMenuRef
,
4653 NULL
, sizeof (MenuRef
), NULL
, &menu
);
4655 err
= GetEventParameter (event
, kEventParamMenuItemIndex
,
4656 typeMenuItemIndex
, NULL
,
4657 sizeof (MenuItemIndex
), NULL
, &menu_item
);
4659 err
= GetMenuItemProperty (menu
, menu_item
,
4660 MAC_EMACS_CREATOR_CODE
, 'help',
4661 sizeof (Lisp_Object
), NULL
, &help
);
4665 /* Temporarily bind Vshow_help_function to Qnil because we don't
4666 want tooltips during menu tracking. */
4667 record_unwind_protect (restore_show_help_function
, Vshow_help_function
);
4668 Vshow_help_function
= Qnil
;
4670 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
4672 unbind_to (specpdl_count
, Qnil
);
4674 return err
== noErr
? noErr
: eventNotHandledErr
;
4677 /* Showing help echo string during menu tracking. */
4680 install_menu_target_item_handler ()
4682 static const EventTypeSpec specs
[] =
4683 {{kEventClassMenu
, kEventMenuTargetItem
}};
4685 return InstallApplicationEventHandler (NewEventHandlerUPP
4686 (menu_target_item_handler
),
4687 GetEventTypeCount (specs
),
4690 #endif /* TARGET_API_MAC_CARBON */
4692 /* Event handler function that pops down a menu on C-g. We can only pop
4693 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4695 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4696 static pascal OSStatus
4697 menu_quit_handler (nextHandler
, theEvent
, userData
)
4698 EventHandlerCallRef nextHandler
;
4704 UInt32 keyModifiers
;
4706 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
4707 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
4710 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
4711 typeUInt32
, NULL
, sizeof(UInt32
),
4712 NULL
, &keyModifiers
);
4714 if (err
== noErr
&& mac_quit_char_key_p (keyModifiers
, keyCode
))
4716 MenuRef menu
= userData
!= 0
4717 ? (MenuRef
)userData
: AcquireRootMenu ();
4719 CancelMenuTracking (menu
, true, 0);
4720 if (!userData
) ReleaseMenu (menu
);
4724 return CallNextEventHandler (nextHandler
, theEvent
);
4726 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4728 /* Add event handler to all menus that belong to KIND so we can detect
4729 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4730 when C-g is detected. NULL means the menu bar. If
4731 CancelMenuTracking isn't available, do nothing. */
4734 install_menu_quit_handler (kind
, root_menu
)
4735 enum mac_menu_kind kind
;
4738 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4739 static const EventTypeSpec typesList
[] =
4740 {{kEventClassKeyboard
, kEventRawKeyDown
}};
4743 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4744 if (CancelMenuTracking
== NULL
)
4747 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
4749 MenuRef menu
= GetMenuRef (id
);
4753 InstallMenuEventHandler (menu
, menu_quit_handler
,
4754 GetEventTypeCount (typesList
),
4755 typesList
, root_menu
, NULL
);
4757 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4764 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
4765 FRAME_PTR f
= p
->pointer
;
4766 MenuRef menu
= GetMenuRef (min_menu_id
[MAC_MENU_POPUP
]);
4770 /* Must reset this manually because the button release event is not
4771 passed to Emacs event loop. */
4772 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
4774 /* delete all menus */
4775 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
4776 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
4784 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4785 until the menu pops down. Return the selection. */
4788 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
4790 widget_value
*first_wv
;
4796 MenuRef menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
4797 int menu_item_choice
;
4798 int specpdl_count
= SPECPDL_INDEX ();
4800 InsertMenu (menu
, -1);
4801 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
4802 min_menu_id
[MAC_MENU_POPUP_SUB
]);
4804 /* Add event handler so we can detect C-g. */
4805 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
4806 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
4808 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
4810 /* Adjust coordinates to be root-window-relative. */
4811 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
4812 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
4814 /* Display the menu. */
4815 popup_activated_flag
= 1;
4816 menu_item_choice
= PopUpMenuSelect (menu
, y
, x
, 0);
4817 popup_activated_flag
= 0;
4819 /* Get the refcon to find the correct item */
4820 if (menu_item_choice
)
4822 MenuRef sel_menu
= GetMenuRef (HiWord (menu_item_choice
));
4825 GetMenuItemRefCon (sel_menu
, LoWord (menu_item_choice
),
4826 (UInt32
*) &result
);
4829 unbind_to (specpdl_count
, Qnil
);
4831 menu_item_selection
= result
;
4835 add_menu_item (menu
, pos
, wv
)
4840 #if TARGET_API_MAC_CARBON
4841 CFStringRef item_name
;
4846 if (name_is_separator (wv
->name
))
4847 AppendMenu (menu
, "\p-");
4850 AppendMenu (menu
, "\pX");
4852 #if TARGET_API_MAC_CARBON
4853 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
4855 if (wv
->key
!= NULL
)
4857 CFStringRef name
, key
;
4860 key
= cfstring_create_with_utf8_cstring (wv
->key
);
4861 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
4867 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
4868 CFRelease (item_name
);
4871 EnableMenuItem (menu
, pos
);
4873 DisableMenuItem (menu
, pos
);
4875 if (STRINGP (wv
->help
))
4876 SetMenuItemProperty (menu
, pos
, MAC_EMACS_CREATOR_CODE
, 'help',
4877 sizeof (Lisp_Object
), &wv
->help
);
4878 #else /* ! TARGET_API_MAC_CARBON */
4879 item_name
[sizeof (item_name
) - 1] = '\0';
4880 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
4881 if (wv
->key
!= NULL
)
4883 int len
= strlen (item_name
);
4885 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
4886 len
= strlen (item_name
);
4887 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
4890 SetMenuItemText (menu
, pos
, item_name
);
4893 EnableItem (menu
, pos
);
4895 DisableItem (menu
, pos
);
4896 #endif /* ! TARGET_API_MAC_CARBON */
4898 /* Draw radio buttons and tickboxes. */
4899 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
4900 || wv
->button_type
== BUTTON_TYPE_RADIO
))
4901 SetItemMark (menu
, pos
, checkMark
);
4903 SetItemMark (menu
, pos
, noMark
);
4905 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
4909 /* Construct native Mac OS menu based on widget_value tree. */
4912 fill_menu (menu
, wv
, kind
, submenu_id
)
4915 enum mac_menu_kind kind
;
4920 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
4922 add_menu_item (menu
, pos
, wv
);
4923 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
4925 MenuRef submenu
= NewMenu (submenu_id
, "\pX");
4927 InsertMenu (submenu
, -1);
4928 #if TARGET_API_MAC_CARBON
4929 SetMenuItemHierarchicalMenu (menu
, pos
, submenu
);
4931 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
4933 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
4940 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4941 the entire menu trees we supply, rather than just the menu bar item
4945 mac_fill_menubar (wv
, deep_p
)
4950 #if !TARGET_API_MAC_CARBON
4951 int title_changed_p
= 0;
4954 /* Clean up the menu bar when filled by the entire menu trees. */
4957 dispose_menus (MAC_MENU_MENU_BAR
, 0);
4958 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
4959 #if !TARGET_API_MAC_CARBON
4960 title_changed_p
= 1;
4964 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4965 titles as much as possible to minimize redraw (if !deep_p). */
4966 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
4967 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
4968 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
4969 wv
= wv
->next
, id
++)
4971 OSStatus err
= noErr
;
4973 #if TARGET_API_MAC_CARBON
4976 title
= CFStringCreateWithCString (NULL
, wv
->name
,
4977 kCFStringEncodingMacRoman
);
4981 strncpy (title
, wv
->name
, 255);
4986 menu
= GetMenuRef (id
);
4989 #if TARGET_API_MAC_CARBON
4990 CFStringRef old_title
;
4992 err
= CopyMenuTitleAsCFString (menu
, &old_title
);
4995 if (CFStringCompare (title
, old_title
, 0) != kCFCompareEqualTo
)
4998 if (id
+ 1 == min_menu_id
[MAC_MENU_MENU_BAR
+ 1]
4999 || GetMenuRef (id
+ 1) == NULL
)
5001 /* This is a workaround for Mac OS X 10.5 where
5002 just calling SetMenuTitleWithCFString fails
5003 to change the title of the last (Help) menu
5010 #endif /* MAC_OSX */
5011 err
= SetMenuTitleWithCFString (menu
, title
);
5013 CFRelease (old_title
);
5016 err
= SetMenuTitleWithCFString (menu
, title
);
5017 #else /* !TARGET_API_MAC_CARBON */
5018 if (!EqualString (title
, (*menu
)->menuData
, false, false))
5022 menu
= NewMenu (id
, title
);
5023 InsertMenu (menu
, GetMenuRef (id
+ 1) ? id
+ 1 : 0);
5024 title_changed_p
= 1;
5026 #endif /* !TARGET_API_MAC_CARBON */
5031 #if TARGET_API_MAC_CARBON
5032 err
= CreateNewMenu (id
, 0, &menu
);
5034 err
= SetMenuTitleWithCFString (menu
, title
);
5036 menu
= NewMenu (id
, title
);
5040 InsertMenu (menu
, 0);
5041 #if !TARGET_API_MAC_CARBON
5042 title_changed_p
= 1;
5046 #if TARGET_API_MAC_CARBON
5052 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
5056 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuRef (id
))
5058 dispose_menus (MAC_MENU_MENU_BAR
, id
);
5059 #if !TARGET_API_MAC_CARBON
5060 title_changed_p
= 1;
5064 #if !TARGET_API_MAC_CARBON
5065 if (title_changed_p
)
5069 /* Add event handler so we can detect C-g. */
5070 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
5071 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
5074 /* Dispose of menus that belong to KIND, and remove them from the menu
5075 list. ID is the lower bound of menu IDs that will be processed. */
5078 dispose_menus (kind
, id
)
5079 enum mac_menu_kind kind
;
5082 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
5084 MenuRef menu
= GetMenuRef (id
);
5099 MenuItemIndex menu_index
;
5101 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandQuit
, 1,
5102 &menu
, &menu_index
);
5104 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5105 EnableMenuCommand (NULL
, kHICommandPreferences
);
5106 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandPreferences
, 1,
5107 &menu
, &menu_index
);
5110 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5111 InsertMenuItemTextWithCFString (menu
, NULL
,
5112 0, kMenuItemAttrSeparator
, 0);
5113 InsertMenuItemTextWithCFString (menu
, CFSTR ("About Emacs"),
5114 0, 0, kHICommandAbout
);
5116 #else /* !MAC_OSX */
5117 #if TARGET_API_MAC_CARBON
5118 SetMenuItemCommandID (GetMenuRef (M_APPLE
), I_ABOUT
, kHICommandAbout
);
5124 /***********************************************************************
5126 ***********************************************************************/
5128 #if TARGET_API_MAC_CARBON
5129 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5130 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5131 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5132 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5133 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5134 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5135 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5137 extern EMACS_TIME timer_check
P_ ((int));
5138 static int quit_dialog_event_loop
;
5140 static pascal OSStatus
5141 mac_handle_dialog_event (next_handler
, event
, data
)
5142 EventHandlerCallRef next_handler
;
5146 OSStatus err
, result
= eventNotHandledErr
;
5147 WindowRef window
= (WindowRef
) data
;
5149 switch (GetEventClass (event
))
5151 case kEventClassCommand
:
5155 err
= GetEventParameter (event
, kEventParamDirectObject
,
5156 typeHICommand
, NULL
, sizeof (HICommand
),
5159 if (DIALOG_BUTTON_COMMAND_ID_P (command
.commandID
))
5161 SetWRefCon (window
, command
.commandID
);
5162 quit_dialog_event_loop
= 1;
5166 result
= CallNextEventHandler (next_handler
, event
);
5170 case kEventClassKeyboard
:
5175 result
= CallNextEventHandler (next_handler
, event
);
5176 if (result
!= eventNotHandledErr
)
5179 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
5180 typeChar
, NULL
, sizeof (char),
5185 case kEscapeCharCode
:
5186 quit_dialog_event_loop
= 1;
5191 UInt32 modifiers
, key_code
;
5193 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
5194 typeUInt32
, NULL
, sizeof (UInt32
),
5197 err
= GetEventParameter (event
, kEventParamKeyCode
,
5198 typeUInt32
, NULL
, sizeof (UInt32
),
5201 if (mac_quit_char_key_p (modifiers
, key_code
))
5202 quit_dialog_event_loop
= 1;
5213 if (quit_dialog_event_loop
)
5215 err
= QuitEventLoop (GetCurrentEventLoop ());
5224 install_dialog_event_handler (window
)
5227 static const EventTypeSpec specs
[] =
5228 {{kEventClassCommand
, kEventCommandProcess
},
5229 {kEventClassKeyboard
, kEventRawKeyDown
}};
5230 static EventHandlerUPP handle_dialog_eventUPP
= NULL
;
5232 if (handle_dialog_eventUPP
== NULL
)
5233 handle_dialog_eventUPP
= NewEventHandlerUPP (mac_handle_dialog_event
);
5234 return InstallWindowEventHandler (window
, handle_dialog_eventUPP
,
5235 GetEventTypeCount (specs
), specs
,
5240 pop_down_dialog (arg
)
5243 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
5244 WindowRef window
= p
->pointer
;
5248 if (popup_activated_flag
)
5249 EndAppModalStateForWindow (window
);
5250 DisposeWindow (window
);
5251 popup_activated_flag
= 0;
5258 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5260 menu_item_selection will be set to the selection. */
5263 create_and_show_dialog (f
, first_wv
)
5265 widget_value
*first_wv
;
5268 char *dialog_name
, *message
;
5269 int nb_buttons
, first_group_count
, i
, result
= 0;
5271 short buttons_height
, text_height
, inner_width
, inner_height
;
5272 Rect empty_rect
, *rects
;
5273 WindowRef window
= NULL
;
5274 ControlRef
*buttons
, default_button
= NULL
, text
;
5275 int specpdl_count
= SPECPDL_INDEX ();
5277 dialog_name
= first_wv
->name
;
5278 nb_buttons
= dialog_name
[1] - '0';
5279 first_group_count
= nb_buttons
- (dialog_name
[4] - '0');
5281 wv
= first_wv
->contents
;
5282 message
= wv
->value
;
5285 SetRect (&empty_rect
, 0, 0, 0, 0);
5287 /* Create dialog window. */
5288 err
= CreateNewWindow (kMovableModalWindowClass
,
5289 kWindowStandardHandlerAttribute
,
5290 &empty_rect
, &window
);
5293 record_unwind_protect (pop_down_dialog
, make_save_value (window
, 0));
5294 err
= SetThemeWindowBackground (window
, kThemeBrushMovableModalBackground
,
5298 err
= SetWindowTitleWithCFString (window
, (dialog_name
[0] == 'Q'
5299 ? CFSTR ("Question")
5300 : CFSTR ("Information")));
5302 /* Create button controls and measure their optimal bounds. */
5305 buttons
= alloca (sizeof (ControlRef
) * nb_buttons
);
5306 rects
= alloca (sizeof (Rect
) * nb_buttons
);
5307 for (i
= 0; i
< nb_buttons
; i
++)
5309 CFStringRef label
= cfstring_create_with_utf8_cstring (wv
->value
);
5315 err
= CreatePushButtonControl (window
, &empty_rect
,
5316 label
, &buttons
[i
]);
5324 err
= DisableControl (buttons
[i
]);
5326 err
= DeactivateControl (buttons
[i
]);
5329 else if (default_button
== NULL
)
5330 default_button
= buttons
[i
];
5336 rects
[i
] = empty_rect
;
5337 err
= GetBestControlRect (buttons
[i
], &rects
[i
], &unused
);
5343 OffsetRect (&rects
[i
], -rects
[i
].left
, -rects
[i
].top
);
5344 if (rects
[i
].right
< DIALOG_BUTTON_MIN_WIDTH
)
5345 rects
[i
].right
= DIALOG_BUTTON_MIN_WIDTH
;
5346 else if (rects
[i
].right
> DIALOG_MAX_INNER_WIDTH
)
5347 rects
[i
].right
= DIALOG_MAX_INNER_WIDTH
;
5349 command_id
= DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv
->call_data
);
5350 err
= SetControlCommandID (buttons
[i
], command_id
);
5358 /* Layout buttons. rects[i] is set relative to the bottom-right
5359 corner of the inner box. */
5362 short bottom
, right
, max_height
, left_align_shift
;
5364 inner_width
= DIALOG_MIN_INNER_WIDTH
;
5365 bottom
= right
= max_height
= 0;
5366 for (i
= 0; i
< nb_buttons
; i
++)
5368 if (right
- rects
[i
].right
< - inner_width
)
5370 if (i
!= first_group_count
5371 && right
- rects
[i
].right
>= - DIALOG_MAX_INNER_WIDTH
)
5372 inner_width
= - (right
- rects
[i
].right
);
5375 bottom
-= max_height
+ DIALOG_BUTTON_BUTTON_VERTICAL_SPACE
;
5376 right
= max_height
= 0;
5379 if (max_height
< rects
[i
].bottom
)
5380 max_height
= rects
[i
].bottom
;
5381 OffsetRect (&rects
[i
], right
- rects
[i
].right
,
5382 bottom
- rects
[i
].bottom
);
5383 right
= rects
[i
].left
- DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5384 if (i
== first_group_count
- 1)
5385 right
-= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5387 buttons_height
= - (bottom
- max_height
);
5389 left_align_shift
= - (inner_width
+ rects
[nb_buttons
- 1].left
);
5390 for (i
= nb_buttons
- 1; i
>= first_group_count
; i
--)
5392 if (bottom
!= rects
[i
].bottom
)
5394 left_align_shift
= - (inner_width
+ rects
[i
].left
);
5395 bottom
= rects
[i
].bottom
;
5397 OffsetRect (&rects
[i
], left_align_shift
, 0);
5401 /* Create a static text control and measure its bounds. */
5404 CFStringRef message_string
;
5407 message_string
= cfstring_create_with_utf8_cstring (message
);
5408 if (message_string
== NULL
)
5412 ControlFontStyleRec text_style
;
5414 text_style
.flags
= 0;
5415 SetRect (&bounds
, 0, 0, inner_width
, 0);
5416 err
= CreateStaticTextControl (window
, &bounds
, message_string
,
5417 &text_style
, &text
);
5418 CFRelease (message_string
);
5424 bounds
= empty_rect
;
5425 err
= GetBestControlRect (text
, &bounds
, &unused
);
5429 text_height
= bounds
.bottom
- bounds
.top
;
5430 if (text_height
< DIALOG_TEXT_MIN_HEIGHT
)
5431 text_height
= DIALOG_TEXT_MIN_HEIGHT
;
5435 /* Place buttons. */
5438 inner_height
= (text_height
+ DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5441 for (i
= 0; i
< nb_buttons
; i
++)
5443 OffsetRect (&rects
[i
], DIALOG_LEFT_MARGIN
+ inner_width
,
5444 DIALOG_TOP_MARGIN
+ inner_height
);
5445 SetControlBounds (buttons
[i
], &rects
[i
]);
5454 SetRect (&bounds
, DIALOG_LEFT_MARGIN
, DIALOG_TOP_MARGIN
,
5455 DIALOG_LEFT_MARGIN
+ inner_width
,
5456 DIALOG_TOP_MARGIN
+ text_height
);
5457 SetControlBounds (text
, &bounds
);
5460 /* Create the application icon at the upper-left corner. */
5463 ControlButtonContentInfo content
;
5465 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
5469 ProcessInfoRec pinfo
;
5474 content
.contentType
= kControlContentIconRef
;
5476 err
= GetProcessBundleLocation (&psn
, &app_location
);
5478 err
= GetIconRefFromFileInfo (&app_location
, 0, NULL
, 0, NULL
,
5479 kIconServicesNormalUsageFlag
,
5480 &content
.u
.iconRef
, &unused
);
5482 bzero (&pinfo
, sizeof (ProcessInfoRec
));
5483 pinfo
.processInfoLength
= sizeof (ProcessInfoRec
);
5484 pinfo
.processAppSpec
= &app_spec
;
5485 err
= GetProcessInformation (&psn
, &pinfo
);
5487 err
= GetIconRefFromFile (&app_spec
, &content
.u
.iconRef
, &unused
);
5493 SetRect (&bounds
, DIALOG_ICON_LEFT_MARGIN
, DIALOG_ICON_TOP_MARGIN
,
5494 DIALOG_ICON_LEFT_MARGIN
+ DIALOG_ICON_WIDTH
,
5495 DIALOG_ICON_TOP_MARGIN
+ DIALOG_ICON_HEIGHT
);
5496 err
= CreateIconControl (window
, &bounds
, &content
, true, &icon
);
5497 ReleaseIconRef (content
.u
.iconRef
);
5501 /* Show the dialog window and run event loop. */
5504 err
= SetWindowDefaultButton (window
, default_button
);
5506 err
= install_dialog_event_handler (window
);
5510 DIALOG_LEFT_MARGIN
+ inner_width
+ DIALOG_RIGHT_MARGIN
,
5511 DIALOG_TOP_MARGIN
+ inner_height
+ DIALOG_BOTTOM_MARGIN
,
5513 err
= RepositionWindow (window
, FRAME_MAC_WINDOW (f
),
5514 kWindowAlertPositionOnParentWindow
);
5518 SetWRefCon (window
, 0);
5519 ShowWindow (window
);
5520 BringToFront (window
);
5521 popup_activated_flag
= 1;
5522 err
= BeginAppModalStateForWindow (window
);
5526 EventTargetRef toolbox_dispatcher
= GetEventDispatcherTarget ();
5528 quit_dialog_event_loop
= 0;
5531 EMACS_TIME next_time
= timer_check (1);
5532 long secs
= EMACS_SECS (next_time
);
5533 long usecs
= EMACS_USECS (next_time
);
5534 EventTimeout timeout
;
5537 if (secs
< 0 || (secs
== 0 && usecs
== 0))
5539 /* Sometimes timer_check returns -1 (no timers) even if
5540 there are timers. So do a timeout anyway. */
5545 timeout
= (secs
* kEventDurationSecond
5546 + usecs
* kEventDurationMicrosecond
);
5547 err
= ReceiveNextEvent (0, NULL
, timeout
, kEventRemoveFromQueue
,
5551 SendEventToEventTarget (event
, toolbox_dispatcher
);
5552 ReleaseEvent (event
);
5554 #if 0 /* defined (MAC_OSX) */
5555 else if (err
!= eventLoopTimedOutErr
)
5557 if (err
== eventLoopQuitErr
)
5562 /* The return value of ReceiveNextEvent seems to be
5563 unreliable. Use our own global variable instead. */
5564 if (quit_dialog_event_loop
)
5574 UInt32 command_id
= GetWRefCon (window
);
5576 if (DIALOG_BUTTON_COMMAND_ID_P (command_id
))
5577 result
= DIALOG_BUTTON_COMMAND_ID_VALUE (command_id
);
5580 unbind_to (specpdl_count
, Qnil
);
5582 menu_item_selection
= result
;
5584 #else /* not TARGET_API_MAC_CARBON */
5585 #define DIALOG_WINDOW_RESOURCE 130
5588 mac_dialog (widget_value
*wv
)
5592 char **button_labels
;
5599 WindowRef window_ptr
;
5602 EventRecord event_record
;
5604 int control_part_code
;
5607 dialog_name
= wv
->name
;
5608 nb_buttons
= dialog_name
[1] - '0';
5609 left_count
= nb_buttons
- (dialog_name
[4] - '0');
5610 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
5611 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
5614 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
5615 strcpy (prompt
, wv
->value
);
5619 for (i
= 0; i
< nb_buttons
; i
++)
5621 button_labels
[i
] = wv
->value
;
5622 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
5623 strcpy (button_labels
[i
], wv
->value
);
5624 c2pstr (button_labels
[i
]);
5625 ref_cons
[i
] = (UInt32
) wv
->call_data
;
5629 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowRef
) -1);
5631 SetPortWindowPort (window_ptr
);
5634 /* Left and right margins in the dialog are 13 pixels each.*/
5636 /* Calculate width of dialog box: 8 pixels on each side of the text
5637 label in each button, 12 pixels between buttons. */
5638 for (i
= 0; i
< nb_buttons
; i
++)
5639 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
5641 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
5644 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
5646 SizeWindow (window_ptr
, dialog_width
, 78, 0);
5647 ShowWindow (window_ptr
);
5649 SetPortWindowPort (window_ptr
);
5654 DrawString (prompt
);
5657 for (i
= 0; i
< nb_buttons
; i
++)
5659 int button_width
= StringWidth (button_labels
[i
]) + 16;
5660 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
5661 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
5662 kControlPushButtonProc
, ref_cons
[i
]);
5663 left
+= button_width
+ 12;
5664 if (i
== left_count
- 1)
5671 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
5672 if (event_record
.what
== mouseDown
)
5674 part_code
= FindWindow (event_record
.where
, &window_ptr
);
5675 if (part_code
== inContent
)
5677 mouse
= event_record
.where
;
5678 GlobalToLocal (&mouse
);
5679 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
5680 if (control_part_code
== kControlButtonPart
)
5681 if (TrackControl (ch
, mouse
, NULL
))
5682 i
= GetControlReference (ch
);
5687 DisposeWindow (window_ptr
);
5691 #endif /* not TARGET_API_MAC_CARBON */
5694 /***********************************************************************
5696 ***********************************************************************/
5698 #if !TARGET_API_MAC_CARBON
5703 extern Lisp_Object Vselection_converter_alist
;
5704 extern Lisp_Object Qmac_scrap_name
, Qmac_ostype
;
5706 static ScrapFlavorType get_flavor_type_from_symbol
P_ ((Lisp_Object
,
5709 /* Get a reference to the selection corresponding to the symbol SYM.
5710 The reference is set to *SEL, and it becomes NULL if there's no
5711 corresponding selection. Clear the selection if CLEAR_P is
5715 mac_get_selection_from_symbol (sym
, clear_p
, sel
)
5720 OSStatus err
= noErr
;
5721 Lisp_Object str
= Fget (sym
, Qmac_scrap_name
);
5727 #if TARGET_API_MAC_CARBON
5729 CFStringRef scrap_name
= cfstring_create_with_string (str
);
5730 OptionBits options
= (clear_p
? kScrapClearNamedScrap
5731 : kScrapGetNamedScrap
);
5733 err
= GetScrapByName (scrap_name
, options
, sel
);
5734 CFRelease (scrap_name
);
5735 #else /* !MAC_OSX */
5737 err
= ClearCurrentScrap ();
5739 err
= GetCurrentScrap (sel
);
5740 #endif /* !MAC_OSX */
5741 #else /* !TARGET_API_MAC_CARBON */
5746 #endif /* !TARGET_API_MAC_CARBON */
5752 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5753 corresponding flavor type. If SEL is non-zero, the return value is
5754 non-zero only when the SEL has the flavor type. */
5756 static ScrapFlavorType
5757 get_flavor_type_from_symbol (sym
, sel
)
5761 Lisp_Object str
= Fget (sym
, Qmac_ostype
);
5762 ScrapFlavorType flavor_type
;
5764 if (STRINGP (str
) && SBYTES (str
) == 4)
5765 flavor_type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
5769 if (flavor_type
&& sel
)
5771 #if TARGET_API_MAC_CARBON
5773 ScrapFlavorFlags flags
;
5775 err
= GetScrapFlavorFlags (sel
, flavor_type
, &flags
);
5778 #else /* !TARGET_API_MAC_CARBON */
5779 SInt32 size
, offset
;
5781 size
= GetScrap (NULL
, flavor_type
, &offset
);
5784 #endif /* !TARGET_API_MAC_CARBON */
5790 /* Check if the symbol SYM has a corresponding selection target type. */
5793 mac_valid_selection_target_p (sym
)
5796 return get_flavor_type_from_symbol (sym
, 0) != 0;
5799 /* Clear the selection whose reference is *SEL. */
5802 mac_clear_selection (sel
)
5805 #if TARGET_API_MAC_CARBON
5807 return ClearScrap (sel
);
5811 err
= ClearCurrentScrap ();
5813 err
= GetCurrentScrap (sel
);
5816 #else /* !TARGET_API_MAC_CARBON */
5817 return ZeroScrap ();
5818 #endif /* !TARGET_API_MAC_CARBON */
5821 /* Get ownership information for SEL. Emacs can detect a change of
5822 the ownership by comparing saved and current values of the
5823 ownership information. */
5826 mac_get_selection_ownership_info (sel
)
5829 #if TARGET_API_MAC_CARBON
5830 return long_to_cons ((unsigned long) sel
);
5831 #else /* !TARGET_API_MAC_CARBON */
5832 ScrapStuffPtr scrap_info
= InfoScrap ();
5834 return make_number (scrap_info
->scrapCount
);
5835 #endif /* !TARGET_API_MAC_CARBON */
5838 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5841 mac_valid_selection_value_p (value
, target
)
5842 Lisp_Object value
, target
;
5844 return STRINGP (value
);
5847 /* Put Lisp object VALUE to the selection SEL. The target type is
5848 specified by TARGET. */
5851 mac_put_selection_value (sel
, target
, value
)
5853 Lisp_Object target
, value
;
5855 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, 0);
5857 if (flavor_type
== 0 || !STRINGP (value
))
5860 #if TARGET_API_MAC_CARBON
5861 return PutScrapFlavor (sel
, flavor_type
, kScrapFlavorMaskNone
,
5862 SBYTES (value
), SDATA (value
));
5863 #else /* !TARGET_API_MAC_CARBON */
5864 return PutScrap (SBYTES (value
), flavor_type
, SDATA (value
));
5865 #endif /* !TARGET_API_MAC_CARBON */
5868 /* Check if data for the target type TARGET is available in SEL. */
5871 mac_selection_has_target_p (sel
, target
)
5875 return get_flavor_type_from_symbol (target
, sel
) != 0;
5878 /* Get data for the target type TARGET from SEL and create a Lisp
5879 string. Return nil if failed to get data. */
5882 mac_get_selection_value (sel
, target
)
5887 Lisp_Object result
= Qnil
;
5888 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, sel
);
5889 #if TARGET_API_MAC_CARBON
5894 err
= GetScrapFlavorSize (sel
, flavor_type
, &size
);
5899 result
= make_uninit_string (size
);
5900 err
= GetScrapFlavorData (sel
, flavor_type
,
5901 &size
, SDATA (result
));
5904 else if (size
< SBYTES (result
))
5905 result
= make_unibyte_string (SDATA (result
), size
);
5907 while (STRINGP (result
) && size
> SBYTES (result
));
5912 SInt32 size
, offset
;
5915 size
= GetScrap (NULL
, flavor_type
, &offset
);
5918 handle
= NewHandle (size
);
5920 size
= GetScrap (handle
, flavor_type
, &offset
);
5922 result
= make_unibyte_string (*handle
, size
);
5923 DisposeHandle (handle
);
5930 /* Get the list of target types in SEL. The return value is a list of
5931 target type symbols possibly followed by scrap flavor type
5935 mac_get_selection_target_list (sel
)
5938 Lisp_Object result
= Qnil
, rest
, target
;
5939 #if TARGET_API_MAC_CARBON
5941 UInt32 count
, i
, type
;
5942 ScrapFlavorInfo
*flavor_info
= NULL
;
5943 Lisp_Object strings
= Qnil
;
5945 err
= GetScrapFlavorCount (sel
, &count
);
5947 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
5948 err
= GetScrapFlavorInfoList (sel
, &count
, flavor_info
);
5951 xfree (flavor_info
);
5954 if (flavor_info
== NULL
)
5957 for (rest
= Vselection_converter_alist
; CONSP (rest
); rest
= XCDR (rest
))
5959 ScrapFlavorType flavor_type
= 0;
5961 if (CONSP (XCAR (rest
))
5962 && (target
= XCAR (XCAR (rest
)),
5964 && (flavor_type
= get_flavor_type_from_symbol (target
, sel
)))
5966 result
= Fcons (target
, result
);
5967 #if TARGET_API_MAC_CARBON
5968 for (i
= 0; i
< count
; i
++)
5969 if (flavor_info
[i
].flavorType
== flavor_type
)
5971 flavor_info
[i
].flavorType
= 0;
5977 #if TARGET_API_MAC_CARBON
5980 for (i
= 0; i
< count
; i
++)
5981 if (flavor_info
[i
].flavorType
)
5983 type
= EndianU32_NtoB (flavor_info
[i
].flavorType
);
5984 strings
= Fcons (make_unibyte_string ((char *) &type
, 4), strings
);
5986 result
= nconc2 (result
, strings
);
5987 xfree (flavor_info
);
5995 /***********************************************************************
5997 ***********************************************************************/
5999 extern pascal OSErr mac_handle_apple_event
P_ ((const AppleEvent
*,
6000 AppleEvent
*, SInt32
));
6001 extern void cleanup_all_suspended_apple_events
P_ ((void));
6004 init_apple_event_handler ()
6009 /* Make sure we have Apple events before starting. */
6010 err
= Gestalt (gestaltAppleEventsAttr
, &result
);
6014 if (!(result
& (1 << gestaltAppleEventsPresent
)))
6017 err
= AEInstallEventHandler (typeWildCard
, typeWildCard
,
6018 #if TARGET_API_MAC_CARBON
6019 NewAEEventHandlerUPP (mac_handle_apple_event
),
6021 NewAEEventHandlerProc (mac_handle_apple_event
),
6027 atexit (cleanup_all_suspended_apple_events
);
6031 /***********************************************************************
6032 Drag and drop support
6033 ***********************************************************************/
6035 #if TARGET_API_MAC_CARBON
6036 extern Lisp_Object Vmac_dnd_known_types
;
6038 static pascal OSErr mac_do_track_drag
P_ ((DragTrackingMessage
, WindowRef
,
6040 static pascal OSErr mac_do_receive_drag
P_ ((WindowRef
, void *, DragRef
));
6041 static DragTrackingHandlerUPP mac_do_track_dragUPP
= NULL
;
6042 static DragReceiveHandlerUPP mac_do_receive_dragUPP
= NULL
;
6045 create_apple_event_from_drag_ref (drag
, num_types
, types
, result
)
6048 const FlavorType
*types
;
6057 err
= CountDragItems (drag
, &num_items
);
6060 err
= AECreateList (NULL
, 0, false, &items
);
6064 for (index
= 1; index
<= num_items
; index
++)
6067 DescType desc_type
= typeNull
;
6070 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6075 for (i
= 0; i
< num_types
; i
++)
6077 err
= GetFlavorDataSize (drag
, item
, types
[i
], &size
);
6080 buf
= xrealloc (buf
, size
);
6081 err
= GetFlavorData (drag
, item
, types
[i
], buf
, &size
, 0);
6085 desc_type
= types
[i
];
6090 err
= AEPutPtr (&items
, index
, desc_type
,
6091 desc_type
!= typeNull
? buf
: NULL
,
6092 desc_type
!= typeNull
? size
: 0);
6101 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
6103 err
= AEPutParamDesc (result
, keyDirectObject
, &items
);
6105 AEDisposeDesc (result
);
6108 AEDisposeDesc (&items
);
6114 mac_store_drag_event (window
, mouse_pos
, modifiers
, desc
)
6120 struct input_event buf
;
6124 buf
.kind
= DRAG_N_DROP_EVENT
;
6125 buf
.modifiers
= mac_to_emacs_modifiers (modifiers
, 0);
6126 buf
.timestamp
= TickCount () * (1000 / 60);
6127 XSETINT (buf
.x
, mouse_pos
.h
);
6128 XSETINT (buf
.y
, mouse_pos
.v
);
6129 XSETFRAME (buf
.frame_or_window
, mac_window_to_frame (window
));
6130 buf
.arg
= mac_aedesc_to_lisp (desc
);
6131 kbd_buffer_store_event (&buf
);
6135 mac_do_track_drag (message
, window
, refcon
, drag
)
6136 DragTrackingMessage message
;
6142 static int can_accept
;
6143 UInt16 num_items
, index
;
6145 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6146 return dragNotAcceptedErr
;
6150 case kDragTrackingEnterHandler
:
6151 err
= CountDragItems (drag
, &num_items
);
6155 for (index
= 1; index
<= num_items
; index
++)
6161 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6164 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6170 if (!(STRINGP (str
) && SBYTES (str
) == 4))
6172 type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6174 err
= GetFlavorFlags (drag
, item
, type
, &flags
);
6184 case kDragTrackingEnterWindow
:
6187 RgnHandle hilite_rgn
= NewRgn ();
6193 GetWindowPortBounds (window
, &r
);
6194 OffsetRect (&r
, -r
.left
, -r
.top
);
6195 RectRgn (hilite_rgn
, &r
);
6196 ShowDragHilite (drag
, hilite_rgn
, true);
6197 DisposeRgn (hilite_rgn
);
6199 SetThemeCursor (kThemeCopyArrowCursor
);
6203 case kDragTrackingInWindow
:
6206 case kDragTrackingLeaveWindow
:
6209 HideDragHilite (drag
);
6210 SetThemeCursor (kThemeArrowCursor
);
6214 case kDragTrackingLeaveHandler
:
6219 return dragNotAcceptedErr
;
6224 mac_do_receive_drag (window
, refcon
, drag
)
6231 Lisp_Object rest
, str
;
6233 AppleEvent apple_event
;
6237 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6238 return dragNotAcceptedErr
;
6241 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6244 if (STRINGP (str
) && SBYTES (str
) == 4)
6248 types
= xmalloc (sizeof (FlavorType
) * num_types
);
6250 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6253 if (STRINGP (str
) && SBYTES (str
) == 4)
6254 types
[i
++] = EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6257 err
= create_apple_event_from_drag_ref (drag
, num_types
, types
,
6262 err
= GetDragMouse (drag
, &mouse_pos
, NULL
);
6265 GlobalToLocal (&mouse_pos
);
6266 err
= GetDragModifiers (drag
, NULL
, NULL
, &modifiers
);
6270 UInt32 key_modifiers
= modifiers
;
6272 err
= AEPutParamPtr (&apple_event
, kEventParamKeyModifiers
,
6273 typeUInt32
, &key_modifiers
, sizeof (UInt32
));
6278 mac_store_drag_event (window
, mouse_pos
, 0, &apple_event
);
6279 AEDisposeDesc (&apple_event
);
6280 mac_wakeup_from_rne ();
6284 return dragNotAcceptedErr
;
6286 #endif /* TARGET_API_MAC_CARBON */
6289 install_drag_handler (window
)
6294 #if TARGET_API_MAC_CARBON
6295 if (mac_do_track_dragUPP
== NULL
)
6296 mac_do_track_dragUPP
= NewDragTrackingHandlerUPP (mac_do_track_drag
);
6297 if (mac_do_receive_dragUPP
== NULL
)
6298 mac_do_receive_dragUPP
= NewDragReceiveHandlerUPP (mac_do_receive_drag
);
6300 err
= InstallTrackingHandler (mac_do_track_dragUPP
, window
, NULL
);
6302 err
= InstallReceiveHandler (mac_do_receive_dragUPP
, window
, NULL
);
6309 remove_drag_handler (window
)
6312 #if TARGET_API_MAC_CARBON
6313 if (mac_do_track_dragUPP
)
6314 RemoveTrackingHandler (mac_do_track_dragUPP
, window
);
6315 if (mac_do_receive_dragUPP
)
6316 RemoveReceiveHandler (mac_do_receive_dragUPP
, window
);
6320 #if TARGET_API_MAC_CARBON
6321 /* Return default value for mac-dnd-known-types. */
6324 mac_dnd_default_known_types ()
6326 Lisp_Object result
= list4 (build_string ("hfs "), build_string ("utxt"),
6327 build_string ("TEXT"), build_string ("TIFF"));
6330 result
= Fcons (build_string ("furl"), result
);
6338 /***********************************************************************
6339 Services menu support
6340 ***********************************************************************/
6343 extern Lisp_Object Qservice
, Qpaste
, Qperform
;
6344 extern Lisp_Object Vmac_service_selection
;
6347 mac_store_service_event (event
)
6353 const EventParamName
*names
;
6354 const EventParamType
*types
;
6355 static const EventParamName names_pfm
[] =
6356 {kEventParamServiceMessageName
, kEventParamServiceUserData
};
6357 static const EventParamType types_pfm
[] =
6358 {typeCFStringRef
, typeCFStringRef
};
6360 switch (GetEventKind (event
))
6362 case kEventServicePaste
:
6369 case kEventServicePerform
:
6371 num_params
= sizeof (names_pfm
) / sizeof (names_pfm
[0]);
6380 err
= mac_store_event_ref_as_apple_event (0, 0, Qservice
, id_key
,
6388 copy_scrap_flavor_data (from_scrap
, to_scrap
, flavor_type
)
6389 ScrapRef from_scrap
, to_scrap
;
6390 ScrapFlavorType flavor_type
;
6393 Size size
, size_allocated
;
6396 err
= GetScrapFlavorSize (from_scrap
, flavor_type
, &size
);
6398 buf
= xmalloc (size
);
6401 size_allocated
= size
;
6402 err
= GetScrapFlavorData (from_scrap
, flavor_type
, &size
, buf
);
6408 else if (size_allocated
< size
)
6409 buf
= xrealloc (buf
, size
);
6419 err
= PutScrapFlavor (to_scrap
, flavor_type
, kScrapFlavorMaskNone
,
6429 mac_handle_service_event (call_ref
, event
, data
)
6430 EventHandlerCallRef call_ref
;
6434 OSStatus err
= noErr
;
6435 ScrapRef cur_scrap
, specific_scrap
;
6436 UInt32 event_kind
= GetEventKind (event
);
6437 CFMutableArrayRef copy_types
, paste_types
;
6440 ScrapFlavorType flavor_type
;
6442 /* Check if Vmac_service_selection is a valid selection that has a
6443 corresponding scrap. */
6444 if (!SYMBOLP (Vmac_service_selection
))
6445 err
= eventNotHandledErr
;
6447 err
= mac_get_selection_from_symbol (Vmac_service_selection
, 0, &cur_scrap
);
6448 if (!(err
== noErr
&& cur_scrap
))
6449 return eventNotHandledErr
;
6453 case kEventServiceGetTypes
:
6454 /* Set paste types. */
6455 err
= GetEventParameter (event
, kEventParamServicePasteTypes
,
6456 typeCFMutableArrayRef
, NULL
,
6457 sizeof (CFMutableArrayRef
), NULL
,
6462 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6464 if (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))
6466 get_flavor_type_from_symbol (XCAR (XCAR (rest
)), 0)))
6468 type
= CreateTypeStringWithOSType (flavor_type
);
6471 CFArrayAppendValue (paste_types
, type
);
6476 /* Set copy types. */
6477 err
= GetEventParameter (event
, kEventParamServiceCopyTypes
,
6478 typeCFMutableArrayRef
, NULL
,
6479 sizeof (CFMutableArrayRef
), NULL
,
6484 if (NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6487 goto copy_all_flavors
;
6489 case kEventServiceCopy
:
6490 err
= GetEventParameter (event
, kEventParamScrapRef
,
6492 sizeof (ScrapRef
), NULL
, &specific_scrap
);
6494 || NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6496 err
= eventNotHandledErr
;
6503 ScrapFlavorInfo
*flavor_info
= NULL
;
6504 ScrapFlavorFlags flags
;
6506 err
= GetScrapFlavorCount (cur_scrap
, &count
);
6508 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
6509 err
= GetScrapFlavorInfoList (cur_scrap
, &count
, flavor_info
);
6512 xfree (flavor_info
);
6515 if (flavor_info
== NULL
)
6518 for (i
= 0; i
< count
; i
++)
6520 flavor_type
= flavor_info
[i
].flavorType
;
6521 err
= GetScrapFlavorFlags (cur_scrap
, flavor_type
, &flags
);
6522 if (err
== noErr
&& !(flags
& kScrapFlavorMaskSenderOnly
))
6524 if (event_kind
== kEventServiceCopy
)
6525 err
= copy_scrap_flavor_data (cur_scrap
, specific_scrap
,
6527 else /* event_kind == kEventServiceGetTypes */
6529 type
= CreateTypeStringWithOSType (flavor_type
);
6532 CFArrayAppendValue (copy_types
, type
);
6538 xfree (flavor_info
);
6542 case kEventServicePaste
:
6543 case kEventServicePerform
:
6545 int data_exists_p
= 0;
6547 err
= GetEventParameter (event
, kEventParamScrapRef
, typeScrapRef
,
6548 NULL
, sizeof (ScrapRef
), NULL
,
6551 err
= mac_clear_selection (&cur_scrap
);
6553 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6556 if (! (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))))
6558 flavor_type
= get_flavor_type_from_symbol (XCAR (XCAR (rest
)),
6560 if (flavor_type
== 0)
6562 err
= copy_scrap_flavor_data (specific_scrap
, cur_scrap
,
6568 err
= eventNotHandledErr
;
6570 err
= mac_store_service_event (event
);
6576 err
= eventNotHandledErr
;
6581 install_service_handler ()
6583 static const EventTypeSpec specs
[] =
6584 {{kEventClassService
, kEventServiceGetTypes
},
6585 {kEventClassService
, kEventServiceCopy
},
6586 {kEventClassService
, kEventServicePaste
},
6587 {kEventClassService
, kEventServicePerform
}};
6589 return InstallApplicationEventHandler (NewEventHandlerUPP
6590 (mac_handle_service_event
),
6591 GetEventTypeCount (specs
),
6594 #endif /* MAC_OSX */
6597 /***********************************************************************
6599 ***********************************************************************/
6602 mac_toolbox_initialize ()
6604 any_help_event_p
= 0;
6609 init_apple_event_handler ();
6616 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6617 (do not change this comment) */