Don't require `cl'.
[emacs.git] / src / macterm.c
blob9655b09c819b13ca6f0312ce6038f11f7705515f
1 /* Implementation of GUI terminal on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 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)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; 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. */
22 /* Contributed by Andrew Choi (akochoi@mac.com). */
24 #include <config.h>
25 #include <signal.h>
27 #include <stdio.h>
29 #include "lisp.h"
30 #include "blockinput.h"
32 #include "macterm.h"
34 #ifndef MAC_OSX
35 #include <alloca.h>
36 #endif
38 #if !TARGET_API_MAC_CARBON
39 #include <Quickdraw.h>
40 #include <ToolUtils.h>
41 #include <Sound.h>
42 #include <Events.h>
43 #include <Script.h>
44 #include <Resources.h>
45 #include <Fonts.h>
46 #include <TextUtils.h>
47 #include <LowMem.h>
48 #include <Controls.h>
49 #include <Windows.h>
50 #include <Displays.h>
51 #if defined (__MRC__) || (__MSL__ >= 0x6000)
52 #include <ControlDefinitions.h>
53 #endif
55 #if __profile__
56 #include <profiler.h>
57 #endif
58 #endif /* not TARGET_API_MAC_CARBON */
60 #include "systty.h"
61 #include "systime.h"
63 #include <ctype.h>
64 #include <errno.h>
65 #include <setjmp.h>
66 #include <sys/stat.h>
68 #include "charset.h"
69 #include "coding.h"
70 #include "frame.h"
71 #include "dispextern.h"
72 #include "fontset.h"
73 #include "termhooks.h"
74 #include "termopts.h"
75 #include "termchar.h"
76 #include "disptab.h"
77 #include "buffer.h"
78 #include "window.h"
79 #include "keyboard.h"
80 #include "intervals.h"
81 #include "atimer.h"
82 #include "keymap.h"
86 /* Non-nil means Emacs uses toolkit scroll bars. */
88 Lisp_Object Vx_toolkit_scroll_bars;
90 /* If non-zero, the text will be rendered using Core Graphics text
91 rendering which may anti-alias the text. */
92 int mac_use_core_graphics;
95 /* Non-zero means that a HELP_EVENT has been generated since Emacs
96 start. */
98 static int any_help_event_p;
100 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
101 static Lisp_Object last_window;
103 /* Non-zero means make use of UNDERLINE_POSITION font properties.
104 (Not yet supported.) */
105 int x_use_underline_position_properties;
107 /* Non-zero means to draw the underline at the same place as the descent line. */
109 int x_underline_at_descent_line;
111 /* This is a chain of structures for all the X displays currently in
112 use. */
114 struct x_display_info *x_display_list;
116 /* This is a list of cons cells, each of the form (NAME
117 FONT-LIST-CACHE . RESOURCE-DATABASE), one for each element of
118 x_display_list and in the same order. NAME is the name of the
119 frame. FONT-LIST-CACHE records previous values returned by
120 x-list-fonts. RESOURCE-DATABASE preserves the X Resource Database
121 equivalent, which is implemented with a Lisp object, for the
122 display. */
124 Lisp_Object x_display_name_list;
126 /* This is display since Mac does not support multiple ones. */
127 struct mac_display_info one_mac_display_info;
129 /* Frame being updated by update_frame. This is declared in term.c.
130 This is set by update_begin and looked at by all the XT functions.
131 It is zero while not inside an update. In that case, the XT
132 functions assume that `selected_frame' is the frame to apply to. */
134 extern struct frame *updating_frame;
136 /* This is a frame waiting to be auto-raised, within XTread_socket. */
138 struct frame *pending_autoraise_frame;
140 /* Mouse movement.
142 Formerly, we used PointerMotionHintMask (in standard_event_mask)
143 so that we would have to call XQueryPointer after each MotionNotify
144 event to ask for another such event. However, this made mouse tracking
145 slow, and there was a bug that made it eventually stop.
147 Simply asking for MotionNotify all the time seems to work better.
149 In order to avoid asking for motion events and then throwing most
150 of them away or busy-polling the server for mouse positions, we ask
151 the server for pointer motion hints. This means that we get only
152 one event per group of mouse movements. "Groups" are delimited by
153 other kinds of events (focus changes and button clicks, for
154 example), or by XQueryPointer calls; when one of these happens, we
155 get another MotionNotify event the next time the mouse moves. This
156 is at least as efficient as getting motion events when mouse
157 tracking is on, and I suspect only negligibly worse when tracking
158 is off. */
160 /* Where the mouse was last time we reported a mouse event. */
162 static Rect last_mouse_glyph;
163 static FRAME_PTR last_mouse_glyph_frame;
165 /* The scroll bar in which the last X motion event occurred.
167 If the last X motion event occurred in a scroll bar, we set this so
168 XTmouse_position can know whether to report a scroll bar motion or
169 an ordinary motion.
171 If the last X motion event didn't occur in a scroll bar, we set
172 this to Qnil, to tell XTmouse_position to return an ordinary motion
173 event. */
175 static Lisp_Object last_mouse_scroll_bar;
177 /* This is a hack. We would really prefer that XTmouse_position would
178 return the time associated with the position it returns, but there
179 doesn't seem to be any way to wrest the time-stamp from the server
180 along with the position query. So, we just keep track of the time
181 of the last movement we received, and return that in hopes that
182 it's somewhat accurate. */
184 static Time last_mouse_movement_time;
186 struct scroll_bar *tracked_scroll_bar = NULL;
188 /* Incremented by XTread_socket whenever it really tries to read
189 events. */
191 #ifdef __STDC__
192 static int volatile input_signal_count;
193 #else
194 static int input_signal_count;
195 #endif
197 extern Lisp_Object Vsystem_name;
199 extern Lisp_Object Qeql;
201 /* A mask of extra modifier bits to put into every keyboard char. */
203 extern EMACS_INT extra_keyboard_modifiers;
205 /* The keysyms to use for the various modifiers. */
207 static Lisp_Object Qalt, Qhyper, Qsuper, Qcontrol, Qmeta, Qmodifier_value;
209 extern int inhibit_window_system;
211 #if __MRC__ && !TARGET_API_MAC_CARBON
212 QDGlobals qd; /* QuickDraw global information structure. */
213 #endif
215 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
217 struct mac_display_info *mac_display_info_for_display (Display *);
218 static void x_update_window_end P_ ((struct window *, int, int));
219 int x_catch_errors P_ ((Display *));
220 void x_uncatch_errors P_ ((Display *, int));
221 void x_lower_frame P_ ((struct frame *));
222 void x_scroll_bar_clear P_ ((struct frame *));
223 int x_had_errors_p P_ ((Display *));
224 void x_wm_set_size_hint P_ ((struct frame *, long, int));
225 void x_raise_frame P_ ((struct frame *));
226 void x_set_window_size P_ ((struct frame *, int, int, int));
227 void x_wm_set_window_state P_ ((struct frame *, int));
228 void x_wm_set_icon_pixmap P_ ((struct frame *, int));
229 void mac_initialize P_ ((void));
230 static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
231 static int x_compute_min_glyph_bounds P_ ((struct frame *));
232 static void x_update_end P_ ((struct frame *));
233 static void XTframe_up_to_date P_ ((struct frame *));
234 static void XTset_terminal_modes P_ ((void));
235 static void XTreset_terminal_modes P_ ((void));
236 static void x_clear_frame P_ ((void));
237 static void frame_highlight P_ ((struct frame *));
238 static void frame_unhighlight P_ ((struct frame *));
239 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
240 static void mac_focus_changed P_ ((int, struct mac_display_info *,
241 struct frame *, struct input_event *));
242 static void x_detect_focus_change P_ ((struct mac_display_info *,
243 const EventRecord *,
244 struct input_event *));
245 static void XTframe_rehighlight P_ ((struct frame *));
246 static void x_frame_rehighlight P_ ((struct x_display_info *));
247 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
248 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
249 enum text_cursor_kinds));
251 static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
252 static void x_flush P_ ((struct frame *f));
253 static void x_update_begin P_ ((struct frame *));
254 static void x_update_window_begin P_ ((struct window *));
255 static void x_after_update_window_line P_ ((struct glyph_row *));
256 static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
257 enum scroll_bar_part *,
258 Lisp_Object *, Lisp_Object *,
259 unsigned long *));
261 static int is_emacs_window P_ ((WindowRef));
262 static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int));
263 static void XSetFont P_ ((Display *, GC, XFontStruct *));
265 #define GC_FORE_COLOR(gc) (&(gc)->fore_color)
266 #define GC_BACK_COLOR(gc) (&(gc)->back_color)
267 #define GC_FONT(gc) ((gc)->xgcv.font)
268 #define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
270 #define CG_SET_FILL_COLOR(context, color) \
271 CGContextSetRGBFillColor (context, \
272 RED_FROM_ULONG (color) / 255.0f, \
273 GREEN_FROM_ULONG (color) / 255.0f, \
274 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
275 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
276 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
277 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
278 do { \
279 if (CGColorGetTypeID != NULL) \
280 CGContextSetFillColorWithColor (context, cg_color); \
281 else \
282 CG_SET_FILL_COLOR (context, color); \
283 } while (0)
284 #else
285 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
286 CGContextSetFillColorWithColor (context, cg_color)
287 #endif
288 #else
289 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
290 CG_SET_FILL_COLOR (context, color)
291 #endif
292 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, gc) \
293 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
294 (gc)->cg_fore_color)
295 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, gc) \
296 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.background, \
297 (gc)->cg_back_color)
300 #define CG_SET_STROKE_COLOR(context, color) \
301 CGContextSetRGBStrokeColor (context, \
302 RED_FROM_ULONG (color) / 255.0f, \
303 GREEN_FROM_ULONG (color) / 255.0f, \
304 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
305 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
306 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
307 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
308 do { \
309 if (CGColorGetTypeID != NULL) \
310 CGContextSetStrokeColorWithColor (context, cg_color); \
311 else \
312 CG_SET_STROKE_COLOR (context, color); \
313 } while (0)
314 #else
315 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
316 CGContextSetStrokeColorWithColor (context, cg_color)
317 #endif
318 #else
319 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
320 CG_SET_STROKE_COLOR (context, color)
321 #endif
322 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, gc) \
323 CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
324 (gc)->cg_fore_color)
326 #if USE_CG_DRAWING
327 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
329 /* Fringe bitmaps. */
331 static int max_fringe_bmp = 0;
332 static CGImageRef *fringe_bmp = 0;
334 static CGColorSpaceRef mac_cg_color_space_rgb;
335 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
336 static CGColorRef mac_cg_color_black;
337 #endif
339 static void
340 init_cg_color ()
342 mac_cg_color_space_rgb = CGColorSpaceCreateDeviceRGB ();
343 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
344 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
345 /* Don't check the availability of CGColorCreate; this symbol is
346 defined even in Mac OS X 10.1. */
347 if (CGColorGetTypeID != NULL)
348 #endif
350 float rgba[] = {0.0f, 0.0f, 0.0f, 1.0f};
352 mac_cg_color_black = CGColorCreate (mac_cg_color_space_rgb, rgba);
354 #endif
357 static CGContextRef
358 mac_begin_cg_clip (f, gc)
359 struct frame *f;
360 GC gc;
362 CGContextRef context = FRAME_CG_CONTEXT (f);
364 if (!context)
366 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
367 FRAME_CG_CONTEXT (f) = context;
370 CGContextSaveGState (context);
371 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
372 CGContextScaleCTM (context, 1, -1);
373 if (gc && gc->n_clip_rects)
374 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
376 return context;
379 static void
380 mac_end_cg_clip (f)
381 struct frame *f;
383 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
386 void
387 mac_prepare_for_quickdraw (f)
388 struct frame *f;
390 if (f == NULL)
392 Lisp_Object rest, frame;
393 FOR_EACH_FRAME (rest, frame)
394 if (FRAME_MAC_P (XFRAME (frame)))
395 mac_prepare_for_quickdraw (XFRAME (frame));
397 else
399 CGContextRef context = FRAME_CG_CONTEXT (f);
401 if (context)
403 CGContextSynchronize (context);
404 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
405 &FRAME_CG_CONTEXT (f));
409 #endif
411 static RgnHandle saved_port_clip_region = NULL;
413 static void
414 mac_begin_clip (f, gc)
415 struct frame *f;
416 GC gc;
418 static RgnHandle new_region = NULL;
420 if (saved_port_clip_region == NULL)
421 saved_port_clip_region = NewRgn ();
422 if (new_region == NULL)
423 new_region = NewRgn ();
425 #if USE_CG_DRAWING
426 mac_prepare_for_quickdraw (f);
427 #endif
428 SetPortWindowPort (FRAME_MAC_WINDOW (f));
430 if (gc->n_clip_rects)
432 GetClip (saved_port_clip_region);
433 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
434 SetClip (new_region);
438 static void
439 mac_end_clip (gc)
440 GC gc;
442 if (gc->n_clip_rects)
443 SetClip (saved_port_clip_region);
447 /* X display function emulation */
449 /* Mac version of XDrawLine. */
451 static void
452 mac_draw_line (f, gc, x1, y1, x2, y2)
453 struct frame *f;
454 GC gc;
455 int x1, y1, x2, y2;
457 #if USE_CG_DRAWING
458 CGContextRef context;
459 float gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
461 if (y1 != y2)
462 gx1 += 0.5f, gx2 += 0.5f;
463 if (x1 != x2)
464 gy1 += 0.5f, gy2 += 0.5f;
466 context = mac_begin_cg_clip (f, gc);
467 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
468 CGContextBeginPath (context);
469 CGContextMoveToPoint (context, gx1, gy1);
470 CGContextAddLineToPoint (context, gx2, gy2);
471 CGContextClosePath (context);
472 CGContextStrokePath (context);
473 mac_end_cg_clip (f);
474 #else
475 if (x1 == x2)
477 if (y1 > y2)
478 y1--;
479 else if (y2 > y1)
480 y2--;
482 else if (y1 == y2)
484 if (x1 > x2)
485 x1--;
486 else
487 x2--;
490 mac_begin_clip (f, gc);
491 RGBForeColor (GC_FORE_COLOR (gc));
492 MoveTo (x1, y1);
493 LineTo (x2, y2);
494 mac_end_clip (gc);
495 #endif
498 /* Mac version of XDrawLine (to Pixmap). */
500 void
501 XDrawLine (display, p, gc, x1, y1, x2, y2)
502 Display *display;
503 Pixmap p;
504 GC gc;
505 int x1, y1, x2, y2;
507 CGrafPtr old_port;
508 GDHandle old_gdh;
510 if (x1 == x2)
512 if (y1 > y2)
513 y1--;
514 else if (y2 > y1)
515 y2--;
517 else if (y1 == y2)
519 if (x1 > x2)
520 x1--;
521 else
522 x2--;
525 GetGWorld (&old_port, &old_gdh);
526 SetGWorld (p, NULL);
528 RGBForeColor (GC_FORE_COLOR (gc));
530 LockPixels (GetGWorldPixMap (p));
531 MoveTo (x1, y1);
532 LineTo (x2, y2);
533 UnlockPixels (GetGWorldPixMap (p));
535 SetGWorld (old_port, old_gdh);
539 static void
540 mac_erase_rectangle (f, gc, x, y, width, height)
541 struct frame *f;
542 GC gc;
543 int x, y;
544 unsigned int width, height;
546 #if USE_CG_DRAWING
548 CGContextRef context;
550 context = mac_begin_cg_clip (f, gc);
551 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
552 CGContextFillRect (context, CGRectMake (x, y, width, height));
553 mac_end_cg_clip (f);
555 #else
557 Rect r;
559 mac_begin_clip (f, gc);
560 RGBBackColor (GC_BACK_COLOR (gc));
561 SetRect (&r, x, y, x + width, y + height);
562 EraseRect (&r);
563 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
564 mac_end_clip (gc);
566 #endif
570 /* Mac version of XClearArea. */
572 void
573 mac_clear_area (f, x, y, width, height)
574 struct frame *f;
575 int x, y;
576 unsigned int width, height;
578 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
581 /* Mac version of XClearWindow. */
583 static void
584 mac_clear_window (f)
585 struct frame *f;
587 #if USE_CG_DRAWING
589 CGContextRef context;
590 GC gc = FRAME_NORMAL_GC (f);
592 context = mac_begin_cg_clip (f, NULL);
593 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
594 CGContextFillRect (context, CGRectMake (0, 0, FRAME_PIXEL_WIDTH (f),
595 FRAME_PIXEL_HEIGHT (f)));
596 mac_end_cg_clip (f);
598 #else /* !USE_CG_DRAWING */
599 SetPortWindowPort (FRAME_MAC_WINDOW (f));
601 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
603 #if TARGET_API_MAC_CARBON
605 Rect r;
607 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
608 EraseRect (&r);
610 #else /* not TARGET_API_MAC_CARBON */
611 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
612 #endif /* not TARGET_API_MAC_CARBON */
613 #endif
617 /* Mac replacement for XCopyArea. */
619 #if USE_CG_DRAWING
620 static void
621 mac_draw_cg_image (image, f, gc, src_x, src_y, width, height,
622 dest_x, dest_y, overlay_p)
623 CGImageRef image;
624 struct frame *f;
625 GC gc;
626 int src_x, src_y;
627 unsigned int width, height;
628 int dest_x, dest_y, overlay_p;
630 CGContextRef context;
631 float port_height = FRAME_PIXEL_HEIGHT (f);
632 CGRect dest_rect = CGRectMake (dest_x, dest_y, width, height);
634 context = mac_begin_cg_clip (f, gc);
635 if (!overlay_p)
637 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
638 CGContextFillRect (context, dest_rect);
640 CGContextClipToRect (context, dest_rect);
641 CGContextScaleCTM (context, 1, -1);
642 CGContextTranslateCTM (context, 0, -port_height);
643 if (CGImageIsMask (image))
644 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
645 CGContextDrawImage (context,
646 CGRectMake (dest_x - src_x,
647 port_height - (dest_y - src_y
648 + CGImageGetHeight (image)),
649 CGImageGetWidth (image),
650 CGImageGetHeight (image)),
651 image);
652 mac_end_cg_clip (f);
655 #else /* !USE_CG_DRAWING */
657 static void
658 mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
659 struct frame *f;
660 GC gc;
661 int x, y, width, height;
662 unsigned short *bits;
663 int overlay_p;
665 BitMap bitmap;
666 Rect r;
668 bitmap.rowBytes = sizeof(unsigned short);
669 bitmap.baseAddr = (char *)bits;
670 SetRect (&(bitmap.bounds), 0, 0, width, height);
672 mac_begin_clip (f, gc);
673 RGBForeColor (GC_FORE_COLOR (gc));
674 RGBBackColor (GC_BACK_COLOR (gc));
675 SetRect (&r, x, y, x + width, y + height);
676 #if TARGET_API_MAC_CARBON
678 CGrafPtr port;
680 GetPort (&port);
681 LockPortBits (port);
682 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
683 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
684 UnlockPortBits (port);
686 #else /* not TARGET_API_MAC_CARBON */
687 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
688 overlay_p ? srcOr : srcCopy, 0);
689 #endif /* not TARGET_API_MAC_CARBON */
690 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
691 mac_end_clip (gc);
693 #endif /* !USE_CG_DRAWING */
696 /* Mac replacement for XCreateBitmapFromBitmapData. */
698 static void
699 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
700 BitMap *bitmap;
701 char *bits;
702 int w, h;
704 static const unsigned char swap_nibble[16]
705 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
706 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
707 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
708 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
709 int i, j, w1;
710 char *p;
712 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
713 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
714 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
715 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
716 for (i = 0; i < h; i++)
718 p = bitmap->baseAddr + i * bitmap->rowBytes;
719 for (j = 0; j < w1; j++)
721 /* Bitswap XBM bytes to match how Mac does things. */
722 unsigned char c = *bits++;
723 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
724 | (swap_nibble[(c>>4) & 0xf]));
728 SetRect (&(bitmap->bounds), 0, 0, w, h);
732 static void
733 mac_free_bitmap (bitmap)
734 BitMap *bitmap;
736 xfree (bitmap->baseAddr);
740 Pixmap
741 XCreatePixmap (display, w, width, height, depth)
742 Display *display;
743 WindowRef w;
744 unsigned int width, height;
745 unsigned int depth;
747 Pixmap pixmap;
748 Rect r;
749 QDErr err;
751 SetPortWindowPort (w);
753 SetRect (&r, 0, 0, width, height);
754 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
755 if (depth == 1)
756 #endif
757 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
758 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
759 else
760 /* CreateCGImageFromPixMaps requires ARGB format. */
761 err = QTNewGWorld (&pixmap, k32ARGBPixelFormat, &r, NULL, NULL, 0);
762 #endif
763 if (err != noErr)
764 return NULL;
765 return pixmap;
769 Pixmap
770 XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
771 Display *display;
772 WindowRef w;
773 char *data;
774 unsigned int width, height;
775 unsigned long fg, bg;
776 unsigned int depth;
778 Pixmap pixmap;
779 BitMap bitmap;
780 CGrafPtr old_port;
781 GDHandle old_gdh;
782 static GC gc = NULL;
784 if (gc == NULL)
785 gc = XCreateGC (display, w, 0, NULL);
787 pixmap = XCreatePixmap (display, w, width, height, depth);
788 if (pixmap == NULL)
789 return NULL;
791 GetGWorld (&old_port, &old_gdh);
792 SetGWorld (pixmap, NULL);
793 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
794 XSetForeground (display, gc, fg);
795 XSetBackground (display, gc, bg);
796 RGBForeColor (GC_FORE_COLOR (gc));
797 RGBBackColor (GC_BACK_COLOR (gc));
798 LockPixels (GetGWorldPixMap (pixmap));
799 #if TARGET_API_MAC_CARBON
800 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
801 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
802 #else /* not TARGET_API_MAC_CARBON */
803 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
804 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
805 #endif /* not TARGET_API_MAC_CARBON */
806 UnlockPixels (GetGWorldPixMap (pixmap));
807 SetGWorld (old_port, old_gdh);
808 mac_free_bitmap (&bitmap);
810 return pixmap;
814 void
815 XFreePixmap (display, pixmap)
816 Display *display;
817 Pixmap pixmap;
819 DisposeGWorld (pixmap);
823 /* Mac replacement for XFillRectangle. */
825 static void
826 mac_fill_rectangle (f, gc, x, y, width, height)
827 struct frame *f;
828 GC gc;
829 int x, y;
830 unsigned int width, height;
832 #if USE_CG_DRAWING
833 CGContextRef context;
835 context = mac_begin_cg_clip (f, gc);
836 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
837 CGContextFillRect (context, CGRectMake (x, y, width, height));
838 mac_end_cg_clip (f);
839 #else
840 Rect r;
842 mac_begin_clip (f, gc);
843 RGBForeColor (GC_FORE_COLOR (gc));
844 SetRect (&r, x, y, x + width, y + height);
845 PaintRect (&r); /* using foreground color of gc */
846 mac_end_clip (gc);
847 #endif
851 /* Mac replacement for XDrawRectangle: dest is a window. */
853 static void
854 mac_draw_rectangle (f, gc, x, y, width, height)
855 struct frame *f;
856 GC gc;
857 int x, y;
858 unsigned int width, height;
860 #if USE_CG_DRAWING
861 CGContextRef context;
863 context = mac_begin_cg_clip (f, gc);
864 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
865 CGContextStrokeRect (context,
866 CGRectMake (x + 0.5f, y + 0.5f, width, height));
867 mac_end_cg_clip (f);
868 #else
869 Rect r;
871 mac_begin_clip (f, gc);
872 RGBForeColor (GC_FORE_COLOR (gc));
873 SetRect (&r, x, y, x + width + 1, y + height + 1);
874 FrameRect (&r); /* using foreground color of gc */
875 mac_end_clip (gc);
876 #endif
880 static void
881 mac_invert_rectangle (f, x, y, width, height)
882 struct frame *f;
883 int x, y;
884 unsigned int width, height;
886 Rect r;
888 #if USE_CG_DRAWING
889 mac_prepare_for_quickdraw (f);
890 #endif
891 SetPortWindowPort (FRAME_MAC_WINDOW (f));
893 SetRect (&r, x, y, x + width, y + height);
895 InvertRect (&r);
899 #if USE_ATSUI
900 static OSStatus
901 atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
902 ConstUniCharArrayPtr text;
903 UniCharCount text_length;
904 ATSUStyle style;
905 ATSUTextLayout *text_layout;
907 OSStatus err;
908 static ATSUTextLayout saved_text_layout = NULL;
910 if (saved_text_layout == NULL)
912 static const UniCharCount lengths[] = {kATSUToTextEnd};
913 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
914 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
915 static ATSLineLayoutOptions line_layout =
916 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
917 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
918 | kATSLineUseQDRendering
919 #else
920 kATSLineIsDisplayOnly | kATSLineFractDisable
921 #endif
923 static const ATSUAttributeValuePtr values[] = {&line_layout};
925 err = ATSUCreateTextLayoutWithTextPtr (text,
926 kATSUFromTextBeginning,
927 kATSUToTextEnd,
928 text_length,
929 1, lengths, &style,
930 &saved_text_layout);
931 if (err == noErr)
932 err = ATSUSetLayoutControls (saved_text_layout,
933 sizeof (tags) / sizeof (tags[0]),
934 tags, sizes, values);
935 if (err == noErr)
936 err = ATSUSetTransientFontMatching (saved_text_layout, true);
938 else
940 err = ATSUSetRunStyle (saved_text_layout, style,
941 kATSUFromTextBeginning, kATSUToTextEnd);
942 if (err == noErr)
943 err = ATSUSetTextPointerLocation (saved_text_layout, text,
944 kATSUFromTextBeginning,
945 kATSUToTextEnd,
946 text_length);
949 if (err == noErr)
950 *text_layout = saved_text_layout;
951 return err;
955 static void
956 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
957 overstrike_p, bytes_per_char)
958 struct frame *f;
959 GC gc;
960 int x, y;
961 char *buf;
962 int nchars, bg_width, overstrike_p, bytes_per_char;
964 OSStatus err;
965 ATSUTextLayout text_layout;
967 xassert (bytes_per_char == 2);
969 #ifndef WORDS_BIG_ENDIAN
971 int i;
972 UniChar *text = (UniChar *)buf;
974 for (i = 0; i < nchars; i++)
975 text[i] = EndianU16_BtoN (text[i]);
977 #endif
978 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
979 nchars,
980 GC_FONT (gc)->mac_style,
981 &text_layout);
982 if (err != noErr)
983 return;
984 #ifdef MAC_OSX
985 if (!mac_use_core_graphics)
987 #endif
988 mac_begin_clip (f, gc);
989 RGBForeColor (GC_FORE_COLOR (gc));
990 if (bg_width)
992 Rect r;
994 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
995 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
996 RGBBackColor (GC_BACK_COLOR (gc));
997 EraseRect (&r);
998 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1000 MoveTo (x, y);
1001 ATSUDrawText (text_layout,
1002 kATSUFromTextBeginning, kATSUToTextEnd,
1003 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1004 if (overstrike_p)
1006 MoveTo (x + 1, y);
1007 ATSUDrawText (text_layout,
1008 kATSUFromTextBeginning, kATSUToTextEnd,
1009 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1011 mac_end_clip (gc);
1012 #ifdef MAC_OSX
1014 else
1016 static CGContextRef context;
1017 float port_height = FRAME_PIXEL_HEIGHT (f);
1018 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1019 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1020 static const ATSUAttributeValuePtr values[] = {&context};
1022 #if USE_CG_DRAWING
1023 context = mac_begin_cg_clip (f, gc);
1024 #else
1025 CGrafPtr port;
1027 GetPort (&port);
1028 QDBeginCGContext (port, &context);
1029 if (gc->n_clip_rects || bg_width)
1031 CGContextTranslateCTM (context, 0, port_height);
1032 CGContextScaleCTM (context, 1, -1);
1033 if (gc->n_clip_rects)
1034 CGContextClipToRects (context, gc->clip_rects,
1035 gc->n_clip_rects);
1036 #endif
1037 if (bg_width)
1039 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1040 CGContextFillRect (context,
1041 CGRectMake (x, y - FONT_BASE (GC_FONT (gc)),
1042 bg_width,
1043 FONT_HEIGHT (GC_FONT (gc))));
1045 CGContextScaleCTM (context, 1, -1);
1046 CGContextTranslateCTM (context, 0, -port_height);
1047 #if !USE_CG_DRAWING
1049 #endif
1050 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1051 err = ATSUSetLayoutControls (text_layout,
1052 sizeof (tags) / sizeof (tags[0]),
1053 tags, sizes, values);
1054 if (err == noErr)
1056 ATSUDrawText (text_layout,
1057 kATSUFromTextBeginning, kATSUToTextEnd,
1058 Long2Fix (x), Long2Fix (port_height - y));
1059 if (overstrike_p)
1060 ATSUDrawText (text_layout,
1061 kATSUFromTextBeginning, kATSUToTextEnd,
1062 Long2Fix (x + 1), Long2Fix (port_height - y));
1064 #if USE_CG_DRAWING
1065 mac_end_cg_clip (f);
1066 context = NULL;
1067 #else
1068 CGContextSynchronize (context);
1069 QDEndCGContext (port, &context);
1070 #endif
1071 #if 0
1072 /* This doesn't work on Mac OS X 10.1. */
1073 ATSUClearLayoutControls (text_layout,
1074 sizeof (tags) / sizeof (tags[0]), tags);
1075 #else
1076 ATSUSetLayoutControls (text_layout,
1077 sizeof (tags) / sizeof (tags[0]),
1078 tags, sizes, values);
1079 #endif
1081 #endif /* MAC_OSX */
1083 #endif /* USE_ATSUI */
1086 static void
1087 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1088 overstrike_p, bytes_per_char)
1089 struct frame *f;
1090 GC gc;
1091 int x, y;
1092 char *buf;
1093 int nchars, bg_width, overstrike_p, bytes_per_char;
1095 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1096 UInt32 savedFlags;
1097 #endif
1099 mac_begin_clip (f, gc);
1100 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1101 if (mac_use_core_graphics)
1102 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
1103 #endif
1104 RGBForeColor (GC_FORE_COLOR (gc));
1105 #ifdef MAC_OS8
1106 if (bg_width)
1108 RGBBackColor (GC_BACK_COLOR (gc));
1109 TextMode (srcCopy);
1111 else
1112 TextMode (srcOr);
1113 #else
1114 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1115 because:
1116 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1117 into an offscreen graphics world first. So performance gain
1118 cannot be expected.)
1119 - It lowers rendering quality.
1120 - Some fonts leave garbage on cursor movement. */
1121 if (bg_width)
1123 Rect r;
1125 RGBBackColor (GC_BACK_COLOR (gc));
1126 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1127 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1128 EraseRect (&r);
1130 TextMode (srcOr);
1131 #endif
1132 TextFont (GC_FONT (gc)->mac_fontnum);
1133 TextSize (GC_FONT (gc)->mac_fontsize);
1134 TextFace (GC_FONT (gc)->mac_fontface);
1135 MoveTo (x, y);
1136 DrawText (buf, 0, nchars * bytes_per_char);
1137 if (overstrike_p)
1139 TextMode (srcOr);
1140 MoveTo (x + 1, y);
1141 DrawText (buf, 0, nchars * bytes_per_char);
1143 if (bg_width)
1144 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1145 mac_end_clip (gc);
1147 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1148 if (mac_use_core_graphics)
1149 SwapQDTextFlags(savedFlags);
1150 #endif
1154 static INLINE void
1155 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1156 overstrike_p, bytes_per_char)
1157 struct frame *f;
1158 GC gc;
1159 int x, y;
1160 char *buf;
1161 int nchars, bg_width, overstrike_p, bytes_per_char;
1163 #if USE_ATSUI
1164 if (GC_FONT (gc)->mac_style)
1165 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1166 overstrike_p, bytes_per_char);
1167 else
1168 #endif /* USE_ATSUI */
1169 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1170 overstrike_p, bytes_per_char);
1174 /* Mac replacement for XDrawImageString. */
1176 static void
1177 mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1178 struct frame *f;
1179 GC gc;
1180 int x, y;
1181 char *buf;
1182 int nchars, bg_width, overstrike_p;
1184 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1185 overstrike_p, 1);
1189 /* Mac replacement for XDrawImageString16. */
1191 static void
1192 mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1193 struct frame *f;
1194 GC gc;
1195 int x, y;
1196 XChar2b *buf;
1197 int nchars, bg_width, overstrike_p;
1199 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1200 overstrike_p, 2);
1204 /* Mac replacement for XQueryTextExtents, but takes a character. If
1205 STYLE is NULL, measurement is done by QuickDraw Text routines for
1206 the font of the current graphics port. If CG_GLYPH is not NULL,
1207 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1209 static OSStatus
1210 mac_query_char_extents (style, c,
1211 font_ascent_return, font_descent_return,
1212 overall_return, cg_glyph)
1213 #if USE_ATSUI
1214 ATSUStyle style;
1215 #else
1216 void *style;
1217 #endif
1218 int c;
1219 int *font_ascent_return, *font_descent_return;
1220 XCharStruct *overall_return;
1221 #if USE_CG_TEXT_DRAWING
1222 CGGlyph *cg_glyph;
1223 #else
1224 void *cg_glyph;
1225 #endif
1227 OSStatus err = noErr;
1228 int width;
1229 Rect char_bounds;
1231 #if USE_ATSUI
1232 if (style)
1234 ATSUTextLayout text_layout;
1235 UniChar ch = c;
1237 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
1238 if (err == noErr
1239 && (font_ascent_return || font_descent_return || overall_return))
1241 ATSTrapezoid glyph_bounds;
1243 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1244 kATSUFromTextBeginning, kATSUToTextEnd,
1245 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1246 kATSUseFractionalOrigins,
1247 #else
1248 kATSUseDeviceOrigins,
1249 #endif
1250 1, &glyph_bounds, NULL);
1251 if (err == noErr)
1253 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1254 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1256 width = Fix2Long (glyph_bounds.upperRight.x
1257 - glyph_bounds.upperLeft.x);
1258 if (font_ascent_return)
1259 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1260 if (font_descent_return)
1261 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1264 if (err == noErr && overall_return)
1266 err = ATSUMeasureTextImage (text_layout,
1267 kATSUFromTextBeginning, kATSUToTextEnd,
1268 0, 0, &char_bounds);
1269 if (err == noErr)
1270 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1271 #if USE_CG_TEXT_DRAWING
1272 if (err == noErr && cg_glyph)
1274 OSStatus err1;
1275 ATSUGlyphInfoArray glyph_info_array;
1276 ByteCount count = sizeof (ATSUGlyphInfoArray);
1278 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1279 kATSUToTextEnd, NULL, NULL, NULL);
1280 if (err1 == noErr)
1281 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1282 kATSUToTextEnd, &count,
1283 &glyph_info_array);
1284 if (err1 == noErr
1285 /* Make sure that we don't have to make layout
1286 adjustments. */
1287 && glyph_info_array.glyphs[0].deltaY == 0.0f
1288 && glyph_info_array.glyphs[0].idealX == 0.0f
1289 && glyph_info_array.glyphs[0].screenX == 0)
1291 xassert (glyph_info_array.glyphs[0].glyphID);
1292 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1294 else
1295 *cg_glyph = 0;
1297 #endif
1300 else
1301 #endif
1303 if (font_ascent_return || font_descent_return)
1305 FontInfo font_info;
1307 GetFontInfo (&font_info);
1308 if (font_ascent_return)
1309 *font_ascent_return = font_info.ascent;
1310 if (font_descent_return)
1311 *font_descent_return = font_info.descent;
1313 if (overall_return)
1315 char ch = c;
1317 width = CharWidth (ch);
1318 QDTextBounds (1, &ch, &char_bounds);
1319 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1323 return err;
1327 /* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1329 static int
1330 mac_text_extents_16 (font_struct, string, nchars, overall_return)
1331 XFontStruct *font_struct;
1332 XChar2b *string;
1333 int nchars;
1334 XCharStruct *overall_return;
1336 int i;
1337 short width = 0, lbearing = 0, rbearing = 0;
1338 XCharStruct *pcm;
1340 for (i = 0; i < nchars; i++)
1342 pcm = mac_per_char_metric (font_struct, string, 0);
1343 if (pcm == NULL)
1344 width += FONT_WIDTH (font_struct);
1345 else
1347 lbearing = min (lbearing, width + pcm->lbearing);
1348 rbearing = max (rbearing, width + pcm->rbearing);
1349 width += pcm->width;
1351 string++;
1354 overall_return->lbearing = lbearing;
1355 overall_return->rbearing = rbearing;
1356 overall_return->width = width;
1358 /* What's the meaning of the return value of XTextExtents16? */
1362 #if USE_CG_TEXT_DRAWING
1363 static int cg_text_anti_aliasing_threshold = 8;
1365 static void
1366 init_cg_text_anti_aliasing_threshold ()
1368 int threshold;
1369 Boolean valid_p;
1371 threshold =
1372 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1373 kCFPreferencesCurrentApplication,
1374 &valid_p);
1375 if (valid_p)
1376 cg_text_anti_aliasing_threshold = threshold;
1379 static int
1380 mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1381 struct frame *f;
1382 GC gc;
1383 int x, y;
1384 XChar2b *buf;
1385 int nchars, bg_width, overstrike_p;
1387 float port_height, gx, gy;
1388 int i;
1389 CGContextRef context;
1390 CGGlyph *glyphs;
1391 CGSize *advances;
1393 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
1394 return 0;
1396 port_height = FRAME_PIXEL_HEIGHT (f);
1397 gx = x;
1398 gy = port_height - y;
1399 glyphs = (CGGlyph *)buf;
1400 advances = alloca (sizeof (CGSize) * nchars);
1401 if (advances == NULL)
1402 return 0;
1403 for (i = 0; i < nchars; i++)
1405 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1407 advances[i].width = pcm->width;
1408 advances[i].height = 0;
1409 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1410 buf++;
1413 #if USE_CG_DRAWING
1414 context = mac_begin_cg_clip (f, gc);
1415 #else
1416 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1417 if (gc->n_clip_rects || bg_width)
1419 CGContextTranslateCTM (context, 0, port_height);
1420 CGContextScaleCTM (context, 1, -1);
1421 if (gc->n_clip_rects)
1422 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1423 #endif
1424 if (bg_width)
1426 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1427 CGContextFillRect
1428 (context,
1429 CGRectMake (gx, y - FONT_BASE (GC_FONT (gc)),
1430 bg_width, FONT_HEIGHT (GC_FONT (gc))));
1432 CGContextScaleCTM (context, 1, -1);
1433 CGContextTranslateCTM (context, 0, -port_height);
1434 #if !USE_CG_DRAWING
1436 #endif
1437 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1438 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1439 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
1440 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1441 CGContextSetShouldAntialias (context, false);
1442 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1443 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1444 if (CGContextShowGlyphsWithAdvances != NULL)
1445 #endif
1447 CGContextSetTextPosition (context, gx, gy);
1448 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1449 if (overstrike_p)
1451 CGContextSetTextPosition (context, gx + 1.0f, gy);
1452 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1455 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1456 else /* CGContextShowGlyphsWithAdvances == NULL */
1457 #endif
1458 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1459 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1461 for (i = 0; i < nchars; i++)
1463 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1464 if (overstrike_p)
1465 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1466 gx += advances[i].width;
1469 #endif
1470 #if USE_CG_DRAWING
1471 mac_end_cg_clip (f);
1472 #else
1473 CGContextSynchronize (context);
1474 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1475 #endif
1477 return 1;
1479 #endif
1482 #if !USE_CG_DRAWING
1483 /* Mac replacement for XCopyArea: dest must be window. */
1485 static void
1486 mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1487 Pixmap src;
1488 struct frame *f;
1489 GC gc;
1490 int src_x, src_y;
1491 unsigned int width, height;
1492 int dest_x, dest_y;
1494 Rect src_r, dest_r;
1496 mac_begin_clip (f, gc);
1498 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1499 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1501 ForeColor (blackColor);
1502 BackColor (whiteColor);
1504 LockPixels (GetGWorldPixMap (src));
1505 #if TARGET_API_MAC_CARBON
1507 CGrafPtr port;
1509 GetPort (&port);
1510 LockPortBits (port);
1511 CopyBits (GetPortBitMapForCopyBits (src),
1512 GetPortBitMapForCopyBits (port),
1513 &src_r, &dest_r, srcCopy, 0);
1514 UnlockPortBits (port);
1516 #else /* not TARGET_API_MAC_CARBON */
1517 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
1518 &src_r, &dest_r, srcCopy, 0);
1519 #endif /* not TARGET_API_MAC_CARBON */
1520 UnlockPixels (GetGWorldPixMap (src));
1522 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1524 mac_end_clip (gc);
1528 static void
1529 mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
1530 width, height, dest_x, dest_y)
1531 Pixmap src, mask;
1532 struct frame *f;
1533 GC gc;
1534 int src_x, src_y;
1535 unsigned int width, height;
1536 int dest_x, dest_y;
1538 Rect src_r, dest_r;
1540 mac_begin_clip (f, gc);
1542 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1543 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1545 ForeColor (blackColor);
1546 BackColor (whiteColor);
1548 LockPixels (GetGWorldPixMap (src));
1549 LockPixels (GetGWorldPixMap (mask));
1550 #if TARGET_API_MAC_CARBON
1552 CGrafPtr port;
1554 GetPort (&port);
1555 LockPortBits (port);
1556 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1557 GetPortBitMapForCopyBits (port),
1558 &src_r, &src_r, &dest_r);
1559 UnlockPortBits (port);
1561 #else /* not TARGET_API_MAC_CARBON */
1562 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
1563 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
1564 #endif /* not TARGET_API_MAC_CARBON */
1565 UnlockPixels (GetGWorldPixMap (mask));
1566 UnlockPixels (GetGWorldPixMap (src));
1568 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1570 mac_end_clip (gc);
1572 #endif /* !USE_CG_DRAWING */
1575 /* Mac replacement for XCopyArea: used only for scrolling. */
1577 static void
1578 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1579 struct frame *f;
1580 GC gc;
1581 int src_x, src_y;
1582 unsigned int width, height;
1583 int dest_x, dest_y;
1585 #if TARGET_API_MAC_CARBON
1586 Rect src_r;
1587 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1589 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1590 #if USE_CG_DRAWING
1591 mac_prepare_for_quickdraw (f);
1592 #endif
1593 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1594 &src_r, dest_x - src_x, dest_y - src_y,
1595 kScrollWindowNoOptions, dummy);
1596 DisposeRgn (dummy);
1597 #else /* not TARGET_API_MAC_CARBON */
1598 Rect src_r, dest_r;
1599 WindowRef w = FRAME_MAC_WINDOW (f);
1601 mac_begin_clip (f, gc);
1603 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1604 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1606 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1607 color mapping in CopyBits. Otherwise, it will be slow. */
1608 ForeColor (blackColor);
1609 BackColor (whiteColor);
1610 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
1612 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1614 mac_end_clip (gc);
1615 #endif /* not TARGET_API_MAC_CARBON */
1619 /* Mac replacement for XChangeGC. */
1621 static void
1622 XChangeGC (display, gc, mask, xgcv)
1623 Display *display;
1624 GC gc;
1625 unsigned long mask;
1626 XGCValues *xgcv;
1628 if (mask & GCForeground)
1629 XSetForeground (display, gc, xgcv->foreground);
1630 if (mask & GCBackground)
1631 XSetBackground (display, gc, xgcv->background);
1632 if (mask & GCFont)
1633 XSetFont (display, gc, xgcv->font);
1637 /* Mac replacement for XCreateGC. */
1640 XCreateGC (display, d, mask, xgcv)
1641 Display *display;
1642 void *d;
1643 unsigned long mask;
1644 XGCValues *xgcv;
1646 GC gc = xmalloc (sizeof (*gc));
1648 bzero (gc, sizeof (*gc));
1649 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1650 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1651 if (CGColorGetTypeID != NULL)
1652 #endif
1654 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1655 CGColorRetain (gc->cg_fore_color);
1656 CGColorRetain (gc->cg_back_color);
1658 #endif
1659 XChangeGC (display, gc, mask, xgcv);
1661 return gc;
1665 /* Used in xfaces.c. */
1667 void
1668 XFreeGC (display, gc)
1669 Display *display;
1670 GC gc;
1672 if (gc->clip_region)
1673 DisposeRgn (gc->clip_region);
1674 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1675 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1676 if (CGColorGetTypeID != NULL)
1677 #endif
1679 CGColorRelease (gc->cg_fore_color);
1680 CGColorRelease (gc->cg_back_color);
1682 #endif
1683 xfree (gc);
1687 /* Mac replacement for XGetGCValues. */
1689 static void
1690 XGetGCValues (display, gc, mask, xgcv)
1691 Display *display;
1692 GC gc;
1693 unsigned long mask;
1694 XGCValues *xgcv;
1696 if (mask & GCForeground)
1697 xgcv->foreground = gc->xgcv.foreground;
1698 if (mask & GCBackground)
1699 xgcv->background = gc->xgcv.background;
1700 if (mask & GCFont)
1701 xgcv->font = gc->xgcv.font;
1705 /* Mac replacement for XSetForeground. */
1707 void
1708 XSetForeground (display, gc, color)
1709 Display *display;
1710 GC gc;
1711 unsigned long color;
1713 if (gc->xgcv.foreground != color)
1715 gc->xgcv.foreground = color;
1716 gc->fore_color.red = RED16_FROM_ULONG (color);
1717 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1718 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
1719 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1720 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1721 if (CGColorGetTypeID != NULL)
1722 #endif
1724 CGColorRelease (gc->cg_fore_color);
1725 if (color == 0)
1727 gc->cg_fore_color = mac_cg_color_black;
1728 CGColorRetain (gc->cg_fore_color);
1730 else
1732 float rgba[4];
1734 rgba[0] = gc->fore_color.red / 65535.0f;
1735 rgba[1] = gc->fore_color.green / 65535.0f;
1736 rgba[2] = gc->fore_color.blue / 65535.0f;
1737 rgba[3] = 1.0f;
1738 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1741 #endif
1746 /* Mac replacement for XSetBackground. */
1748 void
1749 XSetBackground (display, gc, color)
1750 Display *display;
1751 GC gc;
1752 unsigned long color;
1754 if (gc->xgcv.background != color)
1756 gc->xgcv.background = color;
1757 gc->back_color.red = RED16_FROM_ULONG (color);
1758 gc->back_color.green = GREEN16_FROM_ULONG (color);
1759 gc->back_color.blue = BLUE16_FROM_ULONG (color);
1760 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1761 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1762 if (CGColorGetTypeID != NULL)
1763 #endif
1765 CGColorRelease (gc->cg_back_color);
1766 if (color == 0)
1768 gc->cg_back_color = mac_cg_color_black;
1769 CGColorRetain (gc->cg_back_color);
1771 else
1773 float rgba[4];
1775 rgba[0] = gc->back_color.red / 65535.0f;
1776 rgba[1] = gc->back_color.green / 65535.0f;
1777 rgba[2] = gc->back_color.blue / 65535.0f;
1778 rgba[3] = 1.0f;
1779 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1782 #endif
1787 /* Mac replacement for XSetFont. */
1789 static void
1790 XSetFont (display, gc, font)
1791 Display *display;
1792 GC gc;
1793 XFontStruct *font;
1795 gc->xgcv.font = font;
1799 /* Mac replacement for XSetClipRectangles. */
1801 static void
1802 mac_set_clip_rectangles (display, gc, rectangles, n)
1803 Display *display;
1804 GC gc;
1805 Rect *rectangles;
1806 int n;
1808 int i;
1810 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1812 gc->n_clip_rects = n;
1813 if (n > 0)
1815 if (gc->clip_region == NULL)
1816 gc->clip_region = NewRgn ();
1817 RectRgn (gc->clip_region, rectangles);
1818 if (n > 1)
1820 RgnHandle region = NewRgn ();
1822 for (i = 1; i < n; i++)
1824 RectRgn (region, rectangles + i);
1825 UnionRgn (gc->clip_region, region, gc->clip_region);
1827 DisposeRgn (region);
1830 #if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1831 for (i = 0; i < n; i++)
1833 Rect *rect = rectangles + i;
1835 gc->clip_rects[i] = CGRectMake (rect->left, rect->top,
1836 rect->right - rect->left,
1837 rect->bottom - rect->top);
1839 #endif
1843 /* Mac replacement for XSetClipMask. */
1845 static INLINE void
1846 mac_reset_clip_rectangles (display, gc)
1847 Display *display;
1848 GC gc;
1850 gc->n_clip_rects = 0;
1854 /* Mac replacement for XSetWindowBackground. */
1856 void
1857 XSetWindowBackground (display, w, color)
1858 Display *display;
1859 WindowRef w;
1860 unsigned long color;
1862 #if !TARGET_API_MAC_CARBON
1863 AuxWinHandle aw_handle;
1864 CTabHandle ctab_handle;
1865 ColorSpecPtr ct_table;
1866 short ct_size;
1867 #endif
1868 RGBColor bg_color;
1870 bg_color.red = RED16_FROM_ULONG (color);
1871 bg_color.green = GREEN16_FROM_ULONG (color);
1872 bg_color.blue = BLUE16_FROM_ULONG (color);
1874 #if TARGET_API_MAC_CARBON
1875 SetWindowContentColor (w, &bg_color);
1876 #else
1877 if (GetAuxWin (w, &aw_handle))
1879 ctab_handle = (*aw_handle)->awCTable;
1880 HandToHand ((Handle *) &ctab_handle);
1881 ct_table = (*ctab_handle)->ctTable;
1882 ct_size = (*ctab_handle)->ctSize;
1883 while (ct_size > -1)
1885 if (ct_table->value == 0)
1887 ct_table->rgb = bg_color;
1888 CTabChanged (ctab_handle);
1889 SetWinColor (w, (WCTabHandle) ctab_handle);
1891 ct_size--;
1894 #endif
1897 /* Flush display of frame F, or of all frames if F is null. */
1899 static void
1900 x_flush (f)
1901 struct frame *f;
1903 #if TARGET_API_MAC_CARBON
1904 BLOCK_INPUT;
1905 #if USE_CG_DRAWING
1906 mac_prepare_for_quickdraw (f);
1907 #endif
1908 if (f)
1909 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1910 else
1911 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1912 UNBLOCK_INPUT;
1913 #endif
1917 /* Remove calls to XFlush by defining XFlush to an empty replacement.
1918 Calls to XFlush should be unnecessary because the X output buffer
1919 is flushed automatically as needed by calls to XPending,
1920 XNextEvent, or XWindowEvent according to the XFlush man page.
1921 XTread_socket calls XPending. Removing XFlush improves
1922 performance. */
1924 #define XFlush(DISPLAY) (void) 0
1926 #if USE_CG_DRAWING
1927 static void
1928 mac_flush_display_optional (f)
1929 struct frame *f;
1931 BLOCK_INPUT;
1932 mac_prepare_for_quickdraw (f);
1933 UNBLOCK_INPUT;
1935 #endif
1937 /***********************************************************************
1938 Starting and ending an update
1939 ***********************************************************************/
1941 /* Start an update of frame F. This function is installed as a hook
1942 for update_begin, i.e. it is called when update_begin is called.
1943 This function is called prior to calls to x_update_window_begin for
1944 each window being updated. */
1946 static void
1947 x_update_begin (f)
1948 struct frame *f;
1950 #if TARGET_API_MAC_CARBON
1951 /* During update of a frame, availability of input events is
1952 periodically checked with ReceiveNextEvent if
1953 redisplay-dont-pause is nil. That normally flushes window buffer
1954 changes for every check, and thus screen update looks waving even
1955 if no input is available. So we disable screen updates during
1956 update of a frame. */
1957 BLOCK_INPUT;
1958 DisableScreenUpdates ();
1959 UNBLOCK_INPUT;
1960 #endif
1964 /* Start update of window W. Set the global variable updated_window
1965 to the window being updated and set output_cursor to the cursor
1966 position of W. */
1968 static void
1969 x_update_window_begin (w)
1970 struct window *w;
1972 struct frame *f = XFRAME (WINDOW_FRAME (w));
1973 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
1975 updated_window = w;
1976 set_output_cursor (&w->cursor);
1978 BLOCK_INPUT;
1980 if (f == display_info->mouse_face_mouse_frame)
1982 /* Don't do highlighting for mouse motion during the update. */
1983 display_info->mouse_face_defer = 1;
1985 /* If F needs to be redrawn, simply forget about any prior mouse
1986 highlighting. */
1987 if (FRAME_GARBAGED_P (f))
1988 display_info->mouse_face_window = Qnil;
1990 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
1991 their mouse_face_p flag set, which means that they are always
1992 unequal to rows in a desired matrix which never have that
1993 flag set. So, rows containing mouse-face glyphs are never
1994 scrolled, and we don't have to switch the mouse highlight off
1995 here to prevent it from being scrolled. */
1997 /* Can we tell that this update does not affect the window
1998 where the mouse highlight is? If so, no need to turn off.
1999 Likewise, don't do anything if the frame is garbaged;
2000 in that case, the frame's current matrix that we would use
2001 is all wrong, and we will redisplay that line anyway. */
2002 if (!NILP (display_info->mouse_face_window)
2003 && w == XWINDOW (display_info->mouse_face_window))
2005 int i;
2007 for (i = 0; i < w->desired_matrix->nrows; ++i)
2008 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2009 break;
2011 if (i < w->desired_matrix->nrows)
2012 clear_mouse_face (display_info);
2014 #endif /* 0 */
2017 UNBLOCK_INPUT;
2021 /* Draw a vertical window border from (x,y0) to (x,y1) */
2023 static void
2024 mac_draw_vertical_window_border (w, x, y0, y1)
2025 struct window *w;
2026 int x, y0, y1;
2028 struct frame *f = XFRAME (WINDOW_FRAME (w));
2029 struct face *face;
2031 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2032 if (face)
2033 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2034 face->foreground);
2036 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
2039 /* End update of window W (which is equal to updated_window).
2041 Draw vertical borders between horizontally adjacent windows, and
2042 display W's cursor if CURSOR_ON_P is non-zero.
2044 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2045 glyphs in mouse-face were overwritten. In that case we have to
2046 make sure that the mouse-highlight is properly redrawn.
2048 W may be a menu bar pseudo-window in case we don't have X toolkit
2049 support. Such windows don't have a cursor, so don't display it
2050 here. */
2052 static void
2053 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2054 struct window *w;
2055 int cursor_on_p, mouse_face_overwritten_p;
2057 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
2059 if (!w->pseudo_window_p)
2061 BLOCK_INPUT;
2063 if (cursor_on_p)
2064 display_and_set_cursor (w, 1, output_cursor.hpos,
2065 output_cursor.vpos,
2066 output_cursor.x, output_cursor.y);
2068 if (draw_window_fringes (w, 1))
2069 x_draw_vertical_border (w);
2071 UNBLOCK_INPUT;
2074 /* If a row with mouse-face was overwritten, arrange for
2075 XTframe_up_to_date to redisplay the mouse highlight. */
2076 if (mouse_face_overwritten_p)
2078 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2079 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2080 dpyinfo->mouse_face_window = Qnil;
2083 updated_window = NULL;
2087 /* End update of frame F. This function is installed as a hook in
2088 update_end. */
2090 static void
2091 x_update_end (f)
2092 struct frame *f;
2094 /* Mouse highlight may be displayed again. */
2095 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2097 BLOCK_INPUT;
2098 #if TARGET_API_MAC_CARBON
2099 EnableScreenUpdates ();
2100 #endif
2101 XFlush (FRAME_MAC_DISPLAY (f));
2102 UNBLOCK_INPUT;
2106 /* This function is called from various places in xdisp.c whenever a
2107 complete update has been performed. The global variable
2108 updated_window is not available here. */
2110 static void
2111 XTframe_up_to_date (f)
2112 struct frame *f;
2114 if (FRAME_MAC_P (f))
2116 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2118 if (dpyinfo->mouse_face_deferred_gc
2119 || f == dpyinfo->mouse_face_mouse_frame)
2121 BLOCK_INPUT;
2122 if (dpyinfo->mouse_face_mouse_frame)
2123 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2124 dpyinfo->mouse_face_mouse_x,
2125 dpyinfo->mouse_face_mouse_y);
2126 dpyinfo->mouse_face_deferred_gc = 0;
2127 UNBLOCK_INPUT;
2133 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
2134 arrow bitmaps, or clear the fringes if no bitmaps are required
2135 before DESIRED_ROW is made current. The window being updated is
2136 found in updated_window. This function is called from
2137 update_window_line only if it is known that there are differences
2138 between bitmaps to be drawn between current row and DESIRED_ROW. */
2140 static void
2141 x_after_update_window_line (desired_row)
2142 struct glyph_row *desired_row;
2144 struct window *w = updated_window;
2145 struct frame *f;
2146 int width, height;
2148 xassert (w);
2150 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2151 desired_row->redraw_fringe_bitmaps_p = 1;
2153 /* When a window has disappeared, make sure that no rest of
2154 full-width rows stays visible in the internal border. Could
2155 check here if updated_window is the leftmost/rightmost window,
2156 but I guess it's not worth doing since vertically split windows
2157 are almost never used, internal border is rarely set, and the
2158 overhead is very small. */
2159 if (windows_or_buffers_changed
2160 && desired_row->full_width_p
2161 && (f = XFRAME (w->frame),
2162 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2163 width != 0)
2164 && (height = desired_row->visible_height,
2165 height > 0))
2167 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2169 /* Internal border is drawn below the tool bar. */
2170 if (WINDOWP (f->tool_bar_window)
2171 && w == XWINDOW (f->tool_bar_window))
2172 y -= width;
2174 BLOCK_INPUT;
2175 mac_clear_area (f, 0, y, width, height);
2176 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
2177 UNBLOCK_INPUT;
2182 /* Draw the bitmap WHICH in one of the left or right fringes of
2183 window W. ROW is the glyph row for which to display the bitmap; it
2184 determines the vertical position at which the bitmap has to be
2185 drawn. */
2187 static void
2188 x_draw_fringe_bitmap (w, row, p)
2189 struct window *w;
2190 struct glyph_row *row;
2191 struct draw_fringe_bitmap_params *p;
2193 struct frame *f = XFRAME (WINDOW_FRAME (w));
2194 Display *display = FRAME_MAC_DISPLAY (f);
2195 struct face *face = p->face;
2196 int rowY;
2197 int overlay_p = p->overlay_p;
2199 #ifdef MAC_OSX
2200 if (!overlay_p)
2202 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2204 #if 0 /* MAC_TODO: stipple */
2205 /* In case the same realized face is used for fringes and
2206 for something displayed in the text (e.g. face `region' on
2207 mono-displays, the fill style may have been changed to
2208 FillSolid in x_draw_glyph_string_background. */
2209 if (face->stipple)
2210 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2211 else
2212 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2213 #endif
2215 /* If the fringe is adjacent to the left (right) scroll bar of a
2216 leftmost (rightmost, respectively) window, then extend its
2217 background to the gap between the fringe and the bar. */
2218 if ((WINDOW_LEFTMOST_P (w)
2219 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2220 || (WINDOW_RIGHTMOST_P (w)
2221 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2223 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2225 if (sb_width > 0)
2227 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2228 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2229 * FRAME_COLUMN_WIDTH (f));
2231 if (bx < 0
2232 && (left + width == p->x
2233 || p->x + p->wd == left))
2235 /* Bitmap fills the fringe and we need background
2236 extension. */
2237 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2239 bx = p->x;
2240 nx = p->wd;
2241 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2242 row->y));
2243 ny = row->visible_height;
2246 if (bx >= 0)
2248 if (left + width == bx)
2250 bx = left + sb_width;
2251 nx += width - sb_width;
2253 else if (bx + nx == left)
2254 nx += width - sb_width;
2259 if (bx >= 0)
2261 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2262 /* The fringe background has already been filled. */
2263 overlay_p = 1;
2266 #if 0 /* MAC_TODO: stipple */
2267 if (!face->stipple)
2268 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2269 #endif
2271 #endif /* MAC_OSX */
2273 /* Must clip because of partially visible lines. */
2274 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2275 if (p->y < rowY)
2277 /* Adjust position of "bottom aligned" bitmap on partially
2278 visible last row. */
2279 int oldY = row->y;
2280 int oldVH = row->visible_height;
2281 row->visible_height = p->h;
2282 row->y -= rowY - p->y;
2283 x_clip_to_row (w, row, -1, face->gc);
2284 row->y = oldY;
2285 row->visible_height = oldVH;
2287 else
2288 x_clip_to_row (w, row, -1, face->gc);
2290 #ifndef MAC_OSX
2291 if (p->bx >= 0 && !p->overlay_p)
2293 #if 0 /* MAC_TODO: stipple */
2294 /* In case the same realized face is used for fringes and
2295 for something displayed in the text (e.g. face `region' on
2296 mono-displays, the fill style may have been changed to
2297 FillSolid in x_draw_glyph_string_background. */
2298 if (face->stipple)
2299 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2300 else
2301 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2302 #endif
2304 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
2306 #if 0 /* MAC_TODO: stipple */
2307 if (!face->stipple)
2308 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2309 #endif
2311 #endif /* !MAC_OSX */
2313 if (p->which
2314 #if USE_CG_DRAWING
2315 && p->which < max_fringe_bmp
2316 #endif
2319 XGCValues gcv;
2321 XGetGCValues (display, face->gc, GCForeground, &gcv);
2322 XSetForeground (display, face->gc,
2323 (p->cursor_p
2324 ? (p->overlay_p ? face->background
2325 : f->output_data.mac->cursor_pixel)
2326 : face->foreground));
2327 #if USE_CG_DRAWING
2328 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
2329 p->wd, p->h, p->x, p->y, overlay_p);
2330 #else
2331 mac_draw_bitmap (f, face->gc, p->x, p->y,
2332 p->wd, p->h, p->bits + p->dh, overlay_p);
2333 #endif
2334 XSetForeground (display, face->gc, gcv.foreground);
2337 mac_reset_clip_rectangles (display, face->gc);
2340 #if USE_CG_DRAWING
2341 static void
2342 mac_define_fringe_bitmap (which, bits, h, wd)
2343 int which;
2344 unsigned short *bits;
2345 int h, wd;
2347 int i;
2348 CGDataProviderRef provider;
2350 if (which >= max_fringe_bmp)
2352 i = max_fringe_bmp;
2353 max_fringe_bmp = which + 20;
2354 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2355 while (i < max_fringe_bmp)
2356 fringe_bmp[i++] = 0;
2359 for (i = 0; i < h; i++)
2360 bits[i] = ~bits[i];
2361 provider = CGDataProviderCreateWithData (NULL, bits,
2362 sizeof (unsigned short) * h, NULL);
2363 if (provider)
2365 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2366 sizeof (unsigned short),
2367 provider, NULL, 0);
2368 CGDataProviderRelease (provider);
2372 static void
2373 mac_destroy_fringe_bitmap (which)
2374 int which;
2376 if (which >= max_fringe_bmp)
2377 return;
2379 if (fringe_bmp[which])
2380 CGImageRelease (fringe_bmp[which]);
2381 fringe_bmp[which] = 0;
2383 #endif
2386 /* This is called when starting Emacs and when restarting after
2387 suspend. When starting Emacs, no window is mapped. And nothing
2388 must be done to Emacs's own window if it is suspended (though that
2389 rarely happens). */
2391 static void
2392 XTset_terminal_modes ()
2396 /* This is called when exiting or suspending Emacs. Exiting will make
2397 the windows go away, and suspending requires no action. */
2399 static void
2400 XTreset_terminal_modes ()
2406 /***********************************************************************
2407 Display Iterator
2408 ***********************************************************************/
2410 /* Function prototypes of this page. */
2412 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
2413 static int mac_encode_char P_ ((int, XChar2b *, struct font_info *, int *));
2416 static void
2417 pcm_init (pcm, count)
2418 XCharStruct *pcm;
2419 int count;
2421 bzero (pcm, sizeof (XCharStruct) * count);
2422 while (--count >= 0)
2424 pcm->descent = PCM_INVALID;
2425 pcm++;
2429 static enum pcm_status
2430 pcm_get_status (pcm)
2431 const XCharStruct *pcm;
2433 int height = pcm->ascent + pcm->descent;
2435 /* Negative height means some special status. */
2436 return height >= 0 ? PCM_VALID : height;
2439 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2440 is not contained in the font. */
2442 static INLINE XCharStruct *
2443 x_per_char_metric (font, char2b)
2444 XFontStruct *font;
2445 XChar2b *char2b;
2447 /* The result metric information. */
2448 XCharStruct *pcm = NULL;
2450 xassert (font && char2b);
2452 #if USE_ATSUI
2453 if (font->mac_style)
2455 XCharStruct **row = font->bounds.rows + char2b->byte1;
2457 if (*row == NULL)
2459 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2460 pcm_init (*row, 0x100);
2462 pcm = *row + char2b->byte2;
2463 if (pcm_get_status (pcm) != PCM_VALID)
2465 BLOCK_INPUT;
2466 mac_query_char_extents (font->mac_style,
2467 (char2b->byte1 << 8) + char2b->byte2,
2468 NULL, NULL, pcm, NULL);
2469 UNBLOCK_INPUT;
2472 else
2474 #endif
2475 if (font->bounds.per_char != NULL)
2477 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2479 /* min_char_or_byte2 specifies the linear character index
2480 corresponding to the first element of the per_char array,
2481 max_char_or_byte2 is the index of the last character. A
2482 character with non-zero CHAR2B->byte1 is not in the font.
2483 A character with byte2 less than min_char_or_byte2 or
2484 greater max_char_or_byte2 is not in the font. */
2485 if (char2b->byte1 == 0
2486 && char2b->byte2 >= font->min_char_or_byte2
2487 && char2b->byte2 <= font->max_char_or_byte2)
2488 pcm = font->bounds.per_char
2489 + (char2b->byte2 - font->min_char_or_byte2);
2491 else
2493 /* If either min_byte1 or max_byte1 are nonzero, both
2494 min_char_or_byte2 and max_char_or_byte2 are less than
2495 256, and the 2-byte character index values corresponding
2496 to the per_char array element N (counting from 0) are:
2498 byte1 = N/D + min_byte1
2499 byte2 = N\D + min_char_or_byte2
2501 where:
2503 D = max_char_or_byte2 - min_char_or_byte2 + 1
2504 / = integer division
2505 \ = integer modulus */
2506 if (char2b->byte1 >= font->min_byte1
2507 && char2b->byte1 <= font->max_byte1
2508 && char2b->byte2 >= font->min_char_or_byte2
2509 && char2b->byte2 <= font->max_char_or_byte2)
2511 pcm = (font->bounds.per_char
2512 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2513 * (char2b->byte1 - font->min_byte1))
2514 + (char2b->byte2 - font->min_char_or_byte2));
2518 else
2520 /* If the per_char pointer is null, all glyphs between the first
2521 and last character indexes inclusive have the same
2522 information, as given by both min_bounds and max_bounds. */
2523 if (char2b->byte2 >= font->min_char_or_byte2
2524 && char2b->byte2 <= font->max_char_or_byte2)
2525 pcm = &font->max_bounds;
2527 #if USE_ATSUI
2529 #endif
2531 return ((pcm == NULL
2532 || (pcm->width == 0
2533 #if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2534 && (pcm->rbearing - pcm->lbearing) == 0
2535 #endif
2537 ? NULL : pcm);
2540 /* RIF:
2543 static XCharStruct *
2544 mac_per_char_metric (font, char2b, font_type)
2545 XFontStruct *font;
2546 XChar2b *char2b;
2547 int font_type;
2549 return x_per_char_metric (font, char2b);
2552 /* RIF:
2553 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
2554 the two-byte form of C. Encoding is returned in *CHAR2B. */
2556 static int
2557 mac_encode_char (c, char2b, font_info, two_byte_p)
2558 int c;
2559 XChar2b *char2b;
2560 struct font_info *font_info;
2561 int *two_byte_p;
2563 int charset = CHAR_CHARSET (c);
2564 XFontStruct *font = font_info->font;
2566 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2567 This may be either a program in a special encoder language or a
2568 fixed encoding. */
2569 if (font_info->font_encoder)
2571 /* It's a program. */
2572 struct ccl_program *ccl = font_info->font_encoder;
2574 check_ccl_update (ccl);
2575 if (CHARSET_DIMENSION (charset) == 1)
2577 ccl->reg[0] = charset;
2578 ccl->reg[1] = char2b->byte2;
2579 ccl->reg[2] = -1;
2581 else
2583 ccl->reg[0] = charset;
2584 ccl->reg[1] = char2b->byte1;
2585 ccl->reg[2] = char2b->byte2;
2588 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
2590 /* We assume that MSBs are appropriately set/reset by CCL
2591 program. */
2592 if (font->max_byte1 == 0) /* 1-byte font */
2593 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
2594 else
2595 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
2597 else if (font_info->encoding[charset])
2599 /* Fixed encoding scheme. See fontset.h for the meaning of the
2600 encoding numbers. */
2601 int enc = font_info->encoding[charset];
2603 if ((enc == 1 || enc == 2)
2604 && CHARSET_DIMENSION (charset) == 2)
2605 char2b->byte1 |= 0x80;
2607 if (enc == 1 || enc == 3)
2608 char2b->byte2 |= 0x80;
2610 if (enc == 4)
2612 int sjis1, sjis2;
2614 ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2);
2615 char2b->byte1 = sjis1;
2616 char2b->byte2 = sjis2;
2620 if (two_byte_p)
2621 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
2623 return FONT_TYPE_UNKNOWN;
2628 /***********************************************************************
2629 Glyph display
2630 ***********************************************************************/
2634 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2635 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2636 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2637 int));
2638 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2639 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2640 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2641 static void x_draw_glyph_string P_ ((struct glyph_string *));
2642 static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2643 static void x_set_cursor_gc P_ ((struct glyph_string *));
2644 static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2645 static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2646 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2647 unsigned long *, double, int));*/
2648 static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2649 double, int, unsigned long));
2650 static void x_setup_relief_colors P_ ((struct glyph_string *));
2651 static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2652 static void x_draw_image_relief P_ ((struct glyph_string *));
2653 static void x_draw_image_foreground P_ ((struct glyph_string *));
2654 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2655 int, int, int));
2656 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2657 int, int, int, int, int, int,
2658 Rect *));
2659 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2660 int, int, int, Rect *));
2662 #if GLYPH_DEBUG
2663 static void x_check_font P_ ((struct frame *, XFontStruct *));
2664 #endif
2667 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
2668 face. */
2670 static void
2671 x_set_cursor_gc (s)
2672 struct glyph_string *s;
2674 if (s->font == FRAME_FONT (s->f)
2675 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2676 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2677 && !s->cmp)
2678 s->gc = s->f->output_data.mac->cursor_gc;
2679 else
2681 /* Cursor on non-default face: must merge. */
2682 XGCValues xgcv;
2683 unsigned long mask;
2685 xgcv.background = s->f->output_data.mac->cursor_pixel;
2686 xgcv.foreground = s->face->background;
2688 /* If the glyph would be invisible, try a different foreground. */
2689 if (xgcv.foreground == xgcv.background)
2690 xgcv.foreground = s->face->foreground;
2691 if (xgcv.foreground == xgcv.background)
2692 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2693 if (xgcv.foreground == xgcv.background)
2694 xgcv.foreground = s->face->foreground;
2696 /* Make sure the cursor is distinct from text in this face. */
2697 if (xgcv.background == s->face->background
2698 && xgcv.foreground == s->face->foreground)
2700 xgcv.background = s->face->foreground;
2701 xgcv.foreground = s->face->background;
2704 IF_DEBUG (x_check_font (s->f, s->font));
2705 xgcv.font = s->font;
2706 mask = GCForeground | GCBackground | GCFont;
2708 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2709 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2710 mask, &xgcv);
2711 else
2712 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2713 = XCreateGC (s->display, s->window, mask, &xgcv);
2715 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2720 /* Set up S->gc of glyph string S for drawing text in mouse face. */
2722 static void
2723 x_set_mouse_face_gc (s)
2724 struct glyph_string *s;
2726 int face_id;
2727 struct face *face;
2729 /* What face has to be used last for the mouse face? */
2730 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2731 face = FACE_FROM_ID (s->f, face_id);
2732 if (face == NULL)
2733 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2735 if (s->first_glyph->type == CHAR_GLYPH)
2736 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2737 else
2738 face_id = FACE_FOR_CHAR (s->f, face, 0);
2739 s->face = FACE_FROM_ID (s->f, face_id);
2740 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2742 /* If font in this face is same as S->font, use it. */
2743 if (s->font == s->face->font)
2744 s->gc = s->face->gc;
2745 else
2747 /* Otherwise construct scratch_cursor_gc with values from FACE
2748 but font FONT. */
2749 XGCValues xgcv;
2750 unsigned long mask;
2752 xgcv.background = s->face->background;
2753 xgcv.foreground = s->face->foreground;
2754 IF_DEBUG (x_check_font (s->f, s->font));
2755 xgcv.font = s->font;
2756 mask = GCForeground | GCBackground | GCFont;
2758 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2759 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2760 mask, &xgcv);
2761 else
2762 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2763 = XCreateGC (s->display, s->window, mask, &xgcv);
2765 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2768 xassert (s->gc != 0);
2772 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2773 Faces to use in the mode line have already been computed when the
2774 matrix was built, so there isn't much to do, here. */
2776 static INLINE void
2777 x_set_mode_line_face_gc (s)
2778 struct glyph_string *s;
2780 s->gc = s->face->gc;
2784 /* Set S->gc of glyph string S for drawing that glyph string. Set
2785 S->stippled_p to a non-zero value if the face of S has a stipple
2786 pattern. */
2788 static INLINE void
2789 x_set_glyph_string_gc (s)
2790 struct glyph_string *s;
2792 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2794 if (s->hl == DRAW_NORMAL_TEXT)
2796 s->gc = s->face->gc;
2797 s->stippled_p = s->face->stipple != 0;
2799 else if (s->hl == DRAW_INVERSE_VIDEO)
2801 x_set_mode_line_face_gc (s);
2802 s->stippled_p = s->face->stipple != 0;
2804 else if (s->hl == DRAW_CURSOR)
2806 x_set_cursor_gc (s);
2807 s->stippled_p = 0;
2809 else if (s->hl == DRAW_MOUSE_FACE)
2811 x_set_mouse_face_gc (s);
2812 s->stippled_p = s->face->stipple != 0;
2814 else if (s->hl == DRAW_IMAGE_RAISED
2815 || s->hl == DRAW_IMAGE_SUNKEN)
2817 s->gc = s->face->gc;
2818 s->stippled_p = s->face->stipple != 0;
2820 else
2822 s->gc = s->face->gc;
2823 s->stippled_p = s->face->stipple != 0;
2826 /* GC must have been set. */
2827 xassert (s->gc != 0);
2831 /* Set clipping for output of glyph string S. S may be part of a mode
2832 line or menu if we don't have X toolkit support. */
2834 static INLINE void
2835 x_set_glyph_string_clipping (s)
2836 struct glyph_string *s;
2838 Rect rects[MAX_CLIP_RECTS];
2839 int n;
2841 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
2842 mac_set_clip_rectangles (s->display, s->gc, rects, n);
2846 /* RIF:
2847 Compute left and right overhang of glyph string S. If S is a glyph
2848 string for a composition, assume overhangs don't exist. */
2850 static void
2851 mac_compute_glyph_string_overhangs (s)
2852 struct glyph_string *s;
2854 if (!(s->cmp == NULL
2855 && s->first_glyph->type == CHAR_GLYPH))
2856 return;
2858 if (!s->two_byte_p
2859 #if USE_ATSUI
2860 || s->font->mac_style
2861 #endif
2864 XCharStruct cs;
2866 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2867 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2868 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2870 else
2872 Rect r;
2873 MacFontStruct *font = s->font;
2875 #if USE_CG_DRAWING
2876 mac_prepare_for_quickdraw (s->f);
2877 #endif
2878 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
2880 TextFont (font->mac_fontnum);
2881 TextSize (font->mac_fontsize);
2882 TextFace (font->mac_fontface);
2884 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
2886 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
2887 s->left_overhang = r.left < 0 ? -r.left : 0;
2892 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
2894 static INLINE void
2895 x_clear_glyph_string_rect (s, x, y, w, h)
2896 struct glyph_string *s;
2897 int x, y, w, h;
2899 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
2903 /* Draw the background of glyph_string S. If S->background_filled_p
2904 is non-zero don't draw it. FORCE_P non-zero means draw the
2905 background even if it wouldn't be drawn normally. This is used
2906 when a string preceding S draws into the background of S, or S
2907 contains the first component of a composition. */
2909 static void
2910 x_draw_glyph_string_background (s, force_p)
2911 struct glyph_string *s;
2912 int force_p;
2914 /* Nothing to do if background has already been drawn or if it
2915 shouldn't be drawn in the first place. */
2916 if (!s->background_filled_p)
2918 int box_line_width = max (s->face->box_line_width, 0);
2920 #if 0 /* MAC_TODO: stipple */
2921 if (s->stippled_p)
2923 /* Fill background with a stipple pattern. */
2924 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2925 XFillRectangle (s->display, s->window, s->gc, s->x,
2926 s->y + box_line_width,
2927 s->background_width,
2928 s->height - 2 * box_line_width);
2929 XSetFillStyle (s->display, s->gc, FillSolid);
2930 s->background_filled_p = 1;
2932 else
2933 #endif
2934 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2935 || s->font_not_found_p
2936 || s->extends_to_end_of_line_p
2937 || force_p)
2939 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
2940 s->background_width,
2941 s->height - 2 * box_line_width);
2942 s->background_filled_p = 1;
2948 /* Draw the foreground of glyph string S. */
2950 static void
2951 x_draw_glyph_string_foreground (s)
2952 struct glyph_string *s;
2954 int i, x, bg_width;
2956 /* If first glyph of S has a left box line, start drawing the text
2957 of S to the right of that box line. */
2958 if (s->face->box != FACE_NO_BOX
2959 && s->first_glyph->left_box_line_p)
2960 x = s->x + abs (s->face->box_line_width);
2961 else
2962 x = s->x;
2964 /* Draw characters of S as rectangles if S's font could not be
2965 loaded. */
2966 if (s->font_not_found_p)
2968 for (i = 0; i < s->nchars; ++i)
2970 struct glyph *g = s->first_glyph + i;
2971 mac_draw_rectangle (s->f, s->gc, x, s->y,
2972 g->pixel_width - 1, s->height - 1);
2973 x += g->pixel_width;
2976 else
2978 char *char1b = (char *) s->char2b;
2979 int boff = s->font_info->baseline_offset;
2981 if (s->font_info->vertical_centering)
2982 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
2984 /* If we can use 8-bit functions, condense S->char2b. */
2985 if (!s->two_byte_p
2986 #if USE_ATSUI
2987 && GC_FONT (s->gc)->mac_style == NULL
2988 #endif
2990 for (i = 0; i < s->nchars; ++i)
2991 char1b[i] = s->char2b[i].byte2;
2993 /* Draw text with XDrawString if background has already been
2994 filled. Otherwise, use XDrawImageString. (Note that
2995 XDrawImageString is usually faster than XDrawString.) Always
2996 use XDrawImageString when drawing the cursor so that there is
2997 no chance that characters under a box cursor are invisible. */
2998 if (s->for_overlaps
2999 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3000 bg_width = 0; /* Corresponds to XDrawString. */
3001 else
3002 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3004 if (s->two_byte_p
3005 #if USE_ATSUI
3006 || GC_FONT (s->gc)->mac_style
3007 #endif
3009 #if USE_CG_TEXT_DRAWING
3010 if (!s->two_byte_p
3011 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
3012 s->char2b, s->nchars, bg_width,
3013 s->face->overstrike))
3015 else
3016 #endif
3017 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
3018 s->char2b, s->nchars, bg_width,
3019 s->face->overstrike);
3020 else
3021 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
3022 char1b, s->nchars, bg_width,
3023 s->face->overstrike);
3027 /* Draw the foreground of composite glyph string S. */
3029 static void
3030 x_draw_composite_glyph_string_foreground (s)
3031 struct glyph_string *s;
3033 int i, x;
3035 /* If first glyph of S has a left box line, start drawing the text
3036 of S to the right of that box line. */
3037 if (s->face->box != FACE_NO_BOX
3038 && s->first_glyph->left_box_line_p)
3039 x = s->x + abs (s->face->box_line_width);
3040 else
3041 x = s->x;
3043 /* S is a glyph string for a composition. S->gidx is the index of
3044 the first character drawn for glyphs of this composition.
3045 S->gidx == 0 means we are drawing the very first character of
3046 this composition. */
3048 /* Draw a rectangle for the composition if the font for the very
3049 first character of the composition could not be loaded. */
3050 if (s->font_not_found_p)
3052 if (s->gidx == 0)
3053 mac_draw_rectangle (s->f, s->gc, x, s->y,
3054 s->width - 1, s->height - 1);
3056 else
3058 for (i = 0; i < s->nchars; i++, ++s->gidx)
3059 mac_draw_image_string_16 (s->f, s->gc,
3060 x + s->cmp->offsets[s->gidx * 2],
3061 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3062 s->char2b + i, 1, 0, s->face->overstrike);
3067 #ifdef USE_X_TOOLKIT
3069 static struct frame *x_frame_of_widget P_ ((Widget));
3072 /* Return the frame on which widget WIDGET is used.. Abort if frame
3073 cannot be determined. */
3075 static struct frame *
3076 x_frame_of_widget (widget)
3077 Widget widget;
3079 struct x_display_info *dpyinfo;
3080 Lisp_Object tail;
3081 struct frame *f;
3083 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3085 /* Find the top-level shell of the widget. Note that this function
3086 can be called when the widget is not yet realized, so XtWindow
3087 (widget) == 0. That's the reason we can't simply use
3088 x_any_window_to_frame. */
3089 while (!XtIsTopLevelShell (widget))
3090 widget = XtParent (widget);
3092 /* Look for a frame with that top-level widget. Allocate the color
3093 on that frame to get the right gamma correction value. */
3094 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3095 if (GC_FRAMEP (XCAR (tail))
3096 && (f = XFRAME (XCAR (tail)),
3097 (f->output_data.nothing != 1
3098 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3099 && f->output_data.x->widget == widget)
3100 return f;
3102 abort ();
3106 /* Allocate the color COLOR->pixel on the screen and display of
3107 widget WIDGET in colormap CMAP. If an exact match cannot be
3108 allocated, try the nearest color available. Value is non-zero
3109 if successful. This is called from lwlib. */
3112 x_alloc_nearest_color_for_widget (widget, cmap, color)
3113 Widget widget;
3114 Colormap cmap;
3115 XColor *color;
3117 struct frame *f = x_frame_of_widget (widget);
3118 return x_alloc_nearest_color (f, cmap, color);
3122 #endif /* USE_X_TOOLKIT */
3124 #if 0 /* MAC_TODO */
3126 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3127 CMAP. If an exact match can't be allocated, try the nearest color
3128 available. Value is non-zero if successful. Set *COLOR to the
3129 color allocated. */
3132 x_alloc_nearest_color (f, cmap, color)
3133 struct frame *f;
3134 Colormap cmap;
3135 XColor *color;
3137 Display *display = FRAME_X_DISPLAY (f);
3138 Screen *screen = FRAME_X_SCREEN (f);
3139 int rc;
3141 gamma_correct (f, color);
3142 rc = XAllocColor (display, cmap, color);
3143 if (rc == 0)
3145 /* If we got to this point, the colormap is full, so we're going
3146 to try to get the next closest color. The algorithm used is
3147 a least-squares matching, which is what X uses for closest
3148 color matching with StaticColor visuals. */
3149 int nearest, i;
3150 unsigned long nearest_delta = ~0;
3151 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3152 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3154 for (i = 0; i < ncells; ++i)
3155 cells[i].pixel = i;
3156 XQueryColors (display, cmap, cells, ncells);
3158 for (nearest = i = 0; i < ncells; ++i)
3160 long dred = (color->red >> 8) - (cells[i].red >> 8);
3161 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3162 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3163 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3165 if (delta < nearest_delta)
3167 nearest = i;
3168 nearest_delta = delta;
3172 color->red = cells[nearest].red;
3173 color->green = cells[nearest].green;
3174 color->blue = cells[nearest].blue;
3175 rc = XAllocColor (display, cmap, color);
3178 #ifdef DEBUG_X_COLORS
3179 if (rc)
3180 register_color (color->pixel);
3181 #endif /* DEBUG_X_COLORS */
3183 return rc;
3187 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3188 It's necessary to do this instead of just using PIXEL directly to
3189 get color reference counts right. */
3191 unsigned long
3192 x_copy_color (f, pixel)
3193 struct frame *f;
3194 unsigned long pixel;
3196 XColor color;
3198 color.pixel = pixel;
3199 BLOCK_INPUT;
3200 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3201 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3202 UNBLOCK_INPUT;
3203 #ifdef DEBUG_X_COLORS
3204 register_color (pixel);
3205 #endif
3206 return color.pixel;
3210 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3211 It's necessary to do this instead of just using PIXEL directly to
3212 get color reference counts right. */
3214 unsigned long
3215 x_copy_dpy_color (dpy, cmap, pixel)
3216 Display *dpy;
3217 Colormap cmap;
3218 unsigned long pixel;
3220 XColor color;
3222 color.pixel = pixel;
3223 BLOCK_INPUT;
3224 XQueryColor (dpy, cmap, &color);
3225 XAllocColor (dpy, cmap, &color);
3226 UNBLOCK_INPUT;
3227 #ifdef DEBUG_X_COLORS
3228 register_color (pixel);
3229 #endif
3230 return color.pixel;
3233 #endif /* MAC_TODO */
3236 /* Brightness beyond which a color won't have its highlight brightness
3237 boosted.
3239 Nominally, highlight colors for `3d' faces are calculated by
3240 brightening an object's color by a constant scale factor, but this
3241 doesn't yield good results for dark colors, so for colors who's
3242 brightness is less than this value (on a scale of 0-255) have to
3243 use an additional additive factor.
3245 The value here is set so that the default menu-bar/mode-line color
3246 (grey75) will not have its highlights changed at all. */
3247 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3250 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
3251 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3252 If this produces the same color as COLOR, try a color where all RGB
3253 values have DELTA added. Return the allocated color in *COLOR.
3254 DISPLAY is the X display, CMAP is the colormap to operate on.
3255 Value is non-zero if successful. */
3257 static int
3258 mac_alloc_lighter_color (f, color, factor, delta)
3259 struct frame *f;
3260 unsigned long *color;
3261 double factor;
3262 int delta;
3264 unsigned long new;
3265 long bright;
3267 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3268 delta /= 256;
3270 /* Change RGB values by specified FACTOR. Avoid overflow! */
3271 xassert (factor >= 0);
3272 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3273 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3274 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3276 /* Calculate brightness of COLOR. */
3277 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3278 + BLUE_FROM_ULONG (*color)) / 6;
3280 /* We only boost colors that are darker than
3281 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3282 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3283 /* Make an additive adjustment to NEW, because it's dark enough so
3284 that scaling by FACTOR alone isn't enough. */
3286 /* How far below the limit this color is (0 - 1, 1 being darker). */
3287 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3288 /* The additive adjustment. */
3289 int min_delta = delta * dimness * factor / 2;
3291 if (factor < 1)
3292 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3293 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3294 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3295 else
3296 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3297 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3298 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3301 if (new == *color)
3302 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3303 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3304 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3306 /* MAC_TODO: Map to palette and retry with delta if same? */
3307 /* MAC_TODO: Free colors (if using palette)? */
3309 if (new == *color)
3310 return 0;
3312 *color = new;
3314 return 1;
3318 /* Set up the foreground color for drawing relief lines of glyph
3319 string S. RELIEF is a pointer to a struct relief containing the GC
3320 with which lines will be drawn. Use a color that is FACTOR or
3321 DELTA lighter or darker than the relief's background which is found
3322 in S->f->output_data.x->relief_background. If such a color cannot
3323 be allocated, use DEFAULT_PIXEL, instead. */
3325 static void
3326 x_setup_relief_color (f, relief, factor, delta, default_pixel)
3327 struct frame *f;
3328 struct relief *relief;
3329 double factor;
3330 int delta;
3331 unsigned long default_pixel;
3333 XGCValues xgcv;
3334 struct mac_output *di = f->output_data.mac;
3335 unsigned long mask = GCForeground;
3336 unsigned long pixel;
3337 unsigned long background = di->relief_background;
3338 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3340 /* MAC_TODO: Free colors (if using palette)? */
3342 /* Allocate new color. */
3343 xgcv.foreground = default_pixel;
3344 pixel = background;
3345 if (dpyinfo->n_planes != 1
3346 && mac_alloc_lighter_color (f, &pixel, factor, delta))
3348 relief->allocated_p = 1;
3349 xgcv.foreground = relief->pixel = pixel;
3352 if (relief->gc == 0)
3354 #if 0 /* MAC_TODO: stipple */
3355 xgcv.stipple = dpyinfo->gray;
3356 mask |= GCStipple;
3357 #endif
3358 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3360 else
3361 XChangeGC (NULL, relief->gc, mask, &xgcv);
3365 /* Set up colors for the relief lines around glyph string S. */
3367 static void
3368 x_setup_relief_colors (s)
3369 struct glyph_string *s;
3371 struct mac_output *di = s->f->output_data.mac;
3372 unsigned long color;
3374 if (s->face->use_box_color_for_shadows_p)
3375 color = s->face->box_color;
3376 else if (s->first_glyph->type == IMAGE_GLYPH
3377 && s->img->pixmap
3378 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3379 color = IMAGE_BACKGROUND (s->img, s->f, 0);
3380 else
3382 XGCValues xgcv;
3384 /* Get the background color of the face. */
3385 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3386 color = xgcv.background;
3389 if (di->white_relief.gc == 0
3390 || color != di->relief_background)
3392 di->relief_background = color;
3393 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3394 WHITE_PIX_DEFAULT (s->f));
3395 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3396 BLACK_PIX_DEFAULT (s->f));
3401 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
3402 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3403 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3404 relief. LEFT_P non-zero means draw a relief on the left side of
3405 the rectangle. RIGHT_P non-zero means draw a relief on the right
3406 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3407 when drawing. */
3409 static void
3410 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3411 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
3412 struct frame *f;
3413 int left_x, top_y, right_x, bottom_y, width;
3414 int top_p, bot_p, left_p, right_p, raised_p;
3415 Rect *clip_rect;
3417 Display *dpy = FRAME_MAC_DISPLAY (f);
3418 int i;
3419 GC gc;
3421 if (raised_p)
3422 gc = f->output_data.mac->white_relief.gc;
3423 else
3424 gc = f->output_data.mac->black_relief.gc;
3425 mac_set_clip_rectangles (dpy, gc, clip_rect, 1);
3427 /* Top. */
3428 if (top_p)
3429 for (i = 0; i < width; ++i)
3430 mac_draw_line (f, gc,
3431 left_x + i * left_p, top_y + i,
3432 right_x + 1 - i * right_p, top_y + i);
3434 /* Left. */
3435 if (left_p)
3436 for (i = 0; i < width; ++i)
3437 mac_draw_line (f, gc,
3438 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
3440 mac_reset_clip_rectangles (dpy, gc);
3441 if (raised_p)
3442 gc = f->output_data.mac->black_relief.gc;
3443 else
3444 gc = f->output_data.mac->white_relief.gc;
3445 mac_set_clip_rectangles (dpy, gc, clip_rect, 1);
3447 /* Bottom. */
3448 if (bot_p)
3449 for (i = 0; i < width; ++i)
3450 mac_draw_line (f, gc,
3451 left_x + i * left_p, bottom_y - i,
3452 right_x + 1 - i * right_p, bottom_y - i);
3454 /* Right. */
3455 if (right_p)
3456 for (i = 0; i < width; ++i)
3457 mac_draw_line (f, gc,
3458 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3460 mac_reset_clip_rectangles (dpy, gc);
3464 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3465 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3466 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3467 left side of the rectangle. RIGHT_P non-zero means draw a line
3468 on the right side of the rectangle. CLIP_RECT is the clipping
3469 rectangle to use when drawing. */
3471 static void
3472 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3473 left_p, right_p, clip_rect)
3474 struct glyph_string *s;
3475 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
3476 Rect *clip_rect;
3478 XGCValues xgcv;
3480 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3481 XSetForeground (s->display, s->gc, s->face->box_color);
3482 mac_set_clip_rectangles (s->display, s->gc, clip_rect, 1);
3484 /* Top. */
3485 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3486 right_x - left_x + 1, width);
3488 /* Left. */
3489 if (left_p)
3490 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3491 width, bottom_y - top_y + 1);
3493 /* Bottom. */
3494 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3495 right_x - left_x + 1, width);
3497 /* Right. */
3498 if (right_p)
3499 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3500 top_y, width, bottom_y - top_y + 1);
3502 XSetForeground (s->display, s->gc, xgcv.foreground);
3503 mac_reset_clip_rectangles (s->display, s->gc);
3507 /* Draw a box around glyph string S. */
3509 static void
3510 x_draw_glyph_string_box (s)
3511 struct glyph_string *s;
3513 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3514 int left_p, right_p;
3515 struct glyph *last_glyph;
3516 Rect clip_rect;
3518 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3519 ? WINDOW_RIGHT_EDGE_X (s->w)
3520 : window_box_right (s->w, s->area));
3522 /* The glyph that may have a right box line. */
3523 last_glyph = (s->cmp || s->img
3524 ? s->first_glyph
3525 : s->first_glyph + s->nchars - 1);
3527 width = abs (s->face->box_line_width);
3528 raised_p = s->face->box == FACE_RAISED_BOX;
3529 left_x = s->x;
3530 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3531 ? last_x - 1
3532 : min (last_x, s->x + s->background_width) - 1);
3533 top_y = s->y;
3534 bottom_y = top_y + s->height - 1;
3536 left_p = (s->first_glyph->left_box_line_p
3537 || (s->hl == DRAW_MOUSE_FACE
3538 && (s->prev == NULL
3539 || s->prev->hl != s->hl)));
3540 right_p = (last_glyph->right_box_line_p
3541 || (s->hl == DRAW_MOUSE_FACE
3542 && (s->next == NULL
3543 || s->next->hl != s->hl)));
3545 get_glyph_string_clip_rect (s, &clip_rect);
3547 if (s->face->box == FACE_SIMPLE_BOX)
3548 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3549 left_p, right_p, &clip_rect);
3550 else
3552 x_setup_relief_colors (s);
3553 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3554 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
3559 /* Draw foreground of image glyph string S. */
3561 static void
3562 x_draw_image_foreground (s)
3563 struct glyph_string *s;
3565 int x = s->x;
3566 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3568 /* If first glyph of S has a left box line, start drawing it to the
3569 right of that line. */
3570 if (s->face->box != FACE_NO_BOX
3571 && s->first_glyph->left_box_line_p
3572 && s->slice.x == 0)
3573 x += abs (s->face->box_line_width);
3575 /* If there is a margin around the image, adjust x- and y-position
3576 by that margin. */
3577 if (s->slice.x == 0)
3578 x += s->img->hmargin;
3579 if (s->slice.y == 0)
3580 y += s->img->vmargin;
3582 if (s->img->pixmap)
3584 x_set_glyph_string_clipping (s);
3586 #if USE_CG_DRAWING
3587 mac_draw_cg_image (s->img->data.ptr_val,
3588 s->f, s->gc, s->slice.x, s->slice.y,
3589 s->slice.width, s->slice.height, x, y, 1);
3590 #endif
3591 if (s->img->mask)
3592 #if !USE_CG_DRAWING
3593 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3594 s->f, s->gc, s->slice.x, s->slice.y,
3595 s->slice.width, s->slice.height, x, y);
3596 #else
3598 #endif
3599 else
3601 #if !USE_CG_DRAWING
3602 mac_copy_area (s->img->pixmap,
3603 s->f, s->gc, s->slice.x, s->slice.y,
3604 s->slice.width, s->slice.height, x, y);
3605 #endif
3607 /* When the image has a mask, we can expect that at
3608 least part of a mouse highlight or a block cursor will
3609 be visible. If the image doesn't have a mask, make
3610 a block cursor visible by drawing a rectangle around
3611 the image. I believe it's looking better if we do
3612 nothing here for mouse-face. */
3613 if (s->hl == DRAW_CURSOR)
3615 int r = s->img->relief;
3616 if (r < 0) r = -r;
3617 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
3618 s->slice.width + r*2 - 1,
3619 s->slice.height + r*2 - 1);
3623 else
3624 /* Draw a rectangle if image could not be loaded. */
3625 mac_draw_rectangle (s->f, s->gc, x, y,
3626 s->slice.width - 1, s->slice.height - 1);
3630 /* Draw a relief around the image glyph string S. */
3632 static void
3633 x_draw_image_relief (s)
3634 struct glyph_string *s;
3636 int x0, y0, x1, y1, thick, raised_p;
3637 Rect r;
3638 int x = s->x;
3639 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3641 /* If first glyph of S has a left box line, start drawing it to the
3642 right of that line. */
3643 if (s->face->box != FACE_NO_BOX
3644 && s->first_glyph->left_box_line_p
3645 && s->slice.x == 0)
3646 x += abs (s->face->box_line_width);
3648 /* If there is a margin around the image, adjust x- and y-position
3649 by that margin. */
3650 if (s->slice.x == 0)
3651 x += s->img->hmargin;
3652 if (s->slice.y == 0)
3653 y += s->img->vmargin;
3655 if (s->hl == DRAW_IMAGE_SUNKEN
3656 || s->hl == DRAW_IMAGE_RAISED)
3658 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3659 raised_p = s->hl == DRAW_IMAGE_RAISED;
3661 else
3663 thick = abs (s->img->relief);
3664 raised_p = s->img->relief > 0;
3667 x0 = x - thick;
3668 y0 = y - thick;
3669 x1 = x + s->slice.width + thick - 1;
3670 y1 = y + s->slice.height + thick - 1;
3672 x_setup_relief_colors (s);
3673 get_glyph_string_clip_rect (s, &r);
3674 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3675 s->slice.y == 0,
3676 s->slice.y + s->slice.height == s->img->height,
3677 s->slice.x == 0,
3678 s->slice.x + s->slice.width == s->img->width,
3679 &r);
3683 /* Draw part of the background of glyph string S. X, Y, W, and H
3684 give the rectangle to draw. */
3686 static void
3687 x_draw_glyph_string_bg_rect (s, x, y, w, h)
3688 struct glyph_string *s;
3689 int x, y, w, h;
3691 #if 0 /* MAC_TODO: stipple */
3692 if (s->stippled_p)
3694 /* Fill background with a stipple pattern. */
3695 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3696 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3697 XSetFillStyle (s->display, s->gc, FillSolid);
3699 else
3700 #endif /* MAC_TODO */
3701 x_clear_glyph_string_rect (s, x, y, w, h);
3705 /* Draw image glyph string S.
3707 s->y
3708 s->x +-------------------------
3709 | s->face->box
3711 | +-------------------------
3712 | | s->img->margin
3714 | | +-------------------
3715 | | | the image
3719 static void
3720 x_draw_image_glyph_string (s)
3721 struct glyph_string *s;
3723 int x, y;
3724 int box_line_hwidth = abs (s->face->box_line_width);
3725 int box_line_vwidth = max (s->face->box_line_width, 0);
3726 int height;
3728 height = s->height - 2 * box_line_vwidth;
3731 /* Fill background with face under the image. Do it only if row is
3732 taller than image or if image has a clip mask to reduce
3733 flickering. */
3734 s->stippled_p = s->face->stipple != 0;
3735 if (height > s->slice.height
3736 || s->img->hmargin
3737 || s->img->vmargin
3738 || s->img->mask
3739 || s->img->pixmap == 0
3740 || s->width != s->background_width)
3742 x = s->x;
3743 if (s->first_glyph->left_box_line_p
3744 && s->slice.x == 0)
3745 x += box_line_hwidth;
3747 y = s->y;
3748 if (s->slice.y == 0)
3749 y += box_line_vwidth;
3751 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3753 s->background_filled_p = 1;
3756 /* Draw the foreground. */
3757 x_draw_image_foreground (s);
3759 /* If we must draw a relief around the image, do it. */
3760 if (s->img->relief
3761 || s->hl == DRAW_IMAGE_RAISED
3762 || s->hl == DRAW_IMAGE_SUNKEN)
3763 x_draw_image_relief (s);
3767 /* Draw stretch glyph string S. */
3769 static void
3770 x_draw_stretch_glyph_string (s)
3771 struct glyph_string *s;
3773 xassert (s->first_glyph->type == STRETCH_GLYPH);
3774 s->stippled_p = s->face->stipple != 0;
3776 if (s->hl == DRAW_CURSOR
3777 && !x_stretch_cursor_p)
3779 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3780 as wide as the stretch glyph. */
3781 int width, background_width = s->background_width;
3782 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3784 if (x < left_x)
3786 background_width -= left_x - x;
3787 x = left_x;
3789 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3791 /* Draw cursor. */
3792 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3794 /* Clear rest using the GC of the original non-cursor face. */
3795 if (width < background_width)
3797 int y = s->y;
3798 int w = background_width - width, h = s->height;
3799 Rect r;
3800 GC gc;
3802 x += width;
3803 if (s->row->mouse_face_p
3804 && cursor_in_mouse_face_p (s->w))
3806 x_set_mouse_face_gc (s);
3807 gc = s->gc;
3809 else
3810 gc = s->face->gc;
3812 get_glyph_string_clip_rect (s, &r);
3813 mac_set_clip_rectangles (s->display, gc, &r, 1);
3815 #if 0 /* MAC_TODO: stipple */
3816 if (s->face->stipple)
3818 /* Fill background with a stipple pattern. */
3819 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3820 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3821 XSetFillStyle (s->display, gc, FillSolid);
3823 else
3824 #endif /* MAC_TODO */
3825 mac_erase_rectangle (s->f, gc, x, y, w, h);
3828 else if (!s->background_filled_p)
3830 int background_width = s->background_width;
3831 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3833 /* Don't draw into left margin, fringe or scrollbar area
3834 except for header line and mode line. */
3835 if (x < left_x && !s->row->mode_line_p)
3837 background_width -= left_x - x;
3838 x = left_x;
3840 if (background_width > 0)
3841 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3844 s->background_filled_p = 1;
3848 /* Draw glyph string S. */
3850 static void
3851 x_draw_glyph_string (s)
3852 struct glyph_string *s;
3854 int relief_drawn_p = 0;
3856 /* If S draws into the background of its successor that does not
3857 draw a cursor, draw the background of the successor first so that
3858 S can draw into it. This makes S->next use XDrawString instead
3859 of XDrawImageString. */
3860 if (s->next && s->right_overhang && !s->for_overlaps
3861 && s->next->hl != DRAW_CURSOR)
3863 xassert (s->next->img == NULL);
3864 x_set_glyph_string_gc (s->next);
3865 x_set_glyph_string_clipping (s->next);
3866 x_draw_glyph_string_background (s->next, 1);
3869 /* Set up S->gc, set clipping and draw S. */
3870 x_set_glyph_string_gc (s);
3872 /* Draw relief (if any) in advance for char/composition so that the
3873 glyph string can be drawn over it. */
3874 if (!s->for_overlaps
3875 && s->face->box != FACE_NO_BOX
3876 && (s->first_glyph->type == CHAR_GLYPH
3877 || s->first_glyph->type == COMPOSITE_GLYPH))
3880 x_set_glyph_string_clipping (s);
3881 x_draw_glyph_string_background (s, 1);
3882 x_draw_glyph_string_box (s);
3883 x_set_glyph_string_clipping (s);
3884 relief_drawn_p = 1;
3886 else
3887 x_set_glyph_string_clipping (s);
3889 switch (s->first_glyph->type)
3891 case IMAGE_GLYPH:
3892 x_draw_image_glyph_string (s);
3893 break;
3895 case STRETCH_GLYPH:
3896 x_draw_stretch_glyph_string (s);
3897 break;
3899 case CHAR_GLYPH:
3900 if (s->for_overlaps)
3901 s->background_filled_p = 1;
3902 else
3903 x_draw_glyph_string_background (s, 0);
3904 x_draw_glyph_string_foreground (s);
3905 break;
3907 case COMPOSITE_GLYPH:
3908 if (s->for_overlaps || s->gidx > 0)
3909 s->background_filled_p = 1;
3910 else
3911 x_draw_glyph_string_background (s, 1);
3912 x_draw_composite_glyph_string_foreground (s);
3913 break;
3915 default:
3916 abort ();
3919 if (!s->for_overlaps)
3921 /* Draw underline. */
3922 if (s->face->underline_p)
3924 unsigned long tem, h;
3925 int y;
3927 #if 0
3928 /* Get the underline thickness. Default is 1 pixel. */
3929 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
3930 #endif
3931 h = 1;
3933 y = s->y + s->height - h;
3934 if (!x_underline_at_descent_line)
3936 /* Get the underline position. This is the recommended
3937 vertical offset in pixels from the baseline to the top of
3938 the underline. This is a signed value according to the
3939 specs, and its default is
3941 ROUND ((maximum descent) / 2), with
3942 ROUND(x) = floor (x + 0.5) */
3944 #if 0
3945 if (x_use_underline_position_properties
3946 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
3947 y = s->ybase + (long) tem;
3948 else
3949 #endif
3950 if (s->face->font)
3951 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
3954 if (s->face->underline_defaulted_p)
3955 mac_fill_rectangle (s->f, s->gc, s->x, y,
3956 s->background_width, h);
3957 else
3959 XGCValues xgcv;
3960 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3961 XSetForeground (s->display, s->gc, s->face->underline_color);
3962 mac_fill_rectangle (s->f, s->gc, s->x, y,
3963 s->background_width, h);
3964 XSetForeground (s->display, s->gc, xgcv.foreground);
3968 /* Draw overline. */
3969 if (s->face->overline_p)
3971 unsigned long dy = 0, h = 1;
3973 if (s->face->overline_color_defaulted_p)
3974 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3975 s->background_width, h);
3976 else
3978 XGCValues xgcv;
3979 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3980 XSetForeground (s->display, s->gc, s->face->overline_color);
3981 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3982 s->background_width, h);
3983 XSetForeground (s->display, s->gc, xgcv.foreground);
3987 /* Draw strike-through. */
3988 if (s->face->strike_through_p)
3990 unsigned long h = 1;
3991 unsigned long dy = (s->height - h) / 2;
3993 if (s->face->strike_through_color_defaulted_p)
3994 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3995 s->width, h);
3996 else
3998 XGCValues xgcv;
3999 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4000 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4001 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4002 s->width, h);
4003 XSetForeground (s->display, s->gc, xgcv.foreground);
4007 /* Draw relief if not yet drawn. */
4008 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
4009 x_draw_glyph_string_box (s);
4012 /* Reset clipping. */
4013 mac_reset_clip_rectangles (s->display, s->gc);
4016 /* Shift display to make room for inserted glyphs. */
4018 void
4019 mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4020 struct frame *f;
4021 int x, y, width, height, shift_by;
4023 mac_scroll_area (f, f->output_data.mac->normal_gc,
4024 x, y, width, height,
4025 x + shift_by, y);
4028 /* Delete N glyphs at the nominal cursor position. Not implemented
4029 for X frames. */
4031 static void
4032 x_delete_glyphs (n)
4033 register int n;
4035 abort ();
4039 /* Clear entire frame. If updating_frame is non-null, clear that
4040 frame. Otherwise clear the selected frame. */
4042 static void
4043 x_clear_frame ()
4045 struct frame *f;
4047 if (updating_frame)
4048 f = updating_frame;
4049 else
4050 f = SELECTED_FRAME ();
4052 /* Clearing the frame will erase any cursor, so mark them all as no
4053 longer visible. */
4054 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4055 output_cursor.hpos = output_cursor.vpos = 0;
4056 output_cursor.x = -1;
4058 /* We don't set the output cursor here because there will always
4059 follow an explicit cursor_to. */
4060 BLOCK_INPUT;
4061 mac_clear_window (f);
4063 /* We have to clear the scroll bars, too. If we have changed
4064 colors or something like that, then they should be notified. */
4065 x_scroll_bar_clear (f);
4067 XFlush (FRAME_MAC_DISPLAY (f));
4068 UNBLOCK_INPUT;
4073 /* Invert the middle quarter of the frame for .15 sec. */
4075 /* We use the select system call to do the waiting, so we have to make
4076 sure it's available. If it isn't, we just won't do visual bells. */
4078 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4081 /* Subtract the `struct timeval' values X and Y, storing the result in
4082 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4084 static int
4085 timeval_subtract (result, x, y)
4086 struct timeval *result, x, y;
4088 /* Perform the carry for the later subtraction by updating y. This
4089 is safer because on some systems the tv_sec member is unsigned. */
4090 if (x.tv_usec < y.tv_usec)
4092 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4093 y.tv_usec -= 1000000 * nsec;
4094 y.tv_sec += nsec;
4097 if (x.tv_usec - y.tv_usec > 1000000)
4099 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4100 y.tv_usec += 1000000 * nsec;
4101 y.tv_sec -= nsec;
4104 /* Compute the time remaining to wait. tv_usec is certainly
4105 positive. */
4106 result->tv_sec = x.tv_sec - y.tv_sec;
4107 result->tv_usec = x.tv_usec - y.tv_usec;
4109 /* Return indication of whether the result should be considered
4110 negative. */
4111 return x.tv_sec < y.tv_sec;
4114 void
4115 XTflash (f)
4116 struct frame *f;
4118 /* Get the height not including a menu bar widget. */
4119 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4120 /* Height of each line to flash. */
4121 int flash_height = FRAME_LINE_HEIGHT (f);
4122 /* These will be the left and right margins of the rectangles. */
4123 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4124 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4126 int width;
4128 /* Don't flash the area between a scroll bar and the frame
4129 edge it is next to. */
4130 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4132 case vertical_scroll_bar_left:
4133 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4134 break;
4136 case vertical_scroll_bar_right:
4137 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4138 break;
4140 default:
4141 break;
4144 width = flash_right - flash_left;
4146 BLOCK_INPUT;
4148 /* If window is tall, flash top and bottom line. */
4149 if (height > 3 * FRAME_LINE_HEIGHT (f))
4151 mac_invert_rectangle (f, flash_left,
4152 (FRAME_INTERNAL_BORDER_WIDTH (f)
4153 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4154 width, flash_height);
4155 mac_invert_rectangle (f, flash_left,
4156 (height - flash_height
4157 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4158 width, flash_height);
4160 else
4161 /* If it is short, flash it all. */
4162 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4163 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4165 x_flush (f);
4168 struct timeval wakeup;
4170 EMACS_GET_TIME (wakeup);
4172 /* Compute time to wait until, propagating carry from usecs. */
4173 wakeup.tv_usec += 150000;
4174 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4175 wakeup.tv_usec %= 1000000;
4177 /* Keep waiting until past the time wakeup or any input gets
4178 available. */
4179 while (! detect_input_pending ())
4181 struct timeval current;
4182 struct timeval timeout;
4184 EMACS_GET_TIME (current);
4186 /* Break if result would be negative. */
4187 if (timeval_subtract (&current, wakeup, current))
4188 break;
4190 /* How long `select' should wait. */
4191 timeout.tv_sec = 0;
4192 timeout.tv_usec = 10000;
4194 /* Try to wait that long--but we might wake up sooner. */
4195 select (0, NULL, NULL, NULL, &timeout);
4199 /* If window is tall, flash top and bottom line. */
4200 if (height > 3 * FRAME_LINE_HEIGHT (f))
4202 mac_invert_rectangle (f, flash_left,
4203 (FRAME_INTERNAL_BORDER_WIDTH (f)
4204 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4205 width, flash_height);
4206 mac_invert_rectangle (f, flash_left,
4207 (height - flash_height
4208 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4209 width, flash_height);
4211 else
4212 /* If it is short, flash it all. */
4213 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4214 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4216 x_flush (f);
4218 UNBLOCK_INPUT;
4221 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4224 /* Make audible bell. */
4226 void
4227 XTring_bell ()
4229 struct frame *f = SELECTED_FRAME ();
4231 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4232 if (visible_bell)
4233 XTflash (f);
4234 else
4235 #endif
4237 BLOCK_INPUT;
4238 SysBeep (1);
4239 XFlush (FRAME_MAC_DISPLAY (f));
4240 UNBLOCK_INPUT;
4245 /* Specify how many text lines, from the top of the window,
4246 should be affected by insert-lines and delete-lines operations.
4247 This, and those operations, are used only within an update
4248 that is bounded by calls to x_update_begin and x_update_end. */
4250 static void
4251 XTset_terminal_window (n)
4252 register int n;
4254 /* This function intentionally left blank. */
4259 /***********************************************************************
4260 Line Dance
4261 ***********************************************************************/
4263 /* Perform an insert-lines or delete-lines operation, inserting N
4264 lines or deleting -N lines at vertical position VPOS. */
4266 static void
4267 x_ins_del_lines (vpos, n)
4268 int vpos, n;
4270 abort ();
4274 /* Scroll part of the display as described by RUN. */
4276 static void
4277 x_scroll_run (w, run)
4278 struct window *w;
4279 struct run *run;
4281 struct frame *f = XFRAME (w->frame);
4282 int x, y, width, height, from_y, to_y, bottom_y;
4284 /* Get frame-relative bounding box of the text display area of W,
4285 without mode lines. Include in this box the left and right
4286 fringe of W. */
4287 window_box (w, -1, &x, &y, &width, &height);
4289 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4290 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4291 bottom_y = y + height;
4293 if (to_y < from_y)
4295 /* Scrolling up. Make sure we don't copy part of the mode
4296 line at the bottom. */
4297 if (from_y + run->height > bottom_y)
4298 height = bottom_y - from_y;
4299 else
4300 height = run->height;
4302 else
4304 /* Scolling down. Make sure we don't copy over the mode line.
4305 at the bottom. */
4306 if (to_y + run->height > bottom_y)
4307 height = bottom_y - to_y;
4308 else
4309 height = run->height;
4312 BLOCK_INPUT;
4314 /* Cursor off. Will be switched on again in x_update_window_end. */
4315 updated_window = w;
4316 x_clear_cursor (w);
4318 mac_scroll_area (f, f->output_data.mac->normal_gc,
4319 x, from_y,
4320 width, height,
4321 x, to_y);
4323 UNBLOCK_INPUT;
4328 /***********************************************************************
4329 Exposure Events
4330 ***********************************************************************/
4333 static void
4334 frame_highlight (f)
4335 struct frame *f;
4337 x_update_cursor (f, 1);
4340 static void
4341 frame_unhighlight (f)
4342 struct frame *f;
4344 x_update_cursor (f, 1);
4347 /* The focus has changed. Update the frames as necessary to reflect
4348 the new situation. Note that we can't change the selected frame
4349 here, because the Lisp code we are interrupting might become confused.
4350 Each event gets marked with the frame in which it occurred, so the
4351 Lisp code can tell when the switch took place by examining the events. */
4353 static void
4354 x_new_focus_frame (dpyinfo, frame)
4355 struct x_display_info *dpyinfo;
4356 struct frame *frame;
4358 struct frame *old_focus = dpyinfo->x_focus_frame;
4360 if (frame != dpyinfo->x_focus_frame)
4362 /* Set this before calling other routines, so that they see
4363 the correct value of x_focus_frame. */
4364 dpyinfo->x_focus_frame = frame;
4366 if (old_focus && old_focus->auto_lower)
4367 x_lower_frame (old_focus);
4369 #if 0
4370 selected_frame = frame;
4371 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4372 selected_frame);
4373 Fselect_window (selected_frame->selected_window, Qnil);
4374 choose_minibuf_frame ();
4375 #endif /* ! 0 */
4377 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4378 pending_autoraise_frame = dpyinfo->x_focus_frame;
4379 else
4380 pending_autoraise_frame = 0;
4382 #if USE_MAC_FONT_PANEL
4383 if (frame)
4384 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
4385 #endif
4388 x_frame_rehighlight (dpyinfo);
4391 /* Handle FocusIn and FocusOut state changes for FRAME.
4392 If FRAME has focus and there exists more than one frame, puts
4393 a FOCUS_IN_EVENT into *BUFP. */
4395 static void
4396 mac_focus_changed (type, dpyinfo, frame, bufp)
4397 int type;
4398 struct mac_display_info *dpyinfo;
4399 struct frame *frame;
4400 struct input_event *bufp;
4402 if (type == activeFlag)
4404 if (dpyinfo->x_focus_event_frame != frame)
4406 x_new_focus_frame (dpyinfo, frame);
4407 dpyinfo->x_focus_event_frame = frame;
4409 /* Don't stop displaying the initial startup message
4410 for a switch-frame event we don't need. */
4411 if (GC_NILP (Vterminal_frame)
4412 && GC_CONSP (Vframe_list)
4413 && !GC_NILP (XCDR (Vframe_list)))
4415 bufp->kind = FOCUS_IN_EVENT;
4416 XSETFRAME (bufp->frame_or_window, frame);
4420 else
4422 if (dpyinfo->x_focus_event_frame == frame)
4424 dpyinfo->x_focus_event_frame = 0;
4425 x_new_focus_frame (dpyinfo, 0);
4430 /* The focus may have changed. Figure out if it is a real focus change,
4431 by checking both FocusIn/Out and Enter/LeaveNotify events.
4433 Returns FOCUS_IN_EVENT event in *BUFP. */
4435 static void
4436 x_detect_focus_change (dpyinfo, event, bufp)
4437 struct mac_display_info *dpyinfo;
4438 const EventRecord *event;
4439 struct input_event *bufp;
4441 struct frame *frame;
4443 frame = mac_window_to_frame ((WindowRef) event->message);
4444 if (! frame)
4445 return;
4447 /* On Mac, this is only called from focus events, so no switch needed. */
4448 mac_focus_changed ((event->modifiers & activeFlag),
4449 dpyinfo, frame, bufp);
4453 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4455 void
4456 x_mouse_leave (dpyinfo)
4457 struct x_display_info *dpyinfo;
4459 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4462 /* The focus has changed, or we have redirected a frame's focus to
4463 another frame (this happens when a frame uses a surrogate
4464 mini-buffer frame). Shift the highlight as appropriate.
4466 The FRAME argument doesn't necessarily have anything to do with which
4467 frame is being highlighted or un-highlighted; we only use it to find
4468 the appropriate X display info. */
4470 static void
4471 XTframe_rehighlight (frame)
4472 struct frame *frame;
4474 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4477 static void
4478 x_frame_rehighlight (dpyinfo)
4479 struct x_display_info *dpyinfo;
4481 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4483 if (dpyinfo->x_focus_frame)
4485 dpyinfo->x_highlight_frame
4486 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4487 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4488 : dpyinfo->x_focus_frame);
4489 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4491 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4492 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4495 else
4496 dpyinfo->x_highlight_frame = 0;
4498 if (dpyinfo->x_highlight_frame != old_highlight)
4500 if (old_highlight)
4501 frame_unhighlight (old_highlight);
4502 if (dpyinfo->x_highlight_frame)
4503 frame_highlight (dpyinfo->x_highlight_frame);
4509 /* Convert a keysym to its name. */
4511 char *
4512 x_get_keysym_name (keysym)
4513 int keysym;
4515 char *value;
4517 BLOCK_INPUT;
4518 #if 0
4519 value = XKeysymToString (keysym);
4520 #else
4521 value = 0;
4522 #endif
4523 UNBLOCK_INPUT;
4525 return value;
4530 /* Function to report a mouse movement to the mainstream Emacs code.
4531 The input handler calls this.
4533 We have received a mouse movement event, which is given in *event.
4534 If the mouse is over a different glyph than it was last time, tell
4535 the mainstream emacs code by setting mouse_moved. If not, ask for
4536 another motion event, so we can check again the next time it moves. */
4538 static Point last_mouse_motion_position;
4539 static Lisp_Object last_mouse_motion_frame;
4541 static int
4542 note_mouse_movement (frame, pos)
4543 FRAME_PTR frame;
4544 Point *pos;
4546 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4547 #if TARGET_API_MAC_CARBON
4548 Rect r;
4549 #endif
4551 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4552 last_mouse_motion_position = *pos;
4553 XSETFRAME (last_mouse_motion_frame, frame);
4555 if (frame == dpyinfo->mouse_face_mouse_frame
4556 #if TARGET_API_MAC_CARBON
4557 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
4558 #else
4559 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
4560 #endif
4563 /* This case corresponds to LeaveNotify in X11. If we move
4564 outside the frame, then we're certainly no longer on any text
4565 in the frame. */
4566 clear_mouse_face (dpyinfo);
4567 dpyinfo->mouse_face_mouse_frame = 0;
4568 if (!dpyinfo->grabbed)
4569 rif->define_frame_cursor (frame,
4570 frame->output_data.mac->nontext_cursor);
4573 /* Has the mouse moved off the glyph it was on at the last sighting? */
4574 if (frame != last_mouse_glyph_frame
4575 || !PtInRect (*pos, &last_mouse_glyph))
4577 frame->mouse_moved = 1;
4578 last_mouse_scroll_bar = Qnil;
4579 note_mouse_highlight (frame, pos->h, pos->v);
4580 /* Remember which glyph we're now on. */
4581 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
4582 last_mouse_glyph_frame = frame;
4583 return 1;
4586 return 0;
4590 /************************************************************************
4591 Mouse Face
4592 ************************************************************************/
4594 /* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4596 static void
4597 redo_mouse_highlight ()
4599 if (!NILP (last_mouse_motion_frame)
4600 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4601 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4602 last_mouse_motion_position.h,
4603 last_mouse_motion_position.v);
4607 static struct frame *
4608 mac_focus_frame (dpyinfo)
4609 struct mac_display_info *dpyinfo;
4611 if (dpyinfo->x_focus_frame)
4612 return dpyinfo->x_focus_frame;
4613 else
4614 /* Mac version may get events, such as a menu bar click, even when
4615 all the frames are invisible. In this case, we regard the
4616 event came to the selected frame. */
4617 return SELECTED_FRAME ();
4621 /* Return the current position of the mouse.
4622 *FP should be a frame which indicates which display to ask about.
4624 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4625 and *PART to the frame, window, and scroll bar part that the mouse
4626 is over. Set *X and *Y to the portion and whole of the mouse's
4627 position on the scroll bar.
4629 If the mouse movement started elsewhere, set *FP to the frame the
4630 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4631 the mouse is over.
4633 Set *TIME to the server time-stamp for the time at which the mouse
4634 was at this position.
4636 Don't store anything if we don't have a valid set of values to report.
4638 This clears the mouse_moved flag, so we can wait for the next mouse
4639 movement. */
4641 static void
4642 XTmouse_position (fp, insist, bar_window, part, x, y, time)
4643 FRAME_PTR *fp;
4644 int insist;
4645 Lisp_Object *bar_window;
4646 enum scroll_bar_part *part;
4647 Lisp_Object *x, *y;
4648 unsigned long *time;
4650 FRAME_PTR f1;
4652 BLOCK_INPUT;
4654 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4655 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4656 else
4658 Lisp_Object frame, tail;
4660 /* Clear the mouse-moved flag for every frame on this display. */
4661 FOR_EACH_FRAME (tail, frame)
4662 XFRAME (frame)->mouse_moved = 0;
4664 last_mouse_scroll_bar = Qnil;
4666 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4667 && FRAME_LIVE_P (last_mouse_frame))
4668 f1 = last_mouse_frame;
4669 else
4670 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
4672 if (f1)
4674 /* Ok, we found a frame. Store all the values.
4675 last_mouse_glyph is a rectangle used to reduce the
4676 generation of mouse events. To not miss any motion
4677 events, we must divide the frame into rectangles of the
4678 size of the smallest character that could be displayed
4679 on it, i.e. into the same rectangles that matrices on
4680 the frame are divided into. */
4681 Point mouse_pos;
4683 #if TARGET_API_MAC_CARBON
4684 GetGlobalMouse (&mouse_pos);
4685 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4686 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4687 #else
4688 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4689 GetMouse (&mouse_pos);
4690 #endif
4691 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4692 &last_mouse_glyph);
4693 last_mouse_glyph_frame = f1;
4695 *bar_window = Qnil;
4696 *part = 0;
4697 *fp = f1;
4698 XSETINT (*x, mouse_pos.h);
4699 XSETINT (*y, mouse_pos.v);
4700 *time = last_mouse_movement_time;
4704 UNBLOCK_INPUT;
4708 /************************************************************************
4709 Toolkit scroll bars
4710 ************************************************************************/
4712 #ifdef USE_TOOLKIT_SCROLL_BARS
4714 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4715 static OSStatus install_scroll_bar_timer P_ ((void));
4716 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
4717 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
4718 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
4719 struct input_event *));
4720 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
4721 Rect *));
4722 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
4723 ControlPartCode, Point,
4724 struct input_event *));
4725 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
4726 struct input_event *));
4727 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
4728 Point, struct input_event *));
4729 static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4730 int, int, int));
4732 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
4734 static int last_scroll_bar_part;
4736 static EventLoopTimerRef scroll_bar_timer;
4738 static int scroll_bar_timer_event_posted_p;
4740 #define SCROLL_BAR_FIRST_DELAY 0.5
4741 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4743 static pascal void
4744 scroll_bar_timer_callback (timer, data)
4745 EventLoopTimerRef timer;
4746 void *data;
4748 OSStatus err;
4750 err = mac_post_mouse_moved_event ();
4751 if (err == noErr)
4752 scroll_bar_timer_event_posted_p = 1;
4755 static OSStatus
4756 install_scroll_bar_timer ()
4758 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4760 if (scroll_bar_timer_callbackUPP == NULL)
4761 scroll_bar_timer_callbackUPP =
4762 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4764 if (scroll_bar_timer == NULL)
4765 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4766 kEventDurationForever as delays. */
4767 return
4768 InstallEventLoopTimer (GetCurrentEventLoop (),
4769 kEventDurationForever, kEventDurationForever,
4770 scroll_bar_timer_callbackUPP, NULL,
4771 &scroll_bar_timer);
4774 static OSStatus
4775 set_scroll_bar_timer (delay)
4776 EventTimerInterval delay;
4778 if (scroll_bar_timer == NULL)
4779 install_scroll_bar_timer ();
4781 scroll_bar_timer_event_posted_p = 0;
4783 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4786 static int
4787 control_part_code_to_scroll_bar_part (part_code)
4788 ControlPartCode part_code;
4790 switch (part_code)
4792 case kControlUpButtonPart: return scroll_bar_up_arrow;
4793 case kControlDownButtonPart: return scroll_bar_down_arrow;
4794 case kControlPageUpPart: return scroll_bar_above_handle;
4795 case kControlPageDownPart: return scroll_bar_below_handle;
4796 case kControlIndicatorPart: return scroll_bar_handle;
4799 return -1;
4802 static void
4803 construct_scroll_bar_click (bar, part, bufp)
4804 struct scroll_bar *bar;
4805 int part;
4806 struct input_event *bufp;
4808 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4809 bufp->frame_or_window = bar->window;
4810 bufp->arg = Qnil;
4811 bufp->part = part;
4812 bufp->code = 0;
4813 XSETINT (bufp->x, 0);
4814 XSETINT (bufp->y, 0);
4815 bufp->modifiers = 0;
4818 static OSStatus
4819 get_control_part_bounds (ch, part_code, rect)
4820 ControlRef ch;
4821 ControlPartCode part_code;
4822 Rect *rect;
4824 RgnHandle region = NewRgn ();
4825 OSStatus err;
4827 err = GetControlRegion (ch, part_code, region);
4828 if (err == noErr)
4829 GetRegionBounds (region, rect);
4830 DisposeRgn (region);
4832 return err;
4835 static void
4836 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
4837 struct scroll_bar *bar;
4838 ControlPartCode part_code;
4839 Point mouse_pos;
4840 struct input_event *bufp;
4842 int part = control_part_code_to_scroll_bar_part (part_code);
4844 if (part < 0)
4845 return;
4847 if (part != scroll_bar_handle)
4849 construct_scroll_bar_click (bar, part, bufp);
4850 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4851 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
4852 bar->dragging = Qnil;
4854 else
4856 Rect r;
4858 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4859 kControlIndicatorPart, &r);
4860 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
4863 last_scroll_bar_part = part;
4864 tracked_scroll_bar = bar;
4867 static void
4868 x_scroll_bar_handle_release (bar, bufp)
4869 struct scroll_bar *bar;
4870 struct input_event *bufp;
4872 if (last_scroll_bar_part != scroll_bar_handle
4873 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
4874 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
4876 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
4877 set_scroll_bar_timer (kEventDurationForever);
4879 last_scroll_bar_part = -1;
4880 bar->dragging = Qnil;
4881 tracked_scroll_bar = NULL;
4884 static void
4885 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
4886 WindowRef win;
4887 struct scroll_bar *bar;
4888 Point mouse_pos;
4889 struct input_event *bufp;
4891 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
4893 if (last_scroll_bar_part == scroll_bar_handle)
4895 int top, top_range;
4896 Rect r;
4898 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4899 kControlIndicatorPart, &r);
4901 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
4902 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
4904 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
4905 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
4907 if (top < 0)
4908 top = 0;
4909 if (top > top_range)
4910 top = top_range;
4912 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
4913 XSETINT (bufp->x, top);
4914 XSETINT (bufp->y, top_range);
4916 else
4918 ControlPartCode part_code;
4919 int unhilite_p = 0, part;
4921 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
4922 unhilite_p = 1;
4923 else
4925 part = control_part_code_to_scroll_bar_part (part_code);
4927 switch (last_scroll_bar_part)
4929 case scroll_bar_above_handle:
4930 case scroll_bar_below_handle:
4931 if (part != scroll_bar_above_handle
4932 && part != scroll_bar_below_handle)
4933 unhilite_p = 1;
4934 break;
4936 case scroll_bar_up_arrow:
4937 case scroll_bar_down_arrow:
4938 if (part != scroll_bar_up_arrow
4939 && part != scroll_bar_down_arrow)
4940 unhilite_p = 1;
4941 break;
4945 if (unhilite_p)
4946 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
4947 else if (part != last_scroll_bar_part
4948 || scroll_bar_timer_event_posted_p)
4950 construct_scroll_bar_click (bar, part, bufp);
4951 last_scroll_bar_part = part;
4952 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4953 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
4958 /* Set the thumb size and position of scroll bar BAR. We are currently
4959 displaying PORTION out of a whole WHOLE, and our position POSITION. */
4961 static void
4962 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
4963 struct scroll_bar *bar;
4964 int portion, position, whole;
4966 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
4967 int value, viewsize, maximum;
4969 if (XINT (bar->track_height) == 0)
4970 return;
4972 if (whole <= portion)
4973 value = 0, viewsize = 1, maximum = 0;
4974 else
4976 float scale;
4978 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
4979 scale = (float) maximum / (whole - portion);
4980 value = position * scale + 0.5f;
4981 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
4984 BLOCK_INPUT;
4986 if (GetControlViewSize (ch) != viewsize
4987 || GetControl32BitValue (ch) != value
4988 || GetControl32BitMaximum (ch) != maximum)
4990 /* Temporarily hide the scroll bar to avoid multiple redraws. */
4991 SetControlVisibility (ch, false, false);
4993 SetControl32BitMaximum (ch, maximum);
4994 SetControl32BitValue (ch, value);
4995 SetControlViewSize (ch, viewsize);
4997 SetControlVisibility (ch, true, true);
5000 UNBLOCK_INPUT;
5003 #endif /* USE_TOOLKIT_SCROLL_BARS */
5007 /************************************************************************
5008 Scroll bars, general
5009 ************************************************************************/
5011 /* Create a scroll bar and return the scroll bar vector for it. W is
5012 the Emacs window on which to create the scroll bar. TOP, LEFT,
5013 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
5014 scroll bar. */
5016 static struct scroll_bar *
5017 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5018 struct window *w;
5019 int top, left, width, height, disp_top, disp_height;
5021 struct frame *f = XFRAME (w->frame);
5022 struct scroll_bar *bar
5023 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5024 Rect r;
5025 ControlRef ch;
5027 BLOCK_INPUT;
5029 r.left = left;
5030 r.top = disp_top;
5031 r.right = left + width;
5032 r.bottom = disp_top + disp_height;
5034 #if USE_CG_DRAWING
5035 mac_prepare_for_quickdraw (f);
5036 #endif
5037 #if TARGET_API_MAC_CARBON
5038 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
5039 #ifdef USE_TOOLKIT_SCROLL_BARS
5040 false,
5041 #else
5042 width < disp_height,
5043 #endif
5044 0, 0, 0, kControlScrollBarProc, (long) bar);
5045 #else
5046 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5047 0, 0, 0, scrollBarProc, (long) bar);
5048 #endif
5049 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
5051 XSETWINDOW (bar->window, w);
5052 XSETINT (bar->top, top);
5053 XSETINT (bar->left, left);
5054 XSETINT (bar->width, width);
5055 XSETINT (bar->height, height);
5056 XSETINT (bar->start, 0);
5057 XSETINT (bar->end, 0);
5058 bar->dragging = Qnil;
5059 #ifdef MAC_OSX
5060 bar->fringe_extended_p = Qnil;
5061 #endif
5062 #ifdef USE_TOOLKIT_SCROLL_BARS
5063 bar->track_top = Qnil;
5064 bar->track_height = Qnil;
5065 bar->min_handle = Qnil;
5066 #endif
5068 /* Add bar to its frame's list of scroll bars. */
5069 bar->next = FRAME_SCROLL_BARS (f);
5070 bar->prev = Qnil;
5071 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5072 if (!NILP (bar->next))
5073 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5075 UNBLOCK_INPUT;
5076 return bar;
5080 /* Draw BAR's handle in the proper position.
5082 If the handle is already drawn from START to END, don't bother
5083 redrawing it, unless REBUILD is non-zero; in that case, always
5084 redraw it. (REBUILD is handy for drawing the handle after expose
5085 events.)
5087 Normally, we want to constrain the start and end of the handle to
5088 fit inside its rectangle, but if the user is dragging the scroll
5089 bar handle, we want to let them drag it down all the way, so that
5090 the bar's top is as far down as it goes; otherwise, there's no way
5091 to move to the very end of the buffer. */
5093 #ifndef USE_TOOLKIT_SCROLL_BARS
5095 static void
5096 x_scroll_bar_set_handle (bar, start, end, rebuild)
5097 struct scroll_bar *bar;
5098 int start, end;
5099 int rebuild;
5101 int dragging = ! NILP (bar->dragging);
5102 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5103 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5104 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5105 int length = end - start;
5107 /* If the display is already accurate, do nothing. */
5108 if (! rebuild
5109 && start == XINT (bar->start)
5110 && end == XINT (bar->end))
5111 return;
5113 BLOCK_INPUT;
5115 /* Make sure the values are reasonable, and try to preserve the
5116 distance between start and end. */
5117 if (start < 0)
5118 start = 0;
5119 else if (start > top_range)
5120 start = top_range;
5121 end = start + length;
5123 if (end < start)
5124 end = start;
5125 else if (end > top_range && ! dragging)
5126 end = top_range;
5128 /* Store the adjusted setting in the scroll bar. */
5129 XSETINT (bar->start, start);
5130 XSETINT (bar->end, end);
5132 /* Clip the end position, just for display. */
5133 if (end > top_range)
5134 end = top_range;
5136 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5137 top positions, to make sure the handle is always at least that
5138 many pixels tall. */
5139 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5141 SetControlMinimum (ch, 0);
5142 /* Don't inadvertently activate deactivated scroll bars */
5143 if (GetControlMaximum (ch) != -1)
5144 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5145 - (end - start));
5146 SetControlValue (ch, start);
5147 #if TARGET_API_MAC_CARBON
5148 SetControlViewSize (ch, end - start);
5149 #endif
5151 UNBLOCK_INPUT;
5154 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5156 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5157 nil. */
5159 static void
5160 x_scroll_bar_remove (bar)
5161 struct scroll_bar *bar;
5163 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5165 BLOCK_INPUT;
5167 #if USE_CG_DRAWING
5168 mac_prepare_for_quickdraw (f);
5169 #endif
5170 /* Destroy the Mac scroll bar control */
5171 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
5173 /* Disassociate this scroll bar from its window. */
5174 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5176 UNBLOCK_INPUT;
5180 /* Set the handle of the vertical scroll bar for WINDOW to indicate
5181 that we are displaying PORTION characters out of a total of WHOLE
5182 characters, starting at POSITION. If WINDOW has no scroll bar,
5183 create one. */
5185 static void
5186 XTset_vertical_scroll_bar (w, portion, whole, position)
5187 struct window *w;
5188 int portion, whole, position;
5190 struct frame *f = XFRAME (w->frame);
5191 struct scroll_bar *bar;
5192 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
5193 int window_y, window_height;
5194 #ifdef MAC_OSX
5195 int fringe_extended_p;
5196 #endif
5198 /* Get window dimensions. */
5199 window_box (w, -1, 0, &window_y, 0, &window_height);
5200 top = window_y;
5201 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
5202 height = window_height;
5204 /* Compute the left edge of the scroll bar area. */
5205 left = WINDOW_SCROLL_BAR_AREA_X (w);
5207 /* Compute the width of the scroll bar which might be less than
5208 the width of the area reserved for the scroll bar. */
5209 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5210 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
5211 else
5212 sb_width = width;
5214 /* Compute the left edge of the scroll bar. */
5215 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
5216 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
5217 else
5218 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
5220 /* Adjustments according to Inside Macintosh to make it look nice */
5221 disp_top = top;
5222 disp_height = height;
5223 #ifdef MAC_OS8
5224 if (disp_top == 0)
5226 disp_top = -1;
5227 disp_height++;
5229 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
5231 disp_top++;
5232 disp_height--;
5235 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
5236 sb_left++;
5237 #endif
5239 #ifdef MAC_OSX
5240 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5241 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5242 && WINDOW_LEFT_FRINGE_WIDTH (w)
5243 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5244 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5245 else
5246 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5247 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5248 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5249 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5250 #endif
5252 /* Does the scroll bar exist yet? */
5253 if (NILP (w->vertical_scroll_bar))
5255 BLOCK_INPUT;
5256 #ifdef MAC_OSX
5257 if (fringe_extended_p)
5258 mac_clear_area (f, sb_left, top, sb_width, height);
5259 else
5260 #endif
5261 mac_clear_area (f, left, top, width, height);
5262 UNBLOCK_INPUT;
5263 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5264 disp_height);
5265 XSETVECTOR (w->vertical_scroll_bar, bar);
5267 else
5269 /* It may just need to be moved and resized. */
5270 ControlRef ch;
5272 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5273 ch = SCROLL_BAR_CONTROL_REF (bar);
5275 BLOCK_INPUT;
5277 /* If already correctly positioned, do nothing. */
5278 if (!(XINT (bar->left) == sb_left
5279 && XINT (bar->top) == top
5280 && XINT (bar->width) == sb_width
5281 && XINT (bar->height) == height
5282 #ifdef MAC_OSX
5283 && !NILP (bar->fringe_extended_p) == fringe_extended_p
5284 #endif
5287 /* Since toolkit scroll bars are smaller than the space reserved
5288 for them on the frame, we have to clear "under" them. */
5289 #ifdef MAC_OSX
5290 if (fringe_extended_p)
5291 mac_clear_area (f, sb_left, top, sb_width, height);
5292 else
5293 #endif
5294 mac_clear_area (f, left, top, width, height);
5296 #if USE_CG_DRAWING
5297 mac_prepare_for_quickdraw (f);
5298 #endif
5299 HideControl (ch);
5300 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5301 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5302 disp_height);
5303 #ifndef USE_TOOLKIT_SCROLL_BARS
5304 if (sb_width < disp_height)
5305 ShowControl (ch);
5306 #endif
5308 /* Remember new settings. */
5309 XSETINT (bar->left, sb_left);
5310 XSETINT (bar->top, top);
5311 XSETINT (bar->width, sb_width);
5312 XSETINT (bar->height, height);
5313 #ifdef USE_TOOLKIT_SCROLL_BARS
5314 bar->track_top = Qnil;
5315 bar->track_height = Qnil;
5316 bar->min_handle = Qnil;
5317 #endif
5320 UNBLOCK_INPUT;
5323 #ifdef MAC_OSX
5324 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5325 #endif
5327 #ifdef USE_TOOLKIT_SCROLL_BARS
5328 if (NILP (bar->track_top))
5330 if (sb_width >= disp_height
5331 #ifdef MAC_OSX
5332 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5333 #endif
5336 XSETINT (bar->track_top, 0);
5337 XSETINT (bar->track_height, 0);
5338 XSETINT (bar->min_handle, 0);
5340 else
5342 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5343 Rect r0, r1;
5345 BLOCK_INPUT;
5347 SetControl32BitMinimum (ch, 0);
5348 SetControl32BitMaximum (ch, 1 << 30);
5349 SetControlViewSize (ch, 1);
5351 /* Move the scroll bar thumb to the top. */
5352 SetControl32BitValue (ch, 0);
5353 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5355 /* Move the scroll bar thumb to the bottom. */
5356 SetControl32BitValue (ch, 1 << 30);
5357 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5359 UnionRect (&r0, &r1, &r0);
5360 XSETINT (bar->track_top, r0.top);
5361 XSETINT (bar->track_height, r0.bottom - r0.top);
5362 XSETINT (bar->min_handle, r1.bottom - r1.top);
5364 /* Don't show the scroll bar if its height is not enough to
5365 display the scroll bar thumb. */
5366 if (r0.bottom - r0.top > 0)
5367 ShowControl (ch);
5369 UNBLOCK_INPUT;
5373 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5374 #else /* not USE_TOOLKIT_SCROLL_BARS */
5375 /* Set the scroll bar's current state, unless we're currently being
5376 dragged. */
5377 if (NILP (bar->dragging))
5379 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5381 if (whole == 0)
5382 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5383 else
5385 int start = ((double) position * top_range) / whole;
5386 int end = ((double) (position + portion) * top_range) / whole;
5387 x_scroll_bar_set_handle (bar, start, end, 0);
5390 #endif /* not USE_TOOLKIT_SCROLL_BARS */
5394 /* The following three hooks are used when we're doing a thorough
5395 redisplay of the frame. We don't explicitly know which scroll bars
5396 are going to be deleted, because keeping track of when windows go
5397 away is a real pain - "Can you say set-window-configuration, boys
5398 and girls?" Instead, we just assert at the beginning of redisplay
5399 that *all* scroll bars are to be removed, and then save a scroll bar
5400 from the fiery pit when we actually redisplay its window. */
5402 /* Arrange for all scroll bars on FRAME to be removed at the next call
5403 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5404 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5406 static void
5407 XTcondemn_scroll_bars (frame)
5408 FRAME_PTR frame;
5410 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5411 while (! NILP (FRAME_SCROLL_BARS (frame)))
5413 Lisp_Object bar;
5414 bar = FRAME_SCROLL_BARS (frame);
5415 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5416 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5417 XSCROLL_BAR (bar)->prev = Qnil;
5418 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5419 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5420 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5425 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5426 Note that WINDOW isn't necessarily condemned at all. */
5428 static void
5429 XTredeem_scroll_bar (window)
5430 struct window *window;
5432 struct scroll_bar *bar;
5433 struct frame *f;
5435 /* We can't redeem this window's scroll bar if it doesn't have one. */
5436 if (NILP (window->vertical_scroll_bar))
5437 abort ();
5439 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5441 /* Unlink it from the condemned list. */
5442 f = XFRAME (WINDOW_FRAME (window));
5443 if (NILP (bar->prev))
5445 /* If the prev pointer is nil, it must be the first in one of
5446 the lists. */
5447 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5448 /* It's not condemned. Everything's fine. */
5449 return;
5450 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5451 window->vertical_scroll_bar))
5452 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5453 else
5454 /* If its prev pointer is nil, it must be at the front of
5455 one or the other! */
5456 abort ();
5458 else
5459 XSCROLL_BAR (bar->prev)->next = bar->next;
5461 if (! NILP (bar->next))
5462 XSCROLL_BAR (bar->next)->prev = bar->prev;
5464 bar->next = FRAME_SCROLL_BARS (f);
5465 bar->prev = Qnil;
5466 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5467 if (! NILP (bar->next))
5468 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5471 /* Remove all scroll bars on FRAME that haven't been saved since the
5472 last call to `*condemn_scroll_bars_hook'. */
5474 static void
5475 XTjudge_scroll_bars (f)
5476 FRAME_PTR f;
5478 Lisp_Object bar, next;
5480 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5482 /* Clear out the condemned list now so we won't try to process any
5483 more events on the hapless scroll bars. */
5484 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5486 for (; ! NILP (bar); bar = next)
5488 struct scroll_bar *b = XSCROLL_BAR (bar);
5490 x_scroll_bar_remove (b);
5492 next = b->next;
5493 b->next = b->prev = Qnil;
5496 /* Now there should be no references to the condemned scroll bars,
5497 and they should get garbage-collected. */
5501 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
5502 is set to something other than NO_EVENT, it is enqueued.
5504 This may be called from a signal handler, so we have to ignore GC
5505 mark bits. */
5507 static void
5508 x_scroll_bar_handle_click (bar, part_code, er, bufp)
5509 struct scroll_bar *bar;
5510 ControlPartCode part_code;
5511 const EventRecord *er;
5512 struct input_event *bufp;
5514 int win_y, top_range;
5516 if (! GC_WINDOWP (bar->window))
5517 abort ();
5519 bufp->kind = SCROLL_BAR_CLICK_EVENT;
5520 bufp->frame_or_window = bar->window;
5521 bufp->arg = Qnil;
5523 bar->dragging = Qnil;
5525 switch (part_code)
5527 case kControlUpButtonPart:
5528 bufp->part = scroll_bar_up_arrow;
5529 break;
5530 case kControlDownButtonPart:
5531 bufp->part = scroll_bar_down_arrow;
5532 break;
5533 case kControlPageUpPart:
5534 bufp->part = scroll_bar_above_handle;
5535 break;
5536 case kControlPageDownPart:
5537 bufp->part = scroll_bar_below_handle;
5538 break;
5539 #if TARGET_API_MAC_CARBON
5540 default:
5541 #else
5542 case kControlIndicatorPart:
5543 #endif
5544 if (er->what == mouseDown)
5545 bar->dragging = make_number (0);
5546 XSETVECTOR (last_mouse_scroll_bar, bar);
5547 bufp->part = scroll_bar_handle;
5548 break;
5551 win_y = XINT (bufp->y) - XINT (bar->top);
5552 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5554 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5556 win_y -= 24;
5558 if (! NILP (bar->dragging))
5559 win_y -= XINT (bar->dragging);
5561 if (win_y < 0)
5562 win_y = 0;
5563 if (win_y > top_range)
5564 win_y = top_range;
5566 XSETINT (bufp->x, win_y);
5567 XSETINT (bufp->y, top_range);
5570 #ifndef USE_TOOLKIT_SCROLL_BARS
5572 /* Handle some mouse motion while someone is dragging the scroll bar.
5574 This may be called from a signal handler, so we have to ignore GC
5575 mark bits. */
5577 static void
5578 x_scroll_bar_note_movement (bar, y_pos, t)
5579 struct scroll_bar *bar;
5580 int y_pos;
5581 Time t;
5583 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5585 last_mouse_movement_time = t;
5587 f->mouse_moved = 1;
5588 XSETVECTOR (last_mouse_scroll_bar, bar);
5590 /* If we're dragging the bar, display it. */
5591 if (! GC_NILP (bar->dragging))
5593 /* Where should the handle be now? */
5594 int new_start = y_pos - 24;
5596 if (new_start != XINT (bar->start))
5598 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5600 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5605 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5607 /* Return information to the user about the current position of the mouse
5608 on the scroll bar. */
5610 static void
5611 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5612 FRAME_PTR *fp;
5613 Lisp_Object *bar_window;
5614 enum scroll_bar_part *part;
5615 Lisp_Object *x, *y;
5616 unsigned long *time;
5618 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
5619 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5620 #if TARGET_API_MAC_CARBON
5621 WindowRef wp = GetControlOwner (ch);
5622 #else
5623 WindowRef wp = (*ch)->contrlOwner;
5624 #endif
5625 Point mouse_pos;
5626 struct frame *f = mac_window_to_frame (wp);
5627 int win_y, top_range;
5629 #if TARGET_API_MAC_CARBON
5630 GetGlobalMouse (&mouse_pos);
5631 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5632 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5633 #else
5634 SetPortWindowPort (wp);
5635 GetMouse (&mouse_pos);
5636 #endif
5638 win_y = mouse_pos.v - XINT (bar->top);
5639 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5641 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5643 win_y -= 24;
5645 if (! NILP (bar->dragging))
5646 win_y -= XINT (bar->dragging);
5648 if (win_y < 0)
5649 win_y = 0;
5650 if (win_y > top_range)
5651 win_y = top_range;
5653 *fp = f;
5654 *bar_window = bar->window;
5656 if (! NILP (bar->dragging))
5657 *part = scroll_bar_handle;
5658 else if (win_y < XINT (bar->start))
5659 *part = scroll_bar_above_handle;
5660 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5661 *part = scroll_bar_handle;
5662 else
5663 *part = scroll_bar_below_handle;
5665 XSETINT (*x, win_y);
5666 XSETINT (*y, top_range);
5668 f->mouse_moved = 0;
5669 last_mouse_scroll_bar = Qnil;
5671 *time = last_mouse_movement_time;
5675 /* The screen has been cleared so we may have changed foreground or
5676 background colors, and the scroll bars may need to be redrawn.
5677 Clear out the scroll bars, and ask for expose events, so we can
5678 redraw them. */
5680 void
5681 x_scroll_bar_clear (f)
5682 FRAME_PTR f;
5684 XTcondemn_scroll_bars (f);
5685 XTjudge_scroll_bars (f);
5689 /***********************************************************************
5690 Tool-bars
5691 ***********************************************************************/
5692 #if USE_MAC_TOOLBAR
5694 /* In identifiers such as function/variable names, Emacs tool bar is
5695 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5697 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5698 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5700 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5701 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5702 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5703 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5704 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5705 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5706 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5708 static int mac_event_to_emacs_modifiers P_ ((EventRef));
5709 static void mac_handle_origin_change P_ ((struct frame *));
5710 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5711 EventRef, void *));
5713 static void
5714 mac_move_window_with_gravity (f, win_gravity, left, top)
5715 struct frame *f;
5716 int win_gravity;
5717 short left, top;
5719 Rect inner, outer;
5721 mac_get_window_bounds (f, &inner, &outer);
5723 switch (win_gravity)
5725 case NorthWestGravity:
5726 case WestGravity:
5727 case SouthWestGravity:
5728 left += inner.left - outer.left;
5729 break;
5731 case NorthGravity:
5732 case CenterGravity:
5733 case SouthGravity:
5734 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5735 break;
5737 case NorthEastGravity:
5738 case EastGravity:
5739 case SouthEastGravity:
5740 left += inner.right - outer.right;
5741 break;
5744 switch (win_gravity)
5746 case NorthWestGravity:
5747 case NorthGravity:
5748 case NorthEastGravity:
5749 top += inner.top - outer.top;
5750 break;
5752 case WestGravity:
5753 case CenterGravity:
5754 case EastGravity:
5755 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5756 break;
5758 case SouthWestGravity:
5759 case SouthGravity:
5760 case SouthEastGravity:
5761 top += inner.bottom - outer.bottom;
5762 break;
5765 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5768 static void
5769 mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5770 struct frame *f;
5771 int win_gravity;
5772 short *left, *top;
5774 Rect inner, outer;
5776 mac_get_window_bounds (f, &inner, &outer);
5778 switch (win_gravity)
5780 case NorthWestGravity:
5781 case WestGravity:
5782 case SouthWestGravity:
5783 *left = outer.left;
5784 break;
5786 case NorthGravity:
5787 case CenterGravity:
5788 case SouthGravity:
5789 *left = outer.left + ((outer.right - outer.left)
5790 - (inner.right - inner.left)) / 2;
5791 break;
5793 case NorthEastGravity:
5794 case EastGravity:
5795 case SouthEastGravity:
5796 *left = outer.right - (inner.right - inner.left);
5797 break;
5800 switch (win_gravity)
5802 case NorthWestGravity:
5803 case NorthGravity:
5804 case NorthEastGravity:
5805 *top = outer.top;
5806 break;
5808 case WestGravity:
5809 case CenterGravity:
5810 case EastGravity:
5811 *top = outer.top + ((outer.bottom - outer.top)
5812 - (inner.bottom - inner.top)) / 2;
5813 break;
5815 case SouthWestGravity:
5816 case SouthGravity:
5817 case SouthEastGravity:
5818 *top = outer.bottom - (inner.bottom - inner.top);
5819 break;
5823 static OSStatus
5824 mac_handle_toolbar_event (next_handler, event, data)
5825 EventHandlerCallRef next_handler;
5826 EventRef event;
5827 void *data;
5829 OSStatus err, result = eventNotHandledErr;
5831 switch (GetEventKind (event))
5833 case kEventToolbarGetDefaultIdentifiers:
5834 result = noErr;
5835 break;
5837 case kEventToolbarGetAllowedIdentifiers:
5839 CFMutableArrayRef array;
5841 GetEventParameter (event, kEventParamMutableArray,
5842 typeCFMutableArrayRef, NULL,
5843 sizeof (CFMutableArrayRef), NULL, &array);
5844 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5845 result = noErr;
5847 break;
5849 case kEventToolbarCreateItemWithIdentifier:
5851 CFStringRef identifier;
5852 HIToolbarItemRef item = NULL;
5854 GetEventParameter (event, kEventParamToolbarItemIdentifier,
5855 typeCFStringRef, NULL,
5856 sizeof (CFStringRef), NULL, &identifier);
5858 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
5859 == kCFCompareEqualTo)
5860 HIToolbarItemCreate (identifier,
5861 kHIToolbarItemAllowDuplicates
5862 | kHIToolbarItemCantBeRemoved, &item);
5864 if (item)
5866 SetEventParameter (event, kEventParamToolbarItem,
5867 typeHIToolbarItemRef,
5868 sizeof (HIToolbarItemRef), &item);
5869 result = noErr;
5872 break;
5874 default:
5875 abort ();
5878 return result;
5881 static CGImageRef
5882 mac_image_spec_to_cg_image (f, image)
5883 struct frame *f;
5884 Lisp_Object image;
5886 if (!valid_image_p (image))
5887 return NULL;
5888 else
5890 int img_id = lookup_image (f, image);
5891 struct image *img = IMAGE_FROM_ID (f, img_id);
5893 prepare_image_for_display (f, img);
5895 return img->data.ptr_val;
5899 /* Create a tool bar for frame F. */
5901 static OSStatus
5902 mac_create_frame_tool_bar (f)
5903 FRAME_PTR f;
5905 OSStatus err;
5906 HIToolbarRef toolbar;
5908 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
5909 &toolbar);
5910 if (err == noErr)
5912 static const EventTypeSpec specs[] =
5913 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
5914 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
5915 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
5917 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
5918 mac_handle_toolbar_event,
5919 GetEventTypeCount (specs), specs,
5920 f, NULL);
5923 if (err == noErr)
5924 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
5925 if (err == noErr)
5927 static const EventTypeSpec specs[] =
5928 {{kEventClassCommand, kEventCommandProcess}};
5930 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
5931 mac_handle_toolbar_command_event,
5932 GetEventTypeCount (specs),
5933 specs, f, NULL);
5935 if (err == noErr)
5936 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
5938 if (toolbar)
5939 CFRelease (toolbar);
5941 return err;
5944 /* Update the tool bar for frame F. Add new buttons and remove old. */
5946 void
5947 update_frame_tool_bar (f)
5948 FRAME_PTR f;
5950 HIToolbarRef toolbar = NULL;
5951 short left, top;
5952 CFArrayRef old_items = NULL;
5953 CFIndex old_count;
5954 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
5955 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
5957 BLOCK_INPUT;
5959 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
5960 if (toolbar == NULL)
5962 mac_create_frame_tool_bar (f);
5963 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
5964 if (toolbar == NULL)
5965 goto out;
5966 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
5967 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
5970 HIToolbarCopyItems (toolbar, &old_items);
5971 if (old_items == NULL)
5972 goto out;
5974 old_count = CFArrayGetCount (old_items);
5975 pos = 0;
5976 for (i = 0; i < f->n_tool_bar_items; ++i)
5978 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
5980 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
5981 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
5982 int idx;
5983 Lisp_Object image;
5984 CGImageRef cg_image;
5985 CFStringRef label;
5986 HIToolbarItemRef item;
5988 /* If image is a vector, choose the image according to the
5989 button state. */
5990 image = PROP (TOOL_BAR_ITEM_IMAGES);
5991 if (VECTORP (image))
5993 if (enabled_p)
5994 idx = (selected_p
5995 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
5996 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
5997 else
5998 idx = (selected_p
5999 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6000 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6002 xassert (ASIZE (image) >= idx);
6003 image = AREF (image, idx);
6005 else
6006 idx = -1;
6008 cg_image = mac_image_spec_to_cg_image (f, image);
6009 /* Ignore invalid image specifications. */
6010 if (cg_image == NULL)
6011 continue;
6013 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6014 if (label == NULL)
6015 label = CFSTR ("");
6017 if (pos < old_count)
6019 CGImageRef old_cg_image = NULL;
6020 CFStringRef old_label = NULL;
6021 Boolean old_enabled_p;
6023 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6025 HIToolbarItemCopyImage (item, &old_cg_image);
6026 if (cg_image != old_cg_image)
6027 HIToolbarItemSetImage (item, cg_image);
6028 CGImageRelease (old_cg_image);
6030 HIToolbarItemCopyLabel (item, &old_label);
6031 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6032 HIToolbarItemSetLabel (item, label);
6033 CFRelease (old_label);
6035 old_enabled_p = HIToolbarItemIsEnabled (item);
6036 if ((enabled_p || idx >= 0) != old_enabled_p)
6037 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6039 else
6041 item = NULL;
6042 HIToolbarCreateItemWithIdentifier (toolbar,
6043 TOOLBAR_ICON_ITEM_IDENTIFIER,
6044 NULL, &item);
6045 if (item)
6047 HIToolbarItemSetImage (item, cg_image);
6048 HIToolbarItemSetLabel (item, label);
6049 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6050 HIToolbarAppendItem (toolbar, item);
6051 CFRelease (item);
6055 CFRelease (label);
6056 if (item)
6058 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6059 pos++;
6063 CFRelease (old_items);
6065 while (pos < old_count)
6066 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6068 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6069 !win_gravity && f == mac_focus_frame (dpyinfo));
6070 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6071 toolbar visibility change. */
6072 mac_handle_origin_change (f);
6073 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6075 mac_move_window_with_gravity (f, win_gravity, left, top);
6076 /* If the title bar is completely outside the screen, adjust the
6077 position. */
6078 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6079 kWindowConstrainMoveRegardlessOfFit
6080 | kWindowConstrainAllowPartial, NULL, NULL);
6081 f->output_data.mac->toolbar_win_gravity = 0;
6084 out:
6085 UNBLOCK_INPUT;
6088 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6089 doesn't deallocate the resources. */
6091 void
6092 free_frame_tool_bar (f)
6093 FRAME_PTR f;
6095 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6097 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6099 BLOCK_INPUT;
6100 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
6101 (NILP (Fsymbol_value
6102 (intern ("frame-notice-user-settings")))
6103 && f == mac_focus_frame (dpyinfo)));
6104 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6105 on toolbar visibility change. */
6106 mac_handle_origin_change (f);
6107 UNBLOCK_INPUT;
6111 static void
6112 mac_tool_bar_note_mouse_movement (f, event)
6113 struct frame *f;
6114 EventRef event;
6116 OSStatus err;
6117 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6118 int mouse_down_p;
6119 HIViewRef item_view;
6120 UInt32 command_id;
6122 mouse_down_p = (dpyinfo->grabbed
6123 && f == last_mouse_frame
6124 && FRAME_LIVE_P (f));
6125 if (mouse_down_p)
6126 return;
6128 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6129 event, &item_view);
6130 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6131 toolbar item view seems to have the same command ID with that of
6132 the toolbar item. */
6133 if (err == noErr)
6134 err = GetControlCommandID (item_view, &command_id);
6135 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6137 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6139 if (i < f->n_tool_bar_items)
6141 HIRect bounds;
6142 HIViewRef content_view;
6144 err = HIViewGetBounds (item_view, &bounds);
6145 if (err == noErr)
6146 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6147 kHIViewWindowContentID, &content_view);
6148 if (err == noErr)
6149 err = HIViewConvertRect (&bounds, item_view, content_view);
6150 if (err == noErr)
6151 SetRect (&last_mouse_glyph,
6152 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6153 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6155 help_echo_object = help_echo_window = Qnil;
6156 help_echo_pos = -1;
6157 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6158 if (NILP (help_echo_string))
6159 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6164 static OSStatus
6165 mac_handle_toolbar_command_event (next_handler, event, data)
6166 EventHandlerCallRef next_handler;
6167 EventRef event;
6168 void *data;
6170 OSStatus err, result = eventNotHandledErr;
6171 struct frame *f = (struct frame *) data;
6172 HICommand command;
6174 err = GetEventParameter (event, kEventParamDirectObject,
6175 typeHICommand, NULL,
6176 sizeof (HICommand), NULL, &command);
6177 if (err != noErr)
6178 return result;
6180 switch (GetEventKind (event))
6182 case kEventCommandProcess:
6183 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6184 result = CallNextEventHandler (next_handler, event);
6185 else
6187 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6189 if (i < f->n_tool_bar_items
6190 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6192 Lisp_Object frame;
6193 struct input_event buf;
6195 EVENT_INIT (buf);
6197 XSETFRAME (frame, f);
6198 buf.kind = TOOL_BAR_EVENT;
6199 buf.frame_or_window = frame;
6200 buf.arg = frame;
6201 kbd_buffer_store_event (&buf);
6203 buf.kind = TOOL_BAR_EVENT;
6204 buf.frame_or_window = frame;
6205 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6206 buf.modifiers = mac_event_to_emacs_modifiers (event);
6207 kbd_buffer_store_event (&buf);
6209 result = noErr;
6212 break;
6214 default:
6215 abort ();
6217 #undef PROP
6219 return result;
6221 #endif /* USE_MAC_TOOLBAR */
6224 /***********************************************************************
6225 Text Cursor
6226 ***********************************************************************/
6228 /* Set clipping for output in glyph row ROW. W is the window in which
6229 we operate. GC is the graphics context to set clipping in.
6231 ROW may be a text row or, e.g., a mode line. Text rows must be
6232 clipped to the interior of the window dedicated to text display,
6233 mode lines must be clipped to the whole window. */
6235 static void
6236 x_clip_to_row (w, row, area, gc)
6237 struct window *w;
6238 struct glyph_row *row;
6239 int area;
6240 GC gc;
6242 struct frame *f = XFRAME (WINDOW_FRAME (w));
6243 Rect clip_rect;
6244 int window_x, window_y, window_width;
6246 window_box (w, area, &window_x, &window_y, &window_width, 0);
6248 clip_rect.left = window_x;
6249 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6250 clip_rect.top = max (clip_rect.top, window_y);
6251 clip_rect.right = clip_rect.left + window_width;
6252 clip_rect.bottom = clip_rect.top + row->visible_height;
6254 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
6258 /* Draw a hollow box cursor on window W in glyph row ROW. */
6260 static void
6261 x_draw_hollow_cursor (w, row)
6262 struct window *w;
6263 struct glyph_row *row;
6265 struct frame *f = XFRAME (WINDOW_FRAME (w));
6266 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6267 Display *dpy = FRAME_MAC_DISPLAY (f);
6268 int x, y, wd, h;
6269 XGCValues xgcv;
6270 struct glyph *cursor_glyph;
6271 GC gc;
6273 /* Get the glyph the cursor is on. If we can't tell because
6274 the current matrix is invalid or such, give up. */
6275 cursor_glyph = get_phys_cursor_glyph (w);
6276 if (cursor_glyph == NULL)
6277 return;
6279 /* Compute frame-relative coordinates for phys cursor. */
6280 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
6281 wd = w->phys_cursor_width;
6283 /* The foreground of cursor_gc is typically the same as the normal
6284 background color, which can cause the cursor box to be invisible. */
6285 xgcv.foreground = f->output_data.mac->cursor_pixel;
6286 if (dpyinfo->scratch_cursor_gc)
6287 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6288 else
6289 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6290 GCForeground, &xgcv);
6291 gc = dpyinfo->scratch_cursor_gc;
6293 /* Set clipping, draw the rectangle, and reset clipping again. */
6294 x_clip_to_row (w, row, TEXT_AREA, gc);
6295 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
6296 mac_reset_clip_rectangles (dpy, gc);
6300 /* Draw a bar cursor on window W in glyph row ROW.
6302 Implementation note: One would like to draw a bar cursor with an
6303 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6304 Unfortunately, I didn't find a font yet that has this property set.
6305 --gerd. */
6307 static void
6308 x_draw_bar_cursor (w, row, width, kind)
6309 struct window *w;
6310 struct glyph_row *row;
6311 int width;
6312 enum text_cursor_kinds kind;
6314 struct frame *f = XFRAME (w->frame);
6315 struct glyph *cursor_glyph;
6317 /* If cursor is out of bounds, don't draw garbage. This can happen
6318 in mini-buffer windows when switching between echo area glyphs
6319 and mini-buffer. */
6320 cursor_glyph = get_phys_cursor_glyph (w);
6321 if (cursor_glyph == NULL)
6322 return;
6324 /* If on an image, draw like a normal cursor. That's usually better
6325 visible than drawing a bar, esp. if the image is large so that
6326 the bar might not be in the window. */
6327 if (cursor_glyph->type == IMAGE_GLYPH)
6329 struct glyph_row *row;
6330 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6331 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6333 else
6335 Display *dpy = FRAME_MAC_DISPLAY (f);
6336 Window window = FRAME_MAC_WINDOW (f);
6337 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6338 unsigned long mask = GCForeground | GCBackground;
6339 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
6340 XGCValues xgcv;
6342 /* If the glyph's background equals the color we normally draw
6343 the bar cursor in, the bar cursor in its normal color is
6344 invisible. Use the glyph's foreground color instead in this
6345 case, on the assumption that the glyph's colors are chosen so
6346 that the glyph is legible. */
6347 if (face->background == f->output_data.mac->cursor_pixel)
6348 xgcv.background = xgcv.foreground = face->foreground;
6349 else
6350 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
6352 if (gc)
6353 XChangeGC (dpy, gc, mask, &xgcv);
6354 else
6356 gc = XCreateGC (dpy, window, mask, &xgcv);
6357 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6360 if (width < 0)
6361 width = FRAME_CURSOR_WIDTH (f);
6362 width = min (cursor_glyph->pixel_width, width);
6364 w->phys_cursor_width = width;
6365 x_clip_to_row (w, row, TEXT_AREA, gc);
6367 if (kind == BAR_CURSOR)
6368 mac_fill_rectangle (f, gc,
6369 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6370 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6371 width, row->height);
6372 else
6373 mac_fill_rectangle (f, gc,
6374 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6375 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6376 row->height - width),
6377 cursor_glyph->pixel_width,
6378 width);
6380 mac_reset_clip_rectangles (dpy, gc);
6385 /* RIF: Define cursor CURSOR on frame F. */
6387 static void
6388 mac_define_frame_cursor (f, cursor)
6389 struct frame *f;
6390 Cursor cursor;
6392 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6394 if (dpyinfo->x_focus_frame == f)
6395 SetThemeCursor (cursor);
6399 /* RIF: Clear area on frame F. */
6401 static void
6402 mac_clear_frame_area (f, x, y, width, height)
6403 struct frame *f;
6404 int x, y, width, height;
6406 mac_clear_area (f, x, y, width, height);
6410 /* RIF: Draw cursor on window W. */
6412 static void
6413 mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
6414 struct window *w;
6415 struct glyph_row *glyph_row;
6416 int x, y;
6417 int cursor_type, cursor_width;
6418 int on_p, active_p;
6420 if (on_p)
6422 w->phys_cursor_type = cursor_type;
6423 w->phys_cursor_on_p = 1;
6425 if (glyph_row->exact_window_width_line_p
6426 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6428 glyph_row->cursor_in_fringe_p = 1;
6429 draw_fringe_bitmap (w, glyph_row, 0);
6431 else
6432 switch (cursor_type)
6434 case HOLLOW_BOX_CURSOR:
6435 x_draw_hollow_cursor (w, glyph_row);
6436 break;
6438 case FILLED_BOX_CURSOR:
6439 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
6440 break;
6442 case BAR_CURSOR:
6443 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6444 break;
6446 case HBAR_CURSOR:
6447 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
6448 break;
6450 case NO_CURSOR:
6451 w->phys_cursor_width = 0;
6452 break;
6454 default:
6455 abort ();
6461 /* Icons. */
6463 #if 0 /* MAC_TODO: no icon support yet. */
6465 x_bitmap_icon (f, icon)
6466 struct frame *f;
6467 Lisp_Object icon;
6469 HANDLE hicon;
6471 if (FRAME_W32_WINDOW (f) == 0)
6472 return 1;
6474 if (NILP (icon))
6475 hicon = LoadIcon (hinst, EMACS_CLASS);
6476 else if (STRINGP (icon))
6477 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
6478 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6479 else if (SYMBOLP (icon))
6481 LPCTSTR name;
6483 if (EQ (icon, intern ("application")))
6484 name = (LPCTSTR) IDI_APPLICATION;
6485 else if (EQ (icon, intern ("hand")))
6486 name = (LPCTSTR) IDI_HAND;
6487 else if (EQ (icon, intern ("question")))
6488 name = (LPCTSTR) IDI_QUESTION;
6489 else if (EQ (icon, intern ("exclamation")))
6490 name = (LPCTSTR) IDI_EXCLAMATION;
6491 else if (EQ (icon, intern ("asterisk")))
6492 name = (LPCTSTR) IDI_ASTERISK;
6493 else if (EQ (icon, intern ("winlogo")))
6494 name = (LPCTSTR) IDI_WINLOGO;
6495 else
6496 return 1;
6498 hicon = LoadIcon (NULL, name);
6500 else
6501 return 1;
6503 if (hicon == NULL)
6504 return 1;
6506 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6507 (LPARAM) hicon);
6509 return 0;
6511 #endif /* MAC_TODO */
6513 /************************************************************************
6514 Handling X errors
6515 ************************************************************************/
6517 /* Display Error Handling functions not used on W32. Listing them here
6518 helps diff stay in step when comparing w32term.c with xterm.c.
6520 x_error_catcher (display, error)
6521 x_catch_errors (dpy)
6522 x_catch_errors_unwind (old_val)
6523 x_check_errors (dpy, format)
6524 x_had_errors_p (dpy)
6525 x_clear_errors (dpy)
6526 x_uncatch_errors (dpy, count)
6527 x_trace_wire ()
6528 x_connection_signal (signalnum)
6529 x_connection_closed (dpy, error_message)
6530 x_error_quitter (display, error)
6531 x_error_handler (display, error)
6532 x_io_error_quitter (display)
6537 /* Changing the font of the frame. */
6539 /* Give frame F the font named FONTNAME as its default font, and
6540 return the full name of that font. FONTNAME may be a wildcard
6541 pattern; in that case, we choose some font that fits the pattern.
6542 The return value shows which font we chose. */
6544 Lisp_Object
6545 x_new_font (f, fontname)
6546 struct frame *f;
6547 register char *fontname;
6549 struct font_info *fontp
6550 = FS_LOAD_FONT (f, 0, fontname, -1);
6552 if (!fontp)
6553 return Qnil;
6555 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6556 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6557 FRAME_FONTSET (f) = -1;
6559 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6560 FRAME_SPACE_WIDTH (f) = fontp->space_width;
6561 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6563 compute_fringe_widths (f, 1);
6565 /* Compute the scroll bar width in character columns. */
6566 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6568 int wid = FRAME_COLUMN_WIDTH (f);
6569 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6570 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
6572 else
6574 int wid = FRAME_COLUMN_WIDTH (f);
6575 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6578 /* Now make the frame display the given font. */
6579 if (FRAME_MAC_WINDOW (f) != 0)
6581 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
6582 FRAME_FONT (f));
6583 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
6584 FRAME_FONT (f));
6585 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
6586 FRAME_FONT (f));
6588 /* Don't change the size of a tip frame; there's no point in
6589 doing it because it's done in Fx_show_tip, and it leads to
6590 problems because the tip frame has no widget. */
6591 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
6592 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6595 return build_string (fontp->full_name);
6598 /* Give frame F the fontset named FONTSETNAME as its default font, and
6599 return the full name of that fontset. FONTSETNAME may be a wildcard
6600 pattern; in that case, we choose some fontset that fits the pattern.
6601 The return value shows which fontset we chose. */
6603 Lisp_Object
6604 x_new_fontset (f, fontsetname)
6605 struct frame *f;
6606 char *fontsetname;
6608 int fontset = fs_query_fontset (build_string (fontsetname), 0);
6609 Lisp_Object result;
6611 if (fontset < 0)
6612 return Qnil;
6614 if (FRAME_FONTSET (f) == fontset)
6615 /* This fontset is already set in frame F. There's nothing more
6616 to do. */
6617 return fontset_name (fontset);
6619 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6621 if (!STRINGP (result))
6622 /* Can't load ASCII font. */
6623 return Qnil;
6625 /* Since x_new_font doesn't update any fontset information, do it now. */
6626 FRAME_FONTSET (f) = fontset;
6628 return build_string (fontsetname);
6632 /***********************************************************************
6633 TODO: W32 Input Methods
6634 ***********************************************************************/
6635 /* Listing missing functions from xterm.c helps diff stay in step.
6637 xim_destroy_callback (xim, client_data, call_data)
6638 xim_open_dpy (dpyinfo, resource_name)
6639 struct xim_inst_t
6640 xim_instantiate_callback (display, client_data, call_data)
6641 xim_initialize (dpyinfo, resource_name)
6642 xim_close_dpy (dpyinfo)
6647 void
6648 mac_get_window_bounds (f, inner, outer)
6649 struct frame *f;
6650 Rect *inner, *outer;
6652 #if TARGET_API_MAC_CARBON
6653 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6654 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6655 #else /* not TARGET_API_MAC_CARBON */
6656 RgnHandle region = NewRgn ();
6658 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6659 *inner = (*region)->rgnBBox;
6660 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6661 *outer = (*region)->rgnBBox;
6662 DisposeRgn (region);
6663 #endif /* not TARGET_API_MAC_CARBON */
6666 static void
6667 mac_handle_origin_change (f)
6668 struct frame *f;
6670 x_real_positions (f, &f->left_pos, &f->top_pos);
6673 static void
6674 mac_handle_size_change (f, pixelwidth, pixelheight)
6675 struct frame *f;
6676 int pixelwidth, pixelheight;
6678 int cols, rows;
6680 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6681 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6683 if (cols != FRAME_COLS (f)
6684 || rows != FRAME_LINES (f)
6685 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6686 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6688 /* We pass 1 for DELAY since we can't run Lisp code inside of
6689 a BLOCK_INPUT. */
6690 change_frame_size (f, rows, cols, 0, 1, 0);
6691 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6692 FRAME_PIXEL_HEIGHT (f) = pixelheight;
6693 SET_FRAME_GARBAGED (f);
6695 /* If cursor was outside the new size, mark it as off. */
6696 mark_window_cursors_off (XWINDOW (f->root_window));
6698 /* Clear out any recollection of where the mouse highlighting
6699 was, since it might be in a place that's outside the new
6700 frame size. Actually checking whether it is outside is a
6701 pain in the neck, so don't try--just let the highlighting be
6702 done afresh with new size. */
6703 cancel_mouse_face (f);
6705 #if TARGET_API_MAC_CARBON
6706 if (f->output_data.mac->hourglass_control)
6708 #if USE_CG_DRAWING
6709 mac_prepare_for_quickdraw (f);
6710 #endif
6711 MoveControl (f->output_data.mac->hourglass_control,
6712 pixelwidth - HOURGLASS_WIDTH, 0);
6714 #endif
6719 /* Calculate the absolute position in frame F
6720 from its current recorded position values and gravity. */
6722 void
6723 x_calc_absolute_position (f)
6724 struct frame *f;
6726 int width_diff = 0, height_diff = 0;
6727 int flags = f->size_hint_flags;
6728 Rect inner, outer;
6730 /* We have nothing to do if the current position
6731 is already for the top-left corner. */
6732 if (! ((flags & XNegative) || (flags & YNegative)))
6733 return;
6735 /* Find the offsets of the outside upper-left corner of
6736 the inner window, with respect to the outer window. */
6737 BLOCK_INPUT;
6738 mac_get_window_bounds (f, &inner, &outer);
6739 UNBLOCK_INPUT;
6741 width_diff = (outer.right - outer.left) - (inner.right - inner.left);
6742 height_diff = (outer.bottom - outer.top) - (inner.bottom - inner.top);
6744 /* Treat negative positions as relative to the leftmost bottommost
6745 position that fits on the screen. */
6746 if (flags & XNegative)
6747 f->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
6748 - width_diff
6749 - FRAME_PIXEL_WIDTH (f)
6750 + f->left_pos);
6752 if (flags & YNegative)
6753 f->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
6754 - height_diff
6755 - FRAME_PIXEL_HEIGHT (f)
6756 + f->top_pos);
6758 /* The left_pos and top_pos
6759 are now relative to the top and left screen edges,
6760 so the flags should correspond. */
6761 f->size_hint_flags &= ~ (XNegative | YNegative);
6764 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6765 to really change the position, and 0 when calling from
6766 x_make_frame_visible (in that case, XOFF and YOFF are the current
6767 position values). It is -1 when calling from x_set_frame_parameters,
6768 which means, do adjust for borders but don't change the gravity. */
6770 void
6771 x_set_offset (f, xoff, yoff, change_gravity)
6772 struct frame *f;
6773 register int xoff, yoff;
6774 int change_gravity;
6776 if (change_gravity > 0)
6778 f->top_pos = yoff;
6779 f->left_pos = xoff;
6780 f->size_hint_flags &= ~ (XNegative | YNegative);
6781 if (xoff < 0)
6782 f->size_hint_flags |= XNegative;
6783 if (yoff < 0)
6784 f->size_hint_flags |= YNegative;
6785 f->win_gravity = NorthWestGravity;
6787 x_calc_absolute_position (f);
6789 BLOCK_INPUT;
6790 x_wm_set_size_hint (f, (long) 0, 0);
6792 #if TARGET_API_MAC_CARBON
6793 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6794 /* If the title bar is completely outside the screen, adjust the
6795 position. */
6796 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6797 kWindowConstrainMoveRegardlessOfFit
6798 | kWindowConstrainAllowPartial, NULL, NULL);
6799 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
6800 mac_handle_origin_change (f);
6801 #else
6803 Rect inner, outer, screen_rect, dummy;
6804 RgnHandle region = NewRgn ();
6806 mac_get_window_bounds (f, &inner, &outer);
6807 f->x_pixels_diff = inner.left - outer.left;
6808 f->y_pixels_diff = inner.top - outer.top;
6809 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6810 f->top_pos + f->y_pixels_diff, false);
6812 /* If the title bar is completely outside the screen, adjust the
6813 position. The variable `outer' holds the title bar rectangle.
6814 The variable `inner' holds slightly smaller one than `outer',
6815 so that the calculation of overlapping may not become too
6816 strict. */
6817 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6818 outer = (*region)->rgnBBox;
6819 DisposeRgn (region);
6820 inner = outer;
6821 InsetRect (&inner, 8, 8);
6822 screen_rect = qd.screenBits.bounds;
6823 screen_rect.top += GetMBarHeight ();
6825 if (!SectRect (&inner, &screen_rect, &dummy))
6827 if (inner.right <= screen_rect.left)
6828 f->left_pos = screen_rect.left;
6829 else if (inner.left >= screen_rect.right)
6830 f->left_pos = screen_rect.right - (outer.right - outer.left);
6832 if (inner.bottom <= screen_rect.top)
6833 f->top_pos = screen_rect.top;
6834 else if (inner.top >= screen_rect.bottom)
6835 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6837 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6838 f->top_pos + f->y_pixels_diff, false);
6841 #endif
6843 UNBLOCK_INPUT;
6846 /* Call this to change the size of frame F's x-window.
6847 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
6848 for this size change and subsequent size changes.
6849 Otherwise we leave the window gravity unchanged. */
6851 void
6852 x_set_window_size (f, change_gravity, cols, rows)
6853 struct frame *f;
6854 int change_gravity;
6855 int cols, rows;
6857 int pixelwidth, pixelheight;
6859 BLOCK_INPUT;
6861 check_frame_size (f, &rows, &cols);
6862 f->scroll_bar_actual_width
6863 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
6865 compute_fringe_widths (f, 0);
6867 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
6868 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
6870 f->win_gravity = NorthWestGravity;
6871 x_wm_set_size_hint (f, (long) 0, 0);
6873 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
6875 #if TARGET_API_MAC_CARBON
6876 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
6877 #endif
6878 mac_handle_size_change (f, pixelwidth, pixelheight);
6880 if (f->output_data.mac->internal_border_width
6881 != FRAME_INTERNAL_BORDER_WIDTH (f))
6883 mac_clear_window (f);
6884 f->output_data.mac->internal_border_width
6885 = FRAME_INTERNAL_BORDER_WIDTH (f);
6888 SET_FRAME_GARBAGED (f);
6890 UNBLOCK_INPUT;
6893 /* Mouse warping. */
6895 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
6897 void
6898 x_set_mouse_position (f, x, y)
6899 struct frame *f;
6900 int x, y;
6902 int pix_x, pix_y;
6904 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
6905 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
6907 if (pix_x < 0) pix_x = 0;
6908 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
6910 if (pix_y < 0) pix_y = 0;
6911 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
6913 x_set_mouse_pixel_position (f, pix_x, pix_y);
6916 void
6917 x_set_mouse_pixel_position (f, pix_x, pix_y)
6918 struct frame *f;
6919 int pix_x, pix_y;
6921 #ifdef MAC_OSX
6922 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
6923 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
6925 BLOCK_INPUT;
6926 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
6927 UNBLOCK_INPUT;
6928 #else
6929 #if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
6930 BLOCK_INPUT;
6932 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
6933 0, 0, 0, 0, pix_x, pix_y);
6934 UNBLOCK_INPUT;
6935 #endif
6936 #endif
6939 /* focus shifting, raising and lowering. */
6941 void
6942 x_focus_on_frame (f)
6943 struct frame *f;
6945 #if 0 /* This proves to be unpleasant. */
6946 x_raise_frame (f);
6947 #endif
6948 #if 0
6949 /* I don't think that the ICCCM allows programs to do things like this
6950 without the interaction of the window manager. Whatever you end up
6951 doing with this code, do it to x_unfocus_frame too. */
6952 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6953 RevertToPointerRoot, CurrentTime);
6954 #endif /* ! 0 */
6957 void
6958 x_unfocus_frame (f)
6959 struct frame *f;
6963 /* Raise frame F. */
6965 void
6966 x_raise_frame (f)
6967 struct frame *f;
6969 if (f->async_visible)
6971 BLOCK_INPUT;
6972 BringToFront (FRAME_MAC_WINDOW (f));
6973 UNBLOCK_INPUT;
6977 /* Lower frame F. */
6979 void
6980 x_lower_frame (f)
6981 struct frame *f;
6983 if (f->async_visible)
6985 BLOCK_INPUT;
6986 SendBehind (FRAME_MAC_WINDOW (f), NULL);
6987 UNBLOCK_INPUT;
6991 static void
6992 XTframe_raise_lower (f, raise_flag)
6993 FRAME_PTR f;
6994 int raise_flag;
6996 if (raise_flag)
6997 x_raise_frame (f);
6998 else
6999 x_lower_frame (f);
7002 /* Change of visibility. */
7004 static void
7005 mac_handle_visibility_change (f)
7006 struct frame *f;
7008 WindowRef wp = FRAME_MAC_WINDOW (f);
7009 int visible = 0, iconified = 0;
7010 struct input_event buf;
7012 if (IsWindowVisible (wp))
7014 if (IsWindowCollapsed (wp))
7015 iconified = 1;
7016 else
7017 visible = 1;
7020 if (!f->async_visible && visible)
7022 if (f->iconified)
7024 /* wait_reading_process_output will notice this and update
7025 the frame's display structures. If we were made
7026 invisible, we should not set garbaged, because that stops
7027 redrawing on Update events. */
7028 SET_FRAME_GARBAGED (f);
7030 EVENT_INIT (buf);
7031 buf.kind = DEICONIFY_EVENT;
7032 XSETFRAME (buf.frame_or_window, f);
7033 buf.arg = Qnil;
7034 kbd_buffer_store_event (&buf);
7036 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7037 /* Force a redisplay sooner or later to update the
7038 frame titles in case this is the second frame. */
7039 record_asynch_buffer_change ();
7041 else if (f->async_visible && !visible)
7042 if (iconified)
7044 EVENT_INIT (buf);
7045 buf.kind = ICONIFY_EVENT;
7046 XSETFRAME (buf.frame_or_window, f);
7047 buf.arg = Qnil;
7048 kbd_buffer_store_event (&buf);
7051 f->async_visible = visible;
7052 f->async_iconified = iconified;
7055 /* This tries to wait until the frame is really visible.
7056 However, if the window manager asks the user where to position
7057 the frame, this will return before the user finishes doing that.
7058 The frame will not actually be visible at that time,
7059 but it will become visible later when the window manager
7060 finishes with it. */
7062 void
7063 x_make_frame_visible (f)
7064 struct frame *f;
7066 BLOCK_INPUT;
7068 if (! FRAME_VISIBLE_P (f))
7070 /* We test FRAME_GARBAGED_P here to make sure we don't
7071 call x_set_offset a second time
7072 if we get to x_make_frame_visible a second time
7073 before the window gets really visible. */
7074 if (! FRAME_ICONIFIED_P (f)
7075 && ! f->output_data.mac->asked_for_visible)
7076 x_set_offset (f, f->left_pos, f->top_pos, 0);
7078 f->output_data.mac->asked_for_visible = 1;
7080 CollapseWindow (FRAME_MAC_WINDOW (f), false);
7081 ShowWindow (FRAME_MAC_WINDOW (f));
7084 XFlush (FRAME_MAC_DISPLAY (f));
7086 /* Synchronize to ensure Emacs knows the frame is visible
7087 before we do anything else. We do this loop with input not blocked
7088 so that incoming events are handled. */
7090 Lisp_Object frame;
7091 int count;
7093 /* This must come after we set COUNT. */
7094 UNBLOCK_INPUT;
7096 XSETFRAME (frame, f);
7098 /* Wait until the frame is visible. Process X events until a
7099 MapNotify event has been seen, or until we think we won't get a
7100 MapNotify at all.. */
7101 for (count = input_signal_count + 10;
7102 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7104 /* Force processing of queued events. */
7105 x_sync (f);
7107 /* Machines that do polling rather than SIGIO have been
7108 observed to go into a busy-wait here. So we'll fake an
7109 alarm signal to let the handler know that there's something
7110 to be read. We used to raise a real alarm, but it seems
7111 that the handler isn't always enabled here. This is
7112 probably a bug. */
7113 if (input_polling_used ())
7115 /* It could be confusing if a real alarm arrives while
7116 processing the fake one. Turn it off and let the
7117 handler reset it. */
7118 extern void poll_for_input_1 P_ ((void));
7119 int old_poll_suppress_count = poll_suppress_count;
7120 poll_suppress_count = 1;
7121 poll_for_input_1 ();
7122 poll_suppress_count = old_poll_suppress_count;
7125 /* See if a MapNotify event has been processed. */
7126 FRAME_SAMPLE_VISIBILITY (f);
7131 /* Change from mapped state to withdrawn state. */
7133 /* Make the frame visible (mapped and not iconified). */
7135 void
7136 x_make_frame_invisible (f)
7137 struct frame *f;
7139 /* A deactivate event does not occur when the last visible frame is
7140 made invisible. So if we clear the highlight here, it will not
7141 be rehighlighted when it is made visible. */
7142 #if 0
7143 /* Don't keep the highlight on an invisible frame. */
7144 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7145 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7146 #endif
7148 BLOCK_INPUT;
7150 #if !TARGET_API_MAC_CARBON
7151 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7152 that the current position of the window is user-specified, rather than
7153 program-specified, so that when the window is mapped again, it will be
7154 placed at the same location, without forcing the user to position it
7155 by hand again (they have already done that once for this window.) */
7156 x_wm_set_size_hint (f, (long) 0, 1);
7157 #endif
7159 HideWindow (FRAME_MAC_WINDOW (f));
7161 UNBLOCK_INPUT;
7163 #if !TARGET_API_MAC_CARBON
7164 mac_handle_visibility_change (f);
7165 #endif
7168 /* Change window state from mapped to iconified. */
7170 void
7171 x_iconify_frame (f)
7172 struct frame *f;
7174 OSStatus err;
7176 /* A deactivate event does not occur when the last visible frame is
7177 iconified. So if we clear the highlight here, it will not be
7178 rehighlighted when it is deiconified. */
7179 #if 0
7180 /* Don't keep the highlight on an invisible frame. */
7181 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7182 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7183 #endif
7185 if (f->async_iconified)
7186 return;
7188 BLOCK_INPUT;
7190 FRAME_SAMPLE_VISIBILITY (f);
7192 if (! FRAME_VISIBLE_P (f))
7193 ShowWindow (FRAME_MAC_WINDOW (f));
7195 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
7197 UNBLOCK_INPUT;
7199 if (err != noErr)
7200 error ("Can't notify window manager of iconification");
7202 #if !TARGET_API_MAC_CARBON
7203 mac_handle_visibility_change (f);
7204 #endif
7208 /* Free X resources of frame F. */
7210 void
7211 x_free_frame_resources (f)
7212 struct frame *f;
7214 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7215 WindowRef wp = FRAME_MAC_WINDOW (f);
7217 BLOCK_INPUT;
7219 if (wp != tip_window)
7220 remove_window_handler (wp);
7222 #if USE_CG_DRAWING
7223 mac_prepare_for_quickdraw (f);
7224 #endif
7225 DisposeWindow (wp);
7226 if (wp == tip_window)
7227 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7228 closed' event. So we reset tip_window here. */
7229 tip_window = NULL;
7231 free_frame_menubar (f);
7233 if (FRAME_FACE_CACHE (f))
7234 free_frame_faces (f);
7236 x_free_gcs (f);
7238 if (FRAME_SIZE_HINTS (f))
7239 xfree (FRAME_SIZE_HINTS (f));
7241 xfree (f->output_data.mac);
7242 f->output_data.mac = NULL;
7244 if (f == dpyinfo->x_focus_frame)
7246 dpyinfo->x_focus_frame = 0;
7247 #if USE_MAC_FONT_PANEL
7248 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7249 #endif
7251 if (f == dpyinfo->x_focus_event_frame)
7252 dpyinfo->x_focus_event_frame = 0;
7253 if (f == dpyinfo->x_highlight_frame)
7254 dpyinfo->x_highlight_frame = 0;
7256 if (f == dpyinfo->mouse_face_mouse_frame)
7258 dpyinfo->mouse_face_beg_row
7259 = dpyinfo->mouse_face_beg_col = -1;
7260 dpyinfo->mouse_face_end_row
7261 = dpyinfo->mouse_face_end_col = -1;
7262 dpyinfo->mouse_face_window = Qnil;
7263 dpyinfo->mouse_face_deferred_gc = 0;
7264 dpyinfo->mouse_face_mouse_frame = 0;
7267 UNBLOCK_INPUT;
7271 /* Destroy the X window of frame F. */
7273 void
7274 x_destroy_window (f)
7275 struct frame *f;
7277 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7279 x_free_frame_resources (f);
7281 dpyinfo->reference_count--;
7285 /* Setting window manager hints. */
7287 /* Set the normal size hints for the window manager, for frame F.
7288 FLAGS is the flags word to use--or 0 meaning preserve the flags
7289 that the window now has.
7290 If USER_POSITION is nonzero, we set the USPosition
7291 flag (this is useful when FLAGS is 0). */
7292 void
7293 x_wm_set_size_hint (f, flags, user_position)
7294 struct frame *f;
7295 long flags;
7296 int user_position;
7298 int base_width, base_height, width_inc, height_inc;
7299 int min_rows = 0, min_cols = 0;
7300 XSizeHints *size_hints;
7302 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7303 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7304 width_inc = FRAME_COLUMN_WIDTH (f);
7305 height_inc = FRAME_LINE_HEIGHT (f);
7307 check_frame_size (f, &min_rows, &min_cols);
7309 size_hints = FRAME_SIZE_HINTS (f);
7310 if (size_hints == NULL)
7312 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7313 bzero (size_hints, sizeof (XSizeHints));
7316 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7317 size_hints->width_inc = width_inc;
7318 size_hints->height_inc = height_inc;
7319 size_hints->min_width = base_width + min_cols * width_inc;
7320 size_hints->min_height = base_height + min_rows * height_inc;
7321 size_hints->base_width = base_width;
7322 size_hints->base_height = base_height;
7324 if (flags)
7325 size_hints->flags = flags;
7326 else if (user_position)
7328 size_hints->flags &= ~ PPosition;
7329 size_hints->flags |= USPosition;
7333 #if 0 /* MAC_TODO: hide application instead of iconify? */
7334 /* Used for IconicState or NormalState */
7336 void
7337 x_wm_set_window_state (f, state)
7338 struct frame *f;
7339 int state;
7341 #ifdef USE_X_TOOLKIT
7342 Arg al[1];
7344 XtSetArg (al[0], XtNinitialState, state);
7345 XtSetValues (f->output_data.x->widget, al, 1);
7346 #else /* not USE_X_TOOLKIT */
7347 Window window = FRAME_X_WINDOW (f);
7349 f->output_data.x->wm_hints.flags |= StateHint;
7350 f->output_data.x->wm_hints.initial_state = state;
7352 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7353 #endif /* not USE_X_TOOLKIT */
7356 void
7357 x_wm_set_icon_pixmap (f, pixmap_id)
7358 struct frame *f;
7359 int pixmap_id;
7361 Pixmap icon_pixmap;
7363 #ifndef USE_X_TOOLKIT
7364 Window window = FRAME_X_WINDOW (f);
7365 #endif
7367 if (pixmap_id > 0)
7369 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7370 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7372 else
7374 /* It seems there is no way to turn off use of an icon pixmap.
7375 The following line does it, only if no icon has yet been created,
7376 for some window managers. But with mwm it crashes.
7377 Some people say it should clear the IconPixmapHint bit in this case,
7378 but that doesn't work, and the X consortium said it isn't the
7379 right thing at all. Since there is no way to win,
7380 best to explicitly give up. */
7381 #if 0
7382 f->output_data.x->wm_hints.icon_pixmap = None;
7383 #else
7384 return;
7385 #endif
7388 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7391 Arg al[1];
7392 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7393 XtSetValues (f->output_data.x->widget, al, 1);
7396 #else /* not USE_X_TOOLKIT */
7398 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7399 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7401 #endif /* not USE_X_TOOLKIT */
7404 #endif /* MAC_TODO */
7406 void
7407 x_wm_set_icon_position (f, icon_x, icon_y)
7408 struct frame *f;
7409 int icon_x, icon_y;
7411 #if 0 /* MAC_TODO: no icons on Mac */
7412 #ifdef USE_X_TOOLKIT
7413 Window window = XtWindow (f->output_data.x->widget);
7414 #else
7415 Window window = FRAME_X_WINDOW (f);
7416 #endif
7418 f->output_data.x->wm_hints.flags |= IconPositionHint;
7419 f->output_data.x->wm_hints.icon_x = icon_x;
7420 f->output_data.x->wm_hints.icon_y = icon_y;
7422 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7423 #endif /* MAC_TODO */
7427 /***********************************************************************
7428 XLFD Pattern Match
7429 ***********************************************************************/
7431 /* An XLFD pattern is divided into blocks delimited by '*'. This
7432 structure holds information for each block. */
7433 struct xlfdpat_block
7435 /* Length of the pattern string in this block. Non-zero except for
7436 the first and the last blocks. */
7437 int len;
7439 /* Pattern string except the last character in this block. The last
7440 character is replaced with NUL in order to use it as a
7441 sentinel. */
7442 unsigned char *pattern;
7444 /* Last character of the pattern string. Must not be '?'. */
7445 unsigned char last_char;
7447 /* One of the tables for the Boyer-Moore string search. It
7448 specifies the number of positions to proceed for each character
7449 with which the match fails. */
7450 int skip[256];
7452 /* The skip value for the last character in the above `skip' is
7453 assigned to `infinity' in order to simplify a loop condition.
7454 The original value is saved here. */
7455 int last_char_skip;
7458 struct xlfdpat
7460 /* Normalized pattern string. "Normalized" means that capital
7461 letters are lowered, blocks are not empty except the first and
7462 the last ones, and trailing '?'s in a block that is not the last
7463 one are moved to the next one. The last character in each block
7464 is replaced with NUL. */
7465 unsigned char *buf;
7467 /* Number of characters except '*'s and trailing '?'s in the
7468 normalized pattern string. */
7469 int nchars;
7471 /* Number of trailing '?'s in the normalized pattern string. */
7472 int trailing_anychars;
7474 /* Number of blocks and information for each block. The latter is
7475 NULL if the pattern is exact (no '*' or '?' in it). */
7476 int nblocks;
7477 struct xlfdpat_block *blocks;
7480 static void
7481 xlfdpat_destroy (pat)
7482 struct xlfdpat *pat;
7484 if (pat)
7486 if (pat->buf)
7488 if (pat->blocks)
7489 xfree (pat->blocks);
7490 xfree (pat->buf);
7492 xfree (pat);
7496 static struct xlfdpat *
7497 xlfdpat_create (pattern)
7498 const char *pattern;
7500 struct xlfdpat *pat;
7501 int nblocks, i, skip;
7502 unsigned char last_char, *p, *q, *anychar_head;
7503 const unsigned char *ptr;
7504 struct xlfdpat_block *blk;
7506 pat = xmalloc (sizeof (struct xlfdpat));
7507 pat->buf = xmalloc (strlen (pattern) + 1);
7509 /* Normalize the pattern string and store it to `pat->buf'. */
7510 nblocks = 0;
7511 anychar_head = NULL;
7512 q = pat->buf;
7513 last_char = '\0';
7514 for (ptr = pattern; *ptr; ptr++)
7516 unsigned char c = *ptr;
7518 if (c == '*')
7519 if (last_char == '*')
7520 /* ...a** -> ...a* */
7521 continue;
7522 else
7524 if (last_char == '?')
7526 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7527 /* ...*??* -> ...*?? */
7528 continue;
7529 else
7530 /* ...a??* -> ...a*?? */
7532 *anychar_head++ = '*';
7533 c = '?';
7536 nblocks++;
7538 else if (c == '?')
7540 if (last_char != '?')
7541 anychar_head = q;
7543 else
7544 /* On Mac OS X 10.3, tolower also converts non-ASCII
7545 characters for some locales. */
7546 if (isascii (c))
7547 c = tolower (c);
7549 *q++ = last_char = c;
7551 *q = '\0';
7552 nblocks++;
7553 pat->nblocks = nblocks;
7554 if (last_char != '?')
7555 pat->trailing_anychars = 0;
7556 else
7558 pat->trailing_anychars = q - anychar_head;
7559 q = anychar_head;
7561 pat->nchars = q - pat->buf - (nblocks - 1);
7563 if (anychar_head == NULL && nblocks == 1)
7565 /* The pattern is exact. */
7566 pat->blocks = NULL;
7567 return pat;
7570 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
7572 /* Divide the normalized pattern into blocks. */
7573 p = pat->buf;
7574 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7576 blk->pattern = p;
7577 while (*p != '*')
7578 p++;
7579 blk->len = p - blk->pattern;
7580 p++;
7582 blk->pattern = p;
7583 blk->len = q - blk->pattern;
7585 /* Setup a table for the Boyer-Moore string search. */
7586 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7587 if (blk->len != 0)
7589 blk->last_char = blk->pattern[blk->len - 1];
7590 blk->pattern[blk->len - 1] = '\0';
7592 for (skip = 1; skip < blk->len; skip++)
7593 if (blk->pattern[blk->len - skip - 1] == '?')
7594 break;
7596 for (i = 0; i < 256; i++)
7597 blk->skip[i] = skip;
7599 p = blk->pattern + (blk->len - skip);
7600 while (--skip > 0)
7601 blk->skip[*p++] = skip;
7603 blk->last_char_skip = blk->skip[blk->last_char];
7606 return pat;
7609 static INLINE int
7610 xlfdpat_exact_p (pat)
7611 struct xlfdpat *pat;
7613 return pat->blocks == NULL;
7616 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
7617 that the pattern in *BLK matches with its prefix. Return NULL
7618 there is no such strings. STRING must be lowered in advance. */
7620 static const char *
7621 xlfdpat_block_match_1 (blk, string, start_max)
7622 struct xlfdpat_block *blk;
7623 const unsigned char *string;
7624 int start_max;
7626 int start, infinity;
7627 unsigned char *p;
7628 const unsigned char *s;
7630 xassert (blk->len > 0);
7631 xassert (start_max + blk->len <= strlen (string));
7632 xassert (blk->last_char != '?');
7634 /* See the comments in the function `boyer_moore' (search.c) for the
7635 use of `infinity'. */
7636 infinity = start_max + blk->len + 1;
7637 blk->skip[blk->last_char] = infinity;
7639 start = 0;
7642 /* Check the last character of the pattern. */
7643 s = string + blk->len - 1;
7646 start += blk->skip[*(s + start)];
7648 while (start <= start_max);
7650 if (start < infinity)
7651 /* Couldn't find the last character. */
7652 return NULL;
7654 /* No less than `infinity' means we could find the last
7655 character at `s[start - infinity]'. */
7656 start -= infinity;
7658 /* Check the remaining characters. We prefer making no-'?'
7659 cases faster because the use of '?' is really rare. */
7660 p = blk->pattern;
7661 s = string + start;
7664 while (*p++ == *s++)
7667 while (*(p - 1) == '?');
7669 if (*(p - 1) == '\0')
7670 /* Matched. */
7671 return string + start;
7673 /* Didn't match. */
7674 start += blk->last_char_skip;
7676 while (start <= start_max);
7678 return NULL;
7681 #define xlfdpat_block_match(b, s, m) \
7682 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7683 : xlfdpat_block_match_1 (b, s, m))
7685 /* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
7686 matches with STRING. STRING must be lowered in advance. */
7688 static int
7689 xlfdpat_match (pat, string)
7690 struct xlfdpat *pat;
7691 const unsigned char *string;
7693 int str_len, nblocks, i, start_max;
7694 struct xlfdpat_block *blk;
7695 const unsigned char *s;
7697 xassert (pat->nblocks > 0);
7699 if (xlfdpat_exact_p (pat))
7700 return strcmp (pat->buf, string) == 0;
7702 /* The number of the characters in the string must not be smaller
7703 than that in the pattern. */
7704 str_len = strlen (string);
7705 if (str_len < pat->nchars + pat->trailing_anychars)
7706 return 0;
7708 /* Chop off the trailing '?'s. */
7709 str_len -= pat->trailing_anychars;
7711 /* The last block. When it is non-empty, it must match at the end
7712 of the string. */
7713 nblocks = pat->nblocks;
7714 blk = pat->blocks + (nblocks - 1);
7715 if (nblocks == 1)
7716 /* The last block is also the first one. */
7717 return (str_len == blk->len
7718 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7719 else if (blk->len != 0)
7720 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7721 return 0;
7723 /* The first block. When it is non-empty, it must match at the
7724 beginning of the string. */
7725 blk = pat->blocks;
7726 if (blk->len != 0)
7728 s = xlfdpat_block_match (blk, string, 0);
7729 if (s == NULL)
7730 return 0;
7731 string = s + blk->len;
7734 /* The rest of the blocks. */
7735 start_max = str_len - pat->nchars;
7736 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7738 s = xlfdpat_block_match (blk, string, start_max);
7739 if (s == NULL)
7740 return 0;
7741 start_max -= s - string;
7742 string = s + blk->len;
7745 return 1;
7749 /***********************************************************************
7750 Fonts
7751 ***********************************************************************/
7753 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7755 struct font_info *
7756 x_get_font_info (f, font_idx)
7757 FRAME_PTR f;
7758 int font_idx;
7760 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7763 /* the global font name table */
7764 static char **font_name_table = NULL;
7765 static int font_name_table_size = 0;
7766 static int font_name_count = 0;
7768 /* Alist linking font family names to Font Manager font family
7769 references (which can also be used as QuickDraw font IDs). We use
7770 an alist because hash tables are not ready when the terminal frame
7771 for Mac OS Classic is created. */
7772 static Lisp_Object fm_font_family_alist;
7773 #if USE_ATSUI
7774 /* Hash table linking font family names to ATSU font IDs. */
7775 static Lisp_Object atsu_font_id_hash;
7776 /* Alist linking Font Manager style to face attributes. */
7777 static Lisp_Object fm_style_face_attributes_alist;
7778 extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
7779 #endif
7781 /* Alist linking character set strings to Mac text encoding and Emacs
7782 coding system. */
7783 static Lisp_Object Vmac_charset_info_alist;
7785 static Lisp_Object
7786 create_text_encoding_info_alist ()
7788 Lisp_Object result = Qnil, rest;
7790 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7792 Lisp_Object charset_info = XCAR (rest);
7793 Lisp_Object charset, coding_system, text_encoding;
7794 Lisp_Object existing_info;
7796 if (!(CONSP (charset_info)
7797 && (charset = XCAR (charset_info),
7798 STRINGP (charset))
7799 && CONSP (XCDR (charset_info))
7800 && (text_encoding = XCAR (XCDR (charset_info)),
7801 INTEGERP (text_encoding))
7802 && CONSP (XCDR (XCDR (charset_info)))
7803 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7804 SYMBOLP (coding_system))))
7805 continue;
7807 existing_info = assq_no_quit (text_encoding, result);
7808 if (NILP (existing_info))
7809 result = Fcons (list3 (text_encoding, coding_system, charset),
7810 result);
7811 else
7812 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7813 XSETCDR (XCDR (existing_info),
7814 Fcons (charset, XCDR (XCDR (existing_info))));
7817 return result;
7821 static void
7822 decode_mac_font_name (name, size, coding_system)
7823 char *name;
7824 int size;
7825 Lisp_Object coding_system;
7827 struct coding_system coding;
7828 char *buf, *p;
7830 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7832 for (p = name; *p; p++)
7833 if (!isascii (*p) || iscntrl (*p))
7834 break;
7836 if (*p)
7838 setup_coding_system (coding_system, &coding);
7839 coding.src_multibyte = 0;
7840 coding.dst_multibyte = 1;
7841 coding.mode |= CODING_MODE_LAST_BLOCK;
7842 coding.composing = COMPOSITION_DISABLED;
7843 buf = (char *) alloca (size);
7845 decode_coding (&coding, name, buf, strlen (name), size - 1);
7846 bcopy (buf, name, coding.produced);
7847 name[coding.produced] = '\0';
7851 /* If there's just one occurrence of '-' in the family name, it is
7852 replaced with '_'. (More than one occurrence of '-' means a
7853 "FOUNDRY-FAMILY-CHARSET"-style name.) */
7854 p = strchr (name, '-');
7855 if (p && strchr (p + 1, '-') == NULL)
7856 *p = '_';
7858 for (p = name; *p; p++)
7859 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7860 for some locales. */
7861 if (isascii (*p))
7862 *p = tolower (*p);
7866 static char *
7867 mac_to_x_fontname (name, size, style, charset)
7868 const char *name;
7869 int size;
7870 Style style;
7871 char *charset;
7873 Str31 foundry, cs;
7874 Str255 family;
7875 char xf[256], *result;
7876 unsigned char *p;
7878 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
7879 charset = cs;
7880 else
7882 strcpy(foundry, "Apple");
7883 strcpy(family, name);
7886 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
7887 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
7888 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
7890 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
7891 sprintf (result, "-%s-%s-%s", foundry, family, xf);
7892 for (p = result; *p; p++)
7893 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7894 for some locales. */
7895 if (isascii (*p))
7896 *p = tolower (*p);
7897 return result;
7901 /* Parse fully-specified and instantiated X11 font spec XF, and store
7902 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
7903 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
7904 caller must allocate at least 256 and 32 bytes respectively. For
7905 ordinary Mac fonts, the value stored to FAMILY should just be their
7906 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
7907 intlfonts collection contain their charset designation in their
7908 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
7909 types of font names are handled accordingly. */
7911 const int kDefaultFontSize = 12;
7913 static int
7914 parse_x_font_name (xf, family, size, style, charset)
7915 const char *xf;
7916 char *family;
7917 int *size;
7918 Style *style;
7919 char *charset;
7921 Str31 foundry, weight;
7922 int point_size, avgwidth;
7923 char slant[2], *p;
7925 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
7926 foundry, family, weight, slant, size,
7927 &point_size, &avgwidth, charset) != 8
7928 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
7929 foundry, family, weight, slant, size,
7930 &point_size, &avgwidth, charset) != 8)
7931 return 0;
7933 if (*size == 0)
7935 if (point_size > 0)
7936 *size = point_size / 10;
7937 else if (avgwidth > 0)
7938 *size = avgwidth / 10;
7940 if (*size == 0)
7941 *size = kDefaultFontSize;
7943 *style = normal;
7944 if (strcmp (weight, "bold") == 0)
7945 *style |= bold;
7946 if (*slant == 'i')
7947 *style |= italic;
7949 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
7951 int foundry_len = strlen (foundry), family_len = strlen (family);
7953 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
7955 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
7956 but take overlap into account. */
7957 memmove (family + foundry_len + 1, family, family_len);
7958 memcpy (family, foundry, foundry_len);
7959 family[foundry_len] = '-';
7960 family[foundry_len + 1 + family_len] = '-';
7961 strcpy (family + foundry_len + 1 + family_len + 1, charset);
7963 else
7964 return 0;
7967 for (p = family; *p; p++)
7968 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7969 for some locales. */
7970 if (isascii (*p))
7971 *p = tolower (*p);
7973 return 1;
7977 static void
7978 add_font_name_table_entry (char *font_name)
7980 if (font_name_table_size == 0)
7982 font_name_table_size = 256;
7983 font_name_table = (char **)
7984 xmalloc (font_name_table_size * sizeof (char *));
7986 else if (font_name_count + 1 >= font_name_table_size)
7988 font_name_table_size *= 2;
7989 font_name_table = (char **)
7990 xrealloc (font_name_table,
7991 font_name_table_size * sizeof (char *));
7994 font_name_table[font_name_count++] = font_name;
7997 static void
7998 add_mac_font_name (name, size, style, charset)
7999 const char *name;
8000 int size;
8001 Style style;
8002 const char *charset;
8004 if (size > 0)
8005 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8006 else
8008 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8009 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8010 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8011 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8012 charset));
8016 #if USE_ATSUI
8017 static FMFontStyle
8018 fm_get_style_from_font (font)
8019 FMFont font;
8021 OSStatus err;
8022 FMFontStyle style = normal;
8023 ByteCount len;
8024 UInt16 mac_style;
8025 FMFontFamily font_family;
8026 #define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8028 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8029 some font (e.g., Optima) even if it is `bold'. */
8030 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8031 sizeof (mac_style), &mac_style, &len);
8032 if (err == noErr
8033 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8034 style = EndianU16_BtoN (mac_style);
8035 else
8036 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8038 return style;
8041 static ATSUFontID
8042 atsu_find_font_from_family_name (family)
8043 const char *family;
8045 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8046 unsigned hash_code;
8047 int i;
8048 Lisp_Object rest, best;
8049 FMFontStyle min_style, style;
8051 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8052 &hash_code);
8053 if (i < 0)
8054 return kATSUInvalidFontID;
8056 rest = HASH_VALUE (h, i);
8057 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8058 return cons_to_long (rest);
8060 rest = Fnreverse (rest);
8061 best = XCAR (rest);
8062 rest = XCDR (rest);
8063 if (!NILP (rest)
8064 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8067 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8068 if (style < min_style)
8070 best = XCAR (rest);
8071 if (style == normal)
8072 break;
8073 else
8074 min_style = style;
8076 rest = XCDR (rest);
8078 while (!NILP (rest));
8080 HASH_VALUE (h, i) = best;
8081 return cons_to_long (best);
8084 static Lisp_Object
8085 fm_style_to_face_attributes (fm_style)
8086 FMFontStyle fm_style;
8088 Lisp_Object tem;
8090 fm_style &= (bold | italic);
8091 tem = assq_no_quit (make_number (fm_style),
8092 fm_style_face_attributes_alist);
8093 if (!NILP (tem))
8094 return XCDR (tem);
8096 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8097 QCslant, fm_style & italic ? Qitalic : Qnormal);
8098 fm_style_face_attributes_alist =
8099 Fcons (Fcons (make_number (fm_style), tem),
8100 fm_style_face_attributes_alist);
8102 return tem;
8105 static Lisp_Object
8106 atsu_find_font_family_name (font_id)
8107 ATSUFontID font_id;
8109 OSStatus err;
8110 ByteCount len;
8111 Lisp_Object family = Qnil;
8113 err = ATSUFindFontName (font_id, kFontFamilyName,
8114 kFontMacintoshPlatform, kFontNoScript,
8115 kFontNoLanguage, 0, NULL, &len, NULL);
8116 if (err == noErr)
8118 family = make_uninit_string (len);
8119 err = ATSUFindFontName (font_id, kFontFamilyName,
8120 kFontMacintoshPlatform, kFontNoScript,
8121 kFontNoLanguage, len, SDATA (family),
8122 NULL, NULL);
8124 if (err == noErr)
8125 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8127 return family;
8130 Lisp_Object
8131 mac_atsu_font_face_attributes (font_id)
8132 ATSUFontID font_id;
8134 Lisp_Object family, style_attrs;
8136 family = atsu_find_font_family_name (font_id);
8137 if (NILP (family))
8138 return Qnil;
8139 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8140 return Fcons (QCfamily, Fcons (family, style_attrs));
8142 #endif
8144 /* Sets up the table font_name_table to contain the list of all fonts
8145 in the system the first time the table is used so that the Resource
8146 Manager need not be accessed every time this information is
8147 needed. */
8149 static void
8150 init_font_name_table ()
8152 #if TARGET_API_MAC_CARBON
8153 FMFontFamilyIterator ffi;
8154 FMFontFamilyInstanceIterator ffii;
8155 FMFontFamily ff;
8156 Lisp_Object text_encoding_info_alist;
8157 struct gcpro gcpro1;
8159 text_encoding_info_alist = create_text_encoding_info_alist ();
8161 #if USE_ATSUI
8162 #if USE_CG_TEXT_DRAWING
8163 init_cg_text_anti_aliasing_threshold ();
8164 #endif
8165 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8166 text_encoding_info_alist)))
8168 OSStatus err;
8169 struct Lisp_Hash_Table *h;
8170 unsigned hash_code;
8171 ItemCount nfonts, i;
8172 ATSUFontID *font_ids = NULL;
8173 Lisp_Object prev_family = Qnil;
8174 int j;
8176 atsu_font_id_hash =
8177 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8178 make_float (DEFAULT_REHASH_SIZE),
8179 make_float (DEFAULT_REHASH_THRESHOLD),
8180 Qnil, Qnil, Qnil);
8181 h = XHASH_TABLE (atsu_font_id_hash);
8183 err = ATSUFontCount (&nfonts);
8184 if (err == noErr)
8186 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8187 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8189 if (err == noErr)
8190 for (i = 0; i < nfonts; i++)
8192 Lisp_Object family;
8194 family = atsu_find_font_family_name (font_ids[i]);
8195 if (NILP (family) || SREF (family, 0) == '.')
8196 continue;
8197 if (!NILP (Fequal (prev_family, family)))
8198 family = prev_family;
8199 else
8200 j = hash_lookup (h, family, &hash_code);
8201 if (j < 0)
8203 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8204 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8205 Qnil), hash_code);
8207 else if (EQ (prev_family, family))
8208 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8209 HASH_VALUE (h, j));
8210 prev_family = family;
8212 if (font_ids)
8213 xfree (font_ids);
8215 #endif
8217 /* Create a dummy instance iterator here to avoid creating and
8218 destroying it in the loop. */
8219 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8220 return;
8221 /* Create an iterator to enumerate the font families. */
8222 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8223 != noErr)
8225 FMDisposeFontFamilyInstanceIterator (&ffii);
8226 return;
8229 GCPRO1 (text_encoding_info_alist);
8231 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
8233 Str255 name;
8234 FMFont font;
8235 FMFontStyle style;
8236 FMFontSize size;
8237 TextEncoding encoding;
8238 TextEncodingBase sc;
8239 Lisp_Object text_encoding_info, family;
8241 if (FMGetFontFamilyName (ff, name) != noErr)
8242 continue;
8243 p2cstr (name);
8244 if (*name == '.')
8245 continue;
8247 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
8248 continue;
8249 sc = GetTextEncodingBase (encoding);
8250 text_encoding_info = assq_no_quit (make_number (sc),
8251 text_encoding_info_alist);
8252 if (NILP (text_encoding_info))
8253 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8254 text_encoding_info_alist);
8255 decode_mac_font_name (name, sizeof (name),
8256 XCAR (XCDR (text_encoding_info)));
8257 family = build_string (name);
8258 if (!NILP (Fassoc (family, fm_font_family_alist)))
8259 continue;
8260 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
8261 fm_font_family_alist);
8263 /* Point the instance iterator at the current font family. */
8264 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
8265 continue;
8267 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8268 == noErr)
8270 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8272 if (size > 0 || style == normal)
8273 for (; !NILP (rest); rest = XCDR (rest))
8274 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
8278 UNGCPRO;
8280 /* Dispose of the iterators. */
8281 FMDisposeFontFamilyIterator (&ffi);
8282 FMDisposeFontFamilyInstanceIterator (&ffii);
8283 #else /* !TARGET_API_MAC_CARBON */
8284 GrafPtr port;
8285 SInt16 fontnum, old_fontnum;
8286 int num_mac_fonts = CountResources('FOND');
8287 int i, j;
8288 Handle font_handle, font_handle_2;
8289 short id, scriptcode;
8290 ResType type;
8291 Str255 name;
8292 struct FontAssoc *fat;
8293 struct AsscEntry *assc_entry;
8294 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
8295 struct gcpro gcpro1;
8297 GetPort (&port); /* save the current font number used */
8298 old_fontnum = port->txFont;
8300 text_encoding_info_alist = create_text_encoding_info_alist ();
8302 GCPRO1 (text_encoding_info_alist);
8304 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
8306 font_handle = GetIndResource ('FOND', i);
8307 if (!font_handle)
8308 continue;
8310 GetResInfo (font_handle, &id, &type, name);
8311 GetFNum (name, &fontnum);
8312 p2cstr (name);
8313 if (fontnum == 0 || *name == '.')
8314 continue;
8316 TextFont (fontnum);
8317 scriptcode = FontToScript (fontnum);
8318 text_encoding_info = assq_no_quit (make_number (scriptcode),
8319 text_encoding_info_alist);
8320 if (NILP (text_encoding_info))
8321 text_encoding_info = assq_no_quit (make_number (smRoman),
8322 text_encoding_info_alist);
8323 decode_mac_font_name (name, sizeof (name),
8324 XCAR (XCDR (text_encoding_info)));
8325 family = build_string (name);
8326 if (!NILP (Fassoc (family, fm_font_family_alist)))
8327 continue;
8328 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
8329 fm_font_family_alist);
8332 HLock (font_handle);
8334 if (GetResourceSizeOnDisk (font_handle)
8335 >= sizeof (struct FamRec))
8337 fat = (struct FontAssoc *) (*font_handle
8338 + sizeof (struct FamRec));
8339 assc_entry
8340 = (struct AsscEntry *) (*font_handle
8341 + sizeof (struct FamRec)
8342 + sizeof (struct FontAssoc));
8344 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
8346 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8348 for (; !NILP (rest); rest = XCDR (rest))
8349 add_mac_font_name (name, assc_entry->fontSize,
8350 assc_entry->fontStyle,
8351 SDATA (XCAR (rest)));
8355 HUnlock (font_handle);
8356 font_handle_2 = GetNextFOND (font_handle);
8357 ReleaseResource (font_handle);
8358 font_handle = font_handle_2;
8360 while (ResError () == noErr && font_handle);
8363 UNGCPRO;
8365 TextFont (old_fontnum);
8366 #endif /* !TARGET_API_MAC_CARBON */
8370 void
8371 mac_clear_font_name_table ()
8373 int i;
8375 for (i = 0; i < font_name_count; i++)
8376 xfree (font_name_table[i]);
8377 xfree (font_name_table);
8378 font_name_table = NULL;
8379 font_name_table_size = font_name_count = 0;
8380 fm_font_family_alist = Qnil;
8384 enum xlfd_scalable_field_index
8386 XLFD_SCL_PIXEL_SIZE,
8387 XLFD_SCL_POINT_SIZE,
8388 XLFD_SCL_AVGWIDTH,
8389 XLFD_SCL_LAST
8392 static const int xlfd_scalable_fields[] =
8394 6, /* PIXEL_SIZE */
8395 7, /* POINT_SIZE */
8396 11, /* AVGWIDTH */
8400 static Lisp_Object
8401 mac_do_list_fonts (pattern, maxnames)
8402 const char *pattern;
8403 int maxnames;
8405 int i, n_fonts = 0;
8406 Lisp_Object font_list = Qnil;
8407 struct xlfdpat *pat;
8408 char *scaled;
8409 const char *ptr;
8410 int scl_val[XLFD_SCL_LAST], *val;
8411 const int *field;
8412 int exact;
8414 if (font_name_table == NULL) /* Initialize when first used. */
8415 init_font_name_table ();
8417 for (i = 0; i < XLFD_SCL_LAST; i++)
8418 scl_val[i] = -1;
8420 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8421 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8422 fonts are scaled according to the specified size. */
8423 ptr = pattern;
8424 i = 0;
8425 field = xlfd_scalable_fields;
8426 val = scl_val;
8427 if (*ptr == '-')
8430 ptr++;
8431 if (i == *field)
8433 if ('0' <= *ptr && *ptr <= '9')
8435 *val = *ptr++ - '0';
8436 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8437 *val = *val * 10 + *ptr++ - '0';
8438 if (*ptr != '-')
8439 *val = -1;
8441 field++;
8442 val++;
8444 ptr = strchr (ptr, '-');
8445 i++;
8447 while (ptr && i < 14);
8449 if (i == 14 && ptr == NULL)
8451 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8452 scl_val[XLFD_SCL_PIXEL_SIZE] =
8453 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8454 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8455 : -1));
8456 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8457 scl_val[XLFD_SCL_POINT_SIZE] =
8458 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8459 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8460 : -1));
8461 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8462 scl_val[XLFD_SCL_AVGWIDTH] =
8463 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8464 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8465 : -1));
8467 else
8468 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8470 pat = xlfdpat_create (pattern);
8471 if (pat == NULL)
8472 return Qnil;
8474 exact = xlfdpat_exact_p (pat);
8476 for (i = 0; i < font_name_count; i++)
8478 if (xlfdpat_match (pat, font_name_table[i]))
8480 font_list = Fcons (build_string (font_name_table[i]), font_list);
8481 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8482 break;
8484 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
8485 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
8487 int former_len = ptr - font_name_table[i];
8489 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
8490 memcpy (scaled, font_name_table[i], former_len);
8491 sprintf (scaled + former_len,
8492 "-%d-%d-72-72-m-%d-%s",
8493 scl_val[XLFD_SCL_PIXEL_SIZE],
8494 scl_val[XLFD_SCL_POINT_SIZE],
8495 scl_val[XLFD_SCL_AVGWIDTH],
8496 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
8498 if (xlfdpat_match (pat, scaled))
8500 font_list = Fcons (build_string (scaled), font_list);
8501 xfree (scaled);
8502 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8503 break;
8505 else
8506 xfree (scaled);
8510 xlfdpat_destroy (pat);
8512 return font_list;
8515 /* Return a list of names of available fonts matching PATTERN on frame F.
8517 Frame F null means we have not yet created any frame on Mac, and
8518 consult the first display in x_display_list. MAXNAMES sets a limit
8519 on how many fonts to match. */
8521 Lisp_Object
8522 x_list_fonts (f, pattern, size, maxnames)
8523 struct frame *f;
8524 Lisp_Object pattern;
8525 int size, maxnames;
8527 Lisp_Object list = Qnil, patterns, tem, key;
8528 struct mac_display_info *dpyinfo
8529 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
8531 xassert (size <= 0);
8533 patterns = Fassoc (pattern, Valternate_fontname_alist);
8534 if (NILP (patterns))
8535 patterns = Fcons (pattern, Qnil);
8537 for (; CONSP (patterns); patterns = XCDR (patterns))
8539 pattern = XCAR (patterns);
8541 if (!STRINGP (pattern))
8542 continue;
8544 tem = XCAR (XCDR (dpyinfo->name_list_element));
8545 key = Fcons (pattern, make_number (maxnames));
8547 list = Fassoc (key, tem);
8548 if (!NILP (list))
8550 list = Fcdr_safe (list);
8551 /* We have a cashed list. Don't have to get the list again. */
8552 goto label_cached;
8555 BLOCK_INPUT;
8556 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8557 UNBLOCK_INPUT;
8559 /* MAC_TODO: add code for matching outline fonts here */
8561 /* Now store the result in the cache. */
8562 XSETCAR (XCDR (dpyinfo->name_list_element),
8563 Fcons (Fcons (key, list),
8564 XCAR (XCDR (dpyinfo->name_list_element))));
8566 label_cached:
8567 if (NILP (list)) continue; /* Try the remaining alternatives. */
8570 return list;
8574 #if GLYPH_DEBUG
8576 /* Check that FONT is valid on frame F. It is if it can be found in F's
8577 font table. */
8579 static void
8580 x_check_font (f, font)
8581 struct frame *f;
8582 XFontStruct *font;
8584 int i;
8585 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8587 xassert (font != NULL);
8589 for (i = 0; i < dpyinfo->n_fonts; i++)
8590 if (dpyinfo->font_table[i].name
8591 && font == dpyinfo->font_table[i].font)
8592 break;
8594 xassert (i < dpyinfo->n_fonts);
8597 #endif /* GLYPH_DEBUG != 0 */
8599 /* Set *W to the minimum width, *H to the minimum font height of FONT.
8600 Note: There are (broken) X fonts out there with invalid XFontStruct
8601 min_bounds contents. For example, handa@etl.go.jp reports that
8602 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8603 have font->min_bounds.width == 0. */
8605 static INLINE void
8606 x_font_min_bounds (font, w, h)
8607 MacFontStruct *font;
8608 int *w, *h;
8610 *h = FONT_HEIGHT (font);
8611 *w = font->min_bounds.width;
8615 /* Compute the smallest character width and smallest font height over
8616 all fonts available on frame F. Set the members smallest_char_width
8617 and smallest_font_height in F's x_display_info structure to
8618 the values computed. Value is non-zero if smallest_font_height or
8619 smallest_char_width become smaller than they were before. */
8621 static int
8622 x_compute_min_glyph_bounds (f)
8623 struct frame *f;
8625 int i;
8626 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8627 MacFontStruct *font;
8628 int old_width = dpyinfo->smallest_char_width;
8629 int old_height = dpyinfo->smallest_font_height;
8631 dpyinfo->smallest_font_height = 100000;
8632 dpyinfo->smallest_char_width = 100000;
8634 for (i = 0; i < dpyinfo->n_fonts; ++i)
8635 if (dpyinfo->font_table[i].name)
8637 struct font_info *fontp = dpyinfo->font_table + i;
8638 int w, h;
8640 font = (MacFontStruct *) fontp->font;
8641 xassert (font != (MacFontStruct *) ~0);
8642 x_font_min_bounds (font, &w, &h);
8644 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8645 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8648 xassert (dpyinfo->smallest_char_width > 0
8649 && dpyinfo->smallest_font_height > 0);
8651 return (dpyinfo->n_fonts == 1
8652 || dpyinfo->smallest_char_width < old_width
8653 || dpyinfo->smallest_font_height < old_height);
8657 /* Determine whether given string is a fully-specified XLFD: all 14
8658 fields are present, none is '*'. */
8660 static int
8661 is_fully_specified_xlfd (p)
8662 const char *p;
8664 int i;
8665 char *q;
8667 if (*p != '-')
8668 return 0;
8670 for (i = 0; i < 13; i++)
8672 q = strchr (p + 1, '-');
8673 if (q == NULL)
8674 return 0;
8675 if (q - p == 2 && *(p + 1) == '*')
8676 return 0;
8677 p = q;
8680 if (strchr (p + 1, '-') != NULL)
8681 return 0;
8683 if (*(p + 1) == '*' && *(p + 2) == '\0')
8684 return 0;
8686 return 1;
8690 /* mac_load_query_font creates and returns an internal representation
8691 for a font in a MacFontStruct struct. There is really no concept
8692 corresponding to "loading" a font on the Mac. But we check its
8693 existence and find the font number and all other information for it
8694 and store them in the returned MacFontStruct. */
8696 static MacFontStruct *
8697 mac_load_query_font (f, fontname)
8698 struct frame *f;
8699 char *fontname;
8701 int size;
8702 char *name;
8703 Str255 family;
8704 Str31 charset;
8705 SInt16 fontnum;
8706 #if USE_ATSUI
8707 static ATSUFontID font_id;
8708 ATSUStyle mac_style = NULL;
8709 #endif
8710 Style fontface;
8711 #if TARGET_API_MAC_CARBON
8712 TextEncoding encoding;
8713 int scriptcode;
8714 #else
8715 short scriptcode;
8716 #endif
8717 MacFontStruct *font;
8718 XCharStruct *space_bounds = NULL, *pcm;
8720 if (is_fully_specified_xlfd (fontname))
8721 name = fontname;
8722 else
8724 Lisp_Object matched_fonts;
8726 matched_fonts = mac_do_list_fonts (fontname, 1);
8727 if (NILP (matched_fonts))
8728 return NULL;
8729 name = SDATA (XCAR (matched_fonts));
8732 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8733 return NULL;
8735 #if USE_ATSUI
8736 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8738 OSStatus err;
8739 static const ATSUAttributeTag tags[] =
8740 {kATSUFontTag, kATSUSizeTag,
8741 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8742 static const ByteCount sizes[] =
8743 {sizeof (ATSUFontID), sizeof (Fixed),
8744 sizeof (Boolean), sizeof (Boolean)};
8745 static Fixed size_fixed;
8746 static Boolean bold_p, italic_p;
8747 static const ATSUAttributeValuePtr values[] =
8748 {&font_id, &size_fixed,
8749 &bold_p, &italic_p};
8750 static const ATSUFontFeatureType types[] =
8751 {kAllTypographicFeaturesType, kDiacriticsType};
8752 static const ATSUFontFeatureSelector selectors[] =
8753 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
8754 FMFontStyle style;
8756 font_id = atsu_find_font_from_family_name (family);
8757 if (font_id == kATSUInvalidFontID)
8758 return;
8759 size_fixed = Long2Fix (size);
8760 bold_p = (fontface & bold) != 0;
8761 italic_p = (fontface & italic) != 0;
8762 err = ATSUCreateStyle (&mac_style);
8763 if (err != noErr)
8764 return NULL;
8765 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8766 types, selectors);
8767 if (err != noErr)
8768 return NULL;
8769 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8770 tags, sizes, values);
8771 if (err != noErr)
8772 return NULL;
8773 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8774 if (err != noErr)
8775 fontnum = -1;
8776 scriptcode = kTextEncodingMacUnicode;
8778 else
8779 #endif
8781 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8783 if (NILP (tmp))
8784 return NULL;
8785 fontnum = XINT (XCDR (tmp));
8786 #if TARGET_API_MAC_CARBON
8787 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8788 return NULL;
8789 scriptcode = GetTextEncodingBase (encoding);
8790 #else
8791 scriptcode = FontToScript (fontnum);
8792 #endif
8795 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
8797 font->mac_fontnum = fontnum;
8798 font->mac_fontsize = size;
8799 font->mac_fontface = fontface;
8800 font->mac_scriptcode = scriptcode;
8801 #if USE_ATSUI
8802 font->mac_style = mac_style;
8803 #if USE_CG_TEXT_DRAWING
8804 font->cg_font = NULL;
8805 font->cg_glyphs = NULL;
8806 #endif
8807 #endif
8809 /* Apple Japanese (SJIS) font is listed as both
8810 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
8811 (Roman script) in init_font_name_table (). The latter should be
8812 treated as a one-byte font. */
8813 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8814 font->mac_scriptcode = smRoman;
8816 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
8818 #if USE_ATSUI
8819 if (font->mac_style)
8821 OSStatus err;
8822 UniChar c;
8824 font->min_byte1 = 0;
8825 font->max_byte1 = 0xff;
8826 font->min_char_or_byte2 = 0;
8827 font->max_char_or_byte2 = 0xff;
8829 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8830 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8831 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8832 pcm_init (font->bounds.rows[0], 0x100);
8834 #if USE_CG_TEXT_DRAWING
8835 if (fontnum != -1)
8837 FMFontStyle style;
8838 ATSFontRef ats_font;
8840 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
8841 &font_id, &style);
8842 /* Use CG text drawing if italic/bold is not synthesized. */
8843 if (err == noErr && style == fontface)
8845 ats_font = FMGetATSFontRefFromFont (font_id);
8846 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
8850 if (font->cg_font)
8852 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
8853 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
8855 #endif
8856 space_bounds = font->bounds.rows[0] + 0x20;
8857 err = mac_query_char_extents (font->mac_style, 0x20,
8858 &font->ascent, &font->descent,
8859 space_bounds,
8860 #if USE_CG_TEXT_DRAWING
8861 (font->cg_glyphs ? font->cg_glyphs + 0x20
8862 : NULL)
8863 #else
8864 NULL
8865 #endif
8867 if (err != noErr
8868 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
8870 mac_unload_font (&one_mac_display_info, font);
8871 return NULL;
8874 pcm = font->bounds.rows[0];
8875 for (c = 0x21; c <= 0xff; c++)
8877 if (c == 0xad)
8878 /* Soft hyphen is not supported in ATSUI. */
8879 continue;
8880 else if (c == 0x7f)
8882 #if USE_CG_TEXT_DRAWING
8883 if (font->cg_glyphs)
8885 c = 0x9f;
8886 pcm = NULL;
8887 continue;
8889 #endif
8890 break;
8893 mac_query_char_extents (font->mac_style, c, NULL, NULL,
8894 pcm ? pcm + c : NULL,
8895 #if USE_CG_TEXT_DRAWING
8896 (font->cg_glyphs ? font->cg_glyphs + c
8897 : NULL)
8898 #else
8899 NULL
8900 #endif
8903 #if USE_CG_TEXT_DRAWING
8904 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
8906 /* Don't use CG text drawing if font substitution occurs in
8907 ASCII or Latin-1 characters. */
8908 CGFontRelease (font->cg_font);
8909 font->cg_font = NULL;
8910 xfree (font->cg_glyphs);
8911 font->cg_glyphs = NULL;
8912 if (pcm == NULL)
8913 break;
8915 #endif
8918 else
8919 #endif
8921 OSStatus err;
8922 FontInfo the_fontinfo;
8923 int is_two_byte_font;
8925 #if USE_CG_DRAWING
8926 mac_prepare_for_quickdraw (f);
8927 #endif
8928 SetPortWindowPort (FRAME_MAC_WINDOW (f));
8930 TextFont (fontnum);
8931 TextSize (size);
8932 TextFace (fontface);
8934 GetFontInfo (&the_fontinfo);
8936 font->ascent = the_fontinfo.ascent;
8937 font->descent = the_fontinfo.descent;
8939 is_two_byte_font = (font->mac_scriptcode == smJapanese
8940 || font->mac_scriptcode == smTradChinese
8941 || font->mac_scriptcode == smSimpChinese
8942 || font->mac_scriptcode == smKorean);
8944 if (is_two_byte_font)
8946 int char_width;
8948 font->min_byte1 = 0xa1;
8949 font->max_byte1 = 0xfe;
8950 font->min_char_or_byte2 = 0xa1;
8951 font->max_char_or_byte2 = 0xfe;
8953 /* Use the width of an "ideographic space" of that font
8954 because the_fontinfo.widMax returns the wrong width for
8955 some fonts. */
8956 switch (font->mac_scriptcode)
8958 case smJapanese:
8959 font->min_byte1 = 0x81;
8960 font->max_byte1 = 0xfc;
8961 font->min_char_or_byte2 = 0x40;
8962 font->max_char_or_byte2 = 0xfc;
8963 char_width = StringWidth("\p\x81\x40");
8964 break;
8965 case smTradChinese:
8966 font->min_char_or_byte2 = 0x40;
8967 char_width = StringWidth("\p\xa1\x40");
8968 break;
8969 case smSimpChinese:
8970 char_width = StringWidth("\p\xa1\xa1");
8971 break;
8972 case smKorean:
8973 char_width = StringWidth("\p\xa1\xa1");
8974 break;
8977 font->bounds.per_char = NULL;
8979 if (fontface & italic)
8980 font->max_bounds.rbearing = char_width + 1;
8981 else
8982 font->max_bounds.rbearing = char_width;
8983 font->max_bounds.lbearing = 0;
8984 font->max_bounds.width = char_width;
8985 font->max_bounds.ascent = the_fontinfo.ascent;
8986 font->max_bounds.descent = the_fontinfo.descent;
8988 font->min_bounds = font->max_bounds;
8990 else
8992 int c;
8994 font->min_byte1 = font->max_byte1 = 0;
8995 font->min_char_or_byte2 = 0x20;
8996 font->max_char_or_byte2 = 0xff;
8998 font->bounds.per_char =
8999 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
9000 bzero (font->bounds.per_char,
9001 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9003 space_bounds = font->bounds.per_char;
9004 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9005 &font->descent, space_bounds, NULL);
9006 if (err != noErr || space_bounds->width <= 0)
9008 mac_unload_font (&one_mac_display_info, font);
9009 return NULL;
9012 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9013 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
9017 if (space_bounds)
9019 int c;
9021 font->min_bounds = font->max_bounds = *space_bounds;
9022 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9023 if (pcm->width > 0)
9025 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9026 pcm->lbearing);
9027 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9028 pcm->rbearing);
9029 font->min_bounds.width = min (font->min_bounds.width,
9030 pcm->width);
9031 font->min_bounds.ascent = min (font->min_bounds.ascent,
9032 pcm->ascent);
9033 font->min_bounds.descent = min (font->min_bounds.descent,
9034 pcm->descent);
9036 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9037 pcm->lbearing);
9038 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9039 pcm->rbearing);
9040 font->max_bounds.width = max (font->max_bounds.width,
9041 pcm->width);
9042 font->max_bounds.ascent = max (font->max_bounds.ascent,
9043 pcm->ascent);
9044 font->max_bounds.descent = max (font->max_bounds.descent,
9045 pcm->descent);
9047 if (
9048 #if USE_ATSUI
9049 font->mac_style == NULL &&
9050 #endif
9051 font->max_bounds.width == font->min_bounds.width
9052 && font->min_bounds.lbearing >= 0
9053 && font->max_bounds.rbearing <= font->max_bounds.width)
9055 /* Fixed width and no overhangs. */
9056 xfree (font->bounds.per_char);
9057 font->bounds.per_char = NULL;
9061 #if !defined (MAC_OS8) || USE_ATSUI
9062 /* AppKit and WebKit do some adjustment to the heights of Courier,
9063 Helvetica, and Times. This only works on the environments where
9064 srcCopy text transfer mode is never used. */
9065 if (
9066 #ifdef MAC_OS8 /* implies USE_ATSUI */
9067 font->mac_style &&
9068 #endif
9069 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9070 || strcmp (family, "times") == 0))
9071 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9072 #endif
9074 return font;
9078 void
9079 mac_unload_font (dpyinfo, font)
9080 struct mac_display_info *dpyinfo;
9081 XFontStruct *font;
9083 xfree (font->full_name);
9084 #if USE_ATSUI
9085 if (font->mac_style)
9087 int i;
9089 for (i = font->min_byte1; i <= font->max_byte1; i++)
9090 if (font->bounds.rows[i])
9091 xfree (font->bounds.rows[i]);
9092 xfree (font->bounds.rows);
9093 ATSUDisposeStyle (font->mac_style);
9095 else
9096 #endif
9097 if (font->bounds.per_char)
9098 xfree (font->bounds.per_char);
9099 #if USE_CG_TEXT_DRAWING
9100 if (font->cg_font)
9101 CGFontRelease (font->cg_font);
9102 if (font->cg_glyphs)
9103 xfree (font->cg_glyphs);
9104 #endif
9105 xfree (font);
9109 /* Load font named FONTNAME of the size SIZE for frame F, and return a
9110 pointer to the structure font_info while allocating it dynamically.
9111 If SIZE is 0, load any size of font.
9112 If loading is failed, return NULL. */
9114 struct font_info *
9115 x_load_font (f, fontname, size)
9116 struct frame *f;
9117 register char *fontname;
9118 int size;
9120 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9121 Lisp_Object font_names;
9123 /* Get a list of all the fonts that match this name. Once we
9124 have a list of matching fonts, we compare them against the fonts
9125 we already have by comparing names. */
9126 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9128 if (!NILP (font_names))
9130 Lisp_Object tail;
9131 int i;
9133 for (i = 0; i < dpyinfo->n_fonts; i++)
9134 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9135 if (dpyinfo->font_table[i].name
9136 && (!strcmp (dpyinfo->font_table[i].name,
9137 SDATA (XCAR (tail)))
9138 || !strcmp (dpyinfo->font_table[i].full_name,
9139 SDATA (XCAR (tail)))))
9140 return (dpyinfo->font_table + i);
9142 else
9143 return NULL;
9145 /* Load the font and add it to the table. */
9147 struct MacFontStruct *font;
9148 struct font_info *fontp;
9149 int i;
9151 fontname = (char *) SDATA (XCAR (font_names));
9153 BLOCK_INPUT;
9154 font = mac_load_query_font (f, fontname);
9155 UNBLOCK_INPUT;
9156 if (!font)
9157 return NULL;
9159 /* Find a free slot in the font table. */
9160 for (i = 0; i < dpyinfo->n_fonts; ++i)
9161 if (dpyinfo->font_table[i].name == NULL)
9162 break;
9164 /* If no free slot found, maybe enlarge the font table. */
9165 if (i == dpyinfo->n_fonts
9166 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9168 int sz;
9169 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9170 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9171 dpyinfo->font_table
9172 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9175 fontp = dpyinfo->font_table + i;
9176 if (i == dpyinfo->n_fonts)
9177 ++dpyinfo->n_fonts;
9179 /* Now fill in the slots of *FONTP. */
9180 BLOCK_INPUT;
9181 bzero (fontp, sizeof (*fontp));
9182 fontp->font = font;
9183 fontp->font_idx = i;
9184 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9185 bcopy (fontname, fontp->name, strlen (fontname) + 1);
9187 if (font->min_bounds.width == font->max_bounds.width)
9189 /* Fixed width font. */
9190 fontp->average_width = fontp->space_width = font->min_bounds.width;
9192 else
9194 XChar2b char2b;
9195 XCharStruct *pcm;
9197 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9198 pcm = mac_per_char_metric (font, &char2b, 0);
9199 if (pcm)
9200 fontp->space_width = pcm->width;
9201 else
9202 fontp->space_width = FONT_WIDTH (font);
9204 if (pcm)
9206 int width = pcm->width;
9207 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9208 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9209 width += pcm->width;
9210 fontp->average_width = width / 95;
9212 else
9213 fontp->average_width = FONT_WIDTH (font);
9216 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9217 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
9219 fontp->size = font->max_bounds.width;
9220 fontp->height = FONT_HEIGHT (font);
9222 /* For some font, ascent and descent in max_bounds field is
9223 larger than the above value. */
9224 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9225 if (max_height > fontp->height)
9226 fontp->height = max_height;
9229 /* The slot `encoding' specifies how to map a character
9230 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9231 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9232 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9233 2:0xA020..0xFF7F). For the moment, we don't know which charset
9234 uses this font. So, we set information in fontp->encoding[1]
9235 which is never used by any charset. If mapping can't be
9236 decided, set FONT_ENCODING_NOT_DECIDED. */
9237 if (font->mac_scriptcode == smJapanese)
9238 fontp->encoding[1] = 4;
9239 else
9241 fontp->encoding[1]
9242 = (font->max_byte1 == 0
9243 /* 1-byte font */
9244 ? (font->min_char_or_byte2 < 0x80
9245 ? (font->max_char_or_byte2 < 0x80
9246 ? 0 /* 0x20..0x7F */
9247 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9248 : 1) /* 0xA0..0xFF */
9249 /* 2-byte font */
9250 : (font->min_byte1 < 0x80
9251 ? (font->max_byte1 < 0x80
9252 ? (font->min_char_or_byte2 < 0x80
9253 ? (font->max_char_or_byte2 < 0x80
9254 ? 0 /* 0x2020..0x7F7F */
9255 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9256 : 3) /* 0x20A0..0x7FFF */
9257 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9258 : (font->min_char_or_byte2 < 0x80
9259 ? (font->max_char_or_byte2 < 0x80
9260 ? 2 /* 0xA020..0xFF7F */
9261 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9262 : 1))); /* 0xA0A0..0xFFFF */
9265 #if 0 /* MAC_TODO: fill these out with more reasonably values */
9266 fontp->baseline_offset
9267 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9268 ? (long) value : 0);
9269 fontp->relative_compose
9270 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9271 ? (long) value : 0);
9272 fontp->default_ascent
9273 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9274 ? (long) value : 0);
9275 #else
9276 fontp->baseline_offset = 0;
9277 fontp->relative_compose = 0;
9278 fontp->default_ascent = 0;
9279 #endif
9281 /* Set global flag fonts_changed_p to non-zero if the font loaded
9282 has a character with a smaller width than any other character
9283 before, or if the font loaded has a smaller height than any
9284 other font loaded before. If this happens, it will make a
9285 glyph matrix reallocation necessary. */
9286 fonts_changed_p |= x_compute_min_glyph_bounds (f);
9287 UNBLOCK_INPUT;
9288 return fontp;
9293 /* Return a pointer to struct font_info of a font named FONTNAME for
9294 frame F. If no such font is loaded, return NULL. */
9296 struct font_info *
9297 x_query_font (f, fontname)
9298 struct frame *f;
9299 register char *fontname;
9301 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9302 int i;
9304 for (i = 0; i < dpyinfo->n_fonts; i++)
9305 if (dpyinfo->font_table[i].name
9306 && (!xstricmp (dpyinfo->font_table[i].name, fontname)
9307 || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
9308 return (dpyinfo->font_table + i);
9309 return NULL;
9313 /* Find a CCL program for a font specified by FONTP, and set the member
9314 `encoder' of the structure. */
9316 void
9317 x_find_ccl_program (fontp)
9318 struct font_info *fontp;
9320 Lisp_Object list, elt;
9322 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9324 elt = XCAR (list);
9325 if (CONSP (elt)
9326 && STRINGP (XCAR (elt))
9327 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9328 >= 0))
9329 break;
9331 if (! NILP (list))
9333 struct ccl_program *ccl
9334 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9336 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9337 xfree (ccl);
9338 else
9339 fontp->font_encoder = ccl;
9343 #if USE_MAC_FONT_PANEL
9344 /* Whether Font Panel has been shown before. The first call to font
9345 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9346 slow. This variable is used for deferring such a call as much as
9347 possible. */
9348 static int font_panel_shown_p = 0;
9350 extern Lisp_Object Qfont;
9351 static Lisp_Object Qpanel_closed, Qselection;
9353 static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9354 Lisp_Object,
9355 Lisp_Object,
9356 EventRef, UInt32,
9357 const EventParamName *,
9358 const EventParamType *));
9361 mac_font_panel_visible_p ()
9363 return font_panel_shown_p && FPIsFontPanelVisible ();
9366 static pascal OSStatus
9367 mac_handle_font_event (next_handler, event, data)
9368 EventHandlerCallRef next_handler;
9369 EventRef event;
9370 void *data;
9372 OSStatus result, err;
9373 Lisp_Object id_key;
9374 int num_params;
9375 const EventParamName *names;
9376 const EventParamType *types;
9377 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9378 kEventParamATSUFontSize,
9379 kEventParamFMFontFamily,
9380 kEventParamFMFontStyle,
9381 kEventParamFMFontSize,
9382 kEventParamFontColor};
9383 static const EventParamType types_sel[] = {typeATSUFontID,
9384 typeATSUSize,
9385 typeFMFontFamily,
9386 typeFMFontStyle,
9387 typeFMFontSize,
9388 typeFontColor};
9390 result = CallNextEventHandler (next_handler, event);
9391 if (result != eventNotHandledErr)
9392 return result;
9394 switch (GetEventKind (event))
9396 case kEventFontPanelClosed:
9397 id_key = Qpanel_closed;
9398 num_params = 0;
9399 names = NULL;
9400 types = NULL;
9401 break;
9403 case kEventFontSelection:
9404 id_key = Qselection;
9405 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9406 names = names_sel;
9407 types = types_sel;
9408 break;
9411 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9412 event, num_params,
9413 names, types);
9414 if (err == noErr)
9415 result = noErr;
9417 return result;
9420 OSStatus
9421 mac_show_hide_font_panel ()
9423 if (!font_panel_shown_p)
9425 OSStatus err;
9427 static const EventTypeSpec specs[] =
9428 {{kEventClassFont, kEventFontPanelClosed},
9429 {kEventClassFont, kEventFontSelection}};
9431 err = InstallApplicationEventHandler (mac_handle_font_event,
9432 GetEventTypeCount (specs),
9433 specs, NULL, NULL);
9434 if (err != noErr)
9435 return err;
9437 font_panel_shown_p = 1;
9440 return FPShowHideFontPanel ();
9443 OSStatus
9444 mac_set_font_info_for_selection (f, face_id, c)
9445 struct frame *f;
9446 int face_id, c;
9448 OSStatus err;
9449 EventTargetRef target = NULL;
9450 XFontStruct *font = NULL;
9452 if (!mac_font_panel_visible_p ())
9453 return noErr;
9455 if (f)
9457 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
9459 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9461 struct face *face;
9463 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9464 face = FACE_FROM_ID (f, face_id);
9465 font = face->font;
9469 if (font == NULL)
9470 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9471 else
9473 if (font->mac_fontnum != -1)
9475 FontSelectionQDStyle qd_style;
9477 qd_style.version = kFontSelectionQDStyleVersionZero;
9478 qd_style.instance.fontFamily = font->mac_fontnum;
9479 qd_style.instance.fontStyle = font->mac_fontface;
9480 qd_style.size = font->mac_fontsize;
9481 qd_style.hasColor = false;
9483 err = SetFontInfoForSelection (kFontSelectionQDType,
9484 1, &qd_style, target);
9486 else
9487 err = SetFontInfoForSelection (kFontSelectionATSUIType,
9488 1, &font->mac_style, target);
9491 return err;
9493 #endif
9496 /* The Mac Event loop code */
9498 #if !TARGET_API_MAC_CARBON
9499 #include <Events.h>
9500 #include <Quickdraw.h>
9501 #include <Balloons.h>
9502 #include <Devices.h>
9503 #include <Fonts.h>
9504 #include <Gestalt.h>
9505 #include <Menus.h>
9506 #include <Processes.h>
9507 #include <Sound.h>
9508 #include <ToolUtils.h>
9509 #include <TextUtils.h>
9510 #include <Dialogs.h>
9511 #include <Script.h>
9512 #include <Types.h>
9513 #include <Resources.h>
9515 #if __MWERKS__
9516 #include <unix.h>
9517 #endif
9518 #endif /* ! TARGET_API_MAC_CARBON */
9520 #define M_APPLE 234
9521 #define I_ABOUT 1
9523 #define DEFAULT_NUM_COLS 80
9525 #define MIN_DOC_SIZE 64
9526 #define MAX_DOC_SIZE 32767
9528 #define EXTRA_STACK_ALLOC (256 * 1024)
9530 #define ARGV_STRING_LIST_ID 129
9531 #define ABOUT_ALERT_ID 128
9532 #define RAM_TOO_LARGE_ALERT_ID 129
9534 /* Contains the string "reverse", which is a constant for mouse button emu.*/
9535 Lisp_Object Qreverse;
9538 /* Modifier associated with the control key, or nil to ignore. */
9539 Lisp_Object Vmac_control_modifier;
9541 /* Modifier associated with the option key, or nil to ignore. */
9542 Lisp_Object Vmac_option_modifier;
9544 /* Modifier associated with the command key, or nil to ignore. */
9545 Lisp_Object Vmac_command_modifier;
9547 /* Modifier associated with the function key, or nil to ignore. */
9548 Lisp_Object Vmac_function_modifier;
9550 /* True if the option and command modifiers should be used to emulate
9551 a three button mouse */
9552 Lisp_Object Vmac_emulate_three_button_mouse;
9554 #if TARGET_API_MAC_CARBON
9555 /* Non-zero if the mouse wheel button (i.e. button 4) should map to
9556 mouse-2, instead of mouse-3. */
9557 int mac_wheel_button_is_mouse_2;
9559 /* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
9560 for processing before Emacs sees it. */
9561 int mac_pass_command_to_system;
9563 /* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
9564 for processing before Emacs sees it. */
9565 int mac_pass_control_to_system;
9566 #endif
9568 /* Points to the variable `inev' in the function XTread_socket. It is
9569 used for passing an input event to the function back from
9570 Carbon/Apple event handlers. */
9571 static struct input_event *read_socket_inev = NULL;
9573 /* Whether or not the screen configuration has changed. */
9574 static int mac_screen_config_changed = 0;
9576 Point saved_menu_event_location;
9578 /* Apple Events */
9579 #if TARGET_API_MAC_CARBON
9580 static Lisp_Object Qhi_command;
9581 #ifdef MAC_OSX
9582 extern Lisp_Object Qwindow;
9583 static Lisp_Object Qtoolbar_switch_mode;
9584 #endif
9585 #if USE_MAC_TSM
9586 static TSMDocumentID tsm_document_id;
9587 static Lisp_Object Qtext_input;
9588 static Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
9589 static Lisp_Object Vmac_ts_active_input_overlay;
9590 extern Lisp_Object Qbefore_string;
9591 static Lisp_Object Vmac_ts_script_language_on_focus;
9592 static Lisp_Object saved_ts_script_language_on_focus;
9593 static ScriptLanguageRecord saved_ts_language;
9594 static Component saved_ts_component;
9595 #endif
9596 #endif /* TARGET_API_MAC_CARBON */
9597 extern int mac_ready_for_apple_events;
9598 extern Lisp_Object Qundefined;
9599 extern void init_apple_event_handler P_ ((void));
9600 extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9601 Lisp_Object *, Lisp_Object *,
9602 Lisp_Object *));
9603 extern OSErr init_coercion_handler P_ ((void));
9605 /* Drag and Drop */
9606 extern OSErr install_drag_handler P_ ((WindowRef));
9607 extern void remove_drag_handler P_ ((WindowRef));
9609 #if TARGET_API_MAC_CARBON
9610 /* Showing help echo string during menu tracking */
9611 extern OSStatus install_menu_target_item_handler P_ ((void));
9613 #ifdef MAC_OSX
9614 extern OSStatus install_service_handler ();
9615 static Lisp_Object Qservice, Qpaste, Qperform;
9616 #endif
9617 #endif
9619 extern void init_emacs_passwd_dir ();
9620 extern int emacs_main (int, char **, char **);
9622 extern void initialize_applescript();
9623 extern void terminate_applescript();
9625 /* Table for translating Mac keycode to X keysym values. Contributed
9626 by Sudhir Shenoy.
9627 Mapping for special keys is now identical to that in Apple X11
9628 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9629 on the right of the Cmd key on laptops, and fn + `enter' (->
9630 <linefeed>). */
9631 static const unsigned char keycode_to_xkeysym_table[] = {
9632 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9633 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9634 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9636 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9637 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9638 /*0x38*/ 0, 0, 0, 0,
9639 /*0x3C*/ 0, 0, 0, 0,
9641 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9642 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9643 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9644 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9646 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9647 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9648 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9649 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9651 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9652 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9653 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9654 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9656 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9657 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9658 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9659 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9662 #ifdef MAC_OSX
9663 /* Table for translating Mac keycode with the laptop `fn' key to that
9664 without it. Destination symbols in comments are keys on US
9665 keyboard, and they may not be the same on other types of keyboards.
9666 If the destination is identical to the source (f1 ... f12), it
9667 doesn't map `fn' key to a modifier. */
9668 static const unsigned char fn_keycode_to_keycode_table[] = {
9669 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9670 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9671 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9673 /*0x30*/ 0, 0, 0, 0,
9674 /*0x34*/ 0, 0, 0, 0,
9675 /*0x38*/ 0, 0, 0, 0,
9676 /*0x3C*/ 0, 0, 0, 0,
9678 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9679 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9680 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9681 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9683 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9684 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9685 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9686 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9688 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9689 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9690 /*0x68*/ 0, 0, 0, 0,
9691 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9693 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9694 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9695 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9696 /*0x7C*/ 0, 0, 0, 0
9698 #endif /* MAC_OSX */
9700 static int
9701 #if TARGET_API_MAC_CARBON
9702 mac_to_emacs_modifiers (UInt32 mods)
9703 #else
9704 mac_to_emacs_modifiers (EventModifiers mods)
9705 #endif
9707 unsigned int result = 0;
9708 if (mods & shiftKey)
9709 result |= shift_modifier;
9711 /* Deactivated to simplify configuration:
9712 if Vmac_option_modifier is non-NIL, we fully process the Option
9713 key. Otherwise, we only process it if an additional Ctrl or Command
9714 is pressed. That way the system may convert the character to a
9715 composed one.
9716 if ((mods & optionKey) &&
9717 (( !NILP(Vmac_option_modifier) ||
9718 ((mods & cmdKey) || (mods & controlKey))))) */
9720 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
9721 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9722 if (INTEGERP(val))
9723 result |= XUINT(val);
9725 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9726 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9727 if (INTEGERP(val))
9728 result |= XUINT(val);
9730 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9731 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9732 if (INTEGERP(val))
9733 result |= XUINT(val);
9736 #ifdef MAC_OSX
9737 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9738 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9739 if (INTEGERP(val))
9740 result |= XUINT(val);
9742 #endif
9744 return result;
9747 static UInt32
9748 mac_mapped_modifiers (modifiers)
9749 UInt32 modifiers;
9751 UInt32 mapped_modifiers_all =
9752 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9753 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9754 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9756 #ifdef MAC_OSX
9757 mapped_modifiers_all |=
9758 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9759 #endif
9761 return mapped_modifiers_all & modifiers;
9764 static int
9765 mac_get_emulated_btn ( UInt32 modifiers )
9767 int result = 0;
9768 if (!NILP (Vmac_emulate_three_button_mouse)) {
9769 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
9770 if (modifiers & cmdKey)
9771 result = cmdIs3 ? 2 : 1;
9772 else if (modifiers & optionKey)
9773 result = cmdIs3 ? 1 : 2;
9775 return result;
9778 #if TARGET_API_MAC_CARBON
9779 /***** Code to handle C-g testing *****/
9780 extern int quit_char;
9781 extern int make_ctrl_char P_ ((int));
9784 mac_quit_char_key_p (modifiers, key_code)
9785 UInt32 modifiers, key_code;
9787 UInt32 char_code;
9788 unsigned long some_state = 0;
9789 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
9790 int c, emacs_modifiers;
9792 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
9793 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
9794 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
9795 if (char_code & ~0xff)
9796 return 0;
9798 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
9799 if (emacs_modifiers & ctrl_modifier)
9800 c = make_ctrl_char (char_code);
9802 c |= (emacs_modifiers
9803 & (meta_modifier | alt_modifier
9804 | hyper_modifier | super_modifier));
9806 return c == quit_char;
9808 #endif
9810 #if TARGET_API_MAC_CARBON
9811 /* Obtains the event modifiers from the event ref and then calls
9812 mac_to_emacs_modifiers. */
9813 static int
9814 mac_event_to_emacs_modifiers (EventRef eventRef)
9816 UInt32 mods = 0, class;
9818 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
9819 sizeof (UInt32), NULL, &mods);
9820 class = GetEventClass (eventRef);
9821 if (!NILP (Vmac_emulate_three_button_mouse) &&
9822 (class == kEventClassMouse || class == kEventClassCommand))
9824 mods &= ~(optionKey | cmdKey);
9826 return mac_to_emacs_modifiers (mods);
9829 /* Given an event ref, return the code to use for the mouse button
9830 code in the emacs input_event. */
9831 static int
9832 mac_get_mouse_btn (EventRef ref)
9834 EventMouseButton result = kEventMouseButtonPrimary;
9835 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
9836 sizeof (EventMouseButton), NULL, &result);
9837 switch (result)
9839 case kEventMouseButtonPrimary:
9840 if (NILP (Vmac_emulate_three_button_mouse))
9841 return 0;
9842 else {
9843 UInt32 mods = 0;
9844 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
9845 sizeof (UInt32), NULL, &mods);
9846 return mac_get_emulated_btn(mods);
9848 case kEventMouseButtonSecondary:
9849 return mac_wheel_button_is_mouse_2 ? 2 : 1;
9850 case kEventMouseButtonTertiary:
9851 case 4: /* 4 is the number for the mouse wheel button */
9852 return mac_wheel_button_is_mouse_2 ? 1 : 2;
9853 default:
9854 return 0;
9858 /* Normally, ConvertEventRefToEventRecord will correctly handle all
9859 events. However the click of the mouse wheel is not converted to a
9860 mouseDown or mouseUp event. Likewise for dead key events. This
9861 calls ConvertEventRefToEventRecord, but then checks to see if it is
9862 a mouse up/down, or a dead key Carbon event that has not been
9863 converted, and if so, converts it by hand (to be picked up in the
9864 XTread_socket loop). */
9865 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
9867 OSStatus err;
9868 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
9869 EventKind action;
9871 if (result)
9872 return result;
9874 switch (GetEventClass (eventRef))
9876 case kEventClassMouse:
9877 switch (GetEventKind (eventRef))
9879 case kEventMouseDown:
9880 eventRec->what = mouseDown;
9881 result = 1;
9882 break;
9884 case kEventMouseUp:
9885 eventRec->what = mouseUp;
9886 result = 1;
9887 break;
9889 default:
9890 break;
9892 break;
9894 case kEventClassKeyboard:
9895 switch (GetEventKind (eventRef))
9897 case kEventRawKeyDown:
9898 action = keyDown;
9899 goto keystroke_common;
9900 case kEventRawKeyRepeat:
9901 action = autoKey;
9902 goto keystroke_common;
9903 case kEventRawKeyUp:
9904 action = keyUp;
9905 keystroke_common:
9907 unsigned char char_codes;
9908 UInt32 key_code;
9910 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
9911 typeChar, NULL, sizeof (char),
9912 NULL, &char_codes);
9913 if (err == noErr)
9914 err = GetEventParameter (eventRef, kEventParamKeyCode,
9915 typeUInt32, NULL, sizeof (UInt32),
9916 NULL, &key_code);
9917 if (err == noErr)
9919 eventRec->what = action;
9920 eventRec->message = char_codes | ((key_code & 0xff) << 8);
9921 result = 1;
9924 break;
9926 default:
9927 break;
9929 break;
9931 default:
9932 break;
9935 if (result)
9937 /* Need where and when. */
9938 UInt32 mods = 0;
9940 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
9941 NULL, sizeof (Point), NULL, &eventRec->where);
9942 /* Use two step process because new event modifiers are 32-bit
9943 and old are 16-bit. Currently, only loss is NumLock & Fn. */
9944 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
9945 NULL, sizeof (UInt32), NULL, &mods);
9946 eventRec->modifiers = mods;
9948 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
9951 return result;
9954 #endif
9956 #ifdef MAC_OS8
9957 static void
9958 do_get_menus (void)
9960 Handle menubar_handle;
9961 MenuRef menu;
9963 menubar_handle = GetNewMBar (128);
9964 if(menubar_handle == NULL)
9965 abort ();
9966 SetMenuBar (menubar_handle);
9967 DrawMenuBar ();
9969 #if !TARGET_API_MAC_CARBON
9970 menu = GetMenuRef (M_APPLE);
9971 if (menu != NULL)
9972 AppendResMenu (menu, 'DRVR');
9973 else
9974 abort ();
9975 #endif
9979 static void
9980 do_init_managers (void)
9982 #if !TARGET_API_MAC_CARBON
9983 InitGraf (&qd.thePort);
9984 InitFonts ();
9985 FlushEvents (everyEvent, 0);
9986 InitWindows ();
9987 InitMenus ();
9988 TEInit ();
9989 InitDialogs (NULL);
9990 #endif /* !TARGET_API_MAC_CARBON */
9991 InitCursor ();
9993 #if !TARGET_API_MAC_CARBON
9994 /* set up some extra stack space for use by emacs */
9995 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
9997 /* MaxApplZone must be called for AppleScript to execute more
9998 complicated scripts */
9999 MaxApplZone ();
10000 MoreMasters ();
10001 #endif /* !TARGET_API_MAC_CARBON */
10004 static void
10005 do_check_ram_size (void)
10007 SInt32 physical_ram_size, logical_ram_size;
10009 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10010 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
10011 || physical_ram_size > (1 << VALBITS)
10012 || logical_ram_size > (1 << VALBITS))
10014 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10015 exit (1);
10018 #endif /* MAC_OS8 */
10020 static void
10021 do_window_update (WindowRef win)
10023 struct frame *f = mac_window_to_frame (win);
10025 BeginUpdate (win);
10027 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10028 below. */
10029 if (win != tip_window)
10031 if (f->async_visible == 0)
10033 /* Update events may occur when a frame gets iconified. */
10034 #if 0
10035 f->async_visible = 1;
10036 f->async_iconified = 0;
10037 SET_FRAME_GARBAGED (f);
10038 #endif
10040 else
10042 Rect r;
10043 #if TARGET_API_MAC_CARBON
10044 RgnHandle region = NewRgn ();
10046 GetPortVisibleRegion (GetWindowPort (win), region);
10047 GetRegionBounds (region, &r);
10048 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10049 #if USE_CG_DRAWING
10050 mac_prepare_for_quickdraw (f);
10051 #endif
10052 UpdateControls (win, region);
10053 DisposeRgn (region);
10054 #else
10055 r = (*win->visRgn)->rgnBBox;
10056 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10057 UpdateControls (win, win->visRgn);
10058 #endif
10062 EndUpdate (win);
10065 static int
10066 is_emacs_window (WindowRef win)
10068 Lisp_Object tail, frame;
10070 if (!win)
10071 return 0;
10073 FOR_EACH_FRAME (tail, frame)
10074 if (FRAME_MAC_P (XFRAME (frame)))
10075 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10076 return 1;
10078 return 0;
10081 #if USE_MAC_TSM
10082 static OSStatus
10083 mac_tsm_resume ()
10085 OSStatus err;
10086 ScriptLanguageRecord slrec, *slptr = NULL;
10088 err = ActivateTSMDocument (tsm_document_id);
10090 if (err == noErr)
10092 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10093 && EQ (saved_ts_script_language_on_focus, Qt))
10094 slptr = &saved_ts_language;
10095 else if (CONSP (Vmac_ts_script_language_on_focus)
10096 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10097 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10098 && CONSP (saved_ts_script_language_on_focus)
10099 && EQ (XCAR (saved_ts_script_language_on_focus),
10100 XCAR (Vmac_ts_script_language_on_focus))
10101 && EQ (XCDR (saved_ts_script_language_on_focus),
10102 XCDR (Vmac_ts_script_language_on_focus)))
10104 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10105 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10106 slptr = &slrec;
10110 if (slptr)
10112 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10113 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10114 kKeyboardInputMethodClass);
10115 #else
10116 err = SetDefaultInputMethod (saved_ts_component, slptr);
10117 #endif
10118 if (err == noErr)
10119 err = SetTextServiceLanguage (slptr);
10121 /* Seems to be needed on Mac OS X 10.2. */
10122 if (err == noErr)
10123 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10126 return err;
10129 static OSStatus
10130 mac_tsm_suspend ()
10132 OSStatus err;
10133 ScriptLanguageRecord slrec, *slptr = NULL;
10135 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10137 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10139 err = GetTextServiceLanguage (&saved_ts_language);
10140 if (err == noErr)
10141 slptr = &saved_ts_language;
10143 else if (CONSP (Vmac_ts_script_language_on_focus)
10144 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10145 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10147 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10148 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10149 slptr = &slrec;
10152 if (slptr)
10154 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10155 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10156 kKeyboardInputMethodClass);
10157 #else
10158 GetDefaultInputMethod (&saved_ts_component, slptr);
10159 #endif
10162 err = DeactivateTSMDocument (tsm_document_id);
10164 return err;
10166 #endif
10168 #if !TARGET_API_MAC_CARBON
10169 void
10170 do_apple_menu (SInt16 menu_item)
10172 Str255 item_name;
10173 SInt16 da_driver_refnum;
10175 if (menu_item == I_ABOUT)
10176 NoteAlert (ABOUT_ALERT_ID, NULL);
10177 else
10179 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
10180 da_driver_refnum = OpenDeskAcc (item_name);
10183 #endif /* !TARGET_API_MAC_CARBON */
10185 /* Handle drags in size box. Based on code contributed by Ben
10186 Mesander and IM - Window Manager A. */
10188 static void
10189 do_grow_window (w, e)
10190 WindowRef w;
10191 const EventRecord *e;
10193 Rect limit_rect;
10194 int rows, columns, width, height;
10195 struct frame *f = mac_window_to_frame (w);
10196 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10197 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10198 #if TARGET_API_MAC_CARBON
10199 Rect new_rect;
10200 #else
10201 long grow_size;
10202 #endif
10204 if (size_hints->flags & PMinSize)
10206 min_width = size_hints->min_width;
10207 min_height = size_hints->min_height;
10209 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
10211 #if TARGET_API_MAC_CARBON
10212 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10213 return;
10214 height = new_rect.bottom - new_rect.top;
10215 width = new_rect.right - new_rect.left;
10216 #else
10217 grow_size = GrowWindow (w, e->where, &limit_rect);
10218 /* see if it really changed size */
10219 if (grow_size == 0)
10220 return;
10221 height = HiWord (grow_size);
10222 width = LoWord (grow_size);
10223 #endif
10225 if (width != FRAME_PIXEL_WIDTH (f)
10226 || height != FRAME_PIXEL_HEIGHT (f))
10228 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10229 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10231 x_set_window_size (f, 0, columns, rows);
10236 #if TARGET_API_MAC_CARBON
10237 static Point
10238 mac_get_ideal_size (f)
10239 struct frame *f;
10241 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10242 WindowRef w = FRAME_MAC_WINDOW (f);
10243 Point ideal_size;
10244 Rect standard_rect;
10245 int height, width, columns, rows;
10247 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10248 ideal_size.v = dpyinfo->height;
10249 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10250 /* Adjust the standard size according to character boundaries. */
10251 width = standard_rect.right - standard_rect.left;
10252 height = standard_rect.bottom - standard_rect.top;
10253 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10254 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10255 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10256 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10258 return ideal_size;
10260 #endif
10262 /* Handle clicks in zoom box. Calculation of "standard state" based
10263 on code in IM - Window Manager A and code contributed by Ben
10264 Mesander. The standard state of an Emacs window is 80-characters
10265 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10267 static void
10268 do_zoom_window (WindowRef w, int zoom_in_or_out)
10270 Rect zoom_rect, port_rect;
10271 int width, height;
10272 struct frame *f = mac_window_to_frame (w);
10273 #if TARGET_API_MAC_CARBON
10274 Point ideal_size = mac_get_ideal_size (f);
10276 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10277 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10278 && port_rect.left == zoom_rect.left
10279 && port_rect.top == zoom_rect.top)
10280 zoom_in_or_out = inZoomIn;
10281 else
10282 zoom_in_or_out = inZoomOut;
10284 #ifdef MAC_OS8
10285 mac_clear_window (f);
10286 #endif
10287 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
10288 #else /* not TARGET_API_MAC_CARBON */
10289 GrafPtr save_port;
10290 Point top_left;
10291 int w_title_height, rows;
10292 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10294 GetPort (&save_port);
10296 SetPortWindowPort (w);
10298 /* Clear window to avoid flicker. */
10299 EraseRect (&(w->portRect));
10300 if (zoom_in_or_out == inZoomOut)
10302 SetPt (&top_left, w->portRect.left, w->portRect.top);
10303 LocalToGlobal (&top_left);
10305 /* calculate height of window's title bar */
10306 w_title_height = top_left.v - 1
10307 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
10309 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10310 zoom_rect = qd.screenBits.bounds;
10311 zoom_rect.top += w_title_height;
10312 InsetRect (&zoom_rect, 8, 4); /* not too tight */
10314 zoom_rect.right = zoom_rect.left
10315 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10317 /* Adjust the standard size according to character boundaries. */
10318 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10319 zoom_rect.bottom =
10320 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10322 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10323 = zoom_rect;
10326 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
10328 SetPort (save_port);
10329 #endif /* not TARGET_API_MAC_CARBON */
10331 #if !TARGET_API_MAC_CARBON
10332 /* retrieve window size and update application values */
10333 port_rect = w->portRect;
10334 height = port_rect.bottom - port_rect.top;
10335 width = port_rect.right - port_rect.left;
10337 mac_handle_size_change (f, width, height);
10338 mac_handle_origin_change (f);
10339 #endif
10342 static void
10343 mac_set_unicode_keystroke_event (code, buf)
10344 UniChar code;
10345 struct input_event *buf;
10347 int charset_id, c1, c2;
10349 if (code < 0x80)
10351 buf->kind = ASCII_KEYSTROKE_EVENT;
10352 buf->code = code;
10354 else if (code < 0x100)
10356 if (code < 0xA0)
10357 charset_id = CHARSET_8_BIT_CONTROL;
10358 else
10359 charset_id = charset_latin_iso8859_1;
10360 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10361 buf->code = MAKE_CHAR (charset_id, code, 0);
10363 else
10365 if (code < 0x2500)
10366 charset_id = charset_mule_unicode_0100_24ff,
10367 code -= 0x100;
10368 else if (code < 0x33FF)
10369 charset_id = charset_mule_unicode_2500_33ff,
10370 code -= 0x2500;
10371 else if (code >= 0xE000)
10372 charset_id = charset_mule_unicode_e000_ffff,
10373 code -= 0xE000;
10374 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10375 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10376 buf->code = MAKE_CHAR (charset_id, c1, c2);
10380 static void
10381 do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10382 EventKind action;
10383 unsigned char char_code;
10384 UInt32 key_code, modifiers;
10385 unsigned long timestamp;
10386 struct input_event *buf;
10388 static SInt16 last_key_script = -1;
10389 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10390 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10392 #ifdef MAC_OSX
10393 if (mapped_modifiers & kEventKeyModifierFnMask
10394 && key_code <= 0x7f
10395 && fn_keycode_to_keycode_table[key_code])
10396 key_code = fn_keycode_to_keycode_table[key_code];
10397 #endif
10399 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10401 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10402 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10403 #ifdef MAC_OSX
10404 if (modifiers & kEventKeyModifierFnMask
10405 && key_code <= 0x7f
10406 && fn_keycode_to_keycode_table[key_code] == key_code)
10407 modifiers &= ~kEventKeyModifierFnMask;
10408 #endif
10410 else if (mapped_modifiers)
10412 /* translate the keycode back to determine the original key */
10413 #ifdef MAC_OSX
10414 UCKeyboardLayout *uchr_ptr = NULL;
10415 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10416 OSStatus err;
10417 KeyboardLayoutRef layout;
10419 err = KLGetCurrentKeyboardLayout (&layout);
10420 if (err == noErr)
10421 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10422 (const void **) &uchr_ptr);
10423 #else
10424 static SInt16 last_key_layout_id = 0;
10425 static Handle uchr_handle = (Handle)-1;
10426 SInt16 current_key_layout_id =
10427 GetScriptVariable (current_key_script, smScriptKeys);
10429 if (uchr_handle == (Handle)-1
10430 || last_key_layout_id != current_key_layout_id)
10432 uchr_handle = GetResource ('uchr', current_key_layout_id);
10433 last_key_layout_id = current_key_layout_id;
10435 if (uchr_handle)
10436 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10437 #endif
10439 if (uchr_ptr)
10441 OSStatus status;
10442 UInt16 key_action = action - keyDown;
10443 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10444 UInt32 keyboard_type = LMGetKbdType ();
10445 SInt32 dead_key_state = 0;
10446 UniChar code;
10447 UniCharCount actual_length;
10449 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10450 modifier_key_state, keyboard_type,
10451 kUCKeyTranslateNoDeadKeysMask,
10452 &dead_key_state,
10453 1, &actual_length, &code);
10454 if (status == noErr && actual_length == 1)
10455 mac_set_unicode_keystroke_event (code, buf);
10457 #endif /* MAC_OSX */
10459 if (buf->kind == NO_EVENT)
10461 /* This code comes from Keyboard Resource, Appendix C of IM
10462 - Text. This is necessary since shift is ignored in KCHR
10463 table translation when option or command is pressed. It
10464 also does not translate correctly control-shift chars
10465 like C-% so mask off shift here also. */
10466 /* Mask off modifier keys that are mapped to some Emacs
10467 modifiers. */
10468 int new_modifiers = modifiers & ~mapped_modifiers;
10469 /* set high byte of keycode to modifier high byte*/
10470 int new_key_code = key_code | new_modifiers;
10471 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10472 unsigned long some_state = 0;
10473 UInt32 new_char_code;
10475 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10476 if (new_char_code == 0)
10477 /* Seems like a dead key. Append up-stroke. */
10478 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10479 &some_state);
10480 if (new_char_code)
10482 buf->kind = ASCII_KEYSTROKE_EVENT;
10483 buf->code = new_char_code & 0xff;
10488 if (buf->kind == NO_EVENT)
10490 buf->kind = ASCII_KEYSTROKE_EVENT;
10491 buf->code = char_code;
10494 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10495 buf->modifiers |= (extra_keyboard_modifiers
10496 & (meta_modifier | alt_modifier
10497 | hyper_modifier | super_modifier));
10499 #if TARGET_API_MAC_CARBON
10500 if (buf->kind == ASCII_KEYSTROKE_EVENT
10501 && buf->code >= 0x80 && buf->modifiers)
10503 OSStatus err;
10504 TextEncoding encoding = kTextEncodingMacRoman;
10505 TextToUnicodeInfo ttu_info;
10507 UpgradeScriptInfoToTextEncoding (current_key_script,
10508 kTextLanguageDontCare,
10509 kTextRegionDontCare,
10510 NULL, &encoding);
10511 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10512 if (err == noErr)
10514 UniChar code;
10515 Str255 pstr;
10516 ByteCount unicode_len;
10518 pstr[0] = 1;
10519 pstr[1] = buf->code;
10520 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10521 sizeof (UniChar),
10522 &unicode_len, &code);
10523 if (err == noErr && unicode_len == sizeof (UniChar))
10524 mac_set_unicode_keystroke_event (code, buf);
10525 DisposeTextToUnicodeInfo (&ttu_info);
10528 #endif
10530 if (buf->kind == ASCII_KEYSTROKE_EVENT
10531 && buf->code >= 0x80
10532 && last_key_script != current_key_script)
10534 struct input_event event;
10536 EVENT_INIT (event);
10537 event.kind = LANGUAGE_CHANGE_EVENT;
10538 event.arg = Qnil;
10539 event.code = current_key_script;
10540 event.timestamp = timestamp;
10541 kbd_buffer_store_event (&event);
10542 last_key_script = current_key_script;
10546 void
10547 mac_store_apple_event (class, id, desc)
10548 Lisp_Object class, id;
10549 const AEDesc *desc;
10551 struct input_event buf;
10553 EVENT_INIT (buf);
10555 buf.kind = MAC_APPLE_EVENT;
10556 buf.x = class;
10557 buf.y = id;
10558 XSETFRAME (buf.frame_or_window,
10559 mac_focus_frame (&one_mac_display_info));
10560 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10561 is safe to use them during read_socket_hook. */
10562 buf.arg = mac_aedesc_to_lisp (desc);
10563 kbd_buffer_store_event (&buf);
10566 #if TARGET_API_MAC_CARBON
10567 static OSStatus
10568 mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10569 event, num_params, names, types)
10570 AEEventClass class;
10571 AEEventID id;
10572 Lisp_Object class_key, id_key;
10573 EventRef event;
10574 UInt32 num_params;
10575 const EventParamName *names;
10576 const EventParamType *types;
10578 OSStatus err = eventNotHandledErr;
10579 Lisp_Object binding;
10581 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10582 if (!NILP (binding) && !EQ (binding, Qundefined))
10584 if (INTEGERP (binding))
10585 err = XINT (binding);
10586 else
10588 AppleEvent apple_event;
10589 err = create_apple_event_from_event_ref (event, num_params,
10590 names, types,
10591 &apple_event);
10592 if (err == noErr)
10594 mac_store_apple_event (class_key, id_key, &apple_event);
10595 AEDisposeDesc (&apple_event);
10596 mac_wakeup_from_rne ();
10601 return err;
10604 void
10605 mac_store_drag_event (window, mouse_pos, modifiers, desc)
10606 WindowRef window;
10607 Point mouse_pos;
10608 SInt16 modifiers;
10609 const AEDesc *desc;
10611 struct input_event buf;
10613 EVENT_INIT (buf);
10615 buf.kind = DRAG_N_DROP_EVENT;
10616 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10617 buf.timestamp = TickCount () * (1000 / 60);
10618 XSETINT (buf.x, mouse_pos.h);
10619 XSETINT (buf.y, mouse_pos.v);
10620 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10621 buf.arg = mac_aedesc_to_lisp (desc);
10622 kbd_buffer_store_event (&buf);
10625 #ifdef MAC_OSX
10626 OSStatus
10627 mac_store_service_event (event)
10628 EventRef event;
10630 OSStatus err;
10631 Lisp_Object id_key;
10632 int num_params;
10633 const EventParamName *names;
10634 const EventParamType *types;
10635 static const EventParamName names_pfm[] =
10636 {kEventParamServiceMessageName, kEventParamServiceUserData};
10637 static const EventParamType types_pfm[] =
10638 {typeCFStringRef, typeCFStringRef};
10640 switch (GetEventKind (event))
10642 case kEventServicePaste:
10643 id_key = Qpaste;
10644 num_params = 0;
10645 names = NULL;
10646 types = NULL;
10647 break;
10649 case kEventServicePerform:
10650 id_key = Qperform;
10651 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
10652 names = names_pfm;
10653 types = types_pfm;
10654 break;
10656 default:
10657 abort ();
10660 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
10661 event, num_params,
10662 names, types);
10664 return err;
10666 #endif /* MAC_OSX */
10668 static pascal OSStatus
10669 mac_handle_window_event (next_handler, event, data)
10670 EventHandlerCallRef next_handler;
10671 EventRef event;
10672 void *data;
10674 WindowRef wp;
10675 OSStatus err, result = eventNotHandledErr;
10676 struct frame *f;
10677 UInt32 attributes;
10678 XSizeHints *size_hints;
10680 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
10681 NULL, sizeof (WindowRef), NULL, &wp);
10682 if (err != noErr)
10683 return eventNotHandledErr;
10685 f = mac_window_to_frame (wp);
10686 switch (GetEventKind (event))
10688 /* -- window refresh events -- */
10690 case kEventWindowUpdate:
10691 result = CallNextEventHandler (next_handler, event);
10692 if (result != eventNotHandledErr)
10693 break;
10695 do_window_update (wp);
10696 result = noErr;
10697 break;
10699 /* -- window state change events -- */
10701 case kEventWindowShowing:
10702 size_hints = FRAME_SIZE_HINTS (f);
10703 if (!(size_hints->flags & (USPosition | PPosition)))
10705 struct frame *sf = SELECTED_FRAME ();
10707 if (!(FRAME_MAC_P (sf) && sf->async_visible))
10708 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
10709 else
10711 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
10712 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10713 kWindowCascadeStartAtParentWindowScreen
10714 #else
10715 kWindowCascadeOnParentWindowScreen
10716 #endif
10718 #if USE_MAC_TOOLBAR
10719 /* This is a workaround. RepositionWindow fails to put
10720 a window at the cascading position when its parent
10721 window has a Carbon HIToolbar. */
10722 if ((f->left_pos == sf->left_pos
10723 && f->top_pos == sf->top_pos)
10724 || (f->left_pos == sf->left_pos + 10 * 2
10725 && f->top_pos == sf->top_pos + 32 * 2))
10726 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
10727 #endif
10729 result = noErr;
10731 break;
10733 case kEventWindowHiding:
10734 /* Before unmapping the window, update the WM_SIZE_HINTS
10735 property to claim that the current position of the window is
10736 user-specified, rather than program-specified, so that when
10737 the window is mapped again, it will be placed at the same
10738 location, without forcing the user to position it by hand
10739 again (they have already done that once for this window.) */
10740 x_wm_set_size_hint (f, (long) 0, 1);
10741 result = noErr;
10742 break;
10744 case kEventWindowShown:
10745 case kEventWindowHidden:
10746 case kEventWindowCollapsed:
10747 case kEventWindowExpanded:
10748 mac_handle_visibility_change (f);
10749 result = noErr;
10750 break;
10752 case kEventWindowBoundsChanging:
10753 result = CallNextEventHandler (next_handler, event);
10754 if (result != eventNotHandledErr)
10755 break;
10757 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
10758 NULL, sizeof (UInt32), NULL, &attributes);
10759 if (err != noErr)
10760 break;
10762 size_hints = FRAME_SIZE_HINTS (f);
10763 if ((attributes & kWindowBoundsChangeUserResize)
10764 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
10765 == (PResizeInc | PBaseSize | PMinSize)))
10767 Rect bounds;
10768 int width, height;
10770 err = GetEventParameter (event, kEventParamCurrentBounds,
10771 typeQDRectangle, NULL, sizeof (Rect),
10772 NULL, &bounds);
10773 if (err != noErr)
10774 break;
10776 width = bounds.right - bounds.left;
10777 height = bounds.bottom - bounds.top;
10779 if (width < size_hints->min_width)
10780 width = size_hints->min_width;
10781 else
10782 width = size_hints->base_width
10783 + (int) ((width - size_hints->base_width)
10784 / (float) size_hints->width_inc + .5)
10785 * size_hints->width_inc;
10787 if (height < size_hints->min_height)
10788 height = size_hints->min_height;
10789 else
10790 height = size_hints->base_height
10791 + (int) ((height - size_hints->base_height)
10792 / (float) size_hints->height_inc + .5)
10793 * size_hints->height_inc;
10795 bounds.right = bounds.left + width;
10796 bounds.bottom = bounds.top + height;
10797 SetEventParameter (event, kEventParamCurrentBounds,
10798 typeQDRectangle, sizeof (Rect), &bounds);
10799 result = noErr;
10801 break;
10803 case kEventWindowBoundsChanged:
10804 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
10805 NULL, sizeof (UInt32), NULL, &attributes);
10806 if (err != noErr)
10807 break;
10809 if (attributes & kWindowBoundsChangeSizeChanged)
10811 Rect bounds;
10813 err = GetEventParameter (event, kEventParamCurrentBounds,
10814 typeQDRectangle, NULL, sizeof (Rect),
10815 NULL, &bounds);
10816 if (err == noErr)
10818 int width, height;
10820 width = bounds.right - bounds.left;
10821 height = bounds.bottom - bounds.top;
10822 mac_handle_size_change (f, width, height);
10823 mac_wakeup_from_rne ();
10827 if (attributes & kWindowBoundsChangeOriginChanged)
10828 mac_handle_origin_change (f);
10830 result = noErr;
10831 break;
10833 /* -- window action events -- */
10835 case kEventWindowClose:
10837 struct input_event buf;
10839 EVENT_INIT (buf);
10840 buf.kind = DELETE_WINDOW_EVENT;
10841 XSETFRAME (buf.frame_or_window, f);
10842 buf.arg = Qnil;
10843 kbd_buffer_store_event (&buf);
10845 result = noErr;
10846 break;
10848 case kEventWindowGetIdealSize:
10849 result = CallNextEventHandler (next_handler, event);
10850 if (result != eventNotHandledErr)
10851 break;
10854 Point ideal_size = mac_get_ideal_size (f);
10856 err = SetEventParameter (event, kEventParamDimensions,
10857 typeQDPoint, sizeof (Point), &ideal_size);
10858 if (err == noErr)
10859 result = noErr;
10861 break;
10863 #ifdef MAC_OSX
10864 case kEventWindowToolbarSwitchMode:
10866 static const EventParamName names[] = {kEventParamDirectObject,
10867 kEventParamWindowMouseLocation,
10868 kEventParamKeyModifiers,
10869 kEventParamMouseButton,
10870 kEventParamClickCount,
10871 kEventParamMouseChord};
10872 static const EventParamType types[] = {typeWindowRef,
10873 typeQDPoint,
10874 typeUInt32,
10875 typeMouseButton,
10876 typeUInt32,
10877 typeUInt32};
10878 int num_params = sizeof (names) / sizeof (names[0]);
10880 err = mac_store_event_ref_as_apple_event (0, 0,
10881 Qwindow,
10882 Qtoolbar_switch_mode,
10883 event, num_params,
10884 names, types);
10886 if (err == noErr)
10887 result = noErr;
10888 break;
10889 #endif
10891 #if USE_MAC_TSM
10892 /* -- window focus events -- */
10894 case kEventWindowFocusAcquired:
10895 err = mac_tsm_resume ();
10896 if (err == noErr)
10897 result = noErr;
10898 break;
10900 case kEventWindowFocusRelinquish:
10901 err = mac_tsm_suspend ();
10902 if (err == noErr)
10903 result = noErr;
10904 break;
10905 #endif
10907 default:
10908 abort ();
10911 return result;
10914 static pascal OSStatus
10915 mac_handle_application_event (next_handler, event, data)
10916 EventHandlerCallRef next_handler;
10917 EventRef event;
10918 void *data;
10920 OSStatus err, result = eventNotHandledErr;
10922 switch (GetEventKind (event))
10924 #if USE_MAC_TSM
10925 case kEventAppActivated:
10926 err = mac_tsm_resume ();
10927 break;
10929 case kEventAppDeactivated:
10930 err = mac_tsm_suspend ();
10931 break;
10932 #endif
10934 default:
10935 abort ();
10938 if (err == noErr)
10939 result = noErr;
10941 return result;
10944 static pascal OSStatus
10945 mac_handle_keyboard_event (next_handler, event, data)
10946 EventHandlerCallRef next_handler;
10947 EventRef event;
10948 void *data;
10950 OSStatus err, result = eventNotHandledErr;
10951 UInt32 event_kind, key_code, modifiers;
10952 unsigned char char_code;
10954 event_kind = GetEventKind (event);
10955 switch (event_kind)
10957 case kEventRawKeyDown:
10958 case kEventRawKeyRepeat:
10959 case kEventRawKeyUp:
10960 /* When using Carbon Events, we need to pass raw keyboard events
10961 to the TSM ourselves. If TSM handles it, it will pass back
10962 noErr, otherwise it will pass back "eventNotHandledErr" and
10963 we can process it normally. */
10964 result = CallNextEventHandler (next_handler, event);
10965 if (result != eventNotHandledErr)
10966 break;
10968 if (read_socket_inev == NULL)
10969 break;
10971 #if USE_MAC_TSM
10972 if (read_socket_inev->kind != NO_EVENT)
10974 result = noErr;
10975 break;
10977 #endif
10979 if (event_kind == kEventRawKeyUp)
10980 break;
10982 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
10983 typeChar, NULL,
10984 sizeof (char), NULL, &char_code);
10985 if (err != noErr)
10986 break;
10988 err = GetEventParameter (event, kEventParamKeyCode,
10989 typeUInt32, NULL,
10990 sizeof (UInt32), NULL, &key_code);
10991 if (err != noErr)
10992 break;
10994 err = GetEventParameter (event, kEventParamKeyModifiers,
10995 typeUInt32, NULL,
10996 sizeof (UInt32), NULL, &modifiers);
10997 if (err != noErr)
10998 break;
11000 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
11001 char_code, key_code, modifiers,
11002 ((unsigned long)
11003 (GetEventTime (event) / kEventDurationMillisecond)),
11004 read_socket_inev);
11005 result = noErr;
11006 break;
11008 default:
11009 abort ();
11012 return result;
11015 static pascal OSStatus
11016 mac_handle_command_event (next_handler, event, data)
11017 EventHandlerCallRef next_handler;
11018 EventRef event;
11019 void *data;
11021 OSStatus err, result = eventNotHandledErr;
11022 HICommand command;
11023 static const EventParamName names[] =
11024 {kEventParamDirectObject, kEventParamKeyModifiers};
11025 static const EventParamType types[] =
11026 {typeHICommand, typeUInt32};
11027 int num_params = sizeof (names) / sizeof (names[0]);
11029 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11030 NULL, sizeof (HICommand), NULL, &command);
11031 if (err != noErr)
11032 return eventNotHandledErr;
11034 switch (GetEventKind (event))
11036 case kEventCommandProcess:
11037 result = CallNextEventHandler (next_handler, event);
11038 if (result != eventNotHandledErr)
11039 break;
11041 err = GetEventParameter (event, kEventParamDirectObject,
11042 typeHICommand, NULL,
11043 sizeof (HICommand), NULL, &command);
11045 if (err != noErr || command.commandID == 0)
11046 break;
11048 /* A HI command event is mapped to an Apple event whose event
11049 class symbol is `hi-command' and event ID is its command
11050 ID. */
11051 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11052 Qhi_command, Qnil,
11053 event, num_params,
11054 names, types);
11055 if (err == noErr)
11056 result = noErr;
11057 break;
11059 default:
11060 abort ();
11063 return result;
11066 static pascal OSStatus
11067 mac_handle_mouse_event (next_handler, event, data)
11068 EventHandlerCallRef next_handler;
11069 EventRef event;
11070 void *data;
11072 OSStatus err, result = eventNotHandledErr;
11074 switch (GetEventKind (event))
11076 case kEventMouseWheelMoved:
11078 WindowRef wp;
11079 struct frame *f;
11080 EventMouseWheelAxis axis;
11081 SInt32 delta;
11082 Point point;
11084 result = CallNextEventHandler (next_handler, event);
11085 if (result != eventNotHandledErr || read_socket_inev == NULL)
11086 break;
11088 f = mac_focus_frame (&one_mac_display_info);
11090 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11091 NULL, sizeof (WindowRef), NULL, &wp);
11092 if (err != noErr
11093 || wp != FRAME_MAC_WINDOW (f))
11094 break;
11096 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11097 typeMouseWheelAxis, NULL,
11098 sizeof (EventMouseWheelAxis), NULL, &axis);
11099 if (err != noErr || axis != kEventMouseWheelAxisY)
11100 break;
11102 err = GetEventParameter (event, kEventParamMouseLocation,
11103 typeQDPoint, NULL, sizeof (Point),
11104 NULL, &point);
11105 if (err != noErr)
11106 break;
11108 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11109 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
11110 if (point.h < 0 || point.v < 0
11111 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11112 f->tool_bar_window))
11113 break;
11115 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11116 typeSInt32, NULL, sizeof (SInt32),
11117 NULL, &delta);
11118 if (err != noErr)
11119 break;
11121 read_socket_inev->kind = WHEEL_EVENT;
11122 read_socket_inev->code = 0;
11123 read_socket_inev->modifiers =
11124 (mac_event_to_emacs_modifiers (event)
11125 | ((delta < 0) ? down_modifier : up_modifier));
11126 XSETINT (read_socket_inev->x, point.h);
11127 XSETINT (read_socket_inev->y, point.v);
11128 XSETFRAME (read_socket_inev->frame_or_window, f);
11130 result = noErr;
11132 break;
11134 default:
11135 abort ();
11138 return result;
11141 #if USE_MAC_TSM
11142 static pascal OSStatus
11143 mac_handle_text_input_event (next_handler, event, data)
11144 EventHandlerCallRef next_handler;
11145 EventRef event;
11146 void *data;
11148 OSStatus err, result;
11149 Lisp_Object id_key = Qnil;
11150 int num_params;
11151 const EventParamName *names;
11152 const EventParamType *types;
11153 static UInt32 seqno_uaia = 0;
11154 static const EventParamName names_uaia[] =
11155 {kEventParamTextInputSendComponentInstance,
11156 kEventParamTextInputSendRefCon,
11157 kEventParamTextInputSendSLRec,
11158 kEventParamTextInputSendFixLen,
11159 kEventParamTextInputSendText,
11160 kEventParamTextInputSendUpdateRng,
11161 kEventParamTextInputSendHiliteRng,
11162 kEventParamTextInputSendClauseRng,
11163 kEventParamTextInputSendPinRng,
11164 kEventParamTextInputSendTextServiceEncoding,
11165 kEventParamTextInputSendTextServiceMacEncoding,
11166 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
11167 static const EventParamType types_uaia[] =
11168 {typeComponentInstance,
11169 typeLongInteger,
11170 typeIntlWritingCode,
11171 typeLongInteger,
11172 #ifdef MAC_OSX
11173 typeUnicodeText,
11174 #else
11175 typeChar,
11176 #endif
11177 typeTextRangeArray,
11178 typeTextRangeArray,
11179 typeOffsetArray,
11180 typeTextRange,
11181 typeUInt32,
11182 typeUInt32,
11183 typeUInt32};
11184 static const EventParamName names_ufke[] =
11185 {kEventParamTextInputSendComponentInstance,
11186 kEventParamTextInputSendRefCon,
11187 kEventParamTextInputSendSLRec,
11188 kEventParamTextInputSendText};
11189 static const EventParamType types_ufke[] =
11190 {typeComponentInstance,
11191 typeLongInteger,
11192 typeIntlWritingCode,
11193 typeUnicodeText};
11195 result = CallNextEventHandler (next_handler, event);
11196 if (result != eventNotHandledErr)
11197 return result;
11199 switch (GetEventKind (event))
11201 case kEventTextInputUpdateActiveInputArea:
11202 id_key = Qupdate_active_input_area;
11203 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11204 names = names_uaia;
11205 types = types_uaia;
11206 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11207 typeUInt32, sizeof (UInt32), &seqno_uaia);
11208 seqno_uaia++;
11209 result = noErr;
11210 break;
11212 case kEventTextInputUnicodeForKeyEvent:
11214 EventRef kbd_event;
11215 UInt32 actual_size, modifiers;
11217 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11218 typeEventRef, NULL, sizeof (EventRef), NULL,
11219 &kbd_event);
11220 if (err == noErr)
11221 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11222 typeUInt32, NULL,
11223 sizeof (UInt32), NULL, &modifiers);
11224 if (err == noErr && mac_mapped_modifiers (modifiers))
11225 /* There're mapped modifier keys. Process it in
11226 do_keystroke. */
11227 break;
11228 if (err == noErr)
11229 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11230 typeUnicodeText, NULL, 0, &actual_size,
11231 NULL);
11232 if (err == noErr && actual_size == sizeof (UniChar))
11234 UniChar code;
11236 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11237 typeUnicodeText, NULL,
11238 sizeof (UniChar), NULL, &code);
11239 if (err == noErr && code < 0x80)
11241 /* ASCII character. Process it in do_keystroke. */
11242 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
11244 UInt32 key_code;
11246 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11247 typeUInt32, NULL, sizeof (UInt32),
11248 NULL, &key_code);
11249 if (!(err == noErr && key_code <= 0x7f
11250 && keycode_to_xkeysym_table [key_code]))
11252 struct frame *f =
11253 mac_focus_frame (&one_mac_display_info);
11255 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11256 read_socket_inev->code = code;
11257 read_socket_inev->modifiers =
11258 mac_to_emacs_modifiers (modifiers);
11259 read_socket_inev->modifiers |=
11260 (extra_keyboard_modifiers
11261 & (meta_modifier | alt_modifier
11262 | hyper_modifier | super_modifier));
11263 XSETFRAME (read_socket_inev->frame_or_window, f);
11266 break;
11269 if (err == noErr)
11271 /* Non-ASCII keystrokes without mapped modifiers are
11272 processed at the Lisp level. */
11273 id_key = Qunicode_for_key_event;
11274 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11275 names = names_ufke;
11276 types = types_ufke;
11277 result = noErr;
11280 break;
11282 case kEventTextInputOffsetToPos:
11284 struct frame *f;
11285 struct window *w;
11286 Point p;
11288 if (!OVERLAYP (Vmac_ts_active_input_overlay))
11289 break;
11291 /* Strictly speaking, this is not always correct because
11292 previous events may change some states about display. */
11293 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11295 /* Active input area is displayed around the current point. */
11296 f = SELECTED_FRAME ();
11297 w = XWINDOW (f->selected_window);
11299 else if (WINDOWP (echo_area_window))
11301 /* Active input area is displayed in the echo area. */
11302 w = XWINDOW (echo_area_window);
11303 f = WINDOW_XFRAME (w);
11305 else
11306 break;
11308 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
11309 + WINDOW_LEFT_FRINGE_WIDTH (w)
11310 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
11311 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
11312 + FONT_BASE (FRAME_FONT (f))
11313 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
11314 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11315 typeQDPoint, sizeof (typeQDPoint), &p);
11316 if (err == noErr)
11317 result = noErr;
11319 break;
11321 default:
11322 abort ();
11325 if (!NILP (id_key))
11326 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11327 event, num_params,
11328 names, types);
11329 return result;
11331 #endif
11332 #endif /* TARGET_API_MAC_CARBON */
11335 OSStatus
11336 install_window_handler (window)
11337 WindowRef window;
11339 OSStatus err = noErr;
11341 #if TARGET_API_MAC_CARBON
11342 if (err == noErr)
11344 static const EventTypeSpec specs[] =
11346 /* -- window refresh events -- */
11347 {kEventClassWindow, kEventWindowUpdate},
11348 /* -- window state change events -- */
11349 {kEventClassWindow, kEventWindowShowing},
11350 {kEventClassWindow, kEventWindowHiding},
11351 {kEventClassWindow, kEventWindowShown},
11352 {kEventClassWindow, kEventWindowHidden},
11353 {kEventClassWindow, kEventWindowCollapsed},
11354 {kEventClassWindow, kEventWindowExpanded},
11355 {kEventClassWindow, kEventWindowBoundsChanging},
11356 {kEventClassWindow, kEventWindowBoundsChanged},
11357 /* -- window action events -- */
11358 {kEventClassWindow, kEventWindowClose},
11359 {kEventClassWindow, kEventWindowGetIdealSize},
11360 #ifdef MAC_OSX
11361 {kEventClassWindow, kEventWindowToolbarSwitchMode},
11362 #endif
11363 #if USE_MAC_TSM
11364 /* -- window focus events -- */
11365 {kEventClassWindow, kEventWindowFocusAcquired},
11366 {kEventClassWindow, kEventWindowFocusRelinquish},
11367 #endif
11369 static EventHandlerUPP handle_window_eventUPP = NULL;
11371 if (handle_window_eventUPP == NULL)
11372 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
11374 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11375 GetEventTypeCount (specs),
11376 specs, NULL, NULL);
11378 #endif
11380 if (err == noErr)
11381 err = install_drag_handler (window);
11383 return err;
11386 void
11387 remove_window_handler (window)
11388 WindowRef window;
11390 remove_drag_handler (window);
11393 #if TARGET_API_MAC_CARBON
11394 static OSStatus
11395 install_application_handler ()
11397 OSStatus err = noErr;
11399 if (err == noErr)
11401 static const EventTypeSpec specs[] = {
11402 #if USE_MAC_TSM
11403 {kEventClassApplication, kEventAppActivated},
11404 {kEventClassApplication, kEventAppDeactivated},
11405 #endif
11408 err = InstallApplicationEventHandler (NewEventHandlerUPP
11409 (mac_handle_application_event),
11410 GetEventTypeCount (specs),
11411 specs, NULL, NULL);
11414 if (err == noErr)
11416 static const EventTypeSpec specs[] =
11417 {{kEventClassKeyboard, kEventRawKeyDown},
11418 {kEventClassKeyboard, kEventRawKeyRepeat},
11419 {kEventClassKeyboard, kEventRawKeyUp}};
11421 err = InstallApplicationEventHandler (NewEventHandlerUPP
11422 (mac_handle_keyboard_event),
11423 GetEventTypeCount (specs),
11424 specs, NULL, NULL);
11427 if (err == noErr)
11429 static const EventTypeSpec specs[] =
11430 {{kEventClassCommand, kEventCommandProcess}};
11432 err = InstallApplicationEventHandler (NewEventHandlerUPP
11433 (mac_handle_command_event),
11434 GetEventTypeCount (specs),
11435 specs, NULL, NULL);
11438 if (err == noErr)
11440 static const EventTypeSpec specs[] =
11441 {{kEventClassMouse, kEventMouseWheelMoved}};
11443 err = InstallApplicationEventHandler (NewEventHandlerUPP
11444 (mac_handle_mouse_event),
11445 GetEventTypeCount (specs),
11446 specs, NULL, NULL);
11449 #if USE_MAC_TSM
11450 if (err == noErr)
11452 static const EventTypeSpec spec[] =
11453 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11454 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11455 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11457 err = InstallApplicationEventHandler (NewEventHandlerUPP
11458 (mac_handle_text_input_event),
11459 GetEventTypeCount (spec),
11460 spec, NULL, NULL);
11462 #endif
11464 if (err == noErr)
11465 err = install_menu_target_item_handler ();
11467 #ifdef MAC_OSX
11468 if (err == noErr)
11469 err = install_service_handler ();
11470 #endif
11472 return err;
11474 #endif
11476 static pascal void
11477 mac_handle_dm_notification (event)
11478 AppleEvent *event;
11480 mac_screen_config_changed = 1;
11483 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11484 static void
11485 mac_handle_cg_display_reconfig (display, flags, user_info)
11486 CGDirectDisplayID display;
11487 CGDisplayChangeSummaryFlags flags;
11488 void *user_info;
11490 mac_screen_config_changed = 1;
11492 #endif
11494 static OSErr
11495 init_dm_notification_handler ()
11497 OSErr err = noErr;
11499 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11500 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11501 if (CGDisplayRegisterReconfigurationCallback != NULL)
11502 #endif
11504 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11505 NULL);
11507 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11508 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11509 #endif
11510 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11511 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11513 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11514 ProcessSerialNumber psn;
11516 if (handle_dm_notificationUPP == NULL)
11517 handle_dm_notificationUPP =
11518 NewDMNotificationUPP (mac_handle_dm_notification);
11520 err = GetCurrentProcess (&psn);
11521 if (err == noErr)
11522 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11524 #endif
11526 return err;
11529 static void
11530 mac_get_screen_info (dpyinfo)
11531 struct mac_display_info *dpyinfo;
11533 #ifdef MAC_OSX
11534 /* HasDepth returns true if it is possible to have a 32 bit display,
11535 but this may not be what is actually used. Mac OSX can do better. */
11536 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11537 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11539 CGDisplayErr err;
11540 CGDisplayCount ndisps;
11541 CGDirectDisplayID *displays;
11543 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11544 if (err == noErr)
11546 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11547 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11549 if (err == noErr)
11551 CGRect bounds = CGRectZero;
11553 while (ndisps-- > 0)
11554 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11555 dpyinfo->height = CGRectGetHeight (bounds);
11556 dpyinfo->width = CGRectGetWidth (bounds);
11558 else
11560 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11561 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11564 #else /* !MAC_OSX */
11566 GDHandle gdh = GetMainDevice ();
11567 Rect rect = (**gdh).gdRect;
11569 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11570 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11571 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11572 break;
11574 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11575 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11576 UnionRect (&rect, &(**gdh).gdRect, &rect);
11578 dpyinfo->height = rect.bottom - rect.top;
11579 dpyinfo->width = rect.right - rect.left;
11581 #endif /* !MAC_OSX */
11585 #if __profile__
11586 void
11587 profiler_exit_proc ()
11589 ProfilerDump ("\pEmacs.prof");
11590 ProfilerTerm ();
11592 #endif
11594 /* These few functions implement Emacs as a normal Mac application
11595 (almost): set up the heap and the Toolbox, handle necessary system
11596 events plus a few simple menu events. They also set up Emacs's
11597 access to functions defined in the rest of this file. Emacs uses
11598 function hooks to perform all its terminal I/O. A complete list of
11599 these functions appear in termhooks.h. For what they do, read the
11600 comments there and see also w32term.c and xterm.c. What's
11601 noticeably missing here is the event loop, which is normally
11602 present in most Mac application. After performing the necessary
11603 Mac initializations, main passes off control to emacs_main
11604 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11605 (defined further below) to read input. This is where
11606 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
11608 #ifdef MAC_OS8
11609 #undef main
11611 main (void)
11613 #if __profile__ /* is the profiler on? */
11614 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11615 exit(1);
11616 #endif
11618 #if __MWERKS__
11619 /* set creator and type for files created by MSL */
11620 _fcreator = MAC_EMACS_CREATOR_CODE;
11621 _ftype = 'TEXT';
11622 #endif
11624 do_init_managers ();
11626 do_get_menus ();
11628 #ifndef USE_LSB_TAG
11629 do_check_ram_size ();
11630 #endif
11632 init_emacs_passwd_dir ();
11634 init_environ ();
11636 init_coercion_handler ();
11638 initialize_applescript ();
11640 init_apple_event_handler ();
11642 init_dm_notification_handler ();
11645 char **argv;
11646 int argc = 0;
11648 /* set up argv array from STR# resource */
11649 get_string_list (&argv, ARGV_STRING_LIST_ID);
11650 while (argv[argc])
11651 argc++;
11653 /* free up AppleScript resources on exit */
11654 atexit (terminate_applescript);
11656 #if __profile__ /* is the profiler on? */
11657 atexit (profiler_exit_proc);
11658 #endif
11660 /* 3rd param "envp" never used in emacs_main */
11661 (void) emacs_main (argc, argv, 0);
11664 /* Never reached - real exit in Fkill_emacs */
11665 return 0;
11667 #endif
11669 #if !TARGET_API_MAC_CARBON
11670 static RgnHandle mouse_region = NULL;
11672 Boolean
11673 mac_wait_next_event (er, sleep_time, dequeue)
11674 EventRecord *er;
11675 UInt32 sleep_time;
11676 Boolean dequeue;
11678 static EventRecord er_buf = {nullEvent};
11679 UInt32 target_tick, current_tick;
11680 EventMask event_mask;
11682 if (mouse_region == NULL)
11683 mouse_region = NewRgn ();
11685 event_mask = everyEvent;
11686 if (!mac_ready_for_apple_events)
11687 event_mask -= highLevelEventMask;
11689 current_tick = TickCount ();
11690 target_tick = current_tick + sleep_time;
11692 if (er_buf.what == nullEvent)
11693 while (!WaitNextEvent (event_mask, &er_buf,
11694 target_tick - current_tick, mouse_region))
11696 current_tick = TickCount ();
11697 if (target_tick <= current_tick)
11698 return false;
11701 *er = er_buf;
11702 if (dequeue)
11703 er_buf.what = nullEvent;
11704 return true;
11706 #endif /* not TARGET_API_MAC_CARBON */
11708 #if TARGET_API_MAC_CARBON
11709 OSStatus
11710 mac_post_mouse_moved_event ()
11712 EventRef event = NULL;
11713 OSStatus err;
11715 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
11716 kEventAttributeNone, &event);
11717 if (err == noErr)
11719 Point mouse_pos;
11721 GetGlobalMouse (&mouse_pos);
11722 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
11723 sizeof (Point), &mouse_pos);
11725 if (err == noErr)
11727 UInt32 modifiers = GetCurrentKeyModifiers ();
11729 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
11730 sizeof (UInt32), &modifiers);
11732 if (err == noErr)
11733 err = PostEventToQueue (GetCurrentEventQueue (), event,
11734 kEventPriorityStandard);
11735 if (event)
11736 ReleaseEvent (event);
11738 return err;
11740 #endif
11742 /* Emacs calls this whenever it wants to read an input event from the
11743 user. */
11745 XTread_socket (sd, expected, hold_quit)
11746 int sd, expected;
11747 struct input_event *hold_quit;
11749 struct input_event inev;
11750 int count = 0;
11751 #if TARGET_API_MAC_CARBON
11752 EventRef eventRef;
11753 EventTargetRef toolbox_dispatcher;
11754 #endif
11755 EventRecord er;
11756 struct mac_display_info *dpyinfo = &one_mac_display_info;
11758 if (interrupt_input_blocked)
11760 interrupt_input_pending = 1;
11761 return -1;
11764 interrupt_input_pending = 0;
11765 BLOCK_INPUT;
11767 /* So people can tell when we have read the available input. */
11768 input_signal_count++;
11770 ++handling_signal;
11772 #if TARGET_API_MAC_CARBON
11773 toolbox_dispatcher = GetEventDispatcherTarget ();
11775 while (
11776 #if USE_CG_DRAWING
11777 mac_prepare_for_quickdraw (NULL),
11778 #endif
11779 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
11780 kEventRemoveFromQueue, &eventRef))
11781 #else /* !TARGET_API_MAC_CARBON */
11782 while (mac_wait_next_event (&er, 0, true))
11783 #endif /* !TARGET_API_MAC_CARBON */
11785 int do_help = 0;
11786 struct frame *f;
11787 unsigned long timestamp;
11789 EVENT_INIT (inev);
11790 inev.kind = NO_EVENT;
11791 inev.arg = Qnil;
11793 #if TARGET_API_MAC_CARBON
11794 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
11796 if (!mac_convert_event_ref (eventRef, &er))
11797 goto OTHER;
11798 #else /* !TARGET_API_MAC_CARBON */
11799 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
11800 #endif /* !TARGET_API_MAC_CARBON */
11802 switch (er.what)
11804 case mouseDown:
11805 case mouseUp:
11807 WindowRef window_ptr;
11808 ControlPartCode part_code;
11809 int tool_bar_p = 0;
11811 #if TARGET_API_MAC_CARBON
11812 OSStatus err;
11814 /* This is needed to send mouse events like aqua window
11815 buttons to the correct handler. */
11816 read_socket_inev = &inev;
11817 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
11818 read_socket_inev = NULL;
11819 if (err != eventNotHandledErr)
11820 break;
11821 #endif
11822 last_mouse_glyph_frame = 0;
11824 if (dpyinfo->grabbed && last_mouse_frame
11825 && FRAME_LIVE_P (last_mouse_frame))
11827 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
11828 part_code = inContent;
11830 else
11832 part_code = FindWindow (er.where, &window_ptr);
11833 if (tip_window && window_ptr == tip_window)
11835 HideWindow (tip_window);
11836 part_code = FindWindow (er.where, &window_ptr);
11840 if (er.what != mouseDown &&
11841 (part_code != inContent || dpyinfo->grabbed == 0))
11842 break;
11844 switch (part_code)
11846 case inMenuBar:
11847 f = mac_focus_frame (dpyinfo);
11848 saved_menu_event_location = er.where;
11849 inev.kind = MENU_BAR_ACTIVATE_EVENT;
11850 XSETFRAME (inev.frame_or_window, f);
11851 break;
11853 case inContent:
11854 if (
11855 #if TARGET_API_MAC_CARBON
11856 FrontNonFloatingWindow ()
11857 #else
11858 FrontWindow ()
11859 #endif
11860 != window_ptr
11861 || (mac_window_to_frame (window_ptr)
11862 != dpyinfo->x_focus_frame))
11863 SelectWindow (window_ptr);
11864 else
11866 ControlPartCode control_part_code;
11867 ControlRef ch;
11868 Point mouse_loc;
11869 #ifdef MAC_OSX
11870 ControlKind control_kind;
11871 #endif
11873 f = mac_window_to_frame (window_ptr);
11874 /* convert to local coordinates of new window */
11875 mouse_loc.h = (er.where.h
11876 - (f->left_pos
11877 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
11878 mouse_loc.v = (er.where.v
11879 - (f->top_pos
11880 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
11881 #if TARGET_API_MAC_CARBON
11882 ch = FindControlUnderMouse (mouse_loc, window_ptr,
11883 &control_part_code);
11884 #ifdef MAC_OSX
11885 if (ch)
11886 GetControlKind (ch, &control_kind);
11887 #endif
11888 #else
11889 control_part_code = FindControl (mouse_loc, window_ptr,
11890 &ch);
11891 #endif
11893 #if TARGET_API_MAC_CARBON
11894 inev.code = mac_get_mouse_btn (eventRef);
11895 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
11896 #else
11897 inev.code = mac_get_emulated_btn (er.modifiers);
11898 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
11899 #endif
11900 XSETINT (inev.x, mouse_loc.h);
11901 XSETINT (inev.y, mouse_loc.v);
11903 if ((dpyinfo->grabbed && tracked_scroll_bar)
11904 || (ch != 0
11905 #ifndef USE_TOOLKIT_SCROLL_BARS
11906 /* control_part_code becomes kControlNoPart if
11907 a progress indicator is clicked. */
11908 && control_part_code != kControlNoPart
11909 #else /* USE_TOOLKIT_SCROLL_BARS */
11910 #ifdef MAC_OSX
11911 && control_kind.kind == kControlKindScrollBar
11912 #endif /* MAC_OSX */
11913 #endif /* USE_TOOLKIT_SCROLL_BARS */
11916 struct scroll_bar *bar;
11918 if (dpyinfo->grabbed && tracked_scroll_bar)
11920 bar = tracked_scroll_bar;
11921 #ifndef USE_TOOLKIT_SCROLL_BARS
11922 control_part_code = kControlIndicatorPart;
11923 #endif
11925 else
11926 bar = (struct scroll_bar *) GetControlReference (ch);
11927 #ifdef USE_TOOLKIT_SCROLL_BARS
11928 /* Make the "Ctrl-Mouse-2 splits window" work
11929 for toolkit scroll bars. */
11930 if (inev.modifiers & ctrl_modifier)
11931 x_scroll_bar_handle_click (bar, control_part_code,
11932 &er, &inev);
11933 else if (er.what == mouseDown)
11934 x_scroll_bar_handle_press (bar, control_part_code,
11935 mouse_loc, &inev);
11936 else
11937 x_scroll_bar_handle_release (bar, &inev);
11938 #else /* not USE_TOOLKIT_SCROLL_BARS */
11939 x_scroll_bar_handle_click (bar, control_part_code,
11940 &er, &inev);
11941 if (er.what == mouseDown
11942 && control_part_code == kControlIndicatorPart)
11943 tracked_scroll_bar = bar;
11944 else
11945 tracked_scroll_bar = NULL;
11946 #endif /* not USE_TOOLKIT_SCROLL_BARS */
11948 else
11950 Lisp_Object window;
11951 int x = mouse_loc.h;
11952 int y = mouse_loc.v;
11954 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
11955 if (EQ (window, f->tool_bar_window))
11957 if (er.what == mouseDown)
11958 handle_tool_bar_click (f, x, y, 1, 0);
11959 else
11960 handle_tool_bar_click (f, x, y, 0,
11961 inev.modifiers);
11962 tool_bar_p = 1;
11964 else
11966 XSETFRAME (inev.frame_or_window, f);
11967 inev.kind = MOUSE_CLICK_EVENT;
11971 if (er.what == mouseDown)
11973 dpyinfo->grabbed |= (1 << inev.code);
11974 last_mouse_frame = f;
11976 if (!tool_bar_p)
11977 last_tool_bar_item = -1;
11979 else
11981 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
11982 /* If a button is released though it was not
11983 previously pressed, that would be because
11984 of multi-button emulation. */
11985 dpyinfo->grabbed = 0;
11986 else
11987 dpyinfo->grabbed &= ~(1 << inev.code);
11990 /* Ignore any mouse motion that happened before
11991 this event; any subsequent mouse-movement Emacs
11992 events should reflect only motion after the
11993 ButtonPress. */
11994 if (f != 0)
11995 f->mouse_moved = 0;
11997 #ifdef USE_TOOLKIT_SCROLL_BARS
11998 if (inev.kind == MOUSE_CLICK_EVENT
11999 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12000 && (inev.modifiers & ctrl_modifier)))
12001 #endif
12002 switch (er.what)
12004 case mouseDown:
12005 inev.modifiers |= down_modifier;
12006 break;
12007 case mouseUp:
12008 inev.modifiers |= up_modifier;
12009 break;
12012 break;
12014 case inDrag:
12015 #if TARGET_API_MAC_CARBON
12016 case inProxyIcon:
12017 if (IsWindowPathSelectClick (window_ptr, &er))
12019 WindowPathSelect (window_ptr, NULL, NULL);
12020 break;
12022 if (part_code == inProxyIcon
12023 && (TrackWindowProxyDrag (window_ptr, er.where)
12024 != errUserWantsToDragWindow))
12025 break;
12026 DragWindow (window_ptr, er.where, NULL);
12027 #else /* not TARGET_API_MAC_CARBON */
12028 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
12029 /* Update the frame parameters. */
12031 struct frame *f = mac_window_to_frame (window_ptr);
12033 if (f && !f->async_iconified)
12034 mac_handle_origin_change (f);
12036 #endif /* not TARGET_API_MAC_CARBON */
12037 break;
12039 case inGoAway:
12040 if (TrackGoAway (window_ptr, er.where))
12042 inev.kind = DELETE_WINDOW_EVENT;
12043 XSETFRAME (inev.frame_or_window,
12044 mac_window_to_frame (window_ptr));
12046 break;
12048 /* window resize handling added --ben */
12049 case inGrow:
12050 do_grow_window (window_ptr, &er);
12051 break;
12053 /* window zoom handling added --ben */
12054 case inZoomIn:
12055 case inZoomOut:
12056 if (TrackBox (window_ptr, er.where, part_code))
12057 do_zoom_window (window_ptr, part_code);
12058 break;
12060 #if USE_MAC_TOOLBAR
12061 case inStructure:
12063 OSStatus err;
12064 HIViewRef ch;
12066 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12067 eventRef, &ch);
12068 /* This doesn't work on Mac OS X 10.2. */
12069 if (err == noErr)
12070 HIViewClick (ch, eventRef);
12072 break;
12073 #endif /* USE_MAC_TOOLBAR */
12075 default:
12076 break;
12079 break;
12081 #if !TARGET_API_MAC_CARBON
12082 case updateEvt:
12083 do_window_update ((WindowRef) er.message);
12084 break;
12085 #endif
12087 case osEvt:
12088 switch ((er.message >> 24) & 0x000000FF)
12090 case mouseMovedMessage:
12091 #if !TARGET_API_MAC_CARBON
12092 SetRectRgn (mouse_region, er.where.h, er.where.v,
12093 er.where.h + 1, er.where.v + 1);
12094 #endif
12095 previous_help_echo_string = help_echo_string;
12096 help_echo_string = Qnil;
12098 if (dpyinfo->grabbed && last_mouse_frame
12099 && FRAME_LIVE_P (last_mouse_frame))
12100 f = last_mouse_frame;
12101 else
12102 f = dpyinfo->x_focus_frame;
12104 if (dpyinfo->mouse_face_hidden)
12106 dpyinfo->mouse_face_hidden = 0;
12107 clear_mouse_face (dpyinfo);
12110 if (f)
12112 WindowRef wp = FRAME_MAC_WINDOW (f);
12113 Point mouse_pos;
12115 mouse_pos.h = (er.where.h
12116 - (f->left_pos
12117 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12118 mouse_pos.v = (er.where.v
12119 - (f->top_pos
12120 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12121 if (dpyinfo->grabbed && tracked_scroll_bar)
12122 #ifdef USE_TOOLKIT_SCROLL_BARS
12123 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
12124 mouse_pos, &inev);
12125 #else /* not USE_TOOLKIT_SCROLL_BARS */
12126 x_scroll_bar_note_movement (tracked_scroll_bar,
12127 mouse_pos.v
12128 - XINT (tracked_scroll_bar->top),
12129 er.when * (1000 / 60));
12130 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12131 else
12133 /* Generate SELECT_WINDOW_EVENTs when needed. */
12134 if (!NILP (Vmouse_autoselect_window))
12136 Lisp_Object window;
12138 window = window_from_coordinates (f,
12139 mouse_pos.h,
12140 mouse_pos.v,
12141 0, 0, 0, 0);
12143 /* Window will be selected only when it is
12144 not selected now and last mouse movement
12145 event was not in it. Minibuffer window
12146 will be selected only when it is active. */
12147 if (WINDOWP (window)
12148 && !EQ (window, last_window)
12149 && !EQ (window, selected_window))
12151 inev.kind = SELECT_WINDOW_EVENT;
12152 inev.frame_or_window = window;
12155 last_window=window;
12157 if (!note_mouse_movement (f, &mouse_pos))
12158 help_echo_string = previous_help_echo_string;
12159 #if USE_MAC_TOOLBAR
12160 else
12161 mac_tool_bar_note_mouse_movement (f, eventRef);
12162 #endif
12166 /* If the contents of the global variable
12167 help_echo_string has changed, generate a
12168 HELP_EVENT. */
12169 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12170 do_help = 1;
12171 break;
12173 default:
12174 goto OTHER;
12176 break;
12178 case activateEvt:
12180 WindowRef window_ptr = (WindowRef) er.message;
12181 OSErr err;
12182 ControlRef root_control;
12184 if (window_ptr == tip_window)
12186 HideWindow (tip_window);
12187 break;
12190 if (!is_emacs_window (window_ptr))
12191 goto OTHER;
12193 f = mac_window_to_frame (window_ptr);
12195 if ((er.modifiers & activeFlag) != 0)
12197 /* A window has been activated */
12198 Point mouse_loc;
12200 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12201 if (err == noErr)
12202 ActivateControl (root_control);
12204 x_detect_focus_change (dpyinfo, &er, &inev);
12206 mouse_loc.h = (er.where.h
12207 - (f->left_pos
12208 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12209 mouse_loc.v = (er.where.v
12210 - (f->top_pos
12211 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12212 /* Window-activated event counts as mouse movement,
12213 so update things that depend on mouse position. */
12214 note_mouse_movement (f, &mouse_loc);
12216 else
12218 /* A window has been deactivated */
12219 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12220 if (err == noErr)
12221 DeactivateControl (root_control);
12223 #ifdef USE_TOOLKIT_SCROLL_BARS
12224 if (dpyinfo->grabbed && tracked_scroll_bar)
12226 struct input_event event;
12228 EVENT_INIT (event);
12229 event.kind = NO_EVENT;
12230 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
12231 if (event.kind != NO_EVENT)
12233 event.timestamp = timestamp;
12234 kbd_buffer_store_event_hold (&event, hold_quit);
12235 count++;
12238 #endif
12239 dpyinfo->grabbed = 0;
12241 x_detect_focus_change (dpyinfo, &er, &inev);
12243 if (f == dpyinfo->mouse_face_mouse_frame)
12245 /* If we move outside the frame, then we're
12246 certainly no longer on any text in the
12247 frame. */
12248 clear_mouse_face (dpyinfo);
12249 dpyinfo->mouse_face_mouse_frame = 0;
12252 /* Generate a nil HELP_EVENT to cancel a help-echo.
12253 Do it only if there's something to cancel.
12254 Otherwise, the startup message is cleared when the
12255 mouse leaves the frame. */
12256 if (any_help_event_p)
12257 do_help = -1;
12260 break;
12262 case keyDown:
12263 case keyUp:
12264 case autoKey:
12265 ObscureCursor ();
12267 f = mac_focus_frame (dpyinfo);
12268 XSETFRAME (inev.frame_or_window, f);
12270 /* If mouse-highlight is an integer, input clears out mouse
12271 highlighting. */
12272 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12273 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12275 clear_mouse_face (dpyinfo);
12276 dpyinfo->mouse_face_hidden = 1;
12280 UInt32 modifiers = er.modifiers, mapped_modifiers;
12282 #ifdef MAC_OSX
12283 GetEventParameter (eventRef, kEventParamKeyModifiers,
12284 typeUInt32, NULL,
12285 sizeof (UInt32), NULL, &modifiers);
12286 #endif
12287 mapped_modifiers = mac_mapped_modifiers (modifiers);
12289 #if TARGET_API_MAC_CARBON
12290 if (!(mapped_modifiers
12291 & ~(mac_pass_command_to_system ? cmdKey : 0)
12292 & ~(mac_pass_control_to_system ? controlKey : 0)))
12293 goto OTHER;
12294 else
12295 #endif
12296 if (er.what != keyUp)
12297 do_keystroke (er.what, er.message & charCodeMask,
12298 (er.message & keyCodeMask) >> 8,
12299 modifiers, timestamp, &inev);
12301 break;
12303 case kHighLevelEvent:
12304 AEProcessAppleEvent (&er);
12305 break;
12307 default:
12308 OTHER:
12309 #if TARGET_API_MAC_CARBON
12311 OSStatus err;
12313 read_socket_inev = &inev;
12314 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12315 read_socket_inev = NULL;
12317 #endif
12318 break;
12320 #if TARGET_API_MAC_CARBON
12321 ReleaseEvent (eventRef);
12322 #endif
12324 if (inev.kind != NO_EVENT)
12326 inev.timestamp = timestamp;
12327 kbd_buffer_store_event_hold (&inev, hold_quit);
12328 count++;
12331 if (do_help
12332 && !(hold_quit && hold_quit->kind != NO_EVENT))
12334 Lisp_Object frame;
12336 if (f)
12337 XSETFRAME (frame, f);
12338 else
12339 frame = Qnil;
12341 if (do_help > 0)
12343 any_help_event_p = 1;
12344 gen_help_event (help_echo_string, frame, help_echo_window,
12345 help_echo_object, help_echo_pos);
12347 else
12349 help_echo_string = Qnil;
12350 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12352 count++;
12356 /* If the focus was just given to an autoraising frame,
12357 raise it now. */
12358 /* ??? This ought to be able to handle more than one such frame. */
12359 if (pending_autoraise_frame)
12361 x_raise_frame (pending_autoraise_frame);
12362 pending_autoraise_frame = 0;
12365 if (mac_screen_config_changed)
12367 mac_get_screen_info (dpyinfo);
12368 mac_screen_config_changed = 0;
12371 #if !TARGET_API_MAC_CARBON
12372 /* Check which frames are still visible. We do this here because
12373 there doesn't seem to be any direct notification from the Window
12374 Manager that the visibility of a window has changed (at least,
12375 not in all cases). */
12377 Lisp_Object tail, frame;
12379 FOR_EACH_FRAME (tail, frame)
12381 struct frame *f = XFRAME (frame);
12383 /* The tooltip has been drawn already. Avoid the
12384 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12385 if (EQ (frame, tip_frame))
12386 continue;
12388 if (FRAME_MAC_P (f))
12389 mac_handle_visibility_change (f);
12392 #endif
12394 --handling_signal;
12395 UNBLOCK_INPUT;
12396 return count;
12400 /* Need to override CodeWarrior's input function so no conversion is
12401 done on newlines Otherwise compiled functions in .elc files will be
12402 read incorrectly. Defined in ...:MSL C:MSL
12403 Common:Source:buffer_io.c. */
12404 #ifdef __MWERKS__
12405 void
12406 __convert_to_newlines (unsigned char * p, size_t * n)
12408 #pragma unused(p,n)
12411 void
12412 __convert_from_newlines (unsigned char * p, size_t * n)
12414 #pragma unused(p,n)
12416 #endif
12418 #ifdef MAC_OS8
12419 void
12420 make_mac_terminal_frame (struct frame *f)
12422 Lisp_Object frame;
12423 Rect r;
12425 XSETFRAME (frame, f);
12427 f->output_method = output_mac;
12428 f->output_data.mac = (struct mac_output *)
12429 xmalloc (sizeof (struct mac_output));
12430 bzero (f->output_data.mac, sizeof (struct mac_output));
12432 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12434 FRAME_COLS (f) = 96;
12435 FRAME_LINES (f) = 4;
12437 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12438 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12440 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
12442 f->output_data.mac->cursor_pixel = 0;
12443 f->output_data.mac->border_pixel = 0x00ff00;
12444 f->output_data.mac->mouse_pixel = 0xff00ff;
12445 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12447 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12448 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12449 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12450 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12451 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12452 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
12454 FRAME_FONTSET (f) = -1;
12455 f->output_data.mac->explicit_parent = 0;
12456 f->left_pos = 8;
12457 f->top_pos = 32;
12458 f->border_width = 0;
12460 f->internal_border_width = 0;
12462 f->auto_raise = 1;
12463 f->auto_lower = 1;
12465 f->new_text_cols = 0;
12466 f->new_text_lines = 0;
12468 SetRect (&r, f->left_pos, f->top_pos,
12469 f->left_pos + FRAME_PIXEL_WIDTH (f),
12470 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12472 BLOCK_INPUT;
12474 if (!(FRAME_MAC_WINDOW (f) =
12475 NewCWindow (NULL, &r, "\p", true, dBoxProc,
12476 (WindowRef) -1, 1, (long) f->output_data.mac)))
12477 abort ();
12478 /* so that update events can find this mac_output struct */
12479 f->output_data.mac->mFP = f; /* point back to emacs frame */
12481 UNBLOCK_INPUT;
12483 x_make_gc (f);
12485 /* Need to be initialized for unshow_buffer in window.c. */
12486 selected_window = f->selected_window;
12488 Fmodify_frame_parameters (frame,
12489 Fcons (Fcons (Qfont,
12490 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12491 Fmodify_frame_parameters (frame,
12492 Fcons (Fcons (Qforeground_color,
12493 build_string ("black")), Qnil));
12494 Fmodify_frame_parameters (frame,
12495 Fcons (Fcons (Qbackground_color,
12496 build_string ("white")), Qnil));
12498 #endif
12501 /***********************************************************************
12502 Initialization
12503 ***********************************************************************/
12505 static int mac_initialized = 0;
12507 static XrmDatabase
12508 mac_make_rdb (xrm_option)
12509 const char *xrm_option;
12511 XrmDatabase database;
12513 database = xrm_get_preference_database (NULL);
12514 if (xrm_option)
12515 xrm_merge_string_database (database, xrm_option);
12517 return database;
12520 struct mac_display_info *
12521 mac_term_init (display_name, xrm_option, resource_name)
12522 Lisp_Object display_name;
12523 char *xrm_option;
12524 char *resource_name;
12526 struct mac_display_info *dpyinfo;
12528 BLOCK_INPUT;
12530 if (!mac_initialized)
12532 mac_initialize ();
12533 mac_initialized = 1;
12536 if (x_display_list)
12537 error ("Sorry, this version can only handle one display");
12539 dpyinfo = &one_mac_display_info;
12540 bzero (dpyinfo, sizeof (*dpyinfo));
12542 #ifdef MAC_OSX
12543 dpyinfo->mac_id_name
12544 = (char *) xmalloc (SCHARS (Vinvocation_name)
12545 + SCHARS (Vsystem_name)
12546 + 2);
12547 sprintf (dpyinfo->mac_id_name, "%s@%s",
12548 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12549 #else
12550 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12551 strcpy (dpyinfo->mac_id_name, "Mac Display");
12552 #endif
12554 dpyinfo->reference_count = 0;
12555 dpyinfo->resx = 72.0;
12556 dpyinfo->resy = 72.0;
12558 mac_get_screen_info (dpyinfo);
12560 dpyinfo->grabbed = 0;
12561 dpyinfo->root_window = NULL;
12562 dpyinfo->image_cache = make_image_cache ();
12564 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12565 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12566 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12567 dpyinfo->mouse_face_window = Qnil;
12568 dpyinfo->mouse_face_overlay = Qnil;
12569 dpyinfo->mouse_face_hidden = 0;
12571 dpyinfo->xrdb = mac_make_rdb (xrm_option);
12573 /* Put this display on the chain. */
12574 dpyinfo->next = x_display_list;
12575 x_display_list = dpyinfo;
12577 /* Put it on x_display_name_list. */
12578 x_display_name_list = Fcons (Fcons (display_name,
12579 Fcons (Qnil, dpyinfo->xrdb)),
12580 x_display_name_list);
12581 dpyinfo->name_list_element = XCAR (x_display_name_list);
12583 UNBLOCK_INPUT;
12585 return dpyinfo;
12588 /* Get rid of display DPYINFO, assuming all frames are already gone. */
12590 void
12591 x_delete_display (dpyinfo)
12592 struct mac_display_info *dpyinfo;
12594 int i;
12596 /* Discard this display from x_display_name_list and x_display_list.
12597 We can't use Fdelq because that can quit. */
12598 if (! NILP (x_display_name_list)
12599 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12600 x_display_name_list = XCDR (x_display_name_list);
12601 else
12603 Lisp_Object tail;
12605 tail = x_display_name_list;
12606 while (CONSP (tail) && CONSP (XCDR (tail)))
12608 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
12610 XSETCDR (tail, XCDR (XCDR (tail)));
12611 break;
12613 tail = XCDR (tail);
12617 if (x_display_list == dpyinfo)
12618 x_display_list = dpyinfo->next;
12619 else
12621 struct x_display_info *tail;
12623 for (tail = x_display_list; tail; tail = tail->next)
12624 if (tail->next == dpyinfo)
12625 tail->next = tail->next->next;
12628 /* Free the font names in the font table. */
12629 for (i = 0; i < dpyinfo->n_fonts; i++)
12630 if (dpyinfo->font_table[i].name)
12632 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
12633 xfree (dpyinfo->font_table[i].full_name);
12634 xfree (dpyinfo->font_table[i].name);
12637 if (dpyinfo->font_table)
12639 if (dpyinfo->font_table->font_encoder)
12640 xfree (dpyinfo->font_table->font_encoder);
12641 xfree (dpyinfo->font_table);
12643 if (dpyinfo->mac_id_name)
12644 xfree (dpyinfo->mac_id_name);
12646 if (x_display_list == 0)
12648 mac_clear_font_name_table ();
12649 bzero (dpyinfo, sizeof (*dpyinfo));
12654 static void
12655 init_menu_bar ()
12657 #ifdef MAC_OSX
12658 OSStatus err;
12659 MenuRef menu;
12660 MenuItemIndex menu_index;
12662 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
12663 &menu, &menu_index);
12664 if (err == noErr)
12665 SetMenuItemCommandKey (menu, menu_index, false, 0);
12666 EnableMenuCommand (NULL, kHICommandPreferences);
12667 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
12668 &menu, &menu_index);
12669 if (err == noErr)
12671 SetMenuItemCommandKey (menu, menu_index, false, 0);
12672 InsertMenuItemTextWithCFString (menu, NULL,
12673 0, kMenuItemAttrSeparator, 0);
12674 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
12675 0, 0, kHICommandAbout);
12677 #else /* !MAC_OSX */
12678 #if TARGET_API_MAC_CARBON
12679 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
12680 #endif
12681 #endif
12684 #if USE_MAC_TSM
12685 static void
12686 init_tsm ()
12688 #ifdef MAC_OSX
12689 static InterfaceTypeList types = {kUnicodeDocument};
12690 #else
12691 static InterfaceTypeList types = {kTextService};
12692 #endif
12694 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
12695 &tsm_document_id, 0);
12697 #endif
12699 /* Set up use of X before we make the first connection. */
12701 extern frame_parm_handler mac_frame_parm_handlers[];
12703 static struct redisplay_interface x_redisplay_interface =
12705 mac_frame_parm_handlers,
12706 x_produce_glyphs,
12707 x_write_glyphs,
12708 x_insert_glyphs,
12709 x_clear_end_of_line,
12710 x_scroll_run,
12711 x_after_update_window_line,
12712 x_update_window_begin,
12713 x_update_window_end,
12714 x_cursor_to,
12715 x_flush,
12716 #if USE_CG_DRAWING
12717 mac_flush_display_optional,
12718 #else
12719 0, /* flush_display_optional */
12720 #endif
12721 x_clear_window_mouse_face,
12722 x_get_glyph_overhangs,
12723 x_fix_overlapping_area,
12724 x_draw_fringe_bitmap,
12725 #if USE_CG_DRAWING
12726 mac_define_fringe_bitmap,
12727 mac_destroy_fringe_bitmap,
12728 #else
12729 0, /* define_fringe_bitmap */
12730 0, /* destroy_fringe_bitmap */
12731 #endif
12732 mac_per_char_metric,
12733 mac_encode_char,
12734 mac_compute_glyph_string_overhangs,
12735 x_draw_glyph_string,
12736 mac_define_frame_cursor,
12737 mac_clear_frame_area,
12738 mac_draw_window_cursor,
12739 mac_draw_vertical_window_border,
12740 mac_shift_glyphs_for_insert
12743 void
12744 mac_initialize ()
12746 rif = &x_redisplay_interface;
12748 clear_frame_hook = x_clear_frame;
12749 ins_del_lines_hook = x_ins_del_lines;
12750 delete_glyphs_hook = x_delete_glyphs;
12751 ring_bell_hook = XTring_bell;
12752 reset_terminal_modes_hook = XTreset_terminal_modes;
12753 set_terminal_modes_hook = XTset_terminal_modes;
12754 update_begin_hook = x_update_begin;
12755 update_end_hook = x_update_end;
12756 set_terminal_window_hook = XTset_terminal_window;
12757 read_socket_hook = XTread_socket;
12758 frame_up_to_date_hook = XTframe_up_to_date;
12759 mouse_position_hook = XTmouse_position;
12760 frame_rehighlight_hook = XTframe_rehighlight;
12761 frame_raise_lower_hook = XTframe_raise_lower;
12763 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12764 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12765 redeem_scroll_bar_hook = XTredeem_scroll_bar;
12766 judge_scroll_bars_hook = XTjudge_scroll_bars;
12768 scroll_region_ok = 1; /* we'll scroll partial frames */
12769 char_ins_del_ok = 1;
12770 line_ins_del_ok = 1; /* we'll just blt 'em */
12771 fast_clear_end_of_line = 1; /* X does this well */
12772 memory_below_frame = 0; /* we don't remember what scrolls
12773 off the bottom */
12774 baud_rate = 19200;
12776 last_tool_bar_item = -1;
12777 any_help_event_p = 0;
12779 /* Try to use interrupt input; if we can't, then start polling. */
12780 Fset_input_mode (Qt, Qnil, Qt, Qnil);
12782 BLOCK_INPUT;
12784 #if TARGET_API_MAC_CARBON
12786 install_application_handler ();
12788 init_menu_bar ();
12790 #if USE_MAC_TSM
12791 init_tsm ();
12792 #endif
12794 #ifdef MAC_OSX
12795 init_coercion_handler ();
12797 init_apple_event_handler ();
12799 init_dm_notification_handler ();
12801 if (!inhibit_window_system)
12803 static const ProcessSerialNumber psn = {0, kCurrentProcess};
12805 SetFrontProcess (&psn);
12807 #endif
12808 #endif
12810 #if USE_CG_DRAWING
12811 init_cg_color ();
12813 mac_init_fringe ();
12814 #endif
12816 UNBLOCK_INPUT;
12820 void
12821 syms_of_macterm ()
12823 #if 0
12824 staticpro (&x_error_message_string);
12825 x_error_message_string = Qnil;
12826 #endif
12828 Qcontrol = intern ("control"); staticpro (&Qcontrol);
12829 Qmeta = intern ("meta"); staticpro (&Qmeta);
12830 Qalt = intern ("alt"); staticpro (&Qalt);
12831 Qhyper = intern ("hyper"); staticpro (&Qhyper);
12832 Qsuper = intern ("super"); staticpro (&Qsuper);
12833 Qmodifier_value = intern ("modifier-value");
12834 staticpro (&Qmodifier_value);
12836 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
12837 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
12838 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
12839 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
12840 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
12842 #if TARGET_API_MAC_CARBON
12843 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
12844 #ifdef MAC_OSX
12845 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
12846 staticpro (&Qtoolbar_switch_mode);
12847 #if USE_MAC_FONT_PANEL
12848 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
12849 Qselection = intern ("selection"); staticpro (&Qselection);
12850 #endif
12852 Qservice = intern ("service"); staticpro (&Qservice);
12853 Qpaste = intern ("paste"); staticpro (&Qpaste);
12854 Qperform = intern ("perform"); staticpro (&Qperform);
12855 #endif
12856 #if USE_MAC_TSM
12857 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
12858 Qupdate_active_input_area = intern ("update-active-input-area");
12859 staticpro (&Qupdate_active_input_area);
12860 Qunicode_for_key_event = intern ("unicode-for-key-event");
12861 staticpro (&Qunicode_for_key_event);
12862 #endif
12863 #endif
12865 #ifdef MAC_OSX
12866 Fprovide (intern ("mac-carbon"), Qnil);
12867 #endif
12869 staticpro (&Qreverse);
12870 Qreverse = intern ("reverse");
12872 staticpro (&x_display_name_list);
12873 x_display_name_list = Qnil;
12875 staticpro (&last_mouse_scroll_bar);
12876 last_mouse_scroll_bar = Qnil;
12878 staticpro (&fm_font_family_alist);
12879 fm_font_family_alist = Qnil;
12881 #if USE_ATSUI
12882 staticpro (&atsu_font_id_hash);
12883 atsu_font_id_hash = Qnil;
12885 staticpro (&fm_style_face_attributes_alist);
12886 fm_style_face_attributes_alist = Qnil;
12887 #endif
12889 #if USE_MAC_TSM
12890 staticpro (&saved_ts_script_language_on_focus);
12891 saved_ts_script_language_on_focus = Qnil;
12892 #endif
12894 /* We don't yet support this, but defining this here avoids whining
12895 from cus-start.el and other places, like "M-x set-variable". */
12896 DEFVAR_BOOL ("x-use-underline-position-properties",
12897 &x_use_underline_position_properties,
12898 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
12899 A value of nil means ignore them. If you encounter fonts with bogus
12900 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
12901 to 4.1, set this to nil.
12903 NOTE: Not supported on Mac yet. */);
12904 x_use_underline_position_properties = 0;
12906 DEFVAR_BOOL ("x-underline-at-descent-line",
12907 &x_underline_at_descent_line,
12908 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
12909 A value of nil means to draw the underline according to the value of the
12910 variable `x-use-underline-position-properties', which is usually at the
12911 baseline level. The default value is nil. */);
12912 x_underline_at_descent_line = 0;
12914 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
12915 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
12916 #ifdef USE_TOOLKIT_SCROLL_BARS
12917 Vx_toolkit_scroll_bars = Qt;
12918 #else
12919 Vx_toolkit_scroll_bars = Qnil;
12920 #endif
12922 staticpro (&last_mouse_motion_frame);
12923 last_mouse_motion_frame = Qnil;
12925 /* Variables to configure modifier key assignment. */
12927 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
12928 doc: /* *Modifier key assumed when the Mac control key is pressed.
12929 The value can be `control', `meta', `alt', `hyper', or `super' for the
12930 respective modifier. The default is `control'. */);
12931 Vmac_control_modifier = Qcontrol;
12933 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
12934 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
12935 The value can be `control', `meta', `alt', `hyper', or `super' for the
12936 respective modifier. If the value is nil then the key will act as the
12937 normal Mac control modifier, and the option key can be used to compose
12938 characters depending on the chosen Mac keyboard setting. */);
12939 Vmac_option_modifier = Qnil;
12941 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
12942 doc: /* *Modifier key assumed when the Mac command key is pressed.
12943 The value can be `control', `meta', `alt', `hyper', or `super' for the
12944 respective modifier. The default is `meta'. */);
12945 Vmac_command_modifier = Qmeta;
12947 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
12948 doc: /* *Modifier key assumed when the Mac function key is pressed.
12949 The value can be `control', `meta', `alt', `hyper', or `super' for the
12950 respective modifier. Note that remapping the function key may lead to
12951 unexpected results for some keys on non-US/GB keyboards. */);
12952 Vmac_function_modifier = Qnil;
12954 DEFVAR_LISP ("mac-emulate-three-button-mouse",
12955 &Vmac_emulate_three_button_mouse,
12956 doc: /* *Specify a way of three button mouse emulation.
12957 The value can be nil, t, or the symbol `reverse'.
12958 A value of nil means that no emulation should be done and the modifiers
12959 should be placed on the mouse-1 event.
12960 t means that when the option-key is held down while pressing the mouse
12961 button, the click will register as mouse-2 and while the command-key
12962 is held down, the click will register as mouse-3.
12963 The symbol `reverse' means that the option-key will register for
12964 mouse-3 and the command-key will register for mouse-2. */);
12965 Vmac_emulate_three_button_mouse = Qnil;
12967 #if TARGET_API_MAC_CARBON
12968 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
12969 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
12970 Otherwise, the right click will be treated as mouse-2 and the wheel
12971 button will be mouse-3. */);
12972 mac_wheel_button_is_mouse_2 = 1;
12974 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
12975 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
12976 mac_pass_command_to_system = 1;
12978 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
12979 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
12980 mac_pass_control_to_system = 1;
12982 #endif
12984 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
12985 doc: /* *If non-nil, allow anti-aliasing.
12986 The text will be rendered using Core Graphics text rendering which
12987 may anti-alias the text. */);
12988 #if USE_CG_DRAWING
12989 mac_use_core_graphics = 1;
12990 #else
12991 mac_use_core_graphics = 0;
12992 #endif
12994 /* Register an entry for `mac-roman' so that it can be used when
12995 creating the terminal frame on Mac OS 9 before loading
12996 term/mac-win.elc. */
12997 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
12998 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
12999 Each entry should be of the form:
13001 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13003 where CHARSET-NAME is a string used in font names to identify the
13004 charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13005 CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
13006 Vmac_charset_info_alist =
13007 Fcons (list3 (build_string ("mac-roman"),
13008 make_number (smRoman), Qnil), Qnil);
13010 #if USE_MAC_TSM
13011 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13012 doc: /* Overlay used to display Mac TSM active input area. */);
13013 Vmac_ts_active_input_overlay = Qnil;
13015 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13016 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13017 If the value is t, the input script and language are restored to those
13018 used in the last focus frame. If the value is a pair of integers, the
13019 input script and language codes, which are defined in the Script
13020 Manager, are set to its car and cdr parts, respectively. Otherwise,
13021 Emacs doesn't set them and thus follows the system default behavior. */);
13022 Vmac_ts_script_language_on_focus = Qnil;
13023 #endif
13026 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13027 (do not change this comment) */