(Button Types): For define-button-type, clarify type of NAME.
[emacs.git] / src / macterm.c
blob58de15cace0d14cf7e38c521dc50135634f007e3
1 /* Implementation of GUI terminal on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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 static 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_ ((struct terminal *));
235 static void XTreset_terminal_modes P_ ((struct terminal *));
236 static void x_clear_frame P_ ((struct frame *));
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 *));
264 static struct terminal *mac_create_terminal P_ ((struct mac_display_info *dpyinfo));
267 #define GC_FORE_COLOR(gc) (&(gc)->fore_color)
268 #define GC_BACK_COLOR(gc) (&(gc)->back_color)
269 #define GC_FONT(gc) ((gc)->xgcv.font)
270 #define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
272 #define CG_SET_FILL_COLOR(context, color) \
273 CGContextSetRGBFillColor (context, \
274 RED_FROM_ULONG (color) / 255.0f, \
275 GREEN_FROM_ULONG (color) / 255.0f, \
276 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
277 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
278 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
279 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
280 do { \
281 if (CGColorGetTypeID != NULL) \
282 CGContextSetFillColorWithColor (context, cg_color); \
283 else \
284 CG_SET_FILL_COLOR (context, color); \
285 } while (0)
286 #else
287 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
288 CGContextSetFillColorWithColor (context, cg_color)
289 #endif
290 #else
291 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
292 CG_SET_FILL_COLOR (context, color)
293 #endif
294 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, gc) \
295 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
296 (gc)->cg_fore_color)
297 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, gc) \
298 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.background, \
299 (gc)->cg_back_color)
302 #define CG_SET_STROKE_COLOR(context, color) \
303 CGContextSetRGBStrokeColor (context, \
304 RED_FROM_ULONG (color) / 255.0f, \
305 GREEN_FROM_ULONG (color) / 255.0f, \
306 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
307 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
308 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
309 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
310 do { \
311 if (CGColorGetTypeID != NULL) \
312 CGContextSetStrokeColorWithColor (context, cg_color); \
313 else \
314 CG_SET_STROKE_COLOR (context, color); \
315 } while (0)
316 #else
317 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
318 CGContextSetStrokeColorWithColor (context, cg_color)
319 #endif
320 #else
321 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
322 CG_SET_STROKE_COLOR (context, color)
323 #endif
324 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, gc) \
325 CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
326 (gc)->cg_fore_color)
328 #if USE_CG_DRAWING
329 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
331 /* Fringe bitmaps. */
333 static int max_fringe_bmp = 0;
334 static CGImageRef *fringe_bmp = 0;
336 static CGColorSpaceRef mac_cg_color_space_rgb;
337 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
338 static CGColorRef mac_cg_color_black;
339 #endif
341 static void
342 init_cg_color ()
344 mac_cg_color_space_rgb = CGColorSpaceCreateDeviceRGB ();
345 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
346 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
347 /* Don't check the availability of CGColorCreate; this symbol is
348 defined even in Mac OS X 10.1. */
349 if (CGColorGetTypeID != NULL)
350 #endif
352 float rgba[] = {0.0f, 0.0f, 0.0f, 1.0f};
354 mac_cg_color_black = CGColorCreate (mac_cg_color_space_rgb, rgba);
356 #endif
359 static CGContextRef
360 mac_begin_cg_clip (f, gc)
361 struct frame *f;
362 GC gc;
364 CGContextRef context = FRAME_CG_CONTEXT (f);
366 if (!context)
368 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
369 FRAME_CG_CONTEXT (f) = context;
372 CGContextSaveGState (context);
373 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
374 CGContextScaleCTM (context, 1, -1);
375 if (gc && gc->n_clip_rects)
376 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
378 return context;
381 static void
382 mac_end_cg_clip (f)
383 struct frame *f;
385 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
388 void
389 mac_prepare_for_quickdraw (f)
390 struct frame *f;
392 if (f == NULL)
394 Lisp_Object rest, frame;
395 FOR_EACH_FRAME (rest, frame)
396 if (FRAME_MAC_P (XFRAME (frame)))
397 mac_prepare_for_quickdraw (XFRAME (frame));
399 else
401 CGContextRef context = FRAME_CG_CONTEXT (f);
403 if (context)
405 CGContextSynchronize (context);
406 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
407 &FRAME_CG_CONTEXT (f));
411 #endif
413 static RgnHandle saved_port_clip_region = NULL;
415 static void
416 mac_begin_clip (f, gc)
417 struct frame *f;
418 GC gc;
420 static RgnHandle new_region = NULL;
422 if (saved_port_clip_region == NULL)
423 saved_port_clip_region = NewRgn ();
424 if (new_region == NULL)
425 new_region = NewRgn ();
427 #if USE_CG_DRAWING
428 mac_prepare_for_quickdraw (f);
429 #endif
430 SetPortWindowPort (FRAME_MAC_WINDOW (f));
432 if (gc->n_clip_rects)
434 GetClip (saved_port_clip_region);
435 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
436 SetClip (new_region);
440 static void
441 mac_end_clip (gc)
442 GC gc;
444 if (gc->n_clip_rects)
445 SetClip (saved_port_clip_region);
449 /* X display function emulation */
451 /* Mac version of XDrawLine. */
453 static void
454 mac_draw_line (f, gc, x1, y1, x2, y2)
455 struct frame *f;
456 GC gc;
457 int x1, y1, x2, y2;
459 #if USE_CG_DRAWING
460 CGContextRef context;
461 float gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
463 if (y1 != y2)
464 gx1 += 0.5f, gx2 += 0.5f;
465 if (x1 != x2)
466 gy1 += 0.5f, gy2 += 0.5f;
468 context = mac_begin_cg_clip (f, gc);
469 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
470 CGContextBeginPath (context);
471 CGContextMoveToPoint (context, gx1, gy1);
472 CGContextAddLineToPoint (context, gx2, gy2);
473 CGContextClosePath (context);
474 CGContextStrokePath (context);
475 mac_end_cg_clip (f);
476 #else
477 if (x1 == x2)
479 if (y1 > y2)
480 y1--;
481 else if (y2 > y1)
482 y2--;
484 else if (y1 == y2)
486 if (x1 > x2)
487 x1--;
488 else
489 x2--;
492 mac_begin_clip (f, gc);
493 RGBForeColor (GC_FORE_COLOR (gc));
494 MoveTo (x1, y1);
495 LineTo (x2, y2);
496 mac_end_clip (gc);
497 #endif
500 /* Mac version of XDrawLine (to Pixmap). */
502 void
503 XDrawLine (display, p, gc, x1, y1, x2, y2)
504 Display *display;
505 Pixmap p;
506 GC gc;
507 int x1, y1, x2, y2;
509 CGrafPtr old_port;
510 GDHandle old_gdh;
512 if (x1 == x2)
514 if (y1 > y2)
515 y1--;
516 else if (y2 > y1)
517 y2--;
519 else if (y1 == y2)
521 if (x1 > x2)
522 x1--;
523 else
524 x2--;
527 GetGWorld (&old_port, &old_gdh);
528 SetGWorld (p, NULL);
530 RGBForeColor (GC_FORE_COLOR (gc));
532 LockPixels (GetGWorldPixMap (p));
533 MoveTo (x1, y1);
534 LineTo (x2, y2);
535 UnlockPixels (GetGWorldPixMap (p));
537 SetGWorld (old_port, old_gdh);
541 static void
542 mac_erase_rectangle (f, gc, x, y, width, height)
543 struct frame *f;
544 GC gc;
545 int x, y;
546 unsigned int width, height;
548 #if USE_CG_DRAWING
550 CGContextRef context;
552 context = mac_begin_cg_clip (f, gc);
553 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
554 CGContextFillRect (context, CGRectMake (x, y, width, height));
555 mac_end_cg_clip (f);
557 #else
559 Rect r;
561 mac_begin_clip (f, gc);
562 RGBBackColor (GC_BACK_COLOR (gc));
563 SetRect (&r, x, y, x + width, y + height);
564 EraseRect (&r);
565 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
566 mac_end_clip (gc);
568 #endif
572 /* Mac version of XClearArea. */
574 void
575 mac_clear_area (f, x, y, width, height)
576 struct frame *f;
577 int x, y;
578 unsigned int width, height;
580 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
583 /* Mac version of XClearWindow. */
585 static void
586 mac_clear_window (f)
587 struct frame *f;
589 #if USE_CG_DRAWING
591 CGContextRef context;
592 GC gc = FRAME_NORMAL_GC (f);
594 context = mac_begin_cg_clip (f, NULL);
595 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
596 CGContextFillRect (context, CGRectMake (0, 0, FRAME_PIXEL_WIDTH (f),
597 FRAME_PIXEL_HEIGHT (f)));
598 mac_end_cg_clip (f);
600 #else /* !USE_CG_DRAWING */
601 SetPortWindowPort (FRAME_MAC_WINDOW (f));
603 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
605 #if TARGET_API_MAC_CARBON
607 Rect r;
609 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
610 EraseRect (&r);
612 #else /* not TARGET_API_MAC_CARBON */
613 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
614 #endif /* not TARGET_API_MAC_CARBON */
615 #endif
619 /* Mac replacement for XCopyArea. */
621 #if USE_CG_DRAWING
622 static void
623 mac_draw_cg_image (image, f, gc, src_x, src_y, width, height,
624 dest_x, dest_y, overlay_p)
625 CGImageRef image;
626 struct frame *f;
627 GC gc;
628 int src_x, src_y;
629 unsigned int width, height;
630 int dest_x, dest_y, overlay_p;
632 CGContextRef context;
633 float port_height = FRAME_PIXEL_HEIGHT (f);
634 CGRect dest_rect = CGRectMake (dest_x, dest_y, width, height);
636 context = mac_begin_cg_clip (f, gc);
637 if (!overlay_p)
639 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
640 CGContextFillRect (context, dest_rect);
642 CGContextClipToRect (context, dest_rect);
643 CGContextScaleCTM (context, 1, -1);
644 CGContextTranslateCTM (context, 0, -port_height);
645 if (CGImageIsMask (image))
646 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
647 CGContextDrawImage (context,
648 CGRectMake (dest_x - src_x,
649 port_height - (dest_y - src_y
650 + CGImageGetHeight (image)),
651 CGImageGetWidth (image),
652 CGImageGetHeight (image)),
653 image);
654 mac_end_cg_clip (f);
657 #else /* !USE_CG_DRAWING */
659 static void
660 mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
661 struct frame *f;
662 GC gc;
663 int x, y, width, height;
664 unsigned short *bits;
665 int overlay_p;
667 BitMap bitmap;
668 Rect r;
670 bitmap.rowBytes = sizeof(unsigned short);
671 bitmap.baseAddr = (char *)bits;
672 SetRect (&(bitmap.bounds), 0, 0, width, height);
674 mac_begin_clip (f, gc);
675 RGBForeColor (GC_FORE_COLOR (gc));
676 RGBBackColor (GC_BACK_COLOR (gc));
677 SetRect (&r, x, y, x + width, y + height);
678 #if TARGET_API_MAC_CARBON
680 CGrafPtr port;
682 GetPort (&port);
683 LockPortBits (port);
684 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
685 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
686 UnlockPortBits (port);
688 #else /* not TARGET_API_MAC_CARBON */
689 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
690 overlay_p ? srcOr : srcCopy, 0);
691 #endif /* not TARGET_API_MAC_CARBON */
692 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
693 mac_end_clip (gc);
695 #endif /* !USE_CG_DRAWING */
698 /* Mac replacement for XCreateBitmapFromBitmapData. */
700 static void
701 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
702 BitMap *bitmap;
703 char *bits;
704 int w, h;
706 static const unsigned char swap_nibble[16]
707 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
708 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
709 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
710 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
711 int i, j, w1;
712 char *p;
714 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
715 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
716 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
717 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
718 for (i = 0; i < h; i++)
720 p = bitmap->baseAddr + i * bitmap->rowBytes;
721 for (j = 0; j < w1; j++)
723 /* Bitswap XBM bytes to match how Mac does things. */
724 unsigned char c = *bits++;
725 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
726 | (swap_nibble[(c>>4) & 0xf]));
730 SetRect (&(bitmap->bounds), 0, 0, w, h);
734 static void
735 mac_free_bitmap (bitmap)
736 BitMap *bitmap;
738 xfree (bitmap->baseAddr);
742 Pixmap
743 XCreatePixmap (display, w, width, height, depth)
744 Display *display;
745 WindowRef w;
746 unsigned int width, height;
747 unsigned int depth;
749 Pixmap pixmap;
750 Rect r;
751 QDErr err;
753 SetPortWindowPort (w);
755 SetRect (&r, 0, 0, width, height);
756 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
757 if (depth == 1)
758 #endif
759 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
760 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
761 else
762 /* CreateCGImageFromPixMaps requires ARGB format. */
763 err = QTNewGWorld (&pixmap, k32ARGBPixelFormat, &r, NULL, NULL, 0);
764 #endif
765 if (err != noErr)
766 return NULL;
767 return pixmap;
771 Pixmap
772 XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
773 Display *display;
774 WindowRef w;
775 char *data;
776 unsigned int width, height;
777 unsigned long fg, bg;
778 unsigned int depth;
780 Pixmap pixmap;
781 BitMap bitmap;
782 CGrafPtr old_port;
783 GDHandle old_gdh;
784 static GC gc = NULL;
786 if (gc == NULL)
787 gc = XCreateGC (display, w, 0, NULL);
789 pixmap = XCreatePixmap (display, w, width, height, depth);
790 if (pixmap == NULL)
791 return NULL;
793 GetGWorld (&old_port, &old_gdh);
794 SetGWorld (pixmap, NULL);
795 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
796 XSetForeground (display, gc, fg);
797 XSetBackground (display, gc, bg);
798 RGBForeColor (GC_FORE_COLOR (gc));
799 RGBBackColor (GC_BACK_COLOR (gc));
800 LockPixels (GetGWorldPixMap (pixmap));
801 #if TARGET_API_MAC_CARBON
802 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
803 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
804 #else /* not TARGET_API_MAC_CARBON */
805 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
806 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
807 #endif /* not TARGET_API_MAC_CARBON */
808 UnlockPixels (GetGWorldPixMap (pixmap));
809 SetGWorld (old_port, old_gdh);
810 mac_free_bitmap (&bitmap);
812 return pixmap;
816 void
817 XFreePixmap (display, pixmap)
818 Display *display;
819 Pixmap pixmap;
821 DisposeGWorld (pixmap);
825 /* Mac replacement for XFillRectangle. */
827 static void
828 mac_fill_rectangle (f, gc, x, y, width, height)
829 struct frame *f;
830 GC gc;
831 int x, y;
832 unsigned int width, height;
834 #if USE_CG_DRAWING
835 CGContextRef context;
837 context = mac_begin_cg_clip (f, gc);
838 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
839 CGContextFillRect (context, CGRectMake (x, y, width, height));
840 mac_end_cg_clip (f);
841 #else
842 Rect r;
844 mac_begin_clip (f, gc);
845 RGBForeColor (GC_FORE_COLOR (gc));
846 SetRect (&r, x, y, x + width, y + height);
847 PaintRect (&r); /* using foreground color of gc */
848 mac_end_clip (gc);
849 #endif
853 /* Mac replacement for XDrawRectangle: dest is a window. */
855 static void
856 mac_draw_rectangle (f, gc, x, y, width, height)
857 struct frame *f;
858 GC gc;
859 int x, y;
860 unsigned int width, height;
862 #if USE_CG_DRAWING
863 CGContextRef context;
865 context = mac_begin_cg_clip (f, gc);
866 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
867 CGContextStrokeRect (context,
868 CGRectMake (x + 0.5f, y + 0.5f, width, height));
869 mac_end_cg_clip (f);
870 #else
871 Rect r;
873 mac_begin_clip (f, gc);
874 RGBForeColor (GC_FORE_COLOR (gc));
875 SetRect (&r, x, y, x + width + 1, y + height + 1);
876 FrameRect (&r); /* using foreground color of gc */
877 mac_end_clip (gc);
878 #endif
882 static void
883 mac_invert_rectangle (f, x, y, width, height)
884 struct frame *f;
885 int x, y;
886 unsigned int width, height;
888 Rect r;
890 #if USE_CG_DRAWING
891 mac_prepare_for_quickdraw (f);
892 #endif
893 SetPortWindowPort (FRAME_MAC_WINDOW (f));
895 SetRect (&r, x, y, x + width, y + height);
897 InvertRect (&r);
901 #if USE_ATSUI
902 static OSStatus
903 atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
904 ConstUniCharArrayPtr text;
905 UniCharCount text_length;
906 ATSUStyle style;
907 ATSUTextLayout *text_layout;
909 OSStatus err;
910 static ATSUTextLayout saved_text_layout = NULL;
912 if (saved_text_layout == NULL)
914 static const UniCharCount lengths[] = {kATSUToTextEnd};
915 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
916 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
917 static ATSLineLayoutOptions line_layout =
918 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
919 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
920 | kATSLineUseQDRendering
921 #else
922 kATSLineIsDisplayOnly | kATSLineFractDisable
923 #endif
925 static const ATSUAttributeValuePtr values[] = {&line_layout};
927 err = ATSUCreateTextLayoutWithTextPtr (text,
928 kATSUFromTextBeginning,
929 kATSUToTextEnd,
930 text_length,
931 1, lengths, &style,
932 &saved_text_layout);
933 if (err == noErr)
934 err = ATSUSetLayoutControls (saved_text_layout,
935 sizeof (tags) / sizeof (tags[0]),
936 tags, sizes, values);
937 if (err == noErr)
938 err = ATSUSetTransientFontMatching (saved_text_layout, true);
940 else
942 err = ATSUSetRunStyle (saved_text_layout, style,
943 kATSUFromTextBeginning, kATSUToTextEnd);
944 if (err == noErr)
945 err = ATSUSetTextPointerLocation (saved_text_layout, text,
946 kATSUFromTextBeginning,
947 kATSUToTextEnd,
948 text_length);
951 if (err == noErr)
952 *text_layout = saved_text_layout;
953 return err;
957 static void
958 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
959 overstrike_p, bytes_per_char)
960 struct frame *f;
961 GC gc;
962 int x, y;
963 char *buf;
964 int nchars, bg_width, overstrike_p, bytes_per_char;
966 OSStatus err;
967 ATSUTextLayout text_layout;
969 xassert (bytes_per_char == 2);
971 #ifndef WORDS_BIG_ENDIAN
973 int i;
974 UniChar *text = (UniChar *)buf;
976 for (i = 0; i < nchars; i++)
977 text[i] = EndianU16_BtoN (text[i]);
979 #endif
980 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
981 nchars,
982 GC_FONT (gc)->mac_style,
983 &text_layout);
984 if (err != noErr)
985 return;
986 #ifdef MAC_OSX
987 if (!mac_use_core_graphics)
989 #endif
990 mac_begin_clip (f, gc);
991 RGBForeColor (GC_FORE_COLOR (gc));
992 if (bg_width)
994 Rect r;
996 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
997 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
998 RGBBackColor (GC_BACK_COLOR (gc));
999 EraseRect (&r);
1000 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1002 MoveTo (x, y);
1003 ATSUDrawText (text_layout,
1004 kATSUFromTextBeginning, kATSUToTextEnd,
1005 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1006 if (overstrike_p)
1008 MoveTo (x + 1, y);
1009 ATSUDrawText (text_layout,
1010 kATSUFromTextBeginning, kATSUToTextEnd,
1011 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1013 mac_end_clip (gc);
1014 #ifdef MAC_OSX
1016 else
1018 static CGContextRef context;
1019 float port_height = FRAME_PIXEL_HEIGHT (f);
1020 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1021 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1022 static const ATSUAttributeValuePtr values[] = {&context};
1024 #if USE_CG_DRAWING
1025 context = mac_begin_cg_clip (f, gc);
1026 #else
1027 CGrafPtr port;
1029 GetPort (&port);
1030 QDBeginCGContext (port, &context);
1031 if (gc->n_clip_rects || bg_width)
1033 CGContextTranslateCTM (context, 0, port_height);
1034 CGContextScaleCTM (context, 1, -1);
1035 if (gc->n_clip_rects)
1036 CGContextClipToRects (context, gc->clip_rects,
1037 gc->n_clip_rects);
1038 #endif
1039 if (bg_width)
1041 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1042 CGContextFillRect (context,
1043 CGRectMake (x, y - FONT_BASE (GC_FONT (gc)),
1044 bg_width,
1045 FONT_HEIGHT (GC_FONT (gc))));
1047 CGContextScaleCTM (context, 1, -1);
1048 CGContextTranslateCTM (context, 0, -port_height);
1049 #if !USE_CG_DRAWING
1051 #endif
1052 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1053 err = ATSUSetLayoutControls (text_layout,
1054 sizeof (tags) / sizeof (tags[0]),
1055 tags, sizes, values);
1056 if (err == noErr)
1058 ATSUDrawText (text_layout,
1059 kATSUFromTextBeginning, kATSUToTextEnd,
1060 Long2Fix (x), Long2Fix (port_height - y));
1061 if (overstrike_p)
1062 ATSUDrawText (text_layout,
1063 kATSUFromTextBeginning, kATSUToTextEnd,
1064 Long2Fix (x + 1), Long2Fix (port_height - y));
1066 #if USE_CG_DRAWING
1067 mac_end_cg_clip (f);
1068 context = NULL;
1069 #else
1070 CGContextSynchronize (context);
1071 QDEndCGContext (port, &context);
1072 #endif
1073 #if 0
1074 /* This doesn't work on Mac OS X 10.1. */
1075 ATSUClearLayoutControls (text_layout,
1076 sizeof (tags) / sizeof (tags[0]), tags);
1077 #else
1078 ATSUSetLayoutControls (text_layout,
1079 sizeof (tags) / sizeof (tags[0]),
1080 tags, sizes, values);
1081 #endif
1083 #endif /* MAC_OSX */
1085 #endif /* USE_ATSUI */
1088 static void
1089 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1090 overstrike_p, bytes_per_char)
1091 struct frame *f;
1092 GC gc;
1093 int x, y;
1094 char *buf;
1095 int nchars, bg_width, overstrike_p, bytes_per_char;
1097 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1098 UInt32 savedFlags;
1099 #endif
1101 mac_begin_clip (f, gc);
1102 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1103 if (mac_use_core_graphics)
1104 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
1105 #endif
1106 RGBForeColor (GC_FORE_COLOR (gc));
1107 #ifdef MAC_OS8
1108 if (bg_width)
1110 RGBBackColor (GC_BACK_COLOR (gc));
1111 TextMode (srcCopy);
1113 else
1114 TextMode (srcOr);
1115 #else
1116 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1117 because:
1118 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1119 into an offscreen graphics world first. So performance gain
1120 cannot be expected.)
1121 - It lowers rendering quality.
1122 - Some fonts leave garbage on cursor movement. */
1123 if (bg_width)
1125 Rect r;
1127 RGBBackColor (GC_BACK_COLOR (gc));
1128 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1129 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1130 EraseRect (&r);
1132 TextMode (srcOr);
1133 #endif
1134 TextFont (GC_FONT (gc)->mac_fontnum);
1135 TextSize (GC_FONT (gc)->mac_fontsize);
1136 TextFace (GC_FONT (gc)->mac_fontface);
1137 MoveTo (x, y);
1138 DrawText (buf, 0, nchars * bytes_per_char);
1139 if (overstrike_p)
1141 TextMode (srcOr);
1142 MoveTo (x + 1, y);
1143 DrawText (buf, 0, nchars * bytes_per_char);
1145 if (bg_width)
1146 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1147 mac_end_clip (gc);
1149 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1150 if (mac_use_core_graphics)
1151 SwapQDTextFlags(savedFlags);
1152 #endif
1156 static INLINE void
1157 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1158 overstrike_p, bytes_per_char)
1159 struct frame *f;
1160 GC gc;
1161 int x, y;
1162 char *buf;
1163 int nchars, bg_width, overstrike_p, bytes_per_char;
1165 #if USE_ATSUI
1166 if (GC_FONT (gc)->mac_style)
1167 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1168 overstrike_p, bytes_per_char);
1169 else
1170 #endif /* USE_ATSUI */
1171 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1172 overstrike_p, bytes_per_char);
1176 /* Mac replacement for XDrawImageString. */
1178 static void
1179 mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1180 struct frame *f;
1181 GC gc;
1182 int x, y;
1183 char *buf;
1184 int nchars, bg_width, overstrike_p;
1186 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1187 overstrike_p, 1);
1191 /* Mac replacement for XDrawImageString16. */
1193 static void
1194 mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1195 struct frame *f;
1196 GC gc;
1197 int x, y;
1198 XChar2b *buf;
1199 int nchars, bg_width, overstrike_p;
1201 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1202 overstrike_p, 2);
1206 /* Mac replacement for XQueryTextExtents, but takes a character. If
1207 STYLE is NULL, measurement is done by QuickDraw Text routines for
1208 the font of the current graphics port. If CG_GLYPH is not NULL,
1209 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1211 static OSStatus
1212 mac_query_char_extents (style, c,
1213 font_ascent_return, font_descent_return,
1214 overall_return, cg_glyph)
1215 #if USE_ATSUI
1216 ATSUStyle style;
1217 #else
1218 void *style;
1219 #endif
1220 int c;
1221 int *font_ascent_return, *font_descent_return;
1222 XCharStruct *overall_return;
1223 #if USE_CG_TEXT_DRAWING
1224 CGGlyph *cg_glyph;
1225 #else
1226 void *cg_glyph;
1227 #endif
1229 OSStatus err = noErr;
1230 int width;
1231 Rect char_bounds;
1233 #if USE_ATSUI
1234 if (style)
1236 ATSUTextLayout text_layout;
1237 UniChar ch = c;
1239 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
1240 if (err == noErr
1241 && (font_ascent_return || font_descent_return || overall_return))
1243 ATSTrapezoid glyph_bounds;
1245 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1246 kATSUFromTextBeginning, kATSUToTextEnd,
1247 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1248 kATSUseFractionalOrigins,
1249 #else
1250 kATSUseDeviceOrigins,
1251 #endif
1252 1, &glyph_bounds, NULL);
1253 if (err == noErr)
1255 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1256 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1258 width = Fix2Long (glyph_bounds.upperRight.x
1259 - glyph_bounds.upperLeft.x);
1260 if (font_ascent_return)
1261 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1262 if (font_descent_return)
1263 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1266 if (err == noErr && overall_return)
1268 err = ATSUMeasureTextImage (text_layout,
1269 kATSUFromTextBeginning, kATSUToTextEnd,
1270 0, 0, &char_bounds);
1271 if (err == noErr)
1272 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1273 #if USE_CG_TEXT_DRAWING
1274 if (err == noErr && cg_glyph)
1276 OSStatus err1;
1277 ATSUGlyphInfoArray glyph_info_array;
1278 ByteCount count = sizeof (ATSUGlyphInfoArray);
1280 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1281 kATSUToTextEnd, NULL, NULL, NULL);
1282 if (err1 == noErr)
1283 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1284 kATSUToTextEnd, &count,
1285 &glyph_info_array);
1286 if (err1 == noErr
1287 /* Make sure that we don't have to make layout
1288 adjustments. */
1289 && glyph_info_array.glyphs[0].deltaY == 0.0f
1290 && glyph_info_array.glyphs[0].idealX == 0.0f
1291 && glyph_info_array.glyphs[0].screenX == 0)
1293 xassert (glyph_info_array.glyphs[0].glyphID);
1294 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1296 else
1297 *cg_glyph = 0;
1299 #endif
1302 else
1303 #endif
1305 if (font_ascent_return || font_descent_return)
1307 FontInfo font_info;
1309 GetFontInfo (&font_info);
1310 if (font_ascent_return)
1311 *font_ascent_return = font_info.ascent;
1312 if (font_descent_return)
1313 *font_descent_return = font_info.descent;
1315 if (overall_return)
1317 char ch = c;
1319 width = CharWidth (ch);
1320 QDTextBounds (1, &ch, &char_bounds);
1321 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1325 return err;
1329 /* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1331 static int
1332 mac_text_extents_16 (font_struct, string, nchars, overall_return)
1333 XFontStruct *font_struct;
1334 XChar2b *string;
1335 int nchars;
1336 XCharStruct *overall_return;
1338 int i;
1339 short width = 0, lbearing = 0, rbearing = 0;
1340 XCharStruct *pcm;
1342 for (i = 0; i < nchars; i++)
1344 pcm = mac_per_char_metric (font_struct, string, 0);
1345 if (pcm == NULL)
1346 width += FONT_WIDTH (font_struct);
1347 else
1349 lbearing = min (lbearing, width + pcm->lbearing);
1350 rbearing = max (rbearing, width + pcm->rbearing);
1351 width += pcm->width;
1353 string++;
1356 overall_return->lbearing = lbearing;
1357 overall_return->rbearing = rbearing;
1358 overall_return->width = width;
1360 /* What's the meaning of the return value of XTextExtents16? */
1364 #if USE_CG_TEXT_DRAWING
1365 static int cg_text_anti_aliasing_threshold = 8;
1367 static void
1368 init_cg_text_anti_aliasing_threshold ()
1370 int threshold;
1371 Boolean valid_p;
1373 threshold =
1374 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1375 kCFPreferencesCurrentApplication,
1376 &valid_p);
1377 if (valid_p)
1378 cg_text_anti_aliasing_threshold = threshold;
1381 static int
1382 mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1383 struct frame *f;
1384 GC gc;
1385 int x, y;
1386 XChar2b *buf;
1387 int nchars, bg_width, overstrike_p;
1389 float port_height, gx, gy;
1390 int i;
1391 CGContextRef context;
1392 CGGlyph *glyphs;
1393 CGSize *advances;
1395 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
1396 return 0;
1398 port_height = FRAME_PIXEL_HEIGHT (f);
1399 gx = x;
1400 gy = port_height - y;
1401 glyphs = (CGGlyph *)buf;
1402 advances = alloca (sizeof (CGSize) * nchars);
1403 if (advances == NULL)
1404 return 0;
1405 for (i = 0; i < nchars; i++)
1407 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1409 advances[i].width = pcm->width;
1410 advances[i].height = 0;
1411 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1412 buf++;
1415 #if USE_CG_DRAWING
1416 context = mac_begin_cg_clip (f, gc);
1417 #else
1418 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1419 if (gc->n_clip_rects || bg_width)
1421 CGContextTranslateCTM (context, 0, port_height);
1422 CGContextScaleCTM (context, 1, -1);
1423 if (gc->n_clip_rects)
1424 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1425 #endif
1426 if (bg_width)
1428 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1429 CGContextFillRect
1430 (context,
1431 CGRectMake (gx, y - FONT_BASE (GC_FONT (gc)),
1432 bg_width, FONT_HEIGHT (GC_FONT (gc))));
1434 CGContextScaleCTM (context, 1, -1);
1435 CGContextTranslateCTM (context, 0, -port_height);
1436 #if !USE_CG_DRAWING
1438 #endif
1439 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1440 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1441 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
1442 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1443 CGContextSetShouldAntialias (context, false);
1444 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1445 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1446 if (CGContextShowGlyphsWithAdvances != NULL)
1447 #endif
1449 CGContextSetTextPosition (context, gx, gy);
1450 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1451 if (overstrike_p)
1453 CGContextSetTextPosition (context, gx + 1.0f, gy);
1454 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1457 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1458 else /* CGContextShowGlyphsWithAdvances == NULL */
1459 #endif
1460 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1461 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1463 for (i = 0; i < nchars; i++)
1465 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1466 if (overstrike_p)
1467 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1468 gx += advances[i].width;
1471 #endif
1472 #if USE_CG_DRAWING
1473 mac_end_cg_clip (f);
1474 #else
1475 CGContextSynchronize (context);
1476 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1477 #endif
1479 return 1;
1481 #endif
1484 #if !USE_CG_DRAWING
1485 /* Mac replacement for XCopyArea: dest must be window. */
1487 static void
1488 mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1489 Pixmap src;
1490 struct frame *f;
1491 GC gc;
1492 int src_x, src_y;
1493 unsigned int width, height;
1494 int dest_x, dest_y;
1496 Rect src_r, dest_r;
1498 mac_begin_clip (f, gc);
1500 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1501 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1503 ForeColor (blackColor);
1504 BackColor (whiteColor);
1506 LockPixels (GetGWorldPixMap (src));
1507 #if TARGET_API_MAC_CARBON
1509 CGrafPtr port;
1511 GetPort (&port);
1512 LockPortBits (port);
1513 CopyBits (GetPortBitMapForCopyBits (src),
1514 GetPortBitMapForCopyBits (port),
1515 &src_r, &dest_r, srcCopy, 0);
1516 UnlockPortBits (port);
1518 #else /* not TARGET_API_MAC_CARBON */
1519 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
1520 &src_r, &dest_r, srcCopy, 0);
1521 #endif /* not TARGET_API_MAC_CARBON */
1522 UnlockPixels (GetGWorldPixMap (src));
1524 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1526 mac_end_clip (gc);
1530 static void
1531 mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
1532 width, height, dest_x, dest_y)
1533 Pixmap src, mask;
1534 struct frame *f;
1535 GC gc;
1536 int src_x, src_y;
1537 unsigned int width, height;
1538 int dest_x, dest_y;
1540 Rect src_r, dest_r;
1542 mac_begin_clip (f, gc);
1544 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1545 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1547 ForeColor (blackColor);
1548 BackColor (whiteColor);
1550 LockPixels (GetGWorldPixMap (src));
1551 LockPixels (GetGWorldPixMap (mask));
1552 #if TARGET_API_MAC_CARBON
1554 CGrafPtr port;
1556 GetPort (&port);
1557 LockPortBits (port);
1558 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1559 GetPortBitMapForCopyBits (port),
1560 &src_r, &src_r, &dest_r);
1561 UnlockPortBits (port);
1563 #else /* not TARGET_API_MAC_CARBON */
1564 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
1565 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
1566 #endif /* not TARGET_API_MAC_CARBON */
1567 UnlockPixels (GetGWorldPixMap (mask));
1568 UnlockPixels (GetGWorldPixMap (src));
1570 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1572 mac_end_clip (gc);
1574 #endif /* !USE_CG_DRAWING */
1577 /* Mac replacement for XCopyArea: used only for scrolling. */
1579 static void
1580 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1581 struct frame *f;
1582 GC gc;
1583 int src_x, src_y;
1584 unsigned int width, height;
1585 int dest_x, dest_y;
1587 #if TARGET_API_MAC_CARBON
1588 Rect src_r;
1589 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1591 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1592 #if USE_CG_DRAWING
1593 mac_prepare_for_quickdraw (f);
1594 #endif
1595 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1596 &src_r, dest_x - src_x, dest_y - src_y,
1597 kScrollWindowNoOptions, dummy);
1598 DisposeRgn (dummy);
1599 #else /* not TARGET_API_MAC_CARBON */
1600 Rect src_r, dest_r;
1601 WindowRef w = FRAME_MAC_WINDOW (f);
1603 mac_begin_clip (f, gc);
1605 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1606 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1608 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1609 color mapping in CopyBits. Otherwise, it will be slow. */
1610 ForeColor (blackColor);
1611 BackColor (whiteColor);
1612 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
1614 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1616 mac_end_clip (gc);
1617 #endif /* not TARGET_API_MAC_CARBON */
1621 /* Mac replacement for XChangeGC. */
1623 static void
1624 XChangeGC (display, gc, mask, xgcv)
1625 Display *display;
1626 GC gc;
1627 unsigned long mask;
1628 XGCValues *xgcv;
1630 if (mask & GCForeground)
1631 XSetForeground (display, gc, xgcv->foreground);
1632 if (mask & GCBackground)
1633 XSetBackground (display, gc, xgcv->background);
1634 if (mask & GCFont)
1635 XSetFont (display, gc, xgcv->font);
1639 /* Mac replacement for XCreateGC. */
1642 XCreateGC (display, d, mask, xgcv)
1643 Display *display;
1644 void *d;
1645 unsigned long mask;
1646 XGCValues *xgcv;
1648 GC gc = xmalloc (sizeof (*gc));
1650 bzero (gc, sizeof (*gc));
1651 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1652 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1653 if (CGColorGetTypeID != NULL)
1654 #endif
1656 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1657 CGColorRetain (gc->cg_fore_color);
1658 CGColorRetain (gc->cg_back_color);
1660 #endif
1661 XChangeGC (display, gc, mask, xgcv);
1663 return gc;
1667 /* Used in xfaces.c. */
1669 void
1670 XFreeGC (display, gc)
1671 Display *display;
1672 GC gc;
1674 if (gc->clip_region)
1675 DisposeRgn (gc->clip_region);
1676 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1677 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1678 if (CGColorGetTypeID != NULL)
1679 #endif
1681 CGColorRelease (gc->cg_fore_color);
1682 CGColorRelease (gc->cg_back_color);
1684 #endif
1685 xfree (gc);
1689 /* Mac replacement for XGetGCValues. */
1691 static void
1692 XGetGCValues (display, gc, mask, xgcv)
1693 Display *display;
1694 GC gc;
1695 unsigned long mask;
1696 XGCValues *xgcv;
1698 if (mask & GCForeground)
1699 xgcv->foreground = gc->xgcv.foreground;
1700 if (mask & GCBackground)
1701 xgcv->background = gc->xgcv.background;
1702 if (mask & GCFont)
1703 xgcv->font = gc->xgcv.font;
1707 /* Mac replacement for XSetForeground. */
1709 void
1710 XSetForeground (display, gc, color)
1711 Display *display;
1712 GC gc;
1713 unsigned long color;
1715 if (gc->xgcv.foreground != color)
1717 gc->xgcv.foreground = color;
1718 gc->fore_color.red = RED16_FROM_ULONG (color);
1719 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1720 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
1721 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1722 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1723 if (CGColorGetTypeID != NULL)
1724 #endif
1726 CGColorRelease (gc->cg_fore_color);
1727 if (color == 0)
1729 gc->cg_fore_color = mac_cg_color_black;
1730 CGColorRetain (gc->cg_fore_color);
1732 else
1734 float rgba[4];
1736 rgba[0] = gc->fore_color.red / 65535.0f;
1737 rgba[1] = gc->fore_color.green / 65535.0f;
1738 rgba[2] = gc->fore_color.blue / 65535.0f;
1739 rgba[3] = 1.0f;
1740 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1743 #endif
1748 /* Mac replacement for XSetBackground. */
1750 void
1751 XSetBackground (display, gc, color)
1752 Display *display;
1753 GC gc;
1754 unsigned long color;
1756 if (gc->xgcv.background != color)
1758 gc->xgcv.background = color;
1759 gc->back_color.red = RED16_FROM_ULONG (color);
1760 gc->back_color.green = GREEN16_FROM_ULONG (color);
1761 gc->back_color.blue = BLUE16_FROM_ULONG (color);
1762 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1763 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1764 if (CGColorGetTypeID != NULL)
1765 #endif
1767 CGColorRelease (gc->cg_back_color);
1768 if (color == 0)
1770 gc->cg_back_color = mac_cg_color_black;
1771 CGColorRetain (gc->cg_back_color);
1773 else
1775 float rgba[4];
1777 rgba[0] = gc->back_color.red / 65535.0f;
1778 rgba[1] = gc->back_color.green / 65535.0f;
1779 rgba[2] = gc->back_color.blue / 65535.0f;
1780 rgba[3] = 1.0f;
1781 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1784 #endif
1789 /* Mac replacement for XSetFont. */
1791 static void
1792 XSetFont (display, gc, font)
1793 Display *display;
1794 GC gc;
1795 XFontStruct *font;
1797 gc->xgcv.font = font;
1801 /* Mac replacement for XSetClipRectangles. */
1803 static void
1804 mac_set_clip_rectangles (display, gc, rectangles, n)
1805 Display *display;
1806 GC gc;
1807 Rect *rectangles;
1808 int n;
1810 int i;
1812 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1814 gc->n_clip_rects = n;
1815 if (n > 0)
1817 if (gc->clip_region == NULL)
1818 gc->clip_region = NewRgn ();
1819 RectRgn (gc->clip_region, rectangles);
1820 if (n > 1)
1822 RgnHandle region = NewRgn ();
1824 for (i = 1; i < n; i++)
1826 RectRgn (region, rectangles + i);
1827 UnionRgn (gc->clip_region, region, gc->clip_region);
1829 DisposeRgn (region);
1832 #if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1833 for (i = 0; i < n; i++)
1835 Rect *rect = rectangles + i;
1837 gc->clip_rects[i] = CGRectMake (rect->left, rect->top,
1838 rect->right - rect->left,
1839 rect->bottom - rect->top);
1841 #endif
1845 /* Mac replacement for XSetClipMask. */
1847 static INLINE void
1848 mac_reset_clip_rectangles (display, gc)
1849 Display *display;
1850 GC gc;
1852 gc->n_clip_rects = 0;
1856 /* Mac replacement for XSetWindowBackground. */
1858 void
1859 XSetWindowBackground (display, w, color)
1860 Display *display;
1861 WindowRef w;
1862 unsigned long color;
1864 #if !TARGET_API_MAC_CARBON
1865 AuxWinHandle aw_handle;
1866 CTabHandle ctab_handle;
1867 ColorSpecPtr ct_table;
1868 short ct_size;
1869 #endif
1870 RGBColor bg_color;
1872 bg_color.red = RED16_FROM_ULONG (color);
1873 bg_color.green = GREEN16_FROM_ULONG (color);
1874 bg_color.blue = BLUE16_FROM_ULONG (color);
1876 #if TARGET_API_MAC_CARBON
1877 SetWindowContentColor (w, &bg_color);
1878 #else
1879 if (GetAuxWin (w, &aw_handle))
1881 ctab_handle = (*aw_handle)->awCTable;
1882 HandToHand ((Handle *) &ctab_handle);
1883 ct_table = (*ctab_handle)->ctTable;
1884 ct_size = (*ctab_handle)->ctSize;
1885 while (ct_size > -1)
1887 if (ct_table->value == 0)
1889 ct_table->rgb = bg_color;
1890 CTabChanged (ctab_handle);
1891 SetWinColor (w, (WCTabHandle) ctab_handle);
1893 ct_size--;
1896 #endif
1899 /* Flush display of frame F, or of all frames if F is null. */
1901 static void
1902 x_flush (f)
1903 struct frame *f;
1905 #if TARGET_API_MAC_CARBON
1906 BLOCK_INPUT;
1907 #if USE_CG_DRAWING
1908 mac_prepare_for_quickdraw (f);
1909 #endif
1910 if (f)
1911 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1912 else
1913 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1914 UNBLOCK_INPUT;
1915 #endif
1919 /* Remove calls to XFlush by defining XFlush to an empty replacement.
1920 Calls to XFlush should be unnecessary because the X output buffer
1921 is flushed automatically as needed by calls to XPending,
1922 XNextEvent, or XWindowEvent according to the XFlush man page.
1923 XTread_socket calls XPending. Removing XFlush improves
1924 performance. */
1926 #define XFlush(DISPLAY) (void) 0
1928 #if USE_CG_DRAWING
1929 static void
1930 mac_flush_display_optional (f)
1931 struct frame *f;
1933 BLOCK_INPUT;
1934 mac_prepare_for_quickdraw (f);
1935 UNBLOCK_INPUT;
1937 #endif
1939 /***********************************************************************
1940 Starting and ending an update
1941 ***********************************************************************/
1943 /* Start an update of frame F. This function is installed as a hook
1944 for update_begin, i.e. it is called when update_begin is called.
1945 This function is called prior to calls to x_update_window_begin for
1946 each window being updated. */
1948 static void
1949 x_update_begin (f)
1950 struct frame *f;
1952 #if TARGET_API_MAC_CARBON
1953 /* During update of a frame, availability of input events is
1954 periodically checked with ReceiveNextEvent if
1955 redisplay-dont-pause is nil. That normally flushes window buffer
1956 changes for every check, and thus screen update looks waving even
1957 if no input is available. So we disable screen updates during
1958 update of a frame. */
1959 BLOCK_INPUT;
1960 DisableScreenUpdates ();
1961 UNBLOCK_INPUT;
1962 #endif
1966 /* Start update of window W. Set the global variable updated_window
1967 to the window being updated and set output_cursor to the cursor
1968 position of W. */
1970 static void
1971 x_update_window_begin (w)
1972 struct window *w;
1974 struct frame *f = XFRAME (WINDOW_FRAME (w));
1975 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
1977 updated_window = w;
1978 set_output_cursor (&w->cursor);
1980 BLOCK_INPUT;
1982 if (f == display_info->mouse_face_mouse_frame)
1984 /* Don't do highlighting for mouse motion during the update. */
1985 display_info->mouse_face_defer = 1;
1987 /* If F needs to be redrawn, simply forget about any prior mouse
1988 highlighting. */
1989 if (FRAME_GARBAGED_P (f))
1990 display_info->mouse_face_window = Qnil;
1992 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
1993 their mouse_face_p flag set, which means that they are always
1994 unequal to rows in a desired matrix which never have that
1995 flag set. So, rows containing mouse-face glyphs are never
1996 scrolled, and we don't have to switch the mouse highlight off
1997 here to prevent it from being scrolled. */
1999 /* Can we tell that this update does not affect the window
2000 where the mouse highlight is? If so, no need to turn off.
2001 Likewise, don't do anything if the frame is garbaged;
2002 in that case, the frame's current matrix that we would use
2003 is all wrong, and we will redisplay that line anyway. */
2004 if (!NILP (display_info->mouse_face_window)
2005 && w == XWINDOW (display_info->mouse_face_window))
2007 int i;
2009 for (i = 0; i < w->desired_matrix->nrows; ++i)
2010 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2011 break;
2013 if (i < w->desired_matrix->nrows)
2014 clear_mouse_face (display_info);
2016 #endif /* 0 */
2019 UNBLOCK_INPUT;
2023 /* Draw a vertical window border from (x,y0) to (x,y1) */
2025 static void
2026 mac_draw_vertical_window_border (w, x, y0, y1)
2027 struct window *w;
2028 int x, y0, y1;
2030 struct frame *f = XFRAME (WINDOW_FRAME (w));
2031 struct face *face;
2033 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2034 if (face)
2035 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2036 face->foreground);
2038 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
2041 /* End update of window W (which is equal to updated_window).
2043 Draw vertical borders between horizontally adjacent windows, and
2044 display W's cursor if CURSOR_ON_P is non-zero.
2046 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2047 glyphs in mouse-face were overwritten. In that case we have to
2048 make sure that the mouse-highlight is properly redrawn.
2050 W may be a menu bar pseudo-window in case we don't have X toolkit
2051 support. Such windows don't have a cursor, so don't display it
2052 here. */
2054 static void
2055 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2056 struct window *w;
2057 int cursor_on_p, mouse_face_overwritten_p;
2059 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
2061 if (!w->pseudo_window_p)
2063 BLOCK_INPUT;
2065 if (cursor_on_p)
2066 display_and_set_cursor (w, 1, output_cursor.hpos,
2067 output_cursor.vpos,
2068 output_cursor.x, output_cursor.y);
2070 if (draw_window_fringes (w, 1))
2071 x_draw_vertical_border (w);
2073 UNBLOCK_INPUT;
2076 /* If a row with mouse-face was overwritten, arrange for
2077 XTframe_up_to_date to redisplay the mouse highlight. */
2078 if (mouse_face_overwritten_p)
2080 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2081 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2082 dpyinfo->mouse_face_window = Qnil;
2085 updated_window = NULL;
2089 /* End update of frame F. This function is installed as a hook in
2090 update_end. */
2092 static void
2093 x_update_end (f)
2094 struct frame *f;
2096 /* Mouse highlight may be displayed again. */
2097 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2099 BLOCK_INPUT;
2100 #if TARGET_API_MAC_CARBON
2101 EnableScreenUpdates ();
2102 #endif
2103 XFlush (FRAME_MAC_DISPLAY (f));
2104 UNBLOCK_INPUT;
2108 /* This function is called from various places in xdisp.c whenever a
2109 complete update has been performed. The global variable
2110 updated_window is not available here. */
2112 static void
2113 XTframe_up_to_date (f)
2114 struct frame *f;
2116 if (FRAME_MAC_P (f))
2118 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2120 if (dpyinfo->mouse_face_deferred_gc
2121 || f == dpyinfo->mouse_face_mouse_frame)
2123 BLOCK_INPUT;
2124 if (dpyinfo->mouse_face_mouse_frame)
2125 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2126 dpyinfo->mouse_face_mouse_x,
2127 dpyinfo->mouse_face_mouse_y);
2128 dpyinfo->mouse_face_deferred_gc = 0;
2129 UNBLOCK_INPUT;
2135 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
2136 arrow bitmaps, or clear the fringes if no bitmaps are required
2137 before DESIRED_ROW is made current. The window being updated is
2138 found in updated_window. This function is called from
2139 update_window_line only if it is known that there are differences
2140 between bitmaps to be drawn between current row and DESIRED_ROW. */
2142 static void
2143 x_after_update_window_line (desired_row)
2144 struct glyph_row *desired_row;
2146 struct window *w = updated_window;
2147 struct frame *f;
2148 int width, height;
2150 xassert (w);
2152 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2153 desired_row->redraw_fringe_bitmaps_p = 1;
2155 /* When a window has disappeared, make sure that no rest of
2156 full-width rows stays visible in the internal border. Could
2157 check here if updated_window is the leftmost/rightmost window,
2158 but I guess it's not worth doing since vertically split windows
2159 are almost never used, internal border is rarely set, and the
2160 overhead is very small. */
2161 if (windows_or_buffers_changed
2162 && desired_row->full_width_p
2163 && (f = XFRAME (w->frame),
2164 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2165 width != 0)
2166 && (height = desired_row->visible_height,
2167 height > 0))
2169 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2171 /* Internal border is drawn below the tool bar. */
2172 if (WINDOWP (f->tool_bar_window)
2173 && w == XWINDOW (f->tool_bar_window))
2174 y -= width;
2176 BLOCK_INPUT;
2177 mac_clear_area (f, 0, y, width, height);
2178 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
2179 UNBLOCK_INPUT;
2184 /* Draw the bitmap WHICH in one of the left or right fringes of
2185 window W. ROW is the glyph row for which to display the bitmap; it
2186 determines the vertical position at which the bitmap has to be
2187 drawn. */
2189 static void
2190 x_draw_fringe_bitmap (w, row, p)
2191 struct window *w;
2192 struct glyph_row *row;
2193 struct draw_fringe_bitmap_params *p;
2195 struct frame *f = XFRAME (WINDOW_FRAME (w));
2196 Display *display = FRAME_MAC_DISPLAY (f);
2197 struct face *face = p->face;
2198 int rowY;
2199 int overlay_p = p->overlay_p;
2201 #ifdef MAC_OSX
2202 if (!overlay_p)
2204 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2206 #if 0 /* MAC_TODO: stipple */
2207 /* In case the same realized face is used for fringes and
2208 for something displayed in the text (e.g. face `region' on
2209 mono-displays, the fill style may have been changed to
2210 FillSolid in x_draw_glyph_string_background. */
2211 if (face->stipple)
2212 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2213 else
2214 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2215 #endif
2217 /* If the fringe is adjacent to the left (right) scroll bar of a
2218 leftmost (rightmost, respectively) window, then extend its
2219 background to the gap between the fringe and the bar. */
2220 if ((WINDOW_LEFTMOST_P (w)
2221 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2222 || (WINDOW_RIGHTMOST_P (w)
2223 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2225 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2227 if (sb_width > 0)
2229 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2230 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2231 * FRAME_COLUMN_WIDTH (f));
2233 if (bx < 0
2234 && (left + width == p->x
2235 || p->x + p->wd == left))
2237 /* Bitmap fills the fringe and we need background
2238 extension. */
2239 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2241 bx = p->x;
2242 nx = p->wd;
2243 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2244 row->y));
2245 ny = row->visible_height;
2248 if (bx >= 0)
2250 if (left + width == bx)
2252 bx = left + sb_width;
2253 nx += width - sb_width;
2255 else if (bx + nx == left)
2256 nx += width - sb_width;
2261 if (bx >= 0)
2263 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2264 /* The fringe background has already been filled. */
2265 overlay_p = 1;
2268 #if 0 /* MAC_TODO: stipple */
2269 if (!face->stipple)
2270 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2271 #endif
2273 #endif /* MAC_OSX */
2275 /* Must clip because of partially visible lines. */
2276 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2277 if (p->y < rowY)
2279 /* Adjust position of "bottom aligned" bitmap on partially
2280 visible last row. */
2281 int oldY = row->y;
2282 int oldVH = row->visible_height;
2283 row->visible_height = p->h;
2284 row->y -= rowY - p->y;
2285 x_clip_to_row (w, row, -1, face->gc);
2286 row->y = oldY;
2287 row->visible_height = oldVH;
2289 else
2290 x_clip_to_row (w, row, -1, face->gc);
2292 #ifndef MAC_OSX
2293 if (p->bx >= 0 && !p->overlay_p)
2295 #if 0 /* MAC_TODO: stipple */
2296 /* In case the same realized face is used for fringes and
2297 for something displayed in the text (e.g. face `region' on
2298 mono-displays, the fill style may have been changed to
2299 FillSolid in x_draw_glyph_string_background. */
2300 if (face->stipple)
2301 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2302 else
2303 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2304 #endif
2306 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
2308 #if 0 /* MAC_TODO: stipple */
2309 if (!face->stipple)
2310 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2311 #endif
2313 #endif /* !MAC_OSX */
2315 if (p->which
2316 #if USE_CG_DRAWING
2317 && p->which < max_fringe_bmp
2318 #endif
2321 XGCValues gcv;
2323 XGetGCValues (display, face->gc, GCForeground, &gcv);
2324 XSetForeground (display, face->gc,
2325 (p->cursor_p
2326 ? (p->overlay_p ? face->background
2327 : f->output_data.mac->cursor_pixel)
2328 : face->foreground));
2329 #if USE_CG_DRAWING
2330 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
2331 p->wd, p->h, p->x, p->y, overlay_p);
2332 #else
2333 mac_draw_bitmap (f, face->gc, p->x, p->y,
2334 p->wd, p->h, p->bits + p->dh, overlay_p);
2335 #endif
2336 XSetForeground (display, face->gc, gcv.foreground);
2339 mac_reset_clip_rectangles (display, face->gc);
2342 #if USE_CG_DRAWING
2343 static void
2344 mac_define_fringe_bitmap (which, bits, h, wd)
2345 int which;
2346 unsigned short *bits;
2347 int h, wd;
2349 int i;
2350 CGDataProviderRef provider;
2352 if (which >= max_fringe_bmp)
2354 i = max_fringe_bmp;
2355 max_fringe_bmp = which + 20;
2356 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2357 while (i < max_fringe_bmp)
2358 fringe_bmp[i++] = 0;
2361 for (i = 0; i < h; i++)
2362 bits[i] = ~bits[i];
2364 BLOCK_INPUT;
2366 provider = CGDataProviderCreateWithData (NULL, bits,
2367 sizeof (unsigned short) * h, NULL);
2368 if (provider)
2370 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2371 sizeof (unsigned short),
2372 provider, NULL, 0);
2373 CGDataProviderRelease (provider);
2376 UNBLOCK_INPUT;
2379 static void
2380 mac_destroy_fringe_bitmap (which)
2381 int which;
2383 if (which >= max_fringe_bmp)
2384 return;
2386 if (fringe_bmp[which])
2388 BLOCK_INPUT;
2389 CGImageRelease (fringe_bmp[which]);
2390 UNBLOCK_INPUT;
2392 fringe_bmp[which] = 0;
2394 #endif
2397 /* This is called when starting Emacs and when restarting after
2398 suspend. When starting Emacs, no window is mapped. And nothing
2399 must be done to Emacs's own window if it is suspended (though that
2400 rarely happens). */
2402 static void
2403 XTset_terminal_modes (struct terminal *t)
2407 /* This is called when exiting or suspending Emacs. Exiting will make
2408 the windows go away, and suspending requires no action. */
2410 static void
2411 XTreset_terminal_modes (struct terminal *t)
2417 /***********************************************************************
2418 Display Iterator
2419 ***********************************************************************/
2421 /* Function prototypes of this page. */
2423 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
2424 static int mac_encode_char P_ ((int, XChar2b *, struct font_info *, int *));
2427 static void
2428 pcm_init (pcm, count)
2429 XCharStruct *pcm;
2430 int count;
2432 bzero (pcm, sizeof (XCharStruct) * count);
2433 while (--count >= 0)
2435 pcm->descent = PCM_INVALID;
2436 pcm++;
2440 static enum pcm_status
2441 pcm_get_status (pcm)
2442 const XCharStruct *pcm;
2444 int height = pcm->ascent + pcm->descent;
2446 /* Negative height means some special status. */
2447 return height >= 0 ? PCM_VALID : height;
2450 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2451 is not contained in the font. */
2453 static INLINE XCharStruct *
2454 x_per_char_metric (font, char2b)
2455 XFontStruct *font;
2456 XChar2b *char2b;
2458 /* The result metric information. */
2459 XCharStruct *pcm = NULL;
2461 xassert (font && char2b);
2463 #if USE_ATSUI
2464 if (font->mac_style)
2466 XCharStruct **row = font->bounds.rows + char2b->byte1;
2468 if (*row == NULL)
2470 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2471 pcm_init (*row, 0x100);
2473 pcm = *row + char2b->byte2;
2474 if (pcm_get_status (pcm) != PCM_VALID)
2476 BLOCK_INPUT;
2477 mac_query_char_extents (font->mac_style,
2478 (char2b->byte1 << 8) + char2b->byte2,
2479 NULL, NULL, pcm, NULL);
2480 UNBLOCK_INPUT;
2483 else
2485 #endif
2486 if (font->bounds.per_char != NULL)
2488 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2490 /* min_char_or_byte2 specifies the linear character index
2491 corresponding to the first element of the per_char array,
2492 max_char_or_byte2 is the index of the last character. A
2493 character with non-zero CHAR2B->byte1 is not in the font.
2494 A character with byte2 less than min_char_or_byte2 or
2495 greater max_char_or_byte2 is not in the font. */
2496 if (char2b->byte1 == 0
2497 && char2b->byte2 >= font->min_char_or_byte2
2498 && char2b->byte2 <= font->max_char_or_byte2)
2499 pcm = font->bounds.per_char
2500 + (char2b->byte2 - font->min_char_or_byte2);
2502 else
2504 /* If either min_byte1 or max_byte1 are nonzero, both
2505 min_char_or_byte2 and max_char_or_byte2 are less than
2506 256, and the 2-byte character index values corresponding
2507 to the per_char array element N (counting from 0) are:
2509 byte1 = N/D + min_byte1
2510 byte2 = N\D + min_char_or_byte2
2512 where:
2514 D = max_char_or_byte2 - min_char_or_byte2 + 1
2515 / = integer division
2516 \ = integer modulus */
2517 if (char2b->byte1 >= font->min_byte1
2518 && char2b->byte1 <= font->max_byte1
2519 && char2b->byte2 >= font->min_char_or_byte2
2520 && char2b->byte2 <= font->max_char_or_byte2)
2522 pcm = (font->bounds.per_char
2523 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2524 * (char2b->byte1 - font->min_byte1))
2525 + (char2b->byte2 - font->min_char_or_byte2));
2529 else
2531 /* If the per_char pointer is null, all glyphs between the first
2532 and last character indexes inclusive have the same
2533 information, as given by both min_bounds and max_bounds. */
2534 if (char2b->byte2 >= font->min_char_or_byte2
2535 && char2b->byte2 <= font->max_char_or_byte2)
2536 pcm = &font->max_bounds;
2538 #if USE_ATSUI
2540 #endif
2542 return ((pcm == NULL
2543 || (pcm->width == 0
2544 #if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2545 && (pcm->rbearing - pcm->lbearing) == 0
2546 #endif
2548 ? NULL : pcm);
2551 /* RIF:
2554 static XCharStruct *
2555 mac_per_char_metric (font, char2b, font_type)
2556 XFontStruct *font;
2557 XChar2b *char2b;
2558 int font_type;
2560 return x_per_char_metric (font, char2b);
2563 /* RIF:
2564 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
2565 the two-byte form of C. Encoding is returned in *CHAR2B. */
2567 static int
2568 mac_encode_char (c, char2b, font_info, two_byte_p)
2569 int c;
2570 XChar2b *char2b;
2571 struct font_info *font_info;
2572 int *two_byte_p;
2574 int charset = CHAR_CHARSET (c);
2575 XFontStruct *font = font_info->font;
2577 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2578 This may be either a program in a special encoder language or a
2579 fixed encoding. */
2580 if (font_info->font_encoder)
2582 /* It's a program. */
2583 struct ccl_program *ccl = font_info->font_encoder;
2585 check_ccl_update (ccl);
2586 if (CHARSET_DIMENSION (charset) == 1)
2588 ccl->reg[0] = charset;
2589 ccl->reg[1] = char2b->byte2;
2590 ccl->reg[2] = -1;
2592 else
2594 ccl->reg[0] = charset;
2595 ccl->reg[1] = char2b->byte1;
2596 ccl->reg[2] = char2b->byte2;
2599 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
2601 /* We assume that MSBs are appropriately set/reset by CCL
2602 program. */
2603 if (font->max_byte1 == 0) /* 1-byte font */
2604 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
2605 else
2606 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
2608 else if (font_info->encoding[charset])
2610 /* Fixed encoding scheme. See fontset.h for the meaning of the
2611 encoding numbers. */
2612 int enc = font_info->encoding[charset];
2614 if ((enc == 1 || enc == 2)
2615 && CHARSET_DIMENSION (charset) == 2)
2616 char2b->byte1 |= 0x80;
2618 if (enc == 1 || enc == 3)
2619 char2b->byte2 |= 0x80;
2621 if (enc == 4)
2623 int sjis1, sjis2;
2625 ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2);
2626 char2b->byte1 = sjis1;
2627 char2b->byte2 = sjis2;
2631 if (two_byte_p)
2632 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
2634 return FONT_TYPE_UNKNOWN;
2639 /***********************************************************************
2640 Glyph display
2641 ***********************************************************************/
2645 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2646 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2647 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2648 int));
2649 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2650 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2651 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2652 static void x_draw_glyph_string P_ ((struct glyph_string *));
2653 static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2654 static void x_set_cursor_gc P_ ((struct glyph_string *));
2655 static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2656 static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2657 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2658 unsigned long *, double, int));*/
2659 static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2660 double, int, unsigned long));
2661 static void x_setup_relief_colors P_ ((struct glyph_string *));
2662 static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2663 static void x_draw_image_relief P_ ((struct glyph_string *));
2664 static void x_draw_image_foreground P_ ((struct glyph_string *));
2665 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2666 int, int, int));
2667 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2668 int, int, int, int, int, int,
2669 Rect *));
2670 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2671 int, int, int, Rect *));
2673 #if GLYPH_DEBUG
2674 static void x_check_font P_ ((struct frame *, XFontStruct *));
2675 #endif
2678 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
2679 face. */
2681 static void
2682 x_set_cursor_gc (s)
2683 struct glyph_string *s;
2685 if (s->font == FRAME_FONT (s->f)
2686 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2687 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2688 && !s->cmp)
2689 s->gc = s->f->output_data.mac->cursor_gc;
2690 else
2692 /* Cursor on non-default face: must merge. */
2693 XGCValues xgcv;
2694 unsigned long mask;
2696 xgcv.background = s->f->output_data.mac->cursor_pixel;
2697 xgcv.foreground = s->face->background;
2699 /* If the glyph would be invisible, try a different foreground. */
2700 if (xgcv.foreground == xgcv.background)
2701 xgcv.foreground = s->face->foreground;
2702 if (xgcv.foreground == xgcv.background)
2703 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2704 if (xgcv.foreground == xgcv.background)
2705 xgcv.foreground = s->face->foreground;
2707 /* Make sure the cursor is distinct from text in this face. */
2708 if (xgcv.background == s->face->background
2709 && xgcv.foreground == s->face->foreground)
2711 xgcv.background = s->face->foreground;
2712 xgcv.foreground = s->face->background;
2715 IF_DEBUG (x_check_font (s->f, s->font));
2716 xgcv.font = s->font;
2717 mask = GCForeground | GCBackground | GCFont;
2719 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2720 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2721 mask, &xgcv);
2722 else
2723 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2724 = XCreateGC (s->display, s->window, mask, &xgcv);
2726 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2731 /* Set up S->gc of glyph string S for drawing text in mouse face. */
2733 static void
2734 x_set_mouse_face_gc (s)
2735 struct glyph_string *s;
2737 int face_id;
2738 struct face *face;
2740 /* What face has to be used last for the mouse face? */
2741 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2742 face = FACE_FROM_ID (s->f, face_id);
2743 if (face == NULL)
2744 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2746 if (s->first_glyph->type == CHAR_GLYPH)
2747 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2748 else
2749 face_id = FACE_FOR_CHAR (s->f, face, 0);
2750 s->face = FACE_FROM_ID (s->f, face_id);
2751 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2753 /* If font in this face is same as S->font, use it. */
2754 if (s->font == s->face->font)
2755 s->gc = s->face->gc;
2756 else
2758 /* Otherwise construct scratch_cursor_gc with values from FACE
2759 but font FONT. */
2760 XGCValues xgcv;
2761 unsigned long mask;
2763 xgcv.background = s->face->background;
2764 xgcv.foreground = s->face->foreground;
2765 IF_DEBUG (x_check_font (s->f, s->font));
2766 xgcv.font = s->font;
2767 mask = GCForeground | GCBackground | GCFont;
2769 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2770 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2771 mask, &xgcv);
2772 else
2773 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2774 = XCreateGC (s->display, s->window, mask, &xgcv);
2776 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2779 xassert (s->gc != 0);
2783 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2784 Faces to use in the mode line have already been computed when the
2785 matrix was built, so there isn't much to do, here. */
2787 static INLINE void
2788 x_set_mode_line_face_gc (s)
2789 struct glyph_string *s;
2791 s->gc = s->face->gc;
2795 /* Set S->gc of glyph string S for drawing that glyph string. Set
2796 S->stippled_p to a non-zero value if the face of S has a stipple
2797 pattern. */
2799 static INLINE void
2800 x_set_glyph_string_gc (s)
2801 struct glyph_string *s;
2803 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2805 if (s->hl == DRAW_NORMAL_TEXT)
2807 s->gc = s->face->gc;
2808 s->stippled_p = s->face->stipple != 0;
2810 else if (s->hl == DRAW_INVERSE_VIDEO)
2812 x_set_mode_line_face_gc (s);
2813 s->stippled_p = s->face->stipple != 0;
2815 else if (s->hl == DRAW_CURSOR)
2817 x_set_cursor_gc (s);
2818 s->stippled_p = 0;
2820 else if (s->hl == DRAW_MOUSE_FACE)
2822 x_set_mouse_face_gc (s);
2823 s->stippled_p = s->face->stipple != 0;
2825 else if (s->hl == DRAW_IMAGE_RAISED
2826 || s->hl == DRAW_IMAGE_SUNKEN)
2828 s->gc = s->face->gc;
2829 s->stippled_p = s->face->stipple != 0;
2831 else
2833 s->gc = s->face->gc;
2834 s->stippled_p = s->face->stipple != 0;
2837 /* GC must have been set. */
2838 xassert (s->gc != 0);
2842 /* Set clipping for output of glyph string S. S may be part of a mode
2843 line or menu if we don't have X toolkit support. */
2845 static INLINE void
2846 x_set_glyph_string_clipping (s)
2847 struct glyph_string *s;
2849 Rect rects[MAX_CLIP_RECTS];
2850 int n;
2852 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
2853 mac_set_clip_rectangles (s->display, s->gc, rects, n);
2857 /* RIF:
2858 Compute left and right overhang of glyph string S. If S is a glyph
2859 string for a composition, assume overhangs don't exist. */
2861 static void
2862 mac_compute_glyph_string_overhangs (s)
2863 struct glyph_string *s;
2865 if (!(s->cmp == NULL
2866 && s->first_glyph->type == CHAR_GLYPH))
2867 return;
2869 if (!s->two_byte_p
2870 #if USE_ATSUI
2871 || s->font->mac_style
2872 #endif
2875 XCharStruct cs;
2877 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2878 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2879 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2881 else
2883 Rect r;
2884 MacFontStruct *font = s->font;
2886 #if USE_CG_DRAWING
2887 mac_prepare_for_quickdraw (s->f);
2888 #endif
2889 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
2891 TextFont (font->mac_fontnum);
2892 TextSize (font->mac_fontsize);
2893 TextFace (font->mac_fontface);
2895 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
2897 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
2898 s->left_overhang = r.left < 0 ? -r.left : 0;
2903 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
2905 static INLINE void
2906 x_clear_glyph_string_rect (s, x, y, w, h)
2907 struct glyph_string *s;
2908 int x, y, w, h;
2910 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
2914 /* Draw the background of glyph_string S. If S->background_filled_p
2915 is non-zero don't draw it. FORCE_P non-zero means draw the
2916 background even if it wouldn't be drawn normally. This is used
2917 when a string preceding S draws into the background of S, or S
2918 contains the first component of a composition. */
2920 static void
2921 x_draw_glyph_string_background (s, force_p)
2922 struct glyph_string *s;
2923 int force_p;
2925 /* Nothing to do if background has already been drawn or if it
2926 shouldn't be drawn in the first place. */
2927 if (!s->background_filled_p)
2929 int box_line_width = max (s->face->box_line_width, 0);
2931 #if 0 /* MAC_TODO: stipple */
2932 if (s->stippled_p)
2934 /* Fill background with a stipple pattern. */
2935 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2936 XFillRectangle (s->display, s->window, s->gc, s->x,
2937 s->y + box_line_width,
2938 s->background_width,
2939 s->height - 2 * box_line_width);
2940 XSetFillStyle (s->display, s->gc, FillSolid);
2941 s->background_filled_p = 1;
2943 else
2944 #endif
2945 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2946 || s->font_not_found_p
2947 || s->extends_to_end_of_line_p
2948 || force_p)
2950 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
2951 s->background_width,
2952 s->height - 2 * box_line_width);
2953 s->background_filled_p = 1;
2959 /* Draw the foreground of glyph string S. */
2961 static void
2962 x_draw_glyph_string_foreground (s)
2963 struct glyph_string *s;
2965 int i, x, bg_width;
2967 /* If first glyph of S has a left box line, start drawing the text
2968 of S to the right of that box line. */
2969 if (s->face->box != FACE_NO_BOX
2970 && s->first_glyph->left_box_line_p)
2971 x = s->x + eabs (s->face->box_line_width);
2972 else
2973 x = s->x;
2975 /* Draw characters of S as rectangles if S's font could not be
2976 loaded. */
2977 if (s->font_not_found_p)
2979 for (i = 0; i < s->nchars; ++i)
2981 struct glyph *g = s->first_glyph + i;
2982 mac_draw_rectangle (s->f, s->gc, x, s->y,
2983 g->pixel_width - 1, s->height - 1);
2984 x += g->pixel_width;
2987 else
2989 char *char1b = (char *) s->char2b;
2990 int boff = s->font_info->baseline_offset;
2992 if (s->font_info->vertical_centering)
2993 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
2995 /* If we can use 8-bit functions, condense S->char2b. */
2996 if (!s->two_byte_p
2997 #if USE_ATSUI
2998 && GC_FONT (s->gc)->mac_style == NULL
2999 #endif
3001 for (i = 0; i < s->nchars; ++i)
3002 char1b[i] = s->char2b[i].byte2;
3004 /* Draw text with XDrawString if background has already been
3005 filled. Otherwise, use XDrawImageString. (Note that
3006 XDrawImageString is usually faster than XDrawString.) Always
3007 use XDrawImageString when drawing the cursor so that there is
3008 no chance that characters under a box cursor are invisible. */
3009 if (s->for_overlaps
3010 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3011 bg_width = 0; /* Corresponds to XDrawString. */
3012 else
3013 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3015 if (s->two_byte_p
3016 #if USE_ATSUI
3017 || GC_FONT (s->gc)->mac_style
3018 #endif
3020 #if USE_CG_TEXT_DRAWING
3021 if (!s->two_byte_p
3022 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
3023 s->char2b, s->nchars, bg_width,
3024 s->face->overstrike))
3026 else
3027 #endif
3028 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
3029 s->char2b, s->nchars, bg_width,
3030 s->face->overstrike);
3031 else
3032 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
3033 char1b, s->nchars, bg_width,
3034 s->face->overstrike);
3038 /* Draw the foreground of composite glyph string S. */
3040 static void
3041 x_draw_composite_glyph_string_foreground (s)
3042 struct glyph_string *s;
3044 int i, x;
3046 /* If first glyph of S has a left box line, start drawing the text
3047 of S to the right of that box line. */
3048 if (s->face->box != FACE_NO_BOX
3049 && s->first_glyph->left_box_line_p)
3050 x = s->x + eabs (s->face->box_line_width);
3051 else
3052 x = s->x;
3054 /* S is a glyph string for a composition. S->gidx is the index of
3055 the first character drawn for glyphs of this composition.
3056 S->gidx == 0 means we are drawing the very first character of
3057 this composition. */
3059 /* Draw a rectangle for the composition if the font for the very
3060 first character of the composition could not be loaded. */
3061 if (s->font_not_found_p)
3063 if (s->gidx == 0)
3064 mac_draw_rectangle (s->f, s->gc, x, s->y,
3065 s->width - 1, s->height - 1);
3067 else
3069 for (i = 0; i < s->nchars; i++, ++s->gidx)
3070 if (mac_per_char_metric (GC_FONT (s->gc), s->char2b + i, 0) == NULL)
3071 /* This is a nonexistent or zero-width glyph such as a
3072 combining diacritic. Draw a rectangle. */
3073 mac_draw_rectangle (s->f, s->gc,
3074 x + s->cmp->offsets[s->gidx * 2], s->y,
3075 FONT_WIDTH (GC_FONT (s->gc)) - 1, s->height - 1);
3076 else
3077 mac_draw_image_string_16 (s->f, s->gc,
3078 x + s->cmp->offsets[s->gidx * 2],
3079 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3080 s->char2b + i, 1, 0, s->face->overstrike);
3085 #ifdef USE_X_TOOLKIT
3087 static struct frame *x_frame_of_widget P_ ((Widget));
3090 /* Return the frame on which widget WIDGET is used.. Abort if frame
3091 cannot be determined. */
3093 static struct frame *
3094 x_frame_of_widget (widget)
3095 Widget widget;
3097 struct x_display_info *dpyinfo;
3098 Lisp_Object tail;
3099 struct frame *f;
3101 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3103 /* Find the top-level shell of the widget. Note that this function
3104 can be called when the widget is not yet realized, so XtWindow
3105 (widget) == 0. That's the reason we can't simply use
3106 x_any_window_to_frame. */
3107 while (!XtIsTopLevelShell (widget))
3108 widget = XtParent (widget);
3110 /* Look for a frame with that top-level widget. Allocate the color
3111 on that frame to get the right gamma correction value. */
3112 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3113 if (GC_FRAMEP (XCAR (tail))
3114 && (f = XFRAME (XCAR (tail)),
3115 (f->output_data.nothing != 1
3116 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3117 && f->output_data.x->widget == widget)
3118 return f;
3120 abort ();
3124 /* Allocate the color COLOR->pixel on the screen and display of
3125 widget WIDGET in colormap CMAP. If an exact match cannot be
3126 allocated, try the nearest color available. Value is non-zero
3127 if successful. This is called from lwlib. */
3130 x_alloc_nearest_color_for_widget (widget, cmap, color)
3131 Widget widget;
3132 Colormap cmap;
3133 XColor *color;
3135 struct frame *f = x_frame_of_widget (widget);
3136 return x_alloc_nearest_color (f, cmap, color);
3140 #endif /* USE_X_TOOLKIT */
3142 #if 0 /* MAC_TODO */
3144 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3145 CMAP. If an exact match can't be allocated, try the nearest color
3146 available. Value is non-zero if successful. Set *COLOR to the
3147 color allocated. */
3150 x_alloc_nearest_color (f, cmap, color)
3151 struct frame *f;
3152 Colormap cmap;
3153 XColor *color;
3155 Display *display = FRAME_X_DISPLAY (f);
3156 Screen *screen = FRAME_X_SCREEN (f);
3157 int rc;
3159 gamma_correct (f, color);
3160 rc = XAllocColor (display, cmap, color);
3161 if (rc == 0)
3163 /* If we got to this point, the colormap is full, so we're going
3164 to try to get the next closest color. The algorithm used is
3165 a least-squares matching, which is what X uses for closest
3166 color matching with StaticColor visuals. */
3167 int nearest, i;
3168 unsigned long nearest_delta = ~0;
3169 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3170 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3172 for (i = 0; i < ncells; ++i)
3173 cells[i].pixel = i;
3174 XQueryColors (display, cmap, cells, ncells);
3176 for (nearest = i = 0; i < ncells; ++i)
3178 long dred = (color->red >> 8) - (cells[i].red >> 8);
3179 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3180 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3181 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3183 if (delta < nearest_delta)
3185 nearest = i;
3186 nearest_delta = delta;
3190 color->red = cells[nearest].red;
3191 color->green = cells[nearest].green;
3192 color->blue = cells[nearest].blue;
3193 rc = XAllocColor (display, cmap, color);
3196 #ifdef DEBUG_X_COLORS
3197 if (rc)
3198 register_color (color->pixel);
3199 #endif /* DEBUG_X_COLORS */
3201 return rc;
3205 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3206 It's necessary to do this instead of just using PIXEL directly to
3207 get color reference counts right. */
3209 unsigned long
3210 x_copy_color (f, pixel)
3211 struct frame *f;
3212 unsigned long pixel;
3214 XColor color;
3216 color.pixel = pixel;
3217 BLOCK_INPUT;
3218 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3219 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3220 UNBLOCK_INPUT;
3221 #ifdef DEBUG_X_COLORS
3222 register_color (pixel);
3223 #endif
3224 return color.pixel;
3228 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3229 It's necessary to do this instead of just using PIXEL directly to
3230 get color reference counts right. */
3232 unsigned long
3233 x_copy_dpy_color (dpy, cmap, pixel)
3234 Display *dpy;
3235 Colormap cmap;
3236 unsigned long pixel;
3238 XColor color;
3240 color.pixel = pixel;
3241 BLOCK_INPUT;
3242 XQueryColor (dpy, cmap, &color);
3243 XAllocColor (dpy, cmap, &color);
3244 UNBLOCK_INPUT;
3245 #ifdef DEBUG_X_COLORS
3246 register_color (pixel);
3247 #endif
3248 return color.pixel;
3251 #endif /* MAC_TODO */
3254 /* Brightness beyond which a color won't have its highlight brightness
3255 boosted.
3257 Nominally, highlight colors for `3d' faces are calculated by
3258 brightening an object's color by a constant scale factor, but this
3259 doesn't yield good results for dark colors, so for colors who's
3260 brightness is less than this value (on a scale of 0-255) have to
3261 use an additional additive factor.
3263 The value here is set so that the default menu-bar/mode-line color
3264 (grey75) will not have its highlights changed at all. */
3265 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3268 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
3269 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3270 If this produces the same color as COLOR, try a color where all RGB
3271 values have DELTA added. Return the allocated color in *COLOR.
3272 DISPLAY is the X display, CMAP is the colormap to operate on.
3273 Value is non-zero if successful. */
3275 static int
3276 mac_alloc_lighter_color (f, color, factor, delta)
3277 struct frame *f;
3278 unsigned long *color;
3279 double factor;
3280 int delta;
3282 unsigned long new;
3283 long bright;
3285 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3286 delta /= 256;
3288 /* Change RGB values by specified FACTOR. Avoid overflow! */
3289 xassert (factor >= 0);
3290 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3291 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3292 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3294 /* Calculate brightness of COLOR. */
3295 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3296 + BLUE_FROM_ULONG (*color)) / 6;
3298 /* We only boost colors that are darker than
3299 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3300 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3301 /* Make an additive adjustment to NEW, because it's dark enough so
3302 that scaling by FACTOR alone isn't enough. */
3304 /* How far below the limit this color is (0 - 1, 1 being darker). */
3305 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3306 /* The additive adjustment. */
3307 int min_delta = delta * dimness * factor / 2;
3309 if (factor < 1)
3310 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3311 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3312 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3313 else
3314 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3315 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3316 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3319 if (new == *color)
3320 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3321 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3322 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3324 /* MAC_TODO: Map to palette and retry with delta if same? */
3325 /* MAC_TODO: Free colors (if using palette)? */
3327 if (new == *color)
3328 return 0;
3330 *color = new;
3332 return 1;
3336 /* Set up the foreground color for drawing relief lines of glyph
3337 string S. RELIEF is a pointer to a struct relief containing the GC
3338 with which lines will be drawn. Use a color that is FACTOR or
3339 DELTA lighter or darker than the relief's background which is found
3340 in S->f->output_data.x->relief_background. If such a color cannot
3341 be allocated, use DEFAULT_PIXEL, instead. */
3343 static void
3344 x_setup_relief_color (f, relief, factor, delta, default_pixel)
3345 struct frame *f;
3346 struct relief *relief;
3347 double factor;
3348 int delta;
3349 unsigned long default_pixel;
3351 XGCValues xgcv;
3352 struct mac_output *di = f->output_data.mac;
3353 unsigned long mask = GCForeground;
3354 unsigned long pixel;
3355 unsigned long background = di->relief_background;
3356 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3358 /* MAC_TODO: Free colors (if using palette)? */
3360 /* Allocate new color. */
3361 xgcv.foreground = default_pixel;
3362 pixel = background;
3363 if (dpyinfo->n_planes != 1
3364 && mac_alloc_lighter_color (f, &pixel, factor, delta))
3366 relief->allocated_p = 1;
3367 xgcv.foreground = relief->pixel = pixel;
3370 if (relief->gc == 0)
3372 #if 0 /* MAC_TODO: stipple */
3373 xgcv.stipple = dpyinfo->gray;
3374 mask |= GCStipple;
3375 #endif
3376 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3378 else
3379 XChangeGC (NULL, relief->gc, mask, &xgcv);
3383 /* Set up colors for the relief lines around glyph string S. */
3385 static void
3386 x_setup_relief_colors (s)
3387 struct glyph_string *s;
3389 struct mac_output *di = s->f->output_data.mac;
3390 unsigned long color;
3392 if (s->face->use_box_color_for_shadows_p)
3393 color = s->face->box_color;
3394 else if (s->first_glyph->type == IMAGE_GLYPH
3395 && s->img->pixmap
3396 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3397 color = IMAGE_BACKGROUND (s->img, s->f, 0);
3398 else
3400 XGCValues xgcv;
3402 /* Get the background color of the face. */
3403 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3404 color = xgcv.background;
3407 if (di->white_relief.gc == 0
3408 || color != di->relief_background)
3410 di->relief_background = color;
3411 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3412 WHITE_PIX_DEFAULT (s->f));
3413 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3414 BLACK_PIX_DEFAULT (s->f));
3419 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
3420 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3421 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3422 relief. LEFT_P non-zero means draw a relief on the left side of
3423 the rectangle. RIGHT_P non-zero means draw a relief on the right
3424 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3425 when drawing. */
3427 static void
3428 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3429 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
3430 struct frame *f;
3431 int left_x, top_y, right_x, bottom_y, width;
3432 int top_p, bot_p, left_p, right_p, raised_p;
3433 Rect *clip_rect;
3435 Display *dpy = FRAME_MAC_DISPLAY (f);
3436 int i;
3437 GC gc;
3439 if (raised_p)
3440 gc = f->output_data.mac->white_relief.gc;
3441 else
3442 gc = f->output_data.mac->black_relief.gc;
3443 mac_set_clip_rectangles (dpy, gc, clip_rect, 1);
3445 /* Top. */
3446 if (top_p)
3447 for (i = 0; i < width; ++i)
3448 mac_draw_line (f, gc,
3449 left_x + i * left_p, top_y + i,
3450 right_x + 1 - i * right_p, top_y + i);
3452 /* Left. */
3453 if (left_p)
3454 for (i = 0; i < width; ++i)
3455 mac_draw_line (f, gc,
3456 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
3458 mac_reset_clip_rectangles (dpy, gc);
3459 if (raised_p)
3460 gc = f->output_data.mac->black_relief.gc;
3461 else
3462 gc = f->output_data.mac->white_relief.gc;
3463 mac_set_clip_rectangles (dpy, gc, clip_rect, 1);
3465 /* Bottom. */
3466 if (bot_p)
3467 for (i = 0; i < width; ++i)
3468 mac_draw_line (f, gc,
3469 left_x + i * left_p, bottom_y - i,
3470 right_x + 1 - i * right_p, bottom_y - i);
3472 /* Right. */
3473 if (right_p)
3474 for (i = 0; i < width; ++i)
3475 mac_draw_line (f, gc,
3476 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3478 mac_reset_clip_rectangles (dpy, gc);
3482 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3483 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3484 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3485 left side of the rectangle. RIGHT_P non-zero means draw a line
3486 on the right side of the rectangle. CLIP_RECT is the clipping
3487 rectangle to use when drawing. */
3489 static void
3490 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3491 left_p, right_p, clip_rect)
3492 struct glyph_string *s;
3493 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
3494 Rect *clip_rect;
3496 XGCValues xgcv;
3498 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3499 XSetForeground (s->display, s->gc, s->face->box_color);
3500 mac_set_clip_rectangles (s->display, s->gc, clip_rect, 1);
3502 /* Top. */
3503 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3504 right_x - left_x + 1, width);
3506 /* Left. */
3507 if (left_p)
3508 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3509 width, bottom_y - top_y + 1);
3511 /* Bottom. */
3512 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3513 right_x - left_x + 1, width);
3515 /* Right. */
3516 if (right_p)
3517 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3518 top_y, width, bottom_y - top_y + 1);
3520 XSetForeground (s->display, s->gc, xgcv.foreground);
3521 mac_reset_clip_rectangles (s->display, s->gc);
3525 /* Draw a box around glyph string S. */
3527 static void
3528 x_draw_glyph_string_box (s)
3529 struct glyph_string *s;
3531 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3532 int left_p, right_p;
3533 struct glyph *last_glyph;
3534 Rect clip_rect;
3536 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3537 ? WINDOW_RIGHT_EDGE_X (s->w)
3538 : window_box_right (s->w, s->area));
3540 /* The glyph that may have a right box line. */
3541 last_glyph = (s->cmp || s->img
3542 ? s->first_glyph
3543 : s->first_glyph + s->nchars - 1);
3545 width = eabs (s->face->box_line_width);
3546 raised_p = s->face->box == FACE_RAISED_BOX;
3547 left_x = s->x;
3548 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3549 ? last_x - 1
3550 : min (last_x, s->x + s->background_width) - 1);
3551 top_y = s->y;
3552 bottom_y = top_y + s->height - 1;
3554 left_p = (s->first_glyph->left_box_line_p
3555 || (s->hl == DRAW_MOUSE_FACE
3556 && (s->prev == NULL
3557 || s->prev->hl != s->hl)));
3558 right_p = (last_glyph->right_box_line_p
3559 || (s->hl == DRAW_MOUSE_FACE
3560 && (s->next == NULL
3561 || s->next->hl != s->hl)));
3563 get_glyph_string_clip_rect (s, &clip_rect);
3565 if (s->face->box == FACE_SIMPLE_BOX)
3566 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3567 left_p, right_p, &clip_rect);
3568 else
3570 x_setup_relief_colors (s);
3571 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3572 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
3577 /* Draw foreground of image glyph string S. */
3579 static void
3580 x_draw_image_foreground (s)
3581 struct glyph_string *s;
3583 int x = s->x;
3584 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3586 /* If first glyph of S has a left box line, start drawing it to the
3587 right of that line. */
3588 if (s->face->box != FACE_NO_BOX
3589 && s->first_glyph->left_box_line_p
3590 && s->slice.x == 0)
3591 x += eabs (s->face->box_line_width);
3593 /* If there is a margin around the image, adjust x- and y-position
3594 by that margin. */
3595 if (s->slice.x == 0)
3596 x += s->img->hmargin;
3597 if (s->slice.y == 0)
3598 y += s->img->vmargin;
3600 if (s->img->pixmap)
3602 x_set_glyph_string_clipping (s);
3604 #if USE_CG_DRAWING
3605 mac_draw_cg_image (s->img->data.ptr_val,
3606 s->f, s->gc, s->slice.x, s->slice.y,
3607 s->slice.width, s->slice.height, x, y, 1);
3608 #endif
3609 if (s->img->mask)
3610 #if !USE_CG_DRAWING
3611 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3612 s->f, s->gc, s->slice.x, s->slice.y,
3613 s->slice.width, s->slice.height, x, y);
3614 #else
3616 #endif
3617 else
3619 #if !USE_CG_DRAWING
3620 mac_copy_area (s->img->pixmap,
3621 s->f, s->gc, s->slice.x, s->slice.y,
3622 s->slice.width, s->slice.height, x, y);
3623 #endif
3625 /* When the image has a mask, we can expect that at
3626 least part of a mouse highlight or a block cursor will
3627 be visible. If the image doesn't have a mask, make
3628 a block cursor visible by drawing a rectangle around
3629 the image. I believe it's looking better if we do
3630 nothing here for mouse-face. */
3631 if (s->hl == DRAW_CURSOR)
3633 int r = s->img->relief;
3634 if (r < 0) r = -r;
3635 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
3636 s->slice.width + r*2 - 1,
3637 s->slice.height + r*2 - 1);
3641 else
3642 /* Draw a rectangle if image could not be loaded. */
3643 mac_draw_rectangle (s->f, s->gc, x, y,
3644 s->slice.width - 1, s->slice.height - 1);
3648 /* Draw a relief around the image glyph string S. */
3650 static void
3651 x_draw_image_relief (s)
3652 struct glyph_string *s;
3654 int x0, y0, x1, y1, thick, raised_p;
3655 Rect r;
3656 int x = s->x;
3657 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3659 /* If first glyph of S has a left box line, start drawing it to the
3660 right of that line. */
3661 if (s->face->box != FACE_NO_BOX
3662 && s->first_glyph->left_box_line_p
3663 && s->slice.x == 0)
3664 x += eabs (s->face->box_line_width);
3666 /* If there is a margin around the image, adjust x- and y-position
3667 by that margin. */
3668 if (s->slice.x == 0)
3669 x += s->img->hmargin;
3670 if (s->slice.y == 0)
3671 y += s->img->vmargin;
3673 if (s->hl == DRAW_IMAGE_SUNKEN
3674 || s->hl == DRAW_IMAGE_RAISED)
3676 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3677 raised_p = s->hl == DRAW_IMAGE_RAISED;
3679 else
3681 thick = eabs (s->img->relief);
3682 raised_p = s->img->relief > 0;
3685 x0 = x - thick;
3686 y0 = y - thick;
3687 x1 = x + s->slice.width + thick - 1;
3688 y1 = y + s->slice.height + thick - 1;
3690 x_setup_relief_colors (s);
3691 get_glyph_string_clip_rect (s, &r);
3692 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3693 s->slice.y == 0,
3694 s->slice.y + s->slice.height == s->img->height,
3695 s->slice.x == 0,
3696 s->slice.x + s->slice.width == s->img->width,
3697 &r);
3701 /* Draw part of the background of glyph string S. X, Y, W, and H
3702 give the rectangle to draw. */
3704 static void
3705 x_draw_glyph_string_bg_rect (s, x, y, w, h)
3706 struct glyph_string *s;
3707 int x, y, w, h;
3709 #if 0 /* MAC_TODO: stipple */
3710 if (s->stippled_p)
3712 /* Fill background with a stipple pattern. */
3713 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3714 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3715 XSetFillStyle (s->display, s->gc, FillSolid);
3717 else
3718 #endif /* MAC_TODO */
3719 x_clear_glyph_string_rect (s, x, y, w, h);
3723 /* Draw image glyph string S.
3725 s->y
3726 s->x +-------------------------
3727 | s->face->box
3729 | +-------------------------
3730 | | s->img->margin
3732 | | +-------------------
3733 | | | the image
3737 static void
3738 x_draw_image_glyph_string (s)
3739 struct glyph_string *s;
3741 int x, y;
3742 int box_line_hwidth = eabs (s->face->box_line_width);
3743 int box_line_vwidth = max (s->face->box_line_width, 0);
3744 int height;
3746 height = s->height - 2 * box_line_vwidth;
3749 /* Fill background with face under the image. Do it only if row is
3750 taller than image or if image has a clip mask to reduce
3751 flickering. */
3752 s->stippled_p = s->face->stipple != 0;
3753 if (height > s->slice.height
3754 || s->img->hmargin
3755 || s->img->vmargin
3756 || s->img->mask
3757 || s->img->pixmap == 0
3758 || s->width != s->background_width)
3760 x = s->x;
3761 if (s->first_glyph->left_box_line_p
3762 && s->slice.x == 0)
3763 x += box_line_hwidth;
3765 y = s->y;
3766 if (s->slice.y == 0)
3767 y += box_line_vwidth;
3769 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3771 s->background_filled_p = 1;
3774 /* Draw the foreground. */
3775 x_draw_image_foreground (s);
3777 /* If we must draw a relief around the image, do it. */
3778 if (s->img->relief
3779 || s->hl == DRAW_IMAGE_RAISED
3780 || s->hl == DRAW_IMAGE_SUNKEN)
3781 x_draw_image_relief (s);
3785 /* Draw stretch glyph string S. */
3787 static void
3788 x_draw_stretch_glyph_string (s)
3789 struct glyph_string *s;
3791 xassert (s->first_glyph->type == STRETCH_GLYPH);
3793 if (s->hl == DRAW_CURSOR
3794 && !x_stretch_cursor_p)
3796 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3797 as wide as the stretch glyph. */
3798 int width, background_width = s->background_width;
3799 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3801 if (x < left_x)
3803 background_width -= left_x - x;
3804 x = left_x;
3806 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3808 /* Draw cursor. */
3809 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3811 /* Clear rest using the GC of the original non-cursor face. */
3812 if (width < background_width)
3814 int y = s->y;
3815 int w = background_width - width, h = s->height;
3816 Rect r;
3817 GC gc;
3819 x += width;
3820 if (s->row->mouse_face_p
3821 && cursor_in_mouse_face_p (s->w))
3823 x_set_mouse_face_gc (s);
3824 gc = s->gc;
3826 else
3827 gc = s->face->gc;
3829 get_glyph_string_clip_rect (s, &r);
3830 mac_set_clip_rectangles (s->display, gc, &r, 1);
3832 #if 0 /* MAC_TODO: stipple */
3833 if (s->face->stipple)
3835 /* Fill background with a stipple pattern. */
3836 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3837 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3838 XSetFillStyle (s->display, gc, FillSolid);
3840 else
3841 #endif /* MAC_TODO */
3842 mac_erase_rectangle (s->f, gc, x, y, w, h);
3845 else if (!s->background_filled_p)
3847 int background_width = s->background_width;
3848 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3850 /* Don't draw into left margin, fringe or scrollbar area
3851 except for header line and mode line. */
3852 if (x < left_x && !s->row->mode_line_p)
3854 background_width -= left_x - x;
3855 x = left_x;
3857 if (background_width > 0)
3858 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3861 s->background_filled_p = 1;
3865 /* Draw glyph string S. */
3867 static void
3868 x_draw_glyph_string (s)
3869 struct glyph_string *s;
3871 int relief_drawn_p = 0;
3873 /* If S draws into the background of its successor that does not
3874 draw a cursor, draw the background of the successor first so that
3875 S can draw into it. This makes S->next use XDrawString instead
3876 of XDrawImageString. */
3877 if (s->next && s->right_overhang && !s->for_overlaps
3878 && s->next->hl != DRAW_CURSOR)
3880 xassert (s->next->img == NULL);
3881 x_set_glyph_string_gc (s->next);
3882 x_set_glyph_string_clipping (s->next);
3883 x_draw_glyph_string_background (s->next, 1);
3886 /* Set up S->gc, set clipping and draw S. */
3887 x_set_glyph_string_gc (s);
3889 /* Draw relief (if any) in advance for char/composition so that the
3890 glyph string can be drawn over it. */
3891 if (!s->for_overlaps
3892 && s->face->box != FACE_NO_BOX
3893 && (s->first_glyph->type == CHAR_GLYPH
3894 || s->first_glyph->type == COMPOSITE_GLYPH))
3897 x_set_glyph_string_clipping (s);
3898 x_draw_glyph_string_background (s, 1);
3899 x_draw_glyph_string_box (s);
3900 x_set_glyph_string_clipping (s);
3901 relief_drawn_p = 1;
3903 else
3904 x_set_glyph_string_clipping (s);
3906 switch (s->first_glyph->type)
3908 case IMAGE_GLYPH:
3909 x_draw_image_glyph_string (s);
3910 break;
3912 case STRETCH_GLYPH:
3913 x_draw_stretch_glyph_string (s);
3914 break;
3916 case CHAR_GLYPH:
3917 if (s->for_overlaps)
3918 s->background_filled_p = 1;
3919 else
3920 x_draw_glyph_string_background (s, 0);
3921 x_draw_glyph_string_foreground (s);
3922 break;
3924 case COMPOSITE_GLYPH:
3925 if (s->for_overlaps || s->gidx > 0)
3926 s->background_filled_p = 1;
3927 else
3928 x_draw_glyph_string_background (s, 1);
3929 x_draw_composite_glyph_string_foreground (s);
3930 break;
3932 default:
3933 abort ();
3936 if (!s->for_overlaps)
3938 /* Draw underline. */
3939 if (s->face->underline_p)
3941 unsigned long tem, h;
3942 int y;
3944 #if 0
3945 /* Get the underline thickness. Default is 1 pixel. */
3946 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
3947 #endif
3948 h = 1;
3950 y = s->y + s->height - h;
3951 if (!x_underline_at_descent_line)
3953 /* Get the underline position. This is the recommended
3954 vertical offset in pixels from the baseline to the top of
3955 the underline. This is a signed value according to the
3956 specs, and its default is
3958 ROUND ((maximum descent) / 2), with
3959 ROUND(x) = floor (x + 0.5) */
3961 #if 0
3962 if (x_use_underline_position_properties
3963 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
3964 y = s->ybase + (long) tem;
3965 else
3966 #endif
3967 if (s->face->font)
3968 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
3971 if (s->face->underline_defaulted_p)
3972 mac_fill_rectangle (s->f, s->gc, s->x, y,
3973 s->background_width, h);
3974 else
3976 XGCValues xgcv;
3977 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3978 XSetForeground (s->display, s->gc, s->face->underline_color);
3979 mac_fill_rectangle (s->f, s->gc, s->x, y,
3980 s->background_width, h);
3981 XSetForeground (s->display, s->gc, xgcv.foreground);
3985 /* Draw overline. */
3986 if (s->face->overline_p)
3988 unsigned long dy = 0, h = 1;
3990 if (s->face->overline_color_defaulted_p)
3991 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3992 s->background_width, h);
3993 else
3995 XGCValues xgcv;
3996 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3997 XSetForeground (s->display, s->gc, s->face->overline_color);
3998 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3999 s->background_width, h);
4000 XSetForeground (s->display, s->gc, xgcv.foreground);
4004 /* Draw strike-through. */
4005 if (s->face->strike_through_p)
4007 unsigned long h = 1;
4008 unsigned long dy = (s->height - h) / 2;
4010 if (s->face->strike_through_color_defaulted_p)
4011 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4012 s->width, h);
4013 else
4015 XGCValues xgcv;
4016 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4017 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4018 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4019 s->width, h);
4020 XSetForeground (s->display, s->gc, xgcv.foreground);
4024 /* Draw relief if not yet drawn. */
4025 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
4026 x_draw_glyph_string_box (s);
4029 /* Reset clipping. */
4030 mac_reset_clip_rectangles (s->display, s->gc);
4033 /* Shift display to make room for inserted glyphs. */
4035 void
4036 mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4037 struct frame *f;
4038 int x, y, width, height, shift_by;
4040 mac_scroll_area (f, f->output_data.mac->normal_gc,
4041 x, y, width, height,
4042 x + shift_by, y);
4045 /* Delete N glyphs at the nominal cursor position. Not implemented
4046 for X frames. */
4048 static void
4049 x_delete_glyphs (n)
4050 register int n;
4052 abort ();
4056 /* Clear entire frame. If updating_frame is non-null, clear that
4057 frame. Otherwise clear the selected frame. */
4059 static void
4060 x_clear_frame (struct frame *f)
4062 /* Clearing the frame will erase any cursor, so mark them all as no
4063 longer visible. */
4064 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4065 output_cursor.hpos = output_cursor.vpos = 0;
4066 output_cursor.x = -1;
4068 /* We don't set the output cursor here because there will always
4069 follow an explicit cursor_to. */
4070 BLOCK_INPUT;
4071 mac_clear_window (f);
4073 /* We have to clear the scroll bars, too. If we have changed
4074 colors or something like that, then they should be notified. */
4075 x_scroll_bar_clear (f);
4077 XFlush (FRAME_MAC_DISPLAY (f));
4078 UNBLOCK_INPUT;
4083 /* Invert the middle quarter of the frame for .15 sec. */
4085 /* We use the select system call to do the waiting, so we have to make
4086 sure it's available. If it isn't, we just won't do visual bells. */
4088 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4091 /* Subtract the `struct timeval' values X and Y, storing the result in
4092 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4094 static int
4095 timeval_subtract (result, x, y)
4096 struct timeval *result, x, y;
4098 /* Perform the carry for the later subtraction by updating y. This
4099 is safer because on some systems the tv_sec member is unsigned. */
4100 if (x.tv_usec < y.tv_usec)
4102 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4103 y.tv_usec -= 1000000 * nsec;
4104 y.tv_sec += nsec;
4107 if (x.tv_usec - y.tv_usec > 1000000)
4109 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4110 y.tv_usec += 1000000 * nsec;
4111 y.tv_sec -= nsec;
4114 /* Compute the time remaining to wait. tv_usec is certainly
4115 positive. */
4116 result->tv_sec = x.tv_sec - y.tv_sec;
4117 result->tv_usec = x.tv_usec - y.tv_usec;
4119 /* Return indication of whether the result should be considered
4120 negative. */
4121 return x.tv_sec < y.tv_sec;
4124 void
4125 XTflash (f)
4126 struct frame *f;
4128 /* Get the height not including a menu bar widget. */
4129 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4130 /* Height of each line to flash. */
4131 int flash_height = FRAME_LINE_HEIGHT (f);
4132 /* These will be the left and right margins of the rectangles. */
4133 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4134 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4136 int width;
4138 /* Don't flash the area between a scroll bar and the frame
4139 edge it is next to. */
4140 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4142 case vertical_scroll_bar_left:
4143 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4144 break;
4146 case vertical_scroll_bar_right:
4147 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4148 break;
4150 default:
4151 break;
4154 width = flash_right - flash_left;
4156 BLOCK_INPUT;
4158 /* If window is tall, flash top and bottom line. */
4159 if (height > 3 * FRAME_LINE_HEIGHT (f))
4161 mac_invert_rectangle (f, flash_left,
4162 (FRAME_INTERNAL_BORDER_WIDTH (f)
4163 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4164 width, flash_height);
4165 mac_invert_rectangle (f, flash_left,
4166 (height - flash_height
4167 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4168 width, flash_height);
4170 else
4171 /* If it is short, flash it all. */
4172 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4173 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4175 x_flush (f);
4178 struct timeval wakeup;
4180 EMACS_GET_TIME (wakeup);
4182 /* Compute time to wait until, propagating carry from usecs. */
4183 wakeup.tv_usec += 150000;
4184 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4185 wakeup.tv_usec %= 1000000;
4187 /* Keep waiting until past the time wakeup or any input gets
4188 available. */
4189 while (! detect_input_pending ())
4191 struct timeval current;
4192 struct timeval timeout;
4194 EMACS_GET_TIME (current);
4196 /* Break if result would be negative. */
4197 if (timeval_subtract (&current, wakeup, current))
4198 break;
4200 /* How long `select' should wait. */
4201 timeout.tv_sec = 0;
4202 timeout.tv_usec = 10000;
4204 /* Try to wait that long--but we might wake up sooner. */
4205 select (0, NULL, NULL, NULL, &timeout);
4209 /* If window is tall, flash top and bottom line. */
4210 if (height > 3 * FRAME_LINE_HEIGHT (f))
4212 mac_invert_rectangle (f, flash_left,
4213 (FRAME_INTERNAL_BORDER_WIDTH (f)
4214 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4215 width, flash_height);
4216 mac_invert_rectangle (f, flash_left,
4217 (height - flash_height
4218 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4219 width, flash_height);
4221 else
4222 /* If it is short, flash it all. */
4223 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4224 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4226 x_flush (f);
4228 UNBLOCK_INPUT;
4231 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4234 /* Make audible bell. */
4236 void
4237 XTring_bell ()
4239 struct frame *f = SELECTED_FRAME ();
4241 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4242 if (visible_bell)
4243 XTflash (f);
4244 else
4245 #endif
4247 BLOCK_INPUT;
4248 SysBeep (1);
4249 XFlush (FRAME_MAC_DISPLAY (f));
4250 UNBLOCK_INPUT;
4255 /* Specify how many text lines, from the top of the window,
4256 should be affected by insert-lines and delete-lines operations.
4257 This, and those operations, are used only within an update
4258 that is bounded by calls to x_update_begin and x_update_end. */
4260 static void
4261 XTset_terminal_window (n)
4262 register int n;
4264 /* This function intentionally left blank. */
4269 /***********************************************************************
4270 Line Dance
4271 ***********************************************************************/
4273 /* Perform an insert-lines or delete-lines operation, inserting N
4274 lines or deleting -N lines at vertical position VPOS. */
4276 static void
4277 x_ins_del_lines (vpos, n)
4278 int vpos, n;
4280 abort ();
4284 /* Scroll part of the display as described by RUN. */
4286 static void
4287 x_scroll_run (w, run)
4288 struct window *w;
4289 struct run *run;
4291 struct frame *f = XFRAME (w->frame);
4292 int x, y, width, height, from_y, to_y, bottom_y;
4294 /* Get frame-relative bounding box of the text display area of W,
4295 without mode lines. Include in this box the left and right
4296 fringe of W. */
4297 window_box (w, -1, &x, &y, &width, &height);
4299 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4300 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4301 bottom_y = y + height;
4303 if (to_y < from_y)
4305 /* Scrolling up. Make sure we don't copy part of the mode
4306 line at the bottom. */
4307 if (from_y + run->height > bottom_y)
4308 height = bottom_y - from_y;
4309 else
4310 height = run->height;
4312 else
4314 /* Scolling down. Make sure we don't copy over the mode line.
4315 at the bottom. */
4316 if (to_y + run->height > bottom_y)
4317 height = bottom_y - to_y;
4318 else
4319 height = run->height;
4322 BLOCK_INPUT;
4324 /* Cursor off. Will be switched on again in x_update_window_end. */
4325 updated_window = w;
4326 x_clear_cursor (w);
4328 mac_scroll_area (f, f->output_data.mac->normal_gc,
4329 x, from_y,
4330 width, height,
4331 x, to_y);
4333 UNBLOCK_INPUT;
4338 /***********************************************************************
4339 Exposure Events
4340 ***********************************************************************/
4343 static void
4344 frame_highlight (f)
4345 struct frame *f;
4347 x_update_cursor (f, 1);
4350 static void
4351 frame_unhighlight (f)
4352 struct frame *f;
4354 x_update_cursor (f, 1);
4357 /* The focus has changed. Update the frames as necessary to reflect
4358 the new situation. Note that we can't change the selected frame
4359 here, because the Lisp code we are interrupting might become confused.
4360 Each event gets marked with the frame in which it occurred, so the
4361 Lisp code can tell when the switch took place by examining the events. */
4363 static void
4364 x_new_focus_frame (dpyinfo, frame)
4365 struct x_display_info *dpyinfo;
4366 struct frame *frame;
4368 struct frame *old_focus = dpyinfo->x_focus_frame;
4370 if (frame != dpyinfo->x_focus_frame)
4372 /* Set this before calling other routines, so that they see
4373 the correct value of x_focus_frame. */
4374 dpyinfo->x_focus_frame = frame;
4376 if (old_focus && old_focus->auto_lower)
4377 x_lower_frame (old_focus);
4379 #if 0
4380 selected_frame = frame;
4381 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4382 selected_frame);
4383 Fselect_window (selected_frame->selected_window, Qnil);
4384 choose_minibuf_frame ();
4385 #endif /* ! 0 */
4387 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4388 pending_autoraise_frame = dpyinfo->x_focus_frame;
4389 else
4390 pending_autoraise_frame = 0;
4392 #if USE_MAC_FONT_PANEL
4393 if (frame)
4394 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
4395 #endif
4398 x_frame_rehighlight (dpyinfo);
4401 /* Handle FocusIn and FocusOut state changes for FRAME.
4402 If FRAME has focus and there exists more than one frame, puts
4403 a FOCUS_IN_EVENT into *BUFP. */
4405 static void
4406 mac_focus_changed (type, dpyinfo, frame, bufp)
4407 int type;
4408 struct mac_display_info *dpyinfo;
4409 struct frame *frame;
4410 struct input_event *bufp;
4412 if (type == activeFlag)
4414 if (dpyinfo->x_focus_event_frame != frame)
4416 x_new_focus_frame (dpyinfo, frame);
4417 dpyinfo->x_focus_event_frame = frame;
4419 /* Don't stop displaying the initial startup message
4420 for a switch-frame event we don't need. */
4421 if (GC_NILP (Vterminal_frame)
4422 && GC_CONSP (Vframe_list)
4423 && !GC_NILP (XCDR (Vframe_list)))
4425 bufp->kind = FOCUS_IN_EVENT;
4426 XSETFRAME (bufp->frame_or_window, frame);
4430 else
4432 if (dpyinfo->x_focus_event_frame == frame)
4434 dpyinfo->x_focus_event_frame = 0;
4435 x_new_focus_frame (dpyinfo, 0);
4440 /* The focus may have changed. Figure out if it is a real focus change,
4441 by checking both FocusIn/Out and Enter/LeaveNotify events.
4443 Returns FOCUS_IN_EVENT event in *BUFP. */
4445 static void
4446 x_detect_focus_change (dpyinfo, event, bufp)
4447 struct mac_display_info *dpyinfo;
4448 const EventRecord *event;
4449 struct input_event *bufp;
4451 struct frame *frame;
4453 frame = mac_window_to_frame ((WindowRef) event->message);
4454 if (! frame)
4455 return;
4457 /* On Mac, this is only called from focus events, so no switch needed. */
4458 mac_focus_changed ((event->modifiers & activeFlag),
4459 dpyinfo, frame, bufp);
4463 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4465 void
4466 x_mouse_leave (dpyinfo)
4467 struct x_display_info *dpyinfo;
4469 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4472 /* The focus has changed, or we have redirected a frame's focus to
4473 another frame (this happens when a frame uses a surrogate
4474 mini-buffer frame). Shift the highlight as appropriate.
4476 The FRAME argument doesn't necessarily have anything to do with which
4477 frame is being highlighted or un-highlighted; we only use it to find
4478 the appropriate X display info. */
4480 static void
4481 XTframe_rehighlight (frame)
4482 struct frame *frame;
4484 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4487 static void
4488 x_frame_rehighlight (dpyinfo)
4489 struct x_display_info *dpyinfo;
4491 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4493 if (dpyinfo->x_focus_frame)
4495 dpyinfo->x_highlight_frame
4496 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4497 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4498 : dpyinfo->x_focus_frame);
4499 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4501 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4502 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4505 else
4506 dpyinfo->x_highlight_frame = 0;
4508 if (dpyinfo->x_highlight_frame != old_highlight)
4510 if (old_highlight)
4511 frame_unhighlight (old_highlight);
4512 if (dpyinfo->x_highlight_frame)
4513 frame_highlight (dpyinfo->x_highlight_frame);
4519 /* Convert a keysym to its name. */
4521 char *
4522 x_get_keysym_name (keysym)
4523 int keysym;
4525 char *value;
4527 BLOCK_INPUT;
4528 #if 0
4529 value = XKeysymToString (keysym);
4530 #else
4531 value = 0;
4532 #endif
4533 UNBLOCK_INPUT;
4535 return value;
4540 /* Function to report a mouse movement to the mainstream Emacs code.
4541 The input handler calls this.
4543 We have received a mouse movement event, which is given in *event.
4544 If the mouse is over a different glyph than it was last time, tell
4545 the mainstream emacs code by setting mouse_moved. If not, ask for
4546 another motion event, so we can check again the next time it moves. */
4548 static Point last_mouse_motion_position;
4549 static Lisp_Object last_mouse_motion_frame;
4551 static int
4552 note_mouse_movement (frame, pos)
4553 FRAME_PTR frame;
4554 Point *pos;
4556 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4557 #if TARGET_API_MAC_CARBON
4558 Rect r;
4559 #endif
4561 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4562 last_mouse_motion_position = *pos;
4563 XSETFRAME (last_mouse_motion_frame, frame);
4565 if (frame == dpyinfo->mouse_face_mouse_frame
4566 #if TARGET_API_MAC_CARBON
4567 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
4568 #else
4569 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
4570 #endif
4573 /* This case corresponds to LeaveNotify in X11. If we move
4574 outside the frame, then we're certainly no longer on any text
4575 in the frame. */
4576 clear_mouse_face (dpyinfo);
4577 dpyinfo->mouse_face_mouse_frame = 0;
4578 if (!dpyinfo->grabbed)
4579 FRAME_RIF (frame)->define_frame_cursor (frame,
4580 frame->output_data.mac->nontext_cursor);
4583 /* Has the mouse moved off the glyph it was on at the last sighting? */
4584 if (frame != last_mouse_glyph_frame
4585 || !PtInRect (*pos, &last_mouse_glyph))
4587 frame->mouse_moved = 1;
4588 last_mouse_scroll_bar = Qnil;
4589 note_mouse_highlight (frame, pos->h, pos->v);
4590 /* Remember which glyph we're now on. */
4591 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
4592 last_mouse_glyph_frame = frame;
4593 return 1;
4596 return 0;
4600 /************************************************************************
4601 Mouse Face
4602 ************************************************************************/
4604 /* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4606 static void
4607 redo_mouse_highlight ()
4609 if (!NILP (last_mouse_motion_frame)
4610 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4611 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4612 last_mouse_motion_position.h,
4613 last_mouse_motion_position.v);
4617 static struct frame *
4618 mac_focus_frame (dpyinfo)
4619 struct mac_display_info *dpyinfo;
4621 if (dpyinfo->x_focus_frame)
4622 return dpyinfo->x_focus_frame;
4623 else
4624 /* Mac version may get events, such as a menu bar click, even when
4625 all the frames are invisible. In this case, we regard the
4626 event came to the selected frame. */
4627 return SELECTED_FRAME ();
4631 /* Return the current position of the mouse.
4632 *FP should be a frame which indicates which display to ask about.
4634 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4635 and *PART to the frame, window, and scroll bar part that the mouse
4636 is over. Set *X and *Y to the portion and whole of the mouse's
4637 position on the scroll bar.
4639 If the mouse movement started elsewhere, set *FP to the frame the
4640 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4641 the mouse is over.
4643 Set *TIME to the server time-stamp for the time at which the mouse
4644 was at this position.
4646 Don't store anything if we don't have a valid set of values to report.
4648 This clears the mouse_moved flag, so we can wait for the next mouse
4649 movement. */
4651 static void
4652 XTmouse_position (fp, insist, bar_window, part, x, y, time)
4653 FRAME_PTR *fp;
4654 int insist;
4655 Lisp_Object *bar_window;
4656 enum scroll_bar_part *part;
4657 Lisp_Object *x, *y;
4658 unsigned long *time;
4660 FRAME_PTR f1;
4662 BLOCK_INPUT;
4664 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4665 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4666 else
4668 Lisp_Object frame, tail;
4670 /* Clear the mouse-moved flag for every frame on this display. */
4671 FOR_EACH_FRAME (tail, frame)
4672 XFRAME (frame)->mouse_moved = 0;
4674 last_mouse_scroll_bar = Qnil;
4676 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4677 && FRAME_LIVE_P (last_mouse_frame))
4678 f1 = last_mouse_frame;
4679 else
4680 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
4682 if (f1)
4684 /* Ok, we found a frame. Store all the values.
4685 last_mouse_glyph is a rectangle used to reduce the
4686 generation of mouse events. To not miss any motion
4687 events, we must divide the frame into rectangles of the
4688 size of the smallest character that could be displayed
4689 on it, i.e. into the same rectangles that matrices on
4690 the frame are divided into. */
4691 Point mouse_pos;
4693 #if TARGET_API_MAC_CARBON
4694 GetGlobalMouse (&mouse_pos);
4695 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4696 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4697 #else
4698 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4699 GetMouse (&mouse_pos);
4700 #endif
4701 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4702 &last_mouse_glyph);
4703 last_mouse_glyph_frame = f1;
4705 *bar_window = Qnil;
4706 *part = 0;
4707 *fp = f1;
4708 XSETINT (*x, mouse_pos.h);
4709 XSETINT (*y, mouse_pos.v);
4710 *time = last_mouse_movement_time;
4714 UNBLOCK_INPUT;
4718 /************************************************************************
4719 Toolkit scroll bars
4720 ************************************************************************/
4722 #ifdef USE_TOOLKIT_SCROLL_BARS
4724 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4725 static OSStatus install_scroll_bar_timer P_ ((void));
4726 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
4727 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
4728 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
4729 struct input_event *));
4730 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
4731 Rect *));
4732 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
4733 ControlPartCode, Point,
4734 struct input_event *));
4735 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
4736 struct input_event *));
4737 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
4738 Point, struct input_event *));
4739 static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4740 int, int, int));
4742 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
4744 static int last_scroll_bar_part;
4746 static EventLoopTimerRef scroll_bar_timer;
4748 static int scroll_bar_timer_event_posted_p;
4750 #define SCROLL_BAR_FIRST_DELAY 0.5
4751 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4753 static pascal void
4754 scroll_bar_timer_callback (timer, data)
4755 EventLoopTimerRef timer;
4756 void *data;
4758 OSStatus err;
4760 err = mac_post_mouse_moved_event ();
4761 if (err == noErr)
4762 scroll_bar_timer_event_posted_p = 1;
4765 static OSStatus
4766 install_scroll_bar_timer ()
4768 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4770 if (scroll_bar_timer_callbackUPP == NULL)
4771 scroll_bar_timer_callbackUPP =
4772 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4774 if (scroll_bar_timer == NULL)
4775 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4776 kEventDurationForever as delays. */
4777 return
4778 InstallEventLoopTimer (GetCurrentEventLoop (),
4779 kEventDurationForever, kEventDurationForever,
4780 scroll_bar_timer_callbackUPP, NULL,
4781 &scroll_bar_timer);
4784 static OSStatus
4785 set_scroll_bar_timer (delay)
4786 EventTimerInterval delay;
4788 if (scroll_bar_timer == NULL)
4789 install_scroll_bar_timer ();
4791 scroll_bar_timer_event_posted_p = 0;
4793 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4796 static int
4797 control_part_code_to_scroll_bar_part (part_code)
4798 ControlPartCode part_code;
4800 switch (part_code)
4802 case kControlUpButtonPart: return scroll_bar_up_arrow;
4803 case kControlDownButtonPart: return scroll_bar_down_arrow;
4804 case kControlPageUpPart: return scroll_bar_above_handle;
4805 case kControlPageDownPart: return scroll_bar_below_handle;
4806 case kControlIndicatorPart: return scroll_bar_handle;
4809 return -1;
4812 static void
4813 construct_scroll_bar_click (bar, part, bufp)
4814 struct scroll_bar *bar;
4815 int part;
4816 struct input_event *bufp;
4818 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4819 bufp->frame_or_window = bar->window;
4820 bufp->arg = Qnil;
4821 bufp->part = part;
4822 bufp->code = 0;
4823 XSETINT (bufp->x, 0);
4824 XSETINT (bufp->y, 0);
4825 bufp->modifiers = 0;
4828 static OSStatus
4829 get_control_part_bounds (ch, part_code, rect)
4830 ControlRef ch;
4831 ControlPartCode part_code;
4832 Rect *rect;
4834 RgnHandle region = NewRgn ();
4835 OSStatus err;
4837 err = GetControlRegion (ch, part_code, region);
4838 if (err == noErr)
4839 GetRegionBounds (region, rect);
4840 DisposeRgn (region);
4842 return err;
4845 static void
4846 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
4847 struct scroll_bar *bar;
4848 ControlPartCode part_code;
4849 Point mouse_pos;
4850 struct input_event *bufp;
4852 int part = control_part_code_to_scroll_bar_part (part_code);
4854 if (part < 0)
4855 return;
4857 if (part != scroll_bar_handle)
4859 construct_scroll_bar_click (bar, part, bufp);
4860 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4861 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
4862 bar->dragging = Qnil;
4864 else
4866 Rect r;
4868 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4869 kControlIndicatorPart, &r);
4870 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
4873 last_scroll_bar_part = part;
4874 tracked_scroll_bar = bar;
4877 static void
4878 x_scroll_bar_handle_release (bar, bufp)
4879 struct scroll_bar *bar;
4880 struct input_event *bufp;
4882 if (last_scroll_bar_part != scroll_bar_handle
4883 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
4884 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
4886 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
4887 set_scroll_bar_timer (kEventDurationForever);
4889 last_scroll_bar_part = -1;
4890 bar->dragging = Qnil;
4891 tracked_scroll_bar = NULL;
4894 static void
4895 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
4896 WindowRef win;
4897 struct scroll_bar *bar;
4898 Point mouse_pos;
4899 struct input_event *bufp;
4901 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
4903 if (last_scroll_bar_part == scroll_bar_handle)
4905 int top, top_range;
4906 Rect r;
4908 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4909 kControlIndicatorPart, &r);
4911 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
4912 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
4914 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
4915 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
4917 if (top < 0)
4918 top = 0;
4919 if (top > top_range)
4920 top = top_range;
4922 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
4923 XSETINT (bufp->x, top);
4924 XSETINT (bufp->y, top_range);
4926 else
4928 ControlPartCode part_code;
4929 int unhilite_p = 0, part;
4931 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
4932 unhilite_p = 1;
4933 else
4935 part = control_part_code_to_scroll_bar_part (part_code);
4937 switch (last_scroll_bar_part)
4939 case scroll_bar_above_handle:
4940 case scroll_bar_below_handle:
4941 if (part != scroll_bar_above_handle
4942 && part != scroll_bar_below_handle)
4943 unhilite_p = 1;
4944 break;
4946 case scroll_bar_up_arrow:
4947 case scroll_bar_down_arrow:
4948 if (part != scroll_bar_up_arrow
4949 && part != scroll_bar_down_arrow)
4950 unhilite_p = 1;
4951 break;
4955 if (unhilite_p)
4956 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
4957 else if (part != last_scroll_bar_part
4958 || scroll_bar_timer_event_posted_p)
4960 construct_scroll_bar_click (bar, part, bufp);
4961 last_scroll_bar_part = part;
4962 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4963 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
4968 /* Set the thumb size and position of scroll bar BAR. We are currently
4969 displaying PORTION out of a whole WHOLE, and our position POSITION. */
4971 static void
4972 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
4973 struct scroll_bar *bar;
4974 int portion, position, whole;
4976 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
4977 int value, viewsize, maximum;
4979 if (XINT (bar->track_height) == 0)
4980 return;
4982 if (whole <= portion)
4983 value = 0, viewsize = 1, maximum = 0;
4984 else
4986 float scale;
4988 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
4989 scale = (float) maximum / (whole - portion);
4990 value = position * scale + 0.5f;
4991 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
4994 BLOCK_INPUT;
4996 if (GetControlViewSize (ch) != viewsize
4997 || GetControl32BitValue (ch) != value
4998 || GetControl32BitMaximum (ch) != maximum)
5000 /* Temporarily hide the scroll bar to avoid multiple redraws. */
5001 SetControlVisibility (ch, false, false);
5003 SetControl32BitMaximum (ch, maximum);
5004 SetControl32BitValue (ch, value);
5005 SetControlViewSize (ch, viewsize);
5007 SetControlVisibility (ch, true, true);
5010 UNBLOCK_INPUT;
5013 #endif /* USE_TOOLKIT_SCROLL_BARS */
5017 /************************************************************************
5018 Scroll bars, general
5019 ************************************************************************/
5021 /* Create a scroll bar and return the scroll bar vector for it. W is
5022 the Emacs window on which to create the scroll bar. TOP, LEFT,
5023 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
5024 scroll bar. */
5026 static struct scroll_bar *
5027 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5028 struct window *w;
5029 int top, left, width, height, disp_top, disp_height;
5031 struct frame *f = XFRAME (w->frame);
5032 struct scroll_bar *bar
5033 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5034 Rect r;
5035 ControlRef ch;
5037 BLOCK_INPUT;
5039 r.left = left;
5040 r.top = disp_top;
5041 r.right = left + width;
5042 r.bottom = disp_top + disp_height;
5044 #if USE_CG_DRAWING
5045 mac_prepare_for_quickdraw (f);
5046 #endif
5047 #if TARGET_API_MAC_CARBON
5048 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
5049 #ifdef USE_TOOLKIT_SCROLL_BARS
5050 false,
5051 #else
5052 width < disp_height,
5053 #endif
5054 0, 0, 0, kControlScrollBarProc, (long) bar);
5055 #else
5056 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5057 0, 0, 0, scrollBarProc, (long) bar);
5058 #endif
5059 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
5061 XSETWINDOW (bar->window, w);
5062 XSETINT (bar->top, top);
5063 XSETINT (bar->left, left);
5064 XSETINT (bar->width, width);
5065 XSETINT (bar->height, height);
5066 XSETINT (bar->start, 0);
5067 XSETINT (bar->end, 0);
5068 bar->dragging = Qnil;
5069 #ifdef MAC_OSX
5070 bar->fringe_extended_p = Qnil;
5071 #endif
5072 bar->redraw_needed_p = Qnil;
5073 #ifdef USE_TOOLKIT_SCROLL_BARS
5074 bar->track_top = Qnil;
5075 bar->track_height = Qnil;
5076 bar->min_handle = Qnil;
5077 #endif
5079 /* Add bar to its frame's list of scroll bars. */
5080 bar->next = FRAME_SCROLL_BARS (f);
5081 bar->prev = Qnil;
5082 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5083 if (!NILP (bar->next))
5084 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5086 UNBLOCK_INPUT;
5087 return bar;
5091 /* Draw BAR's handle in the proper position.
5093 If the handle is already drawn from START to END, don't bother
5094 redrawing it, unless REBUILD is non-zero; in that case, always
5095 redraw it. (REBUILD is handy for drawing the handle after expose
5096 events.)
5098 Normally, we want to constrain the start and end of the handle to
5099 fit inside its rectangle, but if the user is dragging the scroll
5100 bar handle, we want to let them drag it down all the way, so that
5101 the bar's top is as far down as it goes; otherwise, there's no way
5102 to move to the very end of the buffer. */
5104 #ifndef USE_TOOLKIT_SCROLL_BARS
5106 static void
5107 x_scroll_bar_set_handle (bar, start, end, rebuild)
5108 struct scroll_bar *bar;
5109 int start, end;
5110 int rebuild;
5112 int dragging = ! NILP (bar->dragging);
5113 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5114 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5115 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5116 int length = end - start;
5118 /* If the display is already accurate, do nothing. */
5119 if (! rebuild
5120 && start == XINT (bar->start)
5121 && end == XINT (bar->end))
5122 return;
5124 BLOCK_INPUT;
5126 /* Make sure the values are reasonable, and try to preserve the
5127 distance between start and end. */
5128 if (start < 0)
5129 start = 0;
5130 else if (start > top_range)
5131 start = top_range;
5132 end = start + length;
5134 if (end < start)
5135 end = start;
5136 else if (end > top_range && ! dragging)
5137 end = top_range;
5139 /* Store the adjusted setting in the scroll bar. */
5140 XSETINT (bar->start, start);
5141 XSETINT (bar->end, end);
5143 /* Clip the end position, just for display. */
5144 if (end > top_range)
5145 end = top_range;
5147 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5148 top positions, to make sure the handle is always at least that
5149 many pixels tall. */
5150 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5152 SetControlMinimum (ch, 0);
5153 /* Don't inadvertently activate deactivated scroll bars */
5154 if (GetControlMaximum (ch) != -1)
5155 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5156 - (end - start));
5157 SetControlValue (ch, start);
5158 #if TARGET_API_MAC_CARBON
5159 SetControlViewSize (ch, end - start);
5160 #endif
5162 UNBLOCK_INPUT;
5165 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5167 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5168 nil. */
5170 static void
5171 x_scroll_bar_remove (bar)
5172 struct scroll_bar *bar;
5174 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5176 BLOCK_INPUT;
5178 #if USE_CG_DRAWING
5179 mac_prepare_for_quickdraw (f);
5180 #endif
5181 /* Destroy the Mac scroll bar control */
5182 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
5184 /* Disassociate this scroll bar from its window. */
5185 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5187 UNBLOCK_INPUT;
5191 /* Set the handle of the vertical scroll bar for WINDOW to indicate
5192 that we are displaying PORTION characters out of a total of WHOLE
5193 characters, starting at POSITION. If WINDOW has no scroll bar,
5194 create one. */
5196 static void
5197 XTset_vertical_scroll_bar (w, portion, whole, position)
5198 struct window *w;
5199 int portion, whole, position;
5201 struct frame *f = XFRAME (w->frame);
5202 struct scroll_bar *bar;
5203 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
5204 int window_y, window_height;
5205 #ifdef MAC_OSX
5206 int fringe_extended_p;
5207 #endif
5209 /* Get window dimensions. */
5210 window_box (w, -1, 0, &window_y, 0, &window_height);
5211 top = window_y;
5212 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
5213 height = window_height;
5215 /* Compute the left edge of the scroll bar area. */
5216 left = WINDOW_SCROLL_BAR_AREA_X (w);
5218 /* Compute the width of the scroll bar which might be less than
5219 the width of the area reserved for the scroll bar. */
5220 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5221 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
5222 else
5223 sb_width = width;
5225 /* Compute the left edge of the scroll bar. */
5226 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
5227 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
5228 else
5229 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
5231 /* Adjustments according to Inside Macintosh to make it look nice */
5232 disp_top = top;
5233 disp_height = height;
5234 #ifdef MAC_OS8
5235 if (disp_top == 0)
5237 disp_top = -1;
5238 disp_height++;
5240 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
5242 disp_top++;
5243 disp_height--;
5246 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
5247 sb_left++;
5248 #endif
5250 #ifdef MAC_OSX
5251 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5252 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5253 && WINDOW_LEFT_FRINGE_WIDTH (w)
5254 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5255 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5256 else
5257 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5258 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5259 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5260 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5261 #endif
5263 /* Does the scroll bar exist yet? */
5264 if (NILP (w->vertical_scroll_bar))
5266 BLOCK_INPUT;
5267 #ifdef MAC_OSX
5268 if (fringe_extended_p)
5269 mac_clear_area (f, sb_left, top, sb_width, height);
5270 else
5271 #endif
5272 mac_clear_area (f, left, top, width, height);
5273 UNBLOCK_INPUT;
5274 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5275 disp_height);
5276 XSETVECTOR (w->vertical_scroll_bar, bar);
5278 else
5280 /* It may just need to be moved and resized. */
5281 ControlRef ch;
5283 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5284 ch = SCROLL_BAR_CONTROL_REF (bar);
5286 BLOCK_INPUT;
5288 /* If already correctly positioned, do nothing. */
5289 if (XINT (bar->left) == sb_left
5290 && XINT (bar->top) == top
5291 && XINT (bar->width) == sb_width
5292 && XINT (bar->height) == height
5293 #ifdef MAC_OSX
5294 && !NILP (bar->fringe_extended_p) == fringe_extended_p
5295 #endif
5298 if (!NILP (bar->redraw_needed_p))
5300 #if USE_CG_DRAWING
5301 mac_prepare_for_quickdraw (f);
5302 #endif
5303 Draw1Control (SCROLL_BAR_CONTROL_HANDLE (bar));
5306 else
5308 /* Since toolkit scroll bars are smaller than the space reserved
5309 for them on the frame, we have to clear "under" them. */
5310 #ifdef MAC_OSX
5311 if (fringe_extended_p)
5312 mac_clear_area (f, sb_left, top, sb_width, height);
5313 else
5314 #endif
5315 mac_clear_area (f, left, top, width, height);
5317 #if USE_CG_DRAWING
5318 mac_prepare_for_quickdraw (f);
5319 #endif
5320 HideControl (ch);
5321 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5322 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5323 disp_height);
5324 #ifndef USE_TOOLKIT_SCROLL_BARS
5325 if (sb_width < disp_height)
5326 ShowControl (ch);
5327 #endif
5329 /* Remember new settings. */
5330 XSETINT (bar->left, sb_left);
5331 XSETINT (bar->top, top);
5332 XSETINT (bar->width, sb_width);
5333 XSETINT (bar->height, height);
5334 #ifdef USE_TOOLKIT_SCROLL_BARS
5335 bar->track_top = Qnil;
5336 bar->track_height = Qnil;
5337 bar->min_handle = Qnil;
5338 #endif
5341 UNBLOCK_INPUT;
5344 #ifdef MAC_OSX
5345 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5346 #endif
5348 bar->redraw_needed_p = Qnil;
5350 #ifdef USE_TOOLKIT_SCROLL_BARS
5351 if (NILP (bar->track_top))
5353 if (sb_width >= disp_height
5354 #ifdef MAC_OSX
5355 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5356 #endif
5359 XSETINT (bar->track_top, 0);
5360 XSETINT (bar->track_height, 0);
5361 XSETINT (bar->min_handle, 0);
5363 else
5365 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5366 Rect r0, r1;
5368 BLOCK_INPUT;
5370 SetControl32BitMinimum (ch, 0);
5371 SetControl32BitMaximum (ch, 1 << 30);
5372 SetControlViewSize (ch, 1);
5374 /* Move the scroll bar thumb to the top. */
5375 SetControl32BitValue (ch, 0);
5376 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5378 /* Move the scroll bar thumb to the bottom. */
5379 SetControl32BitValue (ch, 1 << 30);
5380 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5382 UnionRect (&r0, &r1, &r0);
5383 XSETINT (bar->track_top, r0.top);
5384 XSETINT (bar->track_height, r0.bottom - r0.top);
5385 XSETINT (bar->min_handle, r1.bottom - r1.top);
5387 /* Don't show the scroll bar if its height is not enough to
5388 display the scroll bar thumb. */
5389 if (r0.bottom - r0.top > 0)
5390 ShowControl (ch);
5392 UNBLOCK_INPUT;
5396 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5397 #else /* not USE_TOOLKIT_SCROLL_BARS */
5398 /* Set the scroll bar's current state, unless we're currently being
5399 dragged. */
5400 if (NILP (bar->dragging))
5402 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5404 if (whole == 0)
5405 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5406 else
5408 int start = ((double) position * top_range) / whole;
5409 int end = ((double) (position + portion) * top_range) / whole;
5410 x_scroll_bar_set_handle (bar, start, end, 0);
5413 #endif /* not USE_TOOLKIT_SCROLL_BARS */
5417 /* The following three hooks are used when we're doing a thorough
5418 redisplay of the frame. We don't explicitly know which scroll bars
5419 are going to be deleted, because keeping track of when windows go
5420 away is a real pain - "Can you say set-window-configuration, boys
5421 and girls?" Instead, we just assert at the beginning of redisplay
5422 that *all* scroll bars are to be removed, and then save a scroll bar
5423 from the fiery pit when we actually redisplay its window. */
5425 /* Arrange for all scroll bars on FRAME to be removed at the next call
5426 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5427 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5429 static void
5430 XTcondemn_scroll_bars (frame)
5431 FRAME_PTR frame;
5433 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5434 while (! NILP (FRAME_SCROLL_BARS (frame)))
5436 Lisp_Object bar;
5437 bar = FRAME_SCROLL_BARS (frame);
5438 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5439 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5440 XSCROLL_BAR (bar)->prev = Qnil;
5441 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5442 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5443 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5448 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5449 Note that WINDOW isn't necessarily condemned at all. */
5451 static void
5452 XTredeem_scroll_bar (window)
5453 struct window *window;
5455 struct scroll_bar *bar;
5456 struct frame *f;
5458 /* We can't redeem this window's scroll bar if it doesn't have one. */
5459 if (NILP (window->vertical_scroll_bar))
5460 abort ();
5462 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5464 /* Unlink it from the condemned list. */
5465 f = XFRAME (WINDOW_FRAME (window));
5466 if (NILP (bar->prev))
5468 /* If the prev pointer is nil, it must be the first in one of
5469 the lists. */
5470 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5471 /* It's not condemned. Everything's fine. */
5472 return;
5473 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5474 window->vertical_scroll_bar))
5475 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5476 else
5477 /* If its prev pointer is nil, it must be at the front of
5478 one or the other! */
5479 abort ();
5481 else
5482 XSCROLL_BAR (bar->prev)->next = bar->next;
5484 if (! NILP (bar->next))
5485 XSCROLL_BAR (bar->next)->prev = bar->prev;
5487 bar->next = FRAME_SCROLL_BARS (f);
5488 bar->prev = Qnil;
5489 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5490 if (! NILP (bar->next))
5491 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5494 /* Remove all scroll bars on FRAME that haven't been saved since the
5495 last call to `*condemn_scroll_bars_hook'. */
5497 static void
5498 XTjudge_scroll_bars (f)
5499 FRAME_PTR f;
5501 Lisp_Object bar, next;
5503 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5505 /* Clear out the condemned list now so we won't try to process any
5506 more events on the hapless scroll bars. */
5507 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5509 for (; ! NILP (bar); bar = next)
5511 struct scroll_bar *b = XSCROLL_BAR (bar);
5513 x_scroll_bar_remove (b);
5515 next = b->next;
5516 b->next = b->prev = Qnil;
5519 /* Now there should be no references to the condemned scroll bars,
5520 and they should get garbage-collected. */
5524 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
5525 is set to something other than NO_EVENT, it is enqueued.
5527 This may be called from a signal handler, so we have to ignore GC
5528 mark bits. */
5530 static void
5531 x_scroll_bar_handle_click (bar, part_code, er, bufp)
5532 struct scroll_bar *bar;
5533 ControlPartCode part_code;
5534 const EventRecord *er;
5535 struct input_event *bufp;
5537 int win_y, top_range;
5539 if (! GC_WINDOWP (bar->window))
5540 abort ();
5542 bufp->kind = SCROLL_BAR_CLICK_EVENT;
5543 bufp->frame_or_window = bar->window;
5544 bufp->arg = Qnil;
5546 bar->dragging = Qnil;
5548 switch (part_code)
5550 case kControlUpButtonPart:
5551 bufp->part = scroll_bar_up_arrow;
5552 break;
5553 case kControlDownButtonPart:
5554 bufp->part = scroll_bar_down_arrow;
5555 break;
5556 case kControlPageUpPart:
5557 bufp->part = scroll_bar_above_handle;
5558 break;
5559 case kControlPageDownPart:
5560 bufp->part = scroll_bar_below_handle;
5561 break;
5562 #if TARGET_API_MAC_CARBON
5563 default:
5564 #else
5565 case kControlIndicatorPart:
5566 #endif
5567 if (er->what == mouseDown)
5568 bar->dragging = make_number (0);
5569 XSETVECTOR (last_mouse_scroll_bar, bar);
5570 bufp->part = scroll_bar_handle;
5571 break;
5574 win_y = XINT (bufp->y) - XINT (bar->top);
5575 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5577 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5579 win_y -= 24;
5581 if (! NILP (bar->dragging))
5582 win_y -= XINT (bar->dragging);
5584 if (win_y < 0)
5585 win_y = 0;
5586 if (win_y > top_range)
5587 win_y = top_range;
5589 XSETINT (bufp->x, win_y);
5590 XSETINT (bufp->y, top_range);
5593 #ifndef USE_TOOLKIT_SCROLL_BARS
5595 /* Handle some mouse motion while someone is dragging the scroll bar.
5597 This may be called from a signal handler, so we have to ignore GC
5598 mark bits. */
5600 static void
5601 x_scroll_bar_note_movement (bar, y_pos, t)
5602 struct scroll_bar *bar;
5603 int y_pos;
5604 Time t;
5606 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5608 last_mouse_movement_time = t;
5610 f->mouse_moved = 1;
5611 XSETVECTOR (last_mouse_scroll_bar, bar);
5613 /* If we're dragging the bar, display it. */
5614 if (! GC_NILP (bar->dragging))
5616 /* Where should the handle be now? */
5617 int new_start = y_pos - 24;
5619 if (new_start != XINT (bar->start))
5621 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5623 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5628 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5630 /* Return information to the user about the current position of the mouse
5631 on the scroll bar. */
5633 static void
5634 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5635 FRAME_PTR *fp;
5636 Lisp_Object *bar_window;
5637 enum scroll_bar_part *part;
5638 Lisp_Object *x, *y;
5639 unsigned long *time;
5641 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
5642 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5643 #if TARGET_API_MAC_CARBON
5644 WindowRef wp = GetControlOwner (ch);
5645 #else
5646 WindowRef wp = (*ch)->contrlOwner;
5647 #endif
5648 Point mouse_pos;
5649 struct frame *f = mac_window_to_frame (wp);
5650 int win_y, top_range;
5652 #if TARGET_API_MAC_CARBON
5653 GetGlobalMouse (&mouse_pos);
5654 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5655 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5656 #else
5657 SetPortWindowPort (wp);
5658 GetMouse (&mouse_pos);
5659 #endif
5661 win_y = mouse_pos.v - XINT (bar->top);
5662 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5664 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5666 win_y -= 24;
5668 if (! NILP (bar->dragging))
5669 win_y -= XINT (bar->dragging);
5671 if (win_y < 0)
5672 win_y = 0;
5673 if (win_y > top_range)
5674 win_y = top_range;
5676 *fp = f;
5677 *bar_window = bar->window;
5679 if (! NILP (bar->dragging))
5680 *part = scroll_bar_handle;
5681 else if (win_y < XINT (bar->start))
5682 *part = scroll_bar_above_handle;
5683 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5684 *part = scroll_bar_handle;
5685 else
5686 *part = scroll_bar_below_handle;
5688 XSETINT (*x, win_y);
5689 XSETINT (*y, top_range);
5691 f->mouse_moved = 0;
5692 last_mouse_scroll_bar = Qnil;
5694 *time = last_mouse_movement_time;
5698 /* The screen has been cleared so we may have changed foreground or
5699 background colors, and the scroll bars may need to be redrawn.
5700 Clear out the scroll bars, and ask for expose events, so we can
5701 redraw them. */
5703 void
5704 x_scroll_bar_clear (f)
5705 FRAME_PTR f;
5707 Lisp_Object bar;
5709 /* We can have scroll bars even if this is 0,
5710 if we just turned off scroll bar mode.
5711 But in that case we should not clear them. */
5712 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5713 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5714 bar = XSCROLL_BAR (bar)->next)
5715 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
5719 /***********************************************************************
5720 Tool-bars
5721 ***********************************************************************/
5722 #if USE_MAC_TOOLBAR
5724 /* In identifiers such as function/variable names, Emacs tool bar is
5725 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5727 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5728 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5730 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5731 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5732 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5733 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5734 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5735 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5736 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5738 static int mac_event_to_emacs_modifiers P_ ((EventRef));
5739 static void mac_handle_origin_change P_ ((struct frame *));
5740 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5741 EventRef, void *));
5743 static void
5744 mac_move_window_with_gravity (f, win_gravity, left, top)
5745 struct frame *f;
5746 int win_gravity;
5747 short left, top;
5749 Rect inner, outer;
5751 mac_get_window_bounds (f, &inner, &outer);
5753 switch (win_gravity)
5755 case NorthWestGravity:
5756 case WestGravity:
5757 case SouthWestGravity:
5758 left += inner.left - outer.left;
5759 break;
5761 case NorthGravity:
5762 case CenterGravity:
5763 case SouthGravity:
5764 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5765 break;
5767 case NorthEastGravity:
5768 case EastGravity:
5769 case SouthEastGravity:
5770 left += inner.right - outer.right;
5771 break;
5774 switch (win_gravity)
5776 case NorthWestGravity:
5777 case NorthGravity:
5778 case NorthEastGravity:
5779 top += inner.top - outer.top;
5780 break;
5782 case WestGravity:
5783 case CenterGravity:
5784 case EastGravity:
5785 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5786 break;
5788 case SouthWestGravity:
5789 case SouthGravity:
5790 case SouthEastGravity:
5791 top += inner.bottom - outer.bottom;
5792 break;
5795 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5798 static void
5799 mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5800 struct frame *f;
5801 int win_gravity;
5802 short *left, *top;
5804 Rect inner, outer;
5806 mac_get_window_bounds (f, &inner, &outer);
5808 switch (win_gravity)
5810 case NorthWestGravity:
5811 case WestGravity:
5812 case SouthWestGravity:
5813 *left = outer.left;
5814 break;
5816 case NorthGravity:
5817 case CenterGravity:
5818 case SouthGravity:
5819 *left = outer.left + ((outer.right - outer.left)
5820 - (inner.right - inner.left)) / 2;
5821 break;
5823 case NorthEastGravity:
5824 case EastGravity:
5825 case SouthEastGravity:
5826 *left = outer.right - (inner.right - inner.left);
5827 break;
5830 switch (win_gravity)
5832 case NorthWestGravity:
5833 case NorthGravity:
5834 case NorthEastGravity:
5835 *top = outer.top;
5836 break;
5838 case WestGravity:
5839 case CenterGravity:
5840 case EastGravity:
5841 *top = outer.top + ((outer.bottom - outer.top)
5842 - (inner.bottom - inner.top)) / 2;
5843 break;
5845 case SouthWestGravity:
5846 case SouthGravity:
5847 case SouthEastGravity:
5848 *top = outer.bottom - (inner.bottom - inner.top);
5849 break;
5853 static OSStatus
5854 mac_handle_toolbar_event (next_handler, event, data)
5855 EventHandlerCallRef next_handler;
5856 EventRef event;
5857 void *data;
5859 OSStatus err, result = eventNotHandledErr;
5861 switch (GetEventKind (event))
5863 case kEventToolbarGetDefaultIdentifiers:
5864 result = noErr;
5865 break;
5867 case kEventToolbarGetAllowedIdentifiers:
5869 CFMutableArrayRef array;
5871 GetEventParameter (event, kEventParamMutableArray,
5872 typeCFMutableArrayRef, NULL,
5873 sizeof (CFMutableArrayRef), NULL, &array);
5874 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5875 result = noErr;
5877 break;
5879 case kEventToolbarCreateItemWithIdentifier:
5881 CFStringRef identifier;
5882 HIToolbarItemRef item = NULL;
5884 GetEventParameter (event, kEventParamToolbarItemIdentifier,
5885 typeCFStringRef, NULL,
5886 sizeof (CFStringRef), NULL, &identifier);
5888 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
5889 == kCFCompareEqualTo)
5890 HIToolbarItemCreate (identifier,
5891 kHIToolbarItemAllowDuplicates
5892 | kHIToolbarItemCantBeRemoved, &item);
5894 if (item)
5896 SetEventParameter (event, kEventParamToolbarItem,
5897 typeHIToolbarItemRef,
5898 sizeof (HIToolbarItemRef), &item);
5899 result = noErr;
5902 break;
5904 default:
5905 abort ();
5908 return result;
5911 static CGImageRef
5912 mac_image_spec_to_cg_image (f, image)
5913 struct frame *f;
5914 Lisp_Object image;
5916 if (!valid_image_p (image))
5917 return NULL;
5918 else
5920 int img_id = lookup_image (f, image);
5921 struct image *img = IMAGE_FROM_ID (f, img_id);
5923 prepare_image_for_display (f, img);
5925 return img->data.ptr_val;
5929 /* Create a tool bar for frame F. */
5931 static OSStatus
5932 mac_create_frame_tool_bar (f)
5933 FRAME_PTR f;
5935 OSStatus err;
5936 HIToolbarRef toolbar;
5938 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
5939 &toolbar);
5940 if (err == noErr)
5942 static const EventTypeSpec specs[] =
5943 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
5944 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
5945 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
5947 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
5948 mac_handle_toolbar_event,
5949 GetEventTypeCount (specs), specs,
5950 f, NULL);
5953 if (err == noErr)
5954 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
5955 if (err == noErr)
5957 static const EventTypeSpec specs[] =
5958 {{kEventClassCommand, kEventCommandProcess}};
5960 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
5961 mac_handle_toolbar_command_event,
5962 GetEventTypeCount (specs),
5963 specs, f, NULL);
5965 if (err == noErr)
5966 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
5968 if (toolbar)
5969 CFRelease (toolbar);
5971 return err;
5974 /* Update the tool bar for frame F. Add new buttons and remove old. */
5976 void
5977 update_frame_tool_bar (f)
5978 FRAME_PTR f;
5980 HIToolbarRef toolbar = NULL;
5981 short left, top;
5982 CFArrayRef old_items = NULL;
5983 CFIndex old_count;
5984 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
5985 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
5987 BLOCK_INPUT;
5989 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
5990 if (toolbar == NULL)
5992 mac_create_frame_tool_bar (f);
5993 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
5994 if (toolbar == NULL)
5995 goto out;
5996 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
5997 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6000 HIToolbarCopyItems (toolbar, &old_items);
6001 if (old_items == NULL)
6002 goto out;
6004 old_count = CFArrayGetCount (old_items);
6005 pos = 0;
6006 for (i = 0; i < f->n_tool_bar_items; ++i)
6008 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6010 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6011 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6012 int idx;
6013 Lisp_Object image;
6014 CGImageRef cg_image;
6015 CFStringRef label;
6016 HIToolbarItemRef item;
6018 /* If image is a vector, choose the image according to the
6019 button state. */
6020 image = PROP (TOOL_BAR_ITEM_IMAGES);
6021 if (VECTORP (image))
6023 if (enabled_p)
6024 idx = (selected_p
6025 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6026 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6027 else
6028 idx = (selected_p
6029 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6030 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6032 xassert (ASIZE (image) >= idx);
6033 image = AREF (image, idx);
6035 else
6036 idx = -1;
6038 cg_image = mac_image_spec_to_cg_image (f, image);
6039 /* Ignore invalid image specifications. */
6040 if (cg_image == NULL)
6041 continue;
6043 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6044 if (label == NULL)
6045 label = CFSTR ("");
6047 if (pos < old_count)
6049 CGImageRef old_cg_image = NULL;
6050 CFStringRef old_label = NULL;
6051 Boolean old_enabled_p;
6053 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6055 HIToolbarItemCopyImage (item, &old_cg_image);
6056 if (cg_image != old_cg_image)
6057 HIToolbarItemSetImage (item, cg_image);
6058 CGImageRelease (old_cg_image);
6060 HIToolbarItemCopyLabel (item, &old_label);
6061 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6062 HIToolbarItemSetLabel (item, label);
6063 CFRelease (old_label);
6065 old_enabled_p = HIToolbarItemIsEnabled (item);
6066 if ((enabled_p || idx >= 0) != old_enabled_p)
6067 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6069 else
6071 item = NULL;
6072 HIToolbarCreateItemWithIdentifier (toolbar,
6073 TOOLBAR_ICON_ITEM_IDENTIFIER,
6074 NULL, &item);
6075 if (item)
6077 HIToolbarItemSetImage (item, cg_image);
6078 HIToolbarItemSetLabel (item, label);
6079 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6080 HIToolbarAppendItem (toolbar, item);
6081 CFRelease (item);
6085 CFRelease (label);
6086 if (item)
6088 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6089 pos++;
6093 CFRelease (old_items);
6095 while (pos < old_count)
6096 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6098 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6099 !win_gravity && f == mac_focus_frame (dpyinfo));
6100 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6101 toolbar visibility change. */
6102 mac_handle_origin_change (f);
6103 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6105 mac_move_window_with_gravity (f, win_gravity, left, top);
6106 /* If the title bar is completely outside the screen, adjust the
6107 position. */
6108 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6109 kWindowConstrainMoveRegardlessOfFit
6110 | kWindowConstrainAllowPartial, NULL, NULL);
6111 f->output_data.mac->toolbar_win_gravity = 0;
6114 out:
6115 UNBLOCK_INPUT;
6118 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6119 doesn't deallocate the resources. */
6121 void
6122 free_frame_tool_bar (f)
6123 FRAME_PTR f;
6125 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6127 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6129 BLOCK_INPUT;
6130 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
6131 (NILP (Fsymbol_value
6132 (intern ("frame-notice-user-settings")))
6133 && f == mac_focus_frame (dpyinfo)));
6134 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6135 on toolbar visibility change. */
6136 mac_handle_origin_change (f);
6137 UNBLOCK_INPUT;
6141 static void
6142 mac_tool_bar_note_mouse_movement (f, event)
6143 struct frame *f;
6144 EventRef event;
6146 OSStatus err;
6147 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6148 int mouse_down_p;
6149 HIViewRef item_view;
6150 UInt32 command_id;
6152 mouse_down_p = (dpyinfo->grabbed
6153 && f == last_mouse_frame
6154 && FRAME_LIVE_P (f));
6155 if (mouse_down_p)
6156 return;
6158 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6159 event, &item_view);
6160 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6161 toolbar item view seems to have the same command ID with that of
6162 the toolbar item. */
6163 if (err == noErr)
6164 err = GetControlCommandID (item_view, &command_id);
6165 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6167 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6169 if (i < f->n_tool_bar_items)
6171 HIRect bounds;
6172 HIViewRef content_view;
6174 err = HIViewGetBounds (item_view, &bounds);
6175 if (err == noErr)
6176 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6177 kHIViewWindowContentID, &content_view);
6178 if (err == noErr)
6179 err = HIViewConvertRect (&bounds, item_view, content_view);
6180 if (err == noErr)
6181 SetRect (&last_mouse_glyph,
6182 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6183 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6185 help_echo_object = help_echo_window = Qnil;
6186 help_echo_pos = -1;
6187 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6188 if (NILP (help_echo_string))
6189 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6194 static OSStatus
6195 mac_handle_toolbar_command_event (next_handler, event, data)
6196 EventHandlerCallRef next_handler;
6197 EventRef event;
6198 void *data;
6200 OSStatus err, result = eventNotHandledErr;
6201 struct frame *f = (struct frame *) data;
6202 HICommand command;
6204 err = GetEventParameter (event, kEventParamDirectObject,
6205 typeHICommand, NULL,
6206 sizeof (HICommand), NULL, &command);
6207 if (err != noErr)
6208 return result;
6210 switch (GetEventKind (event))
6212 case kEventCommandProcess:
6213 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6214 result = CallNextEventHandler (next_handler, event);
6215 else
6217 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6219 if (i < f->n_tool_bar_items
6220 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6222 Lisp_Object frame;
6223 struct input_event buf;
6225 EVENT_INIT (buf);
6227 XSETFRAME (frame, f);
6228 buf.kind = TOOL_BAR_EVENT;
6229 buf.frame_or_window = frame;
6230 buf.arg = frame;
6231 kbd_buffer_store_event (&buf);
6233 buf.kind = TOOL_BAR_EVENT;
6234 buf.frame_or_window = frame;
6235 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6236 buf.modifiers = mac_event_to_emacs_modifiers (event);
6237 kbd_buffer_store_event (&buf);
6239 result = noErr;
6242 break;
6244 default:
6245 abort ();
6247 #undef PROP
6249 return result;
6251 #endif /* USE_MAC_TOOLBAR */
6254 /***********************************************************************
6255 Text Cursor
6256 ***********************************************************************/
6258 /* Set clipping for output in glyph row ROW. W is the window in which
6259 we operate. GC is the graphics context to set clipping in.
6261 ROW may be a text row or, e.g., a mode line. Text rows must be
6262 clipped to the interior of the window dedicated to text display,
6263 mode lines must be clipped to the whole window. */
6265 static void
6266 x_clip_to_row (w, row, area, gc)
6267 struct window *w;
6268 struct glyph_row *row;
6269 int area;
6270 GC gc;
6272 struct frame *f = XFRAME (WINDOW_FRAME (w));
6273 Rect clip_rect;
6274 int window_x, window_y, window_width;
6276 window_box (w, area, &window_x, &window_y, &window_width, 0);
6278 clip_rect.left = window_x;
6279 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6280 clip_rect.top = max (clip_rect.top, window_y);
6281 clip_rect.right = clip_rect.left + window_width;
6282 clip_rect.bottom = clip_rect.top + row->visible_height;
6284 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
6288 /* Draw a hollow box cursor on window W in glyph row ROW. */
6290 static void
6291 x_draw_hollow_cursor (w, row)
6292 struct window *w;
6293 struct glyph_row *row;
6295 struct frame *f = XFRAME (WINDOW_FRAME (w));
6296 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6297 Display *dpy = FRAME_MAC_DISPLAY (f);
6298 int x, y, wd, h;
6299 XGCValues xgcv;
6300 struct glyph *cursor_glyph;
6301 GC gc;
6303 /* Get the glyph the cursor is on. If we can't tell because
6304 the current matrix is invalid or such, give up. */
6305 cursor_glyph = get_phys_cursor_glyph (w);
6306 if (cursor_glyph == NULL)
6307 return;
6309 /* Compute frame-relative coordinates for phys cursor. */
6310 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
6311 wd = w->phys_cursor_width;
6313 /* The foreground of cursor_gc is typically the same as the normal
6314 background color, which can cause the cursor box to be invisible. */
6315 xgcv.foreground = f->output_data.mac->cursor_pixel;
6316 if (dpyinfo->scratch_cursor_gc)
6317 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6318 else
6319 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6320 GCForeground, &xgcv);
6321 gc = dpyinfo->scratch_cursor_gc;
6323 /* Set clipping, draw the rectangle, and reset clipping again. */
6324 x_clip_to_row (w, row, TEXT_AREA, gc);
6325 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
6326 mac_reset_clip_rectangles (dpy, gc);
6330 /* Draw a bar cursor on window W in glyph row ROW.
6332 Implementation note: One would like to draw a bar cursor with an
6333 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6334 Unfortunately, I didn't find a font yet that has this property set.
6335 --gerd. */
6337 static void
6338 x_draw_bar_cursor (w, row, width, kind)
6339 struct window *w;
6340 struct glyph_row *row;
6341 int width;
6342 enum text_cursor_kinds kind;
6344 struct frame *f = XFRAME (w->frame);
6345 struct glyph *cursor_glyph;
6347 /* If cursor is out of bounds, don't draw garbage. This can happen
6348 in mini-buffer windows when switching between echo area glyphs
6349 and mini-buffer. */
6350 cursor_glyph = get_phys_cursor_glyph (w);
6351 if (cursor_glyph == NULL)
6352 return;
6354 /* If on an image, draw like a normal cursor. That's usually better
6355 visible than drawing a bar, esp. if the image is large so that
6356 the bar might not be in the window. */
6357 if (cursor_glyph->type == IMAGE_GLYPH)
6359 struct glyph_row *row;
6360 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6361 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6363 else
6365 Display *dpy = FRAME_MAC_DISPLAY (f);
6366 Window window = FRAME_MAC_WINDOW (f);
6367 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6368 unsigned long mask = GCForeground | GCBackground;
6369 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
6370 XGCValues xgcv;
6372 /* If the glyph's background equals the color we normally draw
6373 the bar cursor in, the bar cursor in its normal color is
6374 invisible. Use the glyph's foreground color instead in this
6375 case, on the assumption that the glyph's colors are chosen so
6376 that the glyph is legible. */
6377 if (face->background == f->output_data.mac->cursor_pixel)
6378 xgcv.background = xgcv.foreground = face->foreground;
6379 else
6380 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
6382 if (gc)
6383 XChangeGC (dpy, gc, mask, &xgcv);
6384 else
6386 gc = XCreateGC (dpy, window, mask, &xgcv);
6387 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6390 if (width < 0)
6391 width = FRAME_CURSOR_WIDTH (f);
6392 width = min (cursor_glyph->pixel_width, width);
6394 w->phys_cursor_width = width;
6395 x_clip_to_row (w, row, TEXT_AREA, gc);
6397 if (kind == BAR_CURSOR)
6398 mac_fill_rectangle (f, gc,
6399 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6400 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6401 width, row->height);
6402 else
6403 mac_fill_rectangle (f, gc,
6404 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6405 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6406 row->height - width),
6407 cursor_glyph->pixel_width,
6408 width);
6410 mac_reset_clip_rectangles (dpy, gc);
6415 /* RIF: Define cursor CURSOR on frame F. */
6417 static void
6418 mac_define_frame_cursor (f, cursor)
6419 struct frame *f;
6420 Cursor cursor;
6422 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6424 if (dpyinfo->x_focus_frame == f)
6425 SetThemeCursor (cursor);
6429 /* RIF: Clear area on frame F. */
6431 static void
6432 mac_clear_frame_area (f, x, y, width, height)
6433 struct frame *f;
6434 int x, y, width, height;
6436 mac_clear_area (f, x, y, width, height);
6440 /* RIF: Draw cursor on window W. */
6442 static void
6443 mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
6444 struct window *w;
6445 struct glyph_row *glyph_row;
6446 int x, y;
6447 int cursor_type, cursor_width;
6448 int on_p, active_p;
6450 if (on_p)
6452 w->phys_cursor_type = cursor_type;
6453 w->phys_cursor_on_p = 1;
6455 if (glyph_row->exact_window_width_line_p
6456 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6458 glyph_row->cursor_in_fringe_p = 1;
6459 draw_fringe_bitmap (w, glyph_row, 0);
6461 else
6462 switch (cursor_type)
6464 case HOLLOW_BOX_CURSOR:
6465 x_draw_hollow_cursor (w, glyph_row);
6466 break;
6468 case FILLED_BOX_CURSOR:
6469 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
6470 break;
6472 case BAR_CURSOR:
6473 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6474 break;
6476 case HBAR_CURSOR:
6477 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
6478 break;
6480 case NO_CURSOR:
6481 w->phys_cursor_width = 0;
6482 break;
6484 default:
6485 abort ();
6491 /* Icons. */
6493 #if 0 /* MAC_TODO: no icon support yet. */
6495 x_bitmap_icon (f, icon)
6496 struct frame *f;
6497 Lisp_Object icon;
6499 HANDLE hicon;
6501 if (FRAME_W32_WINDOW (f) == 0)
6502 return 1;
6504 if (NILP (icon))
6505 hicon = LoadIcon (hinst, EMACS_CLASS);
6506 else if (STRINGP (icon))
6507 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
6508 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6509 else if (SYMBOLP (icon))
6511 LPCTSTR name;
6513 if (EQ (icon, intern ("application")))
6514 name = (LPCTSTR) IDI_APPLICATION;
6515 else if (EQ (icon, intern ("hand")))
6516 name = (LPCTSTR) IDI_HAND;
6517 else if (EQ (icon, intern ("question")))
6518 name = (LPCTSTR) IDI_QUESTION;
6519 else if (EQ (icon, intern ("exclamation")))
6520 name = (LPCTSTR) IDI_EXCLAMATION;
6521 else if (EQ (icon, intern ("asterisk")))
6522 name = (LPCTSTR) IDI_ASTERISK;
6523 else if (EQ (icon, intern ("winlogo")))
6524 name = (LPCTSTR) IDI_WINLOGO;
6525 else
6526 return 1;
6528 hicon = LoadIcon (NULL, name);
6530 else
6531 return 1;
6533 if (hicon == NULL)
6534 return 1;
6536 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6537 (LPARAM) hicon);
6539 return 0;
6541 #endif /* MAC_TODO */
6543 /************************************************************************
6544 Handling X errors
6545 ************************************************************************/
6547 /* Display Error Handling functions not used on W32. Listing them here
6548 helps diff stay in step when comparing w32term.c with xterm.c.
6550 x_error_catcher (display, error)
6551 x_catch_errors (dpy)
6552 x_catch_errors_unwind (old_val)
6553 x_check_errors (dpy, format)
6554 x_had_errors_p (dpy)
6555 x_clear_errors (dpy)
6556 x_uncatch_errors (dpy, count)
6557 x_trace_wire ()
6558 x_connection_signal (signalnum)
6559 x_connection_closed (dpy, error_message)
6560 x_error_quitter (display, error)
6561 x_error_handler (display, error)
6562 x_io_error_quitter (display)
6567 /* Changing the font of the frame. */
6569 /* Give frame F the font named FONTNAME as its default font, and
6570 return the full name of that font. FONTNAME may be a wildcard
6571 pattern; in that case, we choose some font that fits the pattern.
6572 The return value shows which font we chose. */
6574 Lisp_Object
6575 x_new_font (f, fontname)
6576 struct frame *f;
6577 register char *fontname;
6579 struct font_info *fontp
6580 = FS_LOAD_FONT (f, 0, fontname, -1);
6582 if (!fontp)
6583 return Qnil;
6585 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6586 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6587 FRAME_FONTSET (f) = -1;
6589 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6590 FRAME_SPACE_WIDTH (f) = fontp->space_width;
6591 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6593 compute_fringe_widths (f, 1);
6595 /* Compute the scroll bar width in character columns. */
6596 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6598 int wid = FRAME_COLUMN_WIDTH (f);
6599 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6600 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
6602 else
6604 int wid = FRAME_COLUMN_WIDTH (f);
6605 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6608 /* Now make the frame display the given font. */
6609 if (FRAME_MAC_WINDOW (f) != 0)
6611 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
6612 FRAME_FONT (f));
6613 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
6614 FRAME_FONT (f));
6615 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
6616 FRAME_FONT (f));
6618 /* Don't change the size of a tip frame; there's no point in
6619 doing it because it's done in Fx_show_tip, and it leads to
6620 problems because the tip frame has no widget. */
6621 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
6622 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6625 return build_string (fontp->full_name);
6628 /* Give frame F the fontset named FONTSETNAME as its default font, and
6629 return the full name of that fontset. FONTSETNAME may be a wildcard
6630 pattern; in that case, we choose some fontset that fits the pattern.
6631 The return value shows which fontset we chose. */
6633 Lisp_Object
6634 x_new_fontset (f, fontsetname)
6635 struct frame *f;
6636 char *fontsetname;
6638 int fontset = fs_query_fontset (build_string (fontsetname), 0);
6639 Lisp_Object result;
6641 if (fontset < 0)
6642 return Qnil;
6644 if (FRAME_FONTSET (f) == fontset)
6645 /* This fontset is already set in frame F. There's nothing more
6646 to do. */
6647 return fontset_name (fontset);
6649 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6651 if (!STRINGP (result))
6652 /* Can't load ASCII font. */
6653 return Qnil;
6655 /* Since x_new_font doesn't update any fontset information, do it now. */
6656 FRAME_FONTSET (f) = fontset;
6658 return build_string (fontsetname);
6662 /***********************************************************************
6663 TODO: W32 Input Methods
6664 ***********************************************************************/
6665 /* Listing missing functions from xterm.c helps diff stay in step.
6667 xim_destroy_callback (xim, client_data, call_data)
6668 xim_open_dpy (dpyinfo, resource_name)
6669 struct xim_inst_t
6670 xim_instantiate_callback (display, client_data, call_data)
6671 xim_initialize (dpyinfo, resource_name)
6672 xim_close_dpy (dpyinfo)
6677 void
6678 mac_get_window_bounds (f, inner, outer)
6679 struct frame *f;
6680 Rect *inner, *outer;
6682 #if TARGET_API_MAC_CARBON
6683 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6684 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6685 #else /* not TARGET_API_MAC_CARBON */
6686 RgnHandle region = NewRgn ();
6688 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6689 *inner = (*region)->rgnBBox;
6690 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6691 *outer = (*region)->rgnBBox;
6692 DisposeRgn (region);
6693 #endif /* not TARGET_API_MAC_CARBON */
6696 static void
6697 mac_handle_origin_change (f)
6698 struct frame *f;
6700 x_real_positions (f, &f->left_pos, &f->top_pos);
6703 static void
6704 mac_handle_size_change (f, pixelwidth, pixelheight)
6705 struct frame *f;
6706 int pixelwidth, pixelheight;
6708 int cols, rows;
6710 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6711 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6713 if (cols != FRAME_COLS (f)
6714 || rows != FRAME_LINES (f)
6715 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6716 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6718 /* We pass 1 for DELAY since we can't run Lisp code inside of
6719 a BLOCK_INPUT. */
6720 change_frame_size (f, rows, cols, 0, 1, 0);
6721 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6722 FRAME_PIXEL_HEIGHT (f) = pixelheight;
6723 SET_FRAME_GARBAGED (f);
6725 /* If cursor was outside the new size, mark it as off. */
6726 mark_window_cursors_off (XWINDOW (f->root_window));
6728 /* Clear out any recollection of where the mouse highlighting
6729 was, since it might be in a place that's outside the new
6730 frame size. Actually checking whether it is outside is a
6731 pain in the neck, so don't try--just let the highlighting be
6732 done afresh with new size. */
6733 cancel_mouse_face (f);
6735 #if TARGET_API_MAC_CARBON
6736 if (f->output_data.mac->hourglass_control)
6738 #if USE_CG_DRAWING
6739 mac_prepare_for_quickdraw (f);
6740 #endif
6741 MoveControl (f->output_data.mac->hourglass_control,
6742 pixelwidth - HOURGLASS_WIDTH, 0);
6744 #endif
6749 /* Calculate the absolute position in frame F
6750 from its current recorded position values and gravity. */
6752 void
6753 x_calc_absolute_position (f)
6754 struct frame *f;
6756 int width_diff = 0, height_diff = 0;
6757 int flags = f->size_hint_flags;
6758 Rect inner, outer;
6760 /* We have nothing to do if the current position
6761 is already for the top-left corner. */
6762 if (! ((flags & XNegative) || (flags & YNegative)))
6763 return;
6765 /* Find the offsets of the outside upper-left corner of
6766 the inner window, with respect to the outer window. */
6767 BLOCK_INPUT;
6768 mac_get_window_bounds (f, &inner, &outer);
6769 UNBLOCK_INPUT;
6771 width_diff = (outer.right - outer.left) - (inner.right - inner.left);
6772 height_diff = (outer.bottom - outer.top) - (inner.bottom - inner.top);
6774 /* Treat negative positions as relative to the leftmost bottommost
6775 position that fits on the screen. */
6776 if (flags & XNegative)
6777 f->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
6778 - width_diff
6779 - FRAME_PIXEL_WIDTH (f)
6780 + f->left_pos);
6782 if (flags & YNegative)
6783 f->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
6784 - height_diff
6785 - FRAME_PIXEL_HEIGHT (f)
6786 + f->top_pos);
6788 /* The left_pos and top_pos
6789 are now relative to the top and left screen edges,
6790 so the flags should correspond. */
6791 f->size_hint_flags &= ~ (XNegative | YNegative);
6794 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6795 to really change the position, and 0 when calling from
6796 x_make_frame_visible (in that case, XOFF and YOFF are the current
6797 position values). It is -1 when calling from x_set_frame_parameters,
6798 which means, do adjust for borders but don't change the gravity. */
6800 void
6801 x_set_offset (f, xoff, yoff, change_gravity)
6802 struct frame *f;
6803 register int xoff, yoff;
6804 int change_gravity;
6806 if (change_gravity > 0)
6808 f->top_pos = yoff;
6809 f->left_pos = xoff;
6810 f->size_hint_flags &= ~ (XNegative | YNegative);
6811 if (xoff < 0)
6812 f->size_hint_flags |= XNegative;
6813 if (yoff < 0)
6814 f->size_hint_flags |= YNegative;
6815 f->win_gravity = NorthWestGravity;
6817 x_calc_absolute_position (f);
6819 BLOCK_INPUT;
6820 x_wm_set_size_hint (f, (long) 0, 0);
6822 #if TARGET_API_MAC_CARBON
6823 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6824 /* If the title bar is completely outside the screen, adjust the
6825 position. */
6826 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6827 kWindowConstrainMoveRegardlessOfFit
6828 | kWindowConstrainAllowPartial, NULL, NULL);
6829 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
6830 mac_handle_origin_change (f);
6831 #else
6833 Rect inner, outer, screen_rect, dummy;
6834 RgnHandle region = NewRgn ();
6836 mac_get_window_bounds (f, &inner, &outer);
6837 f->x_pixels_diff = inner.left - outer.left;
6838 f->y_pixels_diff = inner.top - outer.top;
6839 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6840 f->top_pos + f->y_pixels_diff, false);
6842 /* If the title bar is completely outside the screen, adjust the
6843 position. The variable `outer' holds the title bar rectangle.
6844 The variable `inner' holds slightly smaller one than `outer',
6845 so that the calculation of overlapping may not become too
6846 strict. */
6847 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6848 outer = (*region)->rgnBBox;
6849 DisposeRgn (region);
6850 inner = outer;
6851 InsetRect (&inner, 8, 8);
6852 screen_rect = qd.screenBits.bounds;
6853 screen_rect.top += GetMBarHeight ();
6855 if (!SectRect (&inner, &screen_rect, &dummy))
6857 if (inner.right <= screen_rect.left)
6858 f->left_pos = screen_rect.left;
6859 else if (inner.left >= screen_rect.right)
6860 f->left_pos = screen_rect.right - (outer.right - outer.left);
6862 if (inner.bottom <= screen_rect.top)
6863 f->top_pos = screen_rect.top;
6864 else if (inner.top >= screen_rect.bottom)
6865 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6867 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6868 f->top_pos + f->y_pixels_diff, false);
6871 #endif
6873 UNBLOCK_INPUT;
6876 /* Call this to change the size of frame F's x-window.
6877 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
6878 for this size change and subsequent size changes.
6879 Otherwise we leave the window gravity unchanged. */
6881 void
6882 x_set_window_size (f, change_gravity, cols, rows)
6883 struct frame *f;
6884 int change_gravity;
6885 int cols, rows;
6887 int pixelwidth, pixelheight;
6889 BLOCK_INPUT;
6891 check_frame_size (f, &rows, &cols);
6892 f->scroll_bar_actual_width
6893 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
6895 compute_fringe_widths (f, 0);
6897 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
6898 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
6900 f->win_gravity = NorthWestGravity;
6901 x_wm_set_size_hint (f, (long) 0, 0);
6903 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
6905 #if TARGET_API_MAC_CARBON
6906 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
6907 #endif
6908 mac_handle_size_change (f, pixelwidth, pixelheight);
6910 if (f->output_data.mac->internal_border_width
6911 != FRAME_INTERNAL_BORDER_WIDTH (f))
6913 mac_clear_window (f);
6914 f->output_data.mac->internal_border_width
6915 = FRAME_INTERNAL_BORDER_WIDTH (f);
6918 SET_FRAME_GARBAGED (f);
6920 UNBLOCK_INPUT;
6923 /* Mouse warping. */
6925 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
6927 void
6928 x_set_mouse_position (f, x, y)
6929 struct frame *f;
6930 int x, y;
6932 int pix_x, pix_y;
6934 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
6935 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
6937 if (pix_x < 0) pix_x = 0;
6938 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
6940 if (pix_y < 0) pix_y = 0;
6941 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
6943 x_set_mouse_pixel_position (f, pix_x, pix_y);
6946 void
6947 x_set_mouse_pixel_position (f, pix_x, pix_y)
6948 struct frame *f;
6949 int pix_x, pix_y;
6951 #ifdef MAC_OSX
6952 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
6953 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
6955 BLOCK_INPUT;
6956 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
6957 UNBLOCK_INPUT;
6958 #else
6959 #if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
6960 BLOCK_INPUT;
6962 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
6963 0, 0, 0, 0, pix_x, pix_y);
6964 UNBLOCK_INPUT;
6965 #endif
6966 #endif
6969 /* focus shifting, raising and lowering. */
6971 void
6972 x_focus_on_frame (f)
6973 struct frame *f;
6975 #if 0 /* This proves to be unpleasant. */
6976 x_raise_frame (f);
6977 #endif
6978 #if 0
6979 /* I don't think that the ICCCM allows programs to do things like this
6980 without the interaction of the window manager. Whatever you end up
6981 doing with this code, do it to x_unfocus_frame too. */
6982 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6983 RevertToPointerRoot, CurrentTime);
6984 #endif /* ! 0 */
6987 void
6988 x_unfocus_frame (f)
6989 struct frame *f;
6993 /* Raise frame F. */
6995 void
6996 x_raise_frame (f)
6997 struct frame *f;
6999 if (f->async_visible)
7001 BLOCK_INPUT;
7002 BringToFront (FRAME_MAC_WINDOW (f));
7003 UNBLOCK_INPUT;
7007 /* Lower frame F. */
7009 void
7010 x_lower_frame (f)
7011 struct frame *f;
7013 if (f->async_visible)
7015 BLOCK_INPUT;
7016 SendBehind (FRAME_MAC_WINDOW (f), NULL);
7017 UNBLOCK_INPUT;
7021 static void
7022 XTframe_raise_lower (f, raise_flag)
7023 FRAME_PTR f;
7024 int raise_flag;
7026 if (raise_flag)
7027 x_raise_frame (f);
7028 else
7029 x_lower_frame (f);
7032 /* Change of visibility. */
7034 static void
7035 mac_handle_visibility_change (f)
7036 struct frame *f;
7038 WindowRef wp = FRAME_MAC_WINDOW (f);
7039 int visible = 0, iconified = 0;
7040 struct input_event buf;
7042 if (IsWindowVisible (wp))
7044 if (IsWindowCollapsed (wp))
7045 iconified = 1;
7046 else
7047 visible = 1;
7050 if (!f->async_visible && visible)
7052 if (f->iconified)
7054 /* wait_reading_process_output will notice this and update
7055 the frame's display structures. If we were made
7056 invisible, we should not set garbaged, because that stops
7057 redrawing on Update events. */
7058 SET_FRAME_GARBAGED (f);
7060 EVENT_INIT (buf);
7061 buf.kind = DEICONIFY_EVENT;
7062 XSETFRAME (buf.frame_or_window, f);
7063 buf.arg = Qnil;
7064 kbd_buffer_store_event (&buf);
7066 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7067 /* Force a redisplay sooner or later to update the
7068 frame titles in case this is the second frame. */
7069 record_asynch_buffer_change ();
7071 else if (f->async_visible && !visible)
7072 if (iconified)
7074 EVENT_INIT (buf);
7075 buf.kind = ICONIFY_EVENT;
7076 XSETFRAME (buf.frame_or_window, f);
7077 buf.arg = Qnil;
7078 kbd_buffer_store_event (&buf);
7081 f->async_visible = visible;
7082 f->async_iconified = iconified;
7085 /* This tries to wait until the frame is really visible.
7086 However, if the window manager asks the user where to position
7087 the frame, this will return before the user finishes doing that.
7088 The frame will not actually be visible at that time,
7089 but it will become visible later when the window manager
7090 finishes with it. */
7092 void
7093 x_make_frame_visible (f)
7094 struct frame *f;
7096 BLOCK_INPUT;
7098 if (! FRAME_VISIBLE_P (f))
7100 /* We test FRAME_GARBAGED_P here to make sure we don't
7101 call x_set_offset a second time
7102 if we get to x_make_frame_visible a second time
7103 before the window gets really visible. */
7104 if (! FRAME_ICONIFIED_P (f)
7105 && ! f->output_data.mac->asked_for_visible)
7106 x_set_offset (f, f->left_pos, f->top_pos, 0);
7108 f->output_data.mac->asked_for_visible = 1;
7110 CollapseWindow (FRAME_MAC_WINDOW (f), false);
7111 ShowWindow (FRAME_MAC_WINDOW (f));
7114 XFlush (FRAME_MAC_DISPLAY (f));
7116 /* Synchronize to ensure Emacs knows the frame is visible
7117 before we do anything else. We do this loop with input not blocked
7118 so that incoming events are handled. */
7120 Lisp_Object frame;
7121 int count;
7123 /* This must come after we set COUNT. */
7124 UNBLOCK_INPUT;
7126 XSETFRAME (frame, f);
7128 /* Wait until the frame is visible. Process X events until a
7129 MapNotify event has been seen, or until we think we won't get a
7130 MapNotify at all.. */
7131 for (count = input_signal_count + 10;
7132 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7134 /* Force processing of queued events. */
7135 x_sync (f);
7137 /* Machines that do polling rather than SIGIO have been
7138 observed to go into a busy-wait here. So we'll fake an
7139 alarm signal to let the handler know that there's something
7140 to be read. We used to raise a real alarm, but it seems
7141 that the handler isn't always enabled here. This is
7142 probably a bug. */
7143 if (input_polling_used ())
7145 /* It could be confusing if a real alarm arrives while
7146 processing the fake one. Turn it off and let the
7147 handler reset it. */
7148 extern void poll_for_input_1 P_ ((void));
7149 int old_poll_suppress_count = poll_suppress_count;
7150 poll_suppress_count = 1;
7151 poll_for_input_1 ();
7152 poll_suppress_count = old_poll_suppress_count;
7155 /* See if a MapNotify event has been processed. */
7156 FRAME_SAMPLE_VISIBILITY (f);
7161 /* Change from mapped state to withdrawn state. */
7163 /* Make the frame visible (mapped and not iconified). */
7165 void
7166 x_make_frame_invisible (f)
7167 struct frame *f;
7169 /* A deactivate event does not occur when the last visible frame is
7170 made invisible. So if we clear the highlight here, it will not
7171 be rehighlighted when it is made visible. */
7172 #if 0
7173 /* Don't keep the highlight on an invisible frame. */
7174 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7175 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7176 #endif
7178 BLOCK_INPUT;
7180 #if !TARGET_API_MAC_CARBON
7181 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7182 that the current position of the window is user-specified, rather than
7183 program-specified, so that when the window is mapped again, it will be
7184 placed at the same location, without forcing the user to position it
7185 by hand again (they have already done that once for this window.) */
7186 x_wm_set_size_hint (f, (long) 0, 1);
7187 #endif
7189 HideWindow (FRAME_MAC_WINDOW (f));
7191 UNBLOCK_INPUT;
7193 #if !TARGET_API_MAC_CARBON
7194 mac_handle_visibility_change (f);
7195 #endif
7198 /* Change window state from mapped to iconified. */
7200 void
7201 x_iconify_frame (f)
7202 struct frame *f;
7204 OSStatus err;
7206 /* A deactivate event does not occur when the last visible frame is
7207 iconified. So if we clear the highlight here, it will not be
7208 rehighlighted when it is deiconified. */
7209 #if 0
7210 /* Don't keep the highlight on an invisible frame. */
7211 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7212 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7213 #endif
7215 if (f->async_iconified)
7216 return;
7218 BLOCK_INPUT;
7220 FRAME_SAMPLE_VISIBILITY (f);
7222 if (! FRAME_VISIBLE_P (f))
7223 ShowWindow (FRAME_MAC_WINDOW (f));
7225 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
7227 UNBLOCK_INPUT;
7229 if (err != noErr)
7230 error ("Can't notify window manager of iconification");
7232 #if !TARGET_API_MAC_CARBON
7233 mac_handle_visibility_change (f);
7234 #endif
7238 /* Free X resources of frame F. */
7240 void
7241 x_free_frame_resources (f)
7242 struct frame *f;
7244 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7245 WindowRef wp = FRAME_MAC_WINDOW (f);
7247 BLOCK_INPUT;
7249 if (wp != tip_window)
7250 remove_window_handler (wp);
7252 #if USE_CG_DRAWING
7253 mac_prepare_for_quickdraw (f);
7254 #endif
7255 DisposeWindow (wp);
7256 if (wp == tip_window)
7257 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7258 closed' event. So we reset tip_window here. */
7259 tip_window = NULL;
7261 free_frame_menubar (f);
7263 if (FRAME_FACE_CACHE (f))
7264 free_frame_faces (f);
7266 x_free_gcs (f);
7268 if (FRAME_SIZE_HINTS (f))
7269 xfree (FRAME_SIZE_HINTS (f));
7271 xfree (f->output_data.mac);
7272 f->output_data.mac = NULL;
7274 if (f == dpyinfo->x_focus_frame)
7276 dpyinfo->x_focus_frame = 0;
7277 #if USE_MAC_FONT_PANEL
7278 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7279 #endif
7281 if (f == dpyinfo->x_focus_event_frame)
7282 dpyinfo->x_focus_event_frame = 0;
7283 if (f == dpyinfo->x_highlight_frame)
7284 dpyinfo->x_highlight_frame = 0;
7286 if (f == dpyinfo->mouse_face_mouse_frame)
7288 dpyinfo->mouse_face_beg_row
7289 = dpyinfo->mouse_face_beg_col = -1;
7290 dpyinfo->mouse_face_end_row
7291 = dpyinfo->mouse_face_end_col = -1;
7292 dpyinfo->mouse_face_window = Qnil;
7293 dpyinfo->mouse_face_deferred_gc = 0;
7294 dpyinfo->mouse_face_mouse_frame = 0;
7297 UNBLOCK_INPUT;
7301 /* Destroy the X window of frame F. */
7303 void
7304 x_destroy_window (f)
7305 struct frame *f;
7307 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7309 x_free_frame_resources (f);
7311 dpyinfo->reference_count--;
7315 /* Setting window manager hints. */
7317 /* Set the normal size hints for the window manager, for frame F.
7318 FLAGS is the flags word to use--or 0 meaning preserve the flags
7319 that the window now has.
7320 If USER_POSITION is nonzero, we set the USPosition
7321 flag (this is useful when FLAGS is 0). */
7322 void
7323 x_wm_set_size_hint (f, flags, user_position)
7324 struct frame *f;
7325 long flags;
7326 int user_position;
7328 int base_width, base_height, width_inc, height_inc;
7329 int min_rows = 0, min_cols = 0;
7330 XSizeHints *size_hints;
7332 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7333 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7334 width_inc = FRAME_COLUMN_WIDTH (f);
7335 height_inc = FRAME_LINE_HEIGHT (f);
7337 check_frame_size (f, &min_rows, &min_cols);
7339 size_hints = FRAME_SIZE_HINTS (f);
7340 if (size_hints == NULL)
7342 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7343 bzero (size_hints, sizeof (XSizeHints));
7346 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7347 size_hints->width_inc = width_inc;
7348 size_hints->height_inc = height_inc;
7349 size_hints->min_width = base_width + min_cols * width_inc;
7350 size_hints->min_height = base_height + min_rows * height_inc;
7351 size_hints->base_width = base_width;
7352 size_hints->base_height = base_height;
7354 if (flags)
7355 size_hints->flags = flags;
7356 else if (user_position)
7358 size_hints->flags &= ~ PPosition;
7359 size_hints->flags |= USPosition;
7363 #if 0 /* MAC_TODO: hide application instead of iconify? */
7364 /* Used for IconicState or NormalState */
7366 void
7367 x_wm_set_window_state (f, state)
7368 struct frame *f;
7369 int state;
7371 #ifdef USE_X_TOOLKIT
7372 Arg al[1];
7374 XtSetArg (al[0], XtNinitialState, state);
7375 XtSetValues (f->output_data.x->widget, al, 1);
7376 #else /* not USE_X_TOOLKIT */
7377 Window window = FRAME_X_WINDOW (f);
7379 f->output_data.x->wm_hints.flags |= StateHint;
7380 f->output_data.x->wm_hints.initial_state = state;
7382 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7383 #endif /* not USE_X_TOOLKIT */
7386 void
7387 x_wm_set_icon_pixmap (f, pixmap_id)
7388 struct frame *f;
7389 int pixmap_id;
7391 Pixmap icon_pixmap;
7393 #ifndef USE_X_TOOLKIT
7394 Window window = FRAME_X_WINDOW (f);
7395 #endif
7397 if (pixmap_id > 0)
7399 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7400 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7402 else
7404 /* It seems there is no way to turn off use of an icon pixmap.
7405 The following line does it, only if no icon has yet been created,
7406 for some window managers. But with mwm it crashes.
7407 Some people say it should clear the IconPixmapHint bit in this case,
7408 but that doesn't work, and the X consortium said it isn't the
7409 right thing at all. Since there is no way to win,
7410 best to explicitly give up. */
7411 #if 0
7412 f->output_data.x->wm_hints.icon_pixmap = None;
7413 #else
7414 return;
7415 #endif
7418 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7421 Arg al[1];
7422 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7423 XtSetValues (f->output_data.x->widget, al, 1);
7426 #else /* not USE_X_TOOLKIT */
7428 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7429 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7431 #endif /* not USE_X_TOOLKIT */
7434 #endif /* MAC_TODO */
7436 void
7437 x_wm_set_icon_position (f, icon_x, icon_y)
7438 struct frame *f;
7439 int icon_x, icon_y;
7441 #if 0 /* MAC_TODO: no icons on Mac */
7442 #ifdef USE_X_TOOLKIT
7443 Window window = XtWindow (f->output_data.x->widget);
7444 #else
7445 Window window = FRAME_X_WINDOW (f);
7446 #endif
7448 f->output_data.x->wm_hints.flags |= IconPositionHint;
7449 f->output_data.x->wm_hints.icon_x = icon_x;
7450 f->output_data.x->wm_hints.icon_y = icon_y;
7452 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7453 #endif /* MAC_TODO */
7457 /***********************************************************************
7458 XLFD Pattern Match
7459 ***********************************************************************/
7461 /* An XLFD pattern is divided into blocks delimited by '*'. This
7462 structure holds information for each block. */
7463 struct xlfdpat_block
7465 /* Length of the pattern string in this block. Non-zero except for
7466 the first and the last blocks. */
7467 int len;
7469 /* Pattern string except the last character in this block. The last
7470 character is replaced with NUL in order to use it as a
7471 sentinel. */
7472 unsigned char *pattern;
7474 /* Last character of the pattern string. Must not be '?'. */
7475 unsigned char last_char;
7477 /* One of the tables for the Boyer-Moore string search. It
7478 specifies the number of positions to proceed for each character
7479 with which the match fails. */
7480 int skip[256];
7482 /* The skip value for the last character in the above `skip' is
7483 assigned to `infinity' in order to simplify a loop condition.
7484 The original value is saved here. */
7485 int last_char_skip;
7488 struct xlfdpat
7490 /* Normalized pattern string. "Normalized" means that capital
7491 letters are lowered, blocks are not empty except the first and
7492 the last ones, and trailing '?'s in a block that is not the last
7493 one are moved to the next one. The last character in each block
7494 is replaced with NUL. */
7495 unsigned char *buf;
7497 /* Number of characters except '*'s and trailing '?'s in the
7498 normalized pattern string. */
7499 int nchars;
7501 /* Number of trailing '?'s in the normalized pattern string. */
7502 int trailing_anychars;
7504 /* Number of blocks and information for each block. The latter is
7505 NULL if the pattern is exact (no '*' or '?' in it). */
7506 int nblocks;
7507 struct xlfdpat_block *blocks;
7510 static void
7511 xlfdpat_destroy (pat)
7512 struct xlfdpat *pat;
7514 if (pat)
7516 if (pat->buf)
7518 if (pat->blocks)
7519 xfree (pat->blocks);
7520 xfree (pat->buf);
7522 xfree (pat);
7526 static struct xlfdpat *
7527 xlfdpat_create (pattern)
7528 const char *pattern;
7530 struct xlfdpat *pat;
7531 int nblocks, i, skip;
7532 unsigned char last_char, *p, *q, *anychar_head;
7533 const unsigned char *ptr;
7534 struct xlfdpat_block *blk;
7536 pat = xmalloc (sizeof (struct xlfdpat));
7537 pat->buf = xmalloc (strlen (pattern) + 1);
7539 /* Normalize the pattern string and store it to `pat->buf'. */
7540 nblocks = 0;
7541 anychar_head = NULL;
7542 q = pat->buf;
7543 last_char = '\0';
7544 for (ptr = pattern; *ptr; ptr++)
7546 unsigned char c = *ptr;
7548 if (c == '*')
7549 if (last_char == '*')
7550 /* ...a** -> ...a* */
7551 continue;
7552 else
7554 if (last_char == '?')
7556 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7557 /* ...*??* -> ...*?? */
7558 continue;
7559 else
7560 /* ...a??* -> ...a*?? */
7562 *anychar_head++ = '*';
7563 c = '?';
7566 nblocks++;
7568 else if (c == '?')
7570 if (last_char != '?')
7571 anychar_head = q;
7573 else
7574 /* On Mac OS X 10.3, tolower also converts non-ASCII
7575 characters for some locales. */
7576 if (isascii (c))
7577 c = tolower (c);
7579 *q++ = last_char = c;
7581 *q = '\0';
7582 nblocks++;
7583 pat->nblocks = nblocks;
7584 if (last_char != '?')
7585 pat->trailing_anychars = 0;
7586 else
7588 pat->trailing_anychars = q - anychar_head;
7589 q = anychar_head;
7591 pat->nchars = q - pat->buf - (nblocks - 1);
7593 if (anychar_head == NULL && nblocks == 1)
7595 /* The pattern is exact. */
7596 pat->blocks = NULL;
7597 return pat;
7600 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
7602 /* Divide the normalized pattern into blocks. */
7603 p = pat->buf;
7604 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7606 blk->pattern = p;
7607 while (*p != '*')
7608 p++;
7609 blk->len = p - blk->pattern;
7610 p++;
7612 blk->pattern = p;
7613 blk->len = q - blk->pattern;
7615 /* Setup a table for the Boyer-Moore string search. */
7616 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7617 if (blk->len != 0)
7619 blk->last_char = blk->pattern[blk->len - 1];
7620 blk->pattern[blk->len - 1] = '\0';
7622 for (skip = 1; skip < blk->len; skip++)
7623 if (blk->pattern[blk->len - skip - 1] == '?')
7624 break;
7626 for (i = 0; i < 256; i++)
7627 blk->skip[i] = skip;
7629 p = blk->pattern + (blk->len - skip);
7630 while (--skip > 0)
7631 blk->skip[*p++] = skip;
7633 blk->last_char_skip = blk->skip[blk->last_char];
7636 return pat;
7639 static INLINE int
7640 xlfdpat_exact_p (pat)
7641 struct xlfdpat *pat;
7643 return pat->blocks == NULL;
7646 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
7647 that the pattern in *BLK matches with its prefix. Return NULL
7648 there is no such strings. STRING must be lowered in advance. */
7650 static const char *
7651 xlfdpat_block_match_1 (blk, string, start_max)
7652 struct xlfdpat_block *blk;
7653 const unsigned char *string;
7654 int start_max;
7656 int start, infinity;
7657 unsigned char *p;
7658 const unsigned char *s;
7660 xassert (blk->len > 0);
7661 xassert (start_max + blk->len <= strlen (string));
7662 xassert (blk->last_char != '?');
7664 /* See the comments in the function `boyer_moore' (search.c) for the
7665 use of `infinity'. */
7666 infinity = start_max + blk->len + 1;
7667 blk->skip[blk->last_char] = infinity;
7669 start = 0;
7672 /* Check the last character of the pattern. */
7673 s = string + blk->len - 1;
7676 start += blk->skip[*(s + start)];
7678 while (start <= start_max);
7680 if (start < infinity)
7681 /* Couldn't find the last character. */
7682 return NULL;
7684 /* No less than `infinity' means we could find the last
7685 character at `s[start - infinity]'. */
7686 start -= infinity;
7688 /* Check the remaining characters. We prefer making no-'?'
7689 cases faster because the use of '?' is really rare. */
7690 p = blk->pattern;
7691 s = string + start;
7694 while (*p++ == *s++)
7697 while (*(p - 1) == '?');
7699 if (*(p - 1) == '\0')
7700 /* Matched. */
7701 return string + start;
7703 /* Didn't match. */
7704 start += blk->last_char_skip;
7706 while (start <= start_max);
7708 return NULL;
7711 #define xlfdpat_block_match(b, s, m) \
7712 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7713 : xlfdpat_block_match_1 (b, s, m))
7715 /* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
7716 matches with STRING. STRING must be lowered in advance. */
7718 static int
7719 xlfdpat_match (pat, string)
7720 struct xlfdpat *pat;
7721 const unsigned char *string;
7723 int str_len, nblocks, i, start_max;
7724 struct xlfdpat_block *blk;
7725 const unsigned char *s;
7727 xassert (pat->nblocks > 0);
7729 if (xlfdpat_exact_p (pat))
7730 return strcmp (pat->buf, string) == 0;
7732 /* The number of the characters in the string must not be smaller
7733 than that in the pattern. */
7734 str_len = strlen (string);
7735 if (str_len < pat->nchars + pat->trailing_anychars)
7736 return 0;
7738 /* Chop off the trailing '?'s. */
7739 str_len -= pat->trailing_anychars;
7741 /* The last block. When it is non-empty, it must match at the end
7742 of the string. */
7743 nblocks = pat->nblocks;
7744 blk = pat->blocks + (nblocks - 1);
7745 if (nblocks == 1)
7746 /* The last block is also the first one. */
7747 return (str_len == blk->len
7748 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7749 else if (blk->len != 0)
7750 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7751 return 0;
7753 /* The first block. When it is non-empty, it must match at the
7754 beginning of the string. */
7755 blk = pat->blocks;
7756 if (blk->len != 0)
7758 s = xlfdpat_block_match (blk, string, 0);
7759 if (s == NULL)
7760 return 0;
7761 string = s + blk->len;
7764 /* The rest of the blocks. */
7765 start_max = str_len - pat->nchars;
7766 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7768 s = xlfdpat_block_match (blk, string, start_max);
7769 if (s == NULL)
7770 return 0;
7771 start_max -= s - string;
7772 string = s + blk->len;
7775 return 1;
7779 /***********************************************************************
7780 Fonts
7781 ***********************************************************************/
7783 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7785 struct font_info *
7786 x_get_font_info (f, font_idx)
7787 FRAME_PTR f;
7788 int font_idx;
7790 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7793 /* the global font name table */
7794 static char **font_name_table = NULL;
7795 static int font_name_table_size = 0;
7796 static int font_name_count = 0;
7798 /* Alist linking font family names to Font Manager font family
7799 references (which can also be used as QuickDraw font IDs). We use
7800 an alist because hash tables are not ready when the terminal frame
7801 for Mac OS Classic is created. */
7802 static Lisp_Object fm_font_family_alist;
7803 #if USE_ATSUI
7804 /* Hash table linking font family names to ATSU font IDs. */
7805 static Lisp_Object atsu_font_id_hash;
7806 /* Alist linking Font Manager style to face attributes. */
7807 static Lisp_Object fm_style_face_attributes_alist;
7808 extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
7809 #endif
7811 /* Alist linking character set strings to Mac text encoding and Emacs
7812 coding system. */
7813 static Lisp_Object Vmac_charset_info_alist;
7815 static Lisp_Object
7816 create_text_encoding_info_alist ()
7818 Lisp_Object result = Qnil, rest;
7820 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7822 Lisp_Object charset_info = XCAR (rest);
7823 Lisp_Object charset, coding_system, text_encoding;
7824 Lisp_Object existing_info;
7826 if (!(CONSP (charset_info)
7827 && (charset = XCAR (charset_info),
7828 STRINGP (charset))
7829 && CONSP (XCDR (charset_info))
7830 && (text_encoding = XCAR (XCDR (charset_info)),
7831 INTEGERP (text_encoding))
7832 && CONSP (XCDR (XCDR (charset_info)))
7833 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7834 SYMBOLP (coding_system))))
7835 continue;
7837 existing_info = assq_no_quit (text_encoding, result);
7838 if (NILP (existing_info))
7839 result = Fcons (list3 (text_encoding, coding_system, charset),
7840 result);
7841 else
7842 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7843 XSETCDR (XCDR (existing_info),
7844 Fcons (charset, XCDR (XCDR (existing_info))));
7847 return result;
7851 static void
7852 decode_mac_font_name (name, size, coding_system)
7853 char *name;
7854 int size;
7855 Lisp_Object coding_system;
7857 struct coding_system coding;
7858 char *buf, *p;
7860 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7862 for (p = name; *p; p++)
7863 if (!isascii (*p) || iscntrl (*p))
7864 break;
7866 if (*p)
7868 setup_coding_system (coding_system, &coding);
7869 coding.src_multibyte = 0;
7870 coding.dst_multibyte = 1;
7871 coding.mode |= CODING_MODE_LAST_BLOCK;
7872 coding.composing = COMPOSITION_DISABLED;
7873 buf = (char *) alloca (size);
7875 decode_coding (&coding, name, buf, strlen (name), size - 1);
7876 bcopy (buf, name, coding.produced);
7877 name[coding.produced] = '\0';
7881 /* If there's just one occurrence of '-' in the family name, it is
7882 replaced with '_'. (More than one occurrence of '-' means a
7883 "FOUNDRY-FAMILY-CHARSET"-style name.) */
7884 p = strchr (name, '-');
7885 if (p && strchr (p + 1, '-') == NULL)
7886 *p = '_';
7888 for (p = name; *p; p++)
7889 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7890 for some locales. */
7891 if (isascii (*p))
7892 *p = tolower (*p);
7896 static char *
7897 mac_to_x_fontname (name, size, style, charset)
7898 const char *name;
7899 int size;
7900 Style style;
7901 char *charset;
7903 Str31 foundry, cs;
7904 Str255 family;
7905 char xf[256], *result;
7906 unsigned char *p;
7908 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
7909 charset = cs;
7910 else
7912 strcpy(foundry, "Apple");
7913 strcpy(family, name);
7916 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
7917 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
7918 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
7920 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
7921 sprintf (result, "-%s-%s-%s", foundry, family, xf);
7922 for (p = result; *p; p++)
7923 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7924 for some locales. */
7925 if (isascii (*p))
7926 *p = tolower (*p);
7927 return result;
7931 /* Parse fully-specified and instantiated X11 font spec XF, and store
7932 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
7933 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
7934 caller must allocate at least 256 and 32 bytes respectively. For
7935 ordinary Mac fonts, the value stored to FAMILY should just be their
7936 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
7937 intlfonts collection contain their charset designation in their
7938 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
7939 types of font names are handled accordingly. */
7941 const int kDefaultFontSize = 12;
7943 static int
7944 parse_x_font_name (xf, family, size, style, charset)
7945 const char *xf;
7946 char *family;
7947 int *size;
7948 Style *style;
7949 char *charset;
7951 Str31 foundry, weight;
7952 int point_size, avgwidth;
7953 char slant[2], *p;
7955 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
7956 foundry, family, weight, slant, size,
7957 &point_size, &avgwidth, charset) != 8
7958 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
7959 foundry, family, weight, slant, size,
7960 &point_size, &avgwidth, charset) != 8)
7961 return 0;
7963 if (*size == 0)
7965 if (point_size > 0)
7966 *size = point_size / 10;
7967 else if (avgwidth > 0)
7968 *size = avgwidth / 10;
7970 if (*size == 0)
7971 *size = kDefaultFontSize;
7973 *style = normal;
7974 if (strcmp (weight, "bold") == 0)
7975 *style |= bold;
7976 if (*slant == 'i')
7977 *style |= italic;
7979 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
7981 int foundry_len = strlen (foundry), family_len = strlen (family);
7983 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
7985 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
7986 but take overlap into account. */
7987 memmove (family + foundry_len + 1, family, family_len);
7988 memcpy (family, foundry, foundry_len);
7989 family[foundry_len] = '-';
7990 family[foundry_len + 1 + family_len] = '-';
7991 strcpy (family + foundry_len + 1 + family_len + 1, charset);
7993 else
7994 return 0;
7997 for (p = family; *p; p++)
7998 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7999 for some locales. */
8000 if (isascii (*p))
8001 *p = tolower (*p);
8003 return 1;
8007 static void
8008 add_font_name_table_entry (char *font_name)
8010 if (font_name_table_size == 0)
8012 font_name_table_size = 256;
8013 font_name_table = (char **)
8014 xmalloc (font_name_table_size * sizeof (char *));
8016 else if (font_name_count + 1 >= font_name_table_size)
8018 font_name_table_size *= 2;
8019 font_name_table = (char **)
8020 xrealloc (font_name_table,
8021 font_name_table_size * sizeof (char *));
8024 font_name_table[font_name_count++] = font_name;
8027 static void
8028 add_mac_font_name (name, size, style, charset)
8029 const char *name;
8030 int size;
8031 Style style;
8032 const char *charset;
8034 if (size > 0)
8035 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8036 else
8038 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8039 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8040 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8041 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8042 charset));
8046 #if USE_ATSUI
8047 static FMFontStyle
8048 fm_get_style_from_font (font)
8049 FMFont font;
8051 OSStatus err;
8052 FMFontStyle style = normal;
8053 ByteCount len;
8054 UInt16 mac_style;
8055 FMFontFamily font_family;
8056 #define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8058 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8059 some font (e.g., Optima) even if it is `bold'. */
8060 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8061 sizeof (mac_style), &mac_style, &len);
8062 if (err == noErr
8063 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8064 style = EndianU16_BtoN (mac_style);
8065 else
8066 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8068 return style;
8071 static ATSUFontID
8072 atsu_find_font_from_family_name (family)
8073 const char *family;
8075 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8076 unsigned hash_code;
8077 int i;
8078 Lisp_Object rest, best;
8079 FMFontStyle min_style, style;
8081 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8082 &hash_code);
8083 if (i < 0)
8084 return kATSUInvalidFontID;
8086 rest = HASH_VALUE (h, i);
8087 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8088 return cons_to_long (rest);
8090 rest = Fnreverse (rest);
8091 best = XCAR (rest);
8092 rest = XCDR (rest);
8093 if (!NILP (rest)
8094 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8097 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8098 if (style < min_style)
8100 best = XCAR (rest);
8101 if (style == normal)
8102 break;
8103 else
8104 min_style = style;
8106 rest = XCDR (rest);
8108 while (!NILP (rest));
8110 HASH_VALUE (h, i) = best;
8111 return cons_to_long (best);
8114 static Lisp_Object
8115 fm_style_to_face_attributes (fm_style)
8116 FMFontStyle fm_style;
8118 Lisp_Object tem;
8120 fm_style &= (bold | italic);
8121 tem = assq_no_quit (make_number (fm_style),
8122 fm_style_face_attributes_alist);
8123 if (!NILP (tem))
8124 return XCDR (tem);
8126 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8127 QCslant, fm_style & italic ? Qitalic : Qnormal);
8128 fm_style_face_attributes_alist =
8129 Fcons (Fcons (make_number (fm_style), tem),
8130 fm_style_face_attributes_alist);
8132 return tem;
8135 static Lisp_Object
8136 atsu_find_font_family_name (font_id)
8137 ATSUFontID font_id;
8139 OSStatus err;
8140 ByteCount len;
8141 Lisp_Object family = Qnil;
8143 err = ATSUFindFontName (font_id, kFontFamilyName,
8144 kFontMacintoshPlatform, kFontNoScript,
8145 kFontNoLanguage, 0, NULL, &len, NULL);
8146 if (err == noErr)
8148 family = make_uninit_string (len);
8149 err = ATSUFindFontName (font_id, kFontFamilyName,
8150 kFontMacintoshPlatform, kFontNoScript,
8151 kFontNoLanguage, len, SDATA (family),
8152 NULL, NULL);
8154 if (err == noErr)
8155 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8157 return family;
8160 Lisp_Object
8161 mac_atsu_font_face_attributes (font_id)
8162 ATSUFontID font_id;
8164 Lisp_Object family, style_attrs;
8166 family = atsu_find_font_family_name (font_id);
8167 if (NILP (family))
8168 return Qnil;
8169 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8170 return Fcons (QCfamily, Fcons (family, style_attrs));
8172 #endif
8174 /* Sets up the table font_name_table to contain the list of all fonts
8175 in the system the first time the table is used so that the Resource
8176 Manager need not be accessed every time this information is
8177 needed. */
8179 static void
8180 init_font_name_table ()
8182 #if TARGET_API_MAC_CARBON
8183 FMFontFamilyIterator ffi;
8184 FMFontFamilyInstanceIterator ffii;
8185 FMFontFamily ff;
8186 Lisp_Object text_encoding_info_alist;
8187 struct gcpro gcpro1;
8189 text_encoding_info_alist = create_text_encoding_info_alist ();
8191 #if USE_ATSUI
8192 #if USE_CG_TEXT_DRAWING
8193 init_cg_text_anti_aliasing_threshold ();
8194 #endif
8195 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8196 text_encoding_info_alist)))
8198 OSStatus err;
8199 struct Lisp_Hash_Table *h;
8200 unsigned hash_code;
8201 ItemCount nfonts, i;
8202 ATSUFontID *font_ids = NULL;
8203 Lisp_Object prev_family = Qnil;
8204 int j;
8206 atsu_font_id_hash =
8207 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8208 make_float (DEFAULT_REHASH_SIZE),
8209 make_float (DEFAULT_REHASH_THRESHOLD),
8210 Qnil, Qnil, Qnil);
8211 h = XHASH_TABLE (atsu_font_id_hash);
8213 err = ATSUFontCount (&nfonts);
8214 if (err == noErr)
8216 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8217 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8219 if (err == noErr)
8220 for (i = 0; i < nfonts; i++)
8222 Lisp_Object family;
8224 family = atsu_find_font_family_name (font_ids[i]);
8225 if (NILP (family) || SREF (family, 0) == '.')
8226 continue;
8227 if (!NILP (Fequal (prev_family, family)))
8228 family = prev_family;
8229 else
8230 j = hash_lookup (h, family, &hash_code);
8231 if (j < 0)
8233 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8234 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8235 Qnil), hash_code);
8237 else if (EQ (prev_family, family))
8238 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8239 HASH_VALUE (h, j));
8240 prev_family = family;
8242 if (font_ids)
8243 xfree (font_ids);
8245 #endif
8247 /* Create a dummy instance iterator here to avoid creating and
8248 destroying it in the loop. */
8249 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8250 return;
8251 /* Create an iterator to enumerate the font families. */
8252 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8253 != noErr)
8255 FMDisposeFontFamilyInstanceIterator (&ffii);
8256 return;
8259 GCPRO1 (text_encoding_info_alist);
8261 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
8263 Str255 name;
8264 FMFont font;
8265 FMFontStyle style;
8266 FMFontSize size;
8267 TextEncoding encoding;
8268 TextEncodingBase sc;
8269 Lisp_Object text_encoding_info, family;
8271 if (FMGetFontFamilyName (ff, name) != noErr)
8272 continue;
8273 p2cstr (name);
8274 if (*name == '.')
8275 continue;
8277 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
8278 continue;
8279 sc = GetTextEncodingBase (encoding);
8280 text_encoding_info = assq_no_quit (make_number (sc),
8281 text_encoding_info_alist);
8282 if (NILP (text_encoding_info))
8283 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8284 text_encoding_info_alist);
8285 decode_mac_font_name (name, sizeof (name),
8286 XCAR (XCDR (text_encoding_info)));
8287 family = build_string (name);
8288 if (!NILP (Fassoc (family, fm_font_family_alist)))
8289 continue;
8290 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
8291 fm_font_family_alist);
8293 /* Point the instance iterator at the current font family. */
8294 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
8295 continue;
8297 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8298 == noErr)
8300 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8302 if (size > 0 || style == normal)
8303 for (; CONSP (rest); rest = XCDR (rest))
8304 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
8308 UNGCPRO;
8310 /* Dispose of the iterators. */
8311 FMDisposeFontFamilyIterator (&ffi);
8312 FMDisposeFontFamilyInstanceIterator (&ffii);
8313 #else /* !TARGET_API_MAC_CARBON */
8314 GrafPtr port;
8315 SInt16 fontnum, old_fontnum;
8316 int num_mac_fonts = CountResources('FOND');
8317 int i, j;
8318 Handle font_handle, font_handle_2;
8319 short id, scriptcode;
8320 ResType type;
8321 Str255 name;
8322 struct FontAssoc *fat;
8323 struct AsscEntry *assc_entry;
8324 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
8325 struct gcpro gcpro1;
8327 GetPort (&port); /* save the current font number used */
8328 old_fontnum = port->txFont;
8330 text_encoding_info_alist = create_text_encoding_info_alist ();
8332 GCPRO1 (text_encoding_info_alist);
8334 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
8336 font_handle = GetIndResource ('FOND', i);
8337 if (!font_handle)
8338 continue;
8340 GetResInfo (font_handle, &id, &type, name);
8341 GetFNum (name, &fontnum);
8342 p2cstr (name);
8343 if (fontnum == 0 || *name == '.')
8344 continue;
8346 TextFont (fontnum);
8347 scriptcode = FontToScript (fontnum);
8348 text_encoding_info = assq_no_quit (make_number (scriptcode),
8349 text_encoding_info_alist);
8350 if (NILP (text_encoding_info))
8351 text_encoding_info = assq_no_quit (make_number (smRoman),
8352 text_encoding_info_alist);
8353 decode_mac_font_name (name, sizeof (name),
8354 XCAR (XCDR (text_encoding_info)));
8355 family = build_string (name);
8356 if (!NILP (Fassoc (family, fm_font_family_alist)))
8357 continue;
8358 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
8359 fm_font_family_alist);
8362 HLock (font_handle);
8364 if (GetResourceSizeOnDisk (font_handle)
8365 >= sizeof (struct FamRec))
8367 fat = (struct FontAssoc *) (*font_handle
8368 + sizeof (struct FamRec));
8369 assc_entry
8370 = (struct AsscEntry *) (*font_handle
8371 + sizeof (struct FamRec)
8372 + sizeof (struct FontAssoc));
8374 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
8376 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8378 for (; CONSP (rest); rest = XCDR (rest))
8379 add_mac_font_name (name, assc_entry->fontSize,
8380 assc_entry->fontStyle,
8381 SDATA (XCAR (rest)));
8385 HUnlock (font_handle);
8386 font_handle_2 = GetNextFOND (font_handle);
8387 ReleaseResource (font_handle);
8388 font_handle = font_handle_2;
8390 while (ResError () == noErr && font_handle);
8393 UNGCPRO;
8395 TextFont (old_fontnum);
8396 #endif /* !TARGET_API_MAC_CARBON */
8400 void
8401 mac_clear_font_name_table ()
8403 int i;
8405 for (i = 0; i < font_name_count; i++)
8406 xfree (font_name_table[i]);
8407 xfree (font_name_table);
8408 font_name_table = NULL;
8409 font_name_table_size = font_name_count = 0;
8410 fm_font_family_alist = Qnil;
8414 enum xlfd_scalable_field_index
8416 XLFD_SCL_PIXEL_SIZE,
8417 XLFD_SCL_POINT_SIZE,
8418 XLFD_SCL_AVGWIDTH,
8419 XLFD_SCL_LAST
8422 static const int xlfd_scalable_fields[] =
8424 6, /* PIXEL_SIZE */
8425 7, /* POINT_SIZE */
8426 11, /* AVGWIDTH */
8430 static Lisp_Object
8431 mac_do_list_fonts (pattern, maxnames)
8432 const char *pattern;
8433 int maxnames;
8435 int i, n_fonts = 0;
8436 Lisp_Object font_list = Qnil;
8437 struct xlfdpat *pat;
8438 char *scaled;
8439 const char *ptr;
8440 int scl_val[XLFD_SCL_LAST], *val;
8441 const int *field;
8442 int exact;
8444 if (font_name_table == NULL) /* Initialize when first used. */
8445 init_font_name_table ();
8447 for (i = 0; i < XLFD_SCL_LAST; i++)
8448 scl_val[i] = -1;
8450 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8451 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8452 fonts are scaled according to the specified size. */
8453 ptr = pattern;
8454 i = 0;
8455 field = xlfd_scalable_fields;
8456 val = scl_val;
8457 if (*ptr == '-')
8460 ptr++;
8461 if (i == *field)
8463 if ('0' <= *ptr && *ptr <= '9')
8465 *val = *ptr++ - '0';
8466 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8467 *val = *val * 10 + *ptr++ - '0';
8468 if (*ptr != '-')
8469 *val = -1;
8471 field++;
8472 val++;
8474 ptr = strchr (ptr, '-');
8475 i++;
8477 while (ptr && i < 14);
8479 if (i == 14 && ptr == NULL)
8481 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8482 scl_val[XLFD_SCL_PIXEL_SIZE] =
8483 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8484 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8485 : -1));
8486 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8487 scl_val[XLFD_SCL_POINT_SIZE] =
8488 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8489 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8490 : -1));
8491 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8492 scl_val[XLFD_SCL_AVGWIDTH] =
8493 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8494 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8495 : -1));
8497 else
8498 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8500 pat = xlfdpat_create (pattern);
8501 if (pat == NULL)
8502 return Qnil;
8504 exact = xlfdpat_exact_p (pat);
8506 for (i = 0; i < font_name_count; i++)
8508 if (xlfdpat_match (pat, font_name_table[i]))
8510 font_list = Fcons (build_string (font_name_table[i]), font_list);
8511 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8512 break;
8514 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
8515 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
8517 int former_len = ptr - font_name_table[i];
8519 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
8520 memcpy (scaled, font_name_table[i], former_len);
8521 sprintf (scaled + former_len,
8522 "-%d-%d-72-72-m-%d-%s",
8523 scl_val[XLFD_SCL_PIXEL_SIZE],
8524 scl_val[XLFD_SCL_POINT_SIZE],
8525 scl_val[XLFD_SCL_AVGWIDTH],
8526 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
8528 if (xlfdpat_match (pat, scaled))
8530 font_list = Fcons (build_string (scaled), font_list);
8531 xfree (scaled);
8532 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8533 break;
8535 else
8536 xfree (scaled);
8540 xlfdpat_destroy (pat);
8542 return font_list;
8545 /* Return a list of names of available fonts matching PATTERN on frame F.
8547 Frame F null means we have not yet created any frame on Mac, and
8548 consult the first display in x_display_list. MAXNAMES sets a limit
8549 on how many fonts to match. */
8551 Lisp_Object
8552 x_list_fonts (f, pattern, size, maxnames)
8553 struct frame *f;
8554 Lisp_Object pattern;
8555 int size, maxnames;
8557 Lisp_Object list = Qnil, patterns, tem, key;
8558 struct mac_display_info *dpyinfo
8559 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
8561 xassert (size <= 0);
8563 patterns = Fassoc (pattern, Valternate_fontname_alist);
8564 if (NILP (patterns))
8565 patterns = Fcons (pattern, Qnil);
8567 for (; CONSP (patterns); patterns = XCDR (patterns))
8569 pattern = XCAR (patterns);
8571 if (!STRINGP (pattern))
8572 continue;
8574 tem = XCAR (XCDR (dpyinfo->name_list_element));
8575 key = Fcons (pattern, make_number (maxnames));
8577 list = Fassoc (key, tem);
8578 if (!NILP (list))
8580 list = Fcdr_safe (list);
8581 /* We have a cashed list. Don't have to get the list again. */
8582 goto label_cached;
8585 BLOCK_INPUT;
8586 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8587 UNBLOCK_INPUT;
8589 /* MAC_TODO: add code for matching outline fonts here */
8591 /* Now store the result in the cache. */
8592 XSETCAR (XCDR (dpyinfo->name_list_element),
8593 Fcons (Fcons (key, list),
8594 XCAR (XCDR (dpyinfo->name_list_element))));
8596 label_cached:
8597 if (NILP (list)) continue; /* Try the remaining alternatives. */
8600 return list;
8604 #if GLYPH_DEBUG
8606 /* Check that FONT is valid on frame F. It is if it can be found in F's
8607 font table. */
8609 static void
8610 x_check_font (f, font)
8611 struct frame *f;
8612 XFontStruct *font;
8614 int i;
8615 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8617 xassert (font != NULL);
8619 for (i = 0; i < dpyinfo->n_fonts; i++)
8620 if (dpyinfo->font_table[i].name
8621 && font == dpyinfo->font_table[i].font)
8622 break;
8624 xassert (i < dpyinfo->n_fonts);
8627 #endif /* GLYPH_DEBUG != 0 */
8629 /* Set *W to the minimum width, *H to the minimum font height of FONT.
8630 Note: There are (broken) X fonts out there with invalid XFontStruct
8631 min_bounds contents. For example, handa@etl.go.jp reports that
8632 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8633 have font->min_bounds.width == 0. */
8635 static INLINE void
8636 x_font_min_bounds (font, w, h)
8637 MacFontStruct *font;
8638 int *w, *h;
8640 *h = FONT_HEIGHT (font);
8641 *w = font->min_bounds.width;
8645 /* Compute the smallest character width and smallest font height over
8646 all fonts available on frame F. Set the members smallest_char_width
8647 and smallest_font_height in F's x_display_info structure to
8648 the values computed. Value is non-zero if smallest_font_height or
8649 smallest_char_width become smaller than they were before. */
8651 static int
8652 x_compute_min_glyph_bounds (f)
8653 struct frame *f;
8655 int i;
8656 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8657 MacFontStruct *font;
8658 int old_width = dpyinfo->smallest_char_width;
8659 int old_height = dpyinfo->smallest_font_height;
8661 dpyinfo->smallest_font_height = 100000;
8662 dpyinfo->smallest_char_width = 100000;
8664 for (i = 0; i < dpyinfo->n_fonts; ++i)
8665 if (dpyinfo->font_table[i].name)
8667 struct font_info *fontp = dpyinfo->font_table + i;
8668 int w, h;
8670 font = (MacFontStruct *) fontp->font;
8671 xassert (font != (MacFontStruct *) ~0);
8672 x_font_min_bounds (font, &w, &h);
8674 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8675 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8678 xassert (dpyinfo->smallest_char_width > 0
8679 && dpyinfo->smallest_font_height > 0);
8681 return (dpyinfo->n_fonts == 1
8682 || dpyinfo->smallest_char_width < old_width
8683 || dpyinfo->smallest_font_height < old_height);
8687 /* Determine whether given string is a fully-specified XLFD: all 14
8688 fields are present, none is '*'. */
8690 static int
8691 is_fully_specified_xlfd (p)
8692 const char *p;
8694 int i;
8695 char *q;
8697 if (*p != '-')
8698 return 0;
8700 for (i = 0; i < 13; i++)
8702 q = strchr (p + 1, '-');
8703 if (q == NULL)
8704 return 0;
8705 if (q - p == 2 && *(p + 1) == '*')
8706 return 0;
8707 p = q;
8710 if (strchr (p + 1, '-') != NULL)
8711 return 0;
8713 if (*(p + 1) == '*' && *(p + 2) == '\0')
8714 return 0;
8716 return 1;
8720 /* mac_load_query_font creates and returns an internal representation
8721 for a font in a MacFontStruct struct. There is really no concept
8722 corresponding to "loading" a font on the Mac. But we check its
8723 existence and find the font number and all other information for it
8724 and store them in the returned MacFontStruct. */
8726 static MacFontStruct *
8727 mac_load_query_font (f, fontname)
8728 struct frame *f;
8729 char *fontname;
8731 int size;
8732 char *name;
8733 Str255 family;
8734 Str31 charset;
8735 SInt16 fontnum;
8736 #if USE_ATSUI
8737 static ATSUFontID font_id;
8738 ATSUStyle mac_style = NULL;
8739 #endif
8740 Style fontface;
8741 #if TARGET_API_MAC_CARBON
8742 TextEncoding encoding;
8743 int scriptcode;
8744 #else
8745 short scriptcode;
8746 #endif
8747 MacFontStruct *font;
8748 XCharStruct *space_bounds = NULL, *pcm;
8750 if (is_fully_specified_xlfd (fontname))
8751 name = fontname;
8752 else
8754 Lisp_Object matched_fonts;
8756 matched_fonts = mac_do_list_fonts (fontname, 1);
8757 if (NILP (matched_fonts))
8758 return NULL;
8759 name = SDATA (XCAR (matched_fonts));
8762 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8763 return NULL;
8765 #if USE_ATSUI
8766 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8768 OSStatus err;
8769 static const ATSUAttributeTag tags[] =
8770 {kATSUFontTag, kATSUSizeTag,
8771 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8772 static const ByteCount sizes[] =
8773 {sizeof (ATSUFontID), sizeof (Fixed),
8774 sizeof (Boolean), sizeof (Boolean)};
8775 static Fixed size_fixed;
8776 static Boolean bold_p, italic_p;
8777 static const ATSUAttributeValuePtr values[] =
8778 {&font_id, &size_fixed,
8779 &bold_p, &italic_p};
8780 static const ATSUFontFeatureType types[] =
8781 {kAllTypographicFeaturesType, kDiacriticsType};
8782 static const ATSUFontFeatureSelector selectors[] =
8783 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
8784 FMFontStyle style;
8786 font_id = atsu_find_font_from_family_name (family);
8787 if (font_id == kATSUInvalidFontID)
8788 return NULL;
8789 size_fixed = Long2Fix (size);
8790 bold_p = (fontface & bold) != 0;
8791 italic_p = (fontface & italic) != 0;
8792 err = ATSUCreateStyle (&mac_style);
8793 if (err != noErr)
8794 return NULL;
8795 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8796 types, selectors);
8797 if (err != noErr)
8798 return NULL;
8799 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8800 tags, sizes, values);
8801 if (err != noErr)
8802 return NULL;
8803 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8804 if (err != noErr)
8805 fontnum = -1;
8806 scriptcode = kTextEncodingMacUnicode;
8808 else
8809 #endif
8811 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8813 if (NILP (tmp))
8814 return NULL;
8815 fontnum = XINT (XCDR (tmp));
8816 #if TARGET_API_MAC_CARBON
8817 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8818 return NULL;
8819 scriptcode = GetTextEncodingBase (encoding);
8820 #else
8821 scriptcode = FontToScript (fontnum);
8822 #endif
8825 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
8827 font->mac_fontnum = fontnum;
8828 font->mac_fontsize = size;
8829 font->mac_fontface = fontface;
8830 font->mac_scriptcode = scriptcode;
8831 #if USE_ATSUI
8832 font->mac_style = mac_style;
8833 #if USE_CG_TEXT_DRAWING
8834 font->cg_font = NULL;
8835 font->cg_glyphs = NULL;
8836 #endif
8837 #endif
8839 /* Apple Japanese (SJIS) font is listed as both
8840 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
8841 (Roman script) in init_font_name_table (). The latter should be
8842 treated as a one-byte font. */
8843 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8844 font->mac_scriptcode = smRoman;
8846 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
8848 #if USE_ATSUI
8849 if (font->mac_style)
8851 OSStatus err;
8852 UniChar c;
8854 font->min_byte1 = 0;
8855 font->max_byte1 = 0xff;
8856 font->min_char_or_byte2 = 0;
8857 font->max_char_or_byte2 = 0xff;
8859 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8860 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8861 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8862 pcm_init (font->bounds.rows[0], 0x100);
8864 #if USE_CG_TEXT_DRAWING
8865 if (fontnum != -1)
8867 FMFontStyle style;
8868 ATSFontRef ats_font;
8870 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
8871 &font_id, &style);
8872 /* Use CG text drawing if italic/bold is not synthesized. */
8873 if (err == noErr && style == fontface)
8875 ats_font = FMGetATSFontRefFromFont (font_id);
8876 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
8880 if (font->cg_font)
8882 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
8883 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
8885 #endif
8886 space_bounds = font->bounds.rows[0] + 0x20;
8887 err = mac_query_char_extents (font->mac_style, 0x20,
8888 &font->ascent, &font->descent,
8889 space_bounds,
8890 #if USE_CG_TEXT_DRAWING
8891 (font->cg_glyphs ? font->cg_glyphs + 0x20
8892 : NULL)
8893 #else
8894 NULL
8895 #endif
8897 if (err != noErr
8898 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
8900 mac_unload_font (&one_mac_display_info, font);
8901 return NULL;
8904 pcm = font->bounds.rows[0];
8905 for (c = 0x21; c <= 0xff; c++)
8907 if (c == 0xad)
8908 /* Soft hyphen is not supported in ATSUI. */
8909 continue;
8910 else if (c == 0x7f)
8912 #if USE_CG_TEXT_DRAWING
8913 if (font->cg_glyphs)
8915 c = 0x9f;
8916 pcm = NULL;
8917 continue;
8919 #endif
8920 break;
8923 mac_query_char_extents (font->mac_style, c, NULL, NULL,
8924 pcm ? pcm + c : NULL,
8925 #if USE_CG_TEXT_DRAWING
8926 (font->cg_glyphs ? font->cg_glyphs + c
8927 : NULL)
8928 #else
8929 NULL
8930 #endif
8933 #if USE_CG_TEXT_DRAWING
8934 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
8936 /* Don't use CG text drawing if font substitution occurs in
8937 ASCII or Latin-1 characters. */
8938 CGFontRelease (font->cg_font);
8939 font->cg_font = NULL;
8940 xfree (font->cg_glyphs);
8941 font->cg_glyphs = NULL;
8942 if (pcm == NULL)
8943 break;
8945 #endif
8948 else
8949 #endif
8951 OSStatus err;
8952 FontInfo the_fontinfo;
8953 int is_two_byte_font;
8955 #if USE_CG_DRAWING
8956 mac_prepare_for_quickdraw (f);
8957 #endif
8958 SetPortWindowPort (FRAME_MAC_WINDOW (f));
8960 TextFont (fontnum);
8961 TextSize (size);
8962 TextFace (fontface);
8964 GetFontInfo (&the_fontinfo);
8966 font->ascent = the_fontinfo.ascent;
8967 font->descent = the_fontinfo.descent;
8969 is_two_byte_font = (font->mac_scriptcode == smJapanese
8970 || font->mac_scriptcode == smTradChinese
8971 || font->mac_scriptcode == smSimpChinese
8972 || font->mac_scriptcode == smKorean);
8974 if (is_two_byte_font)
8976 int char_width;
8978 font->min_byte1 = 0xa1;
8979 font->max_byte1 = 0xfe;
8980 font->min_char_or_byte2 = 0xa1;
8981 font->max_char_or_byte2 = 0xfe;
8983 /* Use the width of an "ideographic space" of that font
8984 because the_fontinfo.widMax returns the wrong width for
8985 some fonts. */
8986 switch (font->mac_scriptcode)
8988 case smJapanese:
8989 font->min_byte1 = 0x81;
8990 font->max_byte1 = 0xfc;
8991 font->min_char_or_byte2 = 0x40;
8992 font->max_char_or_byte2 = 0xfc;
8993 char_width = StringWidth("\p\x81\x40");
8994 break;
8995 case smTradChinese:
8996 font->min_char_or_byte2 = 0x40;
8997 char_width = StringWidth("\p\xa1\x40");
8998 break;
8999 case smSimpChinese:
9000 char_width = StringWidth("\p\xa1\xa1");
9001 break;
9002 case smKorean:
9003 char_width = StringWidth("\p\xa1\xa1");
9004 break;
9007 font->bounds.per_char = NULL;
9009 if (fontface & italic)
9010 font->max_bounds.rbearing = char_width + 1;
9011 else
9012 font->max_bounds.rbearing = char_width;
9013 font->max_bounds.lbearing = 0;
9014 font->max_bounds.width = char_width;
9015 font->max_bounds.ascent = the_fontinfo.ascent;
9016 font->max_bounds.descent = the_fontinfo.descent;
9018 font->min_bounds = font->max_bounds;
9020 else
9022 int c;
9024 font->min_byte1 = font->max_byte1 = 0;
9025 font->min_char_or_byte2 = 0x20;
9026 font->max_char_or_byte2 = 0xff;
9028 font->bounds.per_char =
9029 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
9030 bzero (font->bounds.per_char,
9031 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9033 space_bounds = font->bounds.per_char;
9034 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9035 &font->descent, space_bounds, NULL);
9036 if (err != noErr || space_bounds->width <= 0)
9038 mac_unload_font (&one_mac_display_info, font);
9039 return NULL;
9042 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9043 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
9047 if (space_bounds)
9049 int c;
9051 font->min_bounds = font->max_bounds = *space_bounds;
9052 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9053 if (pcm->width > 0)
9055 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9056 pcm->lbearing);
9057 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9058 pcm->rbearing);
9059 font->min_bounds.width = min (font->min_bounds.width,
9060 pcm->width);
9061 font->min_bounds.ascent = min (font->min_bounds.ascent,
9062 pcm->ascent);
9063 font->min_bounds.descent = min (font->min_bounds.descent,
9064 pcm->descent);
9066 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9067 pcm->lbearing);
9068 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9069 pcm->rbearing);
9070 font->max_bounds.width = max (font->max_bounds.width,
9071 pcm->width);
9072 font->max_bounds.ascent = max (font->max_bounds.ascent,
9073 pcm->ascent);
9074 font->max_bounds.descent = max (font->max_bounds.descent,
9075 pcm->descent);
9077 if (
9078 #if USE_ATSUI
9079 font->mac_style == NULL &&
9080 #endif
9081 font->max_bounds.width == font->min_bounds.width
9082 && font->min_bounds.lbearing >= 0
9083 && font->max_bounds.rbearing <= font->max_bounds.width)
9085 /* Fixed width and no overhangs. */
9086 xfree (font->bounds.per_char);
9087 font->bounds.per_char = NULL;
9091 #if !defined (MAC_OS8) || USE_ATSUI
9092 /* AppKit and WebKit do some adjustment to the heights of Courier,
9093 Helvetica, and Times. This only works on the environments where
9094 srcCopy text transfer mode is never used. */
9095 if (
9096 #ifdef MAC_OS8 /* implies USE_ATSUI */
9097 font->mac_style &&
9098 #endif
9099 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9100 || strcmp (family, "times") == 0))
9101 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9102 #endif
9104 return font;
9108 void
9109 mac_unload_font (dpyinfo, font)
9110 struct mac_display_info *dpyinfo;
9111 XFontStruct *font;
9113 xfree (font->full_name);
9114 #if USE_ATSUI
9115 if (font->mac_style)
9117 int i;
9119 for (i = font->min_byte1; i <= font->max_byte1; i++)
9120 if (font->bounds.rows[i])
9121 xfree (font->bounds.rows[i]);
9122 xfree (font->bounds.rows);
9123 ATSUDisposeStyle (font->mac_style);
9125 else
9126 #endif
9127 if (font->bounds.per_char)
9128 xfree (font->bounds.per_char);
9129 #if USE_CG_TEXT_DRAWING
9130 if (font->cg_font)
9131 CGFontRelease (font->cg_font);
9132 if (font->cg_glyphs)
9133 xfree (font->cg_glyphs);
9134 #endif
9135 xfree (font);
9139 /* Load font named FONTNAME of the size SIZE for frame F, and return a
9140 pointer to the structure font_info while allocating it dynamically.
9141 If SIZE is 0, load any size of font.
9142 If loading is failed, return NULL. */
9144 struct font_info *
9145 x_load_font (f, fontname, size)
9146 struct frame *f;
9147 register char *fontname;
9148 int size;
9150 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9151 Lisp_Object font_names;
9153 /* Get a list of all the fonts that match this name. Once we
9154 have a list of matching fonts, we compare them against the fonts
9155 we already have by comparing names. */
9156 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9158 if (!NILP (font_names))
9160 Lisp_Object tail;
9161 int i;
9163 for (i = 0; i < dpyinfo->n_fonts; i++)
9164 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9165 if (dpyinfo->font_table[i].name
9166 && (!strcmp (dpyinfo->font_table[i].name,
9167 SDATA (XCAR (tail)))
9168 || !strcmp (dpyinfo->font_table[i].full_name,
9169 SDATA (XCAR (tail)))))
9170 return (dpyinfo->font_table + i);
9172 else
9173 return NULL;
9175 /* Load the font and add it to the table. */
9177 struct MacFontStruct *font;
9178 struct font_info *fontp;
9179 int i;
9181 fontname = (char *) SDATA (XCAR (font_names));
9183 BLOCK_INPUT;
9184 font = mac_load_query_font (f, fontname);
9185 UNBLOCK_INPUT;
9186 if (!font)
9187 return NULL;
9189 /* Find a free slot in the font table. */
9190 for (i = 0; i < dpyinfo->n_fonts; ++i)
9191 if (dpyinfo->font_table[i].name == NULL)
9192 break;
9194 /* If no free slot found, maybe enlarge the font table. */
9195 if (i == dpyinfo->n_fonts
9196 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9198 int sz;
9199 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9200 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9201 dpyinfo->font_table
9202 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9205 fontp = dpyinfo->font_table + i;
9206 if (i == dpyinfo->n_fonts)
9207 ++dpyinfo->n_fonts;
9209 /* Now fill in the slots of *FONTP. */
9210 BLOCK_INPUT;
9211 bzero (fontp, sizeof (*fontp));
9212 fontp->font = font;
9213 fontp->font_idx = i;
9214 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9215 bcopy (fontname, fontp->name, strlen (fontname) + 1);
9217 if (font->min_bounds.width == font->max_bounds.width)
9219 /* Fixed width font. */
9220 fontp->average_width = fontp->space_width = font->min_bounds.width;
9222 else
9224 XChar2b char2b;
9225 XCharStruct *pcm;
9227 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9228 pcm = mac_per_char_metric (font, &char2b, 0);
9229 if (pcm)
9230 fontp->space_width = pcm->width;
9231 else
9232 fontp->space_width = FONT_WIDTH (font);
9234 if (pcm)
9236 int width = pcm->width;
9237 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9238 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9239 width += pcm->width;
9240 fontp->average_width = width / 95;
9242 else
9243 fontp->average_width = FONT_WIDTH (font);
9246 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9247 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
9249 fontp->size = font->max_bounds.width;
9250 fontp->height = FONT_HEIGHT (font);
9252 /* For some font, ascent and descent in max_bounds field is
9253 larger than the above value. */
9254 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9255 if (max_height > fontp->height)
9256 fontp->height = max_height;
9259 /* The slot `encoding' specifies how to map a character
9260 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9261 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9262 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9263 2:0xA020..0xFF7F). For the moment, we don't know which charset
9264 uses this font. So, we set information in fontp->encoding[1]
9265 which is never used by any charset. If mapping can't be
9266 decided, set FONT_ENCODING_NOT_DECIDED. */
9267 if (font->mac_scriptcode == smJapanese)
9268 fontp->encoding[1] = 4;
9269 else
9271 fontp->encoding[1]
9272 = (font->max_byte1 == 0
9273 /* 1-byte font */
9274 ? (font->min_char_or_byte2 < 0x80
9275 ? (font->max_char_or_byte2 < 0x80
9276 ? 0 /* 0x20..0x7F */
9277 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9278 : 1) /* 0xA0..0xFF */
9279 /* 2-byte font */
9280 : (font->min_byte1 < 0x80
9281 ? (font->max_byte1 < 0x80
9282 ? (font->min_char_or_byte2 < 0x80
9283 ? (font->max_char_or_byte2 < 0x80
9284 ? 0 /* 0x2020..0x7F7F */
9285 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9286 : 3) /* 0x20A0..0x7FFF */
9287 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9288 : (font->min_char_or_byte2 < 0x80
9289 ? (font->max_char_or_byte2 < 0x80
9290 ? 2 /* 0xA020..0xFF7F */
9291 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9292 : 1))); /* 0xA0A0..0xFFFF */
9295 #if 0 /* MAC_TODO: fill these out with more reasonably values */
9296 fontp->baseline_offset
9297 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9298 ? (long) value : 0);
9299 fontp->relative_compose
9300 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9301 ? (long) value : 0);
9302 fontp->default_ascent
9303 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9304 ? (long) value : 0);
9305 #else
9306 fontp->baseline_offset = 0;
9307 fontp->relative_compose = 0;
9308 fontp->default_ascent = 0;
9309 #endif
9311 /* Set global flag fonts_changed_p to non-zero if the font loaded
9312 has a character with a smaller width than any other character
9313 before, or if the font loaded has a smaller height than any
9314 other font loaded before. If this happens, it will make a
9315 glyph matrix reallocation necessary. */
9316 fonts_changed_p |= x_compute_min_glyph_bounds (f);
9317 UNBLOCK_INPUT;
9318 return fontp;
9323 /* Return a pointer to struct font_info of a font named FONTNAME for
9324 frame F. If no such font is loaded, return NULL. */
9326 struct font_info *
9327 x_query_font (f, fontname)
9328 struct frame *f;
9329 register char *fontname;
9331 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9332 int i;
9334 for (i = 0; i < dpyinfo->n_fonts; i++)
9335 if (dpyinfo->font_table[i].name
9336 && (!xstricmp (dpyinfo->font_table[i].name, fontname)
9337 || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
9338 return (dpyinfo->font_table + i);
9339 return NULL;
9343 /* Find a CCL program for a font specified by FONTP, and set the member
9344 `encoder' of the structure. */
9346 void
9347 x_find_ccl_program (fontp)
9348 struct font_info *fontp;
9350 Lisp_Object list, elt;
9352 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9354 elt = XCAR (list);
9355 if (CONSP (elt)
9356 && STRINGP (XCAR (elt))
9357 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9358 >= 0))
9359 break;
9361 if (! NILP (list))
9363 struct ccl_program *ccl
9364 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9366 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9367 xfree (ccl);
9368 else
9369 fontp->font_encoder = ccl;
9373 #if USE_MAC_FONT_PANEL
9374 /* Whether Font Panel has been shown before. The first call to font
9375 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9376 slow. This variable is used for deferring such a call as much as
9377 possible. */
9378 static int font_panel_shown_p = 0;
9380 extern Lisp_Object Qfont;
9381 static Lisp_Object Qpanel_closed, Qselection;
9383 static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9384 Lisp_Object,
9385 Lisp_Object,
9386 EventRef, UInt32,
9387 const EventParamName *,
9388 const EventParamType *));
9391 mac_font_panel_visible_p ()
9393 return font_panel_shown_p && FPIsFontPanelVisible ();
9396 static pascal OSStatus
9397 mac_handle_font_event (next_handler, event, data)
9398 EventHandlerCallRef next_handler;
9399 EventRef event;
9400 void *data;
9402 OSStatus result, err;
9403 Lisp_Object id_key;
9404 int num_params;
9405 const EventParamName *names;
9406 const EventParamType *types;
9407 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9408 kEventParamATSUFontSize,
9409 kEventParamFMFontFamily,
9410 kEventParamFMFontStyle,
9411 kEventParamFMFontSize,
9412 kEventParamFontColor};
9413 static const EventParamType types_sel[] = {typeATSUFontID,
9414 typeATSUSize,
9415 typeFMFontFamily,
9416 typeFMFontStyle,
9417 typeFMFontSize,
9418 typeFontColor};
9420 result = CallNextEventHandler (next_handler, event);
9421 if (result != eventNotHandledErr)
9422 return result;
9424 switch (GetEventKind (event))
9426 case kEventFontPanelClosed:
9427 id_key = Qpanel_closed;
9428 num_params = 0;
9429 names = NULL;
9430 types = NULL;
9431 break;
9433 case kEventFontSelection:
9434 id_key = Qselection;
9435 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9436 names = names_sel;
9437 types = types_sel;
9438 break;
9441 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9442 event, num_params,
9443 names, types);
9444 if (err == noErr)
9445 result = noErr;
9447 return result;
9450 OSStatus
9451 mac_show_hide_font_panel ()
9453 if (!font_panel_shown_p)
9455 OSStatus err;
9457 static const EventTypeSpec specs[] =
9458 {{kEventClassFont, kEventFontPanelClosed},
9459 {kEventClassFont, kEventFontSelection}};
9461 err = InstallApplicationEventHandler (mac_handle_font_event,
9462 GetEventTypeCount (specs),
9463 specs, NULL, NULL);
9464 if (err != noErr)
9465 return err;
9467 font_panel_shown_p = 1;
9470 return FPShowHideFontPanel ();
9473 OSStatus
9474 mac_set_font_info_for_selection (f, face_id, c)
9475 struct frame *f;
9476 int face_id, c;
9478 OSStatus err;
9479 EventTargetRef target = NULL;
9480 XFontStruct *font = NULL;
9482 if (!mac_font_panel_visible_p ())
9483 return noErr;
9485 if (f)
9487 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
9489 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9491 struct face *face;
9493 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9494 face = FACE_FROM_ID (f, face_id);
9495 font = face->font;
9499 if (font == NULL)
9500 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9501 else
9503 if (font->mac_fontnum != -1)
9505 FontSelectionQDStyle qd_style;
9507 qd_style.version = kFontSelectionQDStyleVersionZero;
9508 qd_style.instance.fontFamily = font->mac_fontnum;
9509 qd_style.instance.fontStyle = font->mac_fontface;
9510 qd_style.size = font->mac_fontsize;
9511 qd_style.hasColor = false;
9513 err = SetFontInfoForSelection (kFontSelectionQDType,
9514 1, &qd_style, target);
9516 else
9517 err = SetFontInfoForSelection (kFontSelectionATSUIType,
9518 1, &font->mac_style, target);
9521 return err;
9523 #endif
9526 /* The Mac Event loop code */
9528 #if !TARGET_API_MAC_CARBON
9529 #include <Events.h>
9530 #include <Quickdraw.h>
9531 #include <Balloons.h>
9532 #include <Devices.h>
9533 #include <Fonts.h>
9534 #include <Gestalt.h>
9535 #include <Menus.h>
9536 #include <Processes.h>
9537 #include <Sound.h>
9538 #include <ToolUtils.h>
9539 #include <TextUtils.h>
9540 #include <Dialogs.h>
9541 #include <Script.h>
9542 #include <Types.h>
9543 #include <Resources.h>
9545 #if __MWERKS__
9546 #include <unix.h>
9547 #endif
9548 #endif /* ! TARGET_API_MAC_CARBON */
9550 #define M_APPLE 234
9551 #define I_ABOUT 1
9553 #define DEFAULT_NUM_COLS 80
9555 #define MIN_DOC_SIZE 64
9556 #define MAX_DOC_SIZE 32767
9558 #define EXTRA_STACK_ALLOC (256 * 1024)
9560 #define ARGV_STRING_LIST_ID 129
9561 #define ABOUT_ALERT_ID 128
9562 #define RAM_TOO_LARGE_ALERT_ID 129
9564 /* Contains the string "reverse", which is a constant for mouse button emu.*/
9565 Lisp_Object Qreverse;
9568 /* Modifier associated with the control key, or nil to ignore. */
9569 Lisp_Object Vmac_control_modifier;
9571 /* Modifier associated with the option key, or nil to ignore. */
9572 Lisp_Object Vmac_option_modifier;
9574 /* Modifier associated with the command key, or nil to ignore. */
9575 Lisp_Object Vmac_command_modifier;
9577 /* Modifier associated with the function key, or nil to ignore. */
9578 Lisp_Object Vmac_function_modifier;
9580 /* True if the option and command modifiers should be used to emulate
9581 a three button mouse */
9582 Lisp_Object Vmac_emulate_three_button_mouse;
9584 #if TARGET_API_MAC_CARBON
9585 /* Non-zero if the mouse wheel button (i.e. button 4) should map to
9586 mouse-2, instead of mouse-3. */
9587 int mac_wheel_button_is_mouse_2;
9589 /* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
9590 for processing before Emacs sees it. */
9591 int mac_pass_command_to_system;
9593 /* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
9594 for processing before Emacs sees it. */
9595 int mac_pass_control_to_system;
9596 #endif
9598 /* Points to the variable `inev' in the function XTread_socket. It is
9599 used for passing an input event to the function back from
9600 Carbon/Apple event handlers. */
9601 static struct input_event *read_socket_inev = NULL;
9603 /* Whether or not the screen configuration has changed. */
9604 static int mac_screen_config_changed = 0;
9606 Point saved_menu_event_location;
9608 /* Apple Events */
9609 #if TARGET_API_MAC_CARBON
9610 static Lisp_Object Qhi_command;
9611 #ifdef MAC_OSX
9612 extern Lisp_Object Qwindow;
9613 static Lisp_Object Qtoolbar_switch_mode;
9614 #endif
9615 #if USE_MAC_TSM
9616 static TSMDocumentID tsm_document_id;
9617 static Lisp_Object Qtext_input;
9618 static Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
9619 static Lisp_Object Vmac_ts_active_input_overlay;
9620 extern Lisp_Object Qbefore_string;
9621 static Lisp_Object Vmac_ts_script_language_on_focus;
9622 static Lisp_Object saved_ts_script_language_on_focus;
9623 static ScriptLanguageRecord saved_ts_language;
9624 static Component saved_ts_component;
9625 #endif
9626 #endif /* TARGET_API_MAC_CARBON */
9627 extern int mac_ready_for_apple_events;
9628 extern Lisp_Object Qundefined;
9629 extern void init_apple_event_handler P_ ((void));
9630 extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9631 Lisp_Object *, Lisp_Object *,
9632 Lisp_Object *));
9633 extern OSErr init_coercion_handler P_ ((void));
9635 /* Drag and Drop */
9636 extern OSErr install_drag_handler P_ ((WindowRef));
9637 extern void remove_drag_handler P_ ((WindowRef));
9639 #if TARGET_API_MAC_CARBON
9640 /* Showing help echo string during menu tracking */
9641 extern OSStatus install_menu_target_item_handler P_ ((void));
9643 #ifdef MAC_OSX
9644 extern OSStatus install_service_handler ();
9645 static Lisp_Object Qservice, Qpaste, Qperform;
9646 #endif
9647 #endif
9649 extern void init_emacs_passwd_dir ();
9650 extern int emacs_main (int, char **, char **);
9652 extern void initialize_applescript();
9653 extern void terminate_applescript();
9655 /* Table for translating Mac keycode to X keysym values. Contributed
9656 by Sudhir Shenoy.
9657 Mapping for special keys is now identical to that in Apple X11
9658 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9659 on the right of the Cmd key on laptops, and fn + `enter' (->
9660 <linefeed>). */
9661 static const unsigned char keycode_to_xkeysym_table[] = {
9662 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9663 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9664 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9666 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9667 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9668 /*0x38*/ 0, 0, 0, 0,
9669 /*0x3C*/ 0, 0, 0, 0,
9671 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9672 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9673 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9674 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9676 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9677 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9678 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9679 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9681 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9682 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9683 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9684 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9686 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9687 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9688 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9689 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9692 #ifdef MAC_OSX
9693 /* Table for translating Mac keycode with the laptop `fn' key to that
9694 without it. Destination symbols in comments are keys on US
9695 keyboard, and they may not be the same on other types of keyboards.
9696 If the destination is identical to the source (f1 ... f12), it
9697 doesn't map `fn' key to a modifier. */
9698 static const unsigned char fn_keycode_to_keycode_table[] = {
9699 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9700 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9701 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9703 /*0x30*/ 0, 0, 0, 0,
9704 /*0x34*/ 0, 0, 0, 0,
9705 /*0x38*/ 0, 0, 0, 0,
9706 /*0x3C*/ 0, 0, 0, 0,
9708 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9709 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9710 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9711 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9713 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9714 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9715 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9716 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9718 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9719 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9720 /*0x68*/ 0, 0, 0, 0,
9721 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9723 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9724 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9725 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9726 /*0x7C*/ 0, 0, 0, 0
9728 #endif /* MAC_OSX */
9730 static int
9731 #if TARGET_API_MAC_CARBON
9732 mac_to_emacs_modifiers (UInt32 mods)
9733 #else
9734 mac_to_emacs_modifiers (EventModifiers mods)
9735 #endif
9737 unsigned int result = 0;
9738 if (mods & shiftKey)
9739 result |= shift_modifier;
9741 /* Deactivated to simplify configuration:
9742 if Vmac_option_modifier is non-NIL, we fully process the Option
9743 key. Otherwise, we only process it if an additional Ctrl or Command
9744 is pressed. That way the system may convert the character to a
9745 composed one.
9746 if ((mods & optionKey) &&
9747 (( !NILP(Vmac_option_modifier) ||
9748 ((mods & cmdKey) || (mods & controlKey))))) */
9750 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
9751 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9752 if (INTEGERP(val))
9753 result |= XUINT(val);
9755 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9756 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9757 if (INTEGERP(val))
9758 result |= XUINT(val);
9760 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9761 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9762 if (INTEGERP(val))
9763 result |= XUINT(val);
9766 #ifdef MAC_OSX
9767 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9768 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9769 if (INTEGERP(val))
9770 result |= XUINT(val);
9772 #endif
9774 return result;
9777 static UInt32
9778 mac_mapped_modifiers (modifiers)
9779 UInt32 modifiers;
9781 UInt32 mapped_modifiers_all =
9782 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9783 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9784 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9786 #ifdef MAC_OSX
9787 mapped_modifiers_all |=
9788 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9789 #endif
9791 return mapped_modifiers_all & modifiers;
9794 static int
9795 mac_get_emulated_btn ( UInt32 modifiers )
9797 int result = 0;
9798 if (!NILP (Vmac_emulate_three_button_mouse)) {
9799 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
9800 if (modifiers & cmdKey)
9801 result = cmdIs3 ? 2 : 1;
9802 else if (modifiers & optionKey)
9803 result = cmdIs3 ? 1 : 2;
9805 return result;
9808 #if TARGET_API_MAC_CARBON
9809 /***** Code to handle C-g testing *****/
9810 extern int quit_char;
9811 extern int make_ctrl_char P_ ((int));
9814 mac_quit_char_key_p (modifiers, key_code)
9815 UInt32 modifiers, key_code;
9817 UInt32 char_code;
9818 unsigned long some_state = 0;
9819 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
9820 int c, emacs_modifiers;
9822 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
9823 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
9824 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
9825 if (char_code & ~0xff)
9826 return 0;
9828 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
9829 if (emacs_modifiers & ctrl_modifier)
9830 c = make_ctrl_char (char_code);
9832 c |= (emacs_modifiers
9833 & (meta_modifier | alt_modifier
9834 | hyper_modifier | super_modifier));
9836 return c == quit_char;
9838 #endif
9840 #if TARGET_API_MAC_CARBON
9841 /* Obtains the event modifiers from the event ref and then calls
9842 mac_to_emacs_modifiers. */
9843 static int
9844 mac_event_to_emacs_modifiers (EventRef eventRef)
9846 UInt32 mods = 0, class;
9848 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
9849 sizeof (UInt32), NULL, &mods);
9850 class = GetEventClass (eventRef);
9851 if (!NILP (Vmac_emulate_three_button_mouse) &&
9852 (class == kEventClassMouse || class == kEventClassCommand))
9854 mods &= ~(optionKey | cmdKey);
9856 return mac_to_emacs_modifiers (mods);
9859 /* Given an event ref, return the code to use for the mouse button
9860 code in the emacs input_event. */
9861 static int
9862 mac_get_mouse_btn (EventRef ref)
9864 EventMouseButton result = kEventMouseButtonPrimary;
9865 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
9866 sizeof (EventMouseButton), NULL, &result);
9867 switch (result)
9869 case kEventMouseButtonPrimary:
9870 if (NILP (Vmac_emulate_three_button_mouse))
9871 return 0;
9872 else {
9873 UInt32 mods = 0;
9874 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
9875 sizeof (UInt32), NULL, &mods);
9876 return mac_get_emulated_btn(mods);
9878 case kEventMouseButtonSecondary:
9879 return mac_wheel_button_is_mouse_2 ? 2 : 1;
9880 case kEventMouseButtonTertiary:
9881 case 4: /* 4 is the number for the mouse wheel button */
9882 return mac_wheel_button_is_mouse_2 ? 1 : 2;
9883 default:
9884 return 0;
9888 /* Normally, ConvertEventRefToEventRecord will correctly handle all
9889 events. However the click of the mouse wheel is not converted to a
9890 mouseDown or mouseUp event. Likewise for dead key events. This
9891 calls ConvertEventRefToEventRecord, but then checks to see if it is
9892 a mouse up/down, or a dead key Carbon event that has not been
9893 converted, and if so, converts it by hand (to be picked up in the
9894 XTread_socket loop). */
9895 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
9897 OSStatus err;
9898 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
9899 EventKind action;
9901 if (result)
9902 return result;
9904 switch (GetEventClass (eventRef))
9906 case kEventClassMouse:
9907 switch (GetEventKind (eventRef))
9909 case kEventMouseDown:
9910 eventRec->what = mouseDown;
9911 result = 1;
9912 break;
9914 case kEventMouseUp:
9915 eventRec->what = mouseUp;
9916 result = 1;
9917 break;
9919 default:
9920 break;
9922 break;
9924 case kEventClassKeyboard:
9925 switch (GetEventKind (eventRef))
9927 case kEventRawKeyDown:
9928 action = keyDown;
9929 goto keystroke_common;
9930 case kEventRawKeyRepeat:
9931 action = autoKey;
9932 goto keystroke_common;
9933 case kEventRawKeyUp:
9934 action = keyUp;
9935 keystroke_common:
9937 unsigned char char_codes;
9938 UInt32 key_code;
9940 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
9941 typeChar, NULL, sizeof (char),
9942 NULL, &char_codes);
9943 if (err == noErr)
9944 err = GetEventParameter (eventRef, kEventParamKeyCode,
9945 typeUInt32, NULL, sizeof (UInt32),
9946 NULL, &key_code);
9947 if (err == noErr)
9949 eventRec->what = action;
9950 eventRec->message = char_codes | ((key_code & 0xff) << 8);
9951 result = 1;
9954 break;
9956 default:
9957 break;
9959 break;
9961 default:
9962 break;
9965 if (result)
9967 /* Need where and when. */
9968 UInt32 mods = 0;
9970 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
9971 NULL, sizeof (Point), NULL, &eventRec->where);
9972 /* Use two step process because new event modifiers are 32-bit
9973 and old are 16-bit. Currently, only loss is NumLock & Fn. */
9974 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
9975 NULL, sizeof (UInt32), NULL, &mods);
9976 eventRec->modifiers = mods;
9978 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
9981 return result;
9984 #endif
9986 #ifdef MAC_OS8
9987 static void
9988 do_get_menus (void)
9990 Handle menubar_handle;
9991 MenuRef menu;
9993 menubar_handle = GetNewMBar (128);
9994 if(menubar_handle == NULL)
9995 abort ();
9996 SetMenuBar (menubar_handle);
9997 DrawMenuBar ();
9999 #if !TARGET_API_MAC_CARBON
10000 menu = GetMenuRef (M_APPLE);
10001 if (menu != NULL)
10002 AppendResMenu (menu, 'DRVR');
10003 else
10004 abort ();
10005 #endif
10009 static void
10010 do_init_managers (void)
10012 #if !TARGET_API_MAC_CARBON
10013 InitGraf (&qd.thePort);
10014 InitFonts ();
10015 FlushEvents (everyEvent, 0);
10016 InitWindows ();
10017 InitMenus ();
10018 TEInit ();
10019 InitDialogs (NULL);
10020 #endif /* !TARGET_API_MAC_CARBON */
10021 InitCursor ();
10023 #if !TARGET_API_MAC_CARBON
10024 /* set up some extra stack space for use by emacs */
10025 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10027 /* MaxApplZone must be called for AppleScript to execute more
10028 complicated scripts */
10029 MaxApplZone ();
10030 MoreMasters ();
10031 #endif /* !TARGET_API_MAC_CARBON */
10034 static void
10035 do_check_ram_size (void)
10037 SInt32 physical_ram_size, logical_ram_size;
10039 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10040 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
10041 || physical_ram_size > (1 << VALBITS)
10042 || logical_ram_size > (1 << VALBITS))
10044 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10045 exit (1);
10048 #endif /* MAC_OS8 */
10050 static void
10051 do_window_update (WindowRef win)
10053 struct frame *f = mac_window_to_frame (win);
10055 BeginUpdate (win);
10057 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10058 below. */
10059 if (win != tip_window)
10061 if (f->async_visible == 0)
10063 /* Update events may occur when a frame gets iconified. */
10064 #if 0
10065 f->async_visible = 1;
10066 f->async_iconified = 0;
10067 SET_FRAME_GARBAGED (f);
10068 #endif
10070 else
10072 Rect r;
10073 #if TARGET_API_MAC_CARBON
10074 RgnHandle region = NewRgn ();
10076 GetPortVisibleRegion (GetWindowPort (win), region);
10077 GetRegionBounds (region, &r);
10078 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10079 #if USE_CG_DRAWING
10080 mac_prepare_for_quickdraw (f);
10081 #endif
10082 UpdateControls (win, region);
10083 DisposeRgn (region);
10084 #else
10085 r = (*win->visRgn)->rgnBBox;
10086 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10087 UpdateControls (win, win->visRgn);
10088 #endif
10092 EndUpdate (win);
10095 static int
10096 is_emacs_window (WindowRef win)
10098 Lisp_Object tail, frame;
10100 if (!win)
10101 return 0;
10103 FOR_EACH_FRAME (tail, frame)
10104 if (FRAME_MAC_P (XFRAME (frame)))
10105 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10106 return 1;
10108 return 0;
10111 #if USE_MAC_TSM
10112 static OSStatus
10113 mac_tsm_resume ()
10115 OSStatus err;
10116 ScriptLanguageRecord slrec, *slptr = NULL;
10118 err = ActivateTSMDocument (tsm_document_id);
10120 if (err == noErr)
10122 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10123 && EQ (saved_ts_script_language_on_focus, Qt))
10124 slptr = &saved_ts_language;
10125 else if (CONSP (Vmac_ts_script_language_on_focus)
10126 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10127 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10128 && CONSP (saved_ts_script_language_on_focus)
10129 && EQ (XCAR (saved_ts_script_language_on_focus),
10130 XCAR (Vmac_ts_script_language_on_focus))
10131 && EQ (XCDR (saved_ts_script_language_on_focus),
10132 XCDR (Vmac_ts_script_language_on_focus)))
10134 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10135 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10136 slptr = &slrec;
10140 if (slptr)
10142 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10143 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10144 kKeyboardInputMethodClass);
10145 #else
10146 err = SetDefaultInputMethod (saved_ts_component, slptr);
10147 #endif
10148 if (err == noErr)
10149 err = SetTextServiceLanguage (slptr);
10151 /* Seems to be needed on Mac OS X 10.2. */
10152 if (err == noErr)
10153 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10156 return err;
10159 static OSStatus
10160 mac_tsm_suspend ()
10162 OSStatus err;
10163 ScriptLanguageRecord slrec, *slptr = NULL;
10165 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10167 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10169 err = GetTextServiceLanguage (&saved_ts_language);
10170 if (err == noErr)
10171 slptr = &saved_ts_language;
10173 else if (CONSP (Vmac_ts_script_language_on_focus)
10174 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10175 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10177 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10178 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10179 slptr = &slrec;
10182 if (slptr)
10184 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10185 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10186 kKeyboardInputMethodClass);
10187 #else
10188 GetDefaultInputMethod (&saved_ts_component, slptr);
10189 #endif
10192 err = DeactivateTSMDocument (tsm_document_id);
10194 return err;
10196 #endif
10198 #if !TARGET_API_MAC_CARBON
10199 void
10200 do_apple_menu (SInt16 menu_item)
10202 Str255 item_name;
10203 SInt16 da_driver_refnum;
10205 if (menu_item == I_ABOUT)
10206 NoteAlert (ABOUT_ALERT_ID, NULL);
10207 else
10209 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
10210 da_driver_refnum = OpenDeskAcc (item_name);
10213 #endif /* !TARGET_API_MAC_CARBON */
10215 /* Handle drags in size box. Based on code contributed by Ben
10216 Mesander and IM - Window Manager A. */
10218 static void
10219 do_grow_window (w, e)
10220 WindowRef w;
10221 const EventRecord *e;
10223 Rect limit_rect;
10224 int rows, columns, width, height;
10225 struct frame *f = mac_window_to_frame (w);
10226 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10227 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10228 #if TARGET_API_MAC_CARBON
10229 Rect new_rect;
10230 #else
10231 long grow_size;
10232 #endif
10234 if (size_hints->flags & PMinSize)
10236 min_width = size_hints->min_width;
10237 min_height = size_hints->min_height;
10239 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
10241 #if TARGET_API_MAC_CARBON
10242 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10243 return;
10244 height = new_rect.bottom - new_rect.top;
10245 width = new_rect.right - new_rect.left;
10246 #else
10247 grow_size = GrowWindow (w, e->where, &limit_rect);
10248 /* see if it really changed size */
10249 if (grow_size == 0)
10250 return;
10251 height = HiWord (grow_size);
10252 width = LoWord (grow_size);
10253 #endif
10255 if (width != FRAME_PIXEL_WIDTH (f)
10256 || height != FRAME_PIXEL_HEIGHT (f))
10258 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10259 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10261 x_set_window_size (f, 0, columns, rows);
10266 #if TARGET_API_MAC_CARBON
10267 static Point
10268 mac_get_ideal_size (f)
10269 struct frame *f;
10271 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10272 WindowRef w = FRAME_MAC_WINDOW (f);
10273 Point ideal_size;
10274 Rect standard_rect;
10275 int height, width, columns, rows;
10277 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10278 ideal_size.v = dpyinfo->height;
10279 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10280 /* Adjust the standard size according to character boundaries. */
10281 width = standard_rect.right - standard_rect.left;
10282 height = standard_rect.bottom - standard_rect.top;
10283 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10284 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10285 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10286 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10288 return ideal_size;
10290 #endif
10292 /* Handle clicks in zoom box. Calculation of "standard state" based
10293 on code in IM - Window Manager A and code contributed by Ben
10294 Mesander. The standard state of an Emacs window is 80-characters
10295 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10297 static void
10298 do_zoom_window (WindowRef w, int zoom_in_or_out)
10300 Rect zoom_rect, port_rect;
10301 int width, height;
10302 struct frame *f = mac_window_to_frame (w);
10303 #if TARGET_API_MAC_CARBON
10304 Point ideal_size = mac_get_ideal_size (f);
10306 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10307 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10308 && port_rect.left == zoom_rect.left
10309 && port_rect.top == zoom_rect.top)
10310 zoom_in_or_out = inZoomIn;
10311 else
10312 zoom_in_or_out = inZoomOut;
10314 #ifdef MAC_OS8
10315 mac_clear_window (f);
10316 #endif
10317 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
10318 #else /* not TARGET_API_MAC_CARBON */
10319 GrafPtr save_port;
10320 Point top_left;
10321 int w_title_height, rows;
10322 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10324 GetPort (&save_port);
10326 SetPortWindowPort (w);
10328 /* Clear window to avoid flicker. */
10329 EraseRect (&(w->portRect));
10330 if (zoom_in_or_out == inZoomOut)
10332 SetPt (&top_left, w->portRect.left, w->portRect.top);
10333 LocalToGlobal (&top_left);
10335 /* calculate height of window's title bar */
10336 w_title_height = top_left.v - 1
10337 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
10339 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10340 zoom_rect = qd.screenBits.bounds;
10341 zoom_rect.top += w_title_height;
10342 InsetRect (&zoom_rect, 8, 4); /* not too tight */
10344 zoom_rect.right = zoom_rect.left
10345 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10347 /* Adjust the standard size according to character boundaries. */
10348 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10349 zoom_rect.bottom =
10350 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10352 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10353 = zoom_rect;
10356 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
10358 SetPort (save_port);
10359 #endif /* not TARGET_API_MAC_CARBON */
10361 #if !TARGET_API_MAC_CARBON
10362 /* retrieve window size and update application values */
10363 port_rect = w->portRect;
10364 height = port_rect.bottom - port_rect.top;
10365 width = port_rect.right - port_rect.left;
10367 mac_handle_size_change (f, width, height);
10368 mac_handle_origin_change (f);
10369 #endif
10372 static void
10373 mac_set_unicode_keystroke_event (code, buf)
10374 UniChar code;
10375 struct input_event *buf;
10377 int charset_id, c1, c2;
10379 if (code < 0x80)
10381 buf->kind = ASCII_KEYSTROKE_EVENT;
10382 buf->code = code;
10384 else if (code < 0x100)
10386 if (code < 0xA0)
10387 charset_id = CHARSET_8_BIT_CONTROL;
10388 else
10389 charset_id = charset_latin_iso8859_1;
10390 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10391 buf->code = MAKE_CHAR (charset_id, code, 0);
10393 else
10395 if (code < 0x2500)
10396 charset_id = charset_mule_unicode_0100_24ff,
10397 code -= 0x100;
10398 else if (code < 0x33FF)
10399 charset_id = charset_mule_unicode_2500_33ff,
10400 code -= 0x2500;
10401 else if (code >= 0xE000)
10402 charset_id = charset_mule_unicode_e000_ffff,
10403 code -= 0xE000;
10404 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10405 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10406 buf->code = MAKE_CHAR (charset_id, c1, c2);
10410 static void
10411 do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10412 EventKind action;
10413 unsigned char char_code;
10414 UInt32 key_code, modifiers;
10415 unsigned long timestamp;
10416 struct input_event *buf;
10418 static SInt16 last_key_script = -1;
10419 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10420 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10422 #ifdef MAC_OSX
10423 if (mapped_modifiers & kEventKeyModifierFnMask
10424 && key_code <= 0x7f
10425 && fn_keycode_to_keycode_table[key_code])
10426 key_code = fn_keycode_to_keycode_table[key_code];
10427 #endif
10429 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10431 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10432 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10433 #ifdef MAC_OSX
10434 if (modifiers & kEventKeyModifierFnMask
10435 && key_code <= 0x7f
10436 && fn_keycode_to_keycode_table[key_code] == key_code)
10437 modifiers &= ~kEventKeyModifierFnMask;
10438 #endif
10440 else if (mapped_modifiers)
10442 /* translate the keycode back to determine the original key */
10443 #ifdef MAC_OSX
10444 UCKeyboardLayout *uchr_ptr = NULL;
10445 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10446 OSStatus err;
10447 KeyboardLayoutRef layout;
10449 err = KLGetCurrentKeyboardLayout (&layout);
10450 if (err == noErr)
10451 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10452 (const void **) &uchr_ptr);
10453 #else
10454 static SInt16 last_key_layout_id = 0;
10455 static Handle uchr_handle = (Handle)-1;
10456 SInt16 current_key_layout_id =
10457 GetScriptVariable (current_key_script, smScriptKeys);
10459 if (uchr_handle == (Handle)-1
10460 || last_key_layout_id != current_key_layout_id)
10462 uchr_handle = GetResource ('uchr', current_key_layout_id);
10463 last_key_layout_id = current_key_layout_id;
10465 if (uchr_handle)
10466 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10467 #endif
10469 if (uchr_ptr)
10471 OSStatus status;
10472 UInt16 key_action = action - keyDown;
10473 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10474 UInt32 keyboard_type = LMGetKbdType ();
10475 SInt32 dead_key_state = 0;
10476 UniChar code;
10477 UniCharCount actual_length;
10479 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10480 modifier_key_state, keyboard_type,
10481 kUCKeyTranslateNoDeadKeysMask,
10482 &dead_key_state,
10483 1, &actual_length, &code);
10484 if (status == noErr && actual_length == 1)
10485 mac_set_unicode_keystroke_event (code, buf);
10487 #endif /* MAC_OSX */
10489 if (buf->kind == NO_EVENT)
10491 /* This code comes from Keyboard Resource, Appendix C of IM
10492 - Text. This is necessary since shift is ignored in KCHR
10493 table translation when option or command is pressed. It
10494 also does not translate correctly control-shift chars
10495 like C-% so mask off shift here also. */
10496 /* Mask off modifier keys that are mapped to some Emacs
10497 modifiers. */
10498 int new_modifiers = modifiers & ~mapped_modifiers;
10499 /* set high byte of keycode to modifier high byte*/
10500 int new_key_code = key_code | new_modifiers;
10501 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10502 unsigned long some_state = 0;
10503 UInt32 new_char_code;
10505 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10506 if (new_char_code == 0)
10507 /* Seems like a dead key. Append up-stroke. */
10508 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10509 &some_state);
10510 if (new_char_code)
10512 buf->kind = ASCII_KEYSTROKE_EVENT;
10513 buf->code = new_char_code & 0xff;
10518 if (buf->kind == NO_EVENT)
10520 buf->kind = ASCII_KEYSTROKE_EVENT;
10521 buf->code = char_code;
10524 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10525 buf->modifiers |= (extra_keyboard_modifiers
10526 & (meta_modifier | alt_modifier
10527 | hyper_modifier | super_modifier));
10529 #if TARGET_API_MAC_CARBON
10530 if (buf->kind == ASCII_KEYSTROKE_EVENT
10531 && buf->code >= 0x80 && buf->modifiers)
10533 OSStatus err;
10534 TextEncoding encoding = kTextEncodingMacRoman;
10535 TextToUnicodeInfo ttu_info;
10537 UpgradeScriptInfoToTextEncoding (current_key_script,
10538 kTextLanguageDontCare,
10539 kTextRegionDontCare,
10540 NULL, &encoding);
10541 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10542 if (err == noErr)
10544 UniChar code;
10545 Str255 pstr;
10546 ByteCount unicode_len;
10548 pstr[0] = 1;
10549 pstr[1] = buf->code;
10550 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10551 sizeof (UniChar),
10552 &unicode_len, &code);
10553 if (err == noErr && unicode_len == sizeof (UniChar))
10554 mac_set_unicode_keystroke_event (code, buf);
10555 DisposeTextToUnicodeInfo (&ttu_info);
10558 #endif
10560 if (buf->kind == ASCII_KEYSTROKE_EVENT
10561 && buf->code >= 0x80
10562 && last_key_script != current_key_script)
10564 struct input_event event;
10566 EVENT_INIT (event);
10567 event.kind = LANGUAGE_CHANGE_EVENT;
10568 event.arg = Qnil;
10569 event.code = current_key_script;
10570 event.timestamp = timestamp;
10571 kbd_buffer_store_event (&event);
10572 last_key_script = current_key_script;
10576 void
10577 mac_store_apple_event (class, id, desc)
10578 Lisp_Object class, id;
10579 const AEDesc *desc;
10581 struct input_event buf;
10583 EVENT_INIT (buf);
10585 buf.kind = MAC_APPLE_EVENT;
10586 buf.x = class;
10587 buf.y = id;
10588 XSETFRAME (buf.frame_or_window,
10589 mac_focus_frame (&one_mac_display_info));
10590 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10591 is safe to use them during read_socket_hook. */
10592 buf.arg = mac_aedesc_to_lisp (desc);
10593 kbd_buffer_store_event (&buf);
10596 #if TARGET_API_MAC_CARBON
10597 static OSStatus
10598 mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10599 event, num_params, names, types)
10600 AEEventClass class;
10601 AEEventID id;
10602 Lisp_Object class_key, id_key;
10603 EventRef event;
10604 UInt32 num_params;
10605 const EventParamName *names;
10606 const EventParamType *types;
10608 OSStatus err = eventNotHandledErr;
10609 Lisp_Object binding;
10611 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10612 if (!NILP (binding) && !EQ (binding, Qundefined))
10614 if (INTEGERP (binding))
10615 err = XINT (binding);
10616 else
10618 AppleEvent apple_event;
10619 err = create_apple_event_from_event_ref (event, num_params,
10620 names, types,
10621 &apple_event);
10622 if (err == noErr)
10624 mac_store_apple_event (class_key, id_key, &apple_event);
10625 AEDisposeDesc (&apple_event);
10626 mac_wakeup_from_rne ();
10631 return err;
10634 void
10635 mac_store_drag_event (window, mouse_pos, modifiers, desc)
10636 WindowRef window;
10637 Point mouse_pos;
10638 SInt16 modifiers;
10639 const AEDesc *desc;
10641 struct input_event buf;
10643 EVENT_INIT (buf);
10645 buf.kind = DRAG_N_DROP_EVENT;
10646 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10647 buf.timestamp = TickCount () * (1000 / 60);
10648 XSETINT (buf.x, mouse_pos.h);
10649 XSETINT (buf.y, mouse_pos.v);
10650 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10651 buf.arg = mac_aedesc_to_lisp (desc);
10652 kbd_buffer_store_event (&buf);
10655 #ifdef MAC_OSX
10656 OSStatus
10657 mac_store_service_event (event)
10658 EventRef event;
10660 OSStatus err;
10661 Lisp_Object id_key;
10662 int num_params;
10663 const EventParamName *names;
10664 const EventParamType *types;
10665 static const EventParamName names_pfm[] =
10666 {kEventParamServiceMessageName, kEventParamServiceUserData};
10667 static const EventParamType types_pfm[] =
10668 {typeCFStringRef, typeCFStringRef};
10670 switch (GetEventKind (event))
10672 case kEventServicePaste:
10673 id_key = Qpaste;
10674 num_params = 0;
10675 names = NULL;
10676 types = NULL;
10677 break;
10679 case kEventServicePerform:
10680 id_key = Qperform;
10681 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
10682 names = names_pfm;
10683 types = types_pfm;
10684 break;
10686 default:
10687 abort ();
10690 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
10691 event, num_params,
10692 names, types);
10694 return err;
10696 #endif /* MAC_OSX */
10698 static pascal OSStatus
10699 mac_handle_window_event (next_handler, event, data)
10700 EventHandlerCallRef next_handler;
10701 EventRef event;
10702 void *data;
10704 WindowRef wp;
10705 OSStatus err, result = eventNotHandledErr;
10706 struct frame *f;
10707 UInt32 attributes;
10708 XSizeHints *size_hints;
10710 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
10711 NULL, sizeof (WindowRef), NULL, &wp);
10712 if (err != noErr)
10713 return eventNotHandledErr;
10715 f = mac_window_to_frame (wp);
10716 switch (GetEventKind (event))
10718 /* -- window refresh events -- */
10720 case kEventWindowUpdate:
10721 result = CallNextEventHandler (next_handler, event);
10722 if (result != eventNotHandledErr)
10723 break;
10725 do_window_update (wp);
10726 result = noErr;
10727 break;
10729 /* -- window state change events -- */
10731 case kEventWindowShowing:
10732 size_hints = FRAME_SIZE_HINTS (f);
10733 if (!(size_hints->flags & (USPosition | PPosition)))
10735 struct frame *sf = SELECTED_FRAME ();
10737 if (!(FRAME_MAC_P (sf) && sf->async_visible))
10738 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
10739 else
10741 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
10742 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10743 kWindowCascadeStartAtParentWindowScreen
10744 #else
10745 kWindowCascadeOnParentWindowScreen
10746 #endif
10748 #if USE_MAC_TOOLBAR
10749 /* This is a workaround. RepositionWindow fails to put
10750 a window at the cascading position when its parent
10751 window has a Carbon HIToolbar. */
10752 if ((f->left_pos == sf->left_pos
10753 && f->top_pos == sf->top_pos)
10754 || (f->left_pos == sf->left_pos + 10 * 2
10755 && f->top_pos == sf->top_pos + 32 * 2))
10756 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
10757 #endif
10759 result = noErr;
10761 break;
10763 case kEventWindowHiding:
10764 /* Before unmapping the window, update the WM_SIZE_HINTS
10765 property to claim that the current position of the window is
10766 user-specified, rather than program-specified, so that when
10767 the window is mapped again, it will be placed at the same
10768 location, without forcing the user to position it by hand
10769 again (they have already done that once for this window.) */
10770 x_wm_set_size_hint (f, (long) 0, 1);
10771 result = noErr;
10772 break;
10774 case kEventWindowShown:
10775 case kEventWindowHidden:
10776 case kEventWindowCollapsed:
10777 case kEventWindowExpanded:
10778 mac_handle_visibility_change (f);
10779 result = noErr;
10780 break;
10782 case kEventWindowBoundsChanging:
10783 result = CallNextEventHandler (next_handler, event);
10784 if (result != eventNotHandledErr)
10785 break;
10787 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
10788 NULL, sizeof (UInt32), NULL, &attributes);
10789 if (err != noErr)
10790 break;
10792 size_hints = FRAME_SIZE_HINTS (f);
10793 if ((attributes & kWindowBoundsChangeUserResize)
10794 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
10795 == (PResizeInc | PBaseSize | PMinSize)))
10797 Rect bounds;
10798 int width, height;
10800 err = GetEventParameter (event, kEventParamCurrentBounds,
10801 typeQDRectangle, NULL, sizeof (Rect),
10802 NULL, &bounds);
10803 if (err != noErr)
10804 break;
10806 width = bounds.right - bounds.left;
10807 height = bounds.bottom - bounds.top;
10809 if (width < size_hints->min_width)
10810 width = size_hints->min_width;
10811 else
10812 width = size_hints->base_width
10813 + (int) ((width - size_hints->base_width)
10814 / (float) size_hints->width_inc + .5)
10815 * size_hints->width_inc;
10817 if (height < size_hints->min_height)
10818 height = size_hints->min_height;
10819 else
10820 height = size_hints->base_height
10821 + (int) ((height - size_hints->base_height)
10822 / (float) size_hints->height_inc + .5)
10823 * size_hints->height_inc;
10825 bounds.right = bounds.left + width;
10826 bounds.bottom = bounds.top + height;
10827 SetEventParameter (event, kEventParamCurrentBounds,
10828 typeQDRectangle, sizeof (Rect), &bounds);
10829 result = noErr;
10831 break;
10833 case kEventWindowBoundsChanged:
10834 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
10835 NULL, sizeof (UInt32), NULL, &attributes);
10836 if (err != noErr)
10837 break;
10839 if (attributes & kWindowBoundsChangeSizeChanged)
10841 Rect bounds;
10843 err = GetEventParameter (event, kEventParamCurrentBounds,
10844 typeQDRectangle, NULL, sizeof (Rect),
10845 NULL, &bounds);
10846 if (err == noErr)
10848 int width, height;
10850 width = bounds.right - bounds.left;
10851 height = bounds.bottom - bounds.top;
10852 mac_handle_size_change (f, width, height);
10853 mac_wakeup_from_rne ();
10857 if (attributes & kWindowBoundsChangeOriginChanged)
10858 mac_handle_origin_change (f);
10860 result = noErr;
10861 break;
10863 /* -- window action events -- */
10865 case kEventWindowClose:
10867 struct input_event buf;
10869 EVENT_INIT (buf);
10870 buf.kind = DELETE_WINDOW_EVENT;
10871 XSETFRAME (buf.frame_or_window, f);
10872 buf.arg = Qnil;
10873 kbd_buffer_store_event (&buf);
10875 result = noErr;
10876 break;
10878 case kEventWindowGetIdealSize:
10879 result = CallNextEventHandler (next_handler, event);
10880 if (result != eventNotHandledErr)
10881 break;
10884 Point ideal_size = mac_get_ideal_size (f);
10886 err = SetEventParameter (event, kEventParamDimensions,
10887 typeQDPoint, sizeof (Point), &ideal_size);
10888 if (err == noErr)
10889 result = noErr;
10891 break;
10893 #ifdef MAC_OSX
10894 case kEventWindowToolbarSwitchMode:
10896 static const EventParamName names[] = {kEventParamDirectObject,
10897 kEventParamWindowMouseLocation,
10898 kEventParamKeyModifiers,
10899 kEventParamMouseButton,
10900 kEventParamClickCount,
10901 kEventParamMouseChord};
10902 static const EventParamType types[] = {typeWindowRef,
10903 typeQDPoint,
10904 typeUInt32,
10905 typeMouseButton,
10906 typeUInt32,
10907 typeUInt32};
10908 int num_params = sizeof (names) / sizeof (names[0]);
10910 err = mac_store_event_ref_as_apple_event (0, 0,
10911 Qwindow,
10912 Qtoolbar_switch_mode,
10913 event, num_params,
10914 names, types);
10916 if (err == noErr)
10917 result = noErr;
10918 break;
10919 #endif
10921 #if USE_MAC_TSM
10922 /* -- window focus events -- */
10924 case kEventWindowFocusAcquired:
10925 err = mac_tsm_resume ();
10926 if (err == noErr)
10927 result = noErr;
10928 break;
10930 case kEventWindowFocusRelinquish:
10931 err = mac_tsm_suspend ();
10932 if (err == noErr)
10933 result = noErr;
10934 break;
10935 #endif
10937 default:
10938 abort ();
10941 return result;
10944 static pascal OSStatus
10945 mac_handle_application_event (next_handler, event, data)
10946 EventHandlerCallRef next_handler;
10947 EventRef event;
10948 void *data;
10950 OSStatus err, result = eventNotHandledErr;
10952 switch (GetEventKind (event))
10954 #if USE_MAC_TSM
10955 case kEventAppActivated:
10956 err = mac_tsm_resume ();
10957 break;
10959 case kEventAppDeactivated:
10960 err = mac_tsm_suspend ();
10961 break;
10962 #endif
10964 default:
10965 abort ();
10968 if (err == noErr)
10969 result = noErr;
10971 return result;
10974 static pascal OSStatus
10975 mac_handle_keyboard_event (next_handler, event, data)
10976 EventHandlerCallRef next_handler;
10977 EventRef event;
10978 void *data;
10980 OSStatus err, result = eventNotHandledErr;
10981 UInt32 event_kind, key_code, modifiers;
10982 unsigned char char_code;
10984 event_kind = GetEventKind (event);
10985 switch (event_kind)
10987 case kEventRawKeyDown:
10988 case kEventRawKeyRepeat:
10989 case kEventRawKeyUp:
10990 /* When using Carbon Events, we need to pass raw keyboard events
10991 to the TSM ourselves. If TSM handles it, it will pass back
10992 noErr, otherwise it will pass back "eventNotHandledErr" and
10993 we can process it normally. */
10994 result = CallNextEventHandler (next_handler, event);
10995 if (result != eventNotHandledErr)
10996 break;
10998 if (read_socket_inev == NULL)
10999 break;
11001 #if USE_MAC_TSM
11002 if (read_socket_inev->kind != NO_EVENT)
11004 result = noErr;
11005 break;
11007 #endif
11009 if (event_kind == kEventRawKeyUp)
11010 break;
11012 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11013 typeChar, NULL,
11014 sizeof (char), NULL, &char_code);
11015 if (err != noErr)
11016 break;
11018 err = GetEventParameter (event, kEventParamKeyCode,
11019 typeUInt32, NULL,
11020 sizeof (UInt32), NULL, &key_code);
11021 if (err != noErr)
11022 break;
11024 err = GetEventParameter (event, kEventParamKeyModifiers,
11025 typeUInt32, NULL,
11026 sizeof (UInt32), NULL, &modifiers);
11027 if (err != noErr)
11028 break;
11030 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
11031 char_code, key_code, modifiers,
11032 ((unsigned long)
11033 (GetEventTime (event) / kEventDurationMillisecond)),
11034 read_socket_inev);
11035 result = noErr;
11036 break;
11038 default:
11039 abort ();
11042 return result;
11045 static pascal OSStatus
11046 mac_handle_command_event (next_handler, event, data)
11047 EventHandlerCallRef next_handler;
11048 EventRef event;
11049 void *data;
11051 OSStatus err, result = eventNotHandledErr;
11052 HICommand command;
11053 static const EventParamName names[] =
11054 {kEventParamDirectObject, kEventParamKeyModifiers};
11055 static const EventParamType types[] =
11056 {typeHICommand, typeUInt32};
11057 int num_params = sizeof (names) / sizeof (names[0]);
11059 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11060 NULL, sizeof (HICommand), NULL, &command);
11061 if (err != noErr)
11062 return eventNotHandledErr;
11064 switch (GetEventKind (event))
11066 case kEventCommandProcess:
11067 result = CallNextEventHandler (next_handler, event);
11068 if (result != eventNotHandledErr)
11069 break;
11071 err = GetEventParameter (event, kEventParamDirectObject,
11072 typeHICommand, NULL,
11073 sizeof (HICommand), NULL, &command);
11075 if (err != noErr || command.commandID == 0)
11076 break;
11078 /* A HI command event is mapped to an Apple event whose event
11079 class symbol is `hi-command' and event ID is its command
11080 ID. */
11081 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11082 Qhi_command, Qnil,
11083 event, num_params,
11084 names, types);
11085 if (err == noErr)
11086 result = noErr;
11087 break;
11089 default:
11090 abort ();
11093 return result;
11096 static pascal OSStatus
11097 mac_handle_mouse_event (next_handler, event, data)
11098 EventHandlerCallRef next_handler;
11099 EventRef event;
11100 void *data;
11102 OSStatus err, result = eventNotHandledErr;
11104 switch (GetEventKind (event))
11106 case kEventMouseWheelMoved:
11108 WindowRef wp;
11109 struct frame *f;
11110 EventMouseWheelAxis axis;
11111 SInt32 delta;
11112 Point point;
11114 result = CallNextEventHandler (next_handler, event);
11115 if (result != eventNotHandledErr || read_socket_inev == NULL)
11116 break;
11118 f = mac_focus_frame (&one_mac_display_info);
11120 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11121 NULL, sizeof (WindowRef), NULL, &wp);
11122 if (err != noErr
11123 || wp != FRAME_MAC_WINDOW (f))
11124 break;
11126 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11127 typeMouseWheelAxis, NULL,
11128 sizeof (EventMouseWheelAxis), NULL, &axis);
11129 if (err != noErr || axis != kEventMouseWheelAxisY)
11130 break;
11132 err = GetEventParameter (event, kEventParamMouseLocation,
11133 typeQDPoint, NULL, sizeof (Point),
11134 NULL, &point);
11135 if (err != noErr)
11136 break;
11138 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11139 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
11140 if (point.h < 0 || point.v < 0
11141 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11142 f->tool_bar_window))
11143 break;
11145 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11146 typeSInt32, NULL, sizeof (SInt32),
11147 NULL, &delta);
11148 if (err != noErr)
11149 break;
11151 read_socket_inev->kind = WHEEL_EVENT;
11152 read_socket_inev->code = 0;
11153 read_socket_inev->modifiers =
11154 (mac_event_to_emacs_modifiers (event)
11155 | ((delta < 0) ? down_modifier : up_modifier));
11156 XSETINT (read_socket_inev->x, point.h);
11157 XSETINT (read_socket_inev->y, point.v);
11158 XSETFRAME (read_socket_inev->frame_or_window, f);
11160 result = noErr;
11162 break;
11164 default:
11165 abort ();
11168 return result;
11171 #if USE_MAC_TSM
11172 static pascal OSStatus
11173 mac_handle_text_input_event (next_handler, event, data)
11174 EventHandlerCallRef next_handler;
11175 EventRef event;
11176 void *data;
11178 OSStatus err, result;
11179 Lisp_Object id_key = Qnil;
11180 int num_params;
11181 const EventParamName *names;
11182 const EventParamType *types;
11183 static UInt32 seqno_uaia = 0;
11184 static const EventParamName names_uaia[] =
11185 {kEventParamTextInputSendComponentInstance,
11186 kEventParamTextInputSendRefCon,
11187 kEventParamTextInputSendSLRec,
11188 kEventParamTextInputSendFixLen,
11189 kEventParamTextInputSendText,
11190 kEventParamTextInputSendUpdateRng,
11191 kEventParamTextInputSendHiliteRng,
11192 kEventParamTextInputSendClauseRng,
11193 kEventParamTextInputSendPinRng,
11194 kEventParamTextInputSendTextServiceEncoding,
11195 kEventParamTextInputSendTextServiceMacEncoding,
11196 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
11197 static const EventParamType types_uaia[] =
11198 {typeComponentInstance,
11199 typeLongInteger,
11200 typeIntlWritingCode,
11201 typeLongInteger,
11202 #ifdef MAC_OSX
11203 typeUnicodeText,
11204 #else
11205 typeChar,
11206 #endif
11207 typeTextRangeArray,
11208 typeTextRangeArray,
11209 typeOffsetArray,
11210 typeTextRange,
11211 typeUInt32,
11212 typeUInt32,
11213 typeUInt32};
11214 static const EventParamName names_ufke[] =
11215 {kEventParamTextInputSendComponentInstance,
11216 kEventParamTextInputSendRefCon,
11217 kEventParamTextInputSendSLRec,
11218 kEventParamTextInputSendText};
11219 static const EventParamType types_ufke[] =
11220 {typeComponentInstance,
11221 typeLongInteger,
11222 typeIntlWritingCode,
11223 typeUnicodeText};
11225 result = CallNextEventHandler (next_handler, event);
11226 if (result != eventNotHandledErr)
11227 return result;
11229 switch (GetEventKind (event))
11231 case kEventTextInputUpdateActiveInputArea:
11232 id_key = Qupdate_active_input_area;
11233 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11234 names = names_uaia;
11235 types = types_uaia;
11236 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11237 typeUInt32, sizeof (UInt32), &seqno_uaia);
11238 seqno_uaia++;
11239 result = noErr;
11240 break;
11242 case kEventTextInputUnicodeForKeyEvent:
11244 EventRef kbd_event;
11245 UInt32 actual_size, modifiers;
11247 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11248 typeEventRef, NULL, sizeof (EventRef), NULL,
11249 &kbd_event);
11250 if (err == noErr)
11251 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11252 typeUInt32, NULL,
11253 sizeof (UInt32), NULL, &modifiers);
11254 if (err == noErr && mac_mapped_modifiers (modifiers))
11255 /* There're mapped modifier keys. Process it in
11256 do_keystroke. */
11257 break;
11258 if (err == noErr)
11259 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11260 typeUnicodeText, NULL, 0, &actual_size,
11261 NULL);
11262 if (err == noErr && actual_size == sizeof (UniChar))
11264 UniChar code;
11266 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11267 typeUnicodeText, NULL,
11268 sizeof (UniChar), NULL, &code);
11269 if (err == noErr && code < 0x80)
11271 /* ASCII character. Process it in do_keystroke. */
11272 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
11274 UInt32 key_code;
11276 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11277 typeUInt32, NULL, sizeof (UInt32),
11278 NULL, &key_code);
11279 if (!(err == noErr && key_code <= 0x7f
11280 && keycode_to_xkeysym_table [key_code]))
11282 struct frame *f =
11283 mac_focus_frame (&one_mac_display_info);
11285 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11286 read_socket_inev->code = code;
11287 read_socket_inev->modifiers =
11288 mac_to_emacs_modifiers (modifiers);
11289 read_socket_inev->modifiers |=
11290 (extra_keyboard_modifiers
11291 & (meta_modifier | alt_modifier
11292 | hyper_modifier | super_modifier));
11293 XSETFRAME (read_socket_inev->frame_or_window, f);
11296 break;
11299 if (err == noErr)
11301 /* Non-ASCII keystrokes without mapped modifiers are
11302 processed at the Lisp level. */
11303 id_key = Qunicode_for_key_event;
11304 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11305 names = names_ufke;
11306 types = types_ufke;
11307 result = noErr;
11310 break;
11312 case kEventTextInputOffsetToPos:
11314 struct frame *f;
11315 struct window *w;
11316 Point p;
11318 if (!OVERLAYP (Vmac_ts_active_input_overlay))
11319 break;
11321 /* Strictly speaking, this is not always correct because
11322 previous events may change some states about display. */
11323 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11325 /* Active input area is displayed around the current point. */
11326 f = SELECTED_FRAME ();
11327 w = XWINDOW (f->selected_window);
11329 else if (WINDOWP (echo_area_window))
11331 /* Active input area is displayed in the echo area. */
11332 w = XWINDOW (echo_area_window);
11333 f = WINDOW_XFRAME (w);
11335 else
11336 break;
11338 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
11339 + WINDOW_LEFT_FRINGE_WIDTH (w)
11340 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
11341 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
11342 + FONT_BASE (FRAME_FONT (f))
11343 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
11344 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11345 typeQDPoint, sizeof (typeQDPoint), &p);
11346 if (err == noErr)
11347 result = noErr;
11349 break;
11351 default:
11352 abort ();
11355 if (!NILP (id_key))
11356 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11357 event, num_params,
11358 names, types);
11359 return result;
11361 #endif
11362 #endif /* TARGET_API_MAC_CARBON */
11365 OSStatus
11366 install_window_handler (window)
11367 WindowRef window;
11369 OSStatus err = noErr;
11371 #if TARGET_API_MAC_CARBON
11372 if (err == noErr)
11374 static const EventTypeSpec specs[] =
11376 /* -- window refresh events -- */
11377 {kEventClassWindow, kEventWindowUpdate},
11378 /* -- window state change events -- */
11379 {kEventClassWindow, kEventWindowShowing},
11380 {kEventClassWindow, kEventWindowHiding},
11381 {kEventClassWindow, kEventWindowShown},
11382 {kEventClassWindow, kEventWindowHidden},
11383 {kEventClassWindow, kEventWindowCollapsed},
11384 {kEventClassWindow, kEventWindowExpanded},
11385 {kEventClassWindow, kEventWindowBoundsChanging},
11386 {kEventClassWindow, kEventWindowBoundsChanged},
11387 /* -- window action events -- */
11388 {kEventClassWindow, kEventWindowClose},
11389 {kEventClassWindow, kEventWindowGetIdealSize},
11390 #ifdef MAC_OSX
11391 {kEventClassWindow, kEventWindowToolbarSwitchMode},
11392 #endif
11393 #if USE_MAC_TSM
11394 /* -- window focus events -- */
11395 {kEventClassWindow, kEventWindowFocusAcquired},
11396 {kEventClassWindow, kEventWindowFocusRelinquish},
11397 #endif
11399 static EventHandlerUPP handle_window_eventUPP = NULL;
11401 if (handle_window_eventUPP == NULL)
11402 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
11404 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11405 GetEventTypeCount (specs),
11406 specs, NULL, NULL);
11408 #endif
11410 if (err == noErr)
11411 err = install_drag_handler (window);
11413 return err;
11416 void
11417 remove_window_handler (window)
11418 WindowRef window;
11420 remove_drag_handler (window);
11423 #if TARGET_API_MAC_CARBON
11424 static OSStatus
11425 install_application_handler ()
11427 OSStatus err = noErr;
11429 if (err == noErr)
11431 static const EventTypeSpec specs[] = {
11432 #if USE_MAC_TSM
11433 {kEventClassApplication, kEventAppActivated},
11434 {kEventClassApplication, kEventAppDeactivated},
11435 #endif
11438 err = InstallApplicationEventHandler (NewEventHandlerUPP
11439 (mac_handle_application_event),
11440 GetEventTypeCount (specs),
11441 specs, NULL, NULL);
11444 if (err == noErr)
11446 static const EventTypeSpec specs[] =
11447 {{kEventClassKeyboard, kEventRawKeyDown},
11448 {kEventClassKeyboard, kEventRawKeyRepeat},
11449 {kEventClassKeyboard, kEventRawKeyUp}};
11451 err = InstallApplicationEventHandler (NewEventHandlerUPP
11452 (mac_handle_keyboard_event),
11453 GetEventTypeCount (specs),
11454 specs, NULL, NULL);
11457 if (err == noErr)
11459 static const EventTypeSpec specs[] =
11460 {{kEventClassCommand, kEventCommandProcess}};
11462 err = InstallApplicationEventHandler (NewEventHandlerUPP
11463 (mac_handle_command_event),
11464 GetEventTypeCount (specs),
11465 specs, NULL, NULL);
11468 if (err == noErr)
11470 static const EventTypeSpec specs[] =
11471 {{kEventClassMouse, kEventMouseWheelMoved}};
11473 err = InstallApplicationEventHandler (NewEventHandlerUPP
11474 (mac_handle_mouse_event),
11475 GetEventTypeCount (specs),
11476 specs, NULL, NULL);
11479 #if USE_MAC_TSM
11480 if (err == noErr)
11482 static const EventTypeSpec spec[] =
11483 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11484 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11485 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11487 err = InstallApplicationEventHandler (NewEventHandlerUPP
11488 (mac_handle_text_input_event),
11489 GetEventTypeCount (spec),
11490 spec, NULL, NULL);
11492 #endif
11494 if (err == noErr)
11495 err = install_menu_target_item_handler ();
11497 #ifdef MAC_OSX
11498 if (err == noErr)
11499 err = install_service_handler ();
11500 #endif
11502 return err;
11504 #endif
11506 static pascal void
11507 mac_handle_dm_notification (event)
11508 AppleEvent *event;
11510 mac_screen_config_changed = 1;
11513 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11514 static void
11515 mac_handle_cg_display_reconfig (display, flags, user_info)
11516 CGDirectDisplayID display;
11517 CGDisplayChangeSummaryFlags flags;
11518 void *user_info;
11520 mac_screen_config_changed = 1;
11522 #endif
11524 static OSErr
11525 init_dm_notification_handler ()
11527 OSErr err = noErr;
11529 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11530 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11531 if (CGDisplayRegisterReconfigurationCallback != NULL)
11532 #endif
11534 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11535 NULL);
11537 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11538 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11539 #endif
11540 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11541 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11543 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11544 ProcessSerialNumber psn;
11546 if (handle_dm_notificationUPP == NULL)
11547 handle_dm_notificationUPP =
11548 NewDMNotificationUPP (mac_handle_dm_notification);
11550 err = GetCurrentProcess (&psn);
11551 if (err == noErr)
11552 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11554 #endif
11556 return err;
11559 static void
11560 mac_get_screen_info (dpyinfo)
11561 struct mac_display_info *dpyinfo;
11563 #ifdef MAC_OSX
11564 /* HasDepth returns true if it is possible to have a 32 bit display,
11565 but this may not be what is actually used. Mac OSX can do better. */
11566 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11567 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11569 CGDisplayErr err;
11570 CGDisplayCount ndisps;
11571 CGDirectDisplayID *displays;
11573 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11574 if (err == noErr)
11576 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11577 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11579 if (err == noErr)
11581 CGRect bounds = CGRectZero;
11583 while (ndisps-- > 0)
11584 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11585 dpyinfo->height = CGRectGetHeight (bounds);
11586 dpyinfo->width = CGRectGetWidth (bounds);
11588 else
11590 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11591 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11594 #else /* !MAC_OSX */
11596 GDHandle gdh = GetMainDevice ();
11597 Rect rect = (**gdh).gdRect;
11599 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11600 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11601 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11602 break;
11604 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11605 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11606 UnionRect (&rect, &(**gdh).gdRect, &rect);
11608 dpyinfo->height = rect.bottom - rect.top;
11609 dpyinfo->width = rect.right - rect.left;
11611 #endif /* !MAC_OSX */
11615 #if __profile__
11616 void
11617 profiler_exit_proc ()
11619 ProfilerDump ("\pEmacs.prof");
11620 ProfilerTerm ();
11622 #endif
11624 /* These few functions implement Emacs as a normal Mac application
11625 (almost): set up the heap and the Toolbox, handle necessary system
11626 events plus a few simple menu events. They also set up Emacs's
11627 access to functions defined in the rest of this file. Emacs uses
11628 function hooks to perform all its terminal I/O. A complete list of
11629 these functions appear in termhooks.h. For what they do, read the
11630 comments there and see also w32term.c and xterm.c. What's
11631 noticeably missing here is the event loop, which is normally
11632 present in most Mac application. After performing the necessary
11633 Mac initializations, main passes off control to emacs_main
11634 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11635 (defined further below) to read input. This is where
11636 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
11638 #ifdef MAC_OS8
11639 #undef main
11641 main (void)
11643 #if __profile__ /* is the profiler on? */
11644 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11645 exit(1);
11646 #endif
11648 #if __MWERKS__
11649 /* set creator and type for files created by MSL */
11650 _fcreator = MAC_EMACS_CREATOR_CODE;
11651 _ftype = 'TEXT';
11652 #endif
11654 do_init_managers ();
11656 do_get_menus ();
11658 #ifndef USE_LSB_TAG
11659 do_check_ram_size ();
11660 #endif
11662 init_emacs_passwd_dir ();
11664 init_environ ();
11666 init_coercion_handler ();
11668 initialize_applescript ();
11670 init_apple_event_handler ();
11672 init_dm_notification_handler ();
11675 char **argv;
11676 int argc = 0;
11678 /* set up argv array from STR# resource */
11679 get_string_list (&argv, ARGV_STRING_LIST_ID);
11680 while (argv[argc])
11681 argc++;
11683 /* free up AppleScript resources on exit */
11684 atexit (terminate_applescript);
11686 #if __profile__ /* is the profiler on? */
11687 atexit (profiler_exit_proc);
11688 #endif
11690 /* 3rd param "envp" never used in emacs_main */
11691 (void) emacs_main (argc, argv, 0);
11694 /* Never reached - real exit in Fkill_emacs */
11695 return 0;
11697 #endif
11699 #if !TARGET_API_MAC_CARBON
11700 static RgnHandle mouse_region = NULL;
11702 Boolean
11703 mac_wait_next_event (er, sleep_time, dequeue)
11704 EventRecord *er;
11705 UInt32 sleep_time;
11706 Boolean dequeue;
11708 static EventRecord er_buf = {nullEvent};
11709 UInt32 target_tick, current_tick;
11710 EventMask event_mask;
11712 if (mouse_region == NULL)
11713 mouse_region = NewRgn ();
11715 event_mask = everyEvent;
11716 if (!mac_ready_for_apple_events)
11717 event_mask -= highLevelEventMask;
11719 current_tick = TickCount ();
11720 target_tick = current_tick + sleep_time;
11722 if (er_buf.what == nullEvent)
11723 while (!WaitNextEvent (event_mask, &er_buf,
11724 target_tick - current_tick, mouse_region))
11726 current_tick = TickCount ();
11727 if (target_tick <= current_tick)
11728 return false;
11731 *er = er_buf;
11732 if (dequeue)
11733 er_buf.what = nullEvent;
11734 return true;
11736 #endif /* not TARGET_API_MAC_CARBON */
11738 #if TARGET_API_MAC_CARBON
11739 OSStatus
11740 mac_post_mouse_moved_event ()
11742 EventRef event = NULL;
11743 OSStatus err;
11745 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
11746 kEventAttributeNone, &event);
11747 if (err == noErr)
11749 Point mouse_pos;
11751 GetGlobalMouse (&mouse_pos);
11752 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
11753 sizeof (Point), &mouse_pos);
11755 if (err == noErr)
11757 UInt32 modifiers = GetCurrentKeyModifiers ();
11759 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
11760 sizeof (UInt32), &modifiers);
11762 if (err == noErr)
11763 err = PostEventToQueue (GetCurrentEventQueue (), event,
11764 kEventPriorityStandard);
11765 if (event)
11766 ReleaseEvent (event);
11768 return err;
11770 #endif
11772 /* Emacs calls this whenever it wants to read an input event from the
11773 user. */
11775 XTread_socket (sd, expected, hold_quit)
11776 int sd, expected;
11777 struct input_event *hold_quit;
11779 struct input_event inev;
11780 int count = 0;
11781 #if TARGET_API_MAC_CARBON
11782 EventRef eventRef;
11783 EventTargetRef toolbox_dispatcher;
11784 #endif
11785 EventRecord er;
11786 struct mac_display_info *dpyinfo = &one_mac_display_info;
11788 if (interrupt_input_blocked)
11790 interrupt_input_pending = 1;
11791 return -1;
11794 interrupt_input_pending = 0;
11795 BLOCK_INPUT;
11797 /* So people can tell when we have read the available input. */
11798 input_signal_count++;
11800 ++handling_signal;
11802 #if TARGET_API_MAC_CARBON
11803 toolbox_dispatcher = GetEventDispatcherTarget ();
11805 while (
11806 #if USE_CG_DRAWING
11807 mac_prepare_for_quickdraw (NULL),
11808 #endif
11809 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
11810 kEventRemoveFromQueue, &eventRef))
11811 #else /* !TARGET_API_MAC_CARBON */
11812 while (mac_wait_next_event (&er, 0, true))
11813 #endif /* !TARGET_API_MAC_CARBON */
11815 int do_help = 0;
11816 struct frame *f;
11817 unsigned long timestamp;
11819 EVENT_INIT (inev);
11820 inev.kind = NO_EVENT;
11821 inev.arg = Qnil;
11823 #if TARGET_API_MAC_CARBON
11824 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
11826 if (!mac_convert_event_ref (eventRef, &er))
11827 goto OTHER;
11828 #else /* !TARGET_API_MAC_CARBON */
11829 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
11830 #endif /* !TARGET_API_MAC_CARBON */
11832 switch (er.what)
11834 case mouseDown:
11835 case mouseUp:
11837 WindowRef window_ptr;
11838 ControlPartCode part_code;
11839 int tool_bar_p = 0;
11841 #if TARGET_API_MAC_CARBON
11842 OSStatus err;
11844 /* This is needed to send mouse events like aqua window
11845 buttons to the correct handler. */
11846 read_socket_inev = &inev;
11847 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
11848 read_socket_inev = NULL;
11849 if (err != eventNotHandledErr)
11850 break;
11851 #endif
11852 last_mouse_glyph_frame = 0;
11854 if (dpyinfo->grabbed && last_mouse_frame
11855 && FRAME_LIVE_P (last_mouse_frame))
11857 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
11858 part_code = inContent;
11860 else
11862 part_code = FindWindow (er.where, &window_ptr);
11863 if (tip_window && window_ptr == tip_window)
11865 HideWindow (tip_window);
11866 part_code = FindWindow (er.where, &window_ptr);
11870 if (er.what != mouseDown &&
11871 (part_code != inContent || dpyinfo->grabbed == 0))
11872 break;
11874 switch (part_code)
11876 case inMenuBar:
11877 f = mac_focus_frame (dpyinfo);
11878 saved_menu_event_location = er.where;
11879 inev.kind = MENU_BAR_ACTIVATE_EVENT;
11880 XSETFRAME (inev.frame_or_window, f);
11881 break;
11883 case inContent:
11884 if (
11885 #if TARGET_API_MAC_CARBON
11886 FrontNonFloatingWindow ()
11887 #else
11888 FrontWindow ()
11889 #endif
11890 != window_ptr
11891 || (mac_window_to_frame (window_ptr)
11892 != dpyinfo->x_focus_frame))
11893 SelectWindow (window_ptr);
11894 else
11896 ControlPartCode control_part_code;
11897 ControlRef ch;
11898 Point mouse_loc;
11899 #ifdef MAC_OSX
11900 ControlKind control_kind;
11901 #endif
11903 f = mac_window_to_frame (window_ptr);
11904 /* convert to local coordinates of new window */
11905 mouse_loc.h = (er.where.h
11906 - (f->left_pos
11907 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
11908 mouse_loc.v = (er.where.v
11909 - (f->top_pos
11910 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
11911 #if TARGET_API_MAC_CARBON
11912 ch = FindControlUnderMouse (mouse_loc, window_ptr,
11913 &control_part_code);
11914 #ifdef MAC_OSX
11915 if (ch)
11916 GetControlKind (ch, &control_kind);
11917 #endif
11918 #else
11919 control_part_code = FindControl (mouse_loc, window_ptr,
11920 &ch);
11921 #endif
11923 #if TARGET_API_MAC_CARBON
11924 inev.code = mac_get_mouse_btn (eventRef);
11925 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
11926 #else
11927 inev.code = mac_get_emulated_btn (er.modifiers);
11928 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
11929 #endif
11930 XSETINT (inev.x, mouse_loc.h);
11931 XSETINT (inev.y, mouse_loc.v);
11933 if ((dpyinfo->grabbed && tracked_scroll_bar)
11934 || (ch != 0
11935 #ifndef USE_TOOLKIT_SCROLL_BARS
11936 /* control_part_code becomes kControlNoPart if
11937 a progress indicator is clicked. */
11938 && control_part_code != kControlNoPart
11939 #else /* USE_TOOLKIT_SCROLL_BARS */
11940 #ifdef MAC_OSX
11941 && control_kind.kind == kControlKindScrollBar
11942 #endif /* MAC_OSX */
11943 #endif /* USE_TOOLKIT_SCROLL_BARS */
11946 struct scroll_bar *bar;
11948 if (dpyinfo->grabbed && tracked_scroll_bar)
11950 bar = tracked_scroll_bar;
11951 #ifndef USE_TOOLKIT_SCROLL_BARS
11952 control_part_code = kControlIndicatorPart;
11953 #endif
11955 else
11956 bar = (struct scroll_bar *) GetControlReference (ch);
11957 #ifdef USE_TOOLKIT_SCROLL_BARS
11958 /* Make the "Ctrl-Mouse-2 splits window" work
11959 for toolkit scroll bars. */
11960 if (inev.modifiers & ctrl_modifier)
11961 x_scroll_bar_handle_click (bar, control_part_code,
11962 &er, &inev);
11963 else if (er.what == mouseDown)
11964 x_scroll_bar_handle_press (bar, control_part_code,
11965 mouse_loc, &inev);
11966 else
11967 x_scroll_bar_handle_release (bar, &inev);
11968 #else /* not USE_TOOLKIT_SCROLL_BARS */
11969 x_scroll_bar_handle_click (bar, control_part_code,
11970 &er, &inev);
11971 if (er.what == mouseDown
11972 && control_part_code == kControlIndicatorPart)
11973 tracked_scroll_bar = bar;
11974 else
11975 tracked_scroll_bar = NULL;
11976 #endif /* not USE_TOOLKIT_SCROLL_BARS */
11978 else
11980 Lisp_Object window;
11981 int x = mouse_loc.h;
11982 int y = mouse_loc.v;
11984 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
11985 if (EQ (window, f->tool_bar_window))
11987 if (er.what == mouseDown)
11988 handle_tool_bar_click (f, x, y, 1, 0);
11989 else
11990 handle_tool_bar_click (f, x, y, 0,
11991 inev.modifiers);
11992 tool_bar_p = 1;
11994 else
11996 XSETFRAME (inev.frame_or_window, f);
11997 inev.kind = MOUSE_CLICK_EVENT;
12001 if (er.what == mouseDown)
12003 dpyinfo->grabbed |= (1 << inev.code);
12004 last_mouse_frame = f;
12006 if (!tool_bar_p)
12007 last_tool_bar_item = -1;
12009 else
12011 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
12012 /* If a button is released though it was not
12013 previously pressed, that would be because
12014 of multi-button emulation. */
12015 dpyinfo->grabbed = 0;
12016 else
12017 dpyinfo->grabbed &= ~(1 << inev.code);
12020 /* Ignore any mouse motion that happened before
12021 this event; any subsequent mouse-movement Emacs
12022 events should reflect only motion after the
12023 ButtonPress. */
12024 if (f != 0)
12025 f->mouse_moved = 0;
12027 #ifdef USE_TOOLKIT_SCROLL_BARS
12028 if (inev.kind == MOUSE_CLICK_EVENT
12029 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12030 && (inev.modifiers & ctrl_modifier)))
12031 #endif
12032 switch (er.what)
12034 case mouseDown:
12035 inev.modifiers |= down_modifier;
12036 break;
12037 case mouseUp:
12038 inev.modifiers |= up_modifier;
12039 break;
12042 break;
12044 case inDrag:
12045 #if TARGET_API_MAC_CARBON
12046 case inProxyIcon:
12047 if (IsWindowPathSelectClick (window_ptr, &er))
12049 WindowPathSelect (window_ptr, NULL, NULL);
12050 break;
12052 if (part_code == inProxyIcon
12053 && (TrackWindowProxyDrag (window_ptr, er.where)
12054 != errUserWantsToDragWindow))
12055 break;
12056 DragWindow (window_ptr, er.where, NULL);
12057 #else /* not TARGET_API_MAC_CARBON */
12058 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
12059 /* Update the frame parameters. */
12061 struct frame *f = mac_window_to_frame (window_ptr);
12063 if (f && !f->async_iconified)
12064 mac_handle_origin_change (f);
12066 #endif /* not TARGET_API_MAC_CARBON */
12067 break;
12069 case inGoAway:
12070 if (TrackGoAway (window_ptr, er.where))
12072 inev.kind = DELETE_WINDOW_EVENT;
12073 XSETFRAME (inev.frame_or_window,
12074 mac_window_to_frame (window_ptr));
12076 break;
12078 /* window resize handling added --ben */
12079 case inGrow:
12080 do_grow_window (window_ptr, &er);
12081 break;
12083 /* window zoom handling added --ben */
12084 case inZoomIn:
12085 case inZoomOut:
12086 if (TrackBox (window_ptr, er.where, part_code))
12087 do_zoom_window (window_ptr, part_code);
12088 break;
12090 #if USE_MAC_TOOLBAR
12091 case inStructure:
12093 OSStatus err;
12094 HIViewRef ch;
12096 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12097 eventRef, &ch);
12098 /* This doesn't work on Mac OS X 10.2. */
12099 if (err == noErr)
12100 HIViewClick (ch, eventRef);
12102 break;
12103 #endif /* USE_MAC_TOOLBAR */
12105 default:
12106 break;
12109 break;
12111 #if !TARGET_API_MAC_CARBON
12112 case updateEvt:
12113 do_window_update ((WindowRef) er.message);
12114 break;
12115 #endif
12117 case osEvt:
12118 switch ((er.message >> 24) & 0x000000FF)
12120 case mouseMovedMessage:
12121 #if !TARGET_API_MAC_CARBON
12122 SetRectRgn (mouse_region, er.where.h, er.where.v,
12123 er.where.h + 1, er.where.v + 1);
12124 #endif
12125 previous_help_echo_string = help_echo_string;
12126 help_echo_string = Qnil;
12128 if (dpyinfo->grabbed && last_mouse_frame
12129 && FRAME_LIVE_P (last_mouse_frame))
12130 f = last_mouse_frame;
12131 else
12132 f = dpyinfo->x_focus_frame;
12134 if (dpyinfo->mouse_face_hidden)
12136 dpyinfo->mouse_face_hidden = 0;
12137 clear_mouse_face (dpyinfo);
12140 if (f)
12142 WindowRef wp = FRAME_MAC_WINDOW (f);
12143 Point mouse_pos;
12145 mouse_pos.h = (er.where.h
12146 - (f->left_pos
12147 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12148 mouse_pos.v = (er.where.v
12149 - (f->top_pos
12150 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12151 if (dpyinfo->grabbed && tracked_scroll_bar)
12152 #ifdef USE_TOOLKIT_SCROLL_BARS
12153 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
12154 mouse_pos, &inev);
12155 #else /* not USE_TOOLKIT_SCROLL_BARS */
12156 x_scroll_bar_note_movement (tracked_scroll_bar,
12157 mouse_pos.v
12158 - XINT (tracked_scroll_bar->top),
12159 er.when * (1000 / 60));
12160 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12161 else
12163 /* Generate SELECT_WINDOW_EVENTs when needed. */
12164 if (!NILP (Vmouse_autoselect_window))
12166 Lisp_Object window;
12168 window = window_from_coordinates (f,
12169 mouse_pos.h,
12170 mouse_pos.v,
12171 0, 0, 0, 0);
12173 /* Window will be selected only when it is
12174 not selected now and last mouse movement
12175 event was not in it. Minibuffer window
12176 will be selected only when it is active. */
12177 if (WINDOWP (window)
12178 && !EQ (window, last_window)
12179 && !EQ (window, selected_window)
12180 /* For click-to-focus window managers
12181 create event iff we don't leave the
12182 selected frame. */
12183 && (focus_follows_mouse
12184 || (EQ (XWINDOW (window)->frame,
12185 XWINDOW (selected_window)->frame))))
12187 inev.kind = SELECT_WINDOW_EVENT;
12188 inev.frame_or_window = window;
12191 last_window=window;
12193 if (!note_mouse_movement (f, &mouse_pos))
12194 help_echo_string = previous_help_echo_string;
12195 #if USE_MAC_TOOLBAR
12196 else
12197 mac_tool_bar_note_mouse_movement (f, eventRef);
12198 #endif
12202 /* If the contents of the global variable
12203 help_echo_string has changed, generate a
12204 HELP_EVENT. */
12205 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12206 do_help = 1;
12207 break;
12209 default:
12210 goto OTHER;
12212 break;
12214 case activateEvt:
12216 WindowRef window_ptr = (WindowRef) er.message;
12217 OSErr err;
12218 ControlRef root_control;
12220 if (window_ptr == tip_window)
12222 HideWindow (tip_window);
12223 break;
12226 if (!is_emacs_window (window_ptr))
12227 goto OTHER;
12229 f = mac_window_to_frame (window_ptr);
12231 if ((er.modifiers & activeFlag) != 0)
12233 /* A window has been activated */
12234 Point mouse_loc;
12236 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12237 if (err == noErr)
12238 ActivateControl (root_control);
12240 x_detect_focus_change (dpyinfo, &er, &inev);
12242 mouse_loc.h = (er.where.h
12243 - (f->left_pos
12244 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12245 mouse_loc.v = (er.where.v
12246 - (f->top_pos
12247 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12248 /* Window-activated event counts as mouse movement,
12249 so update things that depend on mouse position. */
12250 note_mouse_movement (f, &mouse_loc);
12252 else
12254 /* A window has been deactivated */
12255 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12256 if (err == noErr)
12257 DeactivateControl (root_control);
12259 #ifdef USE_TOOLKIT_SCROLL_BARS
12260 if (dpyinfo->grabbed && tracked_scroll_bar)
12262 struct input_event event;
12264 EVENT_INIT (event);
12265 event.kind = NO_EVENT;
12266 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
12267 if (event.kind != NO_EVENT)
12269 event.timestamp = timestamp;
12270 kbd_buffer_store_event_hold (&event, hold_quit);
12271 count++;
12274 #endif
12275 dpyinfo->grabbed = 0;
12277 x_detect_focus_change (dpyinfo, &er, &inev);
12279 if (f == dpyinfo->mouse_face_mouse_frame)
12281 /* If we move outside the frame, then we're
12282 certainly no longer on any text in the
12283 frame. */
12284 clear_mouse_face (dpyinfo);
12285 dpyinfo->mouse_face_mouse_frame = 0;
12288 /* Generate a nil HELP_EVENT to cancel a help-echo.
12289 Do it only if there's something to cancel.
12290 Otherwise, the startup message is cleared when the
12291 mouse leaves the frame. */
12292 if (any_help_event_p)
12293 do_help = -1;
12296 break;
12298 case keyDown:
12299 case keyUp:
12300 case autoKey:
12301 ObscureCursor ();
12303 f = mac_focus_frame (dpyinfo);
12304 XSETFRAME (inev.frame_or_window, f);
12306 /* If mouse-highlight is an integer, input clears out mouse
12307 highlighting. */
12308 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12309 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12311 clear_mouse_face (dpyinfo);
12312 dpyinfo->mouse_face_hidden = 1;
12316 UInt32 modifiers = er.modifiers, mapped_modifiers;
12318 #ifdef MAC_OSX
12319 GetEventParameter (eventRef, kEventParamKeyModifiers,
12320 typeUInt32, NULL,
12321 sizeof (UInt32), NULL, &modifiers);
12322 #endif
12323 mapped_modifiers = mac_mapped_modifiers (modifiers);
12325 #if TARGET_API_MAC_CARBON
12326 if (!(mapped_modifiers
12327 & ~(mac_pass_command_to_system ? cmdKey : 0)
12328 & ~(mac_pass_control_to_system ? controlKey : 0)))
12329 goto OTHER;
12330 else
12331 #endif
12332 if (er.what != keyUp)
12333 do_keystroke (er.what, er.message & charCodeMask,
12334 (er.message & keyCodeMask) >> 8,
12335 modifiers, timestamp, &inev);
12337 break;
12339 case kHighLevelEvent:
12340 AEProcessAppleEvent (&er);
12341 break;
12343 default:
12344 OTHER:
12345 #if TARGET_API_MAC_CARBON
12347 OSStatus err;
12349 read_socket_inev = &inev;
12350 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12351 read_socket_inev = NULL;
12353 #endif
12354 break;
12356 #if TARGET_API_MAC_CARBON
12357 ReleaseEvent (eventRef);
12358 #endif
12360 if (inev.kind != NO_EVENT)
12362 inev.timestamp = timestamp;
12363 kbd_buffer_store_event_hold (&inev, hold_quit);
12364 count++;
12367 if (do_help
12368 && !(hold_quit && hold_quit->kind != NO_EVENT))
12370 Lisp_Object frame;
12372 if (f)
12373 XSETFRAME (frame, f);
12374 else
12375 frame = Qnil;
12377 if (do_help > 0)
12379 any_help_event_p = 1;
12380 gen_help_event (help_echo_string, frame, help_echo_window,
12381 help_echo_object, help_echo_pos);
12383 else
12385 help_echo_string = Qnil;
12386 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12388 count++;
12392 /* If the focus was just given to an autoraising frame,
12393 raise it now. */
12394 /* ??? This ought to be able to handle more than one such frame. */
12395 if (pending_autoraise_frame)
12397 x_raise_frame (pending_autoraise_frame);
12398 pending_autoraise_frame = 0;
12401 if (mac_screen_config_changed)
12403 mac_get_screen_info (dpyinfo);
12404 mac_screen_config_changed = 0;
12407 #if !TARGET_API_MAC_CARBON
12408 /* Check which frames are still visible. We do this here because
12409 there doesn't seem to be any direct notification from the Window
12410 Manager that the visibility of a window has changed (at least,
12411 not in all cases). */
12413 Lisp_Object tail, frame;
12415 FOR_EACH_FRAME (tail, frame)
12417 struct frame *f = XFRAME (frame);
12419 /* The tooltip has been drawn already. Avoid the
12420 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12421 if (EQ (frame, tip_frame))
12422 continue;
12424 if (FRAME_MAC_P (f))
12425 mac_handle_visibility_change (f);
12428 #endif
12430 --handling_signal;
12431 UNBLOCK_INPUT;
12432 return count;
12436 /* Need to override CodeWarrior's input function so no conversion is
12437 done on newlines Otherwise compiled functions in .elc files will be
12438 read incorrectly. Defined in ...:MSL C:MSL
12439 Common:Source:buffer_io.c. */
12440 #ifdef __MWERKS__
12441 void
12442 __convert_to_newlines (unsigned char * p, size_t * n)
12444 #pragma unused(p,n)
12447 void
12448 __convert_from_newlines (unsigned char * p, size_t * n)
12450 #pragma unused(p,n)
12452 #endif
12454 #ifdef MAC_OS8
12455 void
12456 make_mac_terminal_frame (struct frame *f)
12458 Lisp_Object frame;
12459 Rect r;
12461 XSETFRAME (frame, f);
12463 f->output_method = output_mac;
12464 f->output_data.mac = (struct mac_output *)
12465 xmalloc (sizeof (struct mac_output));
12466 bzero (f->output_data.mac, sizeof (struct mac_output));
12468 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12470 FRAME_COLS (f) = 96;
12471 FRAME_LINES (f) = 4;
12473 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12474 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12476 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
12478 f->output_data.mac->cursor_pixel = 0;
12479 f->output_data.mac->border_pixel = 0x00ff00;
12480 f->output_data.mac->mouse_pixel = 0xff00ff;
12481 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12483 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12484 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12485 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12486 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12487 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12488 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
12490 FRAME_FONTSET (f) = -1;
12491 f->output_data.mac->explicit_parent = 0;
12492 f->left_pos = 8;
12493 f->top_pos = 32;
12494 f->border_width = 0;
12496 f->internal_border_width = 0;
12498 f->auto_raise = 1;
12499 f->auto_lower = 1;
12501 f->new_text_cols = 0;
12502 f->new_text_lines = 0;
12504 SetRect (&r, f->left_pos, f->top_pos,
12505 f->left_pos + FRAME_PIXEL_WIDTH (f),
12506 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12508 BLOCK_INPUT;
12510 if (!(FRAME_MAC_WINDOW (f) =
12511 NewCWindow (NULL, &r, "\p", true, dBoxProc,
12512 (WindowRef) -1, 1, (long) f->output_data.mac)))
12513 abort ();
12514 /* so that update events can find this mac_output struct */
12515 f->output_data.mac->mFP = f; /* point back to emacs frame */
12517 UNBLOCK_INPUT;
12519 x_make_gc (f);
12521 /* Need to be initialized for unshow_buffer in window.c. */
12522 selected_window = f->selected_window;
12524 Fmodify_frame_parameters (frame,
12525 Fcons (Fcons (Qfont,
12526 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12527 Fmodify_frame_parameters (frame,
12528 Fcons (Fcons (Qforeground_color,
12529 build_string ("black")), Qnil));
12530 Fmodify_frame_parameters (frame,
12531 Fcons (Fcons (Qbackground_color,
12532 build_string ("white")), Qnil));
12534 #endif
12537 /***********************************************************************
12538 Initialization
12539 ***********************************************************************/
12541 static int mac_initialized = 0;
12543 static XrmDatabase
12544 mac_make_rdb (xrm_option)
12545 const char *xrm_option;
12547 XrmDatabase database;
12549 database = xrm_get_preference_database (NULL);
12550 if (xrm_option)
12551 xrm_merge_string_database (database, xrm_option);
12553 return database;
12556 struct mac_display_info *
12557 mac_term_init (display_name, xrm_option, resource_name)
12558 Lisp_Object display_name;
12559 char *xrm_option;
12560 char *resource_name;
12562 struct mac_display_info *dpyinfo;
12563 struct terminal *terminal;
12565 BLOCK_INPUT;
12567 if (!mac_initialized)
12569 mac_initialize ();
12570 mac_initialized = 1;
12573 if (x_display_list)
12574 error ("Sorry, this version can only handle one display");
12576 dpyinfo = &one_mac_display_info;
12577 bzero (dpyinfo, sizeof (*dpyinfo));
12579 terminal = mac_create_terminal (dpyinfo);
12581 /* Set the name of the terminal. */
12582 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12583 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12584 terminal->name[SBYTES (display_name)] = 0;
12586 #ifdef MAC_OSX
12587 dpyinfo->mac_id_name
12588 = (char *) xmalloc (SCHARS (Vinvocation_name)
12589 + SCHARS (Vsystem_name)
12590 + 2);
12591 sprintf (dpyinfo->mac_id_name, "%s@%s",
12592 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12593 #else
12594 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12595 strcpy (dpyinfo->mac_id_name, "Mac Display");
12596 #endif
12598 dpyinfo->reference_count = 0;
12599 dpyinfo->resx = 72.0;
12600 dpyinfo->resy = 72.0;
12602 mac_get_screen_info (dpyinfo);
12604 dpyinfo->grabbed = 0;
12605 dpyinfo->root_window = NULL;
12606 dpyinfo->image_cache = make_image_cache ();
12608 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12609 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12610 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12611 dpyinfo->mouse_face_window = Qnil;
12612 dpyinfo->mouse_face_overlay = Qnil;
12613 dpyinfo->mouse_face_hidden = 0;
12615 dpyinfo->xrdb = mac_make_rdb (xrm_option);
12617 /* Put this display on the chain. */
12618 dpyinfo->next = x_display_list;
12619 x_display_list = dpyinfo;
12621 /* Put it on x_display_name_list. */
12622 x_display_name_list = Fcons (Fcons (display_name,
12623 Fcons (Qnil, dpyinfo->xrdb)),
12624 x_display_name_list);
12625 dpyinfo->name_list_element = XCAR (x_display_name_list);
12627 /* FIXME: Untested.
12628 Add the default keyboard. */
12629 add_keyboard_wait_descriptor (0);
12631 #if USE_CG_DRAWING
12632 mac_init_fringe (terminal->rif);
12633 #endif
12635 UNBLOCK_INPUT;
12637 return dpyinfo;
12640 /* Get rid of display DPYINFO, assuming all frames are already gone. */
12642 void
12643 x_delete_display (dpyinfo)
12644 struct mac_display_info *dpyinfo;
12646 int i;
12648 /* Discard this display from x_display_name_list and x_display_list.
12649 We can't use Fdelq because that can quit. */
12650 if (! NILP (x_display_name_list)
12651 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12652 x_display_name_list = XCDR (x_display_name_list);
12653 else
12655 Lisp_Object tail;
12657 tail = x_display_name_list;
12658 while (CONSP (tail) && CONSP (XCDR (tail)))
12660 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
12662 XSETCDR (tail, XCDR (XCDR (tail)));
12663 break;
12665 tail = XCDR (tail);
12669 if (x_display_list == dpyinfo)
12670 x_display_list = dpyinfo->next;
12671 else
12673 struct x_display_info *tail;
12675 for (tail = x_display_list; tail; tail = tail->next)
12676 if (tail->next == dpyinfo)
12677 tail->next = tail->next->next;
12680 /* Free the font names in the font table. */
12681 for (i = 0; i < dpyinfo->n_fonts; i++)
12682 if (dpyinfo->font_table[i].name)
12684 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
12685 xfree (dpyinfo->font_table[i].full_name);
12686 xfree (dpyinfo->font_table[i].name);
12689 if (dpyinfo->font_table)
12691 if (dpyinfo->font_table->font_encoder)
12692 xfree (dpyinfo->font_table->font_encoder);
12693 xfree (dpyinfo->font_table);
12695 if (dpyinfo->mac_id_name)
12696 xfree (dpyinfo->mac_id_name);
12698 if (x_display_list == 0)
12700 mac_clear_font_name_table ();
12701 bzero (dpyinfo, sizeof (*dpyinfo));
12706 static void
12707 init_menu_bar ()
12709 #ifdef MAC_OSX
12710 OSStatus err;
12711 MenuRef menu;
12712 MenuItemIndex menu_index;
12714 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
12715 &menu, &menu_index);
12716 if (err == noErr)
12717 SetMenuItemCommandKey (menu, menu_index, false, 0);
12718 EnableMenuCommand (NULL, kHICommandPreferences);
12719 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
12720 &menu, &menu_index);
12721 if (err == noErr)
12723 SetMenuItemCommandKey (menu, menu_index, false, 0);
12724 InsertMenuItemTextWithCFString (menu, NULL,
12725 0, kMenuItemAttrSeparator, 0);
12726 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
12727 0, 0, kHICommandAbout);
12729 #else /* !MAC_OSX */
12730 #if TARGET_API_MAC_CARBON
12731 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
12732 #endif
12733 #endif
12736 #if USE_MAC_TSM
12737 static void
12738 init_tsm ()
12740 #ifdef MAC_OSX
12741 static InterfaceTypeList types = {kUnicodeDocument};
12742 #else
12743 static InterfaceTypeList types = {kTextService};
12744 #endif
12746 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
12747 &tsm_document_id, 0);
12749 #endif
12751 /* Set up use of X before we make the first connection. */
12753 extern frame_parm_handler mac_frame_parm_handlers[];
12755 static struct redisplay_interface x_redisplay_interface =
12757 mac_frame_parm_handlers,
12758 x_produce_glyphs,
12759 x_write_glyphs,
12760 x_insert_glyphs,
12761 x_clear_end_of_line,
12762 x_scroll_run,
12763 x_after_update_window_line,
12764 x_update_window_begin,
12765 x_update_window_end,
12766 x_cursor_to,
12767 x_flush,
12768 #if USE_CG_DRAWING
12769 mac_flush_display_optional,
12770 #else
12771 0, /* flush_display_optional */
12772 #endif
12773 x_clear_window_mouse_face,
12774 x_get_glyph_overhangs,
12775 x_fix_overlapping_area,
12776 x_draw_fringe_bitmap,
12777 #if USE_CG_DRAWING
12778 mac_define_fringe_bitmap,
12779 mac_destroy_fringe_bitmap,
12780 #else
12781 0, /* define_fringe_bitmap */
12782 0, /* destroy_fringe_bitmap */
12783 #endif
12784 mac_per_char_metric,
12785 mac_encode_char,
12786 mac_compute_glyph_string_overhangs,
12787 x_draw_glyph_string,
12788 mac_define_frame_cursor,
12789 mac_clear_frame_area,
12790 mac_draw_window_cursor,
12791 mac_draw_vertical_window_border,
12792 mac_shift_glyphs_for_insert
12795 static struct terminal *
12796 mac_create_terminal (struct mac_display_info *dpyinfo)
12798 struct terminal *terminal;
12800 terminal = create_terminal ();
12802 terminal->type = output_mac;
12803 terminal->display_info.mac = dpyinfo;
12804 dpyinfo->terminal = terminal;
12806 terminal->clear_frame_hook = x_clear_frame;
12807 terminal->ins_del_lines_hook = x_ins_del_lines;
12808 terminal->delete_glyphs_hook = x_delete_glyphs;
12809 terminal->ring_bell_hook = XTring_bell;
12810 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
12811 terminal->set_terminal_modes_hook = XTset_terminal_modes;
12812 terminal->update_begin_hook = x_update_begin;
12813 terminal->update_end_hook = x_update_end;
12814 terminal->set_terminal_window_hook = XTset_terminal_window;
12815 terminal->read_socket_hook = XTread_socket;
12816 terminal->frame_up_to_date_hook = XTframe_up_to_date;
12817 terminal->mouse_position_hook = XTmouse_position;
12818 terminal->frame_rehighlight_hook = XTframe_rehighlight;
12819 terminal->frame_raise_lower_hook = XTframe_raise_lower;
12820 /* terminal->fullscreen_hook = XTfullscreen_hook; */
12821 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12822 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12823 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
12824 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
12825 terminal->delete_frame_hook = x_destroy_window;
12826 /* terminal->delete_terminal_hook = x_delete_terminal; */
12828 terminal->rif = &x_redisplay_interface;
12829 #if 0
12830 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
12831 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
12832 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
12833 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
12834 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
12835 scrolls off the
12836 bottom */
12837 #else
12838 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
12839 terminal->char_ins_del_ok = 1;
12840 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
12841 terminal->fast_clear_end_of_line = 1; /* X does this well. */
12842 terminal->memory_below_frame = 0; /* We don't remember what scrolls
12843 off the bottom. */
12845 #endif
12847 /* FIXME: This keyboard setup is 100% untested, just copied from
12848 w32_create_terminal in order to set window-system now that it's
12849 a keyboard object. */
12850 /* We don't yet support separate terminals on Mac, so don't try to share
12851 keyboards between virtual terminals that are on the same physical
12852 terminal like X does. */
12853 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
12854 init_kboard (terminal->kboard);
12855 terminal->kboard->Vwindow_system = intern ("mac");
12856 terminal->kboard->next_kboard = all_kboards;
12857 all_kboards = terminal->kboard;
12858 /* Don't let the initial kboard remain current longer than necessary.
12859 That would cause problems if a file loaded on startup tries to
12860 prompt in the mini-buffer. */
12861 if (current_kboard == initial_kboard)
12862 current_kboard = terminal->kboard;
12863 terminal->kboard->reference_count++;
12865 return terminal;
12868 static void
12869 mac_initialize ()
12872 baud_rate = 19200;
12874 last_tool_bar_item = -1;
12875 any_help_event_p = 0;
12877 /* Try to use interrupt input; if we can't, then start polling. */
12878 Fset_input_interrupt_mode (Qt);
12880 BLOCK_INPUT;
12882 #if TARGET_API_MAC_CARBON
12884 install_application_handler ();
12886 init_menu_bar ();
12888 #if USE_MAC_TSM
12889 init_tsm ();
12890 #endif
12892 #ifdef MAC_OSX
12893 init_coercion_handler ();
12895 init_apple_event_handler ();
12897 init_dm_notification_handler ();
12899 if (!inhibit_window_system)
12901 static const ProcessSerialNumber psn = {0, kCurrentProcess};
12903 SetFrontProcess (&psn);
12905 #endif
12906 #endif
12908 #if USE_CG_DRAWING
12909 init_cg_color ();
12910 #endif
12912 UNBLOCK_INPUT;
12917 void
12918 syms_of_macterm ()
12920 #if 0
12921 staticpro (&x_error_message_string);
12922 x_error_message_string = Qnil;
12923 #endif
12925 Qcontrol = intern ("control"); staticpro (&Qcontrol);
12926 Qmeta = intern ("meta"); staticpro (&Qmeta);
12927 Qalt = intern ("alt"); staticpro (&Qalt);
12928 Qhyper = intern ("hyper"); staticpro (&Qhyper);
12929 Qsuper = intern ("super"); staticpro (&Qsuper);
12930 Qmodifier_value = intern ("modifier-value");
12931 staticpro (&Qmodifier_value);
12933 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
12934 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
12935 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
12936 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
12937 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
12939 #if TARGET_API_MAC_CARBON
12940 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
12941 #ifdef MAC_OSX
12942 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
12943 staticpro (&Qtoolbar_switch_mode);
12944 #if USE_MAC_FONT_PANEL
12945 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
12946 Qselection = intern ("selection"); staticpro (&Qselection);
12947 #endif
12949 Qservice = intern ("service"); staticpro (&Qservice);
12950 Qpaste = intern ("paste"); staticpro (&Qpaste);
12951 Qperform = intern ("perform"); staticpro (&Qperform);
12952 #endif
12953 #if USE_MAC_TSM
12954 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
12955 Qupdate_active_input_area = intern ("update-active-input-area");
12956 staticpro (&Qupdate_active_input_area);
12957 Qunicode_for_key_event = intern ("unicode-for-key-event");
12958 staticpro (&Qunicode_for_key_event);
12959 #endif
12960 #endif
12962 #ifdef MAC_OSX
12963 Fprovide (intern ("mac-carbon"), Qnil);
12964 #endif
12966 staticpro (&Qreverse);
12967 Qreverse = intern ("reverse");
12969 staticpro (&x_display_name_list);
12970 x_display_name_list = Qnil;
12972 staticpro (&last_mouse_scroll_bar);
12973 last_mouse_scroll_bar = Qnil;
12975 staticpro (&fm_font_family_alist);
12976 fm_font_family_alist = Qnil;
12978 #if USE_ATSUI
12979 staticpro (&atsu_font_id_hash);
12980 atsu_font_id_hash = Qnil;
12982 staticpro (&fm_style_face_attributes_alist);
12983 fm_style_face_attributes_alist = Qnil;
12984 #endif
12986 #if USE_MAC_TSM
12987 staticpro (&saved_ts_script_language_on_focus);
12988 saved_ts_script_language_on_focus = Qnil;
12989 #endif
12991 /* We don't yet support this, but defining this here avoids whining
12992 from cus-start.el and other places, like "M-x set-variable". */
12993 DEFVAR_BOOL ("x-use-underline-position-properties",
12994 &x_use_underline_position_properties,
12995 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
12996 A value of nil means ignore them. If you encounter fonts with bogus
12997 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
12998 to 4.1, set this to nil.
13000 NOTE: Not supported on Mac yet. */);
13001 x_use_underline_position_properties = 0;
13003 DEFVAR_BOOL ("x-underline-at-descent-line",
13004 &x_underline_at_descent_line,
13005 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
13006 A value of nil means to draw the underline according to the value of the
13007 variable `x-use-underline-position-properties', which is usually at the
13008 baseline level. The default value is nil. */);
13009 x_underline_at_descent_line = 0;
13011 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
13012 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
13013 #ifdef USE_TOOLKIT_SCROLL_BARS
13014 Vx_toolkit_scroll_bars = Qt;
13015 #else
13016 Vx_toolkit_scroll_bars = Qnil;
13017 #endif
13019 staticpro (&last_mouse_motion_frame);
13020 last_mouse_motion_frame = Qnil;
13022 /* Variables to configure modifier key assignment. */
13024 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
13025 doc: /* *Modifier key assumed when the Mac control key is pressed.
13026 The value can be `control', `meta', `alt', `hyper', or `super' for the
13027 respective modifier. The default is `control'. */);
13028 Vmac_control_modifier = Qcontrol;
13030 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
13031 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13032 The value can be `control', `meta', `alt', `hyper', or `super' for the
13033 respective modifier. If the value is nil then the key will act as the
13034 normal Mac control modifier, and the option key can be used to compose
13035 characters depending on the chosen Mac keyboard setting. */);
13036 Vmac_option_modifier = Qnil;
13038 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
13039 doc: /* *Modifier key assumed when the Mac command key is pressed.
13040 The value can be `control', `meta', `alt', `hyper', or `super' for the
13041 respective modifier. The default is `meta'. */);
13042 Vmac_command_modifier = Qmeta;
13044 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
13045 doc: /* *Modifier key assumed when the Mac function key is pressed.
13046 The value can be `control', `meta', `alt', `hyper', or `super' for the
13047 respective modifier. Note that remapping the function key may lead to
13048 unexpected results for some keys on non-US/GB keyboards. */);
13049 Vmac_function_modifier = Qnil;
13051 DEFVAR_LISP ("mac-emulate-three-button-mouse",
13052 &Vmac_emulate_three_button_mouse,
13053 doc: /* *Specify a way of three button mouse emulation.
13054 The value can be nil, t, or the symbol `reverse'.
13055 A value of nil means that no emulation should be done and the modifiers
13056 should be placed on the mouse-1 event.
13057 t means that when the option-key is held down while pressing the mouse
13058 button, the click will register as mouse-2 and while the command-key
13059 is held down, the click will register as mouse-3.
13060 The symbol `reverse' means that the option-key will register for
13061 mouse-3 and the command-key will register for mouse-2. */);
13062 Vmac_emulate_three_button_mouse = Qnil;
13064 #if TARGET_API_MAC_CARBON
13065 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
13066 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
13067 Otherwise, the right click will be treated as mouse-2 and the wheel
13068 button will be mouse-3. */);
13069 mac_wheel_button_is_mouse_2 = 1;
13071 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
13072 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
13073 mac_pass_command_to_system = 1;
13075 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
13076 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
13077 mac_pass_control_to_system = 1;
13079 #endif
13081 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
13082 doc: /* *If non-nil, allow anti-aliasing.
13083 The text will be rendered using Core Graphics text rendering which
13084 may anti-alias the text. */);
13085 #if USE_CG_DRAWING
13086 mac_use_core_graphics = 1;
13087 #else
13088 mac_use_core_graphics = 0;
13089 #endif
13091 /* Register an entry for `mac-roman' so that it can be used when
13092 creating the terminal frame on Mac OS 9 before loading
13093 term/mac-win.elc. */
13094 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
13095 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
13096 Each entry should be of the form:
13098 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13100 where CHARSET-NAME is a string used in font names to identify the
13101 charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13102 CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
13103 Vmac_charset_info_alist =
13104 Fcons (list3 (build_string ("mac-roman"),
13105 make_number (smRoman), Qnil), Qnil);
13107 #if USE_MAC_TSM
13108 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13109 doc: /* Overlay used to display Mac TSM active input area. */);
13110 Vmac_ts_active_input_overlay = Qnil;
13112 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13113 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13114 If the value is t, the input script and language are restored to those
13115 used in the last focus frame. If the value is a pair of integers, the
13116 input script and language codes, which are defined in the Script
13117 Manager, are set to its car and cdr parts, respectively. Otherwise,
13118 Emacs doesn't set them and thus follows the system default behavior. */);
13119 Vmac_ts_script_language_on_focus = Qnil;
13120 #endif
13123 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13124 (do not change this comment) */