Merge from emacs--rel--22
[emacs.git] / src / macterm.c
blob671ac1010d2847eb505fbe4276510ca9544d92f3
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"
83 #include "character.h"
84 #include "ccl.h"
88 /* Non-nil means Emacs uses toolkit scroll bars. */
90 Lisp_Object Vx_toolkit_scroll_bars;
92 /* If non-zero, the text will be rendered using Core Graphics text
93 rendering which may anti-alias the text. */
94 int mac_use_core_graphics;
97 /* Non-zero means that a HELP_EVENT has been generated since Emacs
98 start. */
100 static int any_help_event_p;
102 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
103 static Lisp_Object last_window;
105 /* Non-zero means make use of UNDERLINE_POSITION font properties.
106 (Not yet supported.) */
107 int x_use_underline_position_properties;
109 /* Non-zero means to draw the underline at the same place as the descent line. */
111 int x_underline_at_descent_line;
113 /* This is a chain of structures for all the X displays currently in
114 use. */
116 struct x_display_info *x_display_list;
118 /* This is a list of cons cells, each of the form (NAME
119 FONT-LIST-CACHE . RESOURCE-DATABASE), one for each element of
120 x_display_list and in the same order. NAME is the name of the
121 frame. FONT-LIST-CACHE records previous values returned by
122 x-list-fonts. RESOURCE-DATABASE preserves the X Resource Database
123 equivalent, which is implemented with a Lisp object, for the
124 display. */
126 Lisp_Object x_display_name_list;
128 /* This is display since Mac does not support multiple ones. */
129 struct mac_display_info one_mac_display_info;
131 /* Frame being updated by update_frame. This is declared in term.c.
132 This is set by update_begin and looked at by all the XT functions.
133 It is zero while not inside an update. In that case, the XT
134 functions assume that `selected_frame' is the frame to apply to. */
136 extern struct frame *updating_frame;
138 /* This is a frame waiting to be auto-raised, within XTread_socket. */
140 struct frame *pending_autoraise_frame;
142 /* Mouse movement.
144 Formerly, we used PointerMotionHintMask (in standard_event_mask)
145 so that we would have to call XQueryPointer after each MotionNotify
146 event to ask for another such event. However, this made mouse tracking
147 slow, and there was a bug that made it eventually stop.
149 Simply asking for MotionNotify all the time seems to work better.
151 In order to avoid asking for motion events and then throwing most
152 of them away or busy-polling the server for mouse positions, we ask
153 the server for pointer motion hints. This means that we get only
154 one event per group of mouse movements. "Groups" are delimited by
155 other kinds of events (focus changes and button clicks, for
156 example), or by XQueryPointer calls; when one of these happens, we
157 get another MotionNotify event the next time the mouse moves. This
158 is at least as efficient as getting motion events when mouse
159 tracking is on, and I suspect only negligibly worse when tracking
160 is off. */
162 /* Where the mouse was last time we reported a mouse event. */
164 static Rect last_mouse_glyph;
165 static FRAME_PTR last_mouse_glyph_frame;
167 /* The scroll bar in which the last X motion event occurred.
169 If the last X motion event occurred in a scroll bar, we set this so
170 XTmouse_position can know whether to report a scroll bar motion or
171 an ordinary motion.
173 If the last X motion event didn't occur in a scroll bar, we set
174 this to Qnil, to tell XTmouse_position to return an ordinary motion
175 event. */
177 static Lisp_Object last_mouse_scroll_bar;
179 /* This is a hack. We would really prefer that XTmouse_position would
180 return the time associated with the position it returns, but there
181 doesn't seem to be any way to wrest the time-stamp from the server
182 along with the position query. So, we just keep track of the time
183 of the last movement we received, and return that in hopes that
184 it's somewhat accurate. */
186 static Time last_mouse_movement_time;
188 struct scroll_bar *tracked_scroll_bar = NULL;
190 /* Incremented by XTread_socket whenever it really tries to read
191 events. */
193 #ifdef __STDC__
194 static int volatile input_signal_count;
195 #else
196 static int input_signal_count;
197 #endif
199 extern Lisp_Object Vsystem_name;
201 extern Lisp_Object Qeql;
203 /* A mask of extra modifier bits to put into every keyboard char. */
205 extern EMACS_INT extra_keyboard_modifiers;
207 /* The keysyms to use for the various modifiers. */
209 static Lisp_Object Qalt, Qhyper, Qsuper, Qcontrol, Qmeta, Qmodifier_value;
211 extern int inhibit_window_system;
213 #if __MRC__ && !TARGET_API_MAC_CARBON
214 QDGlobals qd; /* QuickDraw global information structure. */
215 #endif
217 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
219 struct mac_display_info *mac_display_info_for_display (Display *);
220 static void x_update_window_end P_ ((struct window *, int, int));
221 int x_catch_errors P_ ((Display *));
222 void x_uncatch_errors P_ ((Display *, int));
223 void x_lower_frame P_ ((struct frame *));
224 void x_scroll_bar_clear P_ ((struct frame *));
225 int x_had_errors_p P_ ((Display *));
226 void x_wm_set_size_hint P_ ((struct frame *, long, int));
227 void x_raise_frame P_ ((struct frame *));
228 void x_set_window_size P_ ((struct frame *, int, int, int));
229 void x_wm_set_window_state P_ ((struct frame *, int));
230 void x_wm_set_icon_pixmap P_ ((struct frame *, int));
231 static void mac_initialize P_ ((void));
232 static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
233 static int x_compute_min_glyph_bounds P_ ((struct frame *));
234 static void x_update_end P_ ((struct frame *));
235 static void XTframe_up_to_date P_ ((struct frame *));
236 static void XTset_terminal_modes P_ ((struct terminal *));
237 static void XTreset_terminal_modes P_ ((struct terminal *));
238 static void x_clear_frame P_ ((struct frame *));
239 static void frame_highlight P_ ((struct frame *));
240 static void frame_unhighlight P_ ((struct frame *));
241 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
242 static void mac_focus_changed P_ ((int, struct mac_display_info *,
243 struct frame *, struct input_event *));
244 static void x_detect_focus_change P_ ((struct mac_display_info *,
245 const EventRecord *,
246 struct input_event *));
247 static void XTframe_rehighlight P_ ((struct frame *));
248 static void x_frame_rehighlight P_ ((struct x_display_info *));
249 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
250 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
251 enum text_cursor_kinds));
253 static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
254 static void x_flush P_ ((struct frame *f));
255 static void x_update_begin P_ ((struct frame *));
256 static void x_update_window_begin P_ ((struct window *));
257 static void x_after_update_window_line P_ ((struct glyph_row *));
258 static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
259 enum scroll_bar_part *,
260 Lisp_Object *, Lisp_Object *,
261 unsigned long *));
263 static int is_emacs_window P_ ((WindowRef));
264 static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int));
265 static void XSetFont P_ ((Display *, GC, XFontStruct *));
266 static struct terminal *mac_create_terminal P_ ((struct mac_display_info *dpyinfo));
269 #define GC_FORE_COLOR(gc) (&(gc)->fore_color)
270 #define GC_BACK_COLOR(gc) (&(gc)->back_color)
271 #define GC_FONT(gc) ((gc)->xgcv.font)
272 #define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
274 #define CG_SET_FILL_COLOR(context, color) \
275 CGContextSetRGBFillColor (context, \
276 RED_FROM_ULONG (color) / 255.0f, \
277 GREEN_FROM_ULONG (color) / 255.0f, \
278 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
279 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
280 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
281 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
282 do { \
283 if (CGColorGetTypeID != NULL) \
284 CGContextSetFillColorWithColor (context, cg_color); \
285 else \
286 CG_SET_FILL_COLOR (context, color); \
287 } while (0)
288 #else
289 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
290 CGContextSetFillColorWithColor (context, cg_color)
291 #endif
292 #else
293 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
294 CG_SET_FILL_COLOR (context, color)
295 #endif
296 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, gc) \
297 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
298 (gc)->cg_fore_color)
299 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, gc) \
300 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.background, \
301 (gc)->cg_back_color)
304 #define CG_SET_STROKE_COLOR(context, color) \
305 CGContextSetRGBStrokeColor (context, \
306 RED_FROM_ULONG (color) / 255.0f, \
307 GREEN_FROM_ULONG (color) / 255.0f, \
308 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
309 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
310 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
311 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
312 do { \
313 if (CGColorGetTypeID != NULL) \
314 CGContextSetStrokeColorWithColor (context, cg_color); \
315 else \
316 CG_SET_STROKE_COLOR (context, color); \
317 } while (0)
318 #else
319 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
320 CGContextSetStrokeColorWithColor (context, cg_color)
321 #endif
322 #else
323 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
324 CG_SET_STROKE_COLOR (context, color)
325 #endif
326 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, gc) \
327 CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
328 (gc)->cg_fore_color)
330 #if USE_CG_DRAWING
331 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
333 /* Fringe bitmaps. */
335 static int max_fringe_bmp = 0;
336 static CGImageRef *fringe_bmp = 0;
338 CGColorSpaceRef mac_cg_color_space_rgb;
339 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
340 static CGColorRef mac_cg_color_black;
341 #endif
343 static void
344 init_cg_color ()
346 mac_cg_color_space_rgb = CGColorSpaceCreateDeviceRGB ();
347 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
348 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
349 /* Don't check the availability of CGColorCreate; this symbol is
350 defined even in Mac OS X 10.1. */
351 if (CGColorGetTypeID != NULL)
352 #endif
354 CGFloat rgba[] = {0.0f, 0.0f, 0.0f, 1.0f};
356 mac_cg_color_black = CGColorCreate (mac_cg_color_space_rgb, rgba);
358 #endif
361 static CGContextRef
362 mac_begin_cg_clip (f, gc)
363 struct frame *f;
364 GC gc;
366 CGContextRef context = FRAME_CG_CONTEXT (f);
368 if (!context)
370 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
371 FRAME_CG_CONTEXT (f) = context;
374 CGContextSaveGState (context);
375 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
376 CGContextScaleCTM (context, 1, -1);
377 if (gc && gc->n_clip_rects)
378 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
380 return context;
383 static void
384 mac_end_cg_clip (f)
385 struct frame *f;
387 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
390 void
391 mac_prepare_for_quickdraw (f)
392 struct frame *f;
394 if (f == NULL)
396 Lisp_Object rest, frame;
397 FOR_EACH_FRAME (rest, frame)
398 if (FRAME_MAC_P (XFRAME (frame)))
399 mac_prepare_for_quickdraw (XFRAME (frame));
401 else
403 CGContextRef context = FRAME_CG_CONTEXT (f);
405 if (context)
407 CGContextSynchronize (context);
408 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
409 &FRAME_CG_CONTEXT (f));
413 #endif
415 static RgnHandle saved_port_clip_region = NULL;
417 static void
418 mac_begin_clip (f, gc)
419 struct frame *f;
420 GC gc;
422 static RgnHandle new_region = NULL;
424 if (saved_port_clip_region == NULL)
425 saved_port_clip_region = NewRgn ();
426 if (new_region == NULL)
427 new_region = NewRgn ();
429 #if USE_CG_DRAWING
430 mac_prepare_for_quickdraw (f);
431 #endif
432 SetPortWindowPort (FRAME_MAC_WINDOW (f));
434 if (gc->n_clip_rects)
436 GetClip (saved_port_clip_region);
437 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
438 SetClip (new_region);
442 static void
443 mac_end_clip (gc)
444 GC gc;
446 if (gc->n_clip_rects)
447 SetClip (saved_port_clip_region);
451 /* X display function emulation */
453 /* Mac version of XDrawLine. */
455 static void
456 mac_draw_line (f, gc, x1, y1, x2, y2)
457 struct frame *f;
458 GC gc;
459 int x1, y1, x2, y2;
461 #if USE_CG_DRAWING
462 CGContextRef context;
463 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
465 if (y1 != y2)
466 gx1 += 0.5f, gx2 += 0.5f;
467 if (x1 != x2)
468 gy1 += 0.5f, gy2 += 0.5f;
470 context = mac_begin_cg_clip (f, gc);
471 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
472 CGContextBeginPath (context);
473 CGContextMoveToPoint (context, gx1, gy1);
474 CGContextAddLineToPoint (context, gx2, gy2);
475 CGContextClosePath (context);
476 CGContextStrokePath (context);
477 mac_end_cg_clip (f);
478 #else
479 if (x1 == x2)
481 if (y1 > y2)
482 y1--;
483 else if (y2 > y1)
484 y2--;
486 else if (y1 == y2)
488 if (x1 > x2)
489 x1--;
490 else
491 x2--;
494 mac_begin_clip (f, gc);
495 RGBForeColor (GC_FORE_COLOR (gc));
496 MoveTo (x1, y1);
497 LineTo (x2, y2);
498 mac_end_clip (gc);
499 #endif
502 /* Mac version of XDrawLine (to Pixmap). */
504 void
505 XDrawLine (display, p, gc, x1, y1, x2, y2)
506 Display *display;
507 Pixmap p;
508 GC gc;
509 int x1, y1, x2, y2;
511 #if USE_MAC_IMAGE_IO
512 CGContextRef context;
513 XImagePtr ximg = p;
514 CGColorSpaceRef color_space;
515 CGImageAlphaInfo alpha_info;
516 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
518 if (y1 != y2)
519 gx1 += 0.5f, gx2 += 0.5f;
520 if (x1 != x2)
521 gy1 += 0.5f, gy2 += 0.5f;
523 if (ximg->bits_per_pixel == 32)
525 color_space = mac_cg_color_space_rgb;
526 alpha_info = (kCGImageAlphaNoneSkipFirst
527 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
528 | kCGBitmapByteOrder32Host
529 #endif
532 else
534 color_space = NULL;
535 alpha_info = kCGImageAlphaOnly;
537 if (color_space == NULL)
538 return;
539 context = CGBitmapContextCreate (ximg->data, ximg->width,
540 ximg->height, 8,
541 ximg->bytes_per_line, color_space,
542 alpha_info);
543 if (ximg->bits_per_pixel == 32)
544 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
545 else
546 CGContextSetGrayStrokeColor (context, gc->xgcv.foreground / 255.0f, 1.0);
547 CGContextMoveToPoint (context, gx1, gy1);
548 CGContextAddLineToPoint (context, gx2, gy2);
549 CGContextClosePath (context);
550 CGContextStrokePath (context);
551 CGContextRelease (context);
552 #else
553 CGrafPtr old_port;
554 GDHandle old_gdh;
556 if (x1 == x2)
558 if (y1 > y2)
559 y1--;
560 else if (y2 > y1)
561 y2--;
563 else if (y1 == y2)
565 if (x1 > x2)
566 x1--;
567 else
568 x2--;
571 GetGWorld (&old_port, &old_gdh);
572 SetGWorld (p, NULL);
574 RGBForeColor (GC_FORE_COLOR (gc));
576 LockPixels (GetGWorldPixMap (p));
577 MoveTo (x1, y1);
578 LineTo (x2, y2);
579 UnlockPixels (GetGWorldPixMap (p));
581 SetGWorld (old_port, old_gdh);
582 #endif
586 static void
587 mac_erase_rectangle (f, gc, x, y, width, height)
588 struct frame *f;
589 GC gc;
590 int x, y;
591 unsigned int width, height;
593 #if USE_CG_DRAWING
595 CGContextRef context;
597 context = mac_begin_cg_clip (f, gc);
598 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
599 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
600 mac_end_cg_clip (f);
602 #else
604 Rect r;
606 mac_begin_clip (f, gc);
607 RGBBackColor (GC_BACK_COLOR (gc));
608 SetRect (&r, x, y, x + width, y + height);
609 EraseRect (&r);
610 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
611 mac_end_clip (gc);
613 #endif
617 /* Mac version of XClearArea. */
619 void
620 mac_clear_area (f, x, y, width, height)
621 struct frame *f;
622 int x, y;
623 unsigned int width, height;
625 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
628 /* Mac version of XClearWindow. */
630 static void
631 mac_clear_window (f)
632 struct frame *f;
634 #if USE_CG_DRAWING
636 CGContextRef context;
637 GC gc = FRAME_NORMAL_GC (f);
639 context = mac_begin_cg_clip (f, NULL);
640 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
641 CGContextFillRect (context, CGRectMake (0, 0, FRAME_PIXEL_WIDTH (f),
642 FRAME_PIXEL_HEIGHT (f)));
643 mac_end_cg_clip (f);
645 #else /* !USE_CG_DRAWING */
646 SetPortWindowPort (FRAME_MAC_WINDOW (f));
648 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
650 #if TARGET_API_MAC_CARBON
652 Rect r;
654 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
655 EraseRect (&r);
657 #else /* not TARGET_API_MAC_CARBON */
658 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
659 #endif /* not TARGET_API_MAC_CARBON */
660 #endif
664 /* Mac replacement for XCopyArea. */
666 #if USE_CG_DRAWING
667 static void
668 mac_draw_cg_image (image, f, gc, src_x, src_y, width, height,
669 dest_x, dest_y, overlay_p)
670 CGImageRef image;
671 struct frame *f;
672 GC gc;
673 int src_x, src_y;
674 unsigned int width, height;
675 int dest_x, dest_y, overlay_p;
677 CGContextRef context;
678 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
679 CGRect dest_rect = mac_rect_make (f, dest_x, dest_y, width, height);
681 context = mac_begin_cg_clip (f, gc);
682 if (!overlay_p)
684 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
685 CGContextFillRect (context, dest_rect);
687 CGContextClipToRect (context, dest_rect);
688 CGContextScaleCTM (context, 1, -1);
689 CGContextTranslateCTM (context, 0, -port_height);
690 if (CGImageIsMask (image))
691 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
692 CGContextDrawImage (context,
693 mac_rect_make (f, dest_x - src_x,
694 port_height - (dest_y - src_y
695 + CGImageGetHeight (image)),
696 CGImageGetWidth (image),
697 CGImageGetHeight (image)),
698 image);
699 mac_end_cg_clip (f);
702 #else /* !USE_CG_DRAWING */
704 static void
705 mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
706 struct frame *f;
707 GC gc;
708 int x, y, width, height;
709 unsigned short *bits;
710 int overlay_p;
712 BitMap bitmap;
713 Rect r;
715 bitmap.rowBytes = sizeof(unsigned short);
716 bitmap.baseAddr = (char *)bits;
717 SetRect (&(bitmap.bounds), 0, 0, width, height);
719 mac_begin_clip (f, gc);
720 RGBForeColor (GC_FORE_COLOR (gc));
721 RGBBackColor (GC_BACK_COLOR (gc));
722 SetRect (&r, x, y, x + width, y + height);
723 #if TARGET_API_MAC_CARBON
725 CGrafPtr port;
727 GetPort (&port);
728 LockPortBits (port);
729 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
730 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
731 UnlockPortBits (port);
733 #else /* not TARGET_API_MAC_CARBON */
734 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
735 overlay_p ? srcOr : srcCopy, 0);
736 #endif /* not TARGET_API_MAC_CARBON */
737 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
738 mac_end_clip (gc);
740 #endif /* !USE_CG_DRAWING */
743 /* Mac replacement for XCreateBitmapFromBitmapData. */
745 static void
746 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
747 BitMap *bitmap;
748 char *bits;
749 int w, h;
751 static const unsigned char swap_nibble[16]
752 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
753 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
754 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
755 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
756 int i, j, w1;
757 char *p;
759 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
760 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
761 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
762 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
763 for (i = 0; i < h; i++)
765 p = bitmap->baseAddr + i * bitmap->rowBytes;
766 for (j = 0; j < w1; j++)
768 /* Bitswap XBM bytes to match how Mac does things. */
769 unsigned char c = *bits++;
770 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
771 | (swap_nibble[(c>>4) & 0xf]));
775 SetRect (&(bitmap->bounds), 0, 0, w, h);
779 static void
780 mac_free_bitmap (bitmap)
781 BitMap *bitmap;
783 xfree (bitmap->baseAddr);
787 Pixmap
788 XCreatePixmap (display, w, width, height, depth)
789 Display *display;
790 Window w;
791 unsigned int width, height;
792 unsigned int depth;
794 #if USE_MAC_IMAGE_IO
795 XImagePtr ximg;
797 ximg = xmalloc (sizeof (*ximg));
798 ximg->width = width;
799 ximg->height = height;
800 ximg->bits_per_pixel = depth == 1 ? 8 : 32;
801 ximg->bytes_per_line = width * (ximg->bits_per_pixel / 8);
802 ximg->data = xmalloc (ximg->bytes_per_line * height);
803 return ximg;
804 #else
805 Pixmap pixmap;
806 Rect r;
807 QDErr err;
809 #ifdef MAC_OS8
810 SetPortWindowPort (w);
811 #endif
812 SetRect (&r, 0, 0, width, height);
813 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
814 if (depth == 1)
815 #endif
816 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
817 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
818 else
819 /* CreateCGImageFromPixMaps requires ARGB format. */
820 err = QTNewGWorld (&pixmap, k32ARGBPixelFormat, &r, NULL, NULL, 0);
821 #endif
822 if (err != noErr)
823 return NULL;
824 return pixmap;
825 #endif
829 Pixmap
830 XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
831 Display *display;
832 Window w;
833 char *data;
834 unsigned int width, height;
835 unsigned long fg, bg;
836 unsigned int depth;
838 Pixmap pixmap;
839 BitMap bitmap;
840 #if USE_MAC_IMAGE_IO
841 CGDataProviderRef provider;
842 CGImageRef image_mask;
843 CGContextRef context;
845 pixmap = XCreatePixmap (display, w, width, height, depth);
846 if (pixmap == NULL)
847 return NULL;
849 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
850 provider = CGDataProviderCreateWithData (NULL, bitmap.baseAddr,
851 bitmap.rowBytes * height, NULL);
852 image_mask = CGImageMaskCreate (width, height, 1, 1, bitmap.rowBytes,
853 provider, NULL, 0);
854 CGDataProviderRelease (provider);
856 context = CGBitmapContextCreate (pixmap->data, width, height, 8,
857 pixmap->bytes_per_line,
858 mac_cg_color_space_rgb,
859 kCGImageAlphaNoneSkipFirst
860 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
861 | kCGBitmapByteOrder32Host
862 #endif
865 CG_SET_FILL_COLOR (context, fg);
866 CGContextFillRect (context, CGRectMake (0, 0, width, height));
867 CG_SET_FILL_COLOR (context, bg);
868 CGContextDrawImage (context, CGRectMake (0, 0, width, height), image_mask);
869 CGContextRelease (context);
870 CGImageRelease (image_mask);
871 #else
872 CGrafPtr old_port;
873 GDHandle old_gdh;
874 static GC gc = NULL;
876 if (gc == NULL)
877 gc = XCreateGC (display, w, 0, NULL);
879 pixmap = XCreatePixmap (display, w, width, height, depth);
880 if (pixmap == NULL)
881 return NULL;
883 GetGWorld (&old_port, &old_gdh);
884 SetGWorld (pixmap, NULL);
885 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
886 XSetForeground (display, gc, fg);
887 XSetBackground (display, gc, bg);
888 RGBForeColor (GC_FORE_COLOR (gc));
889 RGBBackColor (GC_BACK_COLOR (gc));
890 LockPixels (GetGWorldPixMap (pixmap));
891 #if TARGET_API_MAC_CARBON
892 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
893 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
894 #else /* not TARGET_API_MAC_CARBON */
895 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
896 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
897 #endif /* not TARGET_API_MAC_CARBON */
898 UnlockPixels (GetGWorldPixMap (pixmap));
899 SetGWorld (old_port, old_gdh);
900 #endif
901 mac_free_bitmap (&bitmap);
903 return pixmap;
907 void
908 XFreePixmap (display, pixmap)
909 Display *display;
910 Pixmap pixmap;
912 #if USE_MAC_IMAGE_IO
913 if (pixmap)
915 if (pixmap->data)
916 xfree (pixmap->data);
917 xfree (pixmap);
919 #else
920 DisposeGWorld (pixmap);
921 #endif
925 /* Mac replacement for XFillRectangle. */
927 static void
928 mac_fill_rectangle (f, gc, x, y, width, height)
929 struct frame *f;
930 GC gc;
931 int x, y;
932 unsigned int width, height;
934 #if USE_CG_DRAWING
935 CGContextRef context;
937 context = mac_begin_cg_clip (f, gc);
938 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
939 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
940 mac_end_cg_clip (f);
941 #else
942 Rect r;
944 mac_begin_clip (f, gc);
945 RGBForeColor (GC_FORE_COLOR (gc));
946 SetRect (&r, x, y, x + width, y + height);
947 PaintRect (&r); /* using foreground color of gc */
948 mac_end_clip (gc);
949 #endif
953 /* Mac replacement for XDrawRectangle: dest is a window. */
955 static void
956 mac_draw_rectangle (f, gc, x, y, width, height)
957 struct frame *f;
958 GC gc;
959 int x, y;
960 unsigned int width, height;
962 #if USE_CG_DRAWING
963 CGContextRef context;
965 context = mac_begin_cg_clip (f, gc);
966 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
967 CGContextStrokeRect (context,
968 CGRectMake (x + 0.5f, y + 0.5f, width, height));
969 mac_end_cg_clip (f);
970 #else
971 Rect r;
973 mac_begin_clip (f, gc);
974 RGBForeColor (GC_FORE_COLOR (gc));
975 SetRect (&r, x, y, x + width + 1, y + height + 1);
976 FrameRect (&r); /* using foreground color of gc */
977 mac_end_clip (gc);
978 #endif
982 static void
983 mac_invert_rectangle (f, x, y, width, height)
984 struct frame *f;
985 int x, y;
986 unsigned int width, height;
988 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
989 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
990 if (CGContextSetBlendMode != NULL)
991 #endif
993 CGContextRef context;
995 context = mac_begin_cg_clip (f, NULL);
996 CGContextSetRGBFillColor (context, 1.0f, 1.0f, 1.0f, 1.0f);
997 CGContextSetBlendMode (context, kCGBlendModeDifference);
998 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
999 mac_end_cg_clip (f);
1001 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
1002 else /* CGContextSetBlendMode == NULL */
1003 #endif
1004 #endif /* USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 */
1005 #if !USE_CG_DRAWING || MAC_OS_X_VERSION_MAX_ALLOWED < 1040 || (MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020)
1007 Rect r;
1009 #if USE_CG_DRAWING
1010 mac_prepare_for_quickdraw (f);
1011 #endif
1012 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1014 SetRect (&r, x, y, x + width, y + height);
1016 InvertRect (&r);
1020 #if USE_ATSUI
1021 static OSStatus
1022 atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
1023 ConstUniCharArrayPtr text;
1024 UniCharCount text_length;
1025 ATSUStyle style;
1026 ATSUTextLayout *text_layout;
1028 OSStatus err;
1029 static ATSUTextLayout saved_text_layout = NULL;
1031 if (saved_text_layout == NULL)
1033 static const UniCharCount lengths[] = {kATSUToTextEnd};
1034 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
1035 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
1036 static ATSLineLayoutOptions line_layout =
1037 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1038 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
1039 | kATSLineUseQDRendering
1040 #else
1041 kATSLineIsDisplayOnly | kATSLineFractDisable
1042 #endif
1044 static const ATSUAttributeValuePtr values[] = {&line_layout};
1046 err = ATSUCreateTextLayoutWithTextPtr (text,
1047 kATSUFromTextBeginning,
1048 kATSUToTextEnd,
1049 text_length,
1050 1, lengths, &style,
1051 &saved_text_layout);
1052 if (err == noErr)
1053 err = ATSUSetLayoutControls (saved_text_layout,
1054 sizeof (tags) / sizeof (tags[0]),
1055 tags, sizes, values);
1056 if (err == noErr)
1057 err = ATSUSetTransientFontMatching (saved_text_layout, true);
1059 else
1061 err = ATSUSetRunStyle (saved_text_layout, style,
1062 kATSUFromTextBeginning, kATSUToTextEnd);
1063 if (err == noErr)
1064 err = ATSUSetTextPointerLocation (saved_text_layout, text,
1065 kATSUFromTextBeginning,
1066 kATSUToTextEnd,
1067 text_length);
1070 if (err == noErr)
1071 *text_layout = saved_text_layout;
1072 return err;
1076 static void
1077 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1078 overstrike_p, bytes_per_char)
1079 struct frame *f;
1080 GC gc;
1081 int x, y;
1082 char *buf;
1083 int nchars, bg_width, overstrike_p, bytes_per_char;
1085 OSStatus err;
1086 ATSUTextLayout text_layout;
1088 xassert (bytes_per_char == 2);
1090 #ifndef WORDS_BIG_ENDIAN
1092 int i;
1093 UniChar *text = (UniChar *)buf;
1095 for (i = 0; i < nchars; i++)
1096 text[i] = EndianU16_BtoN (text[i]);
1098 #endif
1099 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
1100 nchars,
1101 GC_FONT (gc)->mac_style,
1102 &text_layout);
1103 if (err != noErr)
1104 return;
1105 #ifdef MAC_OSX
1106 if (!mac_use_core_graphics)
1108 #endif
1109 mac_begin_clip (f, gc);
1110 RGBForeColor (GC_FORE_COLOR (gc));
1111 if (bg_width)
1113 Rect r;
1115 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1116 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1117 RGBBackColor (GC_BACK_COLOR (gc));
1118 EraseRect (&r);
1119 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1121 MoveTo (x, y);
1122 ATSUDrawText (text_layout,
1123 kATSUFromTextBeginning, kATSUToTextEnd,
1124 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1125 if (overstrike_p)
1127 MoveTo (x + 1, y);
1128 ATSUDrawText (text_layout,
1129 kATSUFromTextBeginning, kATSUToTextEnd,
1130 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1132 mac_end_clip (gc);
1133 #ifdef MAC_OSX
1135 else
1137 static CGContextRef context;
1138 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
1139 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1140 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1141 static const ATSUAttributeValuePtr values[] = {&context};
1143 #if USE_CG_DRAWING
1144 context = mac_begin_cg_clip (f, gc);
1145 #else
1146 CGrafPtr port;
1148 GetPort (&port);
1149 QDBeginCGContext (port, &context);
1150 if (gc->n_clip_rects || bg_width)
1152 CGContextTranslateCTM (context, 0, port_height);
1153 CGContextScaleCTM (context, 1, -1);
1154 if (gc->n_clip_rects)
1155 CGContextClipToRects (context, gc->clip_rects,
1156 gc->n_clip_rects);
1157 #endif
1158 if (bg_width)
1160 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1161 CGContextFillRect (context,
1162 mac_rect_make (f,
1163 x, y - FONT_BASE (GC_FONT (gc)),
1164 bg_width,
1165 FONT_HEIGHT (GC_FONT (gc))));
1167 CGContextScaleCTM (context, 1, -1);
1168 CGContextTranslateCTM (context, 0, -port_height);
1169 #if !USE_CG_DRAWING
1171 #endif
1172 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1173 err = ATSUSetLayoutControls (text_layout,
1174 sizeof (tags) / sizeof (tags[0]),
1175 tags, sizes, values);
1176 if (err == noErr)
1178 ATSUDrawText (text_layout,
1179 kATSUFromTextBeginning, kATSUToTextEnd,
1180 Long2Fix (x), Long2Fix (port_height - y));
1181 if (overstrike_p)
1182 ATSUDrawText (text_layout,
1183 kATSUFromTextBeginning, kATSUToTextEnd,
1184 Long2Fix (x + 1), Long2Fix (port_height - y));
1186 #if USE_CG_DRAWING
1187 mac_end_cg_clip (f);
1188 context = NULL;
1189 #else
1190 CGContextSynchronize (context);
1191 QDEndCGContext (port, &context);
1192 #endif
1193 #if 0
1194 /* This doesn't work on Mac OS X 10.1. */
1195 ATSUClearLayoutControls (text_layout,
1196 sizeof (tags) / sizeof (tags[0]), tags);
1197 #else
1198 ATSUSetLayoutControls (text_layout,
1199 sizeof (tags) / sizeof (tags[0]),
1200 tags, sizes, values);
1201 #endif
1203 #endif /* MAC_OSX */
1205 #endif /* USE_ATSUI */
1208 static void
1209 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1210 overstrike_p, bytes_per_char)
1211 struct frame *f;
1212 GC gc;
1213 int x, y;
1214 char *buf;
1215 int nchars, bg_width, overstrike_p, bytes_per_char;
1217 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1218 UInt32 savedFlags;
1219 #endif
1221 mac_begin_clip (f, gc);
1222 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1223 if (mac_use_core_graphics)
1224 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
1225 #endif
1226 RGBForeColor (GC_FORE_COLOR (gc));
1227 #ifdef MAC_OS8
1228 if (bg_width)
1230 RGBBackColor (GC_BACK_COLOR (gc));
1231 TextMode (srcCopy);
1233 else
1234 TextMode (srcOr);
1235 #else
1236 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1237 because:
1238 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1239 into an offscreen graphics world first. So performance gain
1240 cannot be expected.)
1241 - It lowers rendering quality.
1242 - Some fonts leave garbage on cursor movement. */
1243 if (bg_width)
1245 Rect r;
1247 RGBBackColor (GC_BACK_COLOR (gc));
1248 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1249 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1250 EraseRect (&r);
1252 TextMode (srcOr);
1253 #endif
1254 TextFont (GC_FONT (gc)->mac_fontnum);
1255 TextSize (GC_FONT (gc)->mac_fontsize);
1256 TextFace (GC_FONT (gc)->mac_fontface);
1257 MoveTo (x, y);
1258 DrawText (buf, 0, nchars * bytes_per_char);
1259 if (overstrike_p)
1261 TextMode (srcOr);
1262 MoveTo (x + 1, y);
1263 DrawText (buf, 0, nchars * bytes_per_char);
1265 if (bg_width)
1266 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1267 mac_end_clip (gc);
1269 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1270 if (mac_use_core_graphics)
1271 SwapQDTextFlags(savedFlags);
1272 #endif
1276 static INLINE void
1277 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1278 overstrike_p, bytes_per_char)
1279 struct frame *f;
1280 GC gc;
1281 int x, y;
1282 char *buf;
1283 int nchars, bg_width, overstrike_p, bytes_per_char;
1285 #if USE_ATSUI
1286 if (GC_FONT (gc)->mac_style)
1287 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1288 overstrike_p, bytes_per_char);
1289 else
1290 #endif /* USE_ATSUI */
1291 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1292 overstrike_p, bytes_per_char);
1296 /* Mac replacement for XDrawImageString. */
1298 static void
1299 mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1300 struct frame *f;
1301 GC gc;
1302 int x, y;
1303 char *buf;
1304 int nchars, bg_width, overstrike_p;
1306 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1307 overstrike_p, 1);
1311 /* Mac replacement for XDrawImageString16. */
1313 static void
1314 mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1315 struct frame *f;
1316 GC gc;
1317 int x, y;
1318 XChar2b *buf;
1319 int nchars, bg_width, overstrike_p;
1321 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1322 overstrike_p, 2);
1326 /* Mac replacement for XQueryTextExtents, but takes a character. If
1327 STYLE is NULL, measurement is done by QuickDraw Text routines for
1328 the font of the current graphics port. If CG_GLYPH is not NULL,
1329 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1331 static OSStatus
1332 mac_query_char_extents (style, c,
1333 font_ascent_return, font_descent_return,
1334 overall_return, cg_glyph)
1335 #if USE_ATSUI
1336 ATSUStyle style;
1337 #else
1338 void *style;
1339 #endif
1340 int c;
1341 int *font_ascent_return, *font_descent_return;
1342 XCharStruct *overall_return;
1343 #if USE_CG_TEXT_DRAWING
1344 CGGlyph *cg_glyph;
1345 #else
1346 void *cg_glyph;
1347 #endif
1349 OSStatus err = noErr;
1350 int width;
1351 Rect char_bounds;
1353 #if USE_ATSUI
1354 if (style)
1356 ATSUTextLayout text_layout;
1357 UniChar ch = c;
1359 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
1360 if (err == noErr
1361 && (font_ascent_return || font_descent_return || overall_return))
1363 ATSTrapezoid glyph_bounds;
1365 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1366 kATSUFromTextBeginning, kATSUToTextEnd,
1367 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1368 kATSUseFractionalOrigins,
1369 #else
1370 kATSUseDeviceOrigins,
1371 #endif
1372 1, &glyph_bounds, NULL);
1373 if (err == noErr)
1375 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1376 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1378 width = Fix2Long (glyph_bounds.upperRight.x
1379 - glyph_bounds.upperLeft.x);
1380 if (font_ascent_return)
1381 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1382 if (font_descent_return)
1383 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1386 if (err == noErr && overall_return)
1388 err = ATSUMeasureTextImage (text_layout,
1389 kATSUFromTextBeginning, kATSUToTextEnd,
1390 0, 0, &char_bounds);
1391 if (err == noErr)
1392 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1393 #if USE_CG_TEXT_DRAWING
1394 if (err == noErr && cg_glyph)
1396 OSStatus err1;
1397 ATSUGlyphInfoArray glyph_info_array;
1398 ByteCount count = sizeof (ATSUGlyphInfoArray);
1400 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1401 kATSUToTextEnd, NULL, NULL, NULL);
1402 if (err1 == noErr)
1403 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1404 kATSUToTextEnd, &count,
1405 &glyph_info_array);
1406 if (err1 == noErr
1407 /* Make sure that we don't have to make layout
1408 adjustments. */
1409 && glyph_info_array.glyphs[0].deltaY == 0.0f
1410 && glyph_info_array.glyphs[0].idealX == 0.0f
1411 && glyph_info_array.glyphs[0].screenX == 0)
1413 xassert (glyph_info_array.glyphs[0].glyphID);
1414 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1416 else
1417 *cg_glyph = 0;
1419 #endif
1422 else
1423 #endif
1425 if (font_ascent_return || font_descent_return)
1427 FontInfo font_info;
1429 GetFontInfo (&font_info);
1430 if (font_ascent_return)
1431 *font_ascent_return = font_info.ascent;
1432 if (font_descent_return)
1433 *font_descent_return = font_info.descent;
1435 if (overall_return)
1437 char ch = c;
1439 width = CharWidth (ch);
1440 QDTextBounds (1, &ch, &char_bounds);
1441 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1445 return err;
1449 /* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1451 static int
1452 mac_text_extents_16 (font_struct, string, nchars, overall_return)
1453 XFontStruct *font_struct;
1454 XChar2b *string;
1455 int nchars;
1456 XCharStruct *overall_return;
1458 int i;
1459 short width = 0, lbearing = 0, rbearing = 0;
1460 XCharStruct *pcm;
1462 for (i = 0; i < nchars; i++)
1464 pcm = mac_per_char_metric (font_struct, string, 0);
1465 if (pcm == NULL)
1466 width += FONT_WIDTH (font_struct);
1467 else
1469 lbearing = min (lbearing, width + pcm->lbearing);
1470 rbearing = max (rbearing, width + pcm->rbearing);
1471 width += pcm->width;
1473 string++;
1476 overall_return->lbearing = lbearing;
1477 overall_return->rbearing = rbearing;
1478 overall_return->width = width;
1480 /* What's the meaning of the return value of XTextExtents16? */
1484 #if USE_CG_TEXT_DRAWING
1485 static int cg_text_anti_aliasing_threshold = 8;
1487 static void
1488 init_cg_text_anti_aliasing_threshold ()
1490 int threshold;
1491 Boolean valid_p;
1493 threshold =
1494 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1495 kCFPreferencesCurrentApplication,
1496 &valid_p);
1497 if (valid_p)
1498 cg_text_anti_aliasing_threshold = threshold;
1501 static int
1502 mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1503 struct frame *f;
1504 GC gc;
1505 int x, y;
1506 XChar2b *buf;
1507 int nchars, bg_width, overstrike_p;
1509 CGFloat port_height, gx, gy;
1510 int i;
1511 CGContextRef context;
1512 CGGlyph *glyphs;
1513 CGSize *advances;
1515 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
1516 return 0;
1518 port_height = FRAME_PIXEL_HEIGHT (f);
1519 gx = x;
1520 gy = port_height - y;
1521 glyphs = (CGGlyph *)buf;
1522 advances = alloca (sizeof (CGSize) * nchars);
1523 if (advances == NULL)
1524 return 0;
1525 for (i = 0; i < nchars; i++)
1527 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1529 advances[i].width = pcm->width;
1530 advances[i].height = 0;
1531 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1532 buf++;
1535 #if USE_CG_DRAWING
1536 context = mac_begin_cg_clip (f, gc);
1537 #else
1538 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1539 if (gc->n_clip_rects || bg_width)
1541 CGContextTranslateCTM (context, 0, port_height);
1542 CGContextScaleCTM (context, 1, -1);
1543 if (gc->n_clip_rects)
1544 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1545 #endif
1546 if (bg_width)
1548 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1549 CGContextFillRect
1550 (context,
1551 mac_rect_make (f, gx, y - FONT_BASE (GC_FONT (gc)),
1552 bg_width, FONT_HEIGHT (GC_FONT (gc))));
1554 CGContextScaleCTM (context, 1, -1);
1555 CGContextTranslateCTM (context, 0, -port_height);
1556 #if !USE_CG_DRAWING
1558 #endif
1559 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1560 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1561 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
1562 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1563 CGContextSetShouldAntialias (context, false);
1564 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1565 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1566 if (CGContextShowGlyphsWithAdvances != NULL)
1567 #endif
1569 CGContextSetTextPosition (context, gx, gy);
1570 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1571 if (overstrike_p)
1573 CGContextSetTextPosition (context, gx + 1.0f, gy);
1574 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1577 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1578 else /* CGContextShowGlyphsWithAdvances == NULL */
1579 #endif
1580 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1581 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1583 for (i = 0; i < nchars; i++)
1585 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1586 if (overstrike_p)
1587 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1588 gx += advances[i].width;
1591 #endif
1592 #if USE_CG_DRAWING
1593 mac_end_cg_clip (f);
1594 #else
1595 CGContextSynchronize (context);
1596 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1597 #endif
1599 return 1;
1601 #endif
1604 #if !USE_CG_DRAWING
1605 /* Mac replacement for XCopyArea: dest must be window. */
1607 static void
1608 mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1609 Pixmap src;
1610 struct frame *f;
1611 GC gc;
1612 int src_x, src_y;
1613 unsigned int width, height;
1614 int dest_x, dest_y;
1616 Rect src_r, dest_r;
1618 mac_begin_clip (f, gc);
1620 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1621 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1623 ForeColor (blackColor);
1624 BackColor (whiteColor);
1626 LockPixels (GetGWorldPixMap (src));
1627 #if TARGET_API_MAC_CARBON
1629 CGrafPtr port;
1631 GetPort (&port);
1632 LockPortBits (port);
1633 CopyBits (GetPortBitMapForCopyBits (src),
1634 GetPortBitMapForCopyBits (port),
1635 &src_r, &dest_r, srcCopy, 0);
1636 UnlockPortBits (port);
1638 #else /* not TARGET_API_MAC_CARBON */
1639 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
1640 &src_r, &dest_r, srcCopy, 0);
1641 #endif /* not TARGET_API_MAC_CARBON */
1642 UnlockPixels (GetGWorldPixMap (src));
1644 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1646 mac_end_clip (gc);
1650 static void
1651 mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
1652 width, height, dest_x, dest_y)
1653 Pixmap src, mask;
1654 struct frame *f;
1655 GC gc;
1656 int src_x, src_y;
1657 unsigned int width, height;
1658 int dest_x, dest_y;
1660 Rect src_r, dest_r;
1662 mac_begin_clip (f, gc);
1664 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1665 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1667 ForeColor (blackColor);
1668 BackColor (whiteColor);
1670 LockPixels (GetGWorldPixMap (src));
1671 LockPixels (GetGWorldPixMap (mask));
1672 #if TARGET_API_MAC_CARBON
1674 CGrafPtr port;
1676 GetPort (&port);
1677 LockPortBits (port);
1678 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1679 GetPortBitMapForCopyBits (port),
1680 &src_r, &src_r, &dest_r);
1681 UnlockPortBits (port);
1683 #else /* not TARGET_API_MAC_CARBON */
1684 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
1685 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
1686 #endif /* not TARGET_API_MAC_CARBON */
1687 UnlockPixels (GetGWorldPixMap (mask));
1688 UnlockPixels (GetGWorldPixMap (src));
1690 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1692 mac_end_clip (gc);
1694 #endif /* !USE_CG_DRAWING */
1697 /* Mac replacement for XCopyArea: used only for scrolling. */
1699 static void
1700 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1701 struct frame *f;
1702 GC gc;
1703 int src_x, src_y;
1704 unsigned int width, height;
1705 int dest_x, dest_y;
1707 #if TARGET_API_MAC_CARBON
1708 Rect src_r;
1709 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1711 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1712 #if USE_CG_DRAWING
1713 mac_prepare_for_quickdraw (f);
1714 #endif
1715 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1716 &src_r, dest_x - src_x, dest_y - src_y,
1717 kScrollWindowNoOptions, dummy);
1718 DisposeRgn (dummy);
1719 #else /* not TARGET_API_MAC_CARBON */
1720 Rect src_r, dest_r;
1721 WindowRef w = FRAME_MAC_WINDOW (f);
1723 mac_begin_clip (f, gc);
1725 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1726 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1728 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1729 color mapping in CopyBits. Otherwise, it will be slow. */
1730 ForeColor (blackColor);
1731 BackColor (whiteColor);
1732 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
1734 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1736 mac_end_clip (gc);
1737 #endif /* not TARGET_API_MAC_CARBON */
1741 /* Mac replacement for XChangeGC. */
1743 static void
1744 XChangeGC (display, gc, mask, xgcv)
1745 Display *display;
1746 GC gc;
1747 unsigned long mask;
1748 XGCValues *xgcv;
1750 if (mask & GCForeground)
1751 XSetForeground (display, gc, xgcv->foreground);
1752 if (mask & GCBackground)
1753 XSetBackground (display, gc, xgcv->background);
1754 if (mask & GCFont)
1755 XSetFont (display, gc, xgcv->font);
1759 /* Mac replacement for XCreateGC. */
1762 XCreateGC (display, d, mask, xgcv)
1763 Display *display;
1764 void *d;
1765 unsigned long mask;
1766 XGCValues *xgcv;
1768 GC gc = xmalloc (sizeof (*gc));
1770 bzero (gc, sizeof (*gc));
1771 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1772 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1773 if (CGColorGetTypeID != NULL)
1774 #endif
1776 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1777 CGColorRetain (gc->cg_fore_color);
1778 CGColorRetain (gc->cg_back_color);
1780 #endif
1781 XChangeGC (display, gc, mask, xgcv);
1783 return gc;
1787 /* Used in xfaces.c. */
1789 void
1790 XFreeGC (display, gc)
1791 Display *display;
1792 GC gc;
1794 if (gc->clip_region)
1795 DisposeRgn (gc->clip_region);
1796 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1797 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1798 if (CGColorGetTypeID != NULL)
1799 #endif
1801 CGColorRelease (gc->cg_fore_color);
1802 CGColorRelease (gc->cg_back_color);
1804 #endif
1805 xfree (gc);
1809 /* Mac replacement for XGetGCValues. */
1811 static void
1812 XGetGCValues (display, gc, mask, xgcv)
1813 Display *display;
1814 GC gc;
1815 unsigned long mask;
1816 XGCValues *xgcv;
1818 if (mask & GCForeground)
1819 xgcv->foreground = gc->xgcv.foreground;
1820 if (mask & GCBackground)
1821 xgcv->background = gc->xgcv.background;
1822 if (mask & GCFont)
1823 xgcv->font = gc->xgcv.font;
1827 /* Mac replacement for XSetForeground. */
1829 void
1830 XSetForeground (display, gc, color)
1831 Display *display;
1832 GC gc;
1833 unsigned long color;
1835 if (gc->xgcv.foreground != color)
1837 gc->xgcv.foreground = color;
1838 gc->fore_color.red = RED16_FROM_ULONG (color);
1839 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1840 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
1841 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1842 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1843 if (CGColorGetTypeID != NULL)
1844 #endif
1846 CGColorRelease (gc->cg_fore_color);
1847 if (color == 0)
1849 gc->cg_fore_color = mac_cg_color_black;
1850 CGColorRetain (gc->cg_fore_color);
1852 else
1854 CGFloat rgba[4];
1856 rgba[0] = gc->fore_color.red / 65535.0f;
1857 rgba[1] = gc->fore_color.green / 65535.0f;
1858 rgba[2] = gc->fore_color.blue / 65535.0f;
1859 rgba[3] = 1.0f;
1860 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1863 #endif
1868 /* Mac replacement for XSetBackground. */
1870 void
1871 XSetBackground (display, gc, color)
1872 Display *display;
1873 GC gc;
1874 unsigned long color;
1876 if (gc->xgcv.background != color)
1878 gc->xgcv.background = color;
1879 gc->back_color.red = RED16_FROM_ULONG (color);
1880 gc->back_color.green = GREEN16_FROM_ULONG (color);
1881 gc->back_color.blue = BLUE16_FROM_ULONG (color);
1882 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1883 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1884 if (CGColorGetTypeID != NULL)
1885 #endif
1887 CGColorRelease (gc->cg_back_color);
1888 if (color == 0)
1890 gc->cg_back_color = mac_cg_color_black;
1891 CGColorRetain (gc->cg_back_color);
1893 else
1895 CGFloat rgba[4];
1897 rgba[0] = gc->back_color.red / 65535.0f;
1898 rgba[1] = gc->back_color.green / 65535.0f;
1899 rgba[2] = gc->back_color.blue / 65535.0f;
1900 rgba[3] = 1.0f;
1901 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1904 #endif
1909 /* Mac replacement for XSetFont. */
1911 static void
1912 XSetFont (display, gc, font)
1913 Display *display;
1914 GC gc;
1915 XFontStruct *font;
1917 gc->xgcv.font = font;
1921 /* Mac replacement for XSetClipRectangles. */
1923 static void
1924 mac_set_clip_rectangles (f, gc, rectangles, n)
1925 struct frame *f;
1926 GC gc;
1927 Rect *rectangles;
1928 int n;
1930 int i;
1932 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1934 gc->n_clip_rects = n;
1935 if (n > 0)
1937 if (gc->clip_region == NULL)
1938 gc->clip_region = NewRgn ();
1939 RectRgn (gc->clip_region, rectangles);
1940 if (n > 1)
1942 RgnHandle region = NewRgn ();
1944 for (i = 1; i < n; i++)
1946 RectRgn (region, rectangles + i);
1947 UnionRgn (gc->clip_region, region, gc->clip_region);
1949 DisposeRgn (region);
1952 #if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1953 for (i = 0; i < n; i++)
1955 Rect *rect = rectangles + i;
1957 gc->clip_rects[i] = mac_rect_make (f, rect->left, rect->top,
1958 rect->right - rect->left,
1959 rect->bottom - rect->top);
1961 #endif
1965 /* Mac replacement for XSetClipMask. */
1967 static INLINE void
1968 mac_reset_clip_rectangles (f, gc)
1969 struct frame *f;
1970 GC gc;
1972 gc->n_clip_rects = 0;
1976 /* Mac replacement for XSetWindowBackground. */
1978 void
1979 XSetWindowBackground (display, w, color)
1980 Display *display;
1981 WindowRef w;
1982 unsigned long color;
1984 #if !TARGET_API_MAC_CARBON
1985 AuxWinHandle aw_handle;
1986 CTabHandle ctab_handle;
1987 ColorSpecPtr ct_table;
1988 short ct_size;
1989 #endif
1990 RGBColor bg_color;
1992 bg_color.red = RED16_FROM_ULONG (color);
1993 bg_color.green = GREEN16_FROM_ULONG (color);
1994 bg_color.blue = BLUE16_FROM_ULONG (color);
1996 #if TARGET_API_MAC_CARBON
1997 SetWindowContentColor (w, &bg_color);
1998 #else
1999 if (GetAuxWin (w, &aw_handle))
2001 ctab_handle = (*aw_handle)->awCTable;
2002 HandToHand ((Handle *) &ctab_handle);
2003 ct_table = (*ctab_handle)->ctTable;
2004 ct_size = (*ctab_handle)->ctSize;
2005 while (ct_size > -1)
2007 if (ct_table->value == 0)
2009 ct_table->rgb = bg_color;
2010 CTabChanged (ctab_handle);
2011 SetWinColor (w, (WCTabHandle) ctab_handle);
2013 ct_size--;
2016 #endif
2019 /* Flush display of frame F, or of all frames if F is null. */
2021 static void
2022 x_flush (f)
2023 struct frame *f;
2025 #if TARGET_API_MAC_CARBON
2026 BLOCK_INPUT;
2027 #if USE_CG_DRAWING
2028 mac_prepare_for_quickdraw (f);
2029 #endif
2030 if (f)
2031 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
2032 else
2033 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
2034 UNBLOCK_INPUT;
2035 #endif
2039 /* Remove calls to XFlush by defining XFlush to an empty replacement.
2040 Calls to XFlush should be unnecessary because the X output buffer
2041 is flushed automatically as needed by calls to XPending,
2042 XNextEvent, or XWindowEvent according to the XFlush man page.
2043 XTread_socket calls XPending. Removing XFlush improves
2044 performance. */
2046 #define XFlush(DISPLAY) (void) 0
2048 #if USE_CG_DRAWING
2049 static void
2050 mac_flush_display_optional (f)
2051 struct frame *f;
2053 BLOCK_INPUT;
2054 mac_prepare_for_quickdraw (f);
2055 UNBLOCK_INPUT;
2057 #endif
2059 /***********************************************************************
2060 Starting and ending an update
2061 ***********************************************************************/
2063 /* Start an update of frame F. This function is installed as a hook
2064 for update_begin, i.e. it is called when update_begin is called.
2065 This function is called prior to calls to x_update_window_begin for
2066 each window being updated. */
2068 static void
2069 x_update_begin (f)
2070 struct frame *f;
2072 #if TARGET_API_MAC_CARBON
2073 /* During update of a frame, availability of input events is
2074 periodically checked with ReceiveNextEvent if
2075 redisplay-dont-pause is nil. That normally flushes window buffer
2076 changes for every check, and thus screen update looks waving even
2077 if no input is available. So we disable screen updates during
2078 update of a frame. */
2079 BLOCK_INPUT;
2080 DisableScreenUpdates ();
2081 UNBLOCK_INPUT;
2082 #endif
2086 /* Start update of window W. Set the global variable updated_window
2087 to the window being updated and set output_cursor to the cursor
2088 position of W. */
2090 static void
2091 x_update_window_begin (w)
2092 struct window *w;
2094 struct frame *f = XFRAME (WINDOW_FRAME (w));
2095 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
2097 updated_window = w;
2098 set_output_cursor (&w->cursor);
2100 BLOCK_INPUT;
2102 if (f == display_info->mouse_face_mouse_frame)
2104 /* Don't do highlighting for mouse motion during the update. */
2105 display_info->mouse_face_defer = 1;
2107 /* If F needs to be redrawn, simply forget about any prior mouse
2108 highlighting. */
2109 if (FRAME_GARBAGED_P (f))
2110 display_info->mouse_face_window = Qnil;
2112 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
2113 their mouse_face_p flag set, which means that they are always
2114 unequal to rows in a desired matrix which never have that
2115 flag set. So, rows containing mouse-face glyphs are never
2116 scrolled, and we don't have to switch the mouse highlight off
2117 here to prevent it from being scrolled. */
2119 /* Can we tell that this update does not affect the window
2120 where the mouse highlight is? If so, no need to turn off.
2121 Likewise, don't do anything if the frame is garbaged;
2122 in that case, the frame's current matrix that we would use
2123 is all wrong, and we will redisplay that line anyway. */
2124 if (!NILP (display_info->mouse_face_window)
2125 && w == XWINDOW (display_info->mouse_face_window))
2127 int i;
2129 for (i = 0; i < w->desired_matrix->nrows; ++i)
2130 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2131 break;
2133 if (i < w->desired_matrix->nrows)
2134 clear_mouse_face (display_info);
2136 #endif /* 0 */
2139 UNBLOCK_INPUT;
2143 /* Draw a vertical window border from (x,y0) to (x,y1) */
2145 static void
2146 mac_draw_vertical_window_border (w, x, y0, y1)
2147 struct window *w;
2148 int x, y0, y1;
2150 struct frame *f = XFRAME (WINDOW_FRAME (w));
2151 struct face *face;
2153 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2154 if (face)
2155 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2156 face->foreground);
2158 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
2161 /* End update of window W (which is equal to updated_window).
2163 Draw vertical borders between horizontally adjacent windows, and
2164 display W's cursor if CURSOR_ON_P is non-zero.
2166 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2167 glyphs in mouse-face were overwritten. In that case we have to
2168 make sure that the mouse-highlight is properly redrawn.
2170 W may be a menu bar pseudo-window in case we don't have X toolkit
2171 support. Such windows don't have a cursor, so don't display it
2172 here. */
2174 static void
2175 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2176 struct window *w;
2177 int cursor_on_p, mouse_face_overwritten_p;
2179 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
2181 if (!w->pseudo_window_p)
2183 BLOCK_INPUT;
2185 if (cursor_on_p)
2186 display_and_set_cursor (w, 1, output_cursor.hpos,
2187 output_cursor.vpos,
2188 output_cursor.x, output_cursor.y);
2190 if (draw_window_fringes (w, 1))
2191 x_draw_vertical_border (w);
2193 UNBLOCK_INPUT;
2196 /* If a row with mouse-face was overwritten, arrange for
2197 XTframe_up_to_date to redisplay the mouse highlight. */
2198 if (mouse_face_overwritten_p)
2200 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2201 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2202 dpyinfo->mouse_face_window = Qnil;
2205 updated_window = NULL;
2209 /* End update of frame F. This function is installed as a hook in
2210 update_end. */
2212 static void
2213 x_update_end (f)
2214 struct frame *f;
2216 /* Mouse highlight may be displayed again. */
2217 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2219 BLOCK_INPUT;
2220 #if TARGET_API_MAC_CARBON
2221 EnableScreenUpdates ();
2222 #endif
2223 XFlush (FRAME_MAC_DISPLAY (f));
2224 UNBLOCK_INPUT;
2228 /* This function is called from various places in xdisp.c whenever a
2229 complete update has been performed. The global variable
2230 updated_window is not available here. */
2232 static void
2233 XTframe_up_to_date (f)
2234 struct frame *f;
2236 if (FRAME_MAC_P (f))
2238 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2240 if (dpyinfo->mouse_face_deferred_gc
2241 || f == dpyinfo->mouse_face_mouse_frame)
2243 BLOCK_INPUT;
2244 if (dpyinfo->mouse_face_mouse_frame)
2245 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2246 dpyinfo->mouse_face_mouse_x,
2247 dpyinfo->mouse_face_mouse_y);
2248 dpyinfo->mouse_face_deferred_gc = 0;
2249 UNBLOCK_INPUT;
2255 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
2256 arrow bitmaps, or clear the fringes if no bitmaps are required
2257 before DESIRED_ROW is made current. The window being updated is
2258 found in updated_window. This function is called from
2259 update_window_line only if it is known that there are differences
2260 between bitmaps to be drawn between current row and DESIRED_ROW. */
2262 static void
2263 x_after_update_window_line (desired_row)
2264 struct glyph_row *desired_row;
2266 struct window *w = updated_window;
2267 struct frame *f;
2268 int width, height;
2270 xassert (w);
2272 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2273 desired_row->redraw_fringe_bitmaps_p = 1;
2275 /* When a window has disappeared, make sure that no rest of
2276 full-width rows stays visible in the internal border. Could
2277 check here if updated_window is the leftmost/rightmost window,
2278 but I guess it's not worth doing since vertically split windows
2279 are almost never used, internal border is rarely set, and the
2280 overhead is very small. */
2281 if (windows_or_buffers_changed
2282 && desired_row->full_width_p
2283 && (f = XFRAME (w->frame),
2284 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2285 width != 0)
2286 && (height = desired_row->visible_height,
2287 height > 0))
2289 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2291 /* Internal border is drawn below the tool bar. */
2292 if (WINDOWP (f->tool_bar_window)
2293 && w == XWINDOW (f->tool_bar_window))
2294 y -= width;
2296 BLOCK_INPUT;
2297 mac_clear_area (f, 0, y, width, height);
2298 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
2299 UNBLOCK_INPUT;
2304 /* Draw the bitmap WHICH in one of the left or right fringes of
2305 window W. ROW is the glyph row for which to display the bitmap; it
2306 determines the vertical position at which the bitmap has to be
2307 drawn. */
2309 static void
2310 x_draw_fringe_bitmap (w, row, p)
2311 struct window *w;
2312 struct glyph_row *row;
2313 struct draw_fringe_bitmap_params *p;
2315 struct frame *f = XFRAME (WINDOW_FRAME (w));
2316 Display *display = FRAME_MAC_DISPLAY (f);
2317 struct face *face = p->face;
2318 int rowY;
2319 int overlay_p = p->overlay_p;
2321 #ifdef MAC_OSX
2322 if (!overlay_p)
2324 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2326 #if 0 /* MAC_TODO: stipple */
2327 /* In case the same realized face is used for fringes and
2328 for something displayed in the text (e.g. face `region' on
2329 mono-displays, the fill style may have been changed to
2330 FillSolid in x_draw_glyph_string_background. */
2331 if (face->stipple)
2332 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2333 else
2334 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2335 #endif
2337 /* If the fringe is adjacent to the left (right) scroll bar of a
2338 leftmost (rightmost, respectively) window, then extend its
2339 background to the gap between the fringe and the bar. */
2340 if ((WINDOW_LEFTMOST_P (w)
2341 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2342 || (WINDOW_RIGHTMOST_P (w)
2343 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2345 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2347 if (sb_width > 0)
2349 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2350 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2351 * FRAME_COLUMN_WIDTH (f));
2353 if (bx < 0
2354 && (left + width == p->x
2355 || p->x + p->wd == left))
2357 /* Bitmap fills the fringe and we need background
2358 extension. */
2359 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2361 bx = p->x;
2362 nx = p->wd;
2363 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2364 row->y));
2365 ny = row->visible_height;
2368 if (bx >= 0)
2370 if (left + width == bx)
2372 bx = left + sb_width;
2373 nx += width - sb_width;
2375 else if (bx + nx == left)
2376 nx += width - sb_width;
2381 if (bx >= 0)
2383 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2384 /* The fringe background has already been filled. */
2385 overlay_p = 1;
2388 #if 0 /* MAC_TODO: stipple */
2389 if (!face->stipple)
2390 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2391 #endif
2393 #endif /* MAC_OSX */
2395 /* Must clip because of partially visible lines. */
2396 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2397 if (p->y < rowY)
2399 /* Adjust position of "bottom aligned" bitmap on partially
2400 visible last row. */
2401 int oldY = row->y;
2402 int oldVH = row->visible_height;
2403 row->visible_height = p->h;
2404 row->y -= rowY - p->y;
2405 x_clip_to_row (w, row, -1, face->gc);
2406 row->y = oldY;
2407 row->visible_height = oldVH;
2409 else
2410 x_clip_to_row (w, row, -1, face->gc);
2412 #ifndef MAC_OSX
2413 if (p->bx >= 0 && !p->overlay_p)
2415 #if 0 /* MAC_TODO: stipple */
2416 /* In case the same realized face is used for fringes and
2417 for something displayed in the text (e.g. face `region' on
2418 mono-displays, the fill style may have been changed to
2419 FillSolid in x_draw_glyph_string_background. */
2420 if (face->stipple)
2421 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2422 else
2423 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2424 #endif
2426 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
2428 #if 0 /* MAC_TODO: stipple */
2429 if (!face->stipple)
2430 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2431 #endif
2433 #endif /* !MAC_OSX */
2435 if (p->which
2436 #if USE_CG_DRAWING
2437 && p->which < max_fringe_bmp
2438 #endif
2441 XGCValues gcv;
2443 XGetGCValues (display, face->gc, GCForeground, &gcv);
2444 XSetForeground (display, face->gc,
2445 (p->cursor_p
2446 ? (p->overlay_p ? face->background
2447 : f->output_data.mac->cursor_pixel)
2448 : face->foreground));
2449 #if USE_CG_DRAWING
2450 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
2451 p->wd, p->h, p->x, p->y, overlay_p);
2452 #else
2453 mac_draw_bitmap (f, face->gc, p->x, p->y,
2454 p->wd, p->h, p->bits + p->dh, overlay_p);
2455 #endif
2456 XSetForeground (display, face->gc, gcv.foreground);
2459 mac_reset_clip_rectangles (f, face->gc);
2462 #if USE_CG_DRAWING
2463 static void
2464 mac_define_fringe_bitmap (which, bits, h, wd)
2465 int which;
2466 unsigned short *bits;
2467 int h, wd;
2469 int i;
2470 CGDataProviderRef provider;
2472 if (which >= max_fringe_bmp)
2474 i = max_fringe_bmp;
2475 max_fringe_bmp = which + 20;
2476 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2477 while (i < max_fringe_bmp)
2478 fringe_bmp[i++] = 0;
2481 for (i = 0; i < h; i++)
2482 bits[i] = ~bits[i];
2484 BLOCK_INPUT;
2486 provider = CGDataProviderCreateWithData (NULL, bits,
2487 sizeof (unsigned short) * h, NULL);
2488 if (provider)
2490 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2491 sizeof (unsigned short),
2492 provider, NULL, 0);
2493 CGDataProviderRelease (provider);
2496 UNBLOCK_INPUT;
2499 static void
2500 mac_destroy_fringe_bitmap (which)
2501 int which;
2503 if (which >= max_fringe_bmp)
2504 return;
2506 if (fringe_bmp[which])
2508 BLOCK_INPUT;
2509 CGImageRelease (fringe_bmp[which]);
2510 UNBLOCK_INPUT;
2512 fringe_bmp[which] = 0;
2514 #endif
2517 /* This is called when starting Emacs and when restarting after
2518 suspend. When starting Emacs, no window is mapped. And nothing
2519 must be done to Emacs's own window if it is suspended (though that
2520 rarely happens). */
2522 static void
2523 XTset_terminal_modes (struct terminal *t)
2527 /* This is called when exiting or suspending Emacs. Exiting will make
2528 the windows go away, and suspending requires no action. */
2530 static void
2531 XTreset_terminal_modes (struct terminal *t)
2537 /***********************************************************************
2538 Display Iterator
2539 ***********************************************************************/
2541 /* Function prototypes of this page. */
2543 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
2544 static int mac_encode_char P_ ((int, XChar2b *, struct font_info *,
2545 struct charset *, int *));
2548 static void
2549 pcm_init (pcm, count)
2550 XCharStruct *pcm;
2551 int count;
2553 bzero (pcm, sizeof (XCharStruct) * count);
2554 while (--count >= 0)
2556 pcm->descent = PCM_INVALID;
2557 pcm++;
2561 static enum pcm_status
2562 pcm_get_status (pcm)
2563 const XCharStruct *pcm;
2565 int height = pcm->ascent + pcm->descent;
2567 /* Negative height means some special status. */
2568 return height >= 0 ? PCM_VALID : height;
2571 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2572 is not contained in the font. */
2574 static INLINE XCharStruct *
2575 x_per_char_metric (font, char2b)
2576 XFontStruct *font;
2577 XChar2b *char2b;
2579 /* The result metric information. */
2580 XCharStruct *pcm = NULL;
2582 xassert (font && char2b);
2584 #if USE_ATSUI
2585 if (font->mac_style)
2587 XCharStruct **row = font->bounds.rows + char2b->byte1;
2589 if (*row == NULL)
2591 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2592 pcm_init (*row, 0x100);
2594 pcm = *row + char2b->byte2;
2595 if (pcm_get_status (pcm) != PCM_VALID)
2597 BLOCK_INPUT;
2598 mac_query_char_extents (font->mac_style,
2599 (char2b->byte1 << 8) + char2b->byte2,
2600 NULL, NULL, pcm, NULL);
2601 UNBLOCK_INPUT;
2604 else
2606 #endif
2607 if (font->bounds.per_char != NULL)
2609 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2611 /* min_char_or_byte2 specifies the linear character index
2612 corresponding to the first element of the per_char array,
2613 max_char_or_byte2 is the index of the last character. A
2614 character with non-zero CHAR2B->byte1 is not in the font.
2615 A character with byte2 less than min_char_or_byte2 or
2616 greater max_char_or_byte2 is not in the font. */
2617 if (char2b->byte1 == 0
2618 && char2b->byte2 >= font->min_char_or_byte2
2619 && char2b->byte2 <= font->max_char_or_byte2)
2620 pcm = font->bounds.per_char
2621 + (char2b->byte2 - font->min_char_or_byte2);
2623 else
2625 /* If either min_byte1 or max_byte1 are nonzero, both
2626 min_char_or_byte2 and max_char_or_byte2 are less than
2627 256, and the 2-byte character index values corresponding
2628 to the per_char array element N (counting from 0) are:
2630 byte1 = N/D + min_byte1
2631 byte2 = N\D + min_char_or_byte2
2633 where:
2635 D = max_char_or_byte2 - min_char_or_byte2 + 1
2636 / = integer division
2637 \ = integer modulus */
2638 if (char2b->byte1 >= font->min_byte1
2639 && char2b->byte1 <= font->max_byte1
2640 && char2b->byte2 >= font->min_char_or_byte2
2641 && char2b->byte2 <= font->max_char_or_byte2)
2643 pcm = (font->bounds.per_char
2644 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2645 * (char2b->byte1 - font->min_byte1))
2646 + (char2b->byte2 - font->min_char_or_byte2));
2650 else
2652 /* If the per_char pointer is null, all glyphs between the first
2653 and last character indexes inclusive have the same
2654 information, as given by both min_bounds and max_bounds. */
2655 if (char2b->byte2 >= font->min_char_or_byte2
2656 && char2b->byte2 <= font->max_char_or_byte2)
2657 pcm = &font->max_bounds;
2659 #if USE_ATSUI
2661 #endif
2663 return ((pcm == NULL
2664 || (pcm->width == 0
2665 #if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2666 && (pcm->rbearing - pcm->lbearing) == 0
2667 #endif
2669 ? NULL : pcm);
2672 /* RIF:
2675 static XCharStruct *
2676 mac_per_char_metric (font, char2b, font_type)
2677 XFontStruct *font;
2678 XChar2b *char2b;
2679 int font_type;
2681 return x_per_char_metric (font, char2b);
2684 /* RIF:
2685 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
2686 the two-byte form of C. Encoding is returned in *CHAR2B. */
2688 static int
2689 mac_encode_char (c, char2b, font_info, charset, two_byte_p)
2690 int c;
2691 XChar2b *char2b;
2692 struct font_info *font_info;
2693 struct charset *charset;
2694 int *two_byte_p;
2696 XFontStruct *font = font_info->font;
2698 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2699 This may be either a program in a special encoder language or a
2700 fixed encoding. */
2701 if (font_info->font_encoder)
2703 /* It's a program. */
2704 struct ccl_program *ccl = font_info->font_encoder;
2706 check_ccl_update (ccl);
2707 if (CHARSET_DIMENSION (charset) == 1)
2709 ccl->reg[0] = CHARSET_ID (charset);
2710 ccl->reg[1] = XCHAR2B_BYTE2 (char2b);
2711 ccl->reg[2] = -1;
2713 else
2715 ccl->reg[0] = CHARSET_ID (charset);
2716 ccl->reg[1] = XCHAR2B_BYTE1 (char2b);
2717 ccl->reg[2] = XCHAR2B_BYTE2 (char2b);
2720 ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
2722 /* We assume that MSBs are appropriately set/reset by CCL
2723 program. */
2724 if (font->max_byte1 == 0) /* 1-byte font */
2725 STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
2726 else
2727 STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
2729 else if (font_info->encoding_type)
2731 /* Fixed encoding scheme. See fontset.h for the meaning of the
2732 encoding numbers. */
2733 unsigned char enc = font_info->encoding_type;
2735 if ((enc == 1 || enc == 2)
2736 && CHARSET_DIMENSION (charset) == 2)
2737 char2b->byte1 |= 0x80;
2739 if (enc == 1 || enc == 3)
2740 char2b->byte2 |= 0x80;
2742 if (enc == 4)
2744 int code = (char2b->byte1 << 8) | char2b->byte2;
2746 JIS_TO_SJIS (code);
2747 STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
2751 if (two_byte_p)
2752 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
2754 return FONT_TYPE_UNKNOWN;
2759 /***********************************************************************
2760 Glyph display
2761 ***********************************************************************/
2765 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2766 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2767 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2768 int));
2769 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2770 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2771 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2772 static void x_draw_glyph_string P_ ((struct glyph_string *));
2773 static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2774 static void x_set_cursor_gc P_ ((struct glyph_string *));
2775 static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2776 static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2777 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2778 unsigned long *, double, int));*/
2779 static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2780 double, int, unsigned long));
2781 static void x_setup_relief_colors P_ ((struct glyph_string *));
2782 static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2783 static void x_draw_image_relief P_ ((struct glyph_string *));
2784 static void x_draw_image_foreground P_ ((struct glyph_string *));
2785 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2786 int, int, int));
2787 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2788 int, int, int, int, int, int,
2789 Rect *));
2790 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2791 int, int, int, Rect *));
2793 #if GLYPH_DEBUG
2794 static void x_check_font P_ ((struct frame *, XFontStruct *));
2795 #endif
2798 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
2799 face. */
2801 static void
2802 x_set_cursor_gc (s)
2803 struct glyph_string *s;
2805 if (s->font == FRAME_FONT (s->f)
2806 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2807 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2808 && !s->cmp)
2809 s->gc = s->f->output_data.mac->cursor_gc;
2810 else
2812 /* Cursor on non-default face: must merge. */
2813 XGCValues xgcv;
2814 unsigned long mask;
2816 xgcv.background = s->f->output_data.mac->cursor_pixel;
2817 xgcv.foreground = s->face->background;
2819 /* If the glyph would be invisible, try a different foreground. */
2820 if (xgcv.foreground == xgcv.background)
2821 xgcv.foreground = s->face->foreground;
2822 if (xgcv.foreground == xgcv.background)
2823 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2824 if (xgcv.foreground == xgcv.background)
2825 xgcv.foreground = s->face->foreground;
2827 /* Make sure the cursor is distinct from text in this face. */
2828 if (xgcv.background == s->face->background
2829 && xgcv.foreground == s->face->foreground)
2831 xgcv.background = s->face->foreground;
2832 xgcv.foreground = s->face->background;
2835 IF_DEBUG (x_check_font (s->f, s->font));
2836 xgcv.font = s->font;
2837 mask = GCForeground | GCBackground | GCFont;
2839 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2840 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2841 mask, &xgcv);
2842 else
2843 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2844 = XCreateGC (s->display, s->window, mask, &xgcv);
2846 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2851 /* Set up S->gc of glyph string S for drawing text in mouse face. */
2853 static void
2854 x_set_mouse_face_gc (s)
2855 struct glyph_string *s;
2857 int face_id;
2858 struct face *face;
2860 /* What face has to be used last for the mouse face? */
2861 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2862 face = FACE_FROM_ID (s->f, face_id);
2863 if (face == NULL)
2864 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2866 if (s->first_glyph->type == CHAR_GLYPH)
2867 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
2868 else
2869 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
2870 s->face = FACE_FROM_ID (s->f, face_id);
2871 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2873 /* If font in this face is same as S->font, use it. */
2874 if (s->font == s->face->font)
2875 s->gc = s->face->gc;
2876 else
2878 /* Otherwise construct scratch_cursor_gc with values from FACE
2879 but font FONT. */
2880 XGCValues xgcv;
2881 unsigned long mask;
2883 xgcv.background = s->face->background;
2884 xgcv.foreground = s->face->foreground;
2885 IF_DEBUG (x_check_font (s->f, s->font));
2886 xgcv.font = s->font;
2887 mask = GCForeground | GCBackground | GCFont;
2889 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2890 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2891 mask, &xgcv);
2892 else
2893 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2894 = XCreateGC (s->display, s->window, mask, &xgcv);
2896 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2899 xassert (s->gc != 0);
2903 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2904 Faces to use in the mode line have already been computed when the
2905 matrix was built, so there isn't much to do, here. */
2907 static INLINE void
2908 x_set_mode_line_face_gc (s)
2909 struct glyph_string *s;
2911 s->gc = s->face->gc;
2915 /* Set S->gc of glyph string S for drawing that glyph string. Set
2916 S->stippled_p to a non-zero value if the face of S has a stipple
2917 pattern. */
2919 static INLINE void
2920 x_set_glyph_string_gc (s)
2921 struct glyph_string *s;
2923 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2925 if (s->hl == DRAW_NORMAL_TEXT)
2927 s->gc = s->face->gc;
2928 s->stippled_p = s->face->stipple != 0;
2930 else if (s->hl == DRAW_INVERSE_VIDEO)
2932 x_set_mode_line_face_gc (s);
2933 s->stippled_p = s->face->stipple != 0;
2935 else if (s->hl == DRAW_CURSOR)
2937 x_set_cursor_gc (s);
2938 s->stippled_p = 0;
2940 else if (s->hl == DRAW_MOUSE_FACE)
2942 x_set_mouse_face_gc (s);
2943 s->stippled_p = s->face->stipple != 0;
2945 else if (s->hl == DRAW_IMAGE_RAISED
2946 || s->hl == DRAW_IMAGE_SUNKEN)
2948 s->gc = s->face->gc;
2949 s->stippled_p = s->face->stipple != 0;
2951 else
2953 s->gc = s->face->gc;
2954 s->stippled_p = s->face->stipple != 0;
2957 /* GC must have been set. */
2958 xassert (s->gc != 0);
2962 /* Set clipping for output of glyph string S. S may be part of a mode
2963 line or menu if we don't have X toolkit support. */
2965 static INLINE void
2966 x_set_glyph_string_clipping (s)
2967 struct glyph_string *s;
2969 Rect rects[MAX_CLIP_RECTS];
2970 int n;
2972 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
2973 mac_set_clip_rectangles (s->f, s->gc, rects, n);
2977 /* RIF:
2978 Compute left and right overhang of glyph string S. If S is a glyph
2979 string for a composition, assume overhangs don't exist. */
2981 static void
2982 mac_compute_glyph_string_overhangs (s)
2983 struct glyph_string *s;
2985 if (!(s->cmp == NULL
2986 && s->first_glyph->type == CHAR_GLYPH))
2987 return;
2989 if (!s->two_byte_p
2990 #if USE_ATSUI
2991 || s->font->mac_style
2992 #endif
2995 XCharStruct cs;
2997 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2998 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2999 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
3001 else
3003 Rect r;
3004 MacFontStruct *font = s->font;
3006 #if USE_CG_DRAWING
3007 mac_prepare_for_quickdraw (s->f);
3008 #endif
3009 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
3011 TextFont (font->mac_fontnum);
3012 TextSize (font->mac_fontsize);
3013 TextFace (font->mac_fontface);
3015 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
3017 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
3018 s->left_overhang = r.left < 0 ? -r.left : 0;
3023 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
3025 static INLINE void
3026 x_clear_glyph_string_rect (s, x, y, w, h)
3027 struct glyph_string *s;
3028 int x, y, w, h;
3030 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
3034 /* Draw the background of glyph_string S. If S->background_filled_p
3035 is non-zero don't draw it. FORCE_P non-zero means draw the
3036 background even if it wouldn't be drawn normally. This is used
3037 when a string preceding S draws into the background of S, or S
3038 contains the first component of a composition. */
3040 static void
3041 x_draw_glyph_string_background (s, force_p)
3042 struct glyph_string *s;
3043 int force_p;
3045 /* Nothing to do if background has already been drawn or if it
3046 shouldn't be drawn in the first place. */
3047 if (!s->background_filled_p)
3049 int box_line_width = max (s->face->box_line_width, 0);
3051 #if 0 /* MAC_TODO: stipple */
3052 if (s->stippled_p)
3054 /* Fill background with a stipple pattern. */
3055 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3056 XFillRectangle (s->display, s->window, s->gc, s->x,
3057 s->y + box_line_width,
3058 s->background_width,
3059 s->height - 2 * box_line_width);
3060 XSetFillStyle (s->display, s->gc, FillSolid);
3061 s->background_filled_p = 1;
3063 else
3064 #endif
3065 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3066 || s->font_not_found_p
3067 || s->extends_to_end_of_line_p
3068 || force_p)
3070 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
3071 s->background_width,
3072 s->height - 2 * box_line_width);
3073 s->background_filled_p = 1;
3079 /* Draw the foreground of glyph string S. */
3081 static void
3082 x_draw_glyph_string_foreground (s)
3083 struct glyph_string *s;
3085 int i, x, bg_width;
3087 /* If first glyph of S has a left box line, start drawing the text
3088 of S to the right of that box line. */
3089 if (s->face->box != FACE_NO_BOX
3090 && s->first_glyph->left_box_line_p)
3091 x = s->x + eabs (s->face->box_line_width);
3092 else
3093 x = s->x;
3095 /* Draw characters of S as rectangles if S's font could not be
3096 loaded. */
3097 if (s->font_not_found_p)
3099 for (i = 0; i < s->nchars; ++i)
3101 struct glyph *g = s->first_glyph + i;
3102 mac_draw_rectangle (s->f, s->gc, x, s->y,
3103 g->pixel_width - 1, s->height - 1);
3104 x += g->pixel_width;
3107 else
3109 char *char1b = (char *) s->char2b;
3110 int boff = s->font_info->baseline_offset;
3112 if (s->font_info->vertical_centering)
3113 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3115 /* If we can use 8-bit functions, condense S->char2b. */
3116 if (!s->two_byte_p
3117 #if USE_ATSUI
3118 && GC_FONT (s->gc)->mac_style == NULL
3119 #endif
3121 for (i = 0; i < s->nchars; ++i)
3122 char1b[i] = s->char2b[i].byte2;
3124 /* Draw text with XDrawString if background has already been
3125 filled. Otherwise, use XDrawImageString. (Note that
3126 XDrawImageString is usually faster than XDrawString.) Always
3127 use XDrawImageString when drawing the cursor so that there is
3128 no chance that characters under a box cursor are invisible. */
3129 if (s->for_overlaps
3130 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3131 bg_width = 0; /* Corresponds to XDrawString. */
3132 else
3133 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3135 if (s->two_byte_p
3136 #if USE_ATSUI
3137 || GC_FONT (s->gc)->mac_style
3138 #endif
3140 #if USE_CG_TEXT_DRAWING
3141 if (!s->two_byte_p
3142 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
3143 s->char2b, s->nchars, bg_width,
3144 s->face->overstrike))
3146 else
3147 #endif
3148 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
3149 s->char2b, s->nchars, bg_width,
3150 s->face->overstrike);
3151 else
3152 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
3153 char1b, s->nchars, bg_width,
3154 s->face->overstrike);
3158 /* Draw the foreground of composite glyph string S. */
3160 static void
3161 x_draw_composite_glyph_string_foreground (s)
3162 struct glyph_string *s;
3164 int i, x;
3166 /* If first glyph of S has a left box line, start drawing the text
3167 of S to the right of that box line. */
3168 if (s->face->box != FACE_NO_BOX
3169 && s->first_glyph->left_box_line_p)
3170 x = s->x + eabs (s->face->box_line_width);
3171 else
3172 x = s->x;
3174 /* S is a glyph string for a composition. S->gidx is the index of
3175 the first character drawn for glyphs of this composition.
3176 S->gidx == 0 means we are drawing the very first character of
3177 this composition. */
3179 /* Draw a rectangle for the composition if the font for the very
3180 first character of the composition could not be loaded. */
3181 if (s->font_not_found_p)
3183 if (s->gidx == 0)
3184 mac_draw_rectangle (s->f, s->gc, x, s->y,
3185 s->width - 1, s->height - 1);
3187 else
3189 for (i = 0; i < s->nchars; i++, ++s->gidx)
3190 if (mac_per_char_metric (GC_FONT (s->gc), s->char2b + i, 0) == NULL)
3191 /* This is a nonexistent or zero-width glyph such as a
3192 combining diacritic. Draw a rectangle. */
3193 mac_draw_rectangle (s->f, s->gc,
3194 x + s->cmp->offsets[s->gidx * 2], s->y,
3195 FONT_WIDTH (GC_FONT (s->gc)) - 1, s->height - 1);
3196 else
3197 mac_draw_image_string_16 (s->f, s->gc,
3198 x + s->cmp->offsets[s->gidx * 2],
3199 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3200 s->char2b + i, 1, 0, s->face->overstrike);
3205 #ifdef USE_X_TOOLKIT
3207 static struct frame *x_frame_of_widget P_ ((Widget));
3210 /* Return the frame on which widget WIDGET is used.. Abort if frame
3211 cannot be determined. */
3213 static struct frame *
3214 x_frame_of_widget (widget)
3215 Widget widget;
3217 struct x_display_info *dpyinfo;
3218 Lisp_Object tail;
3219 struct frame *f;
3221 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3223 /* Find the top-level shell of the widget. Note that this function
3224 can be called when the widget is not yet realized, so XtWindow
3225 (widget) == 0. That's the reason we can't simply use
3226 x_any_window_to_frame. */
3227 while (!XtIsTopLevelShell (widget))
3228 widget = XtParent (widget);
3230 /* Look for a frame with that top-level widget. Allocate the color
3231 on that frame to get the right gamma correction value. */
3232 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
3233 if (FRAMEP (XCAR (tail))
3234 && (f = XFRAME (XCAR (tail)),
3235 (f->output_data.nothing != 1
3236 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3237 && f->output_data.x->widget == widget)
3238 return f;
3240 abort ();
3244 /* Allocate the color COLOR->pixel on the screen and display of
3245 widget WIDGET in colormap CMAP. If an exact match cannot be
3246 allocated, try the nearest color available. Value is non-zero
3247 if successful. This is called from lwlib. */
3250 x_alloc_nearest_color_for_widget (widget, cmap, color)
3251 Widget widget;
3252 Colormap cmap;
3253 XColor *color;
3255 struct frame *f = x_frame_of_widget (widget);
3256 return x_alloc_nearest_color (f, cmap, color);
3260 #endif /* USE_X_TOOLKIT */
3262 #if 0 /* MAC_TODO */
3264 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3265 CMAP. If an exact match can't be allocated, try the nearest color
3266 available. Value is non-zero if successful. Set *COLOR to the
3267 color allocated. */
3270 x_alloc_nearest_color (f, cmap, color)
3271 struct frame *f;
3272 Colormap cmap;
3273 XColor *color;
3275 Display *display = FRAME_X_DISPLAY (f);
3276 Screen *screen = FRAME_X_SCREEN (f);
3277 int rc;
3279 gamma_correct (f, color);
3280 rc = XAllocColor (display, cmap, color);
3281 if (rc == 0)
3283 /* If we got to this point, the colormap is full, so we're going
3284 to try to get the next closest color. The algorithm used is
3285 a least-squares matching, which is what X uses for closest
3286 color matching with StaticColor visuals. */
3287 int nearest, i;
3288 unsigned long nearest_delta = ~0;
3289 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3290 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3292 for (i = 0; i < ncells; ++i)
3293 cells[i].pixel = i;
3294 XQueryColors (display, cmap, cells, ncells);
3296 for (nearest = i = 0; i < ncells; ++i)
3298 long dred = (color->red >> 8) - (cells[i].red >> 8);
3299 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3300 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3301 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3303 if (delta < nearest_delta)
3305 nearest = i;
3306 nearest_delta = delta;
3310 color->red = cells[nearest].red;
3311 color->green = cells[nearest].green;
3312 color->blue = cells[nearest].blue;
3313 rc = XAllocColor (display, cmap, color);
3316 #ifdef DEBUG_X_COLORS
3317 if (rc)
3318 register_color (color->pixel);
3319 #endif /* DEBUG_X_COLORS */
3321 return rc;
3325 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3326 It's necessary to do this instead of just using PIXEL directly to
3327 get color reference counts right. */
3329 unsigned long
3330 x_copy_color (f, pixel)
3331 struct frame *f;
3332 unsigned long pixel;
3334 XColor color;
3336 color.pixel = pixel;
3337 BLOCK_INPUT;
3338 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3339 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3340 UNBLOCK_INPUT;
3341 #ifdef DEBUG_X_COLORS
3342 register_color (pixel);
3343 #endif
3344 return color.pixel;
3348 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3349 It's necessary to do this instead of just using PIXEL directly to
3350 get color reference counts right. */
3352 unsigned long
3353 x_copy_dpy_color (dpy, cmap, pixel)
3354 Display *dpy;
3355 Colormap cmap;
3356 unsigned long pixel;
3358 XColor color;
3360 color.pixel = pixel;
3361 BLOCK_INPUT;
3362 XQueryColor (dpy, cmap, &color);
3363 XAllocColor (dpy, cmap, &color);
3364 UNBLOCK_INPUT;
3365 #ifdef DEBUG_X_COLORS
3366 register_color (pixel);
3367 #endif
3368 return color.pixel;
3371 #endif /* MAC_TODO */
3374 /* Brightness beyond which a color won't have its highlight brightness
3375 boosted.
3377 Nominally, highlight colors for `3d' faces are calculated by
3378 brightening an object's color by a constant scale factor, but this
3379 doesn't yield good results for dark colors, so for colors who's
3380 brightness is less than this value (on a scale of 0-255) have to
3381 use an additional additive factor.
3383 The value here is set so that the default menu-bar/mode-line color
3384 (grey75) will not have its highlights changed at all. */
3385 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3388 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
3389 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3390 If this produces the same color as COLOR, try a color where all RGB
3391 values have DELTA added. Return the allocated color in *COLOR.
3392 DISPLAY is the X display, CMAP is the colormap to operate on.
3393 Value is non-zero if successful. */
3395 static int
3396 mac_alloc_lighter_color (f, color, factor, delta)
3397 struct frame *f;
3398 unsigned long *color;
3399 double factor;
3400 int delta;
3402 unsigned long new;
3403 long bright;
3405 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3406 delta /= 256;
3408 /* Change RGB values by specified FACTOR. Avoid overflow! */
3409 xassert (factor >= 0);
3410 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3411 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3412 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3414 /* Calculate brightness of COLOR. */
3415 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3416 + BLUE_FROM_ULONG (*color)) / 6;
3418 /* We only boost colors that are darker than
3419 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3420 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3421 /* Make an additive adjustment to NEW, because it's dark enough so
3422 that scaling by FACTOR alone isn't enough. */
3424 /* How far below the limit this color is (0 - 1, 1 being darker). */
3425 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3426 /* The additive adjustment. */
3427 int min_delta = delta * dimness * factor / 2;
3429 if (factor < 1)
3430 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3431 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3432 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3433 else
3434 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3435 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3436 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3439 if (new == *color)
3440 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3441 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3442 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3444 /* MAC_TODO: Map to palette and retry with delta if same? */
3445 /* MAC_TODO: Free colors (if using palette)? */
3447 if (new == *color)
3448 return 0;
3450 *color = new;
3452 return 1;
3456 /* Set up the foreground color for drawing relief lines of glyph
3457 string S. RELIEF is a pointer to a struct relief containing the GC
3458 with which lines will be drawn. Use a color that is FACTOR or
3459 DELTA lighter or darker than the relief's background which is found
3460 in S->f->output_data.x->relief_background. If such a color cannot
3461 be allocated, use DEFAULT_PIXEL, instead. */
3463 static void
3464 x_setup_relief_color (f, relief, factor, delta, default_pixel)
3465 struct frame *f;
3466 struct relief *relief;
3467 double factor;
3468 int delta;
3469 unsigned long default_pixel;
3471 XGCValues xgcv;
3472 struct mac_output *di = f->output_data.mac;
3473 unsigned long mask = GCForeground;
3474 unsigned long pixel;
3475 unsigned long background = di->relief_background;
3476 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3478 /* MAC_TODO: Free colors (if using palette)? */
3480 /* Allocate new color. */
3481 xgcv.foreground = default_pixel;
3482 pixel = background;
3483 if (dpyinfo->n_planes != 1
3484 && mac_alloc_lighter_color (f, &pixel, factor, delta))
3486 relief->allocated_p = 1;
3487 xgcv.foreground = relief->pixel = pixel;
3490 if (relief->gc == 0)
3492 #if 0 /* MAC_TODO: stipple */
3493 xgcv.stipple = dpyinfo->gray;
3494 mask |= GCStipple;
3495 #endif
3496 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3498 else
3499 XChangeGC (NULL, relief->gc, mask, &xgcv);
3503 /* Set up colors for the relief lines around glyph string S. */
3505 static void
3506 x_setup_relief_colors (s)
3507 struct glyph_string *s;
3509 struct mac_output *di = s->f->output_data.mac;
3510 unsigned long color;
3512 if (s->face->use_box_color_for_shadows_p)
3513 color = s->face->box_color;
3514 else if (s->first_glyph->type == IMAGE_GLYPH
3515 && s->img->pixmap
3516 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3517 color = IMAGE_BACKGROUND (s->img, s->f, 0);
3518 else
3520 XGCValues xgcv;
3522 /* Get the background color of the face. */
3523 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3524 color = xgcv.background;
3527 if (di->white_relief.gc == 0
3528 || color != di->relief_background)
3530 di->relief_background = color;
3531 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3532 WHITE_PIX_DEFAULT (s->f));
3533 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3534 BLACK_PIX_DEFAULT (s->f));
3539 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
3540 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3541 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3542 relief. LEFT_P non-zero means draw a relief on the left side of
3543 the rectangle. RIGHT_P non-zero means draw a relief on the right
3544 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3545 when drawing. */
3547 static void
3548 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3549 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
3550 struct frame *f;
3551 int left_x, top_y, right_x, bottom_y, width;
3552 int top_p, bot_p, left_p, right_p, raised_p;
3553 Rect *clip_rect;
3555 Display *dpy = FRAME_MAC_DISPLAY (f);
3556 int i;
3557 GC gc;
3559 if (raised_p)
3560 gc = f->output_data.mac->white_relief.gc;
3561 else
3562 gc = f->output_data.mac->black_relief.gc;
3563 mac_set_clip_rectangles (f, gc, clip_rect, 1);
3565 /* Top. */
3566 if (top_p)
3567 for (i = 0; i < width; ++i)
3568 mac_draw_line (f, gc,
3569 left_x + i * left_p, top_y + i,
3570 right_x + 1 - i * right_p, top_y + i);
3572 /* Left. */
3573 if (left_p)
3574 for (i = 0; i < width; ++i)
3575 mac_draw_line (f, gc,
3576 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
3578 mac_reset_clip_rectangles (f, gc);
3579 if (raised_p)
3580 gc = f->output_data.mac->black_relief.gc;
3581 else
3582 gc = f->output_data.mac->white_relief.gc;
3583 mac_set_clip_rectangles (f, gc, clip_rect, 1);
3585 /* Bottom. */
3586 if (bot_p)
3587 for (i = 0; i < width; ++i)
3588 mac_draw_line (f, gc,
3589 left_x + i * left_p, bottom_y - i,
3590 right_x + 1 - i * right_p, bottom_y - i);
3592 /* Right. */
3593 if (right_p)
3594 for (i = 0; i < width; ++i)
3595 mac_draw_line (f, gc,
3596 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3598 mac_reset_clip_rectangles (f, gc);
3602 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3603 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3604 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3605 left side of the rectangle. RIGHT_P non-zero means draw a line
3606 on the right side of the rectangle. CLIP_RECT is the clipping
3607 rectangle to use when drawing. */
3609 static void
3610 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3611 left_p, right_p, clip_rect)
3612 struct glyph_string *s;
3613 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
3614 Rect *clip_rect;
3616 XGCValues xgcv;
3618 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3619 XSetForeground (s->display, s->gc, s->face->box_color);
3620 mac_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
3622 /* Top. */
3623 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3624 right_x - left_x + 1, width);
3626 /* Left. */
3627 if (left_p)
3628 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3629 width, bottom_y - top_y + 1);
3631 /* Bottom. */
3632 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3633 right_x - left_x + 1, width);
3635 /* Right. */
3636 if (right_p)
3637 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3638 top_y, width, bottom_y - top_y + 1);
3640 XSetForeground (s->display, s->gc, xgcv.foreground);
3641 mac_reset_clip_rectangles (s->f, s->gc);
3645 /* Draw a box around glyph string S. */
3647 static void
3648 x_draw_glyph_string_box (s)
3649 struct glyph_string *s;
3651 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3652 int left_p, right_p;
3653 struct glyph *last_glyph;
3654 Rect clip_rect;
3656 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3657 ? WINDOW_RIGHT_EDGE_X (s->w)
3658 : window_box_right (s->w, s->area));
3660 /* The glyph that may have a right box line. */
3661 last_glyph = (s->cmp || s->img
3662 ? s->first_glyph
3663 : s->first_glyph + s->nchars - 1);
3665 width = eabs (s->face->box_line_width);
3666 raised_p = s->face->box == FACE_RAISED_BOX;
3667 left_x = s->x;
3668 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3669 ? last_x - 1
3670 : min (last_x, s->x + s->background_width) - 1);
3671 top_y = s->y;
3672 bottom_y = top_y + s->height - 1;
3674 left_p = (s->first_glyph->left_box_line_p
3675 || (s->hl == DRAW_MOUSE_FACE
3676 && (s->prev == NULL
3677 || s->prev->hl != s->hl)));
3678 right_p = (last_glyph->right_box_line_p
3679 || (s->hl == DRAW_MOUSE_FACE
3680 && (s->next == NULL
3681 || s->next->hl != s->hl)));
3683 get_glyph_string_clip_rect (s, &clip_rect);
3685 if (s->face->box == FACE_SIMPLE_BOX)
3686 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3687 left_p, right_p, &clip_rect);
3688 else
3690 x_setup_relief_colors (s);
3691 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3692 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
3697 /* Draw foreground of image glyph string S. */
3699 static void
3700 x_draw_image_foreground (s)
3701 struct glyph_string *s;
3703 int x = s->x;
3704 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3706 /* If first glyph of S has a left box line, start drawing it to the
3707 right of that line. */
3708 if (s->face->box != FACE_NO_BOX
3709 && s->first_glyph->left_box_line_p
3710 && s->slice.x == 0)
3711 x += eabs (s->face->box_line_width);
3713 /* If there is a margin around the image, adjust x- and y-position
3714 by that margin. */
3715 if (s->slice.x == 0)
3716 x += s->img->hmargin;
3717 if (s->slice.y == 0)
3718 y += s->img->vmargin;
3720 if (s->img->pixmap)
3722 x_set_glyph_string_clipping (s);
3724 #if USE_CG_DRAWING
3725 mac_draw_cg_image (s->img->data.ptr_val,
3726 s->f, s->gc, s->slice.x, s->slice.y,
3727 s->slice.width, s->slice.height, x, y, 1);
3728 #endif
3729 if (s->img->mask)
3730 #if !USE_CG_DRAWING
3731 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3732 s->f, s->gc, s->slice.x, s->slice.y,
3733 s->slice.width, s->slice.height, x, y);
3734 #else
3736 #endif
3737 else
3739 #if !USE_CG_DRAWING
3740 mac_copy_area (s->img->pixmap,
3741 s->f, s->gc, s->slice.x, s->slice.y,
3742 s->slice.width, s->slice.height, x, y);
3743 #endif
3745 /* When the image has a mask, we can expect that at
3746 least part of a mouse highlight or a block cursor will
3747 be visible. If the image doesn't have a mask, make
3748 a block cursor visible by drawing a rectangle around
3749 the image. I believe it's looking better if we do
3750 nothing here for mouse-face. */
3751 if (s->hl == DRAW_CURSOR)
3753 int r = s->img->relief;
3754 if (r < 0) r = -r;
3755 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
3756 s->slice.width + r*2 - 1,
3757 s->slice.height + r*2 - 1);
3761 else
3762 /* Draw a rectangle if image could not be loaded. */
3763 mac_draw_rectangle (s->f, s->gc, x, y,
3764 s->slice.width - 1, s->slice.height - 1);
3768 /* Draw a relief around the image glyph string S. */
3770 static void
3771 x_draw_image_relief (s)
3772 struct glyph_string *s;
3774 int x0, y0, x1, y1, thick, raised_p;
3775 Rect r;
3776 int x = s->x;
3777 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3779 /* If first glyph of S has a left box line, start drawing it to the
3780 right of that line. */
3781 if (s->face->box != FACE_NO_BOX
3782 && s->first_glyph->left_box_line_p
3783 && s->slice.x == 0)
3784 x += eabs (s->face->box_line_width);
3786 /* If there is a margin around the image, adjust x- and y-position
3787 by that margin. */
3788 if (s->slice.x == 0)
3789 x += s->img->hmargin;
3790 if (s->slice.y == 0)
3791 y += s->img->vmargin;
3793 if (s->hl == DRAW_IMAGE_SUNKEN
3794 || s->hl == DRAW_IMAGE_RAISED)
3796 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3797 raised_p = s->hl == DRAW_IMAGE_RAISED;
3799 else
3801 thick = eabs (s->img->relief);
3802 raised_p = s->img->relief > 0;
3805 x0 = x - thick;
3806 y0 = y - thick;
3807 x1 = x + s->slice.width + thick - 1;
3808 y1 = y + s->slice.height + thick - 1;
3810 x_setup_relief_colors (s);
3811 get_glyph_string_clip_rect (s, &r);
3812 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3813 s->slice.y == 0,
3814 s->slice.y + s->slice.height == s->img->height,
3815 s->slice.x == 0,
3816 s->slice.x + s->slice.width == s->img->width,
3817 &r);
3821 /* Draw part of the background of glyph string S. X, Y, W, and H
3822 give the rectangle to draw. */
3824 static void
3825 x_draw_glyph_string_bg_rect (s, x, y, w, h)
3826 struct glyph_string *s;
3827 int x, y, w, h;
3829 #if 0 /* MAC_TODO: stipple */
3830 if (s->stippled_p)
3832 /* Fill background with a stipple pattern. */
3833 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3834 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3835 XSetFillStyle (s->display, s->gc, FillSolid);
3837 else
3838 #endif /* MAC_TODO */
3839 x_clear_glyph_string_rect (s, x, y, w, h);
3843 /* Draw image glyph string S.
3845 s->y
3846 s->x +-------------------------
3847 | s->face->box
3849 | +-------------------------
3850 | | s->img->margin
3852 | | +-------------------
3853 | | | the image
3857 static void
3858 x_draw_image_glyph_string (s)
3859 struct glyph_string *s;
3861 int x, y;
3862 int box_line_hwidth = eabs (s->face->box_line_width);
3863 int box_line_vwidth = max (s->face->box_line_width, 0);
3864 int height;
3866 height = s->height - 2 * box_line_vwidth;
3869 /* Fill background with face under the image. Do it only if row is
3870 taller than image or if image has a clip mask to reduce
3871 flickering. */
3872 s->stippled_p = s->face->stipple != 0;
3873 if (height > s->slice.height
3874 || s->img->hmargin
3875 || s->img->vmargin
3876 || s->img->mask
3877 || s->img->pixmap == 0
3878 || s->width != s->background_width)
3880 x = s->x;
3881 if (s->first_glyph->left_box_line_p
3882 && s->slice.x == 0)
3883 x += box_line_hwidth;
3885 y = s->y;
3886 if (s->slice.y == 0)
3887 y += box_line_vwidth;
3889 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3891 s->background_filled_p = 1;
3894 /* Draw the foreground. */
3895 x_draw_image_foreground (s);
3897 /* If we must draw a relief around the image, do it. */
3898 if (s->img->relief
3899 || s->hl == DRAW_IMAGE_RAISED
3900 || s->hl == DRAW_IMAGE_SUNKEN)
3901 x_draw_image_relief (s);
3905 /* Draw stretch glyph string S. */
3907 static void
3908 x_draw_stretch_glyph_string (s)
3909 struct glyph_string *s;
3911 xassert (s->first_glyph->type == STRETCH_GLYPH);
3913 if (s->hl == DRAW_CURSOR
3914 && !x_stretch_cursor_p)
3916 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3917 as wide as the stretch glyph. */
3918 int width, background_width = s->background_width;
3919 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3921 if (x < left_x)
3923 background_width -= left_x - x;
3924 x = left_x;
3926 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3928 /* Draw cursor. */
3929 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3931 /* Clear rest using the GC of the original non-cursor face. */
3932 if (width < background_width)
3934 int y = s->y;
3935 int w = background_width - width, h = s->height;
3936 Rect r;
3937 GC gc;
3939 x += width;
3940 if (s->row->mouse_face_p
3941 && cursor_in_mouse_face_p (s->w))
3943 x_set_mouse_face_gc (s);
3944 gc = s->gc;
3946 else
3947 gc = s->face->gc;
3949 get_glyph_string_clip_rect (s, &r);
3950 mac_set_clip_rectangles (s->f, gc, &r, 1);
3952 #if 0 /* MAC_TODO: stipple */
3953 if (s->face->stipple)
3955 /* Fill background with a stipple pattern. */
3956 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3957 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3958 XSetFillStyle (s->display, gc, FillSolid);
3960 else
3961 #endif /* MAC_TODO */
3962 mac_erase_rectangle (s->f, gc, x, y, w, h);
3965 else if (!s->background_filled_p)
3967 int background_width = s->background_width;
3968 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3970 /* Don't draw into left margin, fringe or scrollbar area
3971 except for header line and mode line. */
3972 if (x < left_x && !s->row->mode_line_p)
3974 background_width -= left_x - x;
3975 x = left_x;
3977 if (background_width > 0)
3978 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3981 s->background_filled_p = 1;
3985 /* Draw glyph string S. */
3987 static void
3988 x_draw_glyph_string (s)
3989 struct glyph_string *s;
3991 int relief_drawn_p = 0;
3993 /* If S draws into the background of its successor that does not
3994 draw a cursor, draw the background of the successor first so that
3995 S can draw into it. This makes S->next use XDrawString instead
3996 of XDrawImageString. */
3997 if (s->next && s->right_overhang && !s->for_overlaps
3998 && s->next->hl != DRAW_CURSOR)
4000 xassert (s->next->img == NULL);
4001 x_set_glyph_string_gc (s->next);
4002 x_set_glyph_string_clipping (s->next);
4003 x_draw_glyph_string_background (s->next, 1);
4006 /* Set up S->gc, set clipping and draw S. */
4007 x_set_glyph_string_gc (s);
4009 /* Draw relief (if any) in advance for char/composition so that the
4010 glyph string can be drawn over it. */
4011 if (!s->for_overlaps
4012 && s->face->box != FACE_NO_BOX
4013 && (s->first_glyph->type == CHAR_GLYPH
4014 || s->first_glyph->type == COMPOSITE_GLYPH))
4017 x_set_glyph_string_clipping (s);
4018 x_draw_glyph_string_background (s, 1);
4019 x_draw_glyph_string_box (s);
4020 x_set_glyph_string_clipping (s);
4021 relief_drawn_p = 1;
4023 else
4024 x_set_glyph_string_clipping (s);
4026 switch (s->first_glyph->type)
4028 case IMAGE_GLYPH:
4029 x_draw_image_glyph_string (s);
4030 break;
4032 case STRETCH_GLYPH:
4033 x_draw_stretch_glyph_string (s);
4034 break;
4036 case CHAR_GLYPH:
4037 if (s->for_overlaps)
4038 s->background_filled_p = 1;
4039 else
4040 x_draw_glyph_string_background (s, 0);
4041 x_draw_glyph_string_foreground (s);
4042 break;
4044 case COMPOSITE_GLYPH:
4045 if (s->for_overlaps || s->gidx > 0)
4046 s->background_filled_p = 1;
4047 else
4048 x_draw_glyph_string_background (s, 1);
4049 x_draw_composite_glyph_string_foreground (s);
4050 break;
4052 default:
4053 abort ();
4056 if (!s->for_overlaps)
4058 /* Draw underline. */
4059 if (s->face->underline_p)
4061 unsigned long tem, h;
4062 int y;
4064 #if 0
4065 /* Get the underline thickness. Default is 1 pixel. */
4066 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4067 #endif
4068 h = 1;
4070 y = s->y + s->height - h;
4071 if (!x_underline_at_descent_line)
4073 /* Get the underline position. This is the recommended
4074 vertical offset in pixels from the baseline to the top of
4075 the underline. This is a signed value according to the
4076 specs, and its default is
4078 ROUND ((maximum descent) / 2), with
4079 ROUND(x) = floor (x + 0.5) */
4081 #if 0
4082 if (x_use_underline_position_properties
4083 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4084 y = s->ybase + (long) tem;
4085 else
4086 #endif
4087 if (s->face->font)
4088 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4091 if (s->face->underline_defaulted_p)
4092 mac_fill_rectangle (s->f, s->gc, s->x, y,
4093 s->background_width, h);
4094 else
4096 XGCValues xgcv;
4097 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4098 XSetForeground (s->display, s->gc, s->face->underline_color);
4099 mac_fill_rectangle (s->f, s->gc, s->x, y,
4100 s->background_width, h);
4101 XSetForeground (s->display, s->gc, xgcv.foreground);
4105 /* Draw overline. */
4106 if (s->face->overline_p)
4108 unsigned long dy = 0, h = 1;
4110 if (s->face->overline_color_defaulted_p)
4111 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4112 s->background_width, h);
4113 else
4115 XGCValues xgcv;
4116 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4117 XSetForeground (s->display, s->gc, s->face->overline_color);
4118 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4119 s->background_width, h);
4120 XSetForeground (s->display, s->gc, xgcv.foreground);
4124 /* Draw strike-through. */
4125 if (s->face->strike_through_p)
4127 unsigned long h = 1;
4128 unsigned long dy = (s->height - h) / 2;
4130 if (s->face->strike_through_color_defaulted_p)
4131 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4132 s->width, h);
4133 else
4135 XGCValues xgcv;
4136 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4137 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4138 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4139 s->width, h);
4140 XSetForeground (s->display, s->gc, xgcv.foreground);
4144 /* Draw relief if not yet drawn. */
4145 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
4146 x_draw_glyph_string_box (s);
4149 /* Reset clipping. */
4150 mac_reset_clip_rectangles (s->f, s->gc);
4153 /* Shift display to make room for inserted glyphs. */
4155 void
4156 mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4157 struct frame *f;
4158 int x, y, width, height, shift_by;
4160 mac_scroll_area (f, f->output_data.mac->normal_gc,
4161 x, y, width, height,
4162 x + shift_by, y);
4165 /* Delete N glyphs at the nominal cursor position. Not implemented
4166 for X frames. */
4168 static void
4169 x_delete_glyphs (n)
4170 register int n;
4172 abort ();
4176 /* Clear entire frame. If updating_frame is non-null, clear that
4177 frame. Otherwise clear the selected frame. */
4179 static void
4180 x_clear_frame (struct frame *f)
4182 /* Clearing the frame will erase any cursor, so mark them all as no
4183 longer visible. */
4184 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4185 output_cursor.hpos = output_cursor.vpos = 0;
4186 output_cursor.x = -1;
4188 /* We don't set the output cursor here because there will always
4189 follow an explicit cursor_to. */
4190 BLOCK_INPUT;
4191 mac_clear_window (f);
4193 /* We have to clear the scroll bars, too. If we have changed
4194 colors or something like that, then they should be notified. */
4195 x_scroll_bar_clear (f);
4197 XFlush (FRAME_MAC_DISPLAY (f));
4198 UNBLOCK_INPUT;
4203 /* Invert the middle quarter of the frame for .15 sec. */
4205 /* We use the select system call to do the waiting, so we have to make
4206 sure it's available. If it isn't, we just won't do visual bells. */
4208 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4211 /* Subtract the `struct timeval' values X and Y, storing the result in
4212 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4214 static int
4215 timeval_subtract (result, x, y)
4216 struct timeval *result, x, y;
4218 /* Perform the carry for the later subtraction by updating y. This
4219 is safer because on some systems the tv_sec member is unsigned. */
4220 if (x.tv_usec < y.tv_usec)
4222 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4223 y.tv_usec -= 1000000 * nsec;
4224 y.tv_sec += nsec;
4227 if (x.tv_usec - y.tv_usec > 1000000)
4229 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4230 y.tv_usec += 1000000 * nsec;
4231 y.tv_sec -= nsec;
4234 /* Compute the time remaining to wait. tv_usec is certainly
4235 positive. */
4236 result->tv_sec = x.tv_sec - y.tv_sec;
4237 result->tv_usec = x.tv_usec - y.tv_usec;
4239 /* Return indication of whether the result should be considered
4240 negative. */
4241 return x.tv_sec < y.tv_sec;
4244 void
4245 XTflash (f)
4246 struct frame *f;
4248 /* Get the height not including a menu bar widget. */
4249 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4250 /* Height of each line to flash. */
4251 int flash_height = FRAME_LINE_HEIGHT (f);
4252 /* These will be the left and right margins of the rectangles. */
4253 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4254 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4256 int width;
4258 /* Don't flash the area between a scroll bar and the frame
4259 edge it is next to. */
4260 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4262 case vertical_scroll_bar_left:
4263 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4264 break;
4266 case vertical_scroll_bar_right:
4267 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4268 break;
4270 default:
4271 break;
4274 width = flash_right - flash_left;
4276 BLOCK_INPUT;
4278 /* If window is tall, flash top and bottom line. */
4279 if (height > 3 * FRAME_LINE_HEIGHT (f))
4281 mac_invert_rectangle (f, flash_left,
4282 (FRAME_INTERNAL_BORDER_WIDTH (f)
4283 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4284 width, flash_height);
4285 mac_invert_rectangle (f, flash_left,
4286 (height - flash_height
4287 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4288 width, flash_height);
4290 else
4291 /* If it is short, flash it all. */
4292 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4293 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4295 x_flush (f);
4298 struct timeval wakeup;
4300 EMACS_GET_TIME (wakeup);
4302 /* Compute time to wait until, propagating carry from usecs. */
4303 wakeup.tv_usec += 150000;
4304 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4305 wakeup.tv_usec %= 1000000;
4307 /* Keep waiting until past the time wakeup or any input gets
4308 available. */
4309 while (! detect_input_pending ())
4311 struct timeval current;
4312 struct timeval timeout;
4314 EMACS_GET_TIME (current);
4316 /* Break if result would be negative. */
4317 if (timeval_subtract (&current, wakeup, current))
4318 break;
4320 /* How long `select' should wait. */
4321 timeout.tv_sec = 0;
4322 timeout.tv_usec = 10000;
4324 /* Try to wait that long--but we might wake up sooner. */
4325 select (0, NULL, NULL, NULL, &timeout);
4329 /* If window is tall, flash top and bottom line. */
4330 if (height > 3 * FRAME_LINE_HEIGHT (f))
4332 mac_invert_rectangle (f, flash_left,
4333 (FRAME_INTERNAL_BORDER_WIDTH (f)
4334 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4335 width, flash_height);
4336 mac_invert_rectangle (f, flash_left,
4337 (height - flash_height
4338 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4339 width, flash_height);
4341 else
4342 /* If it is short, flash it all. */
4343 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4344 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4346 x_flush (f);
4348 UNBLOCK_INPUT;
4351 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4354 /* Make audible bell. */
4356 void
4357 XTring_bell ()
4359 struct frame *f = SELECTED_FRAME ();
4361 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4362 if (visible_bell)
4363 XTflash (f);
4364 else
4365 #endif
4367 BLOCK_INPUT;
4368 SysBeep (1);
4369 XFlush (FRAME_MAC_DISPLAY (f));
4370 UNBLOCK_INPUT;
4375 /* Specify how many text lines, from the top of the window,
4376 should be affected by insert-lines and delete-lines operations.
4377 This, and those operations, are used only within an update
4378 that is bounded by calls to x_update_begin and x_update_end. */
4380 static void
4381 XTset_terminal_window (n)
4382 register int n;
4384 /* This function intentionally left blank. */
4389 /***********************************************************************
4390 Line Dance
4391 ***********************************************************************/
4393 /* Perform an insert-lines or delete-lines operation, inserting N
4394 lines or deleting -N lines at vertical position VPOS. */
4396 static void
4397 x_ins_del_lines (vpos, n)
4398 int vpos, n;
4400 abort ();
4404 /* Scroll part of the display as described by RUN. */
4406 static void
4407 x_scroll_run (w, run)
4408 struct window *w;
4409 struct run *run;
4411 struct frame *f = XFRAME (w->frame);
4412 int x, y, width, height, from_y, to_y, bottom_y;
4414 /* Get frame-relative bounding box of the text display area of W,
4415 without mode lines. Include in this box the left and right
4416 fringe of W. */
4417 window_box (w, -1, &x, &y, &width, &height);
4419 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4420 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4421 bottom_y = y + height;
4423 if (to_y < from_y)
4425 /* Scrolling up. Make sure we don't copy part of the mode
4426 line at the bottom. */
4427 if (from_y + run->height > bottom_y)
4428 height = bottom_y - from_y;
4429 else
4430 height = run->height;
4432 else
4434 /* Scolling down. Make sure we don't copy over the mode line.
4435 at the bottom. */
4436 if (to_y + run->height > bottom_y)
4437 height = bottom_y - to_y;
4438 else
4439 height = run->height;
4442 BLOCK_INPUT;
4444 /* Cursor off. Will be switched on again in x_update_window_end. */
4445 updated_window = w;
4446 x_clear_cursor (w);
4448 mac_scroll_area (f, f->output_data.mac->normal_gc,
4449 x, from_y,
4450 width, height,
4451 x, to_y);
4453 UNBLOCK_INPUT;
4458 /***********************************************************************
4459 Exposure Events
4460 ***********************************************************************/
4463 static void
4464 frame_highlight (f)
4465 struct frame *f;
4467 x_update_cursor (f, 1);
4470 static void
4471 frame_unhighlight (f)
4472 struct frame *f;
4474 x_update_cursor (f, 1);
4477 /* The focus has changed. Update the frames as necessary to reflect
4478 the new situation. Note that we can't change the selected frame
4479 here, because the Lisp code we are interrupting might become confused.
4480 Each event gets marked with the frame in which it occurred, so the
4481 Lisp code can tell when the switch took place by examining the events. */
4483 static void
4484 x_new_focus_frame (dpyinfo, frame)
4485 struct x_display_info *dpyinfo;
4486 struct frame *frame;
4488 struct frame *old_focus = dpyinfo->x_focus_frame;
4490 if (frame != dpyinfo->x_focus_frame)
4492 /* Set this before calling other routines, so that they see
4493 the correct value of x_focus_frame. */
4494 dpyinfo->x_focus_frame = frame;
4496 if (old_focus && old_focus->auto_lower)
4497 x_lower_frame (old_focus);
4499 #if 0
4500 selected_frame = frame;
4501 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4502 selected_frame);
4503 Fselect_window (selected_frame->selected_window, Qnil);
4504 choose_minibuf_frame ();
4505 #endif /* ! 0 */
4507 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4508 pending_autoraise_frame = dpyinfo->x_focus_frame;
4509 else
4510 pending_autoraise_frame = 0;
4512 #if USE_MAC_FONT_PANEL
4513 if (frame)
4514 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
4515 #endif
4518 x_frame_rehighlight (dpyinfo);
4521 /* Handle FocusIn and FocusOut state changes for FRAME.
4522 If FRAME has focus and there exists more than one frame, puts
4523 a FOCUS_IN_EVENT into *BUFP. */
4525 static void
4526 mac_focus_changed (type, dpyinfo, frame, bufp)
4527 int type;
4528 struct mac_display_info *dpyinfo;
4529 struct frame *frame;
4530 struct input_event *bufp;
4532 if (type == activeFlag)
4534 if (dpyinfo->x_focus_event_frame != frame)
4536 x_new_focus_frame (dpyinfo, frame);
4537 dpyinfo->x_focus_event_frame = frame;
4539 /* Don't stop displaying the initial startup message
4540 for a switch-frame event we don't need. */
4541 if (NILP (Vterminal_frame)
4542 && CONSP (Vframe_list)
4543 && !NILP (XCDR (Vframe_list)))
4545 bufp->kind = FOCUS_IN_EVENT;
4546 XSETFRAME (bufp->frame_or_window, frame);
4550 else
4552 if (dpyinfo->x_focus_event_frame == frame)
4554 dpyinfo->x_focus_event_frame = 0;
4555 x_new_focus_frame (dpyinfo, 0);
4560 /* The focus may have changed. Figure out if it is a real focus change,
4561 by checking both FocusIn/Out and Enter/LeaveNotify events.
4563 Returns FOCUS_IN_EVENT event in *BUFP. */
4565 static void
4566 x_detect_focus_change (dpyinfo, event, bufp)
4567 struct mac_display_info *dpyinfo;
4568 const EventRecord *event;
4569 struct input_event *bufp;
4571 struct frame *frame;
4573 frame = mac_window_to_frame ((WindowRef) event->message);
4574 if (! frame)
4575 return;
4577 /* On Mac, this is only called from focus events, so no switch needed. */
4578 mac_focus_changed ((event->modifiers & activeFlag),
4579 dpyinfo, frame, bufp);
4583 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4585 void
4586 x_mouse_leave (dpyinfo)
4587 struct x_display_info *dpyinfo;
4589 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4592 /* The focus has changed, or we have redirected a frame's focus to
4593 another frame (this happens when a frame uses a surrogate
4594 mini-buffer frame). Shift the highlight as appropriate.
4596 The FRAME argument doesn't necessarily have anything to do with which
4597 frame is being highlighted or un-highlighted; we only use it to find
4598 the appropriate X display info. */
4600 static void
4601 XTframe_rehighlight (frame)
4602 struct frame *frame;
4604 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4607 static void
4608 x_frame_rehighlight (dpyinfo)
4609 struct x_display_info *dpyinfo;
4611 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4613 if (dpyinfo->x_focus_frame)
4615 dpyinfo->x_highlight_frame
4616 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4617 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4618 : dpyinfo->x_focus_frame);
4619 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4621 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4622 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4625 else
4626 dpyinfo->x_highlight_frame = 0;
4628 if (dpyinfo->x_highlight_frame != old_highlight)
4630 if (old_highlight)
4631 frame_unhighlight (old_highlight);
4632 if (dpyinfo->x_highlight_frame)
4633 frame_highlight (dpyinfo->x_highlight_frame);
4639 /* Convert a keysym to its name. */
4641 char *
4642 x_get_keysym_name (keysym)
4643 int keysym;
4645 char *value;
4647 BLOCK_INPUT;
4648 #if 0
4649 value = XKeysymToString (keysym);
4650 #else
4651 value = 0;
4652 #endif
4653 UNBLOCK_INPUT;
4655 return value;
4660 /* Function to report a mouse movement to the mainstream Emacs code.
4661 The input handler calls this.
4663 We have received a mouse movement event, which is given in *event.
4664 If the mouse is over a different glyph than it was last time, tell
4665 the mainstream emacs code by setting mouse_moved. If not, ask for
4666 another motion event, so we can check again the next time it moves. */
4668 static Point last_mouse_motion_position;
4669 static Lisp_Object last_mouse_motion_frame;
4671 static int
4672 note_mouse_movement (frame, pos)
4673 FRAME_PTR frame;
4674 Point *pos;
4676 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4677 #if TARGET_API_MAC_CARBON
4678 Rect r;
4679 #endif
4681 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4682 last_mouse_motion_position = *pos;
4683 XSETFRAME (last_mouse_motion_frame, frame);
4685 if (frame == dpyinfo->mouse_face_mouse_frame
4686 #if TARGET_API_MAC_CARBON
4687 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
4688 #else
4689 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
4690 #endif
4693 /* This case corresponds to LeaveNotify in X11. If we move
4694 outside the frame, then we're certainly no longer on any text
4695 in the frame. */
4696 clear_mouse_face (dpyinfo);
4697 dpyinfo->mouse_face_mouse_frame = 0;
4698 if (!dpyinfo->grabbed)
4699 FRAME_RIF (frame)->define_frame_cursor (frame,
4700 frame->output_data.mac->nontext_cursor);
4703 /* Has the mouse moved off the glyph it was on at the last sighting? */
4704 if (frame != last_mouse_glyph_frame
4705 || !PtInRect (*pos, &last_mouse_glyph))
4707 frame->mouse_moved = 1;
4708 last_mouse_scroll_bar = Qnil;
4709 note_mouse_highlight (frame, pos->h, pos->v);
4710 /* Remember which glyph we're now on. */
4711 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
4712 last_mouse_glyph_frame = frame;
4713 return 1;
4716 return 0;
4720 /************************************************************************
4721 Mouse Face
4722 ************************************************************************/
4724 /* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4726 static void
4727 redo_mouse_highlight ()
4729 if (!NILP (last_mouse_motion_frame)
4730 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4731 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4732 last_mouse_motion_position.h,
4733 last_mouse_motion_position.v);
4737 static struct frame *
4738 mac_focus_frame (dpyinfo)
4739 struct mac_display_info *dpyinfo;
4741 if (dpyinfo->x_focus_frame)
4742 return dpyinfo->x_focus_frame;
4743 else
4744 /* Mac version may get events, such as a menu bar click, even when
4745 all the frames are invisible. In this case, we regard the
4746 event came to the selected frame. */
4747 return SELECTED_FRAME ();
4751 /* Return the current position of the mouse.
4752 *FP should be a frame which indicates which display to ask about.
4754 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4755 and *PART to the frame, window, and scroll bar part that the mouse
4756 is over. Set *X and *Y to the portion and whole of the mouse's
4757 position on the scroll bar.
4759 If the mouse movement started elsewhere, set *FP to the frame the
4760 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4761 the mouse is over.
4763 Set *TIME to the server time-stamp for the time at which the mouse
4764 was at this position.
4766 Don't store anything if we don't have a valid set of values to report.
4768 This clears the mouse_moved flag, so we can wait for the next mouse
4769 movement. */
4771 static void
4772 XTmouse_position (fp, insist, bar_window, part, x, y, time)
4773 FRAME_PTR *fp;
4774 int insist;
4775 Lisp_Object *bar_window;
4776 enum scroll_bar_part *part;
4777 Lisp_Object *x, *y;
4778 unsigned long *time;
4780 FRAME_PTR f1;
4782 BLOCK_INPUT;
4784 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4785 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4786 else
4788 Lisp_Object frame, tail;
4790 /* Clear the mouse-moved flag for every frame on this display. */
4791 FOR_EACH_FRAME (tail, frame)
4792 XFRAME (frame)->mouse_moved = 0;
4794 last_mouse_scroll_bar = Qnil;
4796 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4797 && FRAME_LIVE_P (last_mouse_frame))
4798 f1 = last_mouse_frame;
4799 else
4800 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
4802 if (f1)
4804 /* Ok, we found a frame. Store all the values.
4805 last_mouse_glyph is a rectangle used to reduce the
4806 generation of mouse events. To not miss any motion
4807 events, we must divide the frame into rectangles of the
4808 size of the smallest character that could be displayed
4809 on it, i.e. into the same rectangles that matrices on
4810 the frame are divided into. */
4811 Point mouse_pos;
4813 #if TARGET_API_MAC_CARBON
4814 GetGlobalMouse (&mouse_pos);
4815 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4816 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4817 #else
4818 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4819 GetMouse (&mouse_pos);
4820 #endif
4821 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4822 &last_mouse_glyph);
4823 last_mouse_glyph_frame = f1;
4825 *bar_window = Qnil;
4826 *part = 0;
4827 *fp = f1;
4828 XSETINT (*x, mouse_pos.h);
4829 XSETINT (*y, mouse_pos.v);
4830 *time = last_mouse_movement_time;
4834 UNBLOCK_INPUT;
4838 /************************************************************************
4839 Toolkit scroll bars
4840 ************************************************************************/
4842 #ifdef USE_TOOLKIT_SCROLL_BARS
4844 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4845 static OSStatus install_scroll_bar_timer P_ ((void));
4846 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
4847 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
4848 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
4849 struct input_event *));
4850 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
4851 Rect *));
4852 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
4853 ControlPartCode, Point,
4854 struct input_event *));
4855 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
4856 struct input_event *));
4857 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
4858 Point, struct input_event *));
4859 static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4860 int, int, int));
4862 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
4864 static int last_scroll_bar_part;
4866 static EventLoopTimerRef scroll_bar_timer;
4868 static int scroll_bar_timer_event_posted_p;
4870 #define SCROLL_BAR_FIRST_DELAY 0.5
4871 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4873 static pascal void
4874 scroll_bar_timer_callback (timer, data)
4875 EventLoopTimerRef timer;
4876 void *data;
4878 OSStatus err;
4880 err = mac_post_mouse_moved_event ();
4881 if (err == noErr)
4882 scroll_bar_timer_event_posted_p = 1;
4885 static OSStatus
4886 install_scroll_bar_timer ()
4888 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4890 if (scroll_bar_timer_callbackUPP == NULL)
4891 scroll_bar_timer_callbackUPP =
4892 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4894 if (scroll_bar_timer == NULL)
4895 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4896 kEventDurationForever as delays. */
4897 return
4898 InstallEventLoopTimer (GetCurrentEventLoop (),
4899 kEventDurationForever, kEventDurationForever,
4900 scroll_bar_timer_callbackUPP, NULL,
4901 &scroll_bar_timer);
4904 static OSStatus
4905 set_scroll_bar_timer (delay)
4906 EventTimerInterval delay;
4908 if (scroll_bar_timer == NULL)
4909 install_scroll_bar_timer ();
4911 scroll_bar_timer_event_posted_p = 0;
4913 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4916 static int
4917 control_part_code_to_scroll_bar_part (part_code)
4918 ControlPartCode part_code;
4920 switch (part_code)
4922 case kControlUpButtonPart: return scroll_bar_up_arrow;
4923 case kControlDownButtonPart: return scroll_bar_down_arrow;
4924 case kControlPageUpPart: return scroll_bar_above_handle;
4925 case kControlPageDownPart: return scroll_bar_below_handle;
4926 case kControlIndicatorPart: return scroll_bar_handle;
4929 return -1;
4932 static void
4933 construct_scroll_bar_click (bar, part, bufp)
4934 struct scroll_bar *bar;
4935 int part;
4936 struct input_event *bufp;
4938 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4939 bufp->frame_or_window = bar->window;
4940 bufp->arg = Qnil;
4941 bufp->part = part;
4942 bufp->code = 0;
4943 XSETINT (bufp->x, 0);
4944 XSETINT (bufp->y, 0);
4945 bufp->modifiers = 0;
4948 static OSStatus
4949 get_control_part_bounds (ch, part_code, rect)
4950 ControlRef ch;
4951 ControlPartCode part_code;
4952 Rect *rect;
4954 RgnHandle region = NewRgn ();
4955 OSStatus err;
4957 err = GetControlRegion (ch, part_code, region);
4958 if (err == noErr)
4959 GetRegionBounds (region, rect);
4960 DisposeRgn (region);
4962 return err;
4965 static void
4966 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
4967 struct scroll_bar *bar;
4968 ControlPartCode part_code;
4969 Point mouse_pos;
4970 struct input_event *bufp;
4972 int part = control_part_code_to_scroll_bar_part (part_code);
4974 if (part < 0)
4975 return;
4977 if (part != scroll_bar_handle)
4979 construct_scroll_bar_click (bar, part, bufp);
4980 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4981 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
4982 bar->dragging = Qnil;
4984 else
4986 Rect r;
4988 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4989 kControlIndicatorPart, &r);
4990 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
4993 last_scroll_bar_part = part;
4994 tracked_scroll_bar = bar;
4997 static void
4998 x_scroll_bar_handle_release (bar, bufp)
4999 struct scroll_bar *bar;
5000 struct input_event *bufp;
5002 if (last_scroll_bar_part != scroll_bar_handle
5003 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
5004 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
5006 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5007 set_scroll_bar_timer (kEventDurationForever);
5009 last_scroll_bar_part = -1;
5010 bar->dragging = Qnil;
5011 tracked_scroll_bar = NULL;
5014 static void
5015 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
5016 WindowRef win;
5017 struct scroll_bar *bar;
5018 Point mouse_pos;
5019 struct input_event *bufp;
5021 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5023 if (last_scroll_bar_part == scroll_bar_handle)
5025 int top, top_range;
5026 Rect r;
5028 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
5029 kControlIndicatorPart, &r);
5031 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
5032 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
5034 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
5035 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
5037 if (top < 0)
5038 top = 0;
5039 if (top > top_range)
5040 top = top_range;
5042 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
5043 XSETINT (bufp->x, top);
5044 XSETINT (bufp->y, top_range);
5046 else
5048 ControlPartCode part_code;
5049 int unhilite_p = 0, part;
5051 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
5052 unhilite_p = 1;
5053 else
5055 part = control_part_code_to_scroll_bar_part (part_code);
5057 switch (last_scroll_bar_part)
5059 case scroll_bar_above_handle:
5060 case scroll_bar_below_handle:
5061 if (part != scroll_bar_above_handle
5062 && part != scroll_bar_below_handle)
5063 unhilite_p = 1;
5064 break;
5066 case scroll_bar_up_arrow:
5067 case scroll_bar_down_arrow:
5068 if (part != scroll_bar_up_arrow
5069 && part != scroll_bar_down_arrow)
5070 unhilite_p = 1;
5071 break;
5075 if (unhilite_p)
5076 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5077 else if (part != last_scroll_bar_part
5078 || scroll_bar_timer_event_posted_p)
5080 construct_scroll_bar_click (bar, part, bufp);
5081 last_scroll_bar_part = part;
5082 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5083 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
5088 /* Set the thumb size and position of scroll bar BAR. We are currently
5089 displaying PORTION out of a whole WHOLE, and our position POSITION. */
5091 static void
5092 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
5093 struct scroll_bar *bar;
5094 int portion, position, whole;
5096 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5097 int value, viewsize, maximum;
5099 if (XINT (bar->track_height) == 0)
5100 return;
5102 if (whole <= portion)
5103 value = 0, viewsize = 1, maximum = 0;
5104 else
5106 float scale;
5108 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
5109 scale = (float) maximum / (whole - portion);
5110 value = position * scale + 0.5f;
5111 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
5114 BLOCK_INPUT;
5116 if (GetControlViewSize (ch) != viewsize
5117 || GetControl32BitValue (ch) != value
5118 || GetControl32BitMaximum (ch) != maximum)
5120 /* Temporarily hide the scroll bar to avoid multiple redraws. */
5121 SetControlVisibility (ch, false, false);
5123 SetControl32BitMaximum (ch, maximum);
5124 SetControl32BitValue (ch, value);
5125 SetControlViewSize (ch, viewsize);
5127 SetControlVisibility (ch, true, true);
5130 UNBLOCK_INPUT;
5133 #endif /* USE_TOOLKIT_SCROLL_BARS */
5137 /************************************************************************
5138 Scroll bars, general
5139 ************************************************************************/
5141 /* Create a scroll bar and return the scroll bar vector for it. W is
5142 the Emacs window on which to create the scroll bar. TOP, LEFT,
5143 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
5144 scroll bar. */
5146 static struct scroll_bar *
5147 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5148 struct window *w;
5149 int top, left, width, height, disp_top, disp_height;
5151 struct frame *f = XFRAME (w->frame);
5152 struct scroll_bar *bar
5153 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5154 Rect r;
5155 ControlRef ch;
5157 BLOCK_INPUT;
5159 r.left = left;
5160 r.top = disp_top;
5161 r.right = left + width;
5162 r.bottom = disp_top + disp_height;
5164 #if USE_CG_DRAWING
5165 mac_prepare_for_quickdraw (f);
5166 #endif
5167 #if TARGET_API_MAC_CARBON
5168 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
5169 #ifdef USE_TOOLKIT_SCROLL_BARS
5170 false,
5171 #else
5172 width < disp_height,
5173 #endif
5174 0, 0, 0, kControlScrollBarProc, (long) bar);
5175 #else
5176 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5177 0, 0, 0, scrollBarProc, (long) bar);
5178 #endif
5179 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
5181 XSETWINDOW (bar->window, w);
5182 XSETINT (bar->top, top);
5183 XSETINT (bar->left, left);
5184 XSETINT (bar->width, width);
5185 XSETINT (bar->height, height);
5186 XSETINT (bar->start, 0);
5187 XSETINT (bar->end, 0);
5188 bar->dragging = Qnil;
5189 #ifdef MAC_OSX
5190 bar->fringe_extended_p = Qnil;
5191 #endif
5192 bar->redraw_needed_p = Qnil;
5193 #ifdef USE_TOOLKIT_SCROLL_BARS
5194 bar->track_top = Qnil;
5195 bar->track_height = Qnil;
5196 bar->min_handle = Qnil;
5197 #endif
5199 /* Add bar to its frame's list of scroll bars. */
5200 bar->next = FRAME_SCROLL_BARS (f);
5201 bar->prev = Qnil;
5202 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5203 if (!NILP (bar->next))
5204 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5206 UNBLOCK_INPUT;
5207 return bar;
5211 /* Draw BAR's handle in the proper position.
5213 If the handle is already drawn from START to END, don't bother
5214 redrawing it, unless REBUILD is non-zero; in that case, always
5215 redraw it. (REBUILD is handy for drawing the handle after expose
5216 events.)
5218 Normally, we want to constrain the start and end of the handle to
5219 fit inside its rectangle, but if the user is dragging the scroll
5220 bar handle, we want to let them drag it down all the way, so that
5221 the bar's top is as far down as it goes; otherwise, there's no way
5222 to move to the very end of the buffer. */
5224 #ifndef USE_TOOLKIT_SCROLL_BARS
5226 static void
5227 x_scroll_bar_set_handle (bar, start, end, rebuild)
5228 struct scroll_bar *bar;
5229 int start, end;
5230 int rebuild;
5232 int dragging = ! NILP (bar->dragging);
5233 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5234 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5235 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5236 int length = end - start;
5238 /* If the display is already accurate, do nothing. */
5239 if (! rebuild
5240 && start == XINT (bar->start)
5241 && end == XINT (bar->end))
5242 return;
5244 BLOCK_INPUT;
5246 /* Make sure the values are reasonable, and try to preserve the
5247 distance between start and end. */
5248 if (start < 0)
5249 start = 0;
5250 else if (start > top_range)
5251 start = top_range;
5252 end = start + length;
5254 if (end < start)
5255 end = start;
5256 else if (end > top_range && ! dragging)
5257 end = top_range;
5259 /* Store the adjusted setting in the scroll bar. */
5260 XSETINT (bar->start, start);
5261 XSETINT (bar->end, end);
5263 /* Clip the end position, just for display. */
5264 if (end > top_range)
5265 end = top_range;
5267 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5268 top positions, to make sure the handle is always at least that
5269 many pixels tall. */
5270 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5272 SetControlMinimum (ch, 0);
5273 /* Don't inadvertently activate deactivated scroll bars */
5274 if (GetControlMaximum (ch) != -1)
5275 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5276 - (end - start));
5277 SetControlValue (ch, start);
5278 #if TARGET_API_MAC_CARBON
5279 SetControlViewSize (ch, end - start);
5280 #endif
5282 UNBLOCK_INPUT;
5285 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5287 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5288 nil. */
5290 static void
5291 x_scroll_bar_remove (bar)
5292 struct scroll_bar *bar;
5294 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5296 BLOCK_INPUT;
5298 #if USE_CG_DRAWING
5299 mac_prepare_for_quickdraw (f);
5300 #endif
5301 /* Destroy the Mac scroll bar control */
5302 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
5304 /* Disassociate this scroll bar from its window. */
5305 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5307 UNBLOCK_INPUT;
5311 /* Set the handle of the vertical scroll bar for WINDOW to indicate
5312 that we are displaying PORTION characters out of a total of WHOLE
5313 characters, starting at POSITION. If WINDOW has no scroll bar,
5314 create one. */
5316 static void
5317 XTset_vertical_scroll_bar (w, portion, whole, position)
5318 struct window *w;
5319 int portion, whole, position;
5321 struct frame *f = XFRAME (w->frame);
5322 struct scroll_bar *bar;
5323 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
5324 int window_y, window_height;
5325 #ifdef MAC_OSX
5326 int fringe_extended_p;
5327 #endif
5329 /* Get window dimensions. */
5330 window_box (w, -1, 0, &window_y, 0, &window_height);
5331 top = window_y;
5332 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
5333 height = window_height;
5335 /* Compute the left edge of the scroll bar area. */
5336 left = WINDOW_SCROLL_BAR_AREA_X (w);
5338 /* Compute the width of the scroll bar which might be less than
5339 the width of the area reserved for the scroll bar. */
5340 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5341 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
5342 else
5343 sb_width = width;
5345 /* Compute the left edge of the scroll bar. */
5346 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
5347 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
5348 else
5349 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
5351 /* Adjustments according to Inside Macintosh to make it look nice */
5352 disp_top = top;
5353 disp_height = height;
5354 #ifdef MAC_OS8
5355 if (disp_top == 0)
5357 disp_top = -1;
5358 disp_height++;
5360 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
5362 disp_top++;
5363 disp_height--;
5366 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
5367 sb_left++;
5368 #endif
5370 #ifdef MAC_OSX
5371 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5372 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5373 && WINDOW_LEFT_FRINGE_WIDTH (w)
5374 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5375 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5376 else
5377 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5378 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5379 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5380 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5381 #endif
5383 /* Does the scroll bar exist yet? */
5384 if (NILP (w->vertical_scroll_bar))
5386 BLOCK_INPUT;
5387 #ifdef MAC_OSX
5388 if (fringe_extended_p)
5389 mac_clear_area (f, sb_left, top, sb_width, height);
5390 else
5391 #endif
5392 mac_clear_area (f, left, top, width, height);
5393 UNBLOCK_INPUT;
5394 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5395 disp_height);
5396 XSETVECTOR (w->vertical_scroll_bar, bar);
5398 else
5400 /* It may just need to be moved and resized. */
5401 ControlRef ch;
5403 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5404 ch = SCROLL_BAR_CONTROL_REF (bar);
5406 BLOCK_INPUT;
5408 /* If already correctly positioned, do nothing. */
5409 if (XINT (bar->left) == sb_left
5410 && XINT (bar->top) == top
5411 && XINT (bar->width) == sb_width
5412 && XINT (bar->height) == height
5413 #ifdef MAC_OSX
5414 && !NILP (bar->fringe_extended_p) == fringe_extended_p
5415 #endif
5418 if (!NILP (bar->redraw_needed_p))
5420 #if USE_CG_DRAWING
5421 mac_prepare_for_quickdraw (f);
5422 #endif
5423 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
5426 else
5428 /* Since toolkit scroll bars are smaller than the space reserved
5429 for them on the frame, we have to clear "under" them. */
5430 #ifdef MAC_OSX
5431 if (fringe_extended_p)
5432 mac_clear_area (f, sb_left, top, sb_width, height);
5433 else
5434 #endif
5435 mac_clear_area (f, left, top, width, height);
5437 #if USE_CG_DRAWING
5438 mac_prepare_for_quickdraw (f);
5439 #endif
5440 HideControl (ch);
5441 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5442 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5443 disp_height);
5444 #ifndef USE_TOOLKIT_SCROLL_BARS
5445 if (sb_width < disp_height)
5446 ShowControl (ch);
5447 #endif
5449 /* Remember new settings. */
5450 XSETINT (bar->left, sb_left);
5451 XSETINT (bar->top, top);
5452 XSETINT (bar->width, sb_width);
5453 XSETINT (bar->height, height);
5454 #ifdef USE_TOOLKIT_SCROLL_BARS
5455 bar->track_top = Qnil;
5456 bar->track_height = Qnil;
5457 bar->min_handle = Qnil;
5458 #endif
5461 UNBLOCK_INPUT;
5464 #ifdef MAC_OSX
5465 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5466 #endif
5468 bar->redraw_needed_p = Qnil;
5470 #ifdef USE_TOOLKIT_SCROLL_BARS
5471 if (NILP (bar->track_top))
5473 if (sb_width >= disp_height
5474 #ifdef MAC_OSX
5475 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5476 #endif
5479 XSETINT (bar->track_top, 0);
5480 XSETINT (bar->track_height, 0);
5481 XSETINT (bar->min_handle, 0);
5483 else
5485 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5486 Rect r0, r1;
5488 BLOCK_INPUT;
5490 SetControl32BitMinimum (ch, 0);
5491 SetControl32BitMaximum (ch, 1 << 30);
5492 SetControlViewSize (ch, 1);
5494 /* Move the scroll bar thumb to the top. */
5495 SetControl32BitValue (ch, 0);
5496 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5498 /* Move the scroll bar thumb to the bottom. */
5499 SetControl32BitValue (ch, 1 << 30);
5500 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5502 UnionRect (&r0, &r1, &r0);
5503 XSETINT (bar->track_top, r0.top);
5504 XSETINT (bar->track_height, r0.bottom - r0.top);
5505 XSETINT (bar->min_handle, r1.bottom - r1.top);
5507 /* Don't show the scroll bar if its height is not enough to
5508 display the scroll bar thumb. */
5509 if (r0.bottom - r0.top > 0)
5510 ShowControl (ch);
5512 UNBLOCK_INPUT;
5516 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5517 #else /* not USE_TOOLKIT_SCROLL_BARS */
5518 /* Set the scroll bar's current state, unless we're currently being
5519 dragged. */
5520 if (NILP (bar->dragging))
5522 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5524 if (whole == 0)
5525 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5526 else
5528 int start = ((double) position * top_range) / whole;
5529 int end = ((double) (position + portion) * top_range) / whole;
5530 x_scroll_bar_set_handle (bar, start, end, 0);
5533 #endif /* not USE_TOOLKIT_SCROLL_BARS */
5537 /* The following three hooks are used when we're doing a thorough
5538 redisplay of the frame. We don't explicitly know which scroll bars
5539 are going to be deleted, because keeping track of when windows go
5540 away is a real pain - "Can you say set-window-configuration, boys
5541 and girls?" Instead, we just assert at the beginning of redisplay
5542 that *all* scroll bars are to be removed, and then save a scroll bar
5543 from the fiery pit when we actually redisplay its window. */
5545 /* Arrange for all scroll bars on FRAME to be removed at the next call
5546 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5547 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5549 static void
5550 XTcondemn_scroll_bars (frame)
5551 FRAME_PTR frame;
5553 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5554 while (! NILP (FRAME_SCROLL_BARS (frame)))
5556 Lisp_Object bar;
5557 bar = FRAME_SCROLL_BARS (frame);
5558 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5559 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5560 XSCROLL_BAR (bar)->prev = Qnil;
5561 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5562 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5563 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5568 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5569 Note that WINDOW isn't necessarily condemned at all. */
5571 static void
5572 XTredeem_scroll_bar (window)
5573 struct window *window;
5575 struct scroll_bar *bar;
5576 struct frame *f;
5578 /* We can't redeem this window's scroll bar if it doesn't have one. */
5579 if (NILP (window->vertical_scroll_bar))
5580 abort ();
5582 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5584 /* Unlink it from the condemned list. */
5585 f = XFRAME (WINDOW_FRAME (window));
5586 if (NILP (bar->prev))
5588 /* If the prev pointer is nil, it must be the first in one of
5589 the lists. */
5590 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5591 /* It's not condemned. Everything's fine. */
5592 return;
5593 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5594 window->vertical_scroll_bar))
5595 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5596 else
5597 /* If its prev pointer is nil, it must be at the front of
5598 one or the other! */
5599 abort ();
5601 else
5602 XSCROLL_BAR (bar->prev)->next = bar->next;
5604 if (! NILP (bar->next))
5605 XSCROLL_BAR (bar->next)->prev = bar->prev;
5607 bar->next = FRAME_SCROLL_BARS (f);
5608 bar->prev = Qnil;
5609 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5610 if (! NILP (bar->next))
5611 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5614 /* Remove all scroll bars on FRAME that haven't been saved since the
5615 last call to `*condemn_scroll_bars_hook'. */
5617 static void
5618 XTjudge_scroll_bars (f)
5619 FRAME_PTR f;
5621 Lisp_Object bar, next;
5623 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5625 /* Clear out the condemned list now so we won't try to process any
5626 more events on the hapless scroll bars. */
5627 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5629 for (; ! NILP (bar); bar = next)
5631 struct scroll_bar *b = XSCROLL_BAR (bar);
5633 x_scroll_bar_remove (b);
5635 next = b->next;
5636 b->next = b->prev = Qnil;
5639 /* Now there should be no references to the condemned scroll bars,
5640 and they should get garbage-collected. */
5644 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
5645 is set to something other than NO_EVENT, it is enqueued.
5647 This may be called from a signal handler, so we have to ignore GC
5648 mark bits. */
5650 static void
5651 x_scroll_bar_handle_click (bar, part_code, er, bufp)
5652 struct scroll_bar *bar;
5653 ControlPartCode part_code;
5654 const EventRecord *er;
5655 struct input_event *bufp;
5657 int win_y, top_range;
5659 if (! WINDOWP (bar->window))
5660 abort ();
5662 bufp->kind = SCROLL_BAR_CLICK_EVENT;
5663 bufp->frame_or_window = bar->window;
5664 bufp->arg = Qnil;
5666 bar->dragging = Qnil;
5668 switch (part_code)
5670 case kControlUpButtonPart:
5671 bufp->part = scroll_bar_up_arrow;
5672 break;
5673 case kControlDownButtonPart:
5674 bufp->part = scroll_bar_down_arrow;
5675 break;
5676 case kControlPageUpPart:
5677 bufp->part = scroll_bar_above_handle;
5678 break;
5679 case kControlPageDownPart:
5680 bufp->part = scroll_bar_below_handle;
5681 break;
5682 #if TARGET_API_MAC_CARBON
5683 default:
5684 #else
5685 case kControlIndicatorPart:
5686 #endif
5687 if (er->what == mouseDown)
5688 bar->dragging = make_number (0);
5689 XSETVECTOR (last_mouse_scroll_bar, bar);
5690 bufp->part = scroll_bar_handle;
5691 break;
5694 win_y = XINT (bufp->y) - XINT (bar->top);
5695 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5697 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5699 win_y -= 24;
5701 if (! NILP (bar->dragging))
5702 win_y -= XINT (bar->dragging);
5704 if (win_y < 0)
5705 win_y = 0;
5706 if (win_y > top_range)
5707 win_y = top_range;
5709 XSETINT (bufp->x, win_y);
5710 XSETINT (bufp->y, top_range);
5713 #ifndef USE_TOOLKIT_SCROLL_BARS
5715 /* Handle some mouse motion while someone is dragging the scroll bar.
5717 This may be called from a signal handler, so we have to ignore GC
5718 mark bits. */
5720 static void
5721 x_scroll_bar_note_movement (bar, y_pos, t)
5722 struct scroll_bar *bar;
5723 int y_pos;
5724 Time t;
5726 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5728 last_mouse_movement_time = t;
5730 f->mouse_moved = 1;
5731 XSETVECTOR (last_mouse_scroll_bar, bar);
5733 /* If we're dragging the bar, display it. */
5734 if (! NILP (bar->dragging))
5736 /* Where should the handle be now? */
5737 int new_start = y_pos - 24;
5739 if (new_start != XINT (bar->start))
5741 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5743 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5748 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5750 /* Return information to the user about the current position of the mouse
5751 on the scroll bar. */
5753 static void
5754 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5755 FRAME_PTR *fp;
5756 Lisp_Object *bar_window;
5757 enum scroll_bar_part *part;
5758 Lisp_Object *x, *y;
5759 unsigned long *time;
5761 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
5762 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5763 #if TARGET_API_MAC_CARBON
5764 WindowRef wp = GetControlOwner (ch);
5765 #else
5766 WindowRef wp = (*ch)->contrlOwner;
5767 #endif
5768 Point mouse_pos;
5769 struct frame *f = mac_window_to_frame (wp);
5770 int win_y, top_range;
5772 #if TARGET_API_MAC_CARBON
5773 GetGlobalMouse (&mouse_pos);
5774 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5775 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5776 #else
5777 SetPortWindowPort (wp);
5778 GetMouse (&mouse_pos);
5779 #endif
5781 win_y = mouse_pos.v - XINT (bar->top);
5782 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5784 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5786 win_y -= 24;
5788 if (! NILP (bar->dragging))
5789 win_y -= XINT (bar->dragging);
5791 if (win_y < 0)
5792 win_y = 0;
5793 if (win_y > top_range)
5794 win_y = top_range;
5796 *fp = f;
5797 *bar_window = bar->window;
5799 if (! NILP (bar->dragging))
5800 *part = scroll_bar_handle;
5801 else if (win_y < XINT (bar->start))
5802 *part = scroll_bar_above_handle;
5803 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5804 *part = scroll_bar_handle;
5805 else
5806 *part = scroll_bar_below_handle;
5808 XSETINT (*x, win_y);
5809 XSETINT (*y, top_range);
5811 f->mouse_moved = 0;
5812 last_mouse_scroll_bar = Qnil;
5814 *time = last_mouse_movement_time;
5818 /* The screen has been cleared so we may have changed foreground or
5819 background colors, and the scroll bars may need to be redrawn.
5820 Clear out the scroll bars, and ask for expose events, so we can
5821 redraw them. */
5823 void
5824 x_scroll_bar_clear (f)
5825 FRAME_PTR f;
5827 Lisp_Object bar;
5829 /* We can have scroll bars even if this is 0,
5830 if we just turned off scroll bar mode.
5831 But in that case we should not clear them. */
5832 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5833 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5834 bar = XSCROLL_BAR (bar)->next)
5835 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
5839 /***********************************************************************
5840 Tool-bars
5841 ***********************************************************************/
5842 #if USE_MAC_TOOLBAR
5844 /* In identifiers such as function/variable names, Emacs tool bar is
5845 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5847 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5848 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5850 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5851 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5852 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5853 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5854 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5855 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5856 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5858 static int mac_event_to_emacs_modifiers P_ ((EventRef));
5859 static void mac_handle_origin_change P_ ((struct frame *));
5860 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5861 EventRef, void *));
5863 static void
5864 mac_move_window_with_gravity (f, win_gravity, left, top)
5865 struct frame *f;
5866 int win_gravity;
5867 short left, top;
5869 Rect inner, outer;
5871 mac_get_window_bounds (f, &inner, &outer);
5873 switch (win_gravity)
5875 case NorthWestGravity:
5876 case WestGravity:
5877 case SouthWestGravity:
5878 left += inner.left - outer.left;
5879 break;
5881 case NorthGravity:
5882 case CenterGravity:
5883 case SouthGravity:
5884 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5885 break;
5887 case NorthEastGravity:
5888 case EastGravity:
5889 case SouthEastGravity:
5890 left += inner.right - outer.right;
5891 break;
5894 switch (win_gravity)
5896 case NorthWestGravity:
5897 case NorthGravity:
5898 case NorthEastGravity:
5899 top += inner.top - outer.top;
5900 break;
5902 case WestGravity:
5903 case CenterGravity:
5904 case EastGravity:
5905 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5906 break;
5908 case SouthWestGravity:
5909 case SouthGravity:
5910 case SouthEastGravity:
5911 top += inner.bottom - outer.bottom;
5912 break;
5915 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5918 static void
5919 mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5920 struct frame *f;
5921 int win_gravity;
5922 short *left, *top;
5924 Rect inner, outer;
5926 mac_get_window_bounds (f, &inner, &outer);
5928 switch (win_gravity)
5930 case NorthWestGravity:
5931 case WestGravity:
5932 case SouthWestGravity:
5933 *left = outer.left;
5934 break;
5936 case NorthGravity:
5937 case CenterGravity:
5938 case SouthGravity:
5939 *left = outer.left + ((outer.right - outer.left)
5940 - (inner.right - inner.left)) / 2;
5941 break;
5943 case NorthEastGravity:
5944 case EastGravity:
5945 case SouthEastGravity:
5946 *left = outer.right - (inner.right - inner.left);
5947 break;
5950 switch (win_gravity)
5952 case NorthWestGravity:
5953 case NorthGravity:
5954 case NorthEastGravity:
5955 *top = outer.top;
5956 break;
5958 case WestGravity:
5959 case CenterGravity:
5960 case EastGravity:
5961 *top = outer.top + ((outer.bottom - outer.top)
5962 - (inner.bottom - inner.top)) / 2;
5963 break;
5965 case SouthWestGravity:
5966 case SouthGravity:
5967 case SouthEastGravity:
5968 *top = outer.bottom - (inner.bottom - inner.top);
5969 break;
5973 static OSStatus
5974 mac_handle_toolbar_event (next_handler, event, data)
5975 EventHandlerCallRef next_handler;
5976 EventRef event;
5977 void *data;
5979 OSStatus err, result = eventNotHandledErr;
5981 switch (GetEventKind (event))
5983 case kEventToolbarGetDefaultIdentifiers:
5984 result = noErr;
5985 break;
5987 case kEventToolbarGetAllowedIdentifiers:
5989 CFMutableArrayRef array;
5991 GetEventParameter (event, kEventParamMutableArray,
5992 typeCFMutableArrayRef, NULL,
5993 sizeof (CFMutableArrayRef), NULL, &array);
5994 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5995 result = noErr;
5997 break;
5999 case kEventToolbarCreateItemWithIdentifier:
6001 CFStringRef identifier;
6002 HIToolbarItemRef item = NULL;
6004 GetEventParameter (event, kEventParamToolbarItemIdentifier,
6005 typeCFStringRef, NULL,
6006 sizeof (CFStringRef), NULL, &identifier);
6008 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
6009 == kCFCompareEqualTo)
6010 HIToolbarItemCreate (identifier,
6011 kHIToolbarItemAllowDuplicates
6012 | kHIToolbarItemCantBeRemoved, &item);
6014 if (item)
6016 SetEventParameter (event, kEventParamToolbarItem,
6017 typeHIToolbarItemRef,
6018 sizeof (HIToolbarItemRef), &item);
6019 result = noErr;
6022 break;
6024 default:
6025 abort ();
6028 return result;
6031 static CGImageRef
6032 mac_image_spec_to_cg_image (f, image)
6033 struct frame *f;
6034 Lisp_Object image;
6036 if (!valid_image_p (image))
6037 return NULL;
6038 else
6040 int img_id = lookup_image (f, image);
6041 struct image *img = IMAGE_FROM_ID (f, img_id);
6043 prepare_image_for_display (f, img);
6045 return img->data.ptr_val;
6049 /* Create a tool bar for frame F. */
6051 static OSStatus
6052 mac_create_frame_tool_bar (f)
6053 FRAME_PTR f;
6055 OSStatus err;
6056 HIToolbarRef toolbar;
6058 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
6059 &toolbar);
6060 if (err == noErr)
6062 static const EventTypeSpec specs[] =
6063 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
6064 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
6065 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
6067 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
6068 mac_handle_toolbar_event,
6069 GetEventTypeCount (specs), specs,
6070 f, NULL);
6073 if (err == noErr)
6074 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
6075 if (err == noErr)
6077 static const EventTypeSpec specs[] =
6078 {{kEventClassCommand, kEventCommandProcess}};
6080 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
6081 mac_handle_toolbar_command_event,
6082 GetEventTypeCount (specs),
6083 specs, f, NULL);
6085 if (err == noErr)
6086 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
6088 if (toolbar)
6089 CFRelease (toolbar);
6091 return err;
6094 /* Update the tool bar for frame F. Add new buttons and remove old. */
6096 void
6097 update_frame_tool_bar (f)
6098 FRAME_PTR f;
6100 HIToolbarRef toolbar = NULL;
6101 short left, top;
6102 CFArrayRef old_items = NULL;
6103 CFIndex old_count;
6104 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
6105 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6107 BLOCK_INPUT;
6109 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6110 if (toolbar == NULL)
6112 mac_create_frame_tool_bar (f);
6113 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6114 if (toolbar == NULL)
6115 goto out;
6116 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6117 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6120 HIToolbarCopyItems (toolbar, &old_items);
6121 if (old_items == NULL)
6122 goto out;
6124 old_count = CFArrayGetCount (old_items);
6125 pos = 0;
6126 for (i = 0; i < f->n_tool_bar_items; ++i)
6128 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6130 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6131 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6132 int idx;
6133 Lisp_Object image;
6134 CGImageRef cg_image;
6135 CFStringRef label;
6136 HIToolbarItemRef item;
6138 /* If image is a vector, choose the image according to the
6139 button state. */
6140 image = PROP (TOOL_BAR_ITEM_IMAGES);
6141 if (VECTORP (image))
6143 if (enabled_p)
6144 idx = (selected_p
6145 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6146 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6147 else
6148 idx = (selected_p
6149 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6150 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6152 xassert (ASIZE (image) >= idx);
6153 image = AREF (image, idx);
6155 else
6156 idx = -1;
6158 cg_image = mac_image_spec_to_cg_image (f, image);
6159 /* Ignore invalid image specifications. */
6160 if (cg_image == NULL)
6161 continue;
6163 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6164 if (label == NULL)
6165 label = CFSTR ("");
6167 if (pos < old_count)
6169 CGImageRef old_cg_image = NULL;
6170 CFStringRef old_label = NULL;
6171 Boolean old_enabled_p;
6173 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6175 HIToolbarItemCopyImage (item, &old_cg_image);
6176 if (cg_image != old_cg_image)
6177 HIToolbarItemSetImage (item, cg_image);
6178 CGImageRelease (old_cg_image);
6180 HIToolbarItemCopyLabel (item, &old_label);
6181 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6182 HIToolbarItemSetLabel (item, label);
6183 CFRelease (old_label);
6185 old_enabled_p = HIToolbarItemIsEnabled (item);
6186 if ((enabled_p || idx >= 0) != old_enabled_p)
6187 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6189 else
6191 item = NULL;
6192 HIToolbarCreateItemWithIdentifier (toolbar,
6193 TOOLBAR_ICON_ITEM_IDENTIFIER,
6194 NULL, &item);
6195 if (item)
6197 HIToolbarItemSetImage (item, cg_image);
6198 HIToolbarItemSetLabel (item, label);
6199 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6200 HIToolbarAppendItem (toolbar, item);
6201 CFRelease (item);
6205 CFRelease (label);
6206 if (item)
6208 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6209 pos++;
6213 CFRelease (old_items);
6215 while (pos < old_count)
6216 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6218 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6219 !win_gravity && f == mac_focus_frame (dpyinfo));
6220 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6221 toolbar visibility change. */
6222 mac_handle_origin_change (f);
6223 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6225 mac_move_window_with_gravity (f, win_gravity, left, top);
6226 /* If the title bar is completely outside the screen, adjust the
6227 position. */
6228 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6229 kWindowConstrainMoveRegardlessOfFit
6230 | kWindowConstrainAllowPartial, NULL, NULL);
6231 f->output_data.mac->toolbar_win_gravity = 0;
6234 out:
6235 UNBLOCK_INPUT;
6238 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6239 doesn't deallocate the resources. */
6241 void
6242 free_frame_tool_bar (f)
6243 FRAME_PTR f;
6245 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6247 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6249 BLOCK_INPUT;
6250 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
6251 (NILP (Fsymbol_value
6252 (intern ("frame-notice-user-settings")))
6253 && f == mac_focus_frame (dpyinfo)));
6254 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6255 on toolbar visibility change. */
6256 mac_handle_origin_change (f);
6257 UNBLOCK_INPUT;
6261 static void
6262 mac_tool_bar_note_mouse_movement (f, event)
6263 struct frame *f;
6264 EventRef event;
6266 OSStatus err;
6267 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6268 int mouse_down_p;
6269 HIViewRef item_view;
6270 UInt32 command_id;
6272 mouse_down_p = (dpyinfo->grabbed
6273 && f == last_mouse_frame
6274 && FRAME_LIVE_P (f));
6275 if (mouse_down_p)
6276 return;
6278 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6279 event, &item_view);
6280 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6281 toolbar item view seems to have the same command ID with that of
6282 the toolbar item. */
6283 if (err == noErr)
6284 err = GetControlCommandID (item_view, &command_id);
6285 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6287 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6289 if (i < f->n_tool_bar_items)
6291 HIRect bounds;
6292 HIViewRef content_view;
6294 err = HIViewGetBounds (item_view, &bounds);
6295 if (err == noErr)
6296 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6297 kHIViewWindowContentID, &content_view);
6298 if (err == noErr)
6299 err = HIViewConvertRect (&bounds, item_view, content_view);
6300 if (err == noErr)
6301 SetRect (&last_mouse_glyph,
6302 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6303 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6305 help_echo_object = help_echo_window = Qnil;
6306 help_echo_pos = -1;
6307 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6308 if (NILP (help_echo_string))
6309 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6314 static OSStatus
6315 mac_handle_toolbar_command_event (next_handler, event, data)
6316 EventHandlerCallRef next_handler;
6317 EventRef event;
6318 void *data;
6320 OSStatus err, result = eventNotHandledErr;
6321 struct frame *f = (struct frame *) data;
6322 HICommand command;
6324 err = GetEventParameter (event, kEventParamDirectObject,
6325 typeHICommand, NULL,
6326 sizeof (HICommand), NULL, &command);
6327 if (err != noErr)
6328 return result;
6330 switch (GetEventKind (event))
6332 case kEventCommandProcess:
6333 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6334 result = CallNextEventHandler (next_handler, event);
6335 else
6337 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6339 if (i < f->n_tool_bar_items
6340 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6342 Lisp_Object frame;
6343 struct input_event buf;
6345 EVENT_INIT (buf);
6347 XSETFRAME (frame, f);
6348 buf.kind = TOOL_BAR_EVENT;
6349 buf.frame_or_window = frame;
6350 buf.arg = frame;
6351 kbd_buffer_store_event (&buf);
6353 buf.kind = TOOL_BAR_EVENT;
6354 buf.frame_or_window = frame;
6355 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6356 buf.modifiers = mac_event_to_emacs_modifiers (event);
6357 kbd_buffer_store_event (&buf);
6359 result = noErr;
6362 break;
6364 default:
6365 abort ();
6367 #undef PROP
6369 return result;
6371 #endif /* USE_MAC_TOOLBAR */
6374 /***********************************************************************
6375 Text Cursor
6376 ***********************************************************************/
6378 /* Set clipping for output in glyph row ROW. W is the window in which
6379 we operate. GC is the graphics context to set clipping in.
6381 ROW may be a text row or, e.g., a mode line. Text rows must be
6382 clipped to the interior of the window dedicated to text display,
6383 mode lines must be clipped to the whole window. */
6385 static void
6386 x_clip_to_row (w, row, area, gc)
6387 struct window *w;
6388 struct glyph_row *row;
6389 int area;
6390 GC gc;
6392 struct frame *f = XFRAME (WINDOW_FRAME (w));
6393 Rect clip_rect;
6394 int window_x, window_y, window_width;
6396 window_box (w, area, &window_x, &window_y, &window_width, 0);
6398 clip_rect.left = window_x;
6399 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6400 clip_rect.top = max (clip_rect.top, window_y);
6401 clip_rect.right = clip_rect.left + window_width;
6402 clip_rect.bottom = clip_rect.top + row->visible_height;
6404 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
6408 /* Draw a hollow box cursor on window W in glyph row ROW. */
6410 static void
6411 x_draw_hollow_cursor (w, row)
6412 struct window *w;
6413 struct glyph_row *row;
6415 struct frame *f = XFRAME (WINDOW_FRAME (w));
6416 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6417 Display *dpy = FRAME_MAC_DISPLAY (f);
6418 int x, y, wd, h;
6419 XGCValues xgcv;
6420 struct glyph *cursor_glyph;
6421 GC gc;
6423 /* Get the glyph the cursor is on. If we can't tell because
6424 the current matrix is invalid or such, give up. */
6425 cursor_glyph = get_phys_cursor_glyph (w);
6426 if (cursor_glyph == NULL)
6427 return;
6429 /* Compute frame-relative coordinates for phys cursor. */
6430 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
6431 wd = w->phys_cursor_width;
6433 /* The foreground of cursor_gc is typically the same as the normal
6434 background color, which can cause the cursor box to be invisible. */
6435 xgcv.foreground = f->output_data.mac->cursor_pixel;
6436 if (dpyinfo->scratch_cursor_gc)
6437 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6438 else
6439 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6440 GCForeground, &xgcv);
6441 gc = dpyinfo->scratch_cursor_gc;
6443 /* Set clipping, draw the rectangle, and reset clipping again. */
6444 x_clip_to_row (w, row, TEXT_AREA, gc);
6445 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
6446 mac_reset_clip_rectangles (dpy, gc);
6450 /* Draw a bar cursor on window W in glyph row ROW.
6452 Implementation note: One would like to draw a bar cursor with an
6453 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6454 Unfortunately, I didn't find a font yet that has this property set.
6455 --gerd. */
6457 static void
6458 x_draw_bar_cursor (w, row, width, kind)
6459 struct window *w;
6460 struct glyph_row *row;
6461 int width;
6462 enum text_cursor_kinds kind;
6464 struct frame *f = XFRAME (w->frame);
6465 struct glyph *cursor_glyph;
6467 /* If cursor is out of bounds, don't draw garbage. This can happen
6468 in mini-buffer windows when switching between echo area glyphs
6469 and mini-buffer. */
6470 cursor_glyph = get_phys_cursor_glyph (w);
6471 if (cursor_glyph == NULL)
6472 return;
6474 /* If on an image, draw like a normal cursor. That's usually better
6475 visible than drawing a bar, esp. if the image is large so that
6476 the bar might not be in the window. */
6477 if (cursor_glyph->type == IMAGE_GLYPH)
6479 struct glyph_row *row;
6480 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6481 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6483 else
6485 Display *dpy = FRAME_MAC_DISPLAY (f);
6486 Window window = FRAME_MAC_WINDOW (f);
6487 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6488 unsigned long mask = GCForeground | GCBackground;
6489 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
6490 XGCValues xgcv;
6492 /* If the glyph's background equals the color we normally draw
6493 the bar cursor in, the bar cursor in its normal color is
6494 invisible. Use the glyph's foreground color instead in this
6495 case, on the assumption that the glyph's colors are chosen so
6496 that the glyph is legible. */
6497 if (face->background == f->output_data.mac->cursor_pixel)
6498 xgcv.background = xgcv.foreground = face->foreground;
6499 else
6500 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
6502 if (gc)
6503 XChangeGC (dpy, gc, mask, &xgcv);
6504 else
6506 gc = XCreateGC (dpy, window, mask, &xgcv);
6507 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6510 if (width < 0)
6511 width = FRAME_CURSOR_WIDTH (f);
6512 width = min (cursor_glyph->pixel_width, width);
6514 w->phys_cursor_width = width;
6515 x_clip_to_row (w, row, TEXT_AREA, gc);
6517 if (kind == BAR_CURSOR)
6518 mac_fill_rectangle (f, gc,
6519 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6520 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6521 width, row->height);
6522 else
6523 mac_fill_rectangle (f, gc,
6524 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6525 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6526 row->height - width),
6527 cursor_glyph->pixel_width,
6528 width);
6530 mac_reset_clip_rectangles (f, gc);
6535 /* RIF: Define cursor CURSOR on frame F. */
6537 static void
6538 mac_define_frame_cursor (f, cursor)
6539 struct frame *f;
6540 Cursor cursor;
6542 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6544 if (dpyinfo->x_focus_frame == f)
6545 SetThemeCursor (cursor);
6549 /* RIF: Clear area on frame F. */
6551 static void
6552 mac_clear_frame_area (f, x, y, width, height)
6553 struct frame *f;
6554 int x, y, width, height;
6556 mac_clear_area (f, x, y, width, height);
6560 /* RIF: Draw cursor on window W. */
6562 static void
6563 mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
6564 struct window *w;
6565 struct glyph_row *glyph_row;
6566 int x, y;
6567 int cursor_type, cursor_width;
6568 int on_p, active_p;
6570 if (on_p)
6572 w->phys_cursor_type = cursor_type;
6573 w->phys_cursor_on_p = 1;
6575 if (glyph_row->exact_window_width_line_p
6576 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6578 glyph_row->cursor_in_fringe_p = 1;
6579 draw_fringe_bitmap (w, glyph_row, 0);
6581 else
6582 switch (cursor_type)
6584 case HOLLOW_BOX_CURSOR:
6585 x_draw_hollow_cursor (w, glyph_row);
6586 break;
6588 case FILLED_BOX_CURSOR:
6589 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
6590 break;
6592 case BAR_CURSOR:
6593 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6594 break;
6596 case HBAR_CURSOR:
6597 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
6598 break;
6600 case NO_CURSOR:
6601 w->phys_cursor_width = 0;
6602 break;
6604 default:
6605 abort ();
6611 /* Icons. */
6613 #if 0 /* MAC_TODO: no icon support yet. */
6615 x_bitmap_icon (f, icon)
6616 struct frame *f;
6617 Lisp_Object icon;
6619 HANDLE hicon;
6621 if (FRAME_W32_WINDOW (f) == 0)
6622 return 1;
6624 if (NILP (icon))
6625 hicon = LoadIcon (hinst, EMACS_CLASS);
6626 else if (STRINGP (icon))
6627 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
6628 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6629 else if (SYMBOLP (icon))
6631 LPCTSTR name;
6633 if (EQ (icon, intern ("application")))
6634 name = (LPCTSTR) IDI_APPLICATION;
6635 else if (EQ (icon, intern ("hand")))
6636 name = (LPCTSTR) IDI_HAND;
6637 else if (EQ (icon, intern ("question")))
6638 name = (LPCTSTR) IDI_QUESTION;
6639 else if (EQ (icon, intern ("exclamation")))
6640 name = (LPCTSTR) IDI_EXCLAMATION;
6641 else if (EQ (icon, intern ("asterisk")))
6642 name = (LPCTSTR) IDI_ASTERISK;
6643 else if (EQ (icon, intern ("winlogo")))
6644 name = (LPCTSTR) IDI_WINLOGO;
6645 else
6646 return 1;
6648 hicon = LoadIcon (NULL, name);
6650 else
6651 return 1;
6653 if (hicon == NULL)
6654 return 1;
6656 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6657 (LPARAM) hicon);
6659 return 0;
6661 #endif /* MAC_TODO */
6663 /************************************************************************
6664 Handling X errors
6665 ************************************************************************/
6667 /* Display Error Handling functions not used on W32. Listing them here
6668 helps diff stay in step when comparing w32term.c with xterm.c.
6670 x_error_catcher (display, error)
6671 x_catch_errors (dpy)
6672 x_catch_errors_unwind (old_val)
6673 x_check_errors (dpy, format)
6674 x_had_errors_p (dpy)
6675 x_clear_errors (dpy)
6676 x_uncatch_errors (dpy, count)
6677 x_trace_wire ()
6678 x_connection_signal (signalnum)
6679 x_connection_closed (dpy, error_message)
6680 x_error_quitter (display, error)
6681 x_error_handler (display, error)
6682 x_io_error_quitter (display)
6687 /* Changing the font of the frame. */
6689 /* Give frame F the font named FONTNAME as its default font, and
6690 return the full name of that font. FONTNAME may be a wildcard
6691 pattern; in that case, we choose some font that fits the pattern.
6692 The return value shows which font we chose. */
6694 Lisp_Object
6695 x_new_font (f, fontname)
6696 struct frame *f;
6697 register char *fontname;
6699 struct font_info *fontp
6700 = FS_LOAD_FONT (f, fontname);
6702 if (!fontp)
6703 return Qnil;
6705 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
6706 /* This font is already set in frame F. There's nothing more to
6707 do. */
6708 return build_string (fontp->full_name);
6710 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6711 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6712 FRAME_FONTSET (f) = -1;
6714 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6715 FRAME_SPACE_WIDTH (f) = fontp->space_width;
6716 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6718 compute_fringe_widths (f, 1);
6720 /* Compute the scroll bar width in character columns. */
6721 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6723 int wid = FRAME_COLUMN_WIDTH (f);
6724 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6725 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
6727 else
6729 int wid = FRAME_COLUMN_WIDTH (f);
6730 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6733 /* Now make the frame display the given font. */
6734 if (FRAME_MAC_WINDOW (f) != 0)
6736 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
6737 FRAME_FONT (f));
6738 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
6739 FRAME_FONT (f));
6740 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
6741 FRAME_FONT (f));
6743 /* Don't change the size of a tip frame; there's no point in
6744 doing it because it's done in Fx_show_tip, and it leads to
6745 problems because the tip frame has no widget. */
6746 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
6747 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6750 return build_string (fontp->full_name);
6753 /* Give frame F the fontset named FONTSETNAME as its default fontset,
6754 and return the full name of that fontset. FONTSETNAME may be a
6755 wildcard pattern; in that case, we choose some fontset that fits
6756 the pattern. FONTSETNAME may be a font name for ASCII characters;
6757 in that case, we create a fontset from that font name.
6759 The return value shows which fontset we chose.
6760 If FONTSETNAME specifies the default fontset, return Qt.
6761 If an ASCII font in the specified fontset can't be loaded, return
6762 Qnil. */
6764 Lisp_Object
6765 x_new_fontset (f, fontsetname)
6766 struct frame *f;
6767 Lisp_Object fontsetname;
6769 int fontset = fs_query_fontset (fontsetname, 0);
6770 Lisp_Object result;
6772 if (fontset > 0 && FRAME_FONTSET(f) == fontset)
6773 /* This fontset is already set in frame F. There's nothing more
6774 to do. */
6775 return fontset_name (fontset);
6776 else if (fontset == 0)
6777 /* The default fontset can't be the default font. */
6778 return Qt;
6780 if (fontset > 0)
6781 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6782 else
6783 result = x_new_font (f, SDATA (fontsetname));
6785 if (!STRINGP (result))
6786 /* Can't load ASCII font. */
6787 return Qnil;
6789 if (fontset < 0)
6790 fontset = new_fontset_from_font_name (result);
6792 /* Since x_new_font doesn't update any fontset information, do it now. */
6793 FRAME_FONTSET (f) = fontset;
6795 return fontset_name (fontset);
6799 /***********************************************************************
6800 TODO: W32 Input Methods
6801 ***********************************************************************/
6802 /* Listing missing functions from xterm.c helps diff stay in step.
6804 xim_destroy_callback (xim, client_data, call_data)
6805 xim_open_dpy (dpyinfo, resource_name)
6806 struct xim_inst_t
6807 xim_instantiate_callback (display, client_data, call_data)
6808 xim_initialize (dpyinfo, resource_name)
6809 xim_close_dpy (dpyinfo)
6814 void
6815 mac_get_window_bounds (f, inner, outer)
6816 struct frame *f;
6817 Rect *inner, *outer;
6819 #if TARGET_API_MAC_CARBON
6820 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6821 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6822 #else /* not TARGET_API_MAC_CARBON */
6823 RgnHandle region = NewRgn ();
6825 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6826 *inner = (*region)->rgnBBox;
6827 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6828 *outer = (*region)->rgnBBox;
6829 DisposeRgn (region);
6830 #endif /* not TARGET_API_MAC_CARBON */
6833 static void
6834 mac_handle_origin_change (f)
6835 struct frame *f;
6837 x_real_positions (f, &f->left_pos, &f->top_pos);
6840 static void
6841 mac_handle_size_change (f, pixelwidth, pixelheight)
6842 struct frame *f;
6843 int pixelwidth, pixelheight;
6845 int cols, rows;
6847 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6848 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6850 if (cols != FRAME_COLS (f)
6851 || rows != FRAME_LINES (f)
6852 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6853 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6855 /* We pass 1 for DELAY since we can't run Lisp code inside of
6856 a BLOCK_INPUT. */
6857 change_frame_size (f, rows, cols, 0, 1, 0);
6858 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6859 FRAME_PIXEL_HEIGHT (f) = pixelheight;
6861 /* If cursor was outside the new size, mark it as off. */
6862 mark_window_cursors_off (XWINDOW (f->root_window));
6864 /* Clear out any recollection of where the mouse highlighting
6865 was, since it might be in a place that's outside the new
6866 frame size. Actually checking whether it is outside is a
6867 pain in the neck, so don't try--just let the highlighting be
6868 done afresh with new size. */
6869 cancel_mouse_face (f);
6871 #if TARGET_API_MAC_CARBON
6872 if (f->output_data.mac->hourglass_control)
6874 #if USE_CG_DRAWING
6875 mac_prepare_for_quickdraw (f);
6876 #endif
6877 MoveControl (f->output_data.mac->hourglass_control,
6878 pixelwidth - HOURGLASS_WIDTH, 0);
6880 #endif
6885 /* Calculate the absolute position in frame F
6886 from its current recorded position values and gravity. */
6888 void
6889 x_calc_absolute_position (f)
6890 struct frame *f;
6892 int flags = f->size_hint_flags;
6893 Rect inner, outer;
6895 /* We have nothing to do if the current position
6896 is already for the top-left corner. */
6897 if (! ((flags & XNegative) || (flags & YNegative)))
6898 return;
6900 /* Find the offsets of the outside upper-left corner of
6901 the inner window, with respect to the outer window. */
6902 BLOCK_INPUT;
6903 mac_get_window_bounds (f, &inner, &outer);
6904 UNBLOCK_INPUT;
6906 /* Treat negative positions as relative to the leftmost bottommost
6907 position that fits on the screen. */
6908 if (flags & XNegative)
6909 f->left_pos += (FRAME_MAC_DISPLAY_INFO (f)->width
6910 - (outer.right - outer.left));
6912 if (flags & YNegative)
6913 f->top_pos += (FRAME_MAC_DISPLAY_INFO (f)->height
6914 - (outer.bottom - outer.top));
6916 /* The left_pos and top_pos
6917 are now relative to the top and left screen edges,
6918 so the flags should correspond. */
6919 f->size_hint_flags &= ~ (XNegative | YNegative);
6922 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6923 to really change the position, and 0 when calling from
6924 x_make_frame_visible (in that case, XOFF and YOFF are the current
6925 position values). It is -1 when calling from x_set_frame_parameters,
6926 which means, do adjust for borders but don't change the gravity. */
6928 void
6929 x_set_offset (f, xoff, yoff, change_gravity)
6930 struct frame *f;
6931 register int xoff, yoff;
6932 int change_gravity;
6934 if (change_gravity > 0)
6936 f->top_pos = yoff;
6937 f->left_pos = xoff;
6938 f->size_hint_flags &= ~ (XNegative | YNegative);
6939 if (xoff < 0)
6940 f->size_hint_flags |= XNegative;
6941 if (yoff < 0)
6942 f->size_hint_flags |= YNegative;
6943 f->win_gravity = NorthWestGravity;
6945 x_calc_absolute_position (f);
6947 BLOCK_INPUT;
6948 x_wm_set_size_hint (f, (long) 0, 0);
6950 #if TARGET_API_MAC_CARBON
6951 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6952 /* If the title bar is completely outside the screen, adjust the
6953 position. */
6954 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6955 kWindowConstrainMoveRegardlessOfFit
6956 | kWindowConstrainAllowPartial, NULL, NULL);
6957 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
6958 mac_handle_origin_change (f);
6959 #else
6961 Rect inner, outer, screen_rect, dummy;
6962 RgnHandle region = NewRgn ();
6964 mac_get_window_bounds (f, &inner, &outer);
6965 f->x_pixels_diff = inner.left - outer.left;
6966 f->y_pixels_diff = inner.top - outer.top;
6967 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6968 f->top_pos + f->y_pixels_diff, false);
6970 /* If the title bar is completely outside the screen, adjust the
6971 position. The variable `outer' holds the title bar rectangle.
6972 The variable `inner' holds slightly smaller one than `outer',
6973 so that the calculation of overlapping may not become too
6974 strict. */
6975 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6976 outer = (*region)->rgnBBox;
6977 DisposeRgn (region);
6978 inner = outer;
6979 InsetRect (&inner, 8, 8);
6980 screen_rect = qd.screenBits.bounds;
6981 screen_rect.top += GetMBarHeight ();
6983 if (!SectRect (&inner, &screen_rect, &dummy))
6985 if (inner.right <= screen_rect.left)
6986 f->left_pos = screen_rect.left;
6987 else if (inner.left >= screen_rect.right)
6988 f->left_pos = screen_rect.right - (outer.right - outer.left);
6990 if (inner.bottom <= screen_rect.top)
6991 f->top_pos = screen_rect.top;
6992 else if (inner.top >= screen_rect.bottom)
6993 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6995 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6996 f->top_pos + f->y_pixels_diff, false);
6999 #endif
7001 UNBLOCK_INPUT;
7004 /* Call this to change the size of frame F's x-window.
7005 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
7006 for this size change and subsequent size changes.
7007 Otherwise we leave the window gravity unchanged. */
7009 void
7010 x_set_window_size (f, change_gravity, cols, rows)
7011 struct frame *f;
7012 int change_gravity;
7013 int cols, rows;
7015 int pixelwidth, pixelheight;
7017 BLOCK_INPUT;
7019 check_frame_size (f, &rows, &cols);
7020 f->scroll_bar_actual_width
7021 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
7023 compute_fringe_widths (f, 0);
7025 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
7026 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
7028 f->win_gravity = NorthWestGravity;
7029 x_wm_set_size_hint (f, (long) 0, 0);
7031 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
7033 #if TARGET_API_MAC_CARBON
7034 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
7035 #endif
7036 mac_handle_size_change (f, pixelwidth, pixelheight);
7038 if (f->output_data.mac->internal_border_width
7039 != FRAME_INTERNAL_BORDER_WIDTH (f))
7041 mac_clear_window (f);
7042 f->output_data.mac->internal_border_width
7043 = FRAME_INTERNAL_BORDER_WIDTH (f);
7046 SET_FRAME_GARBAGED (f);
7048 UNBLOCK_INPUT;
7051 /* Mouse warping. */
7053 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
7055 void
7056 x_set_mouse_position (f, x, y)
7057 struct frame *f;
7058 int x, y;
7060 int pix_x, pix_y;
7062 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
7063 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
7065 if (pix_x < 0) pix_x = 0;
7066 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
7068 if (pix_y < 0) pix_y = 0;
7069 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
7071 x_set_mouse_pixel_position (f, pix_x, pix_y);
7074 void
7075 x_set_mouse_pixel_position (f, pix_x, pix_y)
7076 struct frame *f;
7077 int pix_x, pix_y;
7079 #ifdef MAC_OSX
7080 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
7081 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
7083 BLOCK_INPUT;
7084 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
7085 UNBLOCK_INPUT;
7086 #else
7087 #if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
7088 BLOCK_INPUT;
7090 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
7091 0, 0, 0, 0, pix_x, pix_y);
7092 UNBLOCK_INPUT;
7093 #endif
7094 #endif
7097 /* focus shifting, raising and lowering. */
7099 void
7100 x_focus_on_frame (f)
7101 struct frame *f;
7103 #if 0 /* This proves to be unpleasant. */
7104 x_raise_frame (f);
7105 #endif
7106 #if 0
7107 /* I don't think that the ICCCM allows programs to do things like this
7108 without the interaction of the window manager. Whatever you end up
7109 doing with this code, do it to x_unfocus_frame too. */
7110 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7111 RevertToPointerRoot, CurrentTime);
7112 #endif /* ! 0 */
7115 void
7116 x_unfocus_frame (f)
7117 struct frame *f;
7121 /* Raise frame F. */
7123 void
7124 x_raise_frame (f)
7125 struct frame *f;
7127 if (f->async_visible)
7129 BLOCK_INPUT;
7130 BringToFront (FRAME_MAC_WINDOW (f));
7131 UNBLOCK_INPUT;
7135 /* Lower frame F. */
7137 void
7138 x_lower_frame (f)
7139 struct frame *f;
7141 if (f->async_visible)
7143 BLOCK_INPUT;
7144 SendBehind (FRAME_MAC_WINDOW (f), NULL);
7145 UNBLOCK_INPUT;
7149 static void
7150 XTframe_raise_lower (f, raise_flag)
7151 FRAME_PTR f;
7152 int raise_flag;
7154 if (raise_flag)
7155 x_raise_frame (f);
7156 else
7157 x_lower_frame (f);
7160 /* Change of visibility. */
7162 static void
7163 mac_handle_visibility_change (f)
7164 struct frame *f;
7166 WindowRef wp = FRAME_MAC_WINDOW (f);
7167 int visible = 0, iconified = 0;
7168 struct input_event buf;
7170 if (IsWindowVisible (wp))
7172 if (IsWindowCollapsed (wp))
7173 iconified = 1;
7174 else
7175 visible = 1;
7178 if (!f->async_visible && visible)
7180 if (f->iconified)
7182 /* wait_reading_process_output will notice this and update
7183 the frame's display structures. If we were made
7184 invisible, we should not set garbaged, because that stops
7185 redrawing on Update events. */
7186 SET_FRAME_GARBAGED (f);
7188 EVENT_INIT (buf);
7189 buf.kind = DEICONIFY_EVENT;
7190 XSETFRAME (buf.frame_or_window, f);
7191 buf.arg = Qnil;
7192 kbd_buffer_store_event (&buf);
7194 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7195 /* Force a redisplay sooner or later to update the
7196 frame titles in case this is the second frame. */
7197 record_asynch_buffer_change ();
7199 else if (f->async_visible && !visible)
7200 if (iconified)
7202 EVENT_INIT (buf);
7203 buf.kind = ICONIFY_EVENT;
7204 XSETFRAME (buf.frame_or_window, f);
7205 buf.arg = Qnil;
7206 kbd_buffer_store_event (&buf);
7209 f->async_visible = visible;
7210 f->async_iconified = iconified;
7213 /* This tries to wait until the frame is really visible.
7214 However, if the window manager asks the user where to position
7215 the frame, this will return before the user finishes doing that.
7216 The frame will not actually be visible at that time,
7217 but it will become visible later when the window manager
7218 finishes with it. */
7220 void
7221 x_make_frame_visible (f)
7222 struct frame *f;
7224 BLOCK_INPUT;
7226 if (! FRAME_VISIBLE_P (f))
7228 /* We test FRAME_GARBAGED_P here to make sure we don't
7229 call x_set_offset a second time
7230 if we get to x_make_frame_visible a second time
7231 before the window gets really visible. */
7232 if (! FRAME_ICONIFIED_P (f)
7233 && ! f->output_data.mac->asked_for_visible)
7234 x_set_offset (f, f->left_pos, f->top_pos, 0);
7236 f->output_data.mac->asked_for_visible = 1;
7238 CollapseWindow (FRAME_MAC_WINDOW (f), false);
7239 ShowWindow (FRAME_MAC_WINDOW (f));
7242 XFlush (FRAME_MAC_DISPLAY (f));
7244 /* Synchronize to ensure Emacs knows the frame is visible
7245 before we do anything else. We do this loop with input not blocked
7246 so that incoming events are handled. */
7248 Lisp_Object frame;
7249 int count;
7251 /* This must come after we set COUNT. */
7252 UNBLOCK_INPUT;
7254 XSETFRAME (frame, f);
7256 /* Wait until the frame is visible. Process X events until a
7257 MapNotify event has been seen, or until we think we won't get a
7258 MapNotify at all.. */
7259 for (count = input_signal_count + 10;
7260 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7262 /* Force processing of queued events. */
7263 x_sync (f);
7265 /* Machines that do polling rather than SIGIO have been
7266 observed to go into a busy-wait here. So we'll fake an
7267 alarm signal to let the handler know that there's something
7268 to be read. We used to raise a real alarm, but it seems
7269 that the handler isn't always enabled here. This is
7270 probably a bug. */
7271 if (input_polling_used ())
7273 /* It could be confusing if a real alarm arrives while
7274 processing the fake one. Turn it off and let the
7275 handler reset it. */
7276 extern void poll_for_input_1 P_ ((void));
7277 int old_poll_suppress_count = poll_suppress_count;
7278 poll_suppress_count = 1;
7279 poll_for_input_1 ();
7280 poll_suppress_count = old_poll_suppress_count;
7283 /* See if a MapNotify event has been processed. */
7284 FRAME_SAMPLE_VISIBILITY (f);
7289 /* Change from mapped state to withdrawn state. */
7291 /* Make the frame visible (mapped and not iconified). */
7293 void
7294 x_make_frame_invisible (f)
7295 struct frame *f;
7297 /* A deactivate event does not occur when the last visible frame is
7298 made invisible. So if we clear the highlight here, it will not
7299 be rehighlighted when it is made visible. */
7300 #if 0
7301 /* Don't keep the highlight on an invisible frame. */
7302 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7303 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7304 #endif
7306 BLOCK_INPUT;
7308 #if !TARGET_API_MAC_CARBON
7309 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7310 that the current position of the window is user-specified, rather than
7311 program-specified, so that when the window is mapped again, it will be
7312 placed at the same location, without forcing the user to position it
7313 by hand again (they have already done that once for this window.) */
7314 x_wm_set_size_hint (f, (long) 0, 1);
7315 #endif
7317 HideWindow (FRAME_MAC_WINDOW (f));
7319 UNBLOCK_INPUT;
7321 #if !TARGET_API_MAC_CARBON
7322 mac_handle_visibility_change (f);
7323 #endif
7326 /* Change window state from mapped to iconified. */
7328 void
7329 x_iconify_frame (f)
7330 struct frame *f;
7332 OSStatus err;
7334 /* A deactivate event does not occur when the last visible frame is
7335 iconified. So if we clear the highlight here, it will not be
7336 rehighlighted when it is deiconified. */
7337 #if 0
7338 /* Don't keep the highlight on an invisible frame. */
7339 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7340 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7341 #endif
7343 if (f->async_iconified)
7344 return;
7346 BLOCK_INPUT;
7348 FRAME_SAMPLE_VISIBILITY (f);
7350 if (! FRAME_VISIBLE_P (f))
7351 ShowWindow (FRAME_MAC_WINDOW (f));
7353 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
7355 UNBLOCK_INPUT;
7357 if (err != noErr)
7358 error ("Can't notify window manager of iconification");
7360 #if !TARGET_API_MAC_CARBON
7361 mac_handle_visibility_change (f);
7362 #endif
7366 /* Free X resources of frame F. */
7368 void
7369 x_free_frame_resources (f)
7370 struct frame *f;
7372 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7373 WindowRef wp = FRAME_MAC_WINDOW (f);
7375 BLOCK_INPUT;
7377 if (wp != tip_window)
7378 remove_window_handler (wp);
7380 #if USE_CG_DRAWING
7381 mac_prepare_for_quickdraw (f);
7382 #endif
7383 DisposeWindow (wp);
7384 if (wp == tip_window)
7385 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7386 closed' event. So we reset tip_window here. */
7387 tip_window = NULL;
7389 free_frame_menubar (f);
7391 if (FRAME_FACE_CACHE (f))
7392 free_frame_faces (f);
7394 x_free_gcs (f);
7396 if (FRAME_SIZE_HINTS (f))
7397 xfree (FRAME_SIZE_HINTS (f));
7399 xfree (f->output_data.mac);
7400 f->output_data.mac = NULL;
7402 if (f == dpyinfo->x_focus_frame)
7404 dpyinfo->x_focus_frame = 0;
7405 #if USE_MAC_FONT_PANEL
7406 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7407 #endif
7409 if (f == dpyinfo->x_focus_event_frame)
7410 dpyinfo->x_focus_event_frame = 0;
7411 if (f == dpyinfo->x_highlight_frame)
7412 dpyinfo->x_highlight_frame = 0;
7414 if (f == dpyinfo->mouse_face_mouse_frame)
7416 dpyinfo->mouse_face_beg_row
7417 = dpyinfo->mouse_face_beg_col = -1;
7418 dpyinfo->mouse_face_end_row
7419 = dpyinfo->mouse_face_end_col = -1;
7420 dpyinfo->mouse_face_window = Qnil;
7421 dpyinfo->mouse_face_deferred_gc = 0;
7422 dpyinfo->mouse_face_mouse_frame = 0;
7425 UNBLOCK_INPUT;
7429 /* Destroy the X window of frame F. */
7431 void
7432 x_destroy_window (f)
7433 struct frame *f;
7435 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7437 x_free_frame_resources (f);
7439 dpyinfo->reference_count--;
7443 /* Setting window manager hints. */
7445 /* Set the normal size hints for the window manager, for frame F.
7446 FLAGS is the flags word to use--or 0 meaning preserve the flags
7447 that the window now has.
7448 If USER_POSITION is nonzero, we set the USPosition
7449 flag (this is useful when FLAGS is 0). */
7450 void
7451 x_wm_set_size_hint (f, flags, user_position)
7452 struct frame *f;
7453 long flags;
7454 int user_position;
7456 int base_width, base_height, width_inc, height_inc;
7457 int min_rows = 0, min_cols = 0;
7458 XSizeHints *size_hints;
7460 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7461 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7462 width_inc = FRAME_COLUMN_WIDTH (f);
7463 height_inc = FRAME_LINE_HEIGHT (f);
7465 check_frame_size (f, &min_rows, &min_cols);
7467 size_hints = FRAME_SIZE_HINTS (f);
7468 if (size_hints == NULL)
7470 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7471 bzero (size_hints, sizeof (XSizeHints));
7474 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7475 size_hints->width_inc = width_inc;
7476 size_hints->height_inc = height_inc;
7477 size_hints->min_width = base_width + min_cols * width_inc;
7478 size_hints->min_height = base_height + min_rows * height_inc;
7479 size_hints->base_width = base_width;
7480 size_hints->base_height = base_height;
7482 if (flags)
7483 size_hints->flags = flags;
7484 else if (user_position)
7486 size_hints->flags &= ~ PPosition;
7487 size_hints->flags |= USPosition;
7491 #if 0 /* MAC_TODO: hide application instead of iconify? */
7492 /* Used for IconicState or NormalState */
7494 void
7495 x_wm_set_window_state (f, state)
7496 struct frame *f;
7497 int state;
7499 #ifdef USE_X_TOOLKIT
7500 Arg al[1];
7502 XtSetArg (al[0], XtNinitialState, state);
7503 XtSetValues (f->output_data.x->widget, al, 1);
7504 #else /* not USE_X_TOOLKIT */
7505 Window window = FRAME_X_WINDOW (f);
7507 f->output_data.x->wm_hints.flags |= StateHint;
7508 f->output_data.x->wm_hints.initial_state = state;
7510 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7511 #endif /* not USE_X_TOOLKIT */
7514 void
7515 x_wm_set_icon_pixmap (f, pixmap_id)
7516 struct frame *f;
7517 int pixmap_id;
7519 Pixmap icon_pixmap;
7521 #ifndef USE_X_TOOLKIT
7522 Window window = FRAME_X_WINDOW (f);
7523 #endif
7525 if (pixmap_id > 0)
7527 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7528 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7530 else
7532 /* It seems there is no way to turn off use of an icon pixmap.
7533 The following line does it, only if no icon has yet been created,
7534 for some window managers. But with mwm it crashes.
7535 Some people say it should clear the IconPixmapHint bit in this case,
7536 but that doesn't work, and the X consortium said it isn't the
7537 right thing at all. Since there is no way to win,
7538 best to explicitly give up. */
7539 #if 0
7540 f->output_data.x->wm_hints.icon_pixmap = None;
7541 #else
7542 return;
7543 #endif
7546 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7549 Arg al[1];
7550 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7551 XtSetValues (f->output_data.x->widget, al, 1);
7554 #else /* not USE_X_TOOLKIT */
7556 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7557 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7559 #endif /* not USE_X_TOOLKIT */
7562 #endif /* MAC_TODO */
7564 void
7565 x_wm_set_icon_position (f, icon_x, icon_y)
7566 struct frame *f;
7567 int icon_x, icon_y;
7569 #if 0 /* MAC_TODO: no icons on Mac */
7570 #ifdef USE_X_TOOLKIT
7571 Window window = XtWindow (f->output_data.x->widget);
7572 #else
7573 Window window = FRAME_X_WINDOW (f);
7574 #endif
7576 f->output_data.x->wm_hints.flags |= IconPositionHint;
7577 f->output_data.x->wm_hints.icon_x = icon_x;
7578 f->output_data.x->wm_hints.icon_y = icon_y;
7580 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7581 #endif /* MAC_TODO */
7585 /***********************************************************************
7586 XLFD Pattern Match
7587 ***********************************************************************/
7589 /* An XLFD pattern is divided into blocks delimited by '*'. This
7590 structure holds information for each block. */
7591 struct xlfdpat_block
7593 /* Length of the pattern string in this block. Non-zero except for
7594 the first and the last blocks. */
7595 int len;
7597 /* Pattern string except the last character in this block. The last
7598 character is replaced with NUL in order to use it as a
7599 sentinel. */
7600 unsigned char *pattern;
7602 /* Last character of the pattern string. Must not be '?'. */
7603 unsigned char last_char;
7605 /* One of the tables for the Boyer-Moore string search. It
7606 specifies the number of positions to proceed for each character
7607 with which the match fails. */
7608 int skip[256];
7610 /* The skip value for the last character in the above `skip' is
7611 assigned to `infinity' in order to simplify a loop condition.
7612 The original value is saved here. */
7613 int last_char_skip;
7616 struct xlfdpat
7618 /* Normalized pattern string. "Normalized" means that capital
7619 letters are lowered, blocks are not empty except the first and
7620 the last ones, and trailing '?'s in a block that is not the last
7621 one are moved to the next one. The last character in each block
7622 is replaced with NUL. */
7623 unsigned char *buf;
7625 /* Number of characters except '*'s and trailing '?'s in the
7626 normalized pattern string. */
7627 int nchars;
7629 /* Number of trailing '?'s in the normalized pattern string. */
7630 int trailing_anychars;
7632 /* Number of blocks and information for each block. The latter is
7633 NULL if the pattern is exact (no '*' or '?' in it). */
7634 int nblocks;
7635 struct xlfdpat_block *blocks;
7638 static void
7639 xlfdpat_destroy (pat)
7640 struct xlfdpat *pat;
7642 if (pat)
7644 if (pat->buf)
7646 if (pat->blocks)
7647 xfree (pat->blocks);
7648 xfree (pat->buf);
7650 xfree (pat);
7654 static struct xlfdpat *
7655 xlfdpat_create (pattern)
7656 const char *pattern;
7658 struct xlfdpat *pat;
7659 int nblocks, i, skip;
7660 unsigned char last_char, *p, *q, *anychar_head;
7661 const unsigned char *ptr;
7662 struct xlfdpat_block *blk;
7664 pat = xmalloc (sizeof (struct xlfdpat));
7665 pat->buf = xmalloc (strlen (pattern) + 1);
7667 /* Normalize the pattern string and store it to `pat->buf'. */
7668 nblocks = 0;
7669 anychar_head = NULL;
7670 q = pat->buf;
7671 last_char = '\0';
7672 for (ptr = pattern; *ptr; ptr++)
7674 unsigned char c = *ptr;
7676 if (c == '*')
7677 if (last_char == '*')
7678 /* ...a** -> ...a* */
7679 continue;
7680 else
7682 if (last_char == '?')
7684 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7685 /* ...*??* -> ...*?? */
7686 continue;
7687 else
7688 /* ...a??* -> ...a*?? */
7690 *anychar_head++ = '*';
7691 c = '?';
7694 nblocks++;
7696 else if (c == '?')
7698 if (last_char != '?')
7699 anychar_head = q;
7701 else
7702 /* On Mac OS X 10.3, tolower also converts non-ASCII
7703 characters for some locales. */
7704 if (isascii (c))
7705 c = tolower (c);
7707 *q++ = last_char = c;
7709 *q = '\0';
7710 nblocks++;
7711 pat->nblocks = nblocks;
7712 if (last_char != '?')
7713 pat->trailing_anychars = 0;
7714 else
7716 pat->trailing_anychars = q - anychar_head;
7717 q = anychar_head;
7719 pat->nchars = q - pat->buf - (nblocks - 1);
7721 if (anychar_head == NULL && nblocks == 1)
7723 /* The pattern is exact. */
7724 pat->blocks = NULL;
7725 return pat;
7728 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
7730 /* Divide the normalized pattern into blocks. */
7731 p = pat->buf;
7732 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7734 blk->pattern = p;
7735 while (*p != '*')
7736 p++;
7737 blk->len = p - blk->pattern;
7738 p++;
7740 blk->pattern = p;
7741 blk->len = q - blk->pattern;
7743 /* Setup a table for the Boyer-Moore string search. */
7744 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7745 if (blk->len != 0)
7747 blk->last_char = blk->pattern[blk->len - 1];
7748 blk->pattern[blk->len - 1] = '\0';
7750 for (skip = 1; skip < blk->len; skip++)
7751 if (blk->pattern[blk->len - skip - 1] == '?')
7752 break;
7754 for (i = 0; i < 256; i++)
7755 blk->skip[i] = skip;
7757 p = blk->pattern + (blk->len - skip);
7758 while (--skip > 0)
7759 blk->skip[*p++] = skip;
7761 blk->last_char_skip = blk->skip[blk->last_char];
7764 return pat;
7767 static INLINE int
7768 xlfdpat_exact_p (pat)
7769 struct xlfdpat *pat;
7771 return pat->blocks == NULL;
7774 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
7775 that the pattern in *BLK matches with its prefix. Return NULL
7776 there is no such strings. STRING must be lowered in advance. */
7778 static const char *
7779 xlfdpat_block_match_1 (blk, string, start_max)
7780 struct xlfdpat_block *blk;
7781 const unsigned char *string;
7782 int start_max;
7784 int start, infinity;
7785 unsigned char *p;
7786 const unsigned char *s;
7788 xassert (blk->len > 0);
7789 xassert (start_max + blk->len <= strlen (string));
7790 xassert (blk->last_char != '?');
7792 /* See the comments in the function `boyer_moore' (search.c) for the
7793 use of `infinity'. */
7794 infinity = start_max + blk->len + 1;
7795 blk->skip[blk->last_char] = infinity;
7797 start = 0;
7800 /* Check the last character of the pattern. */
7801 s = string + blk->len - 1;
7804 start += blk->skip[*(s + start)];
7806 while (start <= start_max);
7808 if (start < infinity)
7809 /* Couldn't find the last character. */
7810 return NULL;
7812 /* No less than `infinity' means we could find the last
7813 character at `s[start - infinity]'. */
7814 start -= infinity;
7816 /* Check the remaining characters. We prefer making no-'?'
7817 cases faster because the use of '?' is really rare. */
7818 p = blk->pattern;
7819 s = string + start;
7822 while (*p++ == *s++)
7825 while (*(p - 1) == '?');
7827 if (*(p - 1) == '\0')
7828 /* Matched. */
7829 return string + start;
7831 /* Didn't match. */
7832 start += blk->last_char_skip;
7834 while (start <= start_max);
7836 return NULL;
7839 #define xlfdpat_block_match(b, s, m) \
7840 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7841 : xlfdpat_block_match_1 (b, s, m))
7843 /* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
7844 matches with STRING. STRING must be lowered in advance. */
7846 static int
7847 xlfdpat_match (pat, string)
7848 struct xlfdpat *pat;
7849 const unsigned char *string;
7851 int str_len, nblocks, i, start_max;
7852 struct xlfdpat_block *blk;
7853 const unsigned char *s;
7855 xassert (pat->nblocks > 0);
7857 if (xlfdpat_exact_p (pat))
7858 return strcmp (pat->buf, string) == 0;
7860 /* The number of the characters in the string must not be smaller
7861 than that in the pattern. */
7862 str_len = strlen (string);
7863 if (str_len < pat->nchars + pat->trailing_anychars)
7864 return 0;
7866 /* Chop off the trailing '?'s. */
7867 str_len -= pat->trailing_anychars;
7869 /* The last block. When it is non-empty, it must match at the end
7870 of the string. */
7871 nblocks = pat->nblocks;
7872 blk = pat->blocks + (nblocks - 1);
7873 if (nblocks == 1)
7874 /* The last block is also the first one. */
7875 return (str_len == blk->len
7876 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7877 else if (blk->len != 0)
7878 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7879 return 0;
7881 /* The first block. When it is non-empty, it must match at the
7882 beginning of the string. */
7883 blk = pat->blocks;
7884 if (blk->len != 0)
7886 s = xlfdpat_block_match (blk, string, 0);
7887 if (s == NULL)
7888 return 0;
7889 string = s + blk->len;
7892 /* The rest of the blocks. */
7893 start_max = str_len - pat->nchars;
7894 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7896 s = xlfdpat_block_match (blk, string, start_max);
7897 if (s == NULL)
7898 return 0;
7899 start_max -= s - string;
7900 string = s + blk->len;
7903 return 1;
7907 /***********************************************************************
7908 Fonts
7909 ***********************************************************************/
7911 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7913 struct font_info *
7914 x_get_font_info (f, font_idx)
7915 FRAME_PTR f;
7916 int font_idx;
7918 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7921 /* the global font name table */
7922 static char **font_name_table = NULL;
7923 static int font_name_table_size = 0;
7924 static int font_name_count = 0;
7926 /* Alist linking font family names to Font Manager font family
7927 references (which can also be used as QuickDraw font IDs). We use
7928 an alist because hash tables are not ready when the terminal frame
7929 for Mac OS Classic is created. */
7930 static Lisp_Object fm_font_family_alist;
7931 #if USE_ATSUI
7932 /* Hash table linking font family names to ATSU font IDs. */
7933 static Lisp_Object atsu_font_id_hash;
7934 /* Alist linking Font Manager style to face attributes. */
7935 static Lisp_Object fm_style_face_attributes_alist;
7936 extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
7937 #endif
7939 /* Alist linking character set strings to Mac text encoding and Emacs
7940 coding system. */
7941 static Lisp_Object Vmac_charset_info_alist;
7943 static Lisp_Object
7944 create_text_encoding_info_alist ()
7946 Lisp_Object result = Qnil, rest;
7948 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7950 Lisp_Object charset_info = XCAR (rest);
7951 Lisp_Object charset, coding_system, text_encoding;
7952 Lisp_Object existing_info;
7954 if (!(CONSP (charset_info)
7955 && (charset = XCAR (charset_info),
7956 STRINGP (charset))
7957 && CONSP (XCDR (charset_info))
7958 && (text_encoding = XCAR (XCDR (charset_info)),
7959 INTEGERP (text_encoding))
7960 && CONSP (XCDR (XCDR (charset_info)))
7961 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7962 SYMBOLP (coding_system))))
7963 continue;
7965 existing_info = assq_no_quit (text_encoding, result);
7966 if (NILP (existing_info))
7967 result = Fcons (list3 (text_encoding, coding_system, charset),
7968 result);
7969 else
7970 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7971 XSETCDR (XCDR (existing_info),
7972 Fcons (charset, XCDR (XCDR (existing_info))));
7975 return result;
7979 static void
7980 decode_mac_font_name (name, size, coding_system)
7981 char *name;
7982 int size;
7983 Lisp_Object coding_system;
7985 struct coding_system coding;
7986 char *buf, *p;
7988 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7990 for (p = name; *p; p++)
7991 if (!isascii (*p) || iscntrl (*p))
7992 break;
7994 if (*p)
7996 setup_coding_system (coding_system, &coding);
7997 coding.src_multibyte = 0;
7998 coding.dst_multibyte = 1;
7999 coding.mode |= CODING_MODE_LAST_BLOCK;
8000 coding.dst_bytes = size;
8001 coding.destination = (unsigned char *) alloca (coding.dst_bytes);
8003 decode_coding_c_string (&coding, name, strlen (name), Qnil);
8004 bcopy (coding.destination, name, min (coding.produced, size));
8005 name[min (coding.produced, size)] = '\0';
8009 /* If there's just one occurrence of '-' in the family name, it is
8010 replaced with '_'. (More than one occurrence of '-' means a
8011 "FOUNDRY-FAMILY-CHARSET"-style name.) */
8012 p = strchr (name, '-');
8013 if (p && strchr (p + 1, '-') == NULL)
8014 *p = '_';
8016 for (p = name; *p; p++)
8017 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8018 for some locales. */
8019 if (isascii (*p))
8020 *p = tolower (*p);
8024 static char *
8025 mac_to_x_fontname (name, size, style, charset)
8026 const char *name;
8027 int size;
8028 Style style;
8029 char *charset;
8031 Str31 foundry, cs;
8032 Str255 family;
8033 char xf[256], *result;
8034 unsigned char *p;
8036 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
8037 charset = cs;
8038 else
8040 strcpy(foundry, "Apple");
8041 strcpy(family, name);
8044 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
8045 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
8046 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
8048 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
8049 sprintf (result, "-%s-%s-%s", foundry, family, xf);
8050 for (p = result; *p; p++)
8051 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8052 for some locales. */
8053 if (isascii (*p))
8054 *p = tolower (*p);
8055 return result;
8059 /* Parse fully-specified and instantiated X11 font spec XF, and store
8060 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
8061 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
8062 caller must allocate at least 256 and 32 bytes respectively. For
8063 ordinary Mac fonts, the value stored to FAMILY should just be their
8064 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
8065 intlfonts collection contain their charset designation in their
8066 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
8067 types of font names are handled accordingly. */
8069 const int kDefaultFontSize = 12;
8071 static int
8072 parse_x_font_name (xf, family, size, style, charset)
8073 const char *xf;
8074 char *family;
8075 int *size;
8076 Style *style;
8077 char *charset;
8079 Str31 foundry, weight;
8080 int point_size, avgwidth;
8081 char slant[2], *p;
8083 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8084 foundry, family, weight, slant, size,
8085 &point_size, &avgwidth, charset) != 8
8086 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8087 foundry, family, weight, slant, size,
8088 &point_size, &avgwidth, charset) != 8)
8089 return 0;
8091 if (*size == 0)
8093 if (point_size > 0)
8094 *size = point_size / 10;
8095 else if (avgwidth > 0)
8096 *size = avgwidth / 10;
8098 if (*size == 0)
8099 *size = kDefaultFontSize;
8101 *style = normal;
8102 if (strcmp (weight, "bold") == 0)
8103 *style |= bold;
8104 if (*slant == 'i')
8105 *style |= italic;
8107 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
8109 int foundry_len = strlen (foundry), family_len = strlen (family);
8111 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
8113 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
8114 but take overlap into account. */
8115 memmove (family + foundry_len + 1, family, family_len);
8116 memcpy (family, foundry, foundry_len);
8117 family[foundry_len] = '-';
8118 family[foundry_len + 1 + family_len] = '-';
8119 strcpy (family + foundry_len + 1 + family_len + 1, charset);
8121 else
8122 return 0;
8125 for (p = family; *p; p++)
8126 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8127 for some locales. */
8128 if (isascii (*p))
8129 *p = tolower (*p);
8131 return 1;
8135 static void
8136 add_font_name_table_entry (char *font_name)
8138 if (font_name_table_size == 0)
8140 font_name_table_size = 256;
8141 font_name_table = (char **)
8142 xmalloc (font_name_table_size * sizeof (char *));
8144 else if (font_name_count + 1 >= font_name_table_size)
8146 font_name_table_size *= 2;
8147 font_name_table = (char **)
8148 xrealloc (font_name_table,
8149 font_name_table_size * sizeof (char *));
8152 font_name_table[font_name_count++] = font_name;
8155 static void
8156 add_mac_font_name (name, size, style, charset)
8157 const char *name;
8158 int size;
8159 Style style;
8160 const char *charset;
8162 if (size > 0)
8163 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8164 else
8166 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8167 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8168 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8169 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8170 charset));
8174 #if USE_ATSUI
8175 static FMFontStyle
8176 fm_get_style_from_font (font)
8177 FMFont font;
8179 OSStatus err;
8180 FMFontStyle style = normal;
8181 ByteCount len;
8182 UInt16 mac_style;
8183 FMFontFamily font_family;
8184 #define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8186 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8187 some font (e.g., Optima) even if it is `bold'. */
8188 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8189 sizeof (mac_style), &mac_style, &len);
8190 if (err == noErr
8191 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8192 style = EndianU16_BtoN (mac_style);
8193 else
8194 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8196 return style;
8199 static ATSUFontID
8200 atsu_find_font_from_family_name (family)
8201 const char *family;
8203 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8204 unsigned hash_code;
8205 int i;
8206 Lisp_Object rest, best;
8207 FMFontStyle min_style, style;
8209 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8210 &hash_code);
8211 if (i < 0)
8212 return kATSUInvalidFontID;
8214 rest = HASH_VALUE (h, i);
8215 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8216 return cons_to_long (rest);
8218 rest = Fnreverse (rest);
8219 best = XCAR (rest);
8220 rest = XCDR (rest);
8221 if (!NILP (rest)
8222 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8225 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8226 if (style < min_style)
8228 best = XCAR (rest);
8229 if (style == normal)
8230 break;
8231 else
8232 min_style = style;
8234 rest = XCDR (rest);
8236 while (!NILP (rest));
8238 HASH_VALUE (h, i) = best;
8239 return cons_to_long (best);
8242 static Lisp_Object
8243 fm_style_to_face_attributes (fm_style)
8244 FMFontStyle fm_style;
8246 Lisp_Object tem;
8248 fm_style &= (bold | italic);
8249 tem = assq_no_quit (make_number (fm_style),
8250 fm_style_face_attributes_alist);
8251 if (!NILP (tem))
8252 return XCDR (tem);
8254 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8255 QCslant, fm_style & italic ? Qitalic : Qnormal);
8256 fm_style_face_attributes_alist =
8257 Fcons (Fcons (make_number (fm_style), tem),
8258 fm_style_face_attributes_alist);
8260 return tem;
8263 static Lisp_Object
8264 atsu_find_font_family_name (font_id)
8265 ATSUFontID font_id;
8267 OSStatus err;
8268 ByteCount len;
8269 Lisp_Object family = Qnil;
8271 err = ATSUFindFontName (font_id, kFontFamilyName,
8272 kFontMacintoshPlatform, kFontNoScript,
8273 kFontNoLanguage, 0, NULL, &len, NULL);
8274 if (err == noErr)
8276 family = make_uninit_string (len);
8277 err = ATSUFindFontName (font_id, kFontFamilyName,
8278 kFontMacintoshPlatform, kFontNoScript,
8279 kFontNoLanguage, len, SDATA (family),
8280 NULL, NULL);
8282 if (err == noErr)
8283 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8285 return family;
8288 Lisp_Object
8289 mac_atsu_font_face_attributes (font_id)
8290 ATSUFontID font_id;
8292 Lisp_Object family, style_attrs;
8294 family = atsu_find_font_family_name (font_id);
8295 if (NILP (family))
8296 return Qnil;
8297 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8298 return Fcons (QCfamily, Fcons (family, style_attrs));
8300 #endif
8302 /* Sets up the table font_name_table to contain the list of all fonts
8303 in the system the first time the table is used so that the Resource
8304 Manager need not be accessed every time this information is
8305 needed. */
8307 static void
8308 init_font_name_table ()
8310 #if TARGET_API_MAC_CARBON
8311 FMFontFamilyIterator ffi;
8312 FMFontFamilyInstanceIterator ffii;
8313 FMFontFamily ff;
8314 Lisp_Object text_encoding_info_alist;
8315 struct gcpro gcpro1;
8317 text_encoding_info_alist = create_text_encoding_info_alist ();
8319 #if USE_ATSUI
8320 #if USE_CG_TEXT_DRAWING
8321 init_cg_text_anti_aliasing_threshold ();
8322 #endif
8323 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8324 text_encoding_info_alist)))
8326 OSStatus err;
8327 struct Lisp_Hash_Table *h;
8328 unsigned hash_code;
8329 ItemCount nfonts, i;
8330 ATSUFontID *font_ids = NULL;
8331 Lisp_Object prev_family = Qnil;
8332 int j;
8334 atsu_font_id_hash =
8335 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8336 make_float (DEFAULT_REHASH_SIZE),
8337 make_float (DEFAULT_REHASH_THRESHOLD),
8338 Qnil, Qnil, Qnil);
8339 h = XHASH_TABLE (atsu_font_id_hash);
8341 err = ATSUFontCount (&nfonts);
8342 if (err == noErr)
8344 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8345 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8347 if (err == noErr)
8348 for (i = 0; i < nfonts; i++)
8350 Lisp_Object family;
8352 family = atsu_find_font_family_name (font_ids[i]);
8353 if (NILP (family) || SREF (family, 0) == '.')
8354 continue;
8355 if (!NILP (Fequal (prev_family, family)))
8356 family = prev_family;
8357 else
8358 j = hash_lookup (h, family, &hash_code);
8359 if (j < 0)
8361 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8362 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8363 Qnil), hash_code);
8365 else if (EQ (prev_family, family))
8366 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8367 HASH_VALUE (h, j));
8368 prev_family = family;
8370 if (font_ids)
8371 xfree (font_ids);
8373 #endif
8375 /* Create a dummy instance iterator here to avoid creating and
8376 destroying it in the loop. */
8377 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8378 return;
8379 /* Create an iterator to enumerate the font families. */
8380 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8381 != noErr)
8383 FMDisposeFontFamilyInstanceIterator (&ffii);
8384 return;
8387 GCPRO1 (text_encoding_info_alist);
8389 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
8391 Str255 name;
8392 FMFont font;
8393 FMFontStyle style;
8394 FMFontSize size;
8395 TextEncoding encoding;
8396 TextEncodingBase sc;
8397 Lisp_Object text_encoding_info, family;
8399 if (FMGetFontFamilyName (ff, name) != noErr)
8400 continue;
8401 p2cstr (name);
8402 if (*name == '.')
8403 continue;
8405 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
8406 continue;
8407 sc = GetTextEncodingBase (encoding);
8408 text_encoding_info = assq_no_quit (make_number (sc),
8409 text_encoding_info_alist);
8410 if (NILP (text_encoding_info))
8411 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8412 text_encoding_info_alist);
8413 decode_mac_font_name (name, sizeof (name),
8414 XCAR (XCDR (text_encoding_info)));
8415 family = build_string (name);
8416 if (!NILP (Fassoc (family, fm_font_family_alist)))
8417 continue;
8418 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
8419 fm_font_family_alist);
8421 /* Point the instance iterator at the current font family. */
8422 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
8423 continue;
8425 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8426 == noErr)
8428 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8430 if (size > 0 || style == normal)
8431 for (; CONSP (rest); rest = XCDR (rest))
8432 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
8436 UNGCPRO;
8438 /* Dispose of the iterators. */
8439 FMDisposeFontFamilyIterator (&ffi);
8440 FMDisposeFontFamilyInstanceIterator (&ffii);
8441 #else /* !TARGET_API_MAC_CARBON */
8442 GrafPtr port;
8443 SInt16 fontnum, old_fontnum;
8444 int num_mac_fonts = CountResources('FOND');
8445 int i, j;
8446 Handle font_handle, font_handle_2;
8447 short id, scriptcode;
8448 ResType type;
8449 Str255 name;
8450 struct FontAssoc *fat;
8451 struct AsscEntry *assc_entry;
8452 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
8453 struct gcpro gcpro1;
8455 GetPort (&port); /* save the current font number used */
8456 old_fontnum = port->txFont;
8458 text_encoding_info_alist = create_text_encoding_info_alist ();
8460 GCPRO1 (text_encoding_info_alist);
8462 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
8464 font_handle = GetIndResource ('FOND', i);
8465 if (!font_handle)
8466 continue;
8468 GetResInfo (font_handle, &id, &type, name);
8469 GetFNum (name, &fontnum);
8470 p2cstr (name);
8471 if (fontnum == 0 || *name == '.')
8472 continue;
8474 TextFont (fontnum);
8475 scriptcode = FontToScript (fontnum);
8476 text_encoding_info = assq_no_quit (make_number (scriptcode),
8477 text_encoding_info_alist);
8478 if (NILP (text_encoding_info))
8479 text_encoding_info = assq_no_quit (make_number (smRoman),
8480 text_encoding_info_alist);
8481 decode_mac_font_name (name, sizeof (name),
8482 XCAR (XCDR (text_encoding_info)));
8483 family = build_string (name);
8484 if (!NILP (Fassoc (family, fm_font_family_alist)))
8485 continue;
8486 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
8487 fm_font_family_alist);
8490 HLock (font_handle);
8492 if (GetResourceSizeOnDisk (font_handle)
8493 >= sizeof (struct FamRec))
8495 fat = (struct FontAssoc *) (*font_handle
8496 + sizeof (struct FamRec));
8497 assc_entry
8498 = (struct AsscEntry *) (*font_handle
8499 + sizeof (struct FamRec)
8500 + sizeof (struct FontAssoc));
8502 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
8504 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8506 for (; CONSP (rest); rest = XCDR (rest))
8507 add_mac_font_name (name, assc_entry->fontSize,
8508 assc_entry->fontStyle,
8509 SDATA (XCAR (rest)));
8513 HUnlock (font_handle);
8514 font_handle_2 = GetNextFOND (font_handle);
8515 ReleaseResource (font_handle);
8516 font_handle = font_handle_2;
8518 while (ResError () == noErr && font_handle);
8521 UNGCPRO;
8523 TextFont (old_fontnum);
8524 #endif /* !TARGET_API_MAC_CARBON */
8528 void
8529 mac_clear_font_name_table ()
8531 int i;
8533 for (i = 0; i < font_name_count; i++)
8534 xfree (font_name_table[i]);
8535 xfree (font_name_table);
8536 font_name_table = NULL;
8537 font_name_table_size = font_name_count = 0;
8538 fm_font_family_alist = Qnil;
8542 enum xlfd_scalable_field_index
8544 XLFD_SCL_PIXEL_SIZE,
8545 XLFD_SCL_POINT_SIZE,
8546 XLFD_SCL_AVGWIDTH,
8547 XLFD_SCL_LAST
8550 static const int xlfd_scalable_fields[] =
8552 6, /* PIXEL_SIZE */
8553 7, /* POINT_SIZE */
8554 11, /* AVGWIDTH */
8558 static Lisp_Object
8559 mac_do_list_fonts (pattern, maxnames)
8560 const char *pattern;
8561 int maxnames;
8563 int i, n_fonts = 0;
8564 Lisp_Object font_list = Qnil;
8565 struct xlfdpat *pat;
8566 char *scaled;
8567 const char *ptr;
8568 int scl_val[XLFD_SCL_LAST], *val;
8569 const int *field;
8570 int exact;
8572 if (font_name_table == NULL) /* Initialize when first used. */
8573 init_font_name_table ();
8575 for (i = 0; i < XLFD_SCL_LAST; i++)
8576 scl_val[i] = -1;
8578 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8579 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8580 fonts are scaled according to the specified size. */
8581 ptr = pattern;
8582 i = 0;
8583 field = xlfd_scalable_fields;
8584 val = scl_val;
8585 if (*ptr == '-')
8588 ptr++;
8589 if (i == *field)
8591 if ('0' <= *ptr && *ptr <= '9')
8593 *val = *ptr++ - '0';
8594 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8595 *val = *val * 10 + *ptr++ - '0';
8596 if (*ptr != '-')
8597 *val = -1;
8599 field++;
8600 val++;
8602 ptr = strchr (ptr, '-');
8603 i++;
8605 while (ptr && i < 14);
8607 if (i == 14 && ptr == NULL)
8609 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8610 scl_val[XLFD_SCL_PIXEL_SIZE] =
8611 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8612 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8613 : -1));
8614 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8615 scl_val[XLFD_SCL_POINT_SIZE] =
8616 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8617 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8618 : -1));
8619 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8620 scl_val[XLFD_SCL_AVGWIDTH] =
8621 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8622 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8623 : -1));
8625 else
8626 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8628 pat = xlfdpat_create (pattern);
8629 if (pat == NULL)
8630 return Qnil;
8632 exact = xlfdpat_exact_p (pat);
8634 for (i = 0; i < font_name_count; i++)
8636 if (xlfdpat_match (pat, font_name_table[i]))
8638 font_list = Fcons (build_string (font_name_table[i]), font_list);
8639 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8640 break;
8642 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
8643 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
8645 int former_len = ptr - font_name_table[i];
8647 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
8648 memcpy (scaled, font_name_table[i], former_len);
8649 sprintf (scaled + former_len,
8650 "-%d-%d-72-72-m-%d-%s",
8651 scl_val[XLFD_SCL_PIXEL_SIZE],
8652 scl_val[XLFD_SCL_POINT_SIZE],
8653 scl_val[XLFD_SCL_AVGWIDTH],
8654 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
8656 if (xlfdpat_match (pat, scaled))
8658 font_list = Fcons (build_string (scaled), font_list);
8659 xfree (scaled);
8660 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8661 break;
8663 else
8664 xfree (scaled);
8668 xlfdpat_destroy (pat);
8670 return font_list;
8673 /* Return a list of names of available fonts matching PATTERN on frame F.
8675 Frame F null means we have not yet created any frame on Mac, and
8676 consult the first display in x_display_list. MAXNAMES sets a limit
8677 on how many fonts to match. */
8679 Lisp_Object
8680 x_list_fonts (f, pattern, size, maxnames)
8681 struct frame *f;
8682 Lisp_Object pattern;
8683 int size, maxnames;
8685 Lisp_Object list = Qnil, patterns, tem, key;
8686 struct mac_display_info *dpyinfo
8687 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
8689 xassert (size <= 0);
8691 patterns = Fassoc (pattern, Valternate_fontname_alist);
8692 if (NILP (patterns))
8693 patterns = Fcons (pattern, Qnil);
8695 for (; CONSP (patterns); patterns = XCDR (patterns))
8697 pattern = XCAR (patterns);
8699 if (!STRINGP (pattern))
8700 continue;
8702 tem = XCAR (XCDR (dpyinfo->name_list_element));
8703 key = Fcons (pattern, make_number (maxnames));
8705 list = Fassoc (key, tem);
8706 if (!NILP (list))
8708 list = Fcdr_safe (list);
8709 /* We have a cashed list. Don't have to get the list again. */
8710 goto label_cached;
8713 BLOCK_INPUT;
8714 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8715 UNBLOCK_INPUT;
8717 /* MAC_TODO: add code for matching outline fonts here */
8719 /* Now store the result in the cache. */
8720 XSETCAR (XCDR (dpyinfo->name_list_element),
8721 Fcons (Fcons (key, list),
8722 XCAR (XCDR (dpyinfo->name_list_element))));
8724 label_cached:
8725 if (NILP (list)) continue; /* Try the remaining alternatives. */
8728 return list;
8732 #if GLYPH_DEBUG
8734 /* Check that FONT is valid on frame F. It is if it can be found in F's
8735 font table. */
8737 static void
8738 x_check_font (f, font)
8739 struct frame *f;
8740 XFontStruct *font;
8742 int i;
8743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8745 xassert (font != NULL);
8747 for (i = 0; i < dpyinfo->n_fonts; i++)
8748 if (dpyinfo->font_table[i].name
8749 && font == dpyinfo->font_table[i].font)
8750 break;
8752 xassert (i < dpyinfo->n_fonts);
8755 #endif /* GLYPH_DEBUG != 0 */
8757 /* Set *W to the minimum width, *H to the minimum font height of FONT.
8758 Note: There are (broken) X fonts out there with invalid XFontStruct
8759 min_bounds contents. For example, handa@etl.go.jp reports that
8760 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8761 have font->min_bounds.width == 0. */
8763 static INLINE void
8764 x_font_min_bounds (font, w, h)
8765 MacFontStruct *font;
8766 int *w, *h;
8768 *h = FONT_HEIGHT (font);
8769 *w = font->min_bounds.width;
8773 /* Compute the smallest character width and smallest font height over
8774 all fonts available on frame F. Set the members smallest_char_width
8775 and smallest_font_height in F's x_display_info structure to
8776 the values computed. Value is non-zero if smallest_font_height or
8777 smallest_char_width become smaller than they were before. */
8779 static int
8780 x_compute_min_glyph_bounds (f)
8781 struct frame *f;
8783 int i;
8784 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8785 MacFontStruct *font;
8786 int old_width = dpyinfo->smallest_char_width;
8787 int old_height = dpyinfo->smallest_font_height;
8789 dpyinfo->smallest_font_height = 100000;
8790 dpyinfo->smallest_char_width = 100000;
8792 for (i = 0; i < dpyinfo->n_fonts; ++i)
8793 if (dpyinfo->font_table[i].name)
8795 struct font_info *fontp = dpyinfo->font_table + i;
8796 int w, h;
8798 font = (MacFontStruct *) fontp->font;
8799 xassert (font != (MacFontStruct *) ~0);
8800 x_font_min_bounds (font, &w, &h);
8802 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8803 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8806 xassert (dpyinfo->smallest_char_width > 0
8807 && dpyinfo->smallest_font_height > 0);
8809 return (dpyinfo->n_fonts == 1
8810 || dpyinfo->smallest_char_width < old_width
8811 || dpyinfo->smallest_font_height < old_height);
8815 /* Determine whether given string is a fully-specified XLFD: all 14
8816 fields are present, none is '*'. */
8818 static int
8819 is_fully_specified_xlfd (p)
8820 const char *p;
8822 int i;
8823 char *q;
8825 if (*p != '-')
8826 return 0;
8828 for (i = 0; i < 13; i++)
8830 q = strchr (p + 1, '-');
8831 if (q == NULL)
8832 return 0;
8833 if (q - p == 2 && *(p + 1) == '*')
8834 return 0;
8835 p = q;
8838 if (strchr (p + 1, '-') != NULL)
8839 return 0;
8841 if (*(p + 1) == '*' && *(p + 2) == '\0')
8842 return 0;
8844 return 1;
8848 /* mac_load_query_font creates and returns an internal representation
8849 for a font in a MacFontStruct struct. There is really no concept
8850 corresponding to "loading" a font on the Mac. But we check its
8851 existence and find the font number and all other information for it
8852 and store them in the returned MacFontStruct. */
8854 static MacFontStruct *
8855 mac_load_query_font (f, fontname)
8856 struct frame *f;
8857 char *fontname;
8859 int size;
8860 char *name;
8861 Str255 family;
8862 Str31 charset;
8863 SInt16 fontnum;
8864 #if USE_ATSUI
8865 static ATSUFontID font_id;
8866 ATSUStyle mac_style = NULL;
8867 #endif
8868 Style fontface;
8869 #if TARGET_API_MAC_CARBON
8870 TextEncoding encoding;
8871 int scriptcode;
8872 #else
8873 short scriptcode;
8874 #endif
8875 MacFontStruct *font;
8876 XCharStruct *space_bounds = NULL, *pcm;
8878 if (is_fully_specified_xlfd (fontname))
8879 name = fontname;
8880 else
8882 Lisp_Object matched_fonts;
8884 matched_fonts = mac_do_list_fonts (fontname, 1);
8885 if (NILP (matched_fonts))
8886 return NULL;
8887 name = SDATA (XCAR (matched_fonts));
8890 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8891 return NULL;
8893 #if USE_ATSUI
8894 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8896 OSStatus err;
8897 static const ATSUAttributeTag tags[] =
8898 {kATSUFontTag, kATSUSizeTag,
8899 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8900 static const ByteCount sizes[] =
8901 {sizeof (ATSUFontID), sizeof (Fixed),
8902 sizeof (Boolean), sizeof (Boolean)};
8903 static Fixed size_fixed;
8904 static Boolean bold_p, italic_p;
8905 static const ATSUAttributeValuePtr values[] =
8906 {&font_id, &size_fixed,
8907 &bold_p, &italic_p};
8908 static const ATSUFontFeatureType types[] =
8909 {kAllTypographicFeaturesType, kDiacriticsType};
8910 static const ATSUFontFeatureSelector selectors[] =
8911 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
8912 FMFontStyle style;
8914 font_id = atsu_find_font_from_family_name (family);
8915 if (font_id == kATSUInvalidFontID)
8916 return NULL;
8917 size_fixed = Long2Fix (size);
8918 bold_p = (fontface & bold) != 0;
8919 italic_p = (fontface & italic) != 0;
8920 err = ATSUCreateStyle (&mac_style);
8921 if (err != noErr)
8922 return NULL;
8923 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8924 types, selectors);
8925 if (err != noErr)
8926 return NULL;
8927 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8928 tags, sizes, values);
8929 if (err != noErr)
8930 return NULL;
8931 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8932 if (err != noErr)
8933 fontnum = -1;
8934 scriptcode = kTextEncodingMacUnicode;
8936 else
8937 #endif
8939 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8941 if (NILP (tmp))
8942 return NULL;
8943 fontnum = XINT (XCDR (tmp));
8944 #if TARGET_API_MAC_CARBON
8945 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8946 return NULL;
8947 scriptcode = GetTextEncodingBase (encoding);
8948 #else
8949 scriptcode = FontToScript (fontnum);
8950 #endif
8953 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
8955 font->mac_fontnum = fontnum;
8956 font->mac_fontsize = size;
8957 font->mac_fontface = fontface;
8958 font->mac_scriptcode = scriptcode;
8959 #if USE_ATSUI
8960 font->mac_style = mac_style;
8961 #if USE_CG_TEXT_DRAWING
8962 font->cg_font = NULL;
8963 font->cg_glyphs = NULL;
8964 #endif
8965 #endif
8967 /* Apple Japanese (SJIS) font is listed as both
8968 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
8969 (Roman script) in init_font_name_table (). The latter should be
8970 treated as a one-byte font. */
8971 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8972 font->mac_scriptcode = smRoman;
8974 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
8976 #if USE_ATSUI
8977 if (font->mac_style)
8979 OSStatus err;
8980 UniChar c;
8982 font->min_byte1 = 0;
8983 font->max_byte1 = 0xff;
8984 font->min_char_or_byte2 = 0;
8985 font->max_char_or_byte2 = 0xff;
8987 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8988 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8989 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8990 pcm_init (font->bounds.rows[0], 0x100);
8992 #if USE_CG_TEXT_DRAWING
8993 if (fontnum != -1)
8995 FMFontStyle style;
8996 ATSFontRef ats_font;
8998 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
8999 &font_id, &style);
9000 /* Use CG text drawing if italic/bold is not synthesized. */
9001 if (err == noErr && style == fontface)
9003 ats_font = FMGetATSFontRefFromFont (font_id);
9004 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
9008 if (font->cg_font)
9010 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
9011 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
9013 #endif
9014 space_bounds = font->bounds.rows[0] + 0x20;
9015 err = mac_query_char_extents (font->mac_style, 0x20,
9016 &font->ascent, &font->descent,
9017 space_bounds,
9018 #if USE_CG_TEXT_DRAWING
9019 (font->cg_glyphs ? font->cg_glyphs + 0x20
9020 : NULL)
9021 #else
9022 NULL
9023 #endif
9025 if (err != noErr
9026 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
9028 mac_unload_font (&one_mac_display_info, font);
9029 return NULL;
9032 pcm = font->bounds.rows[0];
9033 for (c = 0x21; c <= 0xff; c++)
9035 if (c == 0xad)
9036 /* Soft hyphen is not supported in ATSUI. */
9037 continue;
9038 else if (c == 0x7f)
9040 #if USE_CG_TEXT_DRAWING
9041 if (font->cg_glyphs)
9043 c = 0x9f;
9044 pcm = NULL;
9045 continue;
9047 #endif
9048 break;
9051 mac_query_char_extents (font->mac_style, c, NULL, NULL,
9052 pcm ? pcm + c : NULL,
9053 #if USE_CG_TEXT_DRAWING
9054 (font->cg_glyphs ? font->cg_glyphs + c
9055 : NULL)
9056 #else
9057 NULL
9058 #endif
9061 #if USE_CG_TEXT_DRAWING
9062 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
9064 /* Don't use CG text drawing if font substitution occurs in
9065 ASCII or Latin-1 characters. */
9066 CGFontRelease (font->cg_font);
9067 font->cg_font = NULL;
9068 xfree (font->cg_glyphs);
9069 font->cg_glyphs = NULL;
9070 if (pcm == NULL)
9071 break;
9073 #endif
9076 else
9077 #endif
9079 OSStatus err;
9080 FontInfo the_fontinfo;
9081 int is_two_byte_font;
9083 #if USE_CG_DRAWING
9084 mac_prepare_for_quickdraw (f);
9085 #endif
9086 SetPortWindowPort (FRAME_MAC_WINDOW (f));
9088 TextFont (fontnum);
9089 TextSize (size);
9090 TextFace (fontface);
9092 GetFontInfo (&the_fontinfo);
9094 font->ascent = the_fontinfo.ascent;
9095 font->descent = the_fontinfo.descent;
9097 is_two_byte_font = (font->mac_scriptcode == smJapanese
9098 || font->mac_scriptcode == smTradChinese
9099 || font->mac_scriptcode == smSimpChinese
9100 || font->mac_scriptcode == smKorean);
9102 if (is_two_byte_font)
9104 int char_width;
9106 font->min_byte1 = 0xa1;
9107 font->max_byte1 = 0xfe;
9108 font->min_char_or_byte2 = 0xa1;
9109 font->max_char_or_byte2 = 0xfe;
9111 /* Use the width of an "ideographic space" of that font
9112 because the_fontinfo.widMax returns the wrong width for
9113 some fonts. */
9114 switch (font->mac_scriptcode)
9116 case smJapanese:
9117 font->min_byte1 = 0x81;
9118 font->max_byte1 = 0xfc;
9119 font->min_char_or_byte2 = 0x40;
9120 font->max_char_or_byte2 = 0xfc;
9121 char_width = StringWidth("\p\x81\x40");
9122 break;
9123 case smTradChinese:
9124 font->min_char_or_byte2 = 0x40;
9125 char_width = StringWidth("\p\xa1\x40");
9126 break;
9127 case smSimpChinese:
9128 char_width = StringWidth("\p\xa1\xa1");
9129 break;
9130 case smKorean:
9131 char_width = StringWidth("\p\xa1\xa1");
9132 break;
9135 font->bounds.per_char = NULL;
9137 if (fontface & italic)
9138 font->max_bounds.rbearing = char_width + 1;
9139 else
9140 font->max_bounds.rbearing = char_width;
9141 font->max_bounds.lbearing = 0;
9142 font->max_bounds.width = char_width;
9143 font->max_bounds.ascent = the_fontinfo.ascent;
9144 font->max_bounds.descent = the_fontinfo.descent;
9146 font->min_bounds = font->max_bounds;
9148 else
9150 int c;
9152 font->min_byte1 = font->max_byte1 = 0;
9153 font->min_char_or_byte2 = 0x20;
9154 font->max_char_or_byte2 = 0xff;
9156 font->bounds.per_char =
9157 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
9158 bzero (font->bounds.per_char,
9159 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9161 space_bounds = font->bounds.per_char;
9162 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9163 &font->descent, space_bounds, NULL);
9164 if (err != noErr || space_bounds->width <= 0)
9166 mac_unload_font (&one_mac_display_info, font);
9167 return NULL;
9170 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9171 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
9175 if (space_bounds)
9177 int c;
9179 font->min_bounds = font->max_bounds = *space_bounds;
9180 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9181 if (pcm->width > 0)
9183 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9184 pcm->lbearing);
9185 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9186 pcm->rbearing);
9187 font->min_bounds.width = min (font->min_bounds.width,
9188 pcm->width);
9189 font->min_bounds.ascent = min (font->min_bounds.ascent,
9190 pcm->ascent);
9191 font->min_bounds.descent = min (font->min_bounds.descent,
9192 pcm->descent);
9194 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9195 pcm->lbearing);
9196 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9197 pcm->rbearing);
9198 font->max_bounds.width = max (font->max_bounds.width,
9199 pcm->width);
9200 font->max_bounds.ascent = max (font->max_bounds.ascent,
9201 pcm->ascent);
9202 font->max_bounds.descent = max (font->max_bounds.descent,
9203 pcm->descent);
9205 if (
9206 #if USE_ATSUI
9207 font->mac_style == NULL &&
9208 #endif
9209 font->max_bounds.width == font->min_bounds.width
9210 && font->min_bounds.lbearing >= 0
9211 && font->max_bounds.rbearing <= font->max_bounds.width)
9213 /* Fixed width and no overhangs. */
9214 xfree (font->bounds.per_char);
9215 font->bounds.per_char = NULL;
9219 #if !defined (MAC_OS8) || USE_ATSUI
9220 /* AppKit and WebKit do some adjustment to the heights of Courier,
9221 Helvetica, and Times. This only works on the environments where
9222 srcCopy text transfer mode is never used. */
9223 if (
9224 #ifdef MAC_OS8 /* implies USE_ATSUI */
9225 font->mac_style &&
9226 #endif
9227 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9228 || strcmp (family, "times") == 0))
9229 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9230 #endif
9232 return font;
9236 void
9237 mac_unload_font (dpyinfo, font)
9238 struct mac_display_info *dpyinfo;
9239 XFontStruct *font;
9241 xfree (font->full_name);
9242 #if USE_ATSUI
9243 if (font->mac_style)
9245 int i;
9247 for (i = font->min_byte1; i <= font->max_byte1; i++)
9248 if (font->bounds.rows[i])
9249 xfree (font->bounds.rows[i]);
9250 xfree (font->bounds.rows);
9251 ATSUDisposeStyle (font->mac_style);
9253 else
9254 #endif
9255 if (font->bounds.per_char)
9256 xfree (font->bounds.per_char);
9257 #if USE_CG_TEXT_DRAWING
9258 if (font->cg_font)
9259 CGFontRelease (font->cg_font);
9260 if (font->cg_glyphs)
9261 xfree (font->cg_glyphs);
9262 #endif
9263 xfree (font);
9267 /* Load font named FONTNAME of the size SIZE for frame F, and return a
9268 pointer to the structure font_info while allocating it dynamically.
9269 If SIZE is 0, load any size of font.
9270 If loading is failed, return NULL. */
9272 struct font_info *
9273 x_load_font (f, fontname, size)
9274 struct frame *f;
9275 register char *fontname;
9276 int size;
9278 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9279 Lisp_Object font_names;
9281 /* Get a list of all the fonts that match this name. Once we
9282 have a list of matching fonts, we compare them against the fonts
9283 we already have by comparing names. */
9284 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9286 if (!NILP (font_names))
9288 Lisp_Object tail;
9289 int i;
9291 for (i = 0; i < dpyinfo->n_fonts; i++)
9292 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9293 if (dpyinfo->font_table[i].name
9294 && (!strcmp (dpyinfo->font_table[i].name,
9295 SDATA (XCAR (tail)))
9296 || !strcmp (dpyinfo->font_table[i].full_name,
9297 SDATA (XCAR (tail)))))
9298 return (dpyinfo->font_table + i);
9300 else
9301 return NULL;
9303 /* Load the font and add it to the table. */
9305 struct MacFontStruct *font;
9306 struct font_info *fontp;
9307 int i;
9309 fontname = (char *) SDATA (XCAR (font_names));
9311 BLOCK_INPUT;
9312 font = mac_load_query_font (f, fontname);
9313 UNBLOCK_INPUT;
9314 if (!font)
9315 return NULL;
9317 /* Find a free slot in the font table. */
9318 for (i = 0; i < dpyinfo->n_fonts; ++i)
9319 if (dpyinfo->font_table[i].name == NULL)
9320 break;
9322 /* If no free slot found, maybe enlarge the font table. */
9323 if (i == dpyinfo->n_fonts
9324 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9326 int sz;
9327 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9328 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9329 dpyinfo->font_table
9330 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9333 fontp = dpyinfo->font_table + i;
9334 if (i == dpyinfo->n_fonts)
9335 ++dpyinfo->n_fonts;
9337 /* Now fill in the slots of *FONTP. */
9338 BLOCK_INPUT;
9339 bzero (fontp, sizeof (*fontp));
9340 fontp->font = font;
9341 fontp->font_idx = i;
9342 fontp->charset = -1; /* fs_load_font sets it. */
9343 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9344 bcopy (fontname, fontp->name, strlen (fontname) + 1);
9346 if (font->min_bounds.width == font->max_bounds.width)
9348 /* Fixed width font. */
9349 fontp->average_width = fontp->space_width = font->min_bounds.width;
9351 else
9353 XChar2b char2b;
9354 XCharStruct *pcm;
9356 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9357 pcm = mac_per_char_metric (font, &char2b, 0);
9358 if (pcm)
9359 fontp->space_width = pcm->width;
9360 else
9361 fontp->space_width = FONT_WIDTH (font);
9363 if (pcm)
9365 int width = pcm->width;
9366 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9367 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9368 width += pcm->width;
9369 fontp->average_width = width / 95;
9371 else
9372 fontp->average_width = FONT_WIDTH (font);
9375 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9376 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
9378 fontp->size = font->max_bounds.width;
9379 fontp->height = FONT_HEIGHT (font);
9381 /* For some font, ascent and descent in max_bounds field is
9382 larger than the above value. */
9383 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9384 if (max_height > fontp->height)
9385 fontp->height = max_height;
9388 /* MAC_TODO: The script encoding is irrelevant in unicode? */
9389 /* The slot `encoding' specifies how to map a character
9390 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9391 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9392 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9393 2:0xA020..0xFF7F). For the moment, we don't know which charset
9394 uses this font. So, we set information in fontp->encoding_type
9395 which is never used by any charset. If mapping can't be
9396 decided, set FONT_ENCODING_NOT_DECIDED. */
9397 if (font->mac_scriptcode == smJapanese)
9398 fontp->encoding_type = 4;
9399 else
9401 fontp->encoding_type
9402 = (font->max_byte1 == 0
9403 /* 1-byte font */
9404 ? (font->min_char_or_byte2 < 0x80
9405 ? (font->max_char_or_byte2 < 0x80
9406 ? 0 /* 0x20..0x7F */
9407 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9408 : 1) /* 0xA0..0xFF */
9409 /* 2-byte font */
9410 : (font->min_byte1 < 0x80
9411 ? (font->max_byte1 < 0x80
9412 ? (font->min_char_or_byte2 < 0x80
9413 ? (font->max_char_or_byte2 < 0x80
9414 ? 0 /* 0x2020..0x7F7F */
9415 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9416 : 3) /* 0x20A0..0x7FFF */
9417 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9418 : (font->min_char_or_byte2 < 0x80
9419 ? (font->max_char_or_byte2 < 0x80
9420 ? 2 /* 0xA020..0xFF7F */
9421 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9422 : 1))); /* 0xA0A0..0xFFFF */
9425 #if 0 /* MAC_TODO: fill these out with more reasonably values */
9426 fontp->baseline_offset
9427 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9428 ? (long) value : 0);
9429 fontp->relative_compose
9430 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9431 ? (long) value : 0);
9432 fontp->default_ascent
9433 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9434 ? (long) value : 0);
9435 #else
9436 fontp->baseline_offset = 0;
9437 fontp->relative_compose = 0;
9438 fontp->default_ascent = 0;
9439 #endif
9441 /* Set global flag fonts_changed_p to non-zero if the font loaded
9442 has a character with a smaller width than any other character
9443 before, or if the font loaded has a smaller height than any
9444 other font loaded before. If this happens, it will make a
9445 glyph matrix reallocation necessary. */
9446 fonts_changed_p |= x_compute_min_glyph_bounds (f);
9447 UNBLOCK_INPUT;
9448 return fontp;
9453 /* Return a pointer to struct font_info of a font named FONTNAME for
9454 frame F. If no such font is loaded, return NULL. */
9456 struct font_info *
9457 x_query_font (f, fontname)
9458 struct frame *f;
9459 register char *fontname;
9461 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9462 int i;
9464 for (i = 0; i < dpyinfo->n_fonts; i++)
9465 if (dpyinfo->font_table[i].name
9466 && (!xstricmp (dpyinfo->font_table[i].name, fontname)
9467 || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
9468 return (dpyinfo->font_table + i);
9469 return NULL;
9473 /* Find a CCL program for a font specified by FONTP, and set the member
9474 `encoder' of the structure. */
9476 void
9477 x_find_ccl_program (fontp)
9478 struct font_info *fontp;
9480 Lisp_Object list, elt;
9482 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9484 elt = XCAR (list);
9485 if (CONSP (elt)
9486 && STRINGP (XCAR (elt))
9487 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9488 >= 0))
9489 break;
9491 if (! NILP (list))
9493 struct ccl_program *ccl
9494 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9496 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9497 xfree (ccl);
9498 else
9499 fontp->font_encoder = ccl;
9503 #if USE_MAC_FONT_PANEL
9504 /* Whether Font Panel has been shown before. The first call to font
9505 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9506 slow. This variable is used for deferring such a call as much as
9507 possible. */
9508 static int font_panel_shown_p = 0;
9510 extern Lisp_Object Qfont;
9511 static Lisp_Object Qpanel_closed, Qselection;
9513 static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9514 Lisp_Object,
9515 Lisp_Object,
9516 EventRef, UInt32,
9517 const EventParamName *,
9518 const EventParamType *));
9521 mac_font_panel_visible_p ()
9523 return font_panel_shown_p && FPIsFontPanelVisible ();
9526 static pascal OSStatus
9527 mac_handle_font_event (next_handler, event, data)
9528 EventHandlerCallRef next_handler;
9529 EventRef event;
9530 void *data;
9532 OSStatus result, err;
9533 Lisp_Object id_key;
9534 int num_params;
9535 const EventParamName *names;
9536 const EventParamType *types;
9537 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9538 kEventParamATSUFontSize,
9539 kEventParamFMFontFamily,
9540 kEventParamFMFontStyle,
9541 kEventParamFMFontSize,
9542 kEventParamFontColor};
9543 static const EventParamType types_sel[] = {typeATSUFontID,
9544 typeATSUSize,
9545 typeFMFontFamily,
9546 typeFMFontStyle,
9547 typeFMFontSize,
9548 typeFontColor};
9550 result = CallNextEventHandler (next_handler, event);
9551 if (result != eventNotHandledErr)
9552 return result;
9554 switch (GetEventKind (event))
9556 case kEventFontPanelClosed:
9557 id_key = Qpanel_closed;
9558 num_params = 0;
9559 names = NULL;
9560 types = NULL;
9561 break;
9563 case kEventFontSelection:
9564 id_key = Qselection;
9565 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9566 names = names_sel;
9567 types = types_sel;
9568 break;
9571 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9572 event, num_params,
9573 names, types);
9574 if (err == noErr)
9575 result = noErr;
9577 return result;
9580 OSStatus
9581 mac_show_hide_font_panel ()
9583 if (!font_panel_shown_p)
9585 OSStatus err;
9587 static const EventTypeSpec specs[] =
9588 {{kEventClassFont, kEventFontPanelClosed},
9589 {kEventClassFont, kEventFontSelection}};
9591 err = InstallApplicationEventHandler (mac_handle_font_event,
9592 GetEventTypeCount (specs),
9593 specs, NULL, NULL);
9594 if (err != noErr)
9595 return err;
9597 font_panel_shown_p = 1;
9600 return FPShowHideFontPanel ();
9603 OSStatus
9604 mac_set_font_info_for_selection (f, face_id, c)
9605 struct frame *f;
9606 int face_id, c;
9608 OSStatus err;
9609 EventTargetRef target = NULL;
9610 XFontStruct *font = NULL;
9612 if (!mac_font_panel_visible_p ())
9613 return noErr;
9615 if (f)
9617 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
9619 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9621 struct face *face;
9623 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9624 face = FACE_FROM_ID (f, face_id);
9625 font = face->font;
9629 if (font == NULL)
9630 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9631 else
9633 if (font->mac_fontnum != -1)
9635 FontSelectionQDStyle qd_style;
9637 qd_style.version = kFontSelectionQDStyleVersionZero;
9638 qd_style.instance.fontFamily = font->mac_fontnum;
9639 qd_style.instance.fontStyle = font->mac_fontface;
9640 qd_style.size = font->mac_fontsize;
9641 qd_style.hasColor = false;
9643 err = SetFontInfoForSelection (kFontSelectionQDType,
9644 1, &qd_style, target);
9646 else
9647 err = SetFontInfoForSelection (kFontSelectionATSUIType,
9648 1, &font->mac_style, target);
9651 return err;
9653 #endif
9656 /* The Mac Event loop code */
9658 #if !TARGET_API_MAC_CARBON
9659 #include <Events.h>
9660 #include <Quickdraw.h>
9661 #include <Balloons.h>
9662 #include <Devices.h>
9663 #include <Fonts.h>
9664 #include <Gestalt.h>
9665 #include <Menus.h>
9666 #include <Processes.h>
9667 #include <Sound.h>
9668 #include <ToolUtils.h>
9669 #include <TextUtils.h>
9670 #include <Dialogs.h>
9671 #include <Script.h>
9672 #include <Types.h>
9673 #include <Resources.h>
9675 #if __MWERKS__
9676 #include <unix.h>
9677 #endif
9678 #endif /* ! TARGET_API_MAC_CARBON */
9680 #define M_APPLE 234
9681 #define I_ABOUT 1
9683 #define DEFAULT_NUM_COLS 80
9685 #define MIN_DOC_SIZE 64
9686 #define MAX_DOC_SIZE 32767
9688 #define EXTRA_STACK_ALLOC (256 * 1024)
9690 #define ARGV_STRING_LIST_ID 129
9691 #define ABOUT_ALERT_ID 128
9692 #define RAM_TOO_LARGE_ALERT_ID 129
9694 /* Contains the string "reverse", which is a constant for mouse button emu.*/
9695 Lisp_Object Qreverse;
9698 /* Modifier associated with the control key, or nil to ignore. */
9699 Lisp_Object Vmac_control_modifier;
9701 /* Modifier associated with the option key, or nil to ignore. */
9702 Lisp_Object Vmac_option_modifier;
9704 /* Modifier associated with the command key, or nil to ignore. */
9705 Lisp_Object Vmac_command_modifier;
9707 /* Modifier associated with the function key, or nil to ignore. */
9708 Lisp_Object Vmac_function_modifier;
9710 /* True if the option and command modifiers should be used to emulate
9711 a three button mouse */
9712 Lisp_Object Vmac_emulate_three_button_mouse;
9714 #if TARGET_API_MAC_CARBON
9715 /* Non-zero if the mouse wheel button (i.e. button 4) should map to
9716 mouse-2, instead of mouse-3. */
9717 int mac_wheel_button_is_mouse_2;
9719 /* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
9720 for processing before Emacs sees it. */
9721 int mac_pass_command_to_system;
9723 /* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
9724 for processing before Emacs sees it. */
9725 int mac_pass_control_to_system;
9726 #endif
9728 /* Points to the variable `inev' in the function XTread_socket. It is
9729 used for passing an input event to the function back from
9730 Carbon/Apple event handlers. */
9731 static struct input_event *read_socket_inev = NULL;
9733 /* Whether or not the screen configuration has changed. */
9734 static int mac_screen_config_changed = 0;
9736 Point saved_menu_event_location;
9738 /* Apple Events */
9739 #if TARGET_API_MAC_CARBON
9740 static Lisp_Object Qhi_command;
9741 #ifdef MAC_OSX
9742 extern Lisp_Object Qwindow;
9743 static Lisp_Object Qtoolbar_switch_mode;
9744 #endif
9745 #if USE_MAC_TSM
9746 static TSMDocumentID tsm_document_id;
9747 Lisp_Object Qtext_input;
9748 Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
9749 Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
9750 extern Lisp_Object Qbefore_string;
9751 static Lisp_Object Vmac_ts_script_language_on_focus;
9752 static Lisp_Object saved_ts_script_language_on_focus;
9753 static ScriptLanguageRecord saved_ts_language;
9754 static Component saved_ts_component;
9755 #endif
9756 #endif /* TARGET_API_MAC_CARBON */
9757 extern int mac_ready_for_apple_events;
9758 extern Lisp_Object Qundefined;
9759 extern void init_apple_event_handler P_ ((void));
9760 extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9761 Lisp_Object *, Lisp_Object *,
9762 Lisp_Object *));
9763 extern OSErr init_coercion_handler P_ ((void));
9765 /* Drag and Drop */
9766 extern OSErr install_drag_handler P_ ((WindowRef));
9767 extern void remove_drag_handler P_ ((WindowRef));
9769 #if TARGET_API_MAC_CARBON
9770 /* Showing help echo string during menu tracking */
9771 extern OSStatus install_menu_target_item_handler P_ ((void));
9773 #ifdef MAC_OSX
9774 extern OSStatus install_service_handler ();
9775 Lisp_Object Qservice, Qpaste, Qperform;
9776 Lisp_Object Qmouse_drag_overlay;
9777 #endif
9778 #endif
9780 extern void init_emacs_passwd_dir ();
9781 extern int emacs_main (int, char **, char **);
9783 extern void initialize_applescript();
9784 extern void terminate_applescript();
9786 /* Table for translating Mac keycode to X keysym values. Contributed
9787 by Sudhir Shenoy.
9788 Mapping for special keys is now identical to that in Apple X11
9789 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9790 on the right of the Cmd key on laptops, and fn + `enter' (->
9791 <linefeed>). */
9792 static const unsigned char keycode_to_xkeysym_table[] = {
9793 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9794 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9795 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9797 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9798 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9799 /*0x38*/ 0, 0, 0, 0,
9800 /*0x3C*/ 0, 0, 0, 0,
9802 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9803 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9804 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9805 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9807 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9808 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9809 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9810 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9812 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9813 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9814 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9815 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9817 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9818 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9819 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9820 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9823 #ifdef MAC_OSX
9824 /* Table for translating Mac keycode with the laptop `fn' key to that
9825 without it. Destination symbols in comments are keys on US
9826 keyboard, and they may not be the same on other types of keyboards.
9827 If the destination is identical to the source (f1 ... f12), it
9828 doesn't map `fn' key to a modifier. */
9829 static const unsigned char fn_keycode_to_keycode_table[] = {
9830 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9831 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9832 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9834 /*0x30*/ 0, 0, 0, 0,
9835 /*0x34*/ 0, 0, 0, 0,
9836 /*0x38*/ 0, 0, 0, 0,
9837 /*0x3C*/ 0, 0, 0, 0,
9839 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9840 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9841 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9842 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9844 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9845 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9846 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9847 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9849 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9850 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9851 /*0x68*/ 0, 0, 0, 0,
9852 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9854 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9855 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9856 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9857 /*0x7C*/ 0, 0, 0, 0
9859 #endif /* MAC_OSX */
9861 static int
9862 #if TARGET_API_MAC_CARBON
9863 mac_to_emacs_modifiers (UInt32 mods)
9864 #else
9865 mac_to_emacs_modifiers (EventModifiers mods)
9866 #endif
9868 unsigned int result = 0;
9869 if (mods & shiftKey)
9870 result |= shift_modifier;
9872 /* Deactivated to simplify configuration:
9873 if Vmac_option_modifier is non-NIL, we fully process the Option
9874 key. Otherwise, we only process it if an additional Ctrl or Command
9875 is pressed. That way the system may convert the character to a
9876 composed one.
9877 if ((mods & optionKey) &&
9878 (( !NILP(Vmac_option_modifier) ||
9879 ((mods & cmdKey) || (mods & controlKey))))) */
9881 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
9882 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9883 if (INTEGERP(val))
9884 result |= XUINT(val);
9886 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9887 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9888 if (INTEGERP(val))
9889 result |= XUINT(val);
9891 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9892 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9893 if (INTEGERP(val))
9894 result |= XUINT(val);
9897 #ifdef MAC_OSX
9898 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9899 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9900 if (INTEGERP(val))
9901 result |= XUINT(val);
9903 #endif
9905 return result;
9908 static UInt32
9909 mac_mapped_modifiers (modifiers)
9910 UInt32 modifiers;
9912 UInt32 mapped_modifiers_all =
9913 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9914 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9915 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9917 #ifdef MAC_OSX
9918 mapped_modifiers_all |=
9919 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9920 #endif
9922 return mapped_modifiers_all & modifiers;
9925 static int
9926 mac_get_emulated_btn ( UInt32 modifiers )
9928 int result = 0;
9929 if (!NILP (Vmac_emulate_three_button_mouse)) {
9930 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
9931 if (modifiers & cmdKey)
9932 result = cmdIs3 ? 2 : 1;
9933 else if (modifiers & optionKey)
9934 result = cmdIs3 ? 1 : 2;
9936 return result;
9939 #ifdef MAC_OSX
9940 void
9941 mac_get_selected_range (w, range)
9942 struct window *w;
9943 CFRange *range;
9945 Lisp_Object overlay = find_symbol_value (Qmouse_drag_overlay);
9946 struct buffer *b = XBUFFER (w->buffer);
9947 int begv = BUF_BEGV (b), zv = BUF_ZV (b);
9948 int start, end;
9950 if (OVERLAYP (overlay)
9951 && EQ (Foverlay_buffer (overlay), w->buffer)
9952 && (start = XINT (Foverlay_start (overlay)),
9953 end = XINT (Foverlay_end (overlay)),
9954 start != end))
9956 else
9958 if (w == XWINDOW (selected_window) && b == current_buffer)
9959 start = PT;
9960 else
9961 start = marker_position (w->pointm);
9963 if (NILP (Vtransient_mark_mode) || NILP (b->mark_active))
9964 end = start;
9965 else
9967 int mark_pos = marker_position (b->mark);
9969 if (start <= mark_pos)
9970 end = mark_pos;
9971 else
9973 end = start;
9974 start = mark_pos;
9979 if (start != end)
9981 if (start < begv)
9982 start = begv;
9983 else if (start > zv)
9984 start = zv;
9986 if (end < begv)
9987 end = begv;
9988 else if (end > zv)
9989 end = zv;
9992 range->location = start - begv;
9993 range->length = end - start;
9996 /* Store the text of the buffer BUF from START to END as Unicode
9997 characters in CHARACTERS. Return non-zero if successful. */
10000 mac_store_buffer_text_to_unicode_chars (buf, start, end, characters)
10001 struct buffer *buf;
10002 int start, end;
10003 UniChar *characters;
10005 int start_byte, end_byte, char_count, byte_count;
10006 struct coding_system coding;
10007 unsigned char *dst = (unsigned char *) characters;
10009 start_byte = buf_charpos_to_bytepos (buf, start);
10010 end_byte = buf_charpos_to_bytepos (buf, end);
10011 char_count = end - start;
10012 byte_count = end_byte - start_byte;
10014 if (setup_coding_system (
10015 #ifdef WORDS_BIG_ENDIAN
10016 intern ("utf-16be")
10017 #else
10018 intern ("utf-16le")
10019 #endif
10020 , &coding) < 0)
10021 return 0;
10023 coding.src_multibyte = !NILP (buf->enable_multibyte_characters);
10024 coding.dst_multibyte = 0;
10025 coding.mode |= CODING_MODE_LAST_BLOCK;
10026 coding.composing = COMPOSITION_DISABLED;
10028 if (BUF_GPT_BYTE (buf) <= start_byte || end_byte <= BUF_GPT_BYTE (buf))
10029 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10030 byte_count, char_count * sizeof (UniChar));
10031 else
10033 int first_byte_count = BUF_GPT_BYTE (buf) - start_byte;
10035 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10036 first_byte_count, char_count * sizeof (UniChar));
10037 if (coding.result == CODING_FINISH_NORMAL)
10038 encode_coding (&coding,
10039 BUF_BYTE_ADDRESS (buf, start_byte + first_byte_count),
10040 dst + coding.produced,
10041 byte_count - first_byte_count,
10042 char_count * sizeof (UniChar) - coding.produced);
10045 if (coding.result != CODING_FINISH_NORMAL)
10046 return 0;
10048 return 1;
10051 void
10052 mac_ax_selected_text_range (f, range)
10053 struct frame *f;
10054 CFRange *range;
10056 mac_get_selected_range (XWINDOW (f->selected_window), range);
10059 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
10060 unsigned int
10061 mac_ax_number_of_characters (f)
10062 struct frame *f;
10064 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
10066 return BUF_ZV (b) - BUF_BEGV (b);
10068 #endif
10069 #endif
10071 #if USE_MAC_TSM
10072 OSStatus
10073 mac_restore_keyboard_input_source ()
10075 OSStatus err = noErr;
10076 ScriptLanguageRecord slrec, *slptr = NULL;
10078 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10079 && EQ (saved_ts_script_language_on_focus, Qt))
10080 slptr = &saved_ts_language;
10081 else if (CONSP (Vmac_ts_script_language_on_focus)
10082 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10083 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10084 && CONSP (saved_ts_script_language_on_focus)
10085 && EQ (XCAR (saved_ts_script_language_on_focus),
10086 XCAR (Vmac_ts_script_language_on_focus))
10087 && EQ (XCDR (saved_ts_script_language_on_focus),
10088 XCDR (Vmac_ts_script_language_on_focus)))
10090 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10091 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10092 slptr = &slrec;
10095 if (slptr)
10097 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10098 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10099 kKeyboardInputMethodClass);
10100 #else
10101 err = SetDefaultInputMethod (saved_ts_component, slptr);
10102 #endif
10103 if (err == noErr)
10104 err = SetTextServiceLanguage (slptr);
10106 /* Seems to be needed on Mac OS X 10.2. */
10107 if (err == noErr)
10108 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10111 return err;
10114 void
10115 mac_save_keyboard_input_source ()
10117 OSStatus err;
10118 ScriptLanguageRecord slrec, *slptr = NULL;
10120 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10122 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10124 err = GetTextServiceLanguage (&saved_ts_language);
10125 if (err == noErr)
10126 slptr = &saved_ts_language;
10128 else if (CONSP (Vmac_ts_script_language_on_focus)
10129 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10130 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10132 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10133 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10134 slptr = &slrec;
10137 if (slptr)
10139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10140 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10141 kKeyboardInputMethodClass);
10142 #else
10143 GetDefaultInputMethod (&saved_ts_component, slptr);
10144 #endif
10147 #endif
10149 #if TARGET_API_MAC_CARBON
10150 /***** Code to handle C-g testing *****/
10151 extern int quit_char;
10152 extern int make_ctrl_char P_ ((int));
10155 mac_quit_char_key_p (modifiers, key_code)
10156 UInt32 modifiers, key_code;
10158 UInt32 char_code;
10159 unsigned long some_state = 0;
10160 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10161 int c, emacs_modifiers;
10163 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
10164 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
10165 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
10166 if (char_code & ~0xff)
10167 return 0;
10169 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
10170 if (emacs_modifiers & ctrl_modifier)
10171 c = make_ctrl_char (char_code);
10173 c |= (emacs_modifiers
10174 & (meta_modifier | alt_modifier
10175 | hyper_modifier | super_modifier));
10177 return c == quit_char;
10179 #endif
10181 #if TARGET_API_MAC_CARBON
10182 /* Obtains the event modifiers from the event ref and then calls
10183 mac_to_emacs_modifiers. */
10184 static int
10185 mac_event_to_emacs_modifiers (EventRef eventRef)
10187 UInt32 mods = 0, class;
10189 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
10190 sizeof (UInt32), NULL, &mods);
10191 class = GetEventClass (eventRef);
10192 if (!NILP (Vmac_emulate_three_button_mouse) &&
10193 (class == kEventClassMouse || class == kEventClassCommand))
10195 mods &= ~(optionKey | cmdKey);
10197 return mac_to_emacs_modifiers (mods);
10200 /* Given an event ref, return the code to use for the mouse button
10201 code in the emacs input_event. */
10202 static int
10203 mac_get_mouse_btn (EventRef ref)
10205 EventMouseButton result = kEventMouseButtonPrimary;
10206 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
10207 sizeof (EventMouseButton), NULL, &result);
10208 switch (result)
10210 case kEventMouseButtonPrimary:
10211 if (NILP (Vmac_emulate_three_button_mouse))
10212 return 0;
10213 else {
10214 UInt32 mods = 0;
10215 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
10216 sizeof (UInt32), NULL, &mods);
10217 return mac_get_emulated_btn(mods);
10219 case kEventMouseButtonSecondary:
10220 return mac_wheel_button_is_mouse_2 ? 2 : 1;
10221 case kEventMouseButtonTertiary:
10222 case 4: /* 4 is the number for the mouse wheel button */
10223 return mac_wheel_button_is_mouse_2 ? 1 : 2;
10224 default:
10225 return 0;
10229 /* Normally, ConvertEventRefToEventRecord will correctly handle all
10230 events. However the click of the mouse wheel is not converted to a
10231 mouseDown or mouseUp event. Likewise for dead key events. This
10232 calls ConvertEventRefToEventRecord, but then checks to see if it is
10233 a mouse up/down, or a dead key Carbon event that has not been
10234 converted, and if so, converts it by hand (to be picked up in the
10235 XTread_socket loop). */
10236 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
10238 OSStatus err;
10239 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
10240 EventKind action;
10242 if (result)
10243 return result;
10245 switch (GetEventClass (eventRef))
10247 case kEventClassMouse:
10248 switch (GetEventKind (eventRef))
10250 case kEventMouseDown:
10251 eventRec->what = mouseDown;
10252 result = 1;
10253 break;
10255 case kEventMouseUp:
10256 eventRec->what = mouseUp;
10257 result = 1;
10258 break;
10260 default:
10261 break;
10263 break;
10265 case kEventClassKeyboard:
10266 switch (GetEventKind (eventRef))
10268 case kEventRawKeyDown:
10269 action = keyDown;
10270 goto keystroke_common;
10271 case kEventRawKeyRepeat:
10272 action = autoKey;
10273 goto keystroke_common;
10274 case kEventRawKeyUp:
10275 action = keyUp;
10276 keystroke_common:
10278 unsigned char char_codes;
10279 UInt32 key_code;
10281 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
10282 typeChar, NULL, sizeof (char),
10283 NULL, &char_codes);
10284 if (err == noErr)
10285 err = GetEventParameter (eventRef, kEventParamKeyCode,
10286 typeUInt32, NULL, sizeof (UInt32),
10287 NULL, &key_code);
10288 if (err == noErr)
10290 eventRec->what = action;
10291 eventRec->message = char_codes | ((key_code & 0xff) << 8);
10292 result = 1;
10295 break;
10297 default:
10298 break;
10300 break;
10302 default:
10303 break;
10306 if (result)
10308 /* Need where and when. */
10309 UInt32 mods = 0;
10311 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
10312 NULL, sizeof (Point), NULL, &eventRec->where);
10313 /* Use two step process because new event modifiers are 32-bit
10314 and old are 16-bit. Currently, only loss is NumLock & Fn. */
10315 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
10316 NULL, sizeof (UInt32), NULL, &mods);
10317 eventRec->modifiers = mods;
10319 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
10322 return result;
10325 #endif
10327 #ifdef MAC_OS8
10328 static void
10329 do_get_menus (void)
10331 Handle menubar_handle;
10332 MenuRef menu;
10334 menubar_handle = GetNewMBar (128);
10335 if(menubar_handle == NULL)
10336 abort ();
10337 SetMenuBar (menubar_handle);
10338 DrawMenuBar ();
10340 #if !TARGET_API_MAC_CARBON
10341 menu = GetMenuRef (M_APPLE);
10342 if (menu != NULL)
10343 AppendResMenu (menu, 'DRVR');
10344 else
10345 abort ();
10346 #endif
10350 static void
10351 do_init_managers (void)
10353 #if !TARGET_API_MAC_CARBON
10354 InitGraf (&qd.thePort);
10355 InitFonts ();
10356 FlushEvents (everyEvent, 0);
10357 InitWindows ();
10358 InitMenus ();
10359 TEInit ();
10360 InitDialogs (NULL);
10361 #endif /* !TARGET_API_MAC_CARBON */
10362 InitCursor ();
10364 #if !TARGET_API_MAC_CARBON
10365 /* set up some extra stack space for use by emacs */
10366 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10368 /* MaxApplZone must be called for AppleScript to execute more
10369 complicated scripts */
10370 MaxApplZone ();
10371 MoreMasters ();
10372 #endif /* !TARGET_API_MAC_CARBON */
10375 static void
10376 do_check_ram_size (void)
10378 SInt32 physical_ram_size, logical_ram_size;
10380 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10381 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
10382 || physical_ram_size > (1 << VALBITS)
10383 || logical_ram_size > (1 << VALBITS))
10385 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10386 exit (1);
10389 #endif /* MAC_OS8 */
10391 static void
10392 do_window_update (WindowRef win)
10394 struct frame *f = mac_window_to_frame (win);
10396 BeginUpdate (win);
10398 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10399 below. */
10400 if (win != tip_window)
10402 if (f->async_visible == 0)
10404 /* Update events may occur when a frame gets iconified. */
10405 #if 0
10406 f->async_visible = 1;
10407 f->async_iconified = 0;
10408 SET_FRAME_GARBAGED (f);
10409 #endif
10411 else
10413 Rect r;
10414 #if TARGET_API_MAC_CARBON
10415 RgnHandle region = NewRgn ();
10417 GetPortVisibleRegion (GetWindowPort (win), region);
10418 GetRegionBounds (region, &r);
10419 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10420 #if USE_CG_DRAWING
10421 mac_prepare_for_quickdraw (f);
10422 #endif
10423 UpdateControls (win, region);
10424 DisposeRgn (region);
10425 #else
10426 r = (*win->visRgn)->rgnBBox;
10427 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10428 UpdateControls (win, win->visRgn);
10429 #endif
10433 EndUpdate (win);
10436 static int
10437 is_emacs_window (WindowRef win)
10439 Lisp_Object tail, frame;
10441 if (!win)
10442 return 0;
10444 FOR_EACH_FRAME (tail, frame)
10445 if (FRAME_MAC_P (XFRAME (frame)))
10446 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10447 return 1;
10449 return 0;
10452 #if USE_MAC_TSM
10453 static OSStatus
10454 mac_tsm_resume ()
10456 OSStatus err;
10457 ScriptLanguageRecord slrec, *slptr = NULL;
10459 err = ActivateTSMDocument (tsm_document_id);
10461 if (err == noErr)
10463 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10464 && EQ (saved_ts_script_language_on_focus, Qt))
10465 slptr = &saved_ts_language;
10466 else if (CONSP (Vmac_ts_script_language_on_focus)
10467 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10468 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10469 && CONSP (saved_ts_script_language_on_focus)
10470 && EQ (XCAR (saved_ts_script_language_on_focus),
10471 XCAR (Vmac_ts_script_language_on_focus))
10472 && EQ (XCDR (saved_ts_script_language_on_focus),
10473 XCDR (Vmac_ts_script_language_on_focus)))
10475 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10476 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10477 slptr = &slrec;
10481 if (slptr)
10483 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10484 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10485 kKeyboardInputMethodClass);
10486 #else
10487 err = SetDefaultInputMethod (saved_ts_component, slptr);
10488 #endif
10489 if (err == noErr)
10490 err = SetTextServiceLanguage (slptr);
10492 /* Seems to be needed on Mac OS X 10.2. */
10493 if (err == noErr)
10494 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10497 return err;
10500 static OSStatus
10501 mac_tsm_suspend ()
10503 OSStatus err;
10504 ScriptLanguageRecord slrec, *slptr = NULL;
10506 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10508 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10510 err = GetTextServiceLanguage (&saved_ts_language);
10511 if (err == noErr)
10512 slptr = &saved_ts_language;
10514 else if (CONSP (Vmac_ts_script_language_on_focus)
10515 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10516 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10518 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10519 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10520 slptr = &slrec;
10523 if (slptr)
10525 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10526 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10527 kKeyboardInputMethodClass);
10528 #else
10529 GetDefaultInputMethod (&saved_ts_component, slptr);
10530 #endif
10533 err = DeactivateTSMDocument (tsm_document_id);
10535 return err;
10537 #endif
10539 #if !TARGET_API_MAC_CARBON
10540 void
10541 do_apple_menu (SInt16 menu_item)
10543 Str255 item_name;
10544 SInt16 da_driver_refnum;
10546 if (menu_item == I_ABOUT)
10547 NoteAlert (ABOUT_ALERT_ID, NULL);
10548 else
10550 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
10551 da_driver_refnum = OpenDeskAcc (item_name);
10554 #endif /* !TARGET_API_MAC_CARBON */
10556 /* Handle drags in size box. Based on code contributed by Ben
10557 Mesander and IM - Window Manager A. */
10559 static void
10560 do_grow_window (w, e)
10561 WindowRef w;
10562 const EventRecord *e;
10564 Rect limit_rect;
10565 int rows, columns, width, height;
10566 struct frame *f = mac_window_to_frame (w);
10567 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10568 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10569 #if TARGET_API_MAC_CARBON
10570 Rect new_rect;
10571 #else
10572 long grow_size;
10573 #endif
10575 if (size_hints->flags & PMinSize)
10577 min_width = size_hints->min_width;
10578 min_height = size_hints->min_height;
10580 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
10582 #if TARGET_API_MAC_CARBON
10583 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10584 return;
10585 height = new_rect.bottom - new_rect.top;
10586 width = new_rect.right - new_rect.left;
10587 #else
10588 grow_size = GrowWindow (w, e->where, &limit_rect);
10589 /* see if it really changed size */
10590 if (grow_size == 0)
10591 return;
10592 height = HiWord (grow_size);
10593 width = LoWord (grow_size);
10594 #endif
10596 if (width != FRAME_PIXEL_WIDTH (f)
10597 || height != FRAME_PIXEL_HEIGHT (f))
10599 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10600 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10602 x_set_window_size (f, 0, columns, rows);
10607 #if TARGET_API_MAC_CARBON
10608 static Point
10609 mac_get_ideal_size (f)
10610 struct frame *f;
10612 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10613 WindowRef w = FRAME_MAC_WINDOW (f);
10614 Point ideal_size;
10615 Rect standard_rect;
10616 int height, width, columns, rows;
10618 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10619 ideal_size.v = dpyinfo->height;
10620 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10621 /* Adjust the standard size according to character boundaries. */
10622 width = standard_rect.right - standard_rect.left;
10623 height = standard_rect.bottom - standard_rect.top;
10624 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10625 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10626 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10627 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10629 return ideal_size;
10631 #endif
10633 /* Handle clicks in zoom box. Calculation of "standard state" based
10634 on code in IM - Window Manager A and code contributed by Ben
10635 Mesander. The standard state of an Emacs window is 80-characters
10636 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10638 static void
10639 do_zoom_window (WindowRef w, int zoom_in_or_out)
10641 Rect zoom_rect, port_rect;
10642 int width, height;
10643 struct frame *f = mac_window_to_frame (w);
10644 #if TARGET_API_MAC_CARBON
10645 Point ideal_size = mac_get_ideal_size (f);
10647 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10648 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10649 && port_rect.left == zoom_rect.left
10650 && port_rect.top == zoom_rect.top)
10651 zoom_in_or_out = inZoomIn;
10652 else
10653 zoom_in_or_out = inZoomOut;
10655 #ifdef MAC_OS8
10656 mac_clear_window (f);
10657 #endif
10658 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
10659 #else /* not TARGET_API_MAC_CARBON */
10660 GrafPtr save_port;
10661 Point top_left;
10662 int w_title_height, rows;
10663 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10665 GetPort (&save_port);
10667 SetPortWindowPort (w);
10669 /* Clear window to avoid flicker. */
10670 EraseRect (&(w->portRect));
10671 if (zoom_in_or_out == inZoomOut)
10673 SetPt (&top_left, w->portRect.left, w->portRect.top);
10674 LocalToGlobal (&top_left);
10676 /* calculate height of window's title bar */
10677 w_title_height = top_left.v - 1
10678 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
10680 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10681 zoom_rect = qd.screenBits.bounds;
10682 zoom_rect.top += w_title_height;
10683 InsetRect (&zoom_rect, 8, 4); /* not too tight */
10685 zoom_rect.right = zoom_rect.left
10686 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10688 /* Adjust the standard size according to character boundaries. */
10689 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10690 zoom_rect.bottom =
10691 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10693 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10694 = zoom_rect;
10697 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
10699 SetPort (save_port);
10700 #endif /* not TARGET_API_MAC_CARBON */
10702 #if !TARGET_API_MAC_CARBON
10703 /* retrieve window size and update application values */
10704 port_rect = w->portRect;
10705 height = port_rect.bottom - port_rect.top;
10706 width = port_rect.right - port_rect.left;
10708 mac_handle_size_change (f, width, height);
10709 mac_handle_origin_change (f);
10710 #endif
10713 static void
10714 mac_set_unicode_keystroke_event (code, buf)
10715 UniChar code;
10716 struct input_event *buf;
10718 int charset_id, c1, c2;
10720 if (code < 0x80)
10722 buf->kind = ASCII_KEYSTROKE_EVENT;
10723 buf->code = code;
10725 else if (code < 0x100)
10727 if (code < 0xA0)
10728 charset_id = CHARSET_8_BIT_CONTROL;
10729 else
10730 charset_id = charset_latin_iso8859_1;
10731 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10732 buf->code = MAKE_CHAR (charset_id, code, 0);
10734 else
10736 if (code < 0x2500)
10737 charset_id = charset_mule_unicode_0100_24ff,
10738 code -= 0x100;
10739 else if (code < 0x33FF)
10740 charset_id = charset_mule_unicode_2500_33ff,
10741 code -= 0x2500;
10742 else if (code >= 0xE000)
10743 charset_id = charset_mule_unicode_e000_ffff,
10744 code -= 0xE000;
10745 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10746 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10747 buf->code = MAKE_CHAR (charset_id, c1, c2);
10751 static void
10752 do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10753 EventKind action;
10754 unsigned char char_code;
10755 UInt32 key_code, modifiers;
10756 unsigned long timestamp;
10757 struct input_event *buf;
10759 static SInt16 last_key_script = -1;
10760 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10761 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10763 #ifdef MAC_OSX
10764 if (mapped_modifiers & kEventKeyModifierFnMask
10765 && key_code <= 0x7f
10766 && fn_keycode_to_keycode_table[key_code])
10767 key_code = fn_keycode_to_keycode_table[key_code];
10768 #endif
10770 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10772 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10773 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10774 #ifdef MAC_OSX
10775 if (modifiers & kEventKeyModifierFnMask
10776 && key_code <= 0x7f
10777 && fn_keycode_to_keycode_table[key_code] == key_code)
10778 modifiers &= ~kEventKeyModifierFnMask;
10779 #endif
10781 else if (mapped_modifiers)
10783 /* translate the keycode back to determine the original key */
10784 #ifdef MAC_OSX
10785 UCKeyboardLayout *uchr_ptr = NULL;
10786 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10787 OSStatus err;
10788 KeyboardLayoutRef layout;
10790 err = KLGetCurrentKeyboardLayout (&layout);
10791 if (err == noErr)
10792 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10793 (const void **) &uchr_ptr);
10794 #else
10795 static SInt16 last_key_layout_id = 0;
10796 static Handle uchr_handle = (Handle)-1;
10797 SInt16 current_key_layout_id =
10798 GetScriptVariable (current_key_script, smScriptKeys);
10800 if (uchr_handle == (Handle)-1
10801 || last_key_layout_id != current_key_layout_id)
10803 uchr_handle = GetResource ('uchr', current_key_layout_id);
10804 last_key_layout_id = current_key_layout_id;
10806 if (uchr_handle)
10807 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10808 #endif
10810 if (uchr_ptr)
10812 OSStatus status;
10813 UInt16 key_action = action - keyDown;
10814 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10815 UInt32 keyboard_type = LMGetKbdType ();
10816 SInt32 dead_key_state = 0;
10817 UniChar code;
10818 UniCharCount actual_length;
10820 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10821 modifier_key_state, keyboard_type,
10822 kUCKeyTranslateNoDeadKeysMask,
10823 &dead_key_state,
10824 1, &actual_length, &code);
10825 if (status == noErr && actual_length == 1)
10826 mac_set_unicode_keystroke_event (code, buf);
10828 #endif /* MAC_OSX */
10830 if (buf->kind == NO_EVENT)
10832 /* This code comes from Keyboard Resource, Appendix C of IM
10833 - Text. This is necessary since shift is ignored in KCHR
10834 table translation when option or command is pressed. It
10835 also does not translate correctly control-shift chars
10836 like C-% so mask off shift here also. */
10837 /* Mask off modifier keys that are mapped to some Emacs
10838 modifiers. */
10839 int new_modifiers = modifiers & ~mapped_modifiers;
10840 /* set high byte of keycode to modifier high byte*/
10841 int new_key_code = key_code | new_modifiers;
10842 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10843 unsigned long some_state = 0;
10844 UInt32 new_char_code;
10846 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10847 if (new_char_code == 0)
10848 /* Seems like a dead key. Append up-stroke. */
10849 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10850 &some_state);
10851 if (new_char_code)
10853 buf->kind = ASCII_KEYSTROKE_EVENT;
10854 buf->code = new_char_code & 0xff;
10859 if (buf->kind == NO_EVENT)
10861 buf->kind = ASCII_KEYSTROKE_EVENT;
10862 buf->code = char_code;
10865 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10866 buf->modifiers |= (extra_keyboard_modifiers
10867 & (meta_modifier | alt_modifier
10868 | hyper_modifier | super_modifier));
10870 #if TARGET_API_MAC_CARBON
10871 if (buf->kind == ASCII_KEYSTROKE_EVENT
10872 && buf->code >= 0x80 && buf->modifiers)
10874 OSStatus err;
10875 TextEncoding encoding = kTextEncodingMacRoman;
10876 TextToUnicodeInfo ttu_info;
10878 UpgradeScriptInfoToTextEncoding (current_key_script,
10879 kTextLanguageDontCare,
10880 kTextRegionDontCare,
10881 NULL, &encoding);
10882 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10883 if (err == noErr)
10885 UniChar code;
10886 Str255 pstr;
10887 ByteCount unicode_len;
10889 pstr[0] = 1;
10890 pstr[1] = buf->code;
10891 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10892 sizeof (UniChar),
10893 &unicode_len, &code);
10894 if (err == noErr && unicode_len == sizeof (UniChar))
10895 mac_set_unicode_keystroke_event (code, buf);
10896 DisposeTextToUnicodeInfo (&ttu_info);
10899 #endif
10901 if (buf->kind == ASCII_KEYSTROKE_EVENT
10902 && buf->code >= 0x80
10903 && last_key_script != current_key_script)
10905 struct input_event event;
10907 EVENT_INIT (event);
10908 event.kind = LANGUAGE_CHANGE_EVENT;
10909 event.arg = Qnil;
10910 event.code = current_key_script;
10911 event.timestamp = timestamp;
10912 kbd_buffer_store_event (&event);
10913 last_key_script = current_key_script;
10917 void
10918 mac_store_apple_event (class, id, desc)
10919 Lisp_Object class, id;
10920 const AEDesc *desc;
10922 struct input_event buf;
10924 EVENT_INIT (buf);
10926 buf.kind = MAC_APPLE_EVENT;
10927 buf.x = class;
10928 buf.y = id;
10929 XSETFRAME (buf.frame_or_window,
10930 mac_focus_frame (&one_mac_display_info));
10931 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10932 is safe to use them during read_socket_hook. */
10933 buf.arg = mac_aedesc_to_lisp (desc);
10934 kbd_buffer_store_event (&buf);
10937 #if TARGET_API_MAC_CARBON
10938 static OSStatus
10939 mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10940 event, num_params, names, types)
10941 AEEventClass class;
10942 AEEventID id;
10943 Lisp_Object class_key, id_key;
10944 EventRef event;
10945 UInt32 num_params;
10946 const EventParamName *names;
10947 const EventParamType *types;
10949 OSStatus err = eventNotHandledErr;
10950 Lisp_Object binding;
10952 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10953 if (!NILP (binding) && !EQ (binding, Qundefined))
10955 if (INTEGERP (binding))
10956 err = XINT (binding);
10957 else
10959 AppleEvent apple_event;
10960 err = create_apple_event_from_event_ref (event, num_params,
10961 names, types,
10962 &apple_event);
10963 if (err == noErr)
10965 mac_store_apple_event (class_key, id_key, &apple_event);
10966 AEDisposeDesc (&apple_event);
10967 mac_wakeup_from_rne ();
10972 return err;
10975 void
10976 mac_store_drag_event (window, mouse_pos, modifiers, desc)
10977 WindowRef window;
10978 Point mouse_pos;
10979 SInt16 modifiers;
10980 const AEDesc *desc;
10982 struct input_event buf;
10984 EVENT_INIT (buf);
10986 buf.kind = DRAG_N_DROP_EVENT;
10987 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10988 buf.timestamp = TickCount () * (1000 / 60);
10989 XSETINT (buf.x, mouse_pos.h);
10990 XSETINT (buf.y, mouse_pos.v);
10991 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10992 buf.arg = mac_aedesc_to_lisp (desc);
10993 kbd_buffer_store_event (&buf);
10996 #ifdef MAC_OSX
10997 OSStatus
10998 mac_store_service_event (event)
10999 EventRef event;
11001 OSStatus err;
11002 Lisp_Object id_key;
11003 int num_params;
11004 const EventParamName *names;
11005 const EventParamType *types;
11006 static const EventParamName names_pfm[] =
11007 {kEventParamServiceMessageName, kEventParamServiceUserData};
11008 static const EventParamType types_pfm[] =
11009 {typeCFStringRef, typeCFStringRef};
11011 switch (GetEventKind (event))
11013 case kEventServicePaste:
11014 id_key = Qpaste;
11015 num_params = 0;
11016 names = NULL;
11017 types = NULL;
11018 break;
11020 case kEventServicePerform:
11021 id_key = Qperform;
11022 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
11023 names = names_pfm;
11024 types = types_pfm;
11025 break;
11027 default:
11028 abort ();
11031 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
11032 event, num_params,
11033 names, types);
11035 return err;
11037 #endif /* MAC_OSX */
11039 static pascal OSStatus
11040 mac_handle_window_event (next_handler, event, data)
11041 EventHandlerCallRef next_handler;
11042 EventRef event;
11043 void *data;
11045 WindowRef wp;
11046 OSStatus err, result = eventNotHandledErr;
11047 struct frame *f;
11048 UInt32 attributes;
11049 XSizeHints *size_hints;
11051 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
11052 NULL, sizeof (WindowRef), NULL, &wp);
11053 if (err != noErr)
11054 return eventNotHandledErr;
11056 f = mac_window_to_frame (wp);
11057 switch (GetEventKind (event))
11059 /* -- window refresh events -- */
11061 case kEventWindowUpdate:
11062 result = CallNextEventHandler (next_handler, event);
11063 if (result != eventNotHandledErr)
11064 break;
11066 do_window_update (wp);
11067 result = noErr;
11068 break;
11070 /* -- window state change events -- */
11072 case kEventWindowShowing:
11073 size_hints = FRAME_SIZE_HINTS (f);
11074 if (!(size_hints->flags & (USPosition | PPosition)))
11076 struct frame *sf = SELECTED_FRAME ();
11078 if (!(FRAME_MAC_P (sf) && sf->async_visible))
11079 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
11080 else
11082 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
11083 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
11084 kWindowCascadeStartAtParentWindowScreen
11085 #else
11086 kWindowCascadeOnParentWindowScreen
11087 #endif
11089 #if USE_MAC_TOOLBAR
11090 /* This is a workaround. RepositionWindow fails to put
11091 a window at the cascading position when its parent
11092 window has a Carbon HIToolbar. */
11093 if ((f->left_pos == sf->left_pos
11094 && f->top_pos == sf->top_pos)
11095 || (f->left_pos == sf->left_pos + 10 * 2
11096 && f->top_pos == sf->top_pos + 32 * 2))
11097 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
11098 #endif
11100 result = noErr;
11102 break;
11104 case kEventWindowHiding:
11105 /* Before unmapping the window, update the WM_SIZE_HINTS
11106 property to claim that the current position of the window is
11107 user-specified, rather than program-specified, so that when
11108 the window is mapped again, it will be placed at the same
11109 location, without forcing the user to position it by hand
11110 again (they have already done that once for this window.) */
11111 x_wm_set_size_hint (f, (long) 0, 1);
11112 result = noErr;
11113 break;
11115 case kEventWindowShown:
11116 case kEventWindowHidden:
11117 case kEventWindowCollapsed:
11118 case kEventWindowExpanded:
11119 mac_handle_visibility_change (f);
11120 result = noErr;
11121 break;
11123 case kEventWindowBoundsChanging:
11124 result = CallNextEventHandler (next_handler, event);
11125 if (result != eventNotHandledErr)
11126 break;
11128 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11129 NULL, sizeof (UInt32), NULL, &attributes);
11130 if (err != noErr)
11131 break;
11133 size_hints = FRAME_SIZE_HINTS (f);
11134 if ((attributes & kWindowBoundsChangeUserResize)
11135 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
11136 == (PResizeInc | PBaseSize | PMinSize)))
11138 Rect bounds;
11139 int width, height;
11141 err = GetEventParameter (event, kEventParamCurrentBounds,
11142 typeQDRectangle, NULL, sizeof (Rect),
11143 NULL, &bounds);
11144 if (err != noErr)
11145 break;
11147 width = bounds.right - bounds.left;
11148 height = bounds.bottom - bounds.top;
11150 if (width < size_hints->min_width)
11151 width = size_hints->min_width;
11152 else
11153 width = size_hints->base_width
11154 + (int) ((width - size_hints->base_width)
11155 / (float) size_hints->width_inc + .5)
11156 * size_hints->width_inc;
11158 if (height < size_hints->min_height)
11159 height = size_hints->min_height;
11160 else
11161 height = size_hints->base_height
11162 + (int) ((height - size_hints->base_height)
11163 / (float) size_hints->height_inc + .5)
11164 * size_hints->height_inc;
11166 bounds.right = bounds.left + width;
11167 bounds.bottom = bounds.top + height;
11168 SetEventParameter (event, kEventParamCurrentBounds,
11169 typeQDRectangle, sizeof (Rect), &bounds);
11170 result = noErr;
11172 break;
11174 case kEventWindowBoundsChanged:
11175 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11176 NULL, sizeof (UInt32), NULL, &attributes);
11177 if (err != noErr)
11178 break;
11180 if (attributes & kWindowBoundsChangeSizeChanged)
11182 Rect bounds;
11184 err = GetEventParameter (event, kEventParamCurrentBounds,
11185 typeQDRectangle, NULL, sizeof (Rect),
11186 NULL, &bounds);
11187 if (err == noErr)
11189 int width, height;
11191 width = bounds.right - bounds.left;
11192 height = bounds.bottom - bounds.top;
11193 mac_handle_size_change (f, width, height);
11194 mac_wakeup_from_rne ();
11198 if (attributes & kWindowBoundsChangeOriginChanged)
11199 mac_handle_origin_change (f);
11201 result = noErr;
11202 break;
11204 /* -- window action events -- */
11206 case kEventWindowClose:
11208 struct input_event buf;
11210 EVENT_INIT (buf);
11211 buf.kind = DELETE_WINDOW_EVENT;
11212 XSETFRAME (buf.frame_or_window, f);
11213 buf.arg = Qnil;
11214 kbd_buffer_store_event (&buf);
11216 result = noErr;
11217 break;
11219 case kEventWindowGetIdealSize:
11220 result = CallNextEventHandler (next_handler, event);
11221 if (result != eventNotHandledErr)
11222 break;
11225 Point ideal_size = mac_get_ideal_size (f);
11227 err = SetEventParameter (event, kEventParamDimensions,
11228 typeQDPoint, sizeof (Point), &ideal_size);
11229 if (err == noErr)
11230 result = noErr;
11232 break;
11234 #ifdef MAC_OSX
11235 case kEventWindowToolbarSwitchMode:
11237 static const EventParamName names[] = {kEventParamDirectObject,
11238 kEventParamWindowMouseLocation,
11239 kEventParamKeyModifiers,
11240 kEventParamMouseButton,
11241 kEventParamClickCount,
11242 kEventParamMouseChord};
11243 static const EventParamType types[] = {typeWindowRef,
11244 typeQDPoint,
11245 typeUInt32,
11246 typeMouseButton,
11247 typeUInt32,
11248 typeUInt32};
11249 int num_params = sizeof (names) / sizeof (names[0]);
11251 err = mac_store_event_ref_as_apple_event (0, 0,
11252 Qwindow,
11253 Qtoolbar_switch_mode,
11254 event, num_params,
11255 names, types);
11257 if (err == noErr)
11258 result = noErr;
11259 break;
11260 #endif
11262 #if USE_MAC_TSM
11263 /* -- window focus events -- */
11265 case kEventWindowFocusAcquired:
11266 err = mac_tsm_resume ();
11267 if (err == noErr)
11268 result = noErr;
11269 break;
11271 case kEventWindowFocusRelinquish:
11272 err = mac_tsm_suspend ();
11273 if (err == noErr)
11274 result = noErr;
11275 break;
11276 #endif
11278 default:
11279 abort ();
11282 return result;
11285 static pascal OSStatus
11286 mac_handle_application_event (next_handler, event, data)
11287 EventHandlerCallRef next_handler;
11288 EventRef event;
11289 void *data;
11291 OSStatus err, result = eventNotHandledErr;
11293 switch (GetEventKind (event))
11295 #if USE_MAC_TSM
11296 case kEventAppActivated:
11297 err = mac_tsm_resume ();
11298 break;
11300 case kEventAppDeactivated:
11301 err = mac_tsm_suspend ();
11302 break;
11303 #endif
11305 default:
11306 abort ();
11309 if (err == noErr)
11310 result = noErr;
11312 return result;
11315 static pascal OSStatus
11316 mac_handle_keyboard_event (next_handler, event, data)
11317 EventHandlerCallRef next_handler;
11318 EventRef event;
11319 void *data;
11321 OSStatus err, result = eventNotHandledErr;
11322 UInt32 event_kind, key_code, modifiers;
11323 unsigned char char_code;
11325 event_kind = GetEventKind (event);
11326 switch (event_kind)
11328 case kEventRawKeyDown:
11329 case kEventRawKeyRepeat:
11330 case kEventRawKeyUp:
11331 /* When using Carbon Events, we need to pass raw keyboard events
11332 to the TSM ourselves. If TSM handles it, it will pass back
11333 noErr, otherwise it will pass back "eventNotHandledErr" and
11334 we can process it normally. */
11335 result = CallNextEventHandler (next_handler, event);
11336 if (result != eventNotHandledErr)
11337 break;
11339 if (read_socket_inev == NULL)
11340 break;
11342 #if USE_MAC_TSM
11343 if (read_socket_inev->kind != NO_EVENT)
11345 result = noErr;
11346 break;
11348 #endif
11350 if (event_kind == kEventRawKeyUp)
11351 break;
11353 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11354 typeChar, NULL,
11355 sizeof (char), NULL, &char_code);
11356 if (err != noErr)
11357 break;
11359 err = GetEventParameter (event, kEventParamKeyCode,
11360 typeUInt32, NULL,
11361 sizeof (UInt32), NULL, &key_code);
11362 if (err != noErr)
11363 break;
11365 err = GetEventParameter (event, kEventParamKeyModifiers,
11366 typeUInt32, NULL,
11367 sizeof (UInt32), NULL, &modifiers);
11368 if (err != noErr)
11369 break;
11371 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
11372 char_code, key_code, modifiers,
11373 ((unsigned long)
11374 (GetEventTime (event) / kEventDurationMillisecond)),
11375 read_socket_inev);
11376 result = noErr;
11377 break;
11379 default:
11380 abort ();
11383 return result;
11386 static pascal OSStatus
11387 mac_handle_command_event (next_handler, event, data)
11388 EventHandlerCallRef next_handler;
11389 EventRef event;
11390 void *data;
11392 OSStatus err, result = eventNotHandledErr;
11393 HICommand command;
11394 static const EventParamName names[] =
11395 {kEventParamDirectObject, kEventParamKeyModifiers};
11396 static const EventParamType types[] =
11397 {typeHICommand, typeUInt32};
11398 int num_params = sizeof (names) / sizeof (names[0]);
11400 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11401 NULL, sizeof (HICommand), NULL, &command);
11402 if (err != noErr)
11403 return eventNotHandledErr;
11405 switch (GetEventKind (event))
11407 case kEventCommandProcess:
11408 result = CallNextEventHandler (next_handler, event);
11409 if (result != eventNotHandledErr)
11410 break;
11412 err = GetEventParameter (event, kEventParamDirectObject,
11413 typeHICommand, NULL,
11414 sizeof (HICommand), NULL, &command);
11416 if (err != noErr || command.commandID == 0)
11417 break;
11419 /* A HI command event is mapped to an Apple event whose event
11420 class symbol is `hi-command' and event ID is its command
11421 ID. */
11422 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11423 Qhi_command, Qnil,
11424 event, num_params,
11425 names, types);
11426 if (err == noErr)
11427 result = noErr;
11428 break;
11430 default:
11431 abort ();
11434 return result;
11437 static pascal OSStatus
11438 mac_handle_mouse_event (next_handler, event, data)
11439 EventHandlerCallRef next_handler;
11440 EventRef event;
11441 void *data;
11443 OSStatus err, result = eventNotHandledErr;
11445 switch (GetEventKind (event))
11447 case kEventMouseWheelMoved:
11449 WindowRef wp;
11450 struct frame *f;
11451 EventMouseWheelAxis axis;
11452 SInt32 delta;
11453 Point point;
11455 result = CallNextEventHandler (next_handler, event);
11456 if (result != eventNotHandledErr || read_socket_inev == NULL)
11457 break;
11459 f = mac_focus_frame (&one_mac_display_info);
11461 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11462 NULL, sizeof (WindowRef), NULL, &wp);
11463 if (err != noErr
11464 || wp != FRAME_MAC_WINDOW (f))
11465 break;
11467 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11468 typeMouseWheelAxis, NULL,
11469 sizeof (EventMouseWheelAxis), NULL, &axis);
11470 if (err != noErr || axis != kEventMouseWheelAxisY)
11471 break;
11473 err = GetEventParameter (event, kEventParamMouseLocation,
11474 typeQDPoint, NULL, sizeof (Point),
11475 NULL, &point);
11476 if (err != noErr)
11477 break;
11479 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11480 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
11481 if (point.h < 0 || point.v < 0
11482 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11483 f->tool_bar_window))
11484 break;
11486 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11487 typeSInt32, NULL, sizeof (SInt32),
11488 NULL, &delta);
11489 if (err != noErr)
11490 break;
11492 read_socket_inev->kind = WHEEL_EVENT;
11493 read_socket_inev->code = 0;
11494 read_socket_inev->modifiers =
11495 (mac_event_to_emacs_modifiers (event)
11496 | ((delta < 0) ? down_modifier : up_modifier));
11497 XSETINT (read_socket_inev->x, point.h);
11498 XSETINT (read_socket_inev->y, point.v);
11499 XSETFRAME (read_socket_inev->frame_or_window, f);
11501 result = noErr;
11503 break;
11505 default:
11506 abort ();
11509 return result;
11512 #if USE_MAC_TSM
11513 static pascal OSStatus
11514 mac_handle_text_input_event (next_handler, event, data)
11515 EventHandlerCallRef next_handler;
11516 EventRef event;
11517 void *data;
11519 OSStatus err, result;
11520 Lisp_Object id_key = Qnil;
11521 int num_params;
11522 const EventParamName *names;
11523 const EventParamType *types;
11524 static UInt32 seqno_uaia = 0;
11525 static const EventParamName names_uaia[] =
11526 {kEventParamTextInputSendComponentInstance,
11527 kEventParamTextInputSendRefCon,
11528 kEventParamTextInputSendSLRec,
11529 kEventParamTextInputSendFixLen,
11530 kEventParamTextInputSendText,
11531 kEventParamTextInputSendUpdateRng,
11532 kEventParamTextInputSendHiliteRng,
11533 kEventParamTextInputSendClauseRng,
11534 kEventParamTextInputSendPinRng,
11535 kEventParamTextInputSendTextServiceEncoding,
11536 kEventParamTextInputSendTextServiceMacEncoding,
11537 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
11538 static const EventParamType types_uaia[] =
11539 {typeComponentInstance,
11540 typeLongInteger,
11541 typeIntlWritingCode,
11542 typeLongInteger,
11543 #ifdef MAC_OSX
11544 typeUnicodeText,
11545 #else
11546 typeChar,
11547 #endif
11548 typeTextRangeArray,
11549 typeTextRangeArray,
11550 typeOffsetArray,
11551 typeTextRange,
11552 typeUInt32,
11553 typeUInt32,
11554 typeUInt32};
11555 static const EventParamName names_ufke[] =
11556 {kEventParamTextInputSendComponentInstance,
11557 kEventParamTextInputSendRefCon,
11558 kEventParamTextInputSendSLRec,
11559 kEventParamTextInputSendText};
11560 static const EventParamType types_ufke[] =
11561 {typeComponentInstance,
11562 typeLongInteger,
11563 typeIntlWritingCode,
11564 typeUnicodeText};
11566 result = CallNextEventHandler (next_handler, event);
11567 if (result != eventNotHandledErr)
11568 return result;
11570 switch (GetEventKind (event))
11572 case kEventTextInputUpdateActiveInputArea:
11573 id_key = Qupdate_active_input_area;
11574 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11575 names = names_uaia;
11576 types = types_uaia;
11577 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11578 typeUInt32, sizeof (UInt32), &seqno_uaia);
11579 seqno_uaia++;
11580 result = noErr;
11581 break;
11583 case kEventTextInputUnicodeForKeyEvent:
11585 EventRef kbd_event;
11586 UInt32 actual_size, modifiers;
11588 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11589 typeEventRef, NULL, sizeof (EventRef), NULL,
11590 &kbd_event);
11591 if (err == noErr)
11592 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11593 typeUInt32, NULL,
11594 sizeof (UInt32), NULL, &modifiers);
11595 if (err == noErr && mac_mapped_modifiers (modifiers))
11596 /* There're mapped modifier keys. Process it in
11597 do_keystroke. */
11598 break;
11599 if (err == noErr)
11600 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11601 typeUnicodeText, NULL, 0, &actual_size,
11602 NULL);
11603 if (err == noErr && actual_size == sizeof (UniChar))
11605 UniChar code;
11607 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11608 typeUnicodeText, NULL,
11609 sizeof (UniChar), NULL, &code);
11610 if (err == noErr && code < 0x80)
11612 /* ASCII character. Process it in do_keystroke. */
11613 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
11615 UInt32 key_code;
11617 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11618 typeUInt32, NULL, sizeof (UInt32),
11619 NULL, &key_code);
11620 if (!(err == noErr && key_code <= 0x7f
11621 && keycode_to_xkeysym_table [key_code]))
11623 struct frame *f =
11624 mac_focus_frame (&one_mac_display_info);
11626 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11627 read_socket_inev->code = code;
11628 read_socket_inev->modifiers =
11629 mac_to_emacs_modifiers (modifiers);
11630 read_socket_inev->modifiers |=
11631 (extra_keyboard_modifiers
11632 & (meta_modifier | alt_modifier
11633 | hyper_modifier | super_modifier));
11634 XSETFRAME (read_socket_inev->frame_or_window, f);
11637 break;
11640 if (err == noErr)
11642 /* Non-ASCII keystrokes without mapped modifiers are
11643 processed at the Lisp level. */
11644 id_key = Qunicode_for_key_event;
11645 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11646 names = names_ufke;
11647 types = types_ufke;
11648 result = noErr;
11651 break;
11653 case kEventTextInputOffsetToPos:
11655 struct frame *f;
11656 struct window *w;
11657 Point p;
11659 if (!OVERLAYP (Vmac_ts_active_input_overlay))
11660 break;
11662 /* Strictly speaking, this is not always correct because
11663 previous events may change some states about display. */
11664 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11666 /* Active input area is displayed around the current point. */
11667 f = SELECTED_FRAME ();
11668 w = XWINDOW (f->selected_window);
11670 else if (WINDOWP (echo_area_window))
11672 /* Active input area is displayed in the echo area. */
11673 w = XWINDOW (echo_area_window);
11674 f = WINDOW_XFRAME (w);
11676 else
11677 break;
11679 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
11680 + WINDOW_LEFT_FRINGE_WIDTH (w)
11681 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
11682 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
11683 + FONT_BASE (FRAME_FONT (f))
11684 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
11685 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11686 typeQDPoint, sizeof (typeQDPoint), &p);
11687 if (err == noErr)
11688 result = noErr;
11690 break;
11692 default:
11693 abort ();
11696 if (!NILP (id_key))
11697 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11698 event, num_params,
11699 names, types);
11700 return result;
11702 #endif
11703 #endif /* TARGET_API_MAC_CARBON */
11706 OSStatus
11707 install_window_handler (window)
11708 WindowRef window;
11710 OSStatus err = noErr;
11712 #if TARGET_API_MAC_CARBON
11713 if (err == noErr)
11715 static const EventTypeSpec specs[] =
11717 /* -- window refresh events -- */
11718 {kEventClassWindow, kEventWindowUpdate},
11719 /* -- window state change events -- */
11720 {kEventClassWindow, kEventWindowShowing},
11721 {kEventClassWindow, kEventWindowHiding},
11722 {kEventClassWindow, kEventWindowShown},
11723 {kEventClassWindow, kEventWindowHidden},
11724 {kEventClassWindow, kEventWindowCollapsed},
11725 {kEventClassWindow, kEventWindowExpanded},
11726 {kEventClassWindow, kEventWindowBoundsChanging},
11727 {kEventClassWindow, kEventWindowBoundsChanged},
11728 /* -- window action events -- */
11729 {kEventClassWindow, kEventWindowClose},
11730 {kEventClassWindow, kEventWindowGetIdealSize},
11731 #ifdef MAC_OSX
11732 {kEventClassWindow, kEventWindowToolbarSwitchMode},
11733 #endif
11734 #if USE_MAC_TSM
11735 /* -- window focus events -- */
11736 {kEventClassWindow, kEventWindowFocusAcquired},
11737 {kEventClassWindow, kEventWindowFocusRelinquish},
11738 #endif
11740 static EventHandlerUPP handle_window_eventUPP = NULL;
11742 if (handle_window_eventUPP == NULL)
11743 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
11745 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11746 GetEventTypeCount (specs),
11747 specs, NULL, NULL);
11749 #endif
11751 if (err == noErr)
11752 err = install_drag_handler (window);
11754 return err;
11757 void
11758 remove_window_handler (window)
11759 WindowRef window;
11761 remove_drag_handler (window);
11764 #if TARGET_API_MAC_CARBON
11765 static OSStatus
11766 install_application_handler ()
11768 OSStatus err = noErr;
11770 if (err == noErr)
11772 static const EventTypeSpec specs[] = {
11773 #if USE_MAC_TSM
11774 {kEventClassApplication, kEventAppActivated},
11775 {kEventClassApplication, kEventAppDeactivated},
11776 #endif
11779 err = InstallApplicationEventHandler (NewEventHandlerUPP
11780 (mac_handle_application_event),
11781 GetEventTypeCount (specs),
11782 specs, NULL, NULL);
11785 if (err == noErr)
11787 static const EventTypeSpec specs[] =
11788 {{kEventClassKeyboard, kEventRawKeyDown},
11789 {kEventClassKeyboard, kEventRawKeyRepeat},
11790 {kEventClassKeyboard, kEventRawKeyUp}};
11792 err = InstallApplicationEventHandler (NewEventHandlerUPP
11793 (mac_handle_keyboard_event),
11794 GetEventTypeCount (specs),
11795 specs, NULL, NULL);
11798 if (err == noErr)
11800 static const EventTypeSpec specs[] =
11801 {{kEventClassCommand, kEventCommandProcess}};
11803 err = InstallApplicationEventHandler (NewEventHandlerUPP
11804 (mac_handle_command_event),
11805 GetEventTypeCount (specs),
11806 specs, NULL, NULL);
11809 if (err == noErr)
11811 static const EventTypeSpec specs[] =
11812 {{kEventClassMouse, kEventMouseWheelMoved}};
11814 err = InstallApplicationEventHandler (NewEventHandlerUPP
11815 (mac_handle_mouse_event),
11816 GetEventTypeCount (specs),
11817 specs, NULL, NULL);
11820 #if USE_MAC_TSM
11821 if (err == noErr)
11823 static const EventTypeSpec spec[] =
11824 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11825 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11826 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11828 err = InstallApplicationEventHandler (NewEventHandlerUPP
11829 (mac_handle_text_input_event),
11830 GetEventTypeCount (spec),
11831 spec, NULL, NULL);
11833 #endif
11835 if (err == noErr)
11836 err = install_menu_target_item_handler ();
11838 #ifdef MAC_OSX
11839 if (err == noErr)
11840 err = install_service_handler ();
11841 #endif
11843 return err;
11845 #endif
11847 static pascal void
11848 mac_handle_dm_notification (event)
11849 AppleEvent *event;
11851 mac_screen_config_changed = 1;
11854 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11855 static void
11856 mac_handle_cg_display_reconfig (display, flags, user_info)
11857 CGDirectDisplayID display;
11858 CGDisplayChangeSummaryFlags flags;
11859 void *user_info;
11861 mac_screen_config_changed = 1;
11863 #endif
11865 static OSErr
11866 init_dm_notification_handler ()
11868 OSErr err = noErr;
11870 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11871 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11872 if (CGDisplayRegisterReconfigurationCallback != NULL)
11873 #endif
11875 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11876 NULL);
11878 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11879 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11880 #endif
11881 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11882 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11884 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11885 ProcessSerialNumber psn;
11887 if (handle_dm_notificationUPP == NULL)
11888 handle_dm_notificationUPP =
11889 NewDMNotificationUPP (mac_handle_dm_notification);
11891 err = GetCurrentProcess (&psn);
11892 if (err == noErr)
11893 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11895 #endif
11897 return err;
11900 static void
11901 mac_get_screen_info (dpyinfo)
11902 struct mac_display_info *dpyinfo;
11904 #ifdef MAC_OSX
11905 /* HasDepth returns true if it is possible to have a 32 bit display,
11906 but this may not be what is actually used. Mac OSX can do better. */
11907 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11908 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11910 CGDisplayErr err;
11911 CGDisplayCount ndisps;
11912 CGDirectDisplayID *displays;
11914 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11915 if (err == noErr)
11917 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11918 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11920 if (err == noErr)
11922 CGRect bounds = CGRectZero;
11924 while (ndisps-- > 0)
11925 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11926 dpyinfo->height = CGRectGetHeight (bounds);
11927 dpyinfo->width = CGRectGetWidth (bounds);
11929 else
11931 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11932 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11935 #else /* !MAC_OSX */
11937 GDHandle gdh = GetMainDevice ();
11938 Rect rect = (**gdh).gdRect;
11940 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11941 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11942 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11943 break;
11945 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11946 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11947 UnionRect (&rect, &(**gdh).gdRect, &rect);
11949 dpyinfo->height = rect.bottom - rect.top;
11950 dpyinfo->width = rect.right - rect.left;
11952 #endif /* !MAC_OSX */
11956 #if __profile__
11957 void
11958 profiler_exit_proc ()
11960 ProfilerDump ("\pEmacs.prof");
11961 ProfilerTerm ();
11963 #endif
11965 /* These few functions implement Emacs as a normal Mac application
11966 (almost): set up the heap and the Toolbox, handle necessary system
11967 events plus a few simple menu events. They also set up Emacs's
11968 access to functions defined in the rest of this file. Emacs uses
11969 function hooks to perform all its terminal I/O. A complete list of
11970 these functions appear in termhooks.h. For what they do, read the
11971 comments there and see also w32term.c and xterm.c. What's
11972 noticeably missing here is the event loop, which is normally
11973 present in most Mac application. After performing the necessary
11974 Mac initializations, main passes off control to emacs_main
11975 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11976 (defined further below) to read input. This is where
11977 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
11979 #ifdef MAC_OS8
11980 #undef main
11982 main (void)
11984 #if __profile__ /* is the profiler on? */
11985 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11986 exit(1);
11987 #endif
11989 #if __MWERKS__
11990 /* set creator and type for files created by MSL */
11991 _fcreator = MAC_EMACS_CREATOR_CODE;
11992 _ftype = 'TEXT';
11993 #endif
11995 do_init_managers ();
11997 do_get_menus ();
11999 #ifndef USE_LSB_TAG
12000 do_check_ram_size ();
12001 #endif
12003 init_emacs_passwd_dir ();
12005 init_environ ();
12007 init_coercion_handler ();
12009 initialize_applescript ();
12011 init_apple_event_handler ();
12013 init_dm_notification_handler ();
12016 char **argv;
12017 int argc = 0;
12019 /* set up argv array from STR# resource */
12020 get_string_list (&argv, ARGV_STRING_LIST_ID);
12021 while (argv[argc])
12022 argc++;
12024 /* free up AppleScript resources on exit */
12025 atexit (terminate_applescript);
12027 #if __profile__ /* is the profiler on? */
12028 atexit (profiler_exit_proc);
12029 #endif
12031 /* 3rd param "envp" never used in emacs_main */
12032 (void) emacs_main (argc, argv, 0);
12035 /* Never reached - real exit in Fkill_emacs */
12036 return 0;
12038 #endif
12040 #if !TARGET_API_MAC_CARBON
12041 static RgnHandle mouse_region = NULL;
12043 Boolean
12044 mac_wait_next_event (er, sleep_time, dequeue)
12045 EventRecord *er;
12046 UInt32 sleep_time;
12047 Boolean dequeue;
12049 static EventRecord er_buf = {nullEvent};
12050 UInt32 target_tick, current_tick;
12051 EventMask event_mask;
12053 if (mouse_region == NULL)
12054 mouse_region = NewRgn ();
12056 event_mask = everyEvent;
12057 if (!mac_ready_for_apple_events)
12058 event_mask -= highLevelEventMask;
12060 current_tick = TickCount ();
12061 target_tick = current_tick + sleep_time;
12063 if (er_buf.what == nullEvent)
12064 while (!WaitNextEvent (event_mask, &er_buf,
12065 target_tick - current_tick, mouse_region))
12067 current_tick = TickCount ();
12068 if (target_tick <= current_tick)
12069 return false;
12072 *er = er_buf;
12073 if (dequeue)
12074 er_buf.what = nullEvent;
12075 return true;
12077 #endif /* not TARGET_API_MAC_CARBON */
12079 #if TARGET_API_MAC_CARBON
12080 OSStatus
12081 mac_post_mouse_moved_event ()
12083 EventRef event = NULL;
12084 OSStatus err;
12086 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
12087 kEventAttributeNone, &event);
12088 if (err == noErr)
12090 Point mouse_pos;
12092 GetGlobalMouse (&mouse_pos);
12093 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
12094 sizeof (Point), &mouse_pos);
12096 if (err == noErr)
12098 UInt32 modifiers = GetCurrentKeyModifiers ();
12100 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
12101 sizeof (UInt32), &modifiers);
12103 if (err == noErr)
12104 err = PostEventToQueue (GetCurrentEventQueue (), event,
12105 kEventPriorityStandard);
12106 if (event)
12107 ReleaseEvent (event);
12109 return err;
12111 #endif
12113 /* Emacs calls this whenever it wants to read an input event from the
12114 user. */
12116 XTread_socket (sd, expected, hold_quit)
12117 int sd, expected;
12118 struct input_event *hold_quit;
12120 struct input_event inev;
12121 int count = 0;
12122 #if TARGET_API_MAC_CARBON
12123 EventRef eventRef;
12124 EventTargetRef toolbox_dispatcher;
12125 #endif
12126 EventRecord er;
12127 struct mac_display_info *dpyinfo = &one_mac_display_info;
12129 if (interrupt_input_blocked)
12131 interrupt_input_pending = 1;
12132 return -1;
12135 interrupt_input_pending = 0;
12136 BLOCK_INPUT;
12138 /* So people can tell when we have read the available input. */
12139 input_signal_count++;
12141 ++handling_signal;
12143 #if TARGET_API_MAC_CARBON
12144 toolbox_dispatcher = GetEventDispatcherTarget ();
12146 while (
12147 #if USE_CG_DRAWING
12148 mac_prepare_for_quickdraw (NULL),
12149 #endif
12150 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
12151 kEventRemoveFromQueue, &eventRef))
12152 #else /* !TARGET_API_MAC_CARBON */
12153 while (mac_wait_next_event (&er, 0, true))
12154 #endif /* !TARGET_API_MAC_CARBON */
12156 int do_help = 0;
12157 struct frame *f;
12158 unsigned long timestamp;
12160 EVENT_INIT (inev);
12161 inev.kind = NO_EVENT;
12162 inev.arg = Qnil;
12164 #if TARGET_API_MAC_CARBON
12165 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
12167 if (!mac_convert_event_ref (eventRef, &er))
12168 goto OTHER;
12169 #else /* !TARGET_API_MAC_CARBON */
12170 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12171 #endif /* !TARGET_API_MAC_CARBON */
12173 switch (er.what)
12175 case mouseDown:
12176 case mouseUp:
12178 WindowRef window_ptr;
12179 ControlPartCode part_code;
12180 int tool_bar_p = 0;
12182 #if TARGET_API_MAC_CARBON
12183 OSStatus err;
12185 /* This is needed to send mouse events like aqua window
12186 buttons to the correct handler. */
12187 read_socket_inev = &inev;
12188 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12189 read_socket_inev = NULL;
12190 if (err != eventNotHandledErr)
12191 break;
12192 #endif
12193 last_mouse_glyph_frame = 0;
12195 if (dpyinfo->grabbed && last_mouse_frame
12196 && FRAME_LIVE_P (last_mouse_frame))
12198 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
12199 part_code = inContent;
12201 else
12203 part_code = FindWindow (er.where, &window_ptr);
12204 if (tip_window && window_ptr == tip_window)
12206 HideWindow (tip_window);
12207 part_code = FindWindow (er.where, &window_ptr);
12211 if (er.what != mouseDown &&
12212 (part_code != inContent || dpyinfo->grabbed == 0))
12213 break;
12215 switch (part_code)
12217 case inMenuBar:
12218 f = mac_focus_frame (dpyinfo);
12219 saved_menu_event_location = er.where;
12220 inev.kind = MENU_BAR_ACTIVATE_EVENT;
12221 XSETFRAME (inev.frame_or_window, f);
12222 break;
12224 case inContent:
12225 if (
12226 #if TARGET_API_MAC_CARBON
12227 FrontNonFloatingWindow ()
12228 #else
12229 FrontWindow ()
12230 #endif
12231 != window_ptr
12232 || (mac_window_to_frame (window_ptr)
12233 != dpyinfo->x_focus_frame))
12234 SelectWindow (window_ptr);
12235 else
12237 ControlPartCode control_part_code;
12238 ControlRef ch;
12239 Point mouse_loc;
12240 #ifdef MAC_OSX
12241 ControlKind control_kind;
12242 #endif
12244 f = mac_window_to_frame (window_ptr);
12245 /* convert to local coordinates of new window */
12246 mouse_loc.h = (er.where.h
12247 - (f->left_pos
12248 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12249 mouse_loc.v = (er.where.v
12250 - (f->top_pos
12251 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12252 #if TARGET_API_MAC_CARBON
12253 ch = FindControlUnderMouse (mouse_loc, window_ptr,
12254 &control_part_code);
12255 #ifdef MAC_OSX
12256 if (ch)
12257 GetControlKind (ch, &control_kind);
12258 #endif
12259 #else
12260 control_part_code = FindControl (mouse_loc, window_ptr,
12261 &ch);
12262 #endif
12264 #if TARGET_API_MAC_CARBON
12265 inev.code = mac_get_mouse_btn (eventRef);
12266 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
12267 #else
12268 inev.code = mac_get_emulated_btn (er.modifiers);
12269 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
12270 #endif
12271 XSETINT (inev.x, mouse_loc.h);
12272 XSETINT (inev.y, mouse_loc.v);
12274 if ((dpyinfo->grabbed && tracked_scroll_bar)
12275 || (ch != 0
12276 #ifndef USE_TOOLKIT_SCROLL_BARS
12277 /* control_part_code becomes kControlNoPart if
12278 a progress indicator is clicked. */
12279 && control_part_code != kControlNoPart
12280 #else /* USE_TOOLKIT_SCROLL_BARS */
12281 #ifdef MAC_OSX
12282 && control_kind.kind == kControlKindScrollBar
12283 #endif /* MAC_OSX */
12284 #endif /* USE_TOOLKIT_SCROLL_BARS */
12287 struct scroll_bar *bar;
12289 if (dpyinfo->grabbed && tracked_scroll_bar)
12291 bar = tracked_scroll_bar;
12292 #ifndef USE_TOOLKIT_SCROLL_BARS
12293 control_part_code = kControlIndicatorPart;
12294 #endif
12296 else
12297 bar = (struct scroll_bar *) GetControlReference (ch);
12298 #ifdef USE_TOOLKIT_SCROLL_BARS
12299 /* Make the "Ctrl-Mouse-2 splits window" work
12300 for toolkit scroll bars. */
12301 if (inev.modifiers & ctrl_modifier)
12302 x_scroll_bar_handle_click (bar, control_part_code,
12303 &er, &inev);
12304 else if (er.what == mouseDown)
12305 x_scroll_bar_handle_press (bar, control_part_code,
12306 mouse_loc, &inev);
12307 else
12308 x_scroll_bar_handle_release (bar, &inev);
12309 #else /* not USE_TOOLKIT_SCROLL_BARS */
12310 x_scroll_bar_handle_click (bar, control_part_code,
12311 &er, &inev);
12312 if (er.what == mouseDown
12313 && control_part_code == kControlIndicatorPart)
12314 tracked_scroll_bar = bar;
12315 else
12316 tracked_scroll_bar = NULL;
12317 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12319 else
12321 Lisp_Object window;
12322 int x = mouse_loc.h;
12323 int y = mouse_loc.v;
12325 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
12326 if (EQ (window, f->tool_bar_window))
12328 if (er.what == mouseDown)
12329 handle_tool_bar_click (f, x, y, 1, 0);
12330 else
12331 handle_tool_bar_click (f, x, y, 0,
12332 inev.modifiers);
12333 tool_bar_p = 1;
12335 else
12337 XSETFRAME (inev.frame_or_window, f);
12338 inev.kind = MOUSE_CLICK_EVENT;
12342 if (er.what == mouseDown)
12344 dpyinfo->grabbed |= (1 << inev.code);
12345 last_mouse_frame = f;
12347 if (!tool_bar_p)
12348 last_tool_bar_item = -1;
12350 else
12352 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
12353 /* If a button is released though it was not
12354 previously pressed, that would be because
12355 of multi-button emulation. */
12356 dpyinfo->grabbed = 0;
12357 else
12358 dpyinfo->grabbed &= ~(1 << inev.code);
12361 /* Ignore any mouse motion that happened before
12362 this event; any subsequent mouse-movement Emacs
12363 events should reflect only motion after the
12364 ButtonPress. */
12365 if (f != 0)
12366 f->mouse_moved = 0;
12368 #ifdef USE_TOOLKIT_SCROLL_BARS
12369 if (inev.kind == MOUSE_CLICK_EVENT
12370 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12371 && (inev.modifiers & ctrl_modifier)))
12372 #endif
12373 switch (er.what)
12375 case mouseDown:
12376 inev.modifiers |= down_modifier;
12377 break;
12378 case mouseUp:
12379 inev.modifiers |= up_modifier;
12380 break;
12383 break;
12385 case inDrag:
12386 #if TARGET_API_MAC_CARBON
12387 case inProxyIcon:
12388 if (IsWindowPathSelectClick (window_ptr, &er))
12390 WindowPathSelect (window_ptr, NULL, NULL);
12391 break;
12393 if (part_code == inProxyIcon
12394 && (TrackWindowProxyDrag (window_ptr, er.where)
12395 != errUserWantsToDragWindow))
12396 break;
12397 DragWindow (window_ptr, er.where, NULL);
12398 #else /* not TARGET_API_MAC_CARBON */
12399 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
12400 /* Update the frame parameters. */
12402 struct frame *f = mac_window_to_frame (window_ptr);
12404 if (f && !f->async_iconified)
12405 mac_handle_origin_change (f);
12407 #endif /* not TARGET_API_MAC_CARBON */
12408 break;
12410 case inGoAway:
12411 if (TrackGoAway (window_ptr, er.where))
12413 inev.kind = DELETE_WINDOW_EVENT;
12414 XSETFRAME (inev.frame_or_window,
12415 mac_window_to_frame (window_ptr));
12417 break;
12419 /* window resize handling added --ben */
12420 case inGrow:
12421 do_grow_window (window_ptr, &er);
12422 break;
12424 /* window zoom handling added --ben */
12425 case inZoomIn:
12426 case inZoomOut:
12427 if (TrackBox (window_ptr, er.where, part_code))
12428 do_zoom_window (window_ptr, part_code);
12429 break;
12431 #if USE_MAC_TOOLBAR
12432 case inStructure:
12434 OSStatus err;
12435 HIViewRef ch;
12437 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12438 eventRef, &ch);
12439 /* This doesn't work on Mac OS X 10.2. */
12440 if (err == noErr)
12441 HIViewClick (ch, eventRef);
12443 break;
12444 #endif /* USE_MAC_TOOLBAR */
12446 default:
12447 break;
12450 break;
12452 #if !TARGET_API_MAC_CARBON
12453 case updateEvt:
12454 do_window_update ((WindowRef) er.message);
12455 break;
12456 #endif
12458 case osEvt:
12459 switch ((er.message >> 24) & 0x000000FF)
12461 case mouseMovedMessage:
12462 #if !TARGET_API_MAC_CARBON
12463 SetRectRgn (mouse_region, er.where.h, er.where.v,
12464 er.where.h + 1, er.where.v + 1);
12465 #endif
12466 previous_help_echo_string = help_echo_string;
12467 help_echo_string = Qnil;
12469 if (dpyinfo->grabbed && last_mouse_frame
12470 && FRAME_LIVE_P (last_mouse_frame))
12471 f = last_mouse_frame;
12472 else
12473 f = dpyinfo->x_focus_frame;
12475 if (dpyinfo->mouse_face_hidden)
12477 dpyinfo->mouse_face_hidden = 0;
12478 clear_mouse_face (dpyinfo);
12481 if (f)
12483 WindowRef wp = FRAME_MAC_WINDOW (f);
12484 Point mouse_pos;
12486 mouse_pos.h = (er.where.h
12487 - (f->left_pos
12488 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12489 mouse_pos.v = (er.where.v
12490 - (f->top_pos
12491 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12492 if (dpyinfo->grabbed && tracked_scroll_bar)
12493 #ifdef USE_TOOLKIT_SCROLL_BARS
12494 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
12495 mouse_pos, &inev);
12496 #else /* not USE_TOOLKIT_SCROLL_BARS */
12497 x_scroll_bar_note_movement (tracked_scroll_bar,
12498 mouse_pos.v
12499 - XINT (tracked_scroll_bar->top),
12500 er.when * (1000 / 60));
12501 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12502 else
12504 /* Generate SELECT_WINDOW_EVENTs when needed. */
12505 if (!NILP (Vmouse_autoselect_window))
12507 Lisp_Object window;
12509 window = window_from_coordinates (f,
12510 mouse_pos.h,
12511 mouse_pos.v,
12512 0, 0, 0, 0);
12514 /* Window will be selected only when it is
12515 not selected now and last mouse movement
12516 event was not in it. Minibuffer window
12517 will be selected only when it is active. */
12518 if (WINDOWP (window)
12519 && !EQ (window, last_window)
12520 && !EQ (window, selected_window)
12521 /* For click-to-focus window managers
12522 create event iff we don't leave the
12523 selected frame. */
12524 && (focus_follows_mouse
12525 || (EQ (XWINDOW (window)->frame,
12526 XWINDOW (selected_window)->frame))))
12528 inev.kind = SELECT_WINDOW_EVENT;
12529 inev.frame_or_window = window;
12532 last_window=window;
12534 if (!note_mouse_movement (f, &mouse_pos))
12535 help_echo_string = previous_help_echo_string;
12536 #if USE_MAC_TOOLBAR
12537 else
12538 mac_tool_bar_note_mouse_movement (f, eventRef);
12539 #endif
12543 /* If the contents of the global variable
12544 help_echo_string has changed, generate a
12545 HELP_EVENT. */
12546 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12547 do_help = 1;
12548 break;
12550 default:
12551 goto OTHER;
12553 break;
12555 case activateEvt:
12557 WindowRef window_ptr = (WindowRef) er.message;
12558 OSErr err;
12559 ControlRef root_control;
12561 if (window_ptr == tip_window)
12563 HideWindow (tip_window);
12564 break;
12567 if (!is_emacs_window (window_ptr))
12568 goto OTHER;
12570 f = mac_window_to_frame (window_ptr);
12572 if ((er.modifiers & activeFlag) != 0)
12574 /* A window has been activated */
12575 Point mouse_loc;
12577 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12578 if (err == noErr)
12579 ActivateControl (root_control);
12581 x_detect_focus_change (dpyinfo, &er, &inev);
12583 mouse_loc.h = (er.where.h
12584 - (f->left_pos
12585 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12586 mouse_loc.v = (er.where.v
12587 - (f->top_pos
12588 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12589 /* Window-activated event counts as mouse movement,
12590 so update things that depend on mouse position. */
12591 note_mouse_movement (f, &mouse_loc);
12593 else
12595 /* A window has been deactivated */
12596 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12597 if (err == noErr)
12598 DeactivateControl (root_control);
12600 #ifdef USE_TOOLKIT_SCROLL_BARS
12601 if (dpyinfo->grabbed && tracked_scroll_bar)
12603 struct input_event event;
12605 EVENT_INIT (event);
12606 event.kind = NO_EVENT;
12607 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
12608 if (event.kind != NO_EVENT)
12610 event.timestamp = timestamp;
12611 kbd_buffer_store_event_hold (&event, hold_quit);
12612 count++;
12615 #endif
12616 dpyinfo->grabbed = 0;
12618 x_detect_focus_change (dpyinfo, &er, &inev);
12620 if (f == dpyinfo->mouse_face_mouse_frame)
12622 /* If we move outside the frame, then we're
12623 certainly no longer on any text in the
12624 frame. */
12625 clear_mouse_face (dpyinfo);
12626 dpyinfo->mouse_face_mouse_frame = 0;
12629 /* Generate a nil HELP_EVENT to cancel a help-echo.
12630 Do it only if there's something to cancel.
12631 Otherwise, the startup message is cleared when the
12632 mouse leaves the frame. */
12633 if (any_help_event_p)
12634 do_help = -1;
12637 break;
12639 case keyDown:
12640 case keyUp:
12641 case autoKey:
12642 ObscureCursor ();
12644 f = mac_focus_frame (dpyinfo);
12645 XSETFRAME (inev.frame_or_window, f);
12647 /* If mouse-highlight is an integer, input clears out mouse
12648 highlighting. */
12649 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12650 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12652 clear_mouse_face (dpyinfo);
12653 dpyinfo->mouse_face_hidden = 1;
12657 UInt32 modifiers = er.modifiers, mapped_modifiers;
12659 #ifdef MAC_OSX
12660 GetEventParameter (eventRef, kEventParamKeyModifiers,
12661 typeUInt32, NULL,
12662 sizeof (UInt32), NULL, &modifiers);
12663 #endif
12664 mapped_modifiers = mac_mapped_modifiers (modifiers);
12666 #if TARGET_API_MAC_CARBON
12667 if (!(mapped_modifiers
12668 & ~(mac_pass_command_to_system ? cmdKey : 0)
12669 & ~(mac_pass_control_to_system ? controlKey : 0)))
12670 goto OTHER;
12671 else
12672 #endif
12673 if (er.what != keyUp)
12674 do_keystroke (er.what, er.message & charCodeMask,
12675 (er.message & keyCodeMask) >> 8,
12676 modifiers, timestamp, &inev);
12678 break;
12680 case kHighLevelEvent:
12681 AEProcessAppleEvent (&er);
12682 break;
12684 default:
12685 OTHER:
12686 #if TARGET_API_MAC_CARBON
12688 OSStatus err;
12690 read_socket_inev = &inev;
12691 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12692 read_socket_inev = NULL;
12694 #endif
12695 break;
12697 #if TARGET_API_MAC_CARBON
12698 ReleaseEvent (eventRef);
12699 #endif
12701 if (inev.kind != NO_EVENT)
12703 inev.timestamp = timestamp;
12704 kbd_buffer_store_event_hold (&inev, hold_quit);
12705 count++;
12708 if (do_help
12709 && !(hold_quit && hold_quit->kind != NO_EVENT))
12711 Lisp_Object frame;
12713 if (f)
12714 XSETFRAME (frame, f);
12715 else
12716 frame = Qnil;
12718 if (do_help > 0)
12720 any_help_event_p = 1;
12721 gen_help_event (help_echo_string, frame, help_echo_window,
12722 help_echo_object, help_echo_pos);
12724 else
12726 help_echo_string = Qnil;
12727 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12729 count++;
12733 /* If the focus was just given to an autoraising frame,
12734 raise it now. */
12735 /* ??? This ought to be able to handle more than one such frame. */
12736 if (pending_autoraise_frame)
12738 x_raise_frame (pending_autoraise_frame);
12739 pending_autoraise_frame = 0;
12742 if (mac_screen_config_changed)
12744 mac_get_screen_info (dpyinfo);
12745 mac_screen_config_changed = 0;
12748 #if !TARGET_API_MAC_CARBON
12749 /* Check which frames are still visible. We do this here because
12750 there doesn't seem to be any direct notification from the Window
12751 Manager that the visibility of a window has changed (at least,
12752 not in all cases). */
12754 Lisp_Object tail, frame;
12756 FOR_EACH_FRAME (tail, frame)
12758 struct frame *f = XFRAME (frame);
12760 /* The tooltip has been drawn already. Avoid the
12761 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12762 if (EQ (frame, tip_frame))
12763 continue;
12765 if (FRAME_MAC_P (f))
12766 mac_handle_visibility_change (f);
12769 #endif
12771 --handling_signal;
12772 UNBLOCK_INPUT;
12773 return count;
12777 /* Need to override CodeWarrior's input function so no conversion is
12778 done on newlines Otherwise compiled functions in .elc files will be
12779 read incorrectly. Defined in ...:MSL C:MSL
12780 Common:Source:buffer_io.c. */
12781 #ifdef __MWERKS__
12782 void
12783 __convert_to_newlines (unsigned char * p, size_t * n)
12785 #pragma unused(p,n)
12788 void
12789 __convert_from_newlines (unsigned char * p, size_t * n)
12791 #pragma unused(p,n)
12793 #endif
12795 #ifdef MAC_OS8
12796 void
12797 make_mac_terminal_frame (struct frame *f)
12799 Lisp_Object frame;
12800 Rect r;
12802 XSETFRAME (frame, f);
12804 f->output_method = output_mac;
12805 f->output_data.mac = (struct mac_output *)
12806 xmalloc (sizeof (struct mac_output));
12807 bzero (f->output_data.mac, sizeof (struct mac_output));
12809 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12811 FRAME_COLS (f) = 96;
12812 FRAME_LINES (f) = 4;
12814 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12815 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12817 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
12819 f->output_data.mac->cursor_pixel = 0;
12820 f->output_data.mac->border_pixel = 0x00ff00;
12821 f->output_data.mac->mouse_pixel = 0xff00ff;
12822 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12824 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12825 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12826 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12827 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12828 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12829 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
12831 FRAME_FONTSET (f) = -1;
12832 f->output_data.mac->explicit_parent = 0;
12833 f->left_pos = 8;
12834 f->top_pos = 32;
12835 f->border_width = 0;
12837 f->internal_border_width = 0;
12839 f->auto_raise = 1;
12840 f->auto_lower = 1;
12842 f->new_text_cols = 0;
12843 f->new_text_lines = 0;
12845 SetRect (&r, f->left_pos, f->top_pos,
12846 f->left_pos + FRAME_PIXEL_WIDTH (f),
12847 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12849 BLOCK_INPUT;
12851 if (!(FRAME_MAC_WINDOW (f) =
12852 NewCWindow (NULL, &r, "\p", true, dBoxProc,
12853 (WindowRef) -1, 1, (long) f->output_data.mac)))
12854 abort ();
12855 /* so that update events can find this mac_output struct */
12856 f->output_data.mac->mFP = f; /* point back to emacs frame */
12858 UNBLOCK_INPUT;
12860 x_make_gc (f);
12862 /* Need to be initialized for unshow_buffer in window.c. */
12863 selected_window = f->selected_window;
12865 Fmodify_frame_parameters (frame,
12866 Fcons (Fcons (Qfont,
12867 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12868 Fmodify_frame_parameters (frame,
12869 Fcons (Fcons (Qforeground_color,
12870 build_string ("black")), Qnil));
12871 Fmodify_frame_parameters (frame,
12872 Fcons (Fcons (Qbackground_color,
12873 build_string ("white")), Qnil));
12875 #endif
12878 /***********************************************************************
12879 Initialization
12880 ***********************************************************************/
12882 static int mac_initialized = 0;
12884 static XrmDatabase
12885 mac_make_rdb (xrm_option)
12886 const char *xrm_option;
12888 XrmDatabase database;
12890 database = xrm_get_preference_database (NULL);
12891 if (xrm_option)
12892 xrm_merge_string_database (database, xrm_option);
12894 return database;
12897 struct mac_display_info *
12898 mac_term_init (display_name, xrm_option, resource_name)
12899 Lisp_Object display_name;
12900 char *xrm_option;
12901 char *resource_name;
12903 struct mac_display_info *dpyinfo;
12904 struct terminal *terminal;
12906 BLOCK_INPUT;
12908 if (!mac_initialized)
12910 mac_initialize ();
12911 mac_initialized = 1;
12914 if (x_display_list)
12915 error ("Sorry, this version can only handle one display");
12917 dpyinfo = &one_mac_display_info;
12918 bzero (dpyinfo, sizeof (*dpyinfo));
12920 terminal = mac_create_terminal (dpyinfo);
12922 /* Set the name of the terminal. */
12923 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12924 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12925 terminal->name[SBYTES (display_name)] = 0;
12927 #ifdef MAC_OSX
12928 dpyinfo->mac_id_name
12929 = (char *) xmalloc (SCHARS (Vinvocation_name)
12930 + SCHARS (Vsystem_name)
12931 + 2);
12932 sprintf (dpyinfo->mac_id_name, "%s@%s",
12933 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12934 #else
12935 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12936 strcpy (dpyinfo->mac_id_name, "Mac Display");
12937 #endif
12939 dpyinfo->reference_count = 0;
12940 dpyinfo->resx = 72.0;
12941 dpyinfo->resy = 72.0;
12943 mac_get_screen_info (dpyinfo);
12945 dpyinfo->grabbed = 0;
12946 dpyinfo->root_window = NULL;
12947 dpyinfo->terminal->image_cache = make_image_cache ();
12949 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12950 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12951 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12952 dpyinfo->mouse_face_window = Qnil;
12953 dpyinfo->mouse_face_overlay = Qnil;
12954 dpyinfo->mouse_face_hidden = 0;
12956 dpyinfo->xrdb = mac_make_rdb (xrm_option);
12958 /* Put this display on the chain. */
12959 dpyinfo->next = x_display_list;
12960 x_display_list = dpyinfo;
12962 /* Put it on x_display_name_list. */
12963 x_display_name_list = Fcons (Fcons (display_name,
12964 Fcons (Qnil, dpyinfo->xrdb)),
12965 x_display_name_list);
12966 dpyinfo->name_list_element = XCAR (x_display_name_list);
12968 /* FIXME: Untested.
12969 Add the default keyboard. */
12970 add_keyboard_wait_descriptor (0);
12972 #if USE_CG_DRAWING
12973 mac_init_fringe (terminal->rif);
12974 #endif
12976 UNBLOCK_INPUT;
12978 return dpyinfo;
12981 /* Get rid of display DPYINFO, assuming all frames are already gone. */
12983 void
12984 x_delete_display (dpyinfo)
12985 struct mac_display_info *dpyinfo;
12987 int i;
12989 /* Discard this display from x_display_name_list and x_display_list.
12990 We can't use Fdelq because that can quit. */
12991 if (! NILP (x_display_name_list)
12992 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12993 x_display_name_list = XCDR (x_display_name_list);
12994 else
12996 Lisp_Object tail;
12998 tail = x_display_name_list;
12999 while (CONSP (tail) && CONSP (XCDR (tail)))
13001 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
13003 XSETCDR (tail, XCDR (XCDR (tail)));
13004 break;
13006 tail = XCDR (tail);
13010 if (x_display_list == dpyinfo)
13011 x_display_list = dpyinfo->next;
13012 else
13014 struct x_display_info *tail;
13016 for (tail = x_display_list; tail; tail = tail->next)
13017 if (tail->next == dpyinfo)
13018 tail->next = tail->next->next;
13021 /* Free the font names in the font table. */
13022 for (i = 0; i < dpyinfo->n_fonts; i++)
13023 if (dpyinfo->font_table[i].name)
13025 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
13026 xfree (dpyinfo->font_table[i].full_name);
13027 xfree (dpyinfo->font_table[i].name);
13030 if (dpyinfo->font_table)
13032 if (dpyinfo->font_table->font_encoder)
13033 xfree (dpyinfo->font_table->font_encoder);
13034 xfree (dpyinfo->font_table);
13036 if (dpyinfo->mac_id_name)
13037 xfree (dpyinfo->mac_id_name);
13039 if (x_display_list == 0)
13041 mac_clear_font_name_table ();
13042 bzero (dpyinfo, sizeof (*dpyinfo));
13047 static void
13048 init_menu_bar ()
13050 #ifdef MAC_OSX
13051 OSStatus err;
13052 MenuRef menu;
13053 MenuItemIndex menu_index;
13055 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
13056 &menu, &menu_index);
13057 if (err == noErr)
13058 SetMenuItemCommandKey (menu, menu_index, false, 0);
13059 EnableMenuCommand (NULL, kHICommandPreferences);
13060 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
13061 &menu, &menu_index);
13062 if (err == noErr)
13064 SetMenuItemCommandKey (menu, menu_index, false, 0);
13065 InsertMenuItemTextWithCFString (menu, NULL,
13066 0, kMenuItemAttrSeparator, 0);
13067 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
13068 0, 0, kHICommandAbout);
13070 #else /* !MAC_OSX */
13071 #if TARGET_API_MAC_CARBON
13072 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
13073 #endif
13074 #endif
13077 #if USE_MAC_TSM
13078 static void
13079 init_tsm ()
13081 #ifdef MAC_OSX
13082 static InterfaceTypeList types = {kUnicodeDocument};
13083 #else
13084 static InterfaceTypeList types = {kTextService};
13085 #endif
13087 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
13088 &tsm_document_id, 0);
13090 #endif
13092 /* Set up use of X before we make the first connection. */
13094 extern frame_parm_handler mac_frame_parm_handlers[];
13096 static struct redisplay_interface x_redisplay_interface =
13098 mac_frame_parm_handlers,
13099 x_produce_glyphs,
13100 x_write_glyphs,
13101 x_insert_glyphs,
13102 x_clear_end_of_line,
13103 x_scroll_run,
13104 x_after_update_window_line,
13105 x_update_window_begin,
13106 x_update_window_end,
13107 x_cursor_to,
13108 x_flush,
13109 #if USE_CG_DRAWING
13110 mac_flush_display_optional,
13111 #else
13112 0, /* flush_display_optional */
13113 #endif
13114 x_clear_window_mouse_face,
13115 x_get_glyph_overhangs,
13116 x_fix_overlapping_area,
13117 x_draw_fringe_bitmap,
13118 #if USE_CG_DRAWING
13119 mac_define_fringe_bitmap,
13120 mac_destroy_fringe_bitmap,
13121 #else
13122 0, /* define_fringe_bitmap */
13123 0, /* destroy_fringe_bitmap */
13124 #endif
13125 mac_per_char_metric,
13126 mac_encode_char,
13127 mac_compute_glyph_string_overhangs,
13128 x_draw_glyph_string,
13129 mac_define_frame_cursor,
13130 mac_clear_frame_area,
13131 mac_draw_window_cursor,
13132 mac_draw_vertical_window_border,
13133 mac_shift_glyphs_for_insert
13136 static struct terminal *
13137 mac_create_terminal (struct mac_display_info *dpyinfo)
13139 struct terminal *terminal;
13141 terminal = create_terminal ();
13143 terminal->type = output_mac;
13144 terminal->display_info.mac = dpyinfo;
13145 dpyinfo->terminal = terminal;
13147 terminal->clear_frame_hook = x_clear_frame;
13148 terminal->ins_del_lines_hook = x_ins_del_lines;
13149 terminal->delete_glyphs_hook = x_delete_glyphs;
13150 terminal->ring_bell_hook = XTring_bell;
13151 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
13152 terminal->set_terminal_modes_hook = XTset_terminal_modes;
13153 terminal->update_begin_hook = x_update_begin;
13154 terminal->update_end_hook = x_update_end;
13155 terminal->set_terminal_window_hook = XTset_terminal_window;
13156 terminal->read_socket_hook = XTread_socket;
13157 terminal->frame_up_to_date_hook = XTframe_up_to_date;
13158 terminal->mouse_position_hook = XTmouse_position;
13159 terminal->frame_rehighlight_hook = XTframe_rehighlight;
13160 terminal->frame_raise_lower_hook = XTframe_raise_lower;
13161 /* terminal->fullscreen_hook = XTfullscreen_hook; */
13162 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13163 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13164 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
13165 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
13166 terminal->delete_frame_hook = x_destroy_window;
13167 /* terminal->delete_terminal_hook = x_delete_terminal; */
13169 terminal->rif = &x_redisplay_interface;
13170 #if 0
13171 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
13172 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
13173 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
13174 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
13175 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
13176 scrolls off the
13177 bottom */
13178 #else
13179 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
13180 terminal->char_ins_del_ok = 1;
13181 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
13182 terminal->fast_clear_end_of_line = 1; /* X does this well. */
13183 terminal->memory_below_frame = 0; /* We don't remember what scrolls
13184 off the bottom. */
13186 #endif
13188 /* FIXME: This keyboard setup is 100% untested, just copied from
13189 w32_create_terminal in order to set window-system now that it's
13190 a keyboard object. */
13191 /* We don't yet support separate terminals on Mac, so don't try to share
13192 keyboards between virtual terminals that are on the same physical
13193 terminal like X does. */
13194 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13195 init_kboard (terminal->kboard);
13196 terminal->kboard->Vwindow_system = intern ("mac");
13197 terminal->kboard->next_kboard = all_kboards;
13198 all_kboards = terminal->kboard;
13199 /* Don't let the initial kboard remain current longer than necessary.
13200 That would cause problems if a file loaded on startup tries to
13201 prompt in the mini-buffer. */
13202 if (current_kboard == initial_kboard)
13203 current_kboard = terminal->kboard;
13204 terminal->kboard->reference_count++;
13206 return terminal;
13209 static void
13210 mac_initialize ()
13213 baud_rate = 19200;
13215 last_tool_bar_item = -1;
13216 any_help_event_p = 0;
13218 /* Try to use interrupt input; if we can't, then start polling. */
13219 Fset_input_interrupt_mode (Qt);
13221 BLOCK_INPUT;
13223 #if TARGET_API_MAC_CARBON
13225 install_application_handler ();
13227 init_menu_bar ();
13229 #if USE_MAC_TSM
13230 init_tsm ();
13231 #endif
13233 #ifdef MAC_OSX
13234 init_coercion_handler ();
13236 init_apple_event_handler ();
13238 init_dm_notification_handler ();
13240 if (!inhibit_window_system)
13242 static const ProcessSerialNumber psn = {0, kCurrentProcess};
13244 SetFrontProcess (&psn);
13246 #endif
13247 #endif
13249 #if USE_CG_DRAWING
13250 init_cg_color ();
13251 #endif
13253 UNBLOCK_INPUT;
13258 void
13259 syms_of_macterm ()
13261 #if 0
13262 staticpro (&x_error_message_string);
13263 x_error_message_string = Qnil;
13264 #endif
13266 Qcontrol = intern ("control"); staticpro (&Qcontrol);
13267 Qmeta = intern ("meta"); staticpro (&Qmeta);
13268 Qalt = intern ("alt"); staticpro (&Qalt);
13269 Qhyper = intern ("hyper"); staticpro (&Qhyper);
13270 Qsuper = intern ("super"); staticpro (&Qsuper);
13271 Qmodifier_value = intern ("modifier-value");
13272 staticpro (&Qmodifier_value);
13274 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
13275 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
13276 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
13277 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
13278 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
13280 #if TARGET_API_MAC_CARBON
13281 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
13282 #ifdef MAC_OSX
13283 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
13284 staticpro (&Qtoolbar_switch_mode);
13285 #if USE_MAC_FONT_PANEL
13286 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
13287 Qselection = intern ("selection"); staticpro (&Qselection);
13288 #endif
13290 Qservice = intern ("service"); staticpro (&Qservice);
13291 Qpaste = intern ("paste"); staticpro (&Qpaste);
13292 Qperform = intern ("perform"); staticpro (&Qperform);
13294 Qmouse_drag_overlay = intern ("mouse-drag-overlay");
13295 staticpro (&Qmouse_drag_overlay);
13296 #endif
13297 #if USE_MAC_TSM
13298 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
13299 Qupdate_active_input_area = intern ("update-active-input-area");
13300 staticpro (&Qupdate_active_input_area);
13301 Qunicode_for_key_event = intern ("unicode-for-key-event");
13302 staticpro (&Qunicode_for_key_event);
13303 #endif
13304 #endif
13306 #ifdef MAC_OSX
13307 Fprovide (intern ("mac-carbon"), Qnil);
13308 #endif
13310 staticpro (&Qreverse);
13311 Qreverse = intern ("reverse");
13313 staticpro (&x_display_name_list);
13314 x_display_name_list = Qnil;
13316 staticpro (&last_mouse_scroll_bar);
13317 last_mouse_scroll_bar = Qnil;
13319 staticpro (&fm_font_family_alist);
13320 fm_font_family_alist = Qnil;
13322 #if USE_ATSUI
13323 staticpro (&atsu_font_id_hash);
13324 atsu_font_id_hash = Qnil;
13326 staticpro (&fm_style_face_attributes_alist);
13327 fm_style_face_attributes_alist = Qnil;
13328 #endif
13330 #if USE_MAC_TSM
13331 staticpro (&saved_ts_script_language_on_focus);
13332 saved_ts_script_language_on_focus = Qnil;
13333 #endif
13335 /* We don't yet support this, but defining this here avoids whining
13336 from cus-start.el and other places, like "M-x set-variable". */
13337 DEFVAR_BOOL ("x-use-underline-position-properties",
13338 &x_use_underline_position_properties,
13339 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
13340 A value of nil means ignore them. If you encounter fonts with bogus
13341 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
13342 to 4.1, set this to nil.
13344 NOTE: Not supported on Mac yet. */);
13345 x_use_underline_position_properties = 0;
13347 DEFVAR_BOOL ("x-underline-at-descent-line",
13348 &x_underline_at_descent_line,
13349 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
13350 A value of nil means to draw the underline according to the value of the
13351 variable `x-use-underline-position-properties', which is usually at the
13352 baseline level. The default value is nil. */);
13353 x_underline_at_descent_line = 0;
13355 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
13356 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
13357 #ifdef USE_TOOLKIT_SCROLL_BARS
13358 Vx_toolkit_scroll_bars = Qt;
13359 #else
13360 Vx_toolkit_scroll_bars = Qnil;
13361 #endif
13363 staticpro (&last_mouse_motion_frame);
13364 last_mouse_motion_frame = Qnil;
13366 /* Variables to configure modifier key assignment. */
13368 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
13369 doc: /* *Modifier key assumed when the Mac control key is pressed.
13370 The value can be `control', `meta', `alt', `hyper', or `super' for the
13371 respective modifier. The default is `control'. */);
13372 Vmac_control_modifier = Qcontrol;
13374 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
13375 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13376 The value can be `control', `meta', `alt', `hyper', or `super' for the
13377 respective modifier. If the value is nil then the key will act as the
13378 normal Mac control modifier, and the option key can be used to compose
13379 characters depending on the chosen Mac keyboard setting. */);
13380 Vmac_option_modifier = Qnil;
13382 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
13383 doc: /* *Modifier key assumed when the Mac command key is pressed.
13384 The value can be `control', `meta', `alt', `hyper', or `super' for the
13385 respective modifier. The default is `meta'. */);
13386 Vmac_command_modifier = Qmeta;
13388 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
13389 doc: /* *Modifier key assumed when the Mac function key is pressed.
13390 The value can be `control', `meta', `alt', `hyper', or `super' for the
13391 respective modifier. Note that remapping the function key may lead to
13392 unexpected results for some keys on non-US/GB keyboards. */);
13393 Vmac_function_modifier = Qnil;
13395 DEFVAR_LISP ("mac-emulate-three-button-mouse",
13396 &Vmac_emulate_three_button_mouse,
13397 doc: /* *Specify a way of three button mouse emulation.
13398 The value can be nil, t, or the symbol `reverse'.
13399 A value of nil means that no emulation should be done and the modifiers
13400 should be placed on the mouse-1 event.
13401 t means that when the option-key is held down while pressing the mouse
13402 button, the click will register as mouse-2 and while the command-key
13403 is held down, the click will register as mouse-3.
13404 The symbol `reverse' means that the option-key will register for
13405 mouse-3 and the command-key will register for mouse-2. */);
13406 Vmac_emulate_three_button_mouse = Qnil;
13408 #if TARGET_API_MAC_CARBON
13409 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
13410 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
13411 Otherwise, the right click will be treated as mouse-2 and the wheel
13412 button will be mouse-3. */);
13413 mac_wheel_button_is_mouse_2 = 1;
13415 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
13416 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
13417 mac_pass_command_to_system = 1;
13419 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
13420 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
13421 mac_pass_control_to_system = 1;
13423 #endif
13425 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
13426 doc: /* *If non-nil, allow anti-aliasing.
13427 The text will be rendered using Core Graphics text rendering which
13428 may anti-alias the text. */);
13429 #if USE_CG_DRAWING
13430 mac_use_core_graphics = 1;
13431 #else
13432 mac_use_core_graphics = 0;
13433 #endif
13435 /* Register an entry for `mac-roman' so that it can be used when
13436 creating the terminal frame on Mac OS 9 before loading
13437 term/mac-win.elc. */
13438 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
13439 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
13440 Each entry should be of the form:
13442 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13444 where CHARSET-NAME is a string used in font names to identify the
13445 charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13446 CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
13447 Vmac_charset_info_alist =
13448 Fcons (list3 (build_string ("mac-roman"),
13449 make_number (smRoman), Qnil), Qnil);
13451 #if USE_MAC_TSM
13452 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13453 doc: /* Overlay used to display Mac TSM active input area. */);
13454 Vmac_ts_active_input_overlay = Qnil;
13456 DEFVAR_LISP ("mac-ts-active-input-buf", &Vmac_ts_active_input_buf,
13457 doc: /* Byte sequence of the current Mac TSM active input area. */);
13458 /* `empty_string' is not ready yet on Mac OS Classic. */
13459 Vmac_ts_active_input_buf = build_string ("");
13461 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13462 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13463 If the value is t, the input script and language are restored to those
13464 used in the last focus frame. If the value is a pair of integers, the
13465 input script and language codes, which are defined in the Script
13466 Manager, are set to its car and cdr parts, respectively. Otherwise,
13467 Emacs doesn't set them and thus follows the system default behavior. */);
13468 Vmac_ts_script_language_on_focus = Qnil;
13469 #endif
13472 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13473 (do not change this comment) */