(tar-summarize-buffer): Fix reporter initialization.
[emacs.git] / src / macterm.c
blobae9aa1108d2b5dfbeadb1982e859c0f286ea9e56
1 /* Implementation of GUI terminal on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 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 of the License, or
10 (at your option) 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. If not, see <http://www.gnu.org/licenses/>. */
20 /* Contributed by Andrew Choi (akochoi@mac.com). */
22 #include <config.h>
23 #include <signal.h>
25 #include <stdio.h>
27 #include "lisp.h"
28 #include "blockinput.h"
30 #include "macterm.h"
32 #ifndef MAC_OSX
33 #include <alloca.h>
34 #endif
36 #if !TARGET_API_MAC_CARBON
37 #include <Quickdraw.h>
38 #include <ToolUtils.h>
39 #include <Sound.h>
40 #include <Events.h>
41 #include <Script.h>
42 #include <Resources.h>
43 #include <Fonts.h>
44 #include <TextUtils.h>
45 #include <LowMem.h>
46 #include <Controls.h>
47 #include <Windows.h>
48 #include <Displays.h>
49 #if defined (__MRC__) || (__MSL__ >= 0x6000)
50 #include <ControlDefinitions.h>
51 #endif
53 #if __profile__
54 #include <profiler.h>
55 #endif
56 #endif /* not TARGET_API_MAC_CARBON */
58 #include "systty.h"
59 #include "systime.h"
61 #include <ctype.h>
62 #include <errno.h>
63 #include <setjmp.h>
64 #include <sys/stat.h>
66 #include "charset.h"
67 #include "coding.h"
68 #include "frame.h"
69 #include "dispextern.h"
70 #include "fontset.h"
71 #include "termhooks.h"
72 #include "termopts.h"
73 #include "termchar.h"
74 #include "disptab.h"
75 #include "buffer.h"
76 #include "window.h"
77 #include "keyboard.h"
78 #include "intervals.h"
79 #include "atimer.h"
80 #include "keymap.h"
81 #include "character.h"
82 #include "ccl.h"
86 /* Non-nil means Emacs uses toolkit scroll bars. */
88 Lisp_Object Vx_toolkit_scroll_bars;
90 /* If non-zero, the text will be rendered using Core Graphics text
91 rendering which may anti-alias the text. */
92 int mac_use_core_graphics;
95 /* Non-zero means that a HELP_EVENT has been generated since Emacs
96 start. */
98 static int any_help_event_p;
100 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
101 static Lisp_Object last_window;
103 /* Non-zero means make use of UNDERLINE_POSITION font properties.
104 (Not yet supported.) */
105 int x_use_underline_position_properties;
107 /* Non-zero means to draw the underline at the same place as the descent line. */
109 int x_underline_at_descent_line;
111 /* This is a chain of structures for all the X displays currently in
112 use. */
114 struct x_display_info *x_display_list;
116 /* This is a list of cons cells, each of the form (NAME
117 FONT-LIST-CACHE . RESOURCE-DATABASE), one for each element of
118 x_display_list and in the same order. NAME is the name of the
119 frame. FONT-LIST-CACHE records previous values returned by
120 x-list-fonts. RESOURCE-DATABASE preserves the X Resource Database
121 equivalent, which is implemented with a Lisp object, for the
122 display. */
124 Lisp_Object x_display_name_list;
126 /* This is display since Mac does not support multiple ones. */
127 struct mac_display_info one_mac_display_info;
129 /* Frame being updated by update_frame. This is declared in term.c.
130 This is set by update_begin and looked at by all the XT functions.
131 It is zero while not inside an update. In that case, the XT
132 functions assume that `selected_frame' is the frame to apply to. */
134 extern struct frame *updating_frame;
136 /* This is a frame waiting to be auto-raised, within XTread_socket. */
138 struct frame *pending_autoraise_frame;
140 /* Mouse movement.
142 Formerly, we used PointerMotionHintMask (in standard_event_mask)
143 so that we would have to call XQueryPointer after each MotionNotify
144 event to ask for another such event. However, this made mouse tracking
145 slow, and there was a bug that made it eventually stop.
147 Simply asking for MotionNotify all the time seems to work better.
149 In order to avoid asking for motion events and then throwing most
150 of them away or busy-polling the server for mouse positions, we ask
151 the server for pointer motion hints. This means that we get only
152 one event per group of mouse movements. "Groups" are delimited by
153 other kinds of events (focus changes and button clicks, for
154 example), or by XQueryPointer calls; when one of these happens, we
155 get another MotionNotify event the next time the mouse moves. This
156 is at least as efficient as getting motion events when mouse
157 tracking is on, and I suspect only negligibly worse when tracking
158 is off. */
160 /* Where the mouse was last time we reported a mouse event. */
162 static Rect last_mouse_glyph;
163 static FRAME_PTR last_mouse_glyph_frame;
165 /* The scroll bar in which the last X motion event occurred.
167 If the last X motion event occurred in a scroll bar, we set this so
168 XTmouse_position can know whether to report a scroll bar motion or
169 an ordinary motion.
171 If the last X motion event didn't occur in a scroll bar, we set
172 this to Qnil, to tell XTmouse_position to return an ordinary motion
173 event. */
175 static Lisp_Object last_mouse_scroll_bar;
177 /* This is a hack. We would really prefer that XTmouse_position would
178 return the time associated with the position it returns, but there
179 doesn't seem to be any way to wrest the time-stamp from the server
180 along with the position query. So, we just keep track of the time
181 of the last movement we received, and return that in hopes that
182 it's somewhat accurate. */
184 static Time last_mouse_movement_time;
186 struct scroll_bar *tracked_scroll_bar = NULL;
188 /* Incremented by XTread_socket whenever it really tries to read
189 events. */
191 #ifdef __STDC__
192 static int volatile input_signal_count;
193 #else
194 static int input_signal_count;
195 #endif
197 extern Lisp_Object Vsystem_name;
199 extern Lisp_Object Qeql;
201 /* A mask of extra modifier bits to put into every keyboard char. */
203 extern EMACS_INT extra_keyboard_modifiers;
205 /* The keysyms to use for the various modifiers. */
207 static Lisp_Object Qalt, Qhyper, Qsuper, Qcontrol, Qmeta, Qmodifier_value;
209 extern int inhibit_window_system;
211 #if __MRC__ && !TARGET_API_MAC_CARBON
212 QDGlobals qd; /* QuickDraw global information structure. */
213 #endif
215 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
217 struct mac_display_info *mac_display_info_for_display (Display *);
218 static void x_update_window_end P_ ((struct window *, int, int));
219 int x_catch_errors P_ ((Display *));
220 void x_uncatch_errors P_ ((Display *, int));
221 void x_lower_frame P_ ((struct frame *));
222 void x_scroll_bar_clear P_ ((struct frame *));
223 int x_had_errors_p P_ ((Display *));
224 void x_wm_set_size_hint P_ ((struct frame *, long, int));
225 void x_raise_frame P_ ((struct frame *));
226 void x_set_window_size P_ ((struct frame *, int, int, int));
227 void x_wm_set_window_state P_ ((struct frame *, int));
228 void x_wm_set_icon_pixmap P_ ((struct frame *, int));
229 static void mac_initialize P_ ((void));
230 static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
231 static int x_compute_min_glyph_bounds P_ ((struct frame *));
232 static void x_update_end P_ ((struct frame *));
233 static void XTframe_up_to_date P_ ((struct frame *));
234 static void XTset_terminal_modes P_ ((struct terminal *));
235 static void XTreset_terminal_modes P_ ((struct terminal *));
236 static void x_clear_frame P_ ((struct frame *));
237 static void frame_highlight P_ ((struct frame *));
238 static void frame_unhighlight P_ ((struct frame *));
239 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
240 static void mac_focus_changed P_ ((int, struct mac_display_info *,
241 struct frame *, struct input_event *));
242 static void x_detect_focus_change P_ ((struct mac_display_info *,
243 const EventRecord *,
244 struct input_event *));
245 static void XTframe_rehighlight P_ ((struct frame *));
246 static void x_frame_rehighlight P_ ((struct x_display_info *));
247 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
248 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
249 enum text_cursor_kinds));
251 static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
252 static void x_flush P_ ((struct frame *f));
253 static void x_update_begin P_ ((struct frame *));
254 static void x_update_window_begin P_ ((struct window *));
255 static void x_after_update_window_line P_ ((struct glyph_row *));
256 static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
257 enum scroll_bar_part *,
258 Lisp_Object *, Lisp_Object *,
259 unsigned long *));
261 static int is_emacs_window P_ ((WindowRef));
262 static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int));
263 static void XSetFont P_ ((Display *, GC, XFontStruct *));
264 static struct terminal *mac_create_terminal P_ ((struct mac_display_info *dpyinfo));
267 #define GC_FORE_COLOR(gc) (&(gc)->fore_color)
268 #define GC_BACK_COLOR(gc) (&(gc)->back_color)
269 #define GC_FONT(gc) ((gc)->xgcv.font)
270 #define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
272 #define CG_SET_FILL_COLOR(context, color) \
273 CGContextSetRGBFillColor (context, \
274 RED_FROM_ULONG (color) / 255.0f, \
275 GREEN_FROM_ULONG (color) / 255.0f, \
276 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
277 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
278 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
279 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
280 do { \
281 if (CGColorGetTypeID != NULL) \
282 CGContextSetFillColorWithColor (context, cg_color); \
283 else \
284 CG_SET_FILL_COLOR (context, color); \
285 } while (0)
286 #else
287 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
288 CGContextSetFillColorWithColor (context, cg_color)
289 #endif
290 #else
291 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
292 CG_SET_FILL_COLOR (context, color)
293 #endif
294 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, gc) \
295 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
296 (gc)->cg_fore_color)
297 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, gc) \
298 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.background, \
299 (gc)->cg_back_color)
302 #define CG_SET_STROKE_COLOR(context, color) \
303 CGContextSetRGBStrokeColor (context, \
304 RED_FROM_ULONG (color) / 255.0f, \
305 GREEN_FROM_ULONG (color) / 255.0f, \
306 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
307 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
308 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
309 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
310 do { \
311 if (CGColorGetTypeID != NULL) \
312 CGContextSetStrokeColorWithColor (context, cg_color); \
313 else \
314 CG_SET_STROKE_COLOR (context, color); \
315 } while (0)
316 #else
317 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
318 CGContextSetStrokeColorWithColor (context, cg_color)
319 #endif
320 #else
321 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
322 CG_SET_STROKE_COLOR (context, color)
323 #endif
324 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, gc) \
325 CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
326 (gc)->cg_fore_color)
328 #if USE_CG_DRAWING
329 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
331 /* Fringe bitmaps. */
333 static int max_fringe_bmp = 0;
334 static CGImageRef *fringe_bmp = 0;
336 CGColorSpaceRef mac_cg_color_space_rgb;
337 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
338 static CGColorRef mac_cg_color_black;
339 #endif
341 static void
342 init_cg_color ()
344 mac_cg_color_space_rgb = CGColorSpaceCreateDeviceRGB ();
345 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
346 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
347 /* Don't check the availability of CGColorCreate; this symbol is
348 defined even in Mac OS X 10.1. */
349 if (CGColorGetTypeID != NULL)
350 #endif
352 CGFloat rgba[] = {0.0f, 0.0f, 0.0f, 1.0f};
354 mac_cg_color_black = CGColorCreate (mac_cg_color_space_rgb, rgba);
356 #endif
359 static CGContextRef
360 mac_begin_cg_clip (f, gc)
361 struct frame *f;
362 GC gc;
364 CGContextRef context = FRAME_CG_CONTEXT (f);
366 if (!context)
368 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
369 FRAME_CG_CONTEXT (f) = context;
372 CGContextSaveGState (context);
373 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
374 CGContextScaleCTM (context, 1, -1);
375 if (gc && gc->n_clip_rects)
376 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
378 return context;
381 static void
382 mac_end_cg_clip (f)
383 struct frame *f;
385 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
388 void
389 mac_prepare_for_quickdraw (f)
390 struct frame *f;
392 if (f == NULL)
394 Lisp_Object rest, frame;
395 FOR_EACH_FRAME (rest, frame)
396 if (FRAME_MAC_P (XFRAME (frame)))
397 mac_prepare_for_quickdraw (XFRAME (frame));
399 else
401 CGContextRef context = FRAME_CG_CONTEXT (f);
403 if (context)
405 CGContextSynchronize (context);
406 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
407 &FRAME_CG_CONTEXT (f));
411 #endif
413 static RgnHandle saved_port_clip_region = NULL;
415 static void
416 mac_begin_clip (f, gc)
417 struct frame *f;
418 GC gc;
420 static RgnHandle new_region = NULL;
422 if (saved_port_clip_region == NULL)
423 saved_port_clip_region = NewRgn ();
424 if (new_region == NULL)
425 new_region = NewRgn ();
427 #if USE_CG_DRAWING
428 mac_prepare_for_quickdraw (f);
429 #endif
430 SetPortWindowPort (FRAME_MAC_WINDOW (f));
432 if (gc->n_clip_rects)
434 GetClip (saved_port_clip_region);
435 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
436 SetClip (new_region);
440 static void
441 mac_end_clip (gc)
442 GC gc;
444 if (gc->n_clip_rects)
445 SetClip (saved_port_clip_region);
449 /* X display function emulation */
451 /* Mac version of XDrawLine. */
453 static void
454 mac_draw_line (f, gc, x1, y1, x2, y2)
455 struct frame *f;
456 GC gc;
457 int x1, y1, x2, y2;
459 #if USE_CG_DRAWING
460 CGContextRef context;
461 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
463 if (y1 != y2)
464 gx1 += 0.5f, gx2 += 0.5f;
465 if (x1 != x2)
466 gy1 += 0.5f, gy2 += 0.5f;
468 context = mac_begin_cg_clip (f, gc);
469 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
470 CGContextBeginPath (context);
471 CGContextMoveToPoint (context, gx1, gy1);
472 CGContextAddLineToPoint (context, gx2, gy2);
473 CGContextClosePath (context);
474 CGContextStrokePath (context);
475 mac_end_cg_clip (f);
476 #else
477 if (x1 == x2)
479 if (y1 > y2)
480 y1--;
481 else if (y2 > y1)
482 y2--;
484 else if (y1 == y2)
486 if (x1 > x2)
487 x1--;
488 else
489 x2--;
492 mac_begin_clip (f, gc);
493 RGBForeColor (GC_FORE_COLOR (gc));
494 MoveTo (x1, y1);
495 LineTo (x2, y2);
496 mac_end_clip (gc);
497 #endif
500 /* Mac version of XDrawLine (to Pixmap). */
502 void
503 XDrawLine (display, p, gc, x1, y1, x2, y2)
504 Display *display;
505 Pixmap p;
506 GC gc;
507 int x1, y1, x2, y2;
509 #if USE_MAC_IMAGE_IO
510 CGContextRef context;
511 XImagePtr ximg = p;
512 CGColorSpaceRef color_space;
513 CGImageAlphaInfo alpha_info;
514 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
516 if (y1 != y2)
517 gx1 += 0.5f, gx2 += 0.5f;
518 if (x1 != x2)
519 gy1 += 0.5f, gy2 += 0.5f;
521 if (ximg->bits_per_pixel == 32)
523 color_space = mac_cg_color_space_rgb;
524 alpha_info = (kCGImageAlphaNoneSkipFirst
525 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
526 | kCGBitmapByteOrder32Host
527 #endif
530 else
532 color_space = NULL;
533 alpha_info = kCGImageAlphaOnly;
535 if (color_space == NULL)
536 return;
537 context = CGBitmapContextCreate (ximg->data, ximg->width,
538 ximg->height, 8,
539 ximg->bytes_per_line, color_space,
540 alpha_info);
541 if (ximg->bits_per_pixel == 32)
542 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
543 else
544 CGContextSetGrayStrokeColor (context, gc->xgcv.foreground / 255.0f, 1.0);
545 CGContextMoveToPoint (context, gx1, gy1);
546 CGContextAddLineToPoint (context, gx2, gy2);
547 CGContextClosePath (context);
548 CGContextStrokePath (context);
549 CGContextRelease (context);
550 #else
551 CGrafPtr old_port;
552 GDHandle old_gdh;
554 if (x1 == x2)
556 if (y1 > y2)
557 y1--;
558 else if (y2 > y1)
559 y2--;
561 else if (y1 == y2)
563 if (x1 > x2)
564 x1--;
565 else
566 x2--;
569 GetGWorld (&old_port, &old_gdh);
570 SetGWorld (p, NULL);
572 RGBForeColor (GC_FORE_COLOR (gc));
574 LockPixels (GetGWorldPixMap (p));
575 MoveTo (x1, y1);
576 LineTo (x2, y2);
577 UnlockPixels (GetGWorldPixMap (p));
579 SetGWorld (old_port, old_gdh);
580 #endif
584 static void
585 mac_erase_rectangle (f, gc, x, y, width, height)
586 struct frame *f;
587 GC gc;
588 int x, y;
589 unsigned int width, height;
591 #if USE_CG_DRAWING
593 CGContextRef context;
595 context = mac_begin_cg_clip (f, gc);
596 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
597 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
598 mac_end_cg_clip (f);
600 #else
602 Rect r;
604 mac_begin_clip (f, gc);
605 RGBBackColor (GC_BACK_COLOR (gc));
606 SetRect (&r, x, y, x + width, y + height);
607 EraseRect (&r);
608 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
609 mac_end_clip (gc);
611 #endif
615 /* Mac version of XClearArea. */
617 void
618 mac_clear_area (f, x, y, width, height)
619 struct frame *f;
620 int x, y;
621 unsigned int width, height;
623 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
626 /* Mac version of XClearWindow. */
628 static void
629 mac_clear_window (f)
630 struct frame *f;
632 #if USE_CG_DRAWING
634 CGContextRef context;
635 GC gc = FRAME_NORMAL_GC (f);
637 context = mac_begin_cg_clip (f, NULL);
638 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
639 CGContextFillRect (context, CGRectMake (0, 0, FRAME_PIXEL_WIDTH (f),
640 FRAME_PIXEL_HEIGHT (f)));
641 mac_end_cg_clip (f);
643 #else /* !USE_CG_DRAWING */
644 SetPortWindowPort (FRAME_MAC_WINDOW (f));
646 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
648 #if TARGET_API_MAC_CARBON
650 Rect r;
652 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
653 EraseRect (&r);
655 #else /* not TARGET_API_MAC_CARBON */
656 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
657 #endif /* not TARGET_API_MAC_CARBON */
658 #endif
662 /* Mac replacement for XCopyArea. */
664 #if USE_CG_DRAWING
665 static void
666 mac_draw_cg_image (image, f, gc, src_x, src_y, width, height,
667 dest_x, dest_y, overlay_p)
668 CGImageRef image;
669 struct frame *f;
670 GC gc;
671 int src_x, src_y;
672 unsigned int width, height;
673 int dest_x, dest_y, overlay_p;
675 CGContextRef context;
676 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
677 CGRect dest_rect = mac_rect_make (f, dest_x, dest_y, width, height);
679 context = mac_begin_cg_clip (f, gc);
680 if (!overlay_p)
682 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
683 CGContextFillRect (context, dest_rect);
685 CGContextClipToRect (context, dest_rect);
686 CGContextScaleCTM (context, 1, -1);
687 CGContextTranslateCTM (context, 0, -port_height);
688 if (CGImageIsMask (image))
689 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
690 CGContextDrawImage (context,
691 mac_rect_make (f, dest_x - src_x,
692 port_height - (dest_y - src_y
693 + CGImageGetHeight (image)),
694 CGImageGetWidth (image),
695 CGImageGetHeight (image)),
696 image);
697 mac_end_cg_clip (f);
700 #else /* !USE_CG_DRAWING */
702 static void
703 mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
704 struct frame *f;
705 GC gc;
706 int x, y, width, height;
707 unsigned short *bits;
708 int overlay_p;
710 BitMap bitmap;
711 Rect r;
713 bitmap.rowBytes = sizeof(unsigned short);
714 bitmap.baseAddr = (char *)bits;
715 SetRect (&(bitmap.bounds), 0, 0, width, height);
717 mac_begin_clip (f, gc);
718 RGBForeColor (GC_FORE_COLOR (gc));
719 RGBBackColor (GC_BACK_COLOR (gc));
720 SetRect (&r, x, y, x + width, y + height);
721 #if TARGET_API_MAC_CARBON
723 CGrafPtr port;
725 GetPort (&port);
726 LockPortBits (port);
727 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
728 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
729 UnlockPortBits (port);
731 #else /* not TARGET_API_MAC_CARBON */
732 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
733 overlay_p ? srcOr : srcCopy, 0);
734 #endif /* not TARGET_API_MAC_CARBON */
735 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
736 mac_end_clip (gc);
738 #endif /* !USE_CG_DRAWING */
741 /* Mac replacement for XCreateBitmapFromBitmapData. */
743 static void
744 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
745 BitMap *bitmap;
746 char *bits;
747 int w, h;
749 static const unsigned char swap_nibble[16]
750 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
751 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
752 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
753 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
754 int i, j, w1;
755 char *p;
757 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
758 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
759 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
760 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
761 for (i = 0; i < h; i++)
763 p = bitmap->baseAddr + i * bitmap->rowBytes;
764 for (j = 0; j < w1; j++)
766 /* Bitswap XBM bytes to match how Mac does things. */
767 unsigned char c = *bits++;
768 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
769 | (swap_nibble[(c>>4) & 0xf]));
773 SetRect (&(bitmap->bounds), 0, 0, w, h);
777 static void
778 mac_free_bitmap (bitmap)
779 BitMap *bitmap;
781 xfree (bitmap->baseAddr);
785 Pixmap
786 XCreatePixmap (display, w, width, height, depth)
787 Display *display;
788 Window w;
789 unsigned int width, height;
790 unsigned int depth;
792 #if USE_MAC_IMAGE_IO
793 XImagePtr ximg;
795 ximg = xmalloc (sizeof (*ximg));
796 ximg->width = width;
797 ximg->height = height;
798 ximg->bits_per_pixel = depth == 1 ? 8 : 32;
799 ximg->bytes_per_line = width * (ximg->bits_per_pixel / 8);
800 ximg->data = xmalloc (ximg->bytes_per_line * height);
801 return ximg;
802 #else
803 Pixmap pixmap;
804 Rect r;
805 QDErr err;
807 #ifdef MAC_OS8
808 SetPortWindowPort (w);
809 #endif
810 SetRect (&r, 0, 0, width, height);
811 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
812 if (depth == 1)
813 #endif
814 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
815 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
816 else
817 /* CreateCGImageFromPixMaps requires ARGB format. */
818 err = QTNewGWorld (&pixmap, k32ARGBPixelFormat, &r, NULL, NULL, 0);
819 #endif
820 if (err != noErr)
821 return NULL;
822 return pixmap;
823 #endif
827 Pixmap
828 XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
829 Display *display;
830 Window w;
831 char *data;
832 unsigned int width, height;
833 unsigned long fg, bg;
834 unsigned int depth;
836 Pixmap pixmap;
837 BitMap bitmap;
838 #if USE_MAC_IMAGE_IO
839 CGDataProviderRef provider;
840 CGImageRef image_mask;
841 CGContextRef context;
843 pixmap = XCreatePixmap (display, w, width, height, depth);
844 if (pixmap == NULL)
845 return NULL;
847 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
848 provider = CGDataProviderCreateWithData (NULL, bitmap.baseAddr,
849 bitmap.rowBytes * height, NULL);
850 image_mask = CGImageMaskCreate (width, height, 1, 1, bitmap.rowBytes,
851 provider, NULL, 0);
852 CGDataProviderRelease (provider);
854 context = CGBitmapContextCreate (pixmap->data, width, height, 8,
855 pixmap->bytes_per_line,
856 mac_cg_color_space_rgb,
857 kCGImageAlphaNoneSkipFirst
858 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
859 | kCGBitmapByteOrder32Host
860 #endif
863 CG_SET_FILL_COLOR (context, fg);
864 CGContextFillRect (context, CGRectMake (0, 0, width, height));
865 CG_SET_FILL_COLOR (context, bg);
866 CGContextDrawImage (context, CGRectMake (0, 0, width, height), image_mask);
867 CGContextRelease (context);
868 CGImageRelease (image_mask);
869 #else
870 CGrafPtr old_port;
871 GDHandle old_gdh;
872 static GC gc = NULL;
874 if (gc == NULL)
875 gc = XCreateGC (display, w, 0, NULL);
877 pixmap = XCreatePixmap (display, w, width, height, depth);
878 if (pixmap == NULL)
879 return NULL;
881 GetGWorld (&old_port, &old_gdh);
882 SetGWorld (pixmap, NULL);
883 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
884 XSetForeground (display, gc, fg);
885 XSetBackground (display, gc, bg);
886 RGBForeColor (GC_FORE_COLOR (gc));
887 RGBBackColor (GC_BACK_COLOR (gc));
888 LockPixels (GetGWorldPixMap (pixmap));
889 #if TARGET_API_MAC_CARBON
890 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
891 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
892 #else /* not TARGET_API_MAC_CARBON */
893 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
894 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
895 #endif /* not TARGET_API_MAC_CARBON */
896 UnlockPixels (GetGWorldPixMap (pixmap));
897 SetGWorld (old_port, old_gdh);
898 #endif
899 mac_free_bitmap (&bitmap);
901 return pixmap;
905 void
906 XFreePixmap (display, pixmap)
907 Display *display;
908 Pixmap pixmap;
910 #if USE_MAC_IMAGE_IO
911 if (pixmap)
913 if (pixmap->data)
914 xfree (pixmap->data);
915 xfree (pixmap);
917 #else
918 DisposeGWorld (pixmap);
919 #endif
923 /* Mac replacement for XFillRectangle. */
925 static void
926 mac_fill_rectangle (f, gc, x, y, width, height)
927 struct frame *f;
928 GC gc;
929 int x, y;
930 unsigned int width, height;
932 #if USE_CG_DRAWING
933 CGContextRef context;
935 context = mac_begin_cg_clip (f, gc);
936 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
937 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
938 mac_end_cg_clip (f);
939 #else
940 Rect r;
942 mac_begin_clip (f, gc);
943 RGBForeColor (GC_FORE_COLOR (gc));
944 SetRect (&r, x, y, x + width, y + height);
945 PaintRect (&r); /* using foreground color of gc */
946 mac_end_clip (gc);
947 #endif
951 /* Mac replacement for XDrawRectangle: dest is a window. */
953 static void
954 mac_draw_rectangle (f, gc, x, y, width, height)
955 struct frame *f;
956 GC gc;
957 int x, y;
958 unsigned int width, height;
960 #if USE_CG_DRAWING
961 CGContextRef context;
963 context = mac_begin_cg_clip (f, gc);
964 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
965 CGContextStrokeRect (context,
966 CGRectMake (x + 0.5f, y + 0.5f, width, height));
967 mac_end_cg_clip (f);
968 #else
969 Rect r;
971 mac_begin_clip (f, gc);
972 RGBForeColor (GC_FORE_COLOR (gc));
973 SetRect (&r, x, y, x + width + 1, y + height + 1);
974 FrameRect (&r); /* using foreground color of gc */
975 mac_end_clip (gc);
976 #endif
980 static void
981 mac_invert_rectangle (f, x, y, width, height)
982 struct frame *f;
983 int x, y;
984 unsigned int width, height;
986 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
987 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
988 if (CGContextSetBlendMode != NULL)
989 #endif
991 CGContextRef context;
993 context = mac_begin_cg_clip (f, NULL);
994 CGContextSetRGBFillColor (context, 1.0f, 1.0f, 1.0f, 1.0f);
995 CGContextSetBlendMode (context, kCGBlendModeDifference);
996 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
997 mac_end_cg_clip (f);
999 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
1000 else /* CGContextSetBlendMode == NULL */
1001 #endif
1002 #endif /* USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 */
1003 #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)
1005 Rect r;
1007 #if USE_CG_DRAWING
1008 mac_prepare_for_quickdraw (f);
1009 #endif
1010 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1012 SetRect (&r, x, y, x + width, y + height);
1014 InvertRect (&r);
1018 #if USE_ATSUI
1019 static OSStatus
1020 atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
1021 ConstUniCharArrayPtr text;
1022 UniCharCount text_length;
1023 ATSUStyle style;
1024 ATSUTextLayout *text_layout;
1026 OSStatus err;
1027 static ATSUTextLayout saved_text_layout = NULL;
1029 if (saved_text_layout == NULL)
1031 static const UniCharCount lengths[] = {kATSUToTextEnd};
1032 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
1033 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
1034 static ATSLineLayoutOptions line_layout =
1035 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1036 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
1037 | kATSLineUseQDRendering
1038 #else
1039 kATSLineIsDisplayOnly | kATSLineFractDisable
1040 #endif
1042 static const ATSUAttributeValuePtr values[] = {&line_layout};
1044 err = ATSUCreateTextLayoutWithTextPtr (text,
1045 kATSUFromTextBeginning,
1046 kATSUToTextEnd,
1047 text_length,
1048 1, lengths, &style,
1049 &saved_text_layout);
1050 if (err == noErr)
1051 err = ATSUSetLayoutControls (saved_text_layout,
1052 sizeof (tags) / sizeof (tags[0]),
1053 tags, sizes, values);
1054 if (err == noErr)
1055 err = ATSUSetTransientFontMatching (saved_text_layout, true);
1057 else
1059 err = ATSUSetRunStyle (saved_text_layout, style,
1060 kATSUFromTextBeginning, kATSUToTextEnd);
1061 if (err == noErr)
1062 err = ATSUSetTextPointerLocation (saved_text_layout, text,
1063 kATSUFromTextBeginning,
1064 kATSUToTextEnd,
1065 text_length);
1068 if (err == noErr)
1069 *text_layout = saved_text_layout;
1070 return err;
1074 static void
1075 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1076 overstrike_p, bytes_per_char)
1077 struct frame *f;
1078 GC gc;
1079 int x, y;
1080 char *buf;
1081 int nchars, bg_width, overstrike_p, bytes_per_char;
1083 OSStatus err;
1084 ATSUTextLayout text_layout;
1086 xassert (bytes_per_char == 2);
1088 #ifndef WORDS_BIG_ENDIAN
1090 int i;
1091 UniChar *text = (UniChar *)buf;
1093 for (i = 0; i < nchars; i++)
1094 text[i] = EndianU16_BtoN (text[i]);
1096 #endif
1097 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
1098 nchars,
1099 GC_FONT (gc)->mac_style,
1100 &text_layout);
1101 if (err != noErr)
1102 return;
1103 #ifdef MAC_OSX
1104 if (!mac_use_core_graphics)
1106 #endif
1107 mac_begin_clip (f, gc);
1108 RGBForeColor (GC_FORE_COLOR (gc));
1109 if (bg_width)
1111 Rect r;
1113 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1114 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1115 RGBBackColor (GC_BACK_COLOR (gc));
1116 EraseRect (&r);
1117 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1119 MoveTo (x, y);
1120 ATSUDrawText (text_layout,
1121 kATSUFromTextBeginning, kATSUToTextEnd,
1122 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1123 if (overstrike_p)
1125 MoveTo (x + 1, y);
1126 ATSUDrawText (text_layout,
1127 kATSUFromTextBeginning, kATSUToTextEnd,
1128 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1130 mac_end_clip (gc);
1131 #ifdef MAC_OSX
1133 else
1135 static CGContextRef context;
1136 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
1137 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1138 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1139 static const ATSUAttributeValuePtr values[] = {&context};
1141 #if USE_CG_DRAWING
1142 context = mac_begin_cg_clip (f, gc);
1143 #else
1144 CGrafPtr port;
1146 GetPort (&port);
1147 QDBeginCGContext (port, &context);
1148 if (gc->n_clip_rects || bg_width)
1150 CGContextTranslateCTM (context, 0, port_height);
1151 CGContextScaleCTM (context, 1, -1);
1152 if (gc->n_clip_rects)
1153 CGContextClipToRects (context, gc->clip_rects,
1154 gc->n_clip_rects);
1155 #endif
1156 if (bg_width)
1158 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1159 CGContextFillRect (context,
1160 mac_rect_make (f,
1161 x, y - FONT_BASE (GC_FONT (gc)),
1162 bg_width,
1163 FONT_HEIGHT (GC_FONT (gc))));
1165 CGContextScaleCTM (context, 1, -1);
1166 CGContextTranslateCTM (context, 0, -port_height);
1167 #if !USE_CG_DRAWING
1169 #endif
1170 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1171 err = ATSUSetLayoutControls (text_layout,
1172 sizeof (tags) / sizeof (tags[0]),
1173 tags, sizes, values);
1174 if (err == noErr)
1176 ATSUDrawText (text_layout,
1177 kATSUFromTextBeginning, kATSUToTextEnd,
1178 Long2Fix (x), Long2Fix (port_height - y));
1179 if (overstrike_p)
1180 ATSUDrawText (text_layout,
1181 kATSUFromTextBeginning, kATSUToTextEnd,
1182 Long2Fix (x + 1), Long2Fix (port_height - y));
1184 #if USE_CG_DRAWING
1185 mac_end_cg_clip (f);
1186 context = NULL;
1187 #else
1188 CGContextSynchronize (context);
1189 QDEndCGContext (port, &context);
1190 #endif
1191 #if 0
1192 /* This doesn't work on Mac OS X 10.1. */
1193 ATSUClearLayoutControls (text_layout,
1194 sizeof (tags) / sizeof (tags[0]), tags);
1195 #else
1196 ATSUSetLayoutControls (text_layout,
1197 sizeof (tags) / sizeof (tags[0]),
1198 tags, sizes, values);
1199 #endif
1201 #endif /* MAC_OSX */
1203 #endif /* USE_ATSUI */
1206 static void
1207 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1208 overstrike_p, bytes_per_char)
1209 struct frame *f;
1210 GC gc;
1211 int x, y;
1212 char *buf;
1213 int nchars, bg_width, overstrike_p, bytes_per_char;
1215 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1216 UInt32 savedFlags;
1217 #endif
1219 mac_begin_clip (f, gc);
1220 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1221 if (mac_use_core_graphics)
1222 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
1223 #endif
1224 RGBForeColor (GC_FORE_COLOR (gc));
1225 #ifdef MAC_OS8
1226 if (bg_width)
1228 RGBBackColor (GC_BACK_COLOR (gc));
1229 TextMode (srcCopy);
1231 else
1232 TextMode (srcOr);
1233 #else
1234 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1235 because:
1236 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1237 into an offscreen graphics world first. So performance gain
1238 cannot be expected.)
1239 - It lowers rendering quality.
1240 - Some fonts leave garbage on cursor movement. */
1241 if (bg_width)
1243 Rect r;
1245 RGBBackColor (GC_BACK_COLOR (gc));
1246 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1247 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1248 EraseRect (&r);
1250 TextMode (srcOr);
1251 #endif
1252 TextFont (GC_FONT (gc)->mac_fontnum);
1253 TextSize (GC_FONT (gc)->mac_fontsize);
1254 TextFace (GC_FONT (gc)->mac_fontface);
1255 MoveTo (x, y);
1256 DrawText (buf, 0, nchars * bytes_per_char);
1257 if (overstrike_p)
1259 TextMode (srcOr);
1260 MoveTo (x + 1, y);
1261 DrawText (buf, 0, nchars * bytes_per_char);
1263 if (bg_width)
1264 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1265 mac_end_clip (gc);
1267 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1268 if (mac_use_core_graphics)
1269 SwapQDTextFlags(savedFlags);
1270 #endif
1274 static INLINE void
1275 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1276 overstrike_p, bytes_per_char)
1277 struct frame *f;
1278 GC gc;
1279 int x, y;
1280 char *buf;
1281 int nchars, bg_width, overstrike_p, bytes_per_char;
1283 #if USE_ATSUI
1284 if (GC_FONT (gc)->mac_style)
1285 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1286 overstrike_p, bytes_per_char);
1287 else
1288 #endif /* USE_ATSUI */
1289 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1290 overstrike_p, bytes_per_char);
1294 /* Mac replacement for XDrawImageString. */
1296 static void
1297 mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1298 struct frame *f;
1299 GC gc;
1300 int x, y;
1301 char *buf;
1302 int nchars, bg_width, overstrike_p;
1304 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1305 overstrike_p, 1);
1309 /* Mac replacement for XDrawImageString16. */
1311 static void
1312 mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1313 struct frame *f;
1314 GC gc;
1315 int x, y;
1316 XChar2b *buf;
1317 int nchars, bg_width, overstrike_p;
1319 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1320 overstrike_p, 2);
1324 /* Mac replacement for XQueryTextExtents, but takes a character. If
1325 STYLE is NULL, measurement is done by QuickDraw Text routines for
1326 the font of the current graphics port. If CG_GLYPH is not NULL,
1327 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1329 static OSStatus
1330 mac_query_char_extents (style, c,
1331 font_ascent_return, font_descent_return,
1332 overall_return, cg_glyph)
1333 #if USE_ATSUI
1334 ATSUStyle style;
1335 #else
1336 void *style;
1337 #endif
1338 int c;
1339 int *font_ascent_return, *font_descent_return;
1340 XCharStruct *overall_return;
1341 #if USE_CG_TEXT_DRAWING
1342 CGGlyph *cg_glyph;
1343 #else
1344 void *cg_glyph;
1345 #endif
1347 OSStatus err = noErr;
1348 int width;
1349 Rect char_bounds;
1351 #if USE_ATSUI
1352 if (style)
1354 ATSUTextLayout text_layout;
1355 UniChar ch = c;
1357 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
1358 if (err == noErr
1359 && (font_ascent_return || font_descent_return || overall_return))
1361 ATSTrapezoid glyph_bounds;
1363 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1364 kATSUFromTextBeginning, kATSUToTextEnd,
1365 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1366 kATSUseFractionalOrigins,
1367 #else
1368 kATSUseDeviceOrigins,
1369 #endif
1370 1, &glyph_bounds, NULL);
1371 if (err == noErr)
1373 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1374 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1376 width = Fix2Long (glyph_bounds.upperRight.x
1377 - glyph_bounds.upperLeft.x);
1378 if (font_ascent_return)
1379 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1380 if (font_descent_return)
1381 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1384 if (err == noErr && overall_return)
1386 err = ATSUMeasureTextImage (text_layout,
1387 kATSUFromTextBeginning, kATSUToTextEnd,
1388 0, 0, &char_bounds);
1389 if (err == noErr)
1390 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1391 #if USE_CG_TEXT_DRAWING
1392 if (err == noErr && cg_glyph)
1394 OSStatus err1;
1395 ATSUGlyphInfoArray glyph_info_array;
1396 ByteCount count = sizeof (ATSUGlyphInfoArray);
1398 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1399 kATSUToTextEnd, NULL, NULL, NULL);
1400 if (err1 == noErr)
1401 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1402 kATSUToTextEnd, &count,
1403 &glyph_info_array);
1404 if (err1 == noErr
1405 /* Make sure that we don't have to make layout
1406 adjustments. */
1407 && glyph_info_array.glyphs[0].deltaY == 0.0f
1408 && glyph_info_array.glyphs[0].idealX == 0.0f
1409 && glyph_info_array.glyphs[0].screenX == 0)
1411 xassert (glyph_info_array.glyphs[0].glyphID);
1412 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1414 else
1415 *cg_glyph = 0;
1417 #endif
1420 else
1421 #endif
1423 if (font_ascent_return || font_descent_return)
1425 FontInfo font_info;
1427 GetFontInfo (&font_info);
1428 if (font_ascent_return)
1429 *font_ascent_return = font_info.ascent;
1430 if (font_descent_return)
1431 *font_descent_return = font_info.descent;
1433 if (overall_return)
1435 char ch = c;
1437 width = CharWidth (ch);
1438 QDTextBounds (1, &ch, &char_bounds);
1439 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1443 return err;
1447 /* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1449 static int
1450 mac_text_extents_16 (font_struct, string, nchars, overall_return)
1451 XFontStruct *font_struct;
1452 XChar2b *string;
1453 int nchars;
1454 XCharStruct *overall_return;
1456 int i;
1457 short width = 0, lbearing = 0, rbearing = 0;
1458 XCharStruct *pcm;
1460 for (i = 0; i < nchars; i++)
1462 pcm = mac_per_char_metric (font_struct, string, 0);
1463 if (pcm == NULL)
1464 width += FONT_WIDTH (font_struct);
1465 else
1467 lbearing = min (lbearing, width + pcm->lbearing);
1468 rbearing = max (rbearing, width + pcm->rbearing);
1469 width += pcm->width;
1471 string++;
1474 overall_return->lbearing = lbearing;
1475 overall_return->rbearing = rbearing;
1476 overall_return->width = width;
1478 /* What's the meaning of the return value of XTextExtents16? */
1482 #if USE_CG_TEXT_DRAWING
1483 static int cg_text_anti_aliasing_threshold = 8;
1485 static void
1486 init_cg_text_anti_aliasing_threshold ()
1488 int threshold;
1489 Boolean valid_p;
1491 threshold =
1492 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1493 kCFPreferencesCurrentApplication,
1494 &valid_p);
1495 if (valid_p)
1496 cg_text_anti_aliasing_threshold = threshold;
1499 static int
1500 mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1501 struct frame *f;
1502 GC gc;
1503 int x, y;
1504 XChar2b *buf;
1505 int nchars, bg_width, overstrike_p;
1507 CGFloat port_height, gx, gy;
1508 int i;
1509 CGContextRef context;
1510 CGGlyph *glyphs;
1511 CGSize *advances;
1513 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
1514 return 0;
1516 port_height = FRAME_PIXEL_HEIGHT (f);
1517 gx = x;
1518 gy = port_height - y;
1519 glyphs = (CGGlyph *)buf;
1520 advances = alloca (sizeof (CGSize) * nchars);
1521 if (advances == NULL)
1522 return 0;
1523 for (i = 0; i < nchars; i++)
1525 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1527 advances[i].width = pcm->width;
1528 advances[i].height = 0;
1529 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1530 buf++;
1533 #if USE_CG_DRAWING
1534 context = mac_begin_cg_clip (f, gc);
1535 #else
1536 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1537 if (gc->n_clip_rects || bg_width)
1539 CGContextTranslateCTM (context, 0, port_height);
1540 CGContextScaleCTM (context, 1, -1);
1541 if (gc->n_clip_rects)
1542 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1543 #endif
1544 if (bg_width)
1546 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1547 CGContextFillRect
1548 (context,
1549 mac_rect_make (f, gx, y - FONT_BASE (GC_FONT (gc)),
1550 bg_width, FONT_HEIGHT (GC_FONT (gc))));
1552 CGContextScaleCTM (context, 1, -1);
1553 CGContextTranslateCTM (context, 0, -port_height);
1554 #if !USE_CG_DRAWING
1556 #endif
1557 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1558 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1559 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
1560 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1561 CGContextSetShouldAntialias (context, false);
1562 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1563 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1564 if (CGContextShowGlyphsWithAdvances != NULL)
1565 #endif
1567 CGContextSetTextPosition (context, gx, gy);
1568 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1569 if (overstrike_p)
1571 CGContextSetTextPosition (context, gx + 1.0f, gy);
1572 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1575 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1576 else /* CGContextShowGlyphsWithAdvances == NULL */
1577 #endif
1578 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1579 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1581 for (i = 0; i < nchars; i++)
1583 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1584 if (overstrike_p)
1585 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1586 gx += advances[i].width;
1589 #endif
1590 #if USE_CG_DRAWING
1591 mac_end_cg_clip (f);
1592 #else
1593 CGContextSynchronize (context);
1594 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1595 #endif
1597 return 1;
1599 #endif
1602 #if !USE_CG_DRAWING
1603 /* Mac replacement for XCopyArea: dest must be window. */
1605 static void
1606 mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1607 Pixmap src;
1608 struct frame *f;
1609 GC gc;
1610 int src_x, src_y;
1611 unsigned int width, height;
1612 int dest_x, dest_y;
1614 Rect src_r, dest_r;
1616 mac_begin_clip (f, gc);
1618 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1619 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1621 ForeColor (blackColor);
1622 BackColor (whiteColor);
1624 LockPixels (GetGWorldPixMap (src));
1625 #if TARGET_API_MAC_CARBON
1627 CGrafPtr port;
1629 GetPort (&port);
1630 LockPortBits (port);
1631 CopyBits (GetPortBitMapForCopyBits (src),
1632 GetPortBitMapForCopyBits (port),
1633 &src_r, &dest_r, srcCopy, 0);
1634 UnlockPortBits (port);
1636 #else /* not TARGET_API_MAC_CARBON */
1637 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
1638 &src_r, &dest_r, srcCopy, 0);
1639 #endif /* not TARGET_API_MAC_CARBON */
1640 UnlockPixels (GetGWorldPixMap (src));
1642 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1644 mac_end_clip (gc);
1648 static void
1649 mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
1650 width, height, dest_x, dest_y)
1651 Pixmap src, mask;
1652 struct frame *f;
1653 GC gc;
1654 int src_x, src_y;
1655 unsigned int width, height;
1656 int dest_x, dest_y;
1658 Rect src_r, dest_r;
1660 mac_begin_clip (f, gc);
1662 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1663 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1665 ForeColor (blackColor);
1666 BackColor (whiteColor);
1668 LockPixels (GetGWorldPixMap (src));
1669 LockPixels (GetGWorldPixMap (mask));
1670 #if TARGET_API_MAC_CARBON
1672 CGrafPtr port;
1674 GetPort (&port);
1675 LockPortBits (port);
1676 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1677 GetPortBitMapForCopyBits (port),
1678 &src_r, &src_r, &dest_r);
1679 UnlockPortBits (port);
1681 #else /* not TARGET_API_MAC_CARBON */
1682 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
1683 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
1684 #endif /* not TARGET_API_MAC_CARBON */
1685 UnlockPixels (GetGWorldPixMap (mask));
1686 UnlockPixels (GetGWorldPixMap (src));
1688 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1690 mac_end_clip (gc);
1692 #endif /* !USE_CG_DRAWING */
1695 /* Mac replacement for XCopyArea: used only for scrolling. */
1697 static void
1698 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1699 struct frame *f;
1700 GC gc;
1701 int src_x, src_y;
1702 unsigned int width, height;
1703 int dest_x, dest_y;
1705 #if TARGET_API_MAC_CARBON
1706 Rect src_r;
1707 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1709 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1710 #if USE_CG_DRAWING
1711 mac_prepare_for_quickdraw (f);
1712 #endif
1713 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1714 &src_r, dest_x - src_x, dest_y - src_y,
1715 kScrollWindowNoOptions, dummy);
1716 DisposeRgn (dummy);
1717 #else /* not TARGET_API_MAC_CARBON */
1718 Rect src_r, dest_r;
1719 WindowRef w = FRAME_MAC_WINDOW (f);
1721 mac_begin_clip (f, gc);
1723 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1724 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1726 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1727 color mapping in CopyBits. Otherwise, it will be slow. */
1728 ForeColor (blackColor);
1729 BackColor (whiteColor);
1730 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
1732 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1734 mac_end_clip (gc);
1735 #endif /* not TARGET_API_MAC_CARBON */
1739 /* Mac replacement for XChangeGC. */
1741 static void
1742 XChangeGC (display, gc, mask, xgcv)
1743 Display *display;
1744 GC gc;
1745 unsigned long mask;
1746 XGCValues *xgcv;
1748 if (mask & GCForeground)
1749 XSetForeground (display, gc, xgcv->foreground);
1750 if (mask & GCBackground)
1751 XSetBackground (display, gc, xgcv->background);
1752 if (mask & GCFont)
1753 XSetFont (display, gc, xgcv->font);
1757 /* Mac replacement for XCreateGC. */
1760 XCreateGC (display, d, mask, xgcv)
1761 Display *display;
1762 void *d;
1763 unsigned long mask;
1764 XGCValues *xgcv;
1766 GC gc = xmalloc (sizeof (*gc));
1768 bzero (gc, sizeof (*gc));
1769 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1770 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1771 if (CGColorGetTypeID != NULL)
1772 #endif
1774 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1775 CGColorRetain (gc->cg_fore_color);
1776 CGColorRetain (gc->cg_back_color);
1778 #endif
1779 XChangeGC (display, gc, mask, xgcv);
1781 return gc;
1785 /* Used in xfaces.c. */
1787 void
1788 XFreeGC (display, gc)
1789 Display *display;
1790 GC gc;
1792 if (gc->clip_region)
1793 DisposeRgn (gc->clip_region);
1794 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1795 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1796 if (CGColorGetTypeID != NULL)
1797 #endif
1799 CGColorRelease (gc->cg_fore_color);
1800 CGColorRelease (gc->cg_back_color);
1802 #endif
1803 xfree (gc);
1807 /* Mac replacement for XGetGCValues. */
1809 static void
1810 XGetGCValues (display, gc, mask, xgcv)
1811 Display *display;
1812 GC gc;
1813 unsigned long mask;
1814 XGCValues *xgcv;
1816 if (mask & GCForeground)
1817 xgcv->foreground = gc->xgcv.foreground;
1818 if (mask & GCBackground)
1819 xgcv->background = gc->xgcv.background;
1820 if (mask & GCFont)
1821 xgcv->font = gc->xgcv.font;
1825 /* Mac replacement for XSetForeground. */
1827 void
1828 XSetForeground (display, gc, color)
1829 Display *display;
1830 GC gc;
1831 unsigned long color;
1833 if (gc->xgcv.foreground != color)
1835 gc->xgcv.foreground = color;
1836 gc->fore_color.red = RED16_FROM_ULONG (color);
1837 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1838 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
1839 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1840 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1841 if (CGColorGetTypeID != NULL)
1842 #endif
1844 CGColorRelease (gc->cg_fore_color);
1845 if (color == 0)
1847 gc->cg_fore_color = mac_cg_color_black;
1848 CGColorRetain (gc->cg_fore_color);
1850 else
1852 CGFloat rgba[4];
1854 rgba[0] = gc->fore_color.red / 65535.0f;
1855 rgba[1] = gc->fore_color.green / 65535.0f;
1856 rgba[2] = gc->fore_color.blue / 65535.0f;
1857 rgba[3] = 1.0f;
1858 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1861 #endif
1866 /* Mac replacement for XSetBackground. */
1868 void
1869 XSetBackground (display, gc, color)
1870 Display *display;
1871 GC gc;
1872 unsigned long color;
1874 if (gc->xgcv.background != color)
1876 gc->xgcv.background = color;
1877 gc->back_color.red = RED16_FROM_ULONG (color);
1878 gc->back_color.green = GREEN16_FROM_ULONG (color);
1879 gc->back_color.blue = BLUE16_FROM_ULONG (color);
1880 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1881 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1882 if (CGColorGetTypeID != NULL)
1883 #endif
1885 CGColorRelease (gc->cg_back_color);
1886 if (color == 0)
1888 gc->cg_back_color = mac_cg_color_black;
1889 CGColorRetain (gc->cg_back_color);
1891 else
1893 CGFloat rgba[4];
1895 rgba[0] = gc->back_color.red / 65535.0f;
1896 rgba[1] = gc->back_color.green / 65535.0f;
1897 rgba[2] = gc->back_color.blue / 65535.0f;
1898 rgba[3] = 1.0f;
1899 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1902 #endif
1907 /* Mac replacement for XSetFont. */
1909 static void
1910 XSetFont (display, gc, font)
1911 Display *display;
1912 GC gc;
1913 XFontStruct *font;
1915 gc->xgcv.font = font;
1919 /* Mac replacement for XSetClipRectangles. */
1921 static void
1922 mac_set_clip_rectangles (f, gc, rectangles, n)
1923 struct frame *f;
1924 GC gc;
1925 Rect *rectangles;
1926 int n;
1928 int i;
1930 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1932 gc->n_clip_rects = n;
1933 if (n > 0)
1935 if (gc->clip_region == NULL)
1936 gc->clip_region = NewRgn ();
1937 RectRgn (gc->clip_region, rectangles);
1938 if (n > 1)
1940 RgnHandle region = NewRgn ();
1942 for (i = 1; i < n; i++)
1944 RectRgn (region, rectangles + i);
1945 UnionRgn (gc->clip_region, region, gc->clip_region);
1947 DisposeRgn (region);
1950 #if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1951 for (i = 0; i < n; i++)
1953 Rect *rect = rectangles + i;
1955 gc->clip_rects[i] = mac_rect_make (f, rect->left, rect->top,
1956 rect->right - rect->left,
1957 rect->bottom - rect->top);
1959 #endif
1963 /* Mac replacement for XSetClipMask. */
1965 static INLINE void
1966 mac_reset_clip_rectangles (f, gc)
1967 struct frame *f;
1968 GC gc;
1970 gc->n_clip_rects = 0;
1974 /* Mac replacement for XSetWindowBackground. */
1976 void
1977 XSetWindowBackground (display, w, color)
1978 Display *display;
1979 WindowRef w;
1980 unsigned long color;
1982 #if !TARGET_API_MAC_CARBON
1983 AuxWinHandle aw_handle;
1984 CTabHandle ctab_handle;
1985 ColorSpecPtr ct_table;
1986 short ct_size;
1987 #endif
1988 RGBColor bg_color;
1990 bg_color.red = RED16_FROM_ULONG (color);
1991 bg_color.green = GREEN16_FROM_ULONG (color);
1992 bg_color.blue = BLUE16_FROM_ULONG (color);
1994 #if TARGET_API_MAC_CARBON
1995 SetWindowContentColor (w, &bg_color);
1996 #else
1997 if (GetAuxWin (w, &aw_handle))
1999 ctab_handle = (*aw_handle)->awCTable;
2000 HandToHand ((Handle *) &ctab_handle);
2001 ct_table = (*ctab_handle)->ctTable;
2002 ct_size = (*ctab_handle)->ctSize;
2003 while (ct_size > -1)
2005 if (ct_table->value == 0)
2007 ct_table->rgb = bg_color;
2008 CTabChanged (ctab_handle);
2009 SetWinColor (w, (WCTabHandle) ctab_handle);
2011 ct_size--;
2014 #endif
2017 /* Flush display of frame F, or of all frames if F is null. */
2019 static void
2020 x_flush (f)
2021 struct frame *f;
2023 #if TARGET_API_MAC_CARBON
2024 BLOCK_INPUT;
2025 #if USE_CG_DRAWING
2026 mac_prepare_for_quickdraw (f);
2027 #endif
2028 if (f)
2029 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
2030 else
2031 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
2032 UNBLOCK_INPUT;
2033 #endif
2037 /* Remove calls to XFlush by defining XFlush to an empty replacement.
2038 Calls to XFlush should be unnecessary because the X output buffer
2039 is flushed automatically as needed by calls to XPending,
2040 XNextEvent, or XWindowEvent according to the XFlush man page.
2041 XTread_socket calls XPending. Removing XFlush improves
2042 performance. */
2044 #define XFlush(DISPLAY) (void) 0
2046 #if USE_CG_DRAWING
2047 static void
2048 mac_flush_display_optional (f)
2049 struct frame *f;
2051 BLOCK_INPUT;
2052 mac_prepare_for_quickdraw (f);
2053 UNBLOCK_INPUT;
2055 #endif
2057 /***********************************************************************
2058 Starting and ending an update
2059 ***********************************************************************/
2061 /* Start an update of frame F. This function is installed as a hook
2062 for update_begin, i.e. it is called when update_begin is called.
2063 This function is called prior to calls to x_update_window_begin for
2064 each window being updated. */
2066 static void
2067 x_update_begin (f)
2068 struct frame *f;
2070 #if TARGET_API_MAC_CARBON
2071 /* During update of a frame, availability of input events is
2072 periodically checked with ReceiveNextEvent if
2073 redisplay-dont-pause is nil. That normally flushes window buffer
2074 changes for every check, and thus screen update looks waving even
2075 if no input is available. So we disable screen updates during
2076 update of a frame. */
2077 BLOCK_INPUT;
2078 DisableScreenUpdates ();
2079 UNBLOCK_INPUT;
2080 #endif
2084 /* Start update of window W. Set the global variable updated_window
2085 to the window being updated and set output_cursor to the cursor
2086 position of W. */
2088 static void
2089 x_update_window_begin (w)
2090 struct window *w;
2092 struct frame *f = XFRAME (WINDOW_FRAME (w));
2093 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
2095 updated_window = w;
2096 set_output_cursor (&w->cursor);
2098 BLOCK_INPUT;
2100 if (f == display_info->mouse_face_mouse_frame)
2102 /* Don't do highlighting for mouse motion during the update. */
2103 display_info->mouse_face_defer = 1;
2105 /* If F needs to be redrawn, simply forget about any prior mouse
2106 highlighting. */
2107 if (FRAME_GARBAGED_P (f))
2108 display_info->mouse_face_window = Qnil;
2110 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
2111 their mouse_face_p flag set, which means that they are always
2112 unequal to rows in a desired matrix which never have that
2113 flag set. So, rows containing mouse-face glyphs are never
2114 scrolled, and we don't have to switch the mouse highlight off
2115 here to prevent it from being scrolled. */
2117 /* Can we tell that this update does not affect the window
2118 where the mouse highlight is? If so, no need to turn off.
2119 Likewise, don't do anything if the frame is garbaged;
2120 in that case, the frame's current matrix that we would use
2121 is all wrong, and we will redisplay that line anyway. */
2122 if (!NILP (display_info->mouse_face_window)
2123 && w == XWINDOW (display_info->mouse_face_window))
2125 int i;
2127 for (i = 0; i < w->desired_matrix->nrows; ++i)
2128 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2129 break;
2131 if (i < w->desired_matrix->nrows)
2132 clear_mouse_face (display_info);
2134 #endif /* 0 */
2137 UNBLOCK_INPUT;
2141 /* Draw a vertical window border from (x,y0) to (x,y1) */
2143 static void
2144 mac_draw_vertical_window_border (w, x, y0, y1)
2145 struct window *w;
2146 int x, y0, y1;
2148 struct frame *f = XFRAME (WINDOW_FRAME (w));
2149 struct face *face;
2151 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2152 if (face)
2153 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2154 face->foreground);
2156 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
2159 /* End update of window W (which is equal to updated_window).
2161 Draw vertical borders between horizontally adjacent windows, and
2162 display W's cursor if CURSOR_ON_P is non-zero.
2164 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2165 glyphs in mouse-face were overwritten. In that case we have to
2166 make sure that the mouse-highlight is properly redrawn.
2168 W may be a menu bar pseudo-window in case we don't have X toolkit
2169 support. Such windows don't have a cursor, so don't display it
2170 here. */
2172 static void
2173 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2174 struct window *w;
2175 int cursor_on_p, mouse_face_overwritten_p;
2177 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
2179 if (!w->pseudo_window_p)
2181 BLOCK_INPUT;
2183 if (cursor_on_p)
2184 display_and_set_cursor (w, 1, output_cursor.hpos,
2185 output_cursor.vpos,
2186 output_cursor.x, output_cursor.y);
2188 if (draw_window_fringes (w, 1))
2189 x_draw_vertical_border (w);
2191 UNBLOCK_INPUT;
2194 /* If a row with mouse-face was overwritten, arrange for
2195 XTframe_up_to_date to redisplay the mouse highlight. */
2196 if (mouse_face_overwritten_p)
2198 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2199 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2200 dpyinfo->mouse_face_window = Qnil;
2203 updated_window = NULL;
2207 /* End update of frame F. This function is installed as a hook in
2208 update_end. */
2210 static void
2211 x_update_end (f)
2212 struct frame *f;
2214 /* Mouse highlight may be displayed again. */
2215 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2217 BLOCK_INPUT;
2218 #if TARGET_API_MAC_CARBON
2219 EnableScreenUpdates ();
2220 #endif
2221 XFlush (FRAME_MAC_DISPLAY (f));
2222 UNBLOCK_INPUT;
2226 /* This function is called from various places in xdisp.c whenever a
2227 complete update has been performed. The global variable
2228 updated_window is not available here. */
2230 static void
2231 XTframe_up_to_date (f)
2232 struct frame *f;
2234 if (FRAME_MAC_P (f))
2236 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2238 if (dpyinfo->mouse_face_deferred_gc
2239 || f == dpyinfo->mouse_face_mouse_frame)
2241 BLOCK_INPUT;
2242 if (dpyinfo->mouse_face_mouse_frame)
2243 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2244 dpyinfo->mouse_face_mouse_x,
2245 dpyinfo->mouse_face_mouse_y);
2246 dpyinfo->mouse_face_deferred_gc = 0;
2247 UNBLOCK_INPUT;
2253 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
2254 arrow bitmaps, or clear the fringes if no bitmaps are required
2255 before DESIRED_ROW is made current. The window being updated is
2256 found in updated_window. This function is called from
2257 update_window_line only if it is known that there are differences
2258 between bitmaps to be drawn between current row and DESIRED_ROW. */
2260 static void
2261 x_after_update_window_line (desired_row)
2262 struct glyph_row *desired_row;
2264 struct window *w = updated_window;
2265 struct frame *f;
2266 int width, height;
2268 xassert (w);
2270 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2271 desired_row->redraw_fringe_bitmaps_p = 1;
2273 /* When a window has disappeared, make sure that no rest of
2274 full-width rows stays visible in the internal border. Could
2275 check here if updated_window is the leftmost/rightmost window,
2276 but I guess it's not worth doing since vertically split windows
2277 are almost never used, internal border is rarely set, and the
2278 overhead is very small. */
2279 if (windows_or_buffers_changed
2280 && desired_row->full_width_p
2281 && (f = XFRAME (w->frame),
2282 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2283 width != 0)
2284 && (height = desired_row->visible_height,
2285 height > 0))
2287 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2289 /* Internal border is drawn below the tool bar. */
2290 if (WINDOWP (f->tool_bar_window)
2291 && w == XWINDOW (f->tool_bar_window))
2292 y -= width;
2294 BLOCK_INPUT;
2295 mac_clear_area (f, 0, y, width, height);
2296 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
2297 UNBLOCK_INPUT;
2302 /* Draw the bitmap WHICH in one of the left or right fringes of
2303 window W. ROW is the glyph row for which to display the bitmap; it
2304 determines the vertical position at which the bitmap has to be
2305 drawn. */
2307 static void
2308 x_draw_fringe_bitmap (w, row, p)
2309 struct window *w;
2310 struct glyph_row *row;
2311 struct draw_fringe_bitmap_params *p;
2313 struct frame *f = XFRAME (WINDOW_FRAME (w));
2314 Display *display = FRAME_MAC_DISPLAY (f);
2315 struct face *face = p->face;
2316 int rowY;
2317 int overlay_p = p->overlay_p;
2319 #ifdef MAC_OSX
2320 if (!overlay_p)
2322 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2324 #if 0 /* MAC_TODO: stipple */
2325 /* In case the same realized face is used for fringes and
2326 for something displayed in the text (e.g. face `region' on
2327 mono-displays, the fill style may have been changed to
2328 FillSolid in x_draw_glyph_string_background. */
2329 if (face->stipple)
2330 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2331 else
2332 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2333 #endif
2335 /* If the fringe is adjacent to the left (right) scroll bar of a
2336 leftmost (rightmost, respectively) window, then extend its
2337 background to the gap between the fringe and the bar. */
2338 if ((WINDOW_LEFTMOST_P (w)
2339 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2340 || (WINDOW_RIGHTMOST_P (w)
2341 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2343 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2345 if (sb_width > 0)
2347 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2348 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2349 * FRAME_COLUMN_WIDTH (f));
2351 if (bx < 0
2352 && (left + width == p->x
2353 || p->x + p->wd == left))
2355 /* Bitmap fills the fringe and we need background
2356 extension. */
2357 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2359 bx = p->x;
2360 nx = p->wd;
2361 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2362 row->y));
2363 ny = row->visible_height;
2366 if (bx >= 0)
2368 if (left + width == bx)
2370 bx = left + sb_width;
2371 nx += width - sb_width;
2373 else if (bx + nx == left)
2374 nx += width - sb_width;
2379 if (bx >= 0)
2381 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2382 /* The fringe background has already been filled. */
2383 overlay_p = 1;
2386 #if 0 /* MAC_TODO: stipple */
2387 if (!face->stipple)
2388 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2389 #endif
2391 #endif /* MAC_OSX */
2393 /* Must clip because of partially visible lines. */
2394 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2395 if (p->y < rowY)
2397 /* Adjust position of "bottom aligned" bitmap on partially
2398 visible last row. */
2399 int oldY = row->y;
2400 int oldVH = row->visible_height;
2401 row->visible_height = p->h;
2402 row->y -= rowY - p->y;
2403 x_clip_to_row (w, row, -1, face->gc);
2404 row->y = oldY;
2405 row->visible_height = oldVH;
2407 else
2408 x_clip_to_row (w, row, -1, face->gc);
2410 #ifndef MAC_OSX
2411 if (p->bx >= 0 && !p->overlay_p)
2413 #if 0 /* MAC_TODO: stipple */
2414 /* In case the same realized face is used for fringes and
2415 for something displayed in the text (e.g. face `region' on
2416 mono-displays, the fill style may have been changed to
2417 FillSolid in x_draw_glyph_string_background. */
2418 if (face->stipple)
2419 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2420 else
2421 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2422 #endif
2424 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
2426 #if 0 /* MAC_TODO: stipple */
2427 if (!face->stipple)
2428 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2429 #endif
2431 #endif /* !MAC_OSX */
2433 if (p->which
2434 #if USE_CG_DRAWING
2435 && p->which < max_fringe_bmp
2436 #endif
2439 XGCValues gcv;
2441 XGetGCValues (display, face->gc, GCForeground, &gcv);
2442 XSetForeground (display, face->gc,
2443 (p->cursor_p
2444 ? (p->overlay_p ? face->background
2445 : f->output_data.mac->cursor_pixel)
2446 : face->foreground));
2447 #if USE_CG_DRAWING
2448 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
2449 p->wd, p->h, p->x, p->y, overlay_p);
2450 #else
2451 mac_draw_bitmap (f, face->gc, p->x, p->y,
2452 p->wd, p->h, p->bits + p->dh, overlay_p);
2453 #endif
2454 XSetForeground (display, face->gc, gcv.foreground);
2457 mac_reset_clip_rectangles (f, face->gc);
2460 #if USE_CG_DRAWING
2461 static void
2462 mac_define_fringe_bitmap (which, bits, h, wd)
2463 int which;
2464 unsigned short *bits;
2465 int h, wd;
2467 int i;
2468 CGDataProviderRef provider;
2470 if (which >= max_fringe_bmp)
2472 i = max_fringe_bmp;
2473 max_fringe_bmp = which + 20;
2474 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2475 while (i < max_fringe_bmp)
2476 fringe_bmp[i++] = 0;
2479 for (i = 0; i < h; i++)
2480 bits[i] = ~bits[i];
2482 BLOCK_INPUT;
2484 provider = CGDataProviderCreateWithData (NULL, bits,
2485 sizeof (unsigned short) * h, NULL);
2486 if (provider)
2488 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2489 sizeof (unsigned short),
2490 provider, NULL, 0);
2491 CGDataProviderRelease (provider);
2494 UNBLOCK_INPUT;
2497 static void
2498 mac_destroy_fringe_bitmap (which)
2499 int which;
2501 if (which >= max_fringe_bmp)
2502 return;
2504 if (fringe_bmp[which])
2506 BLOCK_INPUT;
2507 CGImageRelease (fringe_bmp[which]);
2508 UNBLOCK_INPUT;
2510 fringe_bmp[which] = 0;
2512 #endif
2515 /* This is called when starting Emacs and when restarting after
2516 suspend. When starting Emacs, no window is mapped. And nothing
2517 must be done to Emacs's own window if it is suspended (though that
2518 rarely happens). */
2520 static void
2521 XTset_terminal_modes (struct terminal *t)
2525 /* This is called when exiting or suspending Emacs. Exiting will make
2526 the windows go away, and suspending requires no action. */
2528 static void
2529 XTreset_terminal_modes (struct terminal *t)
2535 /***********************************************************************
2536 Display Iterator
2537 ***********************************************************************/
2539 /* Function prototypes of this page. */
2541 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
2542 static int mac_encode_char P_ ((int, XChar2b *, struct font_info *,
2543 struct charset *, int *));
2546 static void
2547 pcm_init (pcm, count)
2548 XCharStruct *pcm;
2549 int count;
2551 bzero (pcm, sizeof (XCharStruct) * count);
2552 while (--count >= 0)
2554 pcm->descent = PCM_INVALID;
2555 pcm++;
2559 static enum pcm_status
2560 pcm_get_status (pcm)
2561 const XCharStruct *pcm;
2563 int height = pcm->ascent + pcm->descent;
2565 /* Negative height means some special status. */
2566 return height >= 0 ? PCM_VALID : height;
2569 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2570 is not contained in the font. */
2572 static INLINE XCharStruct *
2573 x_per_char_metric (font, char2b)
2574 XFontStruct *font;
2575 XChar2b *char2b;
2577 /* The result metric information. */
2578 XCharStruct *pcm = NULL;
2580 xassert (font && char2b);
2582 #if USE_ATSUI
2583 if (font->mac_style)
2585 XCharStruct **row = font->bounds.rows + char2b->byte1;
2587 if (*row == NULL)
2589 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2590 pcm_init (*row, 0x100);
2592 pcm = *row + char2b->byte2;
2593 if (pcm_get_status (pcm) != PCM_VALID)
2595 BLOCK_INPUT;
2596 mac_query_char_extents (font->mac_style,
2597 (char2b->byte1 << 8) + char2b->byte2,
2598 NULL, NULL, pcm, NULL);
2599 UNBLOCK_INPUT;
2602 else
2604 #endif
2605 if (font->bounds.per_char != NULL)
2607 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2609 /* min_char_or_byte2 specifies the linear character index
2610 corresponding to the first element of the per_char array,
2611 max_char_or_byte2 is the index of the last character. A
2612 character with non-zero CHAR2B->byte1 is not in the font.
2613 A character with byte2 less than min_char_or_byte2 or
2614 greater max_char_or_byte2 is not in the font. */
2615 if (char2b->byte1 == 0
2616 && char2b->byte2 >= font->min_char_or_byte2
2617 && char2b->byte2 <= font->max_char_or_byte2)
2618 pcm = font->bounds.per_char
2619 + (char2b->byte2 - font->min_char_or_byte2);
2621 else
2623 /* If either min_byte1 or max_byte1 are nonzero, both
2624 min_char_or_byte2 and max_char_or_byte2 are less than
2625 256, and the 2-byte character index values corresponding
2626 to the per_char array element N (counting from 0) are:
2628 byte1 = N/D + min_byte1
2629 byte2 = N\D + min_char_or_byte2
2631 where:
2633 D = max_char_or_byte2 - min_char_or_byte2 + 1
2634 / = integer division
2635 \ = integer modulus */
2636 if (char2b->byte1 >= font->min_byte1
2637 && char2b->byte1 <= font->max_byte1
2638 && char2b->byte2 >= font->min_char_or_byte2
2639 && char2b->byte2 <= font->max_char_or_byte2)
2641 pcm = (font->bounds.per_char
2642 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2643 * (char2b->byte1 - font->min_byte1))
2644 + (char2b->byte2 - font->min_char_or_byte2));
2648 else
2650 /* If the per_char pointer is null, all glyphs between the first
2651 and last character indexes inclusive have the same
2652 information, as given by both min_bounds and max_bounds. */
2653 if (char2b->byte2 >= font->min_char_or_byte2
2654 && char2b->byte2 <= font->max_char_or_byte2)
2655 pcm = &font->max_bounds;
2657 #if USE_ATSUI
2659 #endif
2661 return ((pcm == NULL
2662 || (pcm->width == 0
2663 #if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2664 && (pcm->rbearing - pcm->lbearing) == 0
2665 #endif
2667 ? NULL : pcm);
2670 /* RIF:
2673 static XCharStruct *
2674 mac_per_char_metric (font, char2b, font_type)
2675 XFontStruct *font;
2676 XChar2b *char2b;
2677 int font_type;
2679 return x_per_char_metric (font, char2b);
2682 /* RIF:
2683 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
2684 the two-byte form of C. Encoding is returned in *CHAR2B. */
2686 static int
2687 mac_encode_char (c, char2b, font_info, charset, two_byte_p)
2688 int c;
2689 XChar2b *char2b;
2690 struct font_info *font_info;
2691 struct charset *charset;
2692 int *two_byte_p;
2694 XFontStruct *font = font_info->font;
2696 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2697 This may be either a program in a special encoder language or a
2698 fixed encoding. */
2699 if (font_info->font_encoder)
2701 /* It's a program. */
2702 struct ccl_program *ccl = font_info->font_encoder;
2704 check_ccl_update (ccl);
2705 if (CHARSET_DIMENSION (charset) == 1)
2707 ccl->reg[0] = CHARSET_ID (charset);
2708 ccl->reg[1] = XCHAR2B_BYTE2 (char2b);
2709 ccl->reg[2] = -1;
2711 else
2713 ccl->reg[0] = CHARSET_ID (charset);
2714 ccl->reg[1] = XCHAR2B_BYTE1 (char2b);
2715 ccl->reg[2] = XCHAR2B_BYTE2 (char2b);
2718 ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
2720 /* We assume that MSBs are appropriately set/reset by CCL
2721 program. */
2722 if (font->max_byte1 == 0) /* 1-byte font */
2723 STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
2724 else
2725 STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
2727 else if (font_info->encoding_type)
2729 /* Fixed encoding scheme. See fontset.h for the meaning of the
2730 encoding numbers. */
2731 unsigned char enc = font_info->encoding_type;
2733 if ((enc == 1 || enc == 2)
2734 && CHARSET_DIMENSION (charset) == 2)
2735 char2b->byte1 |= 0x80;
2737 if (enc == 1 || enc == 3)
2738 char2b->byte2 |= 0x80;
2740 if (enc == 4)
2742 int code = (char2b->byte1 << 8) | char2b->byte2;
2744 JIS_TO_SJIS (code);
2745 STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
2749 if (two_byte_p)
2750 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
2752 return FONT_TYPE_UNKNOWN;
2757 /***********************************************************************
2758 Glyph display
2759 ***********************************************************************/
2763 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2764 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2765 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2766 int));
2767 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2768 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2769 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2770 static void x_draw_glyph_string P_ ((struct glyph_string *));
2771 static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2772 static void x_set_cursor_gc P_ ((struct glyph_string *));
2773 static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2774 static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2775 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2776 unsigned long *, double, int));*/
2777 static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2778 double, int, unsigned long));
2779 static void x_setup_relief_colors P_ ((struct glyph_string *));
2780 static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2781 static void x_draw_image_relief P_ ((struct glyph_string *));
2782 static void x_draw_image_foreground P_ ((struct glyph_string *));
2783 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2784 int, int, int));
2785 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2786 int, int, int, int, int, int,
2787 Rect *));
2788 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2789 int, int, int, Rect *));
2791 #if GLYPH_DEBUG
2792 static void x_check_font P_ ((struct frame *, XFontStruct *));
2793 #endif
2796 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
2797 face. */
2799 static void
2800 x_set_cursor_gc (s)
2801 struct glyph_string *s;
2803 if (s->font == FRAME_FONT (s->f)
2804 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2805 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2806 && !s->cmp)
2807 s->gc = s->f->output_data.mac->cursor_gc;
2808 else
2810 /* Cursor on non-default face: must merge. */
2811 XGCValues xgcv;
2812 unsigned long mask;
2814 xgcv.background = s->f->output_data.mac->cursor_pixel;
2815 xgcv.foreground = s->face->background;
2817 /* If the glyph would be invisible, try a different foreground. */
2818 if (xgcv.foreground == xgcv.background)
2819 xgcv.foreground = s->face->foreground;
2820 if (xgcv.foreground == xgcv.background)
2821 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2822 if (xgcv.foreground == xgcv.background)
2823 xgcv.foreground = s->face->foreground;
2825 /* Make sure the cursor is distinct from text in this face. */
2826 if (xgcv.background == s->face->background
2827 && xgcv.foreground == s->face->foreground)
2829 xgcv.background = s->face->foreground;
2830 xgcv.foreground = s->face->background;
2833 IF_DEBUG (x_check_font (s->f, s->font));
2834 xgcv.font = s->font;
2835 mask = GCForeground | GCBackground | GCFont;
2837 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2838 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2839 mask, &xgcv);
2840 else
2841 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2842 = XCreateGC (s->display, s->window, mask, &xgcv);
2844 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2849 /* Set up S->gc of glyph string S for drawing text in mouse face. */
2851 static void
2852 x_set_mouse_face_gc (s)
2853 struct glyph_string *s;
2855 int face_id;
2856 struct face *face;
2858 /* What face has to be used last for the mouse face? */
2859 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2860 face = FACE_FROM_ID (s->f, face_id);
2861 if (face == NULL)
2862 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2864 if (s->first_glyph->type == CHAR_GLYPH)
2865 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
2866 else
2867 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
2868 s->face = FACE_FROM_ID (s->f, face_id);
2869 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2871 /* If font in this face is same as S->font, use it. */
2872 if (s->font == s->face->font)
2873 s->gc = s->face->gc;
2874 else
2876 /* Otherwise construct scratch_cursor_gc with values from FACE
2877 but font FONT. */
2878 XGCValues xgcv;
2879 unsigned long mask;
2881 xgcv.background = s->face->background;
2882 xgcv.foreground = s->face->foreground;
2883 IF_DEBUG (x_check_font (s->f, s->font));
2884 xgcv.font = s->font;
2885 mask = GCForeground | GCBackground | GCFont;
2887 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2888 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2889 mask, &xgcv);
2890 else
2891 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2892 = XCreateGC (s->display, s->window, mask, &xgcv);
2894 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2897 xassert (s->gc != 0);
2901 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2902 Faces to use in the mode line have already been computed when the
2903 matrix was built, so there isn't much to do, here. */
2905 static INLINE void
2906 x_set_mode_line_face_gc (s)
2907 struct glyph_string *s;
2909 s->gc = s->face->gc;
2913 /* Set S->gc of glyph string S for drawing that glyph string. Set
2914 S->stippled_p to a non-zero value if the face of S has a stipple
2915 pattern. */
2917 static INLINE void
2918 x_set_glyph_string_gc (s)
2919 struct glyph_string *s;
2921 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2923 if (s->hl == DRAW_NORMAL_TEXT)
2925 s->gc = s->face->gc;
2926 s->stippled_p = s->face->stipple != 0;
2928 else if (s->hl == DRAW_INVERSE_VIDEO)
2930 x_set_mode_line_face_gc (s);
2931 s->stippled_p = s->face->stipple != 0;
2933 else if (s->hl == DRAW_CURSOR)
2935 x_set_cursor_gc (s);
2936 s->stippled_p = 0;
2938 else if (s->hl == DRAW_MOUSE_FACE)
2940 x_set_mouse_face_gc (s);
2941 s->stippled_p = s->face->stipple != 0;
2943 else if (s->hl == DRAW_IMAGE_RAISED
2944 || s->hl == DRAW_IMAGE_SUNKEN)
2946 s->gc = s->face->gc;
2947 s->stippled_p = s->face->stipple != 0;
2949 else
2951 s->gc = s->face->gc;
2952 s->stippled_p = s->face->stipple != 0;
2955 /* GC must have been set. */
2956 xassert (s->gc != 0);
2960 /* Set clipping for output of glyph string S. S may be part of a mode
2961 line or menu if we don't have X toolkit support. */
2963 static INLINE void
2964 x_set_glyph_string_clipping (s)
2965 struct glyph_string *s;
2967 Rect rects[MAX_CLIP_RECTS];
2968 int n;
2970 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
2971 mac_set_clip_rectangles (s->f, s->gc, rects, n);
2975 /* RIF:
2976 Compute left and right overhang of glyph string S. If S is a glyph
2977 string for a composition, assume overhangs don't exist. */
2979 static void
2980 mac_compute_glyph_string_overhangs (s)
2981 struct glyph_string *s;
2983 if (!(s->cmp == NULL
2984 && s->first_glyph->type == CHAR_GLYPH))
2985 return;
2987 if (!s->two_byte_p
2988 #if USE_ATSUI
2989 || s->font->mac_style
2990 #endif
2993 XCharStruct cs;
2995 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2996 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2997 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2999 else
3001 Rect r;
3002 MacFontStruct *font = s->font;
3004 #if USE_CG_DRAWING
3005 mac_prepare_for_quickdraw (s->f);
3006 #endif
3007 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
3009 TextFont (font->mac_fontnum);
3010 TextSize (font->mac_fontsize);
3011 TextFace (font->mac_fontface);
3013 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
3015 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
3016 s->left_overhang = r.left < 0 ? -r.left : 0;
3021 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
3023 static INLINE void
3024 x_clear_glyph_string_rect (s, x, y, w, h)
3025 struct glyph_string *s;
3026 int x, y, w, h;
3028 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
3032 /* Draw the background of glyph_string S. If S->background_filled_p
3033 is non-zero don't draw it. FORCE_P non-zero means draw the
3034 background even if it wouldn't be drawn normally. This is used
3035 when a string preceding S draws into the background of S, or S
3036 contains the first component of a composition. */
3038 static void
3039 x_draw_glyph_string_background (s, force_p)
3040 struct glyph_string *s;
3041 int force_p;
3043 /* Nothing to do if background has already been drawn or if it
3044 shouldn't be drawn in the first place. */
3045 if (!s->background_filled_p)
3047 int box_line_width = max (s->face->box_line_width, 0);
3049 #if 0 /* MAC_TODO: stipple */
3050 if (s->stippled_p)
3052 /* Fill background with a stipple pattern. */
3053 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3054 XFillRectangle (s->display, s->window, s->gc, s->x,
3055 s->y + box_line_width,
3056 s->background_width,
3057 s->height - 2 * box_line_width);
3058 XSetFillStyle (s->display, s->gc, FillSolid);
3059 s->background_filled_p = 1;
3061 else
3062 #endif
3063 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3064 || s->font_not_found_p
3065 || s->extends_to_end_of_line_p
3066 || force_p)
3068 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
3069 s->background_width,
3070 s->height - 2 * box_line_width);
3071 s->background_filled_p = 1;
3077 /* Draw the foreground of glyph string S. */
3079 static void
3080 x_draw_glyph_string_foreground (s)
3081 struct glyph_string *s;
3083 int i, x, bg_width;
3085 /* If first glyph of S has a left box line, start drawing the text
3086 of S to the right of that box line. */
3087 if (s->face->box != FACE_NO_BOX
3088 && s->first_glyph->left_box_line_p)
3089 x = s->x + eabs (s->face->box_line_width);
3090 else
3091 x = s->x;
3093 /* Draw characters of S as rectangles if S's font could not be
3094 loaded. */
3095 if (s->font_not_found_p)
3097 for (i = 0; i < s->nchars; ++i)
3099 struct glyph *g = s->first_glyph + i;
3100 mac_draw_rectangle (s->f, s->gc, x, s->y,
3101 g->pixel_width - 1, s->height - 1);
3102 x += g->pixel_width;
3105 else
3107 char *char1b = (char *) s->char2b;
3108 int boff = s->font_info->baseline_offset;
3110 if (s->font_info->vertical_centering)
3111 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3113 /* If we can use 8-bit functions, condense S->char2b. */
3114 if (!s->two_byte_p
3115 #if USE_ATSUI
3116 && GC_FONT (s->gc)->mac_style == NULL
3117 #endif
3119 for (i = 0; i < s->nchars; ++i)
3120 char1b[i] = s->char2b[i].byte2;
3122 /* Draw text with XDrawString if background has already been
3123 filled. Otherwise, use XDrawImageString. (Note that
3124 XDrawImageString is usually faster than XDrawString.) Always
3125 use XDrawImageString when drawing the cursor so that there is
3126 no chance that characters under a box cursor are invisible. */
3127 if (s->for_overlaps
3128 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3129 bg_width = 0; /* Corresponds to XDrawString. */
3130 else
3131 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3133 if (s->two_byte_p
3134 #if USE_ATSUI
3135 || GC_FONT (s->gc)->mac_style
3136 #endif
3138 #if USE_CG_TEXT_DRAWING
3139 if (!s->two_byte_p
3140 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
3141 s->char2b, s->nchars, bg_width,
3142 s->face->overstrike))
3144 else
3145 #endif
3146 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
3147 s->char2b, s->nchars, bg_width,
3148 s->face->overstrike);
3149 else
3150 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
3151 char1b, s->nchars, bg_width,
3152 s->face->overstrike);
3156 /* Draw the foreground of composite glyph string S. */
3158 static void
3159 x_draw_composite_glyph_string_foreground (s)
3160 struct glyph_string *s;
3162 int i, x;
3164 /* If first glyph of S has a left box line, start drawing the text
3165 of S to the right of that box line. */
3166 if (s->face->box != FACE_NO_BOX
3167 && s->first_glyph->left_box_line_p)
3168 x = s->x + eabs (s->face->box_line_width);
3169 else
3170 x = s->x;
3172 /* S is a glyph string for a composition. S->gidx is the index of
3173 the first character drawn for glyphs of this composition.
3174 S->gidx == 0 means we are drawing the very first character of
3175 this composition. */
3177 /* Draw a rectangle for the composition if the font for the very
3178 first character of the composition could not be loaded. */
3179 if (s->font_not_found_p)
3181 if (s->gidx == 0)
3182 mac_draw_rectangle (s->f, s->gc, x, s->y,
3183 s->width - 1, s->height - 1);
3185 else
3187 for (i = 0; i < s->nchars; i++, ++s->gidx)
3188 if (mac_per_char_metric (GC_FONT (s->gc), s->char2b + i, 0) == NULL)
3189 /* This is a nonexistent or zero-width glyph such as a
3190 combining diacritic. Draw a rectangle. */
3191 mac_draw_rectangle (s->f, s->gc,
3192 x + s->cmp->offsets[s->gidx * 2], s->y,
3193 FONT_WIDTH (GC_FONT (s->gc)) - 1, s->height - 1);
3194 else
3195 mac_draw_image_string_16 (s->f, s->gc,
3196 x + s->cmp->offsets[s->gidx * 2],
3197 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3198 s->char2b + i, 1, 0, s->face->overstrike);
3203 #ifdef USE_X_TOOLKIT
3205 static struct frame *x_frame_of_widget P_ ((Widget));
3208 /* Return the frame on which widget WIDGET is used.. Abort if frame
3209 cannot be determined. */
3211 static struct frame *
3212 x_frame_of_widget (widget)
3213 Widget widget;
3215 struct x_display_info *dpyinfo;
3216 Lisp_Object tail;
3217 struct frame *f;
3219 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3221 /* Find the top-level shell of the widget. Note that this function
3222 can be called when the widget is not yet realized, so XtWindow
3223 (widget) == 0. That's the reason we can't simply use
3224 x_any_window_to_frame. */
3225 while (!XtIsTopLevelShell (widget))
3226 widget = XtParent (widget);
3228 /* Look for a frame with that top-level widget. Allocate the color
3229 on that frame to get the right gamma correction value. */
3230 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
3231 if (FRAMEP (XCAR (tail))
3232 && (f = XFRAME (XCAR (tail)),
3233 (f->output_data.nothing != 1
3234 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3235 && f->output_data.x->widget == widget)
3236 return f;
3238 abort ();
3242 /* Allocate the color COLOR->pixel on the screen and display of
3243 widget WIDGET in colormap CMAP. If an exact match cannot be
3244 allocated, try the nearest color available. Value is non-zero
3245 if successful. This is called from lwlib. */
3248 x_alloc_nearest_color_for_widget (widget, cmap, color)
3249 Widget widget;
3250 Colormap cmap;
3251 XColor *color;
3253 struct frame *f = x_frame_of_widget (widget);
3254 return x_alloc_nearest_color (f, cmap, color);
3258 #endif /* USE_X_TOOLKIT */
3260 #if 0 /* MAC_TODO */
3262 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3263 CMAP. If an exact match can't be allocated, try the nearest color
3264 available. Value is non-zero if successful. Set *COLOR to the
3265 color allocated. */
3268 x_alloc_nearest_color (f, cmap, color)
3269 struct frame *f;
3270 Colormap cmap;
3271 XColor *color;
3273 Display *display = FRAME_X_DISPLAY (f);
3274 Screen *screen = FRAME_X_SCREEN (f);
3275 int rc;
3277 gamma_correct (f, color);
3278 rc = XAllocColor (display, cmap, color);
3279 if (rc == 0)
3281 /* If we got to this point, the colormap is full, so we're going
3282 to try to get the next closest color. The algorithm used is
3283 a least-squares matching, which is what X uses for closest
3284 color matching with StaticColor visuals. */
3285 int nearest, i;
3286 unsigned long nearest_delta = ~0;
3287 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3288 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3290 for (i = 0; i < ncells; ++i)
3291 cells[i].pixel = i;
3292 XQueryColors (display, cmap, cells, ncells);
3294 for (nearest = i = 0; i < ncells; ++i)
3296 long dred = (color->red >> 8) - (cells[i].red >> 8);
3297 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3298 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3299 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3301 if (delta < nearest_delta)
3303 nearest = i;
3304 nearest_delta = delta;
3308 color->red = cells[nearest].red;
3309 color->green = cells[nearest].green;
3310 color->blue = cells[nearest].blue;
3311 rc = XAllocColor (display, cmap, color);
3314 #ifdef DEBUG_X_COLORS
3315 if (rc)
3316 register_color (color->pixel);
3317 #endif /* DEBUG_X_COLORS */
3319 return rc;
3323 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3324 It's necessary to do this instead of just using PIXEL directly to
3325 get color reference counts right. */
3327 unsigned long
3328 x_copy_color (f, pixel)
3329 struct frame *f;
3330 unsigned long pixel;
3332 XColor color;
3334 color.pixel = pixel;
3335 BLOCK_INPUT;
3336 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3337 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3338 UNBLOCK_INPUT;
3339 #ifdef DEBUG_X_COLORS
3340 register_color (pixel);
3341 #endif
3342 return color.pixel;
3346 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3347 It's necessary to do this instead of just using PIXEL directly to
3348 get color reference counts right. */
3350 unsigned long
3351 x_copy_dpy_color (dpy, cmap, pixel)
3352 Display *dpy;
3353 Colormap cmap;
3354 unsigned long pixel;
3356 XColor color;
3358 color.pixel = pixel;
3359 BLOCK_INPUT;
3360 XQueryColor (dpy, cmap, &color);
3361 XAllocColor (dpy, cmap, &color);
3362 UNBLOCK_INPUT;
3363 #ifdef DEBUG_X_COLORS
3364 register_color (pixel);
3365 #endif
3366 return color.pixel;
3369 #endif /* MAC_TODO */
3372 /* Brightness beyond which a color won't have its highlight brightness
3373 boosted.
3375 Nominally, highlight colors for `3d' faces are calculated by
3376 brightening an object's color by a constant scale factor, but this
3377 doesn't yield good results for dark colors, so for colors who's
3378 brightness is less than this value (on a scale of 0-255) have to
3379 use an additional additive factor.
3381 The value here is set so that the default menu-bar/mode-line color
3382 (grey75) will not have its highlights changed at all. */
3383 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3386 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
3387 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3388 If this produces the same color as COLOR, try a color where all RGB
3389 values have DELTA added. Return the allocated color in *COLOR.
3390 DISPLAY is the X display, CMAP is the colormap to operate on.
3391 Value is non-zero if successful. */
3393 static int
3394 mac_alloc_lighter_color (f, color, factor, delta)
3395 struct frame *f;
3396 unsigned long *color;
3397 double factor;
3398 int delta;
3400 unsigned long new;
3401 long bright;
3403 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3404 delta /= 256;
3406 /* Change RGB values by specified FACTOR. Avoid overflow! */
3407 xassert (factor >= 0);
3408 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3409 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3410 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3412 /* Calculate brightness of COLOR. */
3413 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3414 + BLUE_FROM_ULONG (*color)) / 6;
3416 /* We only boost colors that are darker than
3417 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3418 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3419 /* Make an additive adjustment to NEW, because it's dark enough so
3420 that scaling by FACTOR alone isn't enough. */
3422 /* How far below the limit this color is (0 - 1, 1 being darker). */
3423 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3424 /* The additive adjustment. */
3425 int min_delta = delta * dimness * factor / 2;
3427 if (factor < 1)
3428 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3429 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3430 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3431 else
3432 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3433 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3434 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3437 if (new == *color)
3438 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3439 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3440 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3442 /* MAC_TODO: Map to palette and retry with delta if same? */
3443 /* MAC_TODO: Free colors (if using palette)? */
3445 if (new == *color)
3446 return 0;
3448 *color = new;
3450 return 1;
3454 /* Set up the foreground color for drawing relief lines of glyph
3455 string S. RELIEF is a pointer to a struct relief containing the GC
3456 with which lines will be drawn. Use a color that is FACTOR or
3457 DELTA lighter or darker than the relief's background which is found
3458 in S->f->output_data.x->relief_background. If such a color cannot
3459 be allocated, use DEFAULT_PIXEL, instead. */
3461 static void
3462 x_setup_relief_color (f, relief, factor, delta, default_pixel)
3463 struct frame *f;
3464 struct relief *relief;
3465 double factor;
3466 int delta;
3467 unsigned long default_pixel;
3469 XGCValues xgcv;
3470 struct mac_output *di = f->output_data.mac;
3471 unsigned long mask = GCForeground;
3472 unsigned long pixel;
3473 unsigned long background = di->relief_background;
3474 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3476 /* MAC_TODO: Free colors (if using palette)? */
3478 /* Allocate new color. */
3479 xgcv.foreground = default_pixel;
3480 pixel = background;
3481 if (dpyinfo->n_planes != 1
3482 && mac_alloc_lighter_color (f, &pixel, factor, delta))
3484 relief->allocated_p = 1;
3485 xgcv.foreground = relief->pixel = pixel;
3488 if (relief->gc == 0)
3490 #if 0 /* MAC_TODO: stipple */
3491 xgcv.stipple = dpyinfo->gray;
3492 mask |= GCStipple;
3493 #endif
3494 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3496 else
3497 XChangeGC (NULL, relief->gc, mask, &xgcv);
3501 /* Set up colors for the relief lines around glyph string S. */
3503 static void
3504 x_setup_relief_colors (s)
3505 struct glyph_string *s;
3507 struct mac_output *di = s->f->output_data.mac;
3508 unsigned long color;
3510 if (s->face->use_box_color_for_shadows_p)
3511 color = s->face->box_color;
3512 else if (s->first_glyph->type == IMAGE_GLYPH
3513 && s->img->pixmap
3514 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3515 color = IMAGE_BACKGROUND (s->img, s->f, 0);
3516 else
3518 XGCValues xgcv;
3520 /* Get the background color of the face. */
3521 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3522 color = xgcv.background;
3525 if (di->white_relief.gc == 0
3526 || color != di->relief_background)
3528 di->relief_background = color;
3529 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3530 WHITE_PIX_DEFAULT (s->f));
3531 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3532 BLACK_PIX_DEFAULT (s->f));
3537 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
3538 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3539 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3540 relief. LEFT_P non-zero means draw a relief on the left side of
3541 the rectangle. RIGHT_P non-zero means draw a relief on the right
3542 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3543 when drawing. */
3545 static void
3546 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3547 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
3548 struct frame *f;
3549 int left_x, top_y, right_x, bottom_y, width;
3550 int top_p, bot_p, left_p, right_p, raised_p;
3551 Rect *clip_rect;
3553 int i;
3554 GC gc;
3556 if (raised_p)
3557 gc = f->output_data.mac->white_relief.gc;
3558 else
3559 gc = f->output_data.mac->black_relief.gc;
3560 mac_set_clip_rectangles (f, gc, clip_rect, 1);
3562 /* Top. */
3563 if (top_p)
3564 for (i = 0; i < width; ++i)
3565 mac_draw_line (f, gc,
3566 left_x + i * left_p, top_y + i,
3567 right_x + 1 - i * right_p, top_y + i);
3569 /* Left. */
3570 if (left_p)
3571 for (i = 0; i < width; ++i)
3572 mac_draw_line (f, gc,
3573 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
3575 mac_reset_clip_rectangles (f, gc);
3576 if (raised_p)
3577 gc = f->output_data.mac->black_relief.gc;
3578 else
3579 gc = f->output_data.mac->white_relief.gc;
3580 mac_set_clip_rectangles (f, gc, clip_rect, 1);
3582 /* Bottom. */
3583 if (bot_p)
3584 for (i = 0; i < width; ++i)
3585 mac_draw_line (f, gc,
3586 left_x + i * left_p, bottom_y - i,
3587 right_x + 1 - i * right_p, bottom_y - i);
3589 /* Right. */
3590 if (right_p)
3591 for (i = 0; i < width; ++i)
3592 mac_draw_line (f, gc,
3593 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3595 mac_reset_clip_rectangles (f, gc);
3599 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3600 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3601 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3602 left side of the rectangle. RIGHT_P non-zero means draw a line
3603 on the right side of the rectangle. CLIP_RECT is the clipping
3604 rectangle to use when drawing. */
3606 static void
3607 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3608 left_p, right_p, clip_rect)
3609 struct glyph_string *s;
3610 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
3611 Rect *clip_rect;
3613 XGCValues xgcv;
3615 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3616 XSetForeground (s->display, s->gc, s->face->box_color);
3617 mac_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
3619 /* Top. */
3620 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3621 right_x - left_x + 1, width);
3623 /* Left. */
3624 if (left_p)
3625 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3626 width, bottom_y - top_y + 1);
3628 /* Bottom. */
3629 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3630 right_x - left_x + 1, width);
3632 /* Right. */
3633 if (right_p)
3634 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3635 top_y, width, bottom_y - top_y + 1);
3637 XSetForeground (s->display, s->gc, xgcv.foreground);
3638 mac_reset_clip_rectangles (s->f, s->gc);
3642 /* Draw a box around glyph string S. */
3644 static void
3645 x_draw_glyph_string_box (s)
3646 struct glyph_string *s;
3648 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3649 int left_p, right_p;
3650 struct glyph *last_glyph;
3651 Rect clip_rect;
3653 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3654 ? WINDOW_RIGHT_EDGE_X (s->w)
3655 : window_box_right (s->w, s->area));
3657 /* The glyph that may have a right box line. */
3658 last_glyph = (s->cmp || s->img
3659 ? s->first_glyph
3660 : s->first_glyph + s->nchars - 1);
3662 width = eabs (s->face->box_line_width);
3663 raised_p = s->face->box == FACE_RAISED_BOX;
3664 left_x = s->x;
3665 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3666 ? last_x - 1
3667 : min (last_x, s->x + s->background_width) - 1);
3668 top_y = s->y;
3669 bottom_y = top_y + s->height - 1;
3671 left_p = (s->first_glyph->left_box_line_p
3672 || (s->hl == DRAW_MOUSE_FACE
3673 && (s->prev == NULL
3674 || s->prev->hl != s->hl)));
3675 right_p = (last_glyph->right_box_line_p
3676 || (s->hl == DRAW_MOUSE_FACE
3677 && (s->next == NULL
3678 || s->next->hl != s->hl)));
3680 get_glyph_string_clip_rect (s, &clip_rect);
3682 if (s->face->box == FACE_SIMPLE_BOX)
3683 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3684 left_p, right_p, &clip_rect);
3685 else
3687 x_setup_relief_colors (s);
3688 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3689 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
3694 /* Draw foreground of image glyph string S. */
3696 static void
3697 x_draw_image_foreground (s)
3698 struct glyph_string *s;
3700 int x = s->x;
3701 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3703 /* If first glyph of S has a left box line, start drawing it to the
3704 right of that line. */
3705 if (s->face->box != FACE_NO_BOX
3706 && s->first_glyph->left_box_line_p
3707 && s->slice.x == 0)
3708 x += eabs (s->face->box_line_width);
3710 /* If there is a margin around the image, adjust x- and y-position
3711 by that margin. */
3712 if (s->slice.x == 0)
3713 x += s->img->hmargin;
3714 if (s->slice.y == 0)
3715 y += s->img->vmargin;
3717 if (s->img->pixmap)
3719 x_set_glyph_string_clipping (s);
3721 #if USE_CG_DRAWING
3722 mac_draw_cg_image (s->img->data.ptr_val,
3723 s->f, s->gc, s->slice.x, s->slice.y,
3724 s->slice.width, s->slice.height, x, y, 1);
3725 #endif
3726 if (s->img->mask)
3727 #if !USE_CG_DRAWING
3728 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3729 s->f, s->gc, s->slice.x, s->slice.y,
3730 s->slice.width, s->slice.height, x, y);
3731 #else
3733 #endif
3734 else
3736 #if !USE_CG_DRAWING
3737 mac_copy_area (s->img->pixmap,
3738 s->f, s->gc, s->slice.x, s->slice.y,
3739 s->slice.width, s->slice.height, x, y);
3740 #endif
3742 /* When the image has a mask, we can expect that at
3743 least part of a mouse highlight or a block cursor will
3744 be visible. If the image doesn't have a mask, make
3745 a block cursor visible by drawing a rectangle around
3746 the image. I believe it's looking better if we do
3747 nothing here for mouse-face. */
3748 if (s->hl == DRAW_CURSOR)
3750 int r = s->img->relief;
3751 if (r < 0) r = -r;
3752 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
3753 s->slice.width + r*2 - 1,
3754 s->slice.height + r*2 - 1);
3758 else
3759 /* Draw a rectangle if image could not be loaded. */
3760 mac_draw_rectangle (s->f, s->gc, x, y,
3761 s->slice.width - 1, s->slice.height - 1);
3765 /* Draw a relief around the image glyph string S. */
3767 static void
3768 x_draw_image_relief (s)
3769 struct glyph_string *s;
3771 int x0, y0, x1, y1, thick, raised_p;
3772 Rect r;
3773 int x = s->x;
3774 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3776 /* If first glyph of S has a left box line, start drawing it to the
3777 right of that line. */
3778 if (s->face->box != FACE_NO_BOX
3779 && s->first_glyph->left_box_line_p
3780 && s->slice.x == 0)
3781 x += eabs (s->face->box_line_width);
3783 /* If there is a margin around the image, adjust x- and y-position
3784 by that margin. */
3785 if (s->slice.x == 0)
3786 x += s->img->hmargin;
3787 if (s->slice.y == 0)
3788 y += s->img->vmargin;
3790 if (s->hl == DRAW_IMAGE_SUNKEN
3791 || s->hl == DRAW_IMAGE_RAISED)
3793 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3794 raised_p = s->hl == DRAW_IMAGE_RAISED;
3796 else
3798 thick = eabs (s->img->relief);
3799 raised_p = s->img->relief > 0;
3802 x0 = x - thick;
3803 y0 = y - thick;
3804 x1 = x + s->slice.width + thick - 1;
3805 y1 = y + s->slice.height + thick - 1;
3807 x_setup_relief_colors (s);
3808 get_glyph_string_clip_rect (s, &r);
3809 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3810 s->slice.y == 0,
3811 s->slice.y + s->slice.height == s->img->height,
3812 s->slice.x == 0,
3813 s->slice.x + s->slice.width == s->img->width,
3814 &r);
3818 /* Draw part of the background of glyph string S. X, Y, W, and H
3819 give the rectangle to draw. */
3821 static void
3822 x_draw_glyph_string_bg_rect (s, x, y, w, h)
3823 struct glyph_string *s;
3824 int x, y, w, h;
3826 #if 0 /* MAC_TODO: stipple */
3827 if (s->stippled_p)
3829 /* Fill background with a stipple pattern. */
3830 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3831 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3832 XSetFillStyle (s->display, s->gc, FillSolid);
3834 else
3835 #endif /* MAC_TODO */
3836 x_clear_glyph_string_rect (s, x, y, w, h);
3840 /* Draw image glyph string S.
3842 s->y
3843 s->x +-------------------------
3844 | s->face->box
3846 | +-------------------------
3847 | | s->img->margin
3849 | | +-------------------
3850 | | | the image
3854 static void
3855 x_draw_image_glyph_string (s)
3856 struct glyph_string *s;
3858 int x, y;
3859 int box_line_hwidth = eabs (s->face->box_line_width);
3860 int box_line_vwidth = max (s->face->box_line_width, 0);
3861 int height;
3863 height = s->height - 2 * box_line_vwidth;
3866 /* Fill background with face under the image. Do it only if row is
3867 taller than image or if image has a clip mask to reduce
3868 flickering. */
3869 s->stippled_p = s->face->stipple != 0;
3870 if (height > s->slice.height
3871 || s->img->hmargin
3872 || s->img->vmargin
3873 || s->img->mask
3874 || s->img->pixmap == 0
3875 || s->width != s->background_width)
3877 x = s->x;
3878 if (s->first_glyph->left_box_line_p
3879 && s->slice.x == 0)
3880 x += box_line_hwidth;
3882 y = s->y;
3883 if (s->slice.y == 0)
3884 y += box_line_vwidth;
3886 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3888 s->background_filled_p = 1;
3891 /* Draw the foreground. */
3892 x_draw_image_foreground (s);
3894 /* If we must draw a relief around the image, do it. */
3895 if (s->img->relief
3896 || s->hl == DRAW_IMAGE_RAISED
3897 || s->hl == DRAW_IMAGE_SUNKEN)
3898 x_draw_image_relief (s);
3902 /* Draw stretch glyph string S. */
3904 static void
3905 x_draw_stretch_glyph_string (s)
3906 struct glyph_string *s;
3908 xassert (s->first_glyph->type == STRETCH_GLYPH);
3910 if (s->hl == DRAW_CURSOR
3911 && !x_stretch_cursor_p)
3913 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3914 as wide as the stretch glyph. */
3915 int width, background_width = s->background_width;
3916 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3918 if (x < left_x)
3920 background_width -= left_x - x;
3921 x = left_x;
3923 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3925 /* Draw cursor. */
3926 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3928 /* Clear rest using the GC of the original non-cursor face. */
3929 if (width < background_width)
3931 int y = s->y;
3932 int w = background_width - width, h = s->height;
3933 Rect r;
3934 GC gc;
3936 x += width;
3937 if (s->row->mouse_face_p
3938 && cursor_in_mouse_face_p (s->w))
3940 x_set_mouse_face_gc (s);
3941 gc = s->gc;
3943 else
3944 gc = s->face->gc;
3946 get_glyph_string_clip_rect (s, &r);
3947 mac_set_clip_rectangles (s->f, gc, &r, 1);
3949 #if 0 /* MAC_TODO: stipple */
3950 if (s->face->stipple)
3952 /* Fill background with a stipple pattern. */
3953 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3954 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3955 XSetFillStyle (s->display, gc, FillSolid);
3957 else
3958 #endif /* MAC_TODO */
3959 mac_erase_rectangle (s->f, gc, x, y, w, h);
3962 else if (!s->background_filled_p)
3964 int background_width = s->background_width;
3965 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3967 /* Don't draw into left margin, fringe or scrollbar area
3968 except for header line and mode line. */
3969 if (x < left_x && !s->row->mode_line_p)
3971 background_width -= left_x - x;
3972 x = left_x;
3974 if (background_width > 0)
3975 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3978 s->background_filled_p = 1;
3982 /* Draw glyph string S. */
3984 static void
3985 x_draw_glyph_string (s)
3986 struct glyph_string *s;
3988 int relief_drawn_p = 0;
3990 /* If S draws into the background of its successor that does not
3991 draw a cursor, draw the background of the successor first so that
3992 S can draw into it. This makes S->next use XDrawString instead
3993 of XDrawImageString. */
3994 if (s->next && s->right_overhang && !s->for_overlaps
3995 && s->next->hl != DRAW_CURSOR)
3997 xassert (s->next->img == NULL);
3998 x_set_glyph_string_gc (s->next);
3999 x_set_glyph_string_clipping (s->next);
4000 x_draw_glyph_string_background (s->next, 1);
4003 /* Set up S->gc, set clipping and draw S. */
4004 x_set_glyph_string_gc (s);
4006 /* Draw relief (if any) in advance for char/composition so that the
4007 glyph string can be drawn over it. */
4008 if (!s->for_overlaps
4009 && s->face->box != FACE_NO_BOX
4010 && (s->first_glyph->type == CHAR_GLYPH
4011 || s->first_glyph->type == COMPOSITE_GLYPH))
4014 x_set_glyph_string_clipping (s);
4015 x_draw_glyph_string_background (s, 1);
4016 x_draw_glyph_string_box (s);
4017 x_set_glyph_string_clipping (s);
4018 relief_drawn_p = 1;
4020 else
4021 x_set_glyph_string_clipping (s);
4023 switch (s->first_glyph->type)
4025 case IMAGE_GLYPH:
4026 x_draw_image_glyph_string (s);
4027 break;
4029 case STRETCH_GLYPH:
4030 x_draw_stretch_glyph_string (s);
4031 break;
4033 case CHAR_GLYPH:
4034 if (s->for_overlaps)
4035 s->background_filled_p = 1;
4036 else
4037 x_draw_glyph_string_background (s, 0);
4038 x_draw_glyph_string_foreground (s);
4039 break;
4041 case COMPOSITE_GLYPH:
4042 if (s->for_overlaps || s->gidx > 0)
4043 s->background_filled_p = 1;
4044 else
4045 x_draw_glyph_string_background (s, 1);
4046 x_draw_composite_glyph_string_foreground (s);
4047 break;
4049 default:
4050 abort ();
4053 if (!s->for_overlaps)
4055 /* Draw underline. */
4056 if (s->face->underline_p)
4058 unsigned long tem, h;
4059 int y;
4061 #if 0
4062 /* Get the underline thickness. Default is 1 pixel. */
4063 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4064 #endif
4065 h = 1;
4067 y = s->y + s->height - h;
4068 if (!x_underline_at_descent_line)
4070 /* Get the underline position. This is the recommended
4071 vertical offset in pixels from the baseline to the top of
4072 the underline. This is a signed value according to the
4073 specs, and its default is
4075 ROUND ((maximum descent) / 2), with
4076 ROUND(x) = floor (x + 0.5) */
4078 #if 0
4079 if (x_use_underline_position_properties
4080 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4081 y = s->ybase + (long) tem;
4082 else
4083 #endif
4084 if (s->face->font)
4085 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4088 if (s->face->underline_defaulted_p)
4089 mac_fill_rectangle (s->f, s->gc, s->x, y,
4090 s->background_width, h);
4091 else
4093 XGCValues xgcv;
4094 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4095 XSetForeground (s->display, s->gc, s->face->underline_color);
4096 mac_fill_rectangle (s->f, s->gc, s->x, y,
4097 s->background_width, h);
4098 XSetForeground (s->display, s->gc, xgcv.foreground);
4102 /* Draw overline. */
4103 if (s->face->overline_p)
4105 unsigned long dy = 0, h = 1;
4107 if (s->face->overline_color_defaulted_p)
4108 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4109 s->background_width, h);
4110 else
4112 XGCValues xgcv;
4113 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4114 XSetForeground (s->display, s->gc, s->face->overline_color);
4115 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4116 s->background_width, h);
4117 XSetForeground (s->display, s->gc, xgcv.foreground);
4121 /* Draw strike-through. */
4122 if (s->face->strike_through_p)
4124 unsigned long h = 1;
4125 unsigned long dy = (s->height - h) / 2;
4127 if (s->face->strike_through_color_defaulted_p)
4128 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4129 s->width, h);
4130 else
4132 XGCValues xgcv;
4133 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4134 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4135 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4136 s->width, h);
4137 XSetForeground (s->display, s->gc, xgcv.foreground);
4141 /* Draw relief if not yet drawn. */
4142 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
4143 x_draw_glyph_string_box (s);
4146 /* Reset clipping. */
4147 mac_reset_clip_rectangles (s->f, s->gc);
4150 /* Shift display to make room for inserted glyphs. */
4152 void
4153 mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4154 struct frame *f;
4155 int x, y, width, height, shift_by;
4157 mac_scroll_area (f, f->output_data.mac->normal_gc,
4158 x, y, width, height,
4159 x + shift_by, y);
4162 /* Delete N glyphs at the nominal cursor position. Not implemented
4163 for X frames. */
4165 static void
4166 x_delete_glyphs (n)
4167 register int n;
4169 abort ();
4173 /* Clear entire frame. If updating_frame is non-null, clear that
4174 frame. Otherwise clear the selected frame. */
4176 static void
4177 x_clear_frame (struct frame *f)
4179 /* Clearing the frame will erase any cursor, so mark them all as no
4180 longer visible. */
4181 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4182 output_cursor.hpos = output_cursor.vpos = 0;
4183 output_cursor.x = -1;
4185 /* We don't set the output cursor here because there will always
4186 follow an explicit cursor_to. */
4187 BLOCK_INPUT;
4188 mac_clear_window (f);
4190 /* We have to clear the scroll bars, too. If we have changed
4191 colors or something like that, then they should be notified. */
4192 x_scroll_bar_clear (f);
4194 XFlush (FRAME_MAC_DISPLAY (f));
4195 UNBLOCK_INPUT;
4200 /* Invert the middle quarter of the frame for .15 sec. */
4202 /* We use the select system call to do the waiting, so we have to make
4203 sure it's available. If it isn't, we just won't do visual bells. */
4205 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4208 /* Subtract the `struct timeval' values X and Y, storing the result in
4209 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4211 static int
4212 timeval_subtract (result, x, y)
4213 struct timeval *result, x, y;
4215 /* Perform the carry for the later subtraction by updating y. This
4216 is safer because on some systems the tv_sec member is unsigned. */
4217 if (x.tv_usec < y.tv_usec)
4219 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4220 y.tv_usec -= 1000000 * nsec;
4221 y.tv_sec += nsec;
4224 if (x.tv_usec - y.tv_usec > 1000000)
4226 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4227 y.tv_usec += 1000000 * nsec;
4228 y.tv_sec -= nsec;
4231 /* Compute the time remaining to wait. tv_usec is certainly
4232 positive. */
4233 result->tv_sec = x.tv_sec - y.tv_sec;
4234 result->tv_usec = x.tv_usec - y.tv_usec;
4236 /* Return indication of whether the result should be considered
4237 negative. */
4238 return x.tv_sec < y.tv_sec;
4241 void
4242 XTflash (f)
4243 struct frame *f;
4245 /* Get the height not including a menu bar widget. */
4246 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4247 /* Height of each line to flash. */
4248 int flash_height = FRAME_LINE_HEIGHT (f);
4249 /* These will be the left and right margins of the rectangles. */
4250 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4251 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4253 int width;
4255 /* Don't flash the area between a scroll bar and the frame
4256 edge it is next to. */
4257 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4259 case vertical_scroll_bar_left:
4260 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4261 break;
4263 case vertical_scroll_bar_right:
4264 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4265 break;
4267 default:
4268 break;
4271 width = flash_right - flash_left;
4273 BLOCK_INPUT;
4275 /* If window is tall, flash top and bottom line. */
4276 if (height > 3 * FRAME_LINE_HEIGHT (f))
4278 mac_invert_rectangle (f, flash_left,
4279 (FRAME_INTERNAL_BORDER_WIDTH (f)
4280 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4281 width, flash_height);
4282 mac_invert_rectangle (f, flash_left,
4283 (height - flash_height
4284 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4285 width, flash_height);
4287 else
4288 /* If it is short, flash it all. */
4289 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4290 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4292 x_flush (f);
4295 struct timeval wakeup;
4297 EMACS_GET_TIME (wakeup);
4299 /* Compute time to wait until, propagating carry from usecs. */
4300 wakeup.tv_usec += 150000;
4301 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4302 wakeup.tv_usec %= 1000000;
4304 /* Keep waiting until past the time wakeup or any input gets
4305 available. */
4306 while (! detect_input_pending ())
4308 struct timeval current;
4309 struct timeval timeout;
4311 EMACS_GET_TIME (current);
4313 /* Break if result would be negative. */
4314 if (timeval_subtract (&current, wakeup, current))
4315 break;
4317 /* How long `select' should wait. */
4318 timeout.tv_sec = 0;
4319 timeout.tv_usec = 10000;
4321 /* Try to wait that long--but we might wake up sooner. */
4322 select (0, NULL, NULL, NULL, &timeout);
4326 /* If window is tall, flash top and bottom line. */
4327 if (height > 3 * FRAME_LINE_HEIGHT (f))
4329 mac_invert_rectangle (f, flash_left,
4330 (FRAME_INTERNAL_BORDER_WIDTH (f)
4331 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4332 width, flash_height);
4333 mac_invert_rectangle (f, flash_left,
4334 (height - flash_height
4335 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4336 width, flash_height);
4338 else
4339 /* If it is short, flash it all. */
4340 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4341 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4343 x_flush (f);
4345 UNBLOCK_INPUT;
4348 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4351 /* Make audible bell. */
4353 void
4354 XTring_bell ()
4356 struct frame *f = SELECTED_FRAME ();
4358 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4359 if (visible_bell)
4360 XTflash (f);
4361 else
4362 #endif
4364 BLOCK_INPUT;
4365 SysBeep (1);
4366 XFlush (FRAME_MAC_DISPLAY (f));
4367 UNBLOCK_INPUT;
4372 /* Specify how many text lines, from the top of the window,
4373 should be affected by insert-lines and delete-lines operations.
4374 This, and those operations, are used only within an update
4375 that is bounded by calls to x_update_begin and x_update_end. */
4377 static void
4378 XTset_terminal_window (n)
4379 register int n;
4381 /* This function intentionally left blank. */
4386 /***********************************************************************
4387 Line Dance
4388 ***********************************************************************/
4390 /* Perform an insert-lines or delete-lines operation, inserting N
4391 lines or deleting -N lines at vertical position VPOS. */
4393 static void
4394 x_ins_del_lines (vpos, n)
4395 int vpos, n;
4397 abort ();
4401 /* Scroll part of the display as described by RUN. */
4403 static void
4404 x_scroll_run (w, run)
4405 struct window *w;
4406 struct run *run;
4408 struct frame *f = XFRAME (w->frame);
4409 int x, y, width, height, from_y, to_y, bottom_y;
4411 /* Get frame-relative bounding box of the text display area of W,
4412 without mode lines. Include in this box the left and right
4413 fringe of W. */
4414 window_box (w, -1, &x, &y, &width, &height);
4416 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4417 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4418 bottom_y = y + height;
4420 if (to_y < from_y)
4422 /* Scrolling up. Make sure we don't copy part of the mode
4423 line at the bottom. */
4424 if (from_y + run->height > bottom_y)
4425 height = bottom_y - from_y;
4426 else
4427 height = run->height;
4429 else
4431 /* Scolling down. Make sure we don't copy over the mode line.
4432 at the bottom. */
4433 if (to_y + run->height > bottom_y)
4434 height = bottom_y - to_y;
4435 else
4436 height = run->height;
4439 BLOCK_INPUT;
4441 /* Cursor off. Will be switched on again in x_update_window_end. */
4442 updated_window = w;
4443 x_clear_cursor (w);
4445 mac_scroll_area (f, f->output_data.mac->normal_gc,
4446 x, from_y,
4447 width, height,
4448 x, to_y);
4450 UNBLOCK_INPUT;
4455 /***********************************************************************
4456 Exposure Events
4457 ***********************************************************************/
4460 static void
4461 frame_highlight (f)
4462 struct frame *f;
4464 x_update_cursor (f, 1);
4467 static void
4468 frame_unhighlight (f)
4469 struct frame *f;
4471 x_update_cursor (f, 1);
4474 /* The focus has changed. Update the frames as necessary to reflect
4475 the new situation. Note that we can't change the selected frame
4476 here, because the Lisp code we are interrupting might become confused.
4477 Each event gets marked with the frame in which it occurred, so the
4478 Lisp code can tell when the switch took place by examining the events. */
4480 static void
4481 x_new_focus_frame (dpyinfo, frame)
4482 struct x_display_info *dpyinfo;
4483 struct frame *frame;
4485 struct frame *old_focus = dpyinfo->x_focus_frame;
4487 if (frame != dpyinfo->x_focus_frame)
4489 /* Set this before calling other routines, so that they see
4490 the correct value of x_focus_frame. */
4491 dpyinfo->x_focus_frame = frame;
4493 if (old_focus && old_focus->auto_lower)
4494 x_lower_frame (old_focus);
4496 #if 0
4497 selected_frame = frame;
4498 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4499 selected_frame);
4500 Fselect_window (selected_frame->selected_window, Qnil);
4501 choose_minibuf_frame ();
4502 #endif /* ! 0 */
4504 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4505 pending_autoraise_frame = dpyinfo->x_focus_frame;
4506 else
4507 pending_autoraise_frame = 0;
4509 #if USE_MAC_FONT_PANEL
4510 if (frame)
4511 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
4512 #endif
4515 x_frame_rehighlight (dpyinfo);
4518 /* Handle FocusIn and FocusOut state changes for FRAME.
4519 If FRAME has focus and there exists more than one frame, puts
4520 a FOCUS_IN_EVENT into *BUFP. */
4522 static void
4523 mac_focus_changed (type, dpyinfo, frame, bufp)
4524 int type;
4525 struct mac_display_info *dpyinfo;
4526 struct frame *frame;
4527 struct input_event *bufp;
4529 if (type == activeFlag)
4531 if (dpyinfo->x_focus_event_frame != frame)
4533 x_new_focus_frame (dpyinfo, frame);
4534 dpyinfo->x_focus_event_frame = frame;
4536 /* Don't stop displaying the initial startup message
4537 for a switch-frame event we don't need. */
4538 if (NILP (Vterminal_frame)
4539 && CONSP (Vframe_list)
4540 && !NILP (XCDR (Vframe_list)))
4542 bufp->kind = FOCUS_IN_EVENT;
4543 XSETFRAME (bufp->frame_or_window, frame);
4547 else
4549 if (dpyinfo->x_focus_event_frame == frame)
4551 dpyinfo->x_focus_event_frame = 0;
4552 x_new_focus_frame (dpyinfo, 0);
4557 /* The focus may have changed. Figure out if it is a real focus change,
4558 by checking both FocusIn/Out and Enter/LeaveNotify events.
4560 Returns FOCUS_IN_EVENT event in *BUFP. */
4562 static void
4563 x_detect_focus_change (dpyinfo, event, bufp)
4564 struct mac_display_info *dpyinfo;
4565 const EventRecord *event;
4566 struct input_event *bufp;
4568 struct frame *frame;
4570 frame = mac_window_to_frame ((WindowRef) event->message);
4571 if (! frame)
4572 return;
4574 /* On Mac, this is only called from focus events, so no switch needed. */
4575 mac_focus_changed ((event->modifiers & activeFlag),
4576 dpyinfo, frame, bufp);
4580 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4582 void
4583 x_mouse_leave (dpyinfo)
4584 struct x_display_info *dpyinfo;
4586 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4589 /* The focus has changed, or we have redirected a frame's focus to
4590 another frame (this happens when a frame uses a surrogate
4591 mini-buffer frame). Shift the highlight as appropriate.
4593 The FRAME argument doesn't necessarily have anything to do with which
4594 frame is being highlighted or un-highlighted; we only use it to find
4595 the appropriate X display info. */
4597 static void
4598 XTframe_rehighlight (frame)
4599 struct frame *frame;
4601 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4604 static void
4605 x_frame_rehighlight (dpyinfo)
4606 struct x_display_info *dpyinfo;
4608 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4610 if (dpyinfo->x_focus_frame)
4612 dpyinfo->x_highlight_frame
4613 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4614 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4615 : dpyinfo->x_focus_frame);
4616 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4618 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4619 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4622 else
4623 dpyinfo->x_highlight_frame = 0;
4625 if (dpyinfo->x_highlight_frame != old_highlight)
4627 if (old_highlight)
4628 frame_unhighlight (old_highlight);
4629 if (dpyinfo->x_highlight_frame)
4630 frame_highlight (dpyinfo->x_highlight_frame);
4636 /* Convert a keysym to its name. */
4638 char *
4639 x_get_keysym_name (keysym)
4640 int keysym;
4642 char *value;
4644 BLOCK_INPUT;
4645 #if 0
4646 value = XKeysymToString (keysym);
4647 #else
4648 value = 0;
4649 #endif
4650 UNBLOCK_INPUT;
4652 return value;
4657 /* Function to report a mouse movement to the mainstream Emacs code.
4658 The input handler calls this.
4660 We have received a mouse movement event, which is given in *event.
4661 If the mouse is over a different glyph than it was last time, tell
4662 the mainstream emacs code by setting mouse_moved. If not, ask for
4663 another motion event, so we can check again the next time it moves. */
4665 static Point last_mouse_motion_position;
4666 static Lisp_Object last_mouse_motion_frame;
4668 static int
4669 note_mouse_movement (frame, pos)
4670 FRAME_PTR frame;
4671 Point *pos;
4673 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4674 #if TARGET_API_MAC_CARBON
4675 Rect r;
4676 #endif
4678 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4679 last_mouse_motion_position = *pos;
4680 XSETFRAME (last_mouse_motion_frame, frame);
4682 if (frame == dpyinfo->mouse_face_mouse_frame
4683 #if TARGET_API_MAC_CARBON
4684 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
4685 #else
4686 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
4687 #endif
4690 /* This case corresponds to LeaveNotify in X11. If we move
4691 outside the frame, then we're certainly no longer on any text
4692 in the frame. */
4693 clear_mouse_face (dpyinfo);
4694 dpyinfo->mouse_face_mouse_frame = 0;
4695 if (!dpyinfo->grabbed)
4696 FRAME_RIF (frame)->define_frame_cursor (frame,
4697 frame->output_data.mac->nontext_cursor);
4700 /* Has the mouse moved off the glyph it was on at the last sighting? */
4701 if (frame != last_mouse_glyph_frame
4702 || !PtInRect (*pos, &last_mouse_glyph))
4704 frame->mouse_moved = 1;
4705 last_mouse_scroll_bar = Qnil;
4706 note_mouse_highlight (frame, pos->h, pos->v);
4707 /* Remember which glyph we're now on. */
4708 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
4709 last_mouse_glyph_frame = frame;
4710 return 1;
4713 return 0;
4717 /************************************************************************
4718 Mouse Face
4719 ************************************************************************/
4721 /* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4723 static void
4724 redo_mouse_highlight ()
4726 if (!NILP (last_mouse_motion_frame)
4727 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4728 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4729 last_mouse_motion_position.h,
4730 last_mouse_motion_position.v);
4734 static struct frame *
4735 mac_focus_frame (dpyinfo)
4736 struct mac_display_info *dpyinfo;
4738 if (dpyinfo->x_focus_frame)
4739 return dpyinfo->x_focus_frame;
4740 else
4741 /* Mac version may get events, such as a menu bar click, even when
4742 all the frames are invisible. In this case, we regard the
4743 event came to the selected frame. */
4744 return SELECTED_FRAME ();
4748 /* Return the current position of the mouse.
4749 *FP should be a frame which indicates which display to ask about.
4751 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4752 and *PART to the frame, window, and scroll bar part that the mouse
4753 is over. Set *X and *Y to the portion and whole of the mouse's
4754 position on the scroll bar.
4756 If the mouse movement started elsewhere, set *FP to the frame the
4757 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4758 the mouse is over.
4760 Set *TIME to the server time-stamp for the time at which the mouse
4761 was at this position.
4763 Don't store anything if we don't have a valid set of values to report.
4765 This clears the mouse_moved flag, so we can wait for the next mouse
4766 movement. */
4768 static void
4769 XTmouse_position (fp, insist, bar_window, part, x, y, time)
4770 FRAME_PTR *fp;
4771 int insist;
4772 Lisp_Object *bar_window;
4773 enum scroll_bar_part *part;
4774 Lisp_Object *x, *y;
4775 unsigned long *time;
4777 FRAME_PTR f1;
4779 BLOCK_INPUT;
4781 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4782 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4783 else
4785 Lisp_Object frame, tail;
4787 /* Clear the mouse-moved flag for every frame on this display. */
4788 FOR_EACH_FRAME (tail, frame)
4789 XFRAME (frame)->mouse_moved = 0;
4791 last_mouse_scroll_bar = Qnil;
4793 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4794 && FRAME_LIVE_P (last_mouse_frame))
4795 f1 = last_mouse_frame;
4796 else
4797 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
4799 if (f1)
4801 /* Ok, we found a frame. Store all the values.
4802 last_mouse_glyph is a rectangle used to reduce the
4803 generation of mouse events. To not miss any motion
4804 events, we must divide the frame into rectangles of the
4805 size of the smallest character that could be displayed
4806 on it, i.e. into the same rectangles that matrices on
4807 the frame are divided into. */
4808 Point mouse_pos;
4810 #if TARGET_API_MAC_CARBON
4811 GetGlobalMouse (&mouse_pos);
4812 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4813 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4814 #else
4815 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4816 GetMouse (&mouse_pos);
4817 #endif
4818 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4819 &last_mouse_glyph);
4820 last_mouse_glyph_frame = f1;
4822 *bar_window = Qnil;
4823 *part = 0;
4824 *fp = f1;
4825 XSETINT (*x, mouse_pos.h);
4826 XSETINT (*y, mouse_pos.v);
4827 *time = last_mouse_movement_time;
4831 UNBLOCK_INPUT;
4835 /************************************************************************
4836 Toolkit scroll bars
4837 ************************************************************************/
4839 #ifdef USE_TOOLKIT_SCROLL_BARS
4841 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4842 static OSStatus install_scroll_bar_timer P_ ((void));
4843 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
4844 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
4845 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
4846 struct input_event *));
4847 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
4848 Rect *));
4849 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
4850 ControlPartCode, Point,
4851 struct input_event *));
4852 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
4853 struct input_event *));
4854 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
4855 Point, struct input_event *));
4856 static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4857 int, int, int));
4859 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
4861 static int last_scroll_bar_part;
4863 static EventLoopTimerRef scroll_bar_timer;
4865 static int scroll_bar_timer_event_posted_p;
4867 #define SCROLL_BAR_FIRST_DELAY 0.5
4868 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4870 static pascal void
4871 scroll_bar_timer_callback (timer, data)
4872 EventLoopTimerRef timer;
4873 void *data;
4875 OSStatus err;
4877 err = mac_post_mouse_moved_event ();
4878 if (err == noErr)
4879 scroll_bar_timer_event_posted_p = 1;
4882 static OSStatus
4883 install_scroll_bar_timer ()
4885 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4887 if (scroll_bar_timer_callbackUPP == NULL)
4888 scroll_bar_timer_callbackUPP =
4889 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4891 if (scroll_bar_timer == NULL)
4892 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4893 kEventDurationForever as delays. */
4894 return
4895 InstallEventLoopTimer (GetCurrentEventLoop (),
4896 kEventDurationForever, kEventDurationForever,
4897 scroll_bar_timer_callbackUPP, NULL,
4898 &scroll_bar_timer);
4901 static OSStatus
4902 set_scroll_bar_timer (delay)
4903 EventTimerInterval delay;
4905 if (scroll_bar_timer == NULL)
4906 install_scroll_bar_timer ();
4908 scroll_bar_timer_event_posted_p = 0;
4910 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4913 static int
4914 control_part_code_to_scroll_bar_part (part_code)
4915 ControlPartCode part_code;
4917 switch (part_code)
4919 case kControlUpButtonPart: return scroll_bar_up_arrow;
4920 case kControlDownButtonPart: return scroll_bar_down_arrow;
4921 case kControlPageUpPart: return scroll_bar_above_handle;
4922 case kControlPageDownPart: return scroll_bar_below_handle;
4923 case kControlIndicatorPart: return scroll_bar_handle;
4926 return -1;
4929 static void
4930 construct_scroll_bar_click (bar, part, bufp)
4931 struct scroll_bar *bar;
4932 int part;
4933 struct input_event *bufp;
4935 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4936 bufp->frame_or_window = bar->window;
4937 bufp->arg = Qnil;
4938 bufp->part = part;
4939 bufp->code = 0;
4940 XSETINT (bufp->x, 0);
4941 XSETINT (bufp->y, 0);
4942 bufp->modifiers = 0;
4945 static OSStatus
4946 get_control_part_bounds (ch, part_code, rect)
4947 ControlRef ch;
4948 ControlPartCode part_code;
4949 Rect *rect;
4951 RgnHandle region = NewRgn ();
4952 OSStatus err;
4954 err = GetControlRegion (ch, part_code, region);
4955 if (err == noErr)
4956 GetRegionBounds (region, rect);
4957 DisposeRgn (region);
4959 return err;
4962 static void
4963 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
4964 struct scroll_bar *bar;
4965 ControlPartCode part_code;
4966 Point mouse_pos;
4967 struct input_event *bufp;
4969 int part = control_part_code_to_scroll_bar_part (part_code);
4971 if (part < 0)
4972 return;
4974 if (part != scroll_bar_handle)
4976 construct_scroll_bar_click (bar, part, bufp);
4977 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4978 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
4979 bar->dragging = Qnil;
4981 else
4983 Rect r;
4985 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4986 kControlIndicatorPart, &r);
4987 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
4990 last_scroll_bar_part = part;
4991 tracked_scroll_bar = bar;
4994 static void
4995 x_scroll_bar_handle_release (bar, bufp)
4996 struct scroll_bar *bar;
4997 struct input_event *bufp;
4999 if (last_scroll_bar_part != scroll_bar_handle
5000 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
5001 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
5003 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5004 set_scroll_bar_timer (kEventDurationForever);
5006 last_scroll_bar_part = -1;
5007 bar->dragging = Qnil;
5008 tracked_scroll_bar = NULL;
5011 static void
5012 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
5013 WindowRef win;
5014 struct scroll_bar *bar;
5015 Point mouse_pos;
5016 struct input_event *bufp;
5018 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5020 if (last_scroll_bar_part == scroll_bar_handle)
5022 int top, top_range;
5023 Rect r;
5025 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
5026 kControlIndicatorPart, &r);
5028 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
5029 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
5031 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
5032 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
5034 if (top < 0)
5035 top = 0;
5036 if (top > top_range)
5037 top = top_range;
5039 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
5040 XSETINT (bufp->x, top);
5041 XSETINT (bufp->y, top_range);
5043 else
5045 ControlPartCode part_code;
5046 int unhilite_p = 0, part;
5048 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
5049 unhilite_p = 1;
5050 else
5052 part = control_part_code_to_scroll_bar_part (part_code);
5054 switch (last_scroll_bar_part)
5056 case scroll_bar_above_handle:
5057 case scroll_bar_below_handle:
5058 if (part != scroll_bar_above_handle
5059 && part != scroll_bar_below_handle)
5060 unhilite_p = 1;
5061 break;
5063 case scroll_bar_up_arrow:
5064 case scroll_bar_down_arrow:
5065 if (part != scroll_bar_up_arrow
5066 && part != scroll_bar_down_arrow)
5067 unhilite_p = 1;
5068 break;
5072 if (unhilite_p)
5073 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5074 else if (part != last_scroll_bar_part
5075 || scroll_bar_timer_event_posted_p)
5077 construct_scroll_bar_click (bar, part, bufp);
5078 last_scroll_bar_part = part;
5079 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5080 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
5085 /* Set the thumb size and position of scroll bar BAR. We are currently
5086 displaying PORTION out of a whole WHOLE, and our position POSITION. */
5088 static void
5089 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
5090 struct scroll_bar *bar;
5091 int portion, position, whole;
5093 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5094 int value, viewsize, maximum;
5096 if (XINT (bar->track_height) == 0)
5097 return;
5099 if (whole <= portion)
5100 value = 0, viewsize = 1, maximum = 0;
5101 else
5103 float scale;
5105 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
5106 scale = (float) maximum / (whole - portion);
5107 value = position * scale + 0.5f;
5108 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
5111 BLOCK_INPUT;
5113 if (GetControlViewSize (ch) != viewsize
5114 || GetControl32BitValue (ch) != value
5115 || GetControl32BitMaximum (ch) != maximum)
5117 /* Temporarily hide the scroll bar to avoid multiple redraws. */
5118 SetControlVisibility (ch, false, false);
5120 SetControl32BitMaximum (ch, maximum);
5121 SetControl32BitValue (ch, value);
5122 SetControlViewSize (ch, viewsize);
5124 SetControlVisibility (ch, true, true);
5127 UNBLOCK_INPUT;
5130 #endif /* USE_TOOLKIT_SCROLL_BARS */
5134 /************************************************************************
5135 Scroll bars, general
5136 ************************************************************************/
5138 /* Create a scroll bar and return the scroll bar vector for it. W is
5139 the Emacs window on which to create the scroll bar. TOP, LEFT,
5140 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
5141 scroll bar. */
5143 static struct scroll_bar *
5144 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5145 struct window *w;
5146 int top, left, width, height, disp_top, disp_height;
5148 struct frame *f = XFRAME (w->frame);
5149 struct scroll_bar *bar
5150 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5151 Rect r;
5152 ControlRef ch;
5154 BLOCK_INPUT;
5156 r.left = left;
5157 r.top = disp_top;
5158 r.right = left + width;
5159 r.bottom = disp_top + disp_height;
5161 #if USE_CG_DRAWING
5162 mac_prepare_for_quickdraw (f);
5163 #endif
5164 #if TARGET_API_MAC_CARBON
5165 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
5166 #ifdef USE_TOOLKIT_SCROLL_BARS
5167 false,
5168 #else
5169 width < disp_height,
5170 #endif
5171 0, 0, 0, kControlScrollBarProc, (long) bar);
5172 #else
5173 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5174 0, 0, 0, scrollBarProc, (long) bar);
5175 #endif
5176 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
5178 XSETWINDOW (bar->window, w);
5179 XSETINT (bar->top, top);
5180 XSETINT (bar->left, left);
5181 XSETINT (bar->width, width);
5182 XSETINT (bar->height, height);
5183 XSETINT (bar->start, 0);
5184 XSETINT (bar->end, 0);
5185 bar->dragging = Qnil;
5186 #ifdef MAC_OSX
5187 bar->fringe_extended_p = Qnil;
5188 #endif
5189 bar->redraw_needed_p = Qnil;
5190 #ifdef USE_TOOLKIT_SCROLL_BARS
5191 bar->track_top = Qnil;
5192 bar->track_height = Qnil;
5193 bar->min_handle = Qnil;
5194 #endif
5196 /* Add bar to its frame's list of scroll bars. */
5197 bar->next = FRAME_SCROLL_BARS (f);
5198 bar->prev = Qnil;
5199 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5200 if (!NILP (bar->next))
5201 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5203 UNBLOCK_INPUT;
5204 return bar;
5208 /* Draw BAR's handle in the proper position.
5210 If the handle is already drawn from START to END, don't bother
5211 redrawing it, unless REBUILD is non-zero; in that case, always
5212 redraw it. (REBUILD is handy for drawing the handle after expose
5213 events.)
5215 Normally, we want to constrain the start and end of the handle to
5216 fit inside its rectangle, but if the user is dragging the scroll
5217 bar handle, we want to let them drag it down all the way, so that
5218 the bar's top is as far down as it goes; otherwise, there's no way
5219 to move to the very end of the buffer. */
5221 #ifndef USE_TOOLKIT_SCROLL_BARS
5223 static void
5224 x_scroll_bar_set_handle (bar, start, end, rebuild)
5225 struct scroll_bar *bar;
5226 int start, end;
5227 int rebuild;
5229 int dragging = ! NILP (bar->dragging);
5230 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5231 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5232 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5233 int length = end - start;
5235 /* If the display is already accurate, do nothing. */
5236 if (! rebuild
5237 && start == XINT (bar->start)
5238 && end == XINT (bar->end))
5239 return;
5241 BLOCK_INPUT;
5243 /* Make sure the values are reasonable, and try to preserve the
5244 distance between start and end. */
5245 if (start < 0)
5246 start = 0;
5247 else if (start > top_range)
5248 start = top_range;
5249 end = start + length;
5251 if (end < start)
5252 end = start;
5253 else if (end > top_range && ! dragging)
5254 end = top_range;
5256 /* Store the adjusted setting in the scroll bar. */
5257 XSETINT (bar->start, start);
5258 XSETINT (bar->end, end);
5260 /* Clip the end position, just for display. */
5261 if (end > top_range)
5262 end = top_range;
5264 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5265 top positions, to make sure the handle is always at least that
5266 many pixels tall. */
5267 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5269 SetControlMinimum (ch, 0);
5270 /* Don't inadvertently activate deactivated scroll bars */
5271 if (GetControlMaximum (ch) != -1)
5272 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5273 - (end - start));
5274 SetControlValue (ch, start);
5275 #if TARGET_API_MAC_CARBON
5276 SetControlViewSize (ch, end - start);
5277 #endif
5279 UNBLOCK_INPUT;
5282 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5284 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5285 nil. */
5287 static void
5288 x_scroll_bar_remove (bar)
5289 struct scroll_bar *bar;
5291 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5293 BLOCK_INPUT;
5295 #if USE_CG_DRAWING
5296 mac_prepare_for_quickdraw (f);
5297 #endif
5298 /* Destroy the Mac scroll bar control */
5299 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
5301 /* Disassociate this scroll bar from its window. */
5302 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5304 UNBLOCK_INPUT;
5308 /* Set the handle of the vertical scroll bar for WINDOW to indicate
5309 that we are displaying PORTION characters out of a total of WHOLE
5310 characters, starting at POSITION. If WINDOW has no scroll bar,
5311 create one. */
5313 static void
5314 XTset_vertical_scroll_bar (w, portion, whole, position)
5315 struct window *w;
5316 int portion, whole, position;
5318 struct frame *f = XFRAME (w->frame);
5319 struct scroll_bar *bar;
5320 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
5321 int window_y, window_height;
5322 #ifdef MAC_OSX
5323 int fringe_extended_p;
5324 #endif
5326 /* Get window dimensions. */
5327 window_box (w, -1, 0, &window_y, 0, &window_height);
5328 top = window_y;
5329 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
5330 height = window_height;
5332 /* Compute the left edge of the scroll bar area. */
5333 left = WINDOW_SCROLL_BAR_AREA_X (w);
5335 /* Compute the width of the scroll bar which might be less than
5336 the width of the area reserved for the scroll bar. */
5337 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5338 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
5339 else
5340 sb_width = width;
5342 /* Compute the left edge of the scroll bar. */
5343 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
5344 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
5345 else
5346 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
5348 /* Adjustments according to Inside Macintosh to make it look nice */
5349 disp_top = top;
5350 disp_height = height;
5351 #ifdef MAC_OS8
5352 if (disp_top == 0)
5354 disp_top = -1;
5355 disp_height++;
5357 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
5359 disp_top++;
5360 disp_height--;
5363 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
5364 sb_left++;
5365 #endif
5367 #ifdef MAC_OSX
5368 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5369 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5370 && WINDOW_LEFT_FRINGE_WIDTH (w)
5371 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5372 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5373 else
5374 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5375 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5376 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5377 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5378 #endif
5380 /* Does the scroll bar exist yet? */
5381 if (NILP (w->vertical_scroll_bar))
5383 BLOCK_INPUT;
5384 #ifdef MAC_OSX
5385 if (fringe_extended_p)
5386 mac_clear_area (f, sb_left, top, sb_width, height);
5387 else
5388 #endif
5389 mac_clear_area (f, left, top, width, height);
5390 UNBLOCK_INPUT;
5391 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5392 disp_height);
5393 XSETVECTOR (w->vertical_scroll_bar, bar);
5395 else
5397 /* It may just need to be moved and resized. */
5398 ControlRef ch;
5400 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5401 ch = SCROLL_BAR_CONTROL_REF (bar);
5403 BLOCK_INPUT;
5405 /* If already correctly positioned, do nothing. */
5406 if (XINT (bar->left) == sb_left
5407 && XINT (bar->top) == top
5408 && XINT (bar->width) == sb_width
5409 && XINT (bar->height) == height
5410 #ifdef MAC_OSX
5411 && !NILP (bar->fringe_extended_p) == fringe_extended_p
5412 #endif
5415 if (!NILP (bar->redraw_needed_p))
5417 #if USE_CG_DRAWING
5418 mac_prepare_for_quickdraw (f);
5419 #endif
5420 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
5423 else
5425 /* Since toolkit scroll bars are smaller than the space reserved
5426 for them on the frame, we have to clear "under" them. */
5427 #ifdef MAC_OSX
5428 if (fringe_extended_p)
5429 mac_clear_area (f, sb_left, top, sb_width, height);
5430 else
5431 #endif
5432 mac_clear_area (f, left, top, width, height);
5434 #if USE_CG_DRAWING
5435 mac_prepare_for_quickdraw (f);
5436 #endif
5437 HideControl (ch);
5438 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5439 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5440 disp_height);
5441 #ifndef USE_TOOLKIT_SCROLL_BARS
5442 if (sb_width < disp_height)
5443 ShowControl (ch);
5444 #endif
5446 /* Remember new settings. */
5447 XSETINT (bar->left, sb_left);
5448 XSETINT (bar->top, top);
5449 XSETINT (bar->width, sb_width);
5450 XSETINT (bar->height, height);
5451 #ifdef USE_TOOLKIT_SCROLL_BARS
5452 bar->track_top = Qnil;
5453 bar->track_height = Qnil;
5454 bar->min_handle = Qnil;
5455 #endif
5458 UNBLOCK_INPUT;
5461 #ifdef MAC_OSX
5462 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5463 #endif
5465 bar->redraw_needed_p = Qnil;
5467 #ifdef USE_TOOLKIT_SCROLL_BARS
5468 if (NILP (bar->track_top))
5470 if (sb_width >= disp_height
5471 #ifdef MAC_OSX
5472 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5473 #endif
5476 XSETINT (bar->track_top, 0);
5477 XSETINT (bar->track_height, 0);
5478 XSETINT (bar->min_handle, 0);
5480 else
5482 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5483 Rect r0, r1;
5485 BLOCK_INPUT;
5487 SetControl32BitMinimum (ch, 0);
5488 SetControl32BitMaximum (ch, 1 << 30);
5489 SetControlViewSize (ch, 1);
5491 /* Move the scroll bar thumb to the top. */
5492 SetControl32BitValue (ch, 0);
5493 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5495 /* Move the scroll bar thumb to the bottom. */
5496 SetControl32BitValue (ch, 1 << 30);
5497 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5499 UnionRect (&r0, &r1, &r0);
5500 XSETINT (bar->track_top, r0.top);
5501 XSETINT (bar->track_height, r0.bottom - r0.top);
5502 XSETINT (bar->min_handle, r1.bottom - r1.top);
5504 /* Don't show the scroll bar if its height is not enough to
5505 display the scroll bar thumb. */
5506 if (r0.bottom - r0.top > 0)
5507 ShowControl (ch);
5509 UNBLOCK_INPUT;
5513 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5514 #else /* not USE_TOOLKIT_SCROLL_BARS */
5515 /* Set the scroll bar's current state, unless we're currently being
5516 dragged. */
5517 if (NILP (bar->dragging))
5519 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5521 if (whole == 0)
5522 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5523 else
5525 int start = ((double) position * top_range) / whole;
5526 int end = ((double) (position + portion) * top_range) / whole;
5527 x_scroll_bar_set_handle (bar, start, end, 0);
5530 #endif /* not USE_TOOLKIT_SCROLL_BARS */
5534 /* The following three hooks are used when we're doing a thorough
5535 redisplay of the frame. We don't explicitly know which scroll bars
5536 are going to be deleted, because keeping track of when windows go
5537 away is a real pain - "Can you say set-window-configuration, boys
5538 and girls?" Instead, we just assert at the beginning of redisplay
5539 that *all* scroll bars are to be removed, and then save a scroll bar
5540 from the fiery pit when we actually redisplay its window. */
5542 /* Arrange for all scroll bars on FRAME to be removed at the next call
5543 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5544 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5546 static void
5547 XTcondemn_scroll_bars (frame)
5548 FRAME_PTR frame;
5550 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5551 while (! NILP (FRAME_SCROLL_BARS (frame)))
5553 Lisp_Object bar;
5554 bar = FRAME_SCROLL_BARS (frame);
5555 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5556 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5557 XSCROLL_BAR (bar)->prev = Qnil;
5558 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5559 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5560 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5565 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5566 Note that WINDOW isn't necessarily condemned at all. */
5568 static void
5569 XTredeem_scroll_bar (window)
5570 struct window *window;
5572 struct scroll_bar *bar;
5573 struct frame *f;
5575 /* We can't redeem this window's scroll bar if it doesn't have one. */
5576 if (NILP (window->vertical_scroll_bar))
5577 abort ();
5579 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5581 /* Unlink it from the condemned list. */
5582 f = XFRAME (WINDOW_FRAME (window));
5583 if (NILP (bar->prev))
5585 /* If the prev pointer is nil, it must be the first in one of
5586 the lists. */
5587 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5588 /* It's not condemned. Everything's fine. */
5589 return;
5590 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5591 window->vertical_scroll_bar))
5592 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5593 else
5594 /* If its prev pointer is nil, it must be at the front of
5595 one or the other! */
5596 abort ();
5598 else
5599 XSCROLL_BAR (bar->prev)->next = bar->next;
5601 if (! NILP (bar->next))
5602 XSCROLL_BAR (bar->next)->prev = bar->prev;
5604 bar->next = FRAME_SCROLL_BARS (f);
5605 bar->prev = Qnil;
5606 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5607 if (! NILP (bar->next))
5608 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5611 /* Remove all scroll bars on FRAME that haven't been saved since the
5612 last call to `*condemn_scroll_bars_hook'. */
5614 static void
5615 XTjudge_scroll_bars (f)
5616 FRAME_PTR f;
5618 Lisp_Object bar, next;
5620 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5622 /* Clear out the condemned list now so we won't try to process any
5623 more events on the hapless scroll bars. */
5624 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5626 for (; ! NILP (bar); bar = next)
5628 struct scroll_bar *b = XSCROLL_BAR (bar);
5630 x_scroll_bar_remove (b);
5632 next = b->next;
5633 b->next = b->prev = Qnil;
5636 /* Now there should be no references to the condemned scroll bars,
5637 and they should get garbage-collected. */
5641 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
5642 is set to something other than NO_EVENT, it is enqueued.
5644 This may be called from a signal handler, so we have to ignore GC
5645 mark bits. */
5647 static void
5648 x_scroll_bar_handle_click (bar, part_code, er, bufp)
5649 struct scroll_bar *bar;
5650 ControlPartCode part_code;
5651 const EventRecord *er;
5652 struct input_event *bufp;
5654 int win_y, top_range;
5656 if (! WINDOWP (bar->window))
5657 abort ();
5659 bufp->kind = SCROLL_BAR_CLICK_EVENT;
5660 bufp->frame_or_window = bar->window;
5661 bufp->arg = Qnil;
5663 bar->dragging = Qnil;
5665 switch (part_code)
5667 case kControlUpButtonPart:
5668 bufp->part = scroll_bar_up_arrow;
5669 break;
5670 case kControlDownButtonPart:
5671 bufp->part = scroll_bar_down_arrow;
5672 break;
5673 case kControlPageUpPart:
5674 bufp->part = scroll_bar_above_handle;
5675 break;
5676 case kControlPageDownPart:
5677 bufp->part = scroll_bar_below_handle;
5678 break;
5679 #if TARGET_API_MAC_CARBON
5680 default:
5681 #else
5682 case kControlIndicatorPart:
5683 #endif
5684 if (er->what == mouseDown)
5685 bar->dragging = make_number (0);
5686 XSETVECTOR (last_mouse_scroll_bar, bar);
5687 bufp->part = scroll_bar_handle;
5688 break;
5691 win_y = XINT (bufp->y) - XINT (bar->top);
5692 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5694 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5696 win_y -= 24;
5698 if (! NILP (bar->dragging))
5699 win_y -= XINT (bar->dragging);
5701 if (win_y < 0)
5702 win_y = 0;
5703 if (win_y > top_range)
5704 win_y = top_range;
5706 XSETINT (bufp->x, win_y);
5707 XSETINT (bufp->y, top_range);
5710 #ifndef USE_TOOLKIT_SCROLL_BARS
5712 /* Handle some mouse motion while someone is dragging the scroll bar.
5714 This may be called from a signal handler, so we have to ignore GC
5715 mark bits. */
5717 static void
5718 x_scroll_bar_note_movement (bar, y_pos, t)
5719 struct scroll_bar *bar;
5720 int y_pos;
5721 Time t;
5723 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5725 last_mouse_movement_time = t;
5727 f->mouse_moved = 1;
5728 XSETVECTOR (last_mouse_scroll_bar, bar);
5730 /* If we're dragging the bar, display it. */
5731 if (! NILP (bar->dragging))
5733 /* Where should the handle be now? */
5734 int new_start = y_pos - 24;
5736 if (new_start != XINT (bar->start))
5738 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5740 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5745 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5747 /* Return information to the user about the current position of the mouse
5748 on the scroll bar. */
5750 static void
5751 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5752 FRAME_PTR *fp;
5753 Lisp_Object *bar_window;
5754 enum scroll_bar_part *part;
5755 Lisp_Object *x, *y;
5756 unsigned long *time;
5758 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
5759 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5760 #if TARGET_API_MAC_CARBON
5761 WindowRef wp = GetControlOwner (ch);
5762 #else
5763 WindowRef wp = (*ch)->contrlOwner;
5764 #endif
5765 Point mouse_pos;
5766 struct frame *f = mac_window_to_frame (wp);
5767 int win_y, top_range;
5769 #if TARGET_API_MAC_CARBON
5770 GetGlobalMouse (&mouse_pos);
5771 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5772 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5773 #else
5774 SetPortWindowPort (wp);
5775 GetMouse (&mouse_pos);
5776 #endif
5778 win_y = mouse_pos.v - XINT (bar->top);
5779 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5781 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5783 win_y -= 24;
5785 if (! NILP (bar->dragging))
5786 win_y -= XINT (bar->dragging);
5788 if (win_y < 0)
5789 win_y = 0;
5790 if (win_y > top_range)
5791 win_y = top_range;
5793 *fp = f;
5794 *bar_window = bar->window;
5796 if (! NILP (bar->dragging))
5797 *part = scroll_bar_handle;
5798 else if (win_y < XINT (bar->start))
5799 *part = scroll_bar_above_handle;
5800 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5801 *part = scroll_bar_handle;
5802 else
5803 *part = scroll_bar_below_handle;
5805 XSETINT (*x, win_y);
5806 XSETINT (*y, top_range);
5808 f->mouse_moved = 0;
5809 last_mouse_scroll_bar = Qnil;
5811 *time = last_mouse_movement_time;
5815 /* The screen has been cleared so we may have changed foreground or
5816 background colors, and the scroll bars may need to be redrawn.
5817 Clear out the scroll bars, and ask for expose events, so we can
5818 redraw them. */
5820 void
5821 x_scroll_bar_clear (f)
5822 FRAME_PTR f;
5824 Lisp_Object bar;
5826 /* We can have scroll bars even if this is 0,
5827 if we just turned off scroll bar mode.
5828 But in that case we should not clear them. */
5829 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5830 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5831 bar = XSCROLL_BAR (bar)->next)
5832 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
5836 /***********************************************************************
5837 Tool-bars
5838 ***********************************************************************/
5839 #if USE_MAC_TOOLBAR
5841 /* In identifiers such as function/variable names, Emacs tool bar is
5842 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5844 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5845 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5847 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5848 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5849 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5850 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5851 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5852 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5853 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5855 static int mac_event_to_emacs_modifiers P_ ((EventRef));
5856 static void mac_handle_origin_change P_ ((struct frame *));
5857 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5858 EventRef, void *));
5860 static void
5861 mac_move_window_with_gravity (f, win_gravity, left, top)
5862 struct frame *f;
5863 int win_gravity;
5864 short left, top;
5866 Rect inner, outer;
5868 mac_get_window_bounds (f, &inner, &outer);
5870 switch (win_gravity)
5872 case NorthWestGravity:
5873 case WestGravity:
5874 case SouthWestGravity:
5875 left += inner.left - outer.left;
5876 break;
5878 case NorthGravity:
5879 case CenterGravity:
5880 case SouthGravity:
5881 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5882 break;
5884 case NorthEastGravity:
5885 case EastGravity:
5886 case SouthEastGravity:
5887 left += inner.right - outer.right;
5888 break;
5891 switch (win_gravity)
5893 case NorthWestGravity:
5894 case NorthGravity:
5895 case NorthEastGravity:
5896 top += inner.top - outer.top;
5897 break;
5899 case WestGravity:
5900 case CenterGravity:
5901 case EastGravity:
5902 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5903 break;
5905 case SouthWestGravity:
5906 case SouthGravity:
5907 case SouthEastGravity:
5908 top += inner.bottom - outer.bottom;
5909 break;
5912 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5915 static void
5916 mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5917 struct frame *f;
5918 int win_gravity;
5919 short *left, *top;
5921 Rect inner, outer;
5923 mac_get_window_bounds (f, &inner, &outer);
5925 switch (win_gravity)
5927 case NorthWestGravity:
5928 case WestGravity:
5929 case SouthWestGravity:
5930 *left = outer.left;
5931 break;
5933 case NorthGravity:
5934 case CenterGravity:
5935 case SouthGravity:
5936 *left = outer.left + ((outer.right - outer.left)
5937 - (inner.right - inner.left)) / 2;
5938 break;
5940 case NorthEastGravity:
5941 case EastGravity:
5942 case SouthEastGravity:
5943 *left = outer.right - (inner.right - inner.left);
5944 break;
5947 switch (win_gravity)
5949 case NorthWestGravity:
5950 case NorthGravity:
5951 case NorthEastGravity:
5952 *top = outer.top;
5953 break;
5955 case WestGravity:
5956 case CenterGravity:
5957 case EastGravity:
5958 *top = outer.top + ((outer.bottom - outer.top)
5959 - (inner.bottom - inner.top)) / 2;
5960 break;
5962 case SouthWestGravity:
5963 case SouthGravity:
5964 case SouthEastGravity:
5965 *top = outer.bottom - (inner.bottom - inner.top);
5966 break;
5970 static OSStatus
5971 mac_handle_toolbar_event (next_handler, event, data)
5972 EventHandlerCallRef next_handler;
5973 EventRef event;
5974 void *data;
5976 OSStatus err, result = eventNotHandledErr;
5978 switch (GetEventKind (event))
5980 case kEventToolbarGetDefaultIdentifiers:
5981 result = noErr;
5982 break;
5984 case kEventToolbarGetAllowedIdentifiers:
5986 CFMutableArrayRef array;
5988 GetEventParameter (event, kEventParamMutableArray,
5989 typeCFMutableArrayRef, NULL,
5990 sizeof (CFMutableArrayRef), NULL, &array);
5991 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5992 result = noErr;
5994 break;
5996 case kEventToolbarCreateItemWithIdentifier:
5998 CFStringRef identifier;
5999 HIToolbarItemRef item = NULL;
6001 GetEventParameter (event, kEventParamToolbarItemIdentifier,
6002 typeCFStringRef, NULL,
6003 sizeof (CFStringRef), NULL, &identifier);
6005 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
6006 == kCFCompareEqualTo)
6007 HIToolbarItemCreate (identifier,
6008 kHIToolbarItemAllowDuplicates
6009 | kHIToolbarItemCantBeRemoved, &item);
6011 if (item)
6013 SetEventParameter (event, kEventParamToolbarItem,
6014 typeHIToolbarItemRef,
6015 sizeof (HIToolbarItemRef), &item);
6016 result = noErr;
6019 break;
6021 default:
6022 abort ();
6025 return result;
6028 static CGImageRef
6029 mac_image_spec_to_cg_image (f, image)
6030 struct frame *f;
6031 Lisp_Object image;
6033 if (!valid_image_p (image))
6034 return NULL;
6035 else
6037 int img_id = lookup_image (f, image);
6038 struct image *img = IMAGE_FROM_ID (f, img_id);
6040 prepare_image_for_display (f, img);
6042 return img->data.ptr_val;
6046 /* Create a tool bar for frame F. */
6048 static OSStatus
6049 mac_create_frame_tool_bar (f)
6050 FRAME_PTR f;
6052 OSStatus err;
6053 HIToolbarRef toolbar;
6055 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
6056 &toolbar);
6057 if (err == noErr)
6059 static const EventTypeSpec specs[] =
6060 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
6061 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
6062 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
6064 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
6065 mac_handle_toolbar_event,
6066 GetEventTypeCount (specs), specs,
6067 f, NULL);
6070 if (err == noErr)
6071 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
6072 if (err == noErr)
6074 static const EventTypeSpec specs[] =
6075 {{kEventClassCommand, kEventCommandProcess}};
6077 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
6078 mac_handle_toolbar_command_event,
6079 GetEventTypeCount (specs),
6080 specs, f, NULL);
6082 if (err == noErr)
6083 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
6085 if (toolbar)
6086 CFRelease (toolbar);
6088 return err;
6091 /* Update the tool bar for frame F. Add new buttons and remove old. */
6093 void
6094 update_frame_tool_bar (f)
6095 FRAME_PTR f;
6097 HIToolbarRef toolbar = NULL;
6098 short left, top;
6099 CFArrayRef old_items = NULL;
6100 CFIndex old_count;
6101 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
6102 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6104 BLOCK_INPUT;
6106 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6107 if (toolbar == NULL)
6109 mac_create_frame_tool_bar (f);
6110 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6111 if (toolbar == NULL)
6112 goto out;
6113 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6114 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6117 HIToolbarCopyItems (toolbar, &old_items);
6118 if (old_items == NULL)
6119 goto out;
6121 old_count = CFArrayGetCount (old_items);
6122 pos = 0;
6123 for (i = 0; i < f->n_tool_bar_items; ++i)
6125 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6127 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6128 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6129 int idx;
6130 Lisp_Object image;
6131 CGImageRef cg_image;
6132 CFStringRef label;
6133 HIToolbarItemRef item;
6135 /* If image is a vector, choose the image according to the
6136 button state. */
6137 image = PROP (TOOL_BAR_ITEM_IMAGES);
6138 if (VECTORP (image))
6140 if (enabled_p)
6141 idx = (selected_p
6142 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6143 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6144 else
6145 idx = (selected_p
6146 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6147 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6149 xassert (ASIZE (image) >= idx);
6150 image = AREF (image, idx);
6152 else
6153 idx = -1;
6155 cg_image = mac_image_spec_to_cg_image (f, image);
6156 /* Ignore invalid image specifications. */
6157 if (cg_image == NULL)
6158 continue;
6160 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6161 if (label == NULL)
6162 label = CFSTR ("");
6164 if (pos < old_count)
6166 CGImageRef old_cg_image = NULL;
6167 CFStringRef old_label = NULL;
6168 Boolean old_enabled_p;
6170 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6172 HIToolbarItemCopyImage (item, &old_cg_image);
6173 if (cg_image != old_cg_image)
6174 HIToolbarItemSetImage (item, cg_image);
6175 CGImageRelease (old_cg_image);
6177 HIToolbarItemCopyLabel (item, &old_label);
6178 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6179 HIToolbarItemSetLabel (item, label);
6180 CFRelease (old_label);
6182 old_enabled_p = HIToolbarItemIsEnabled (item);
6183 if ((enabled_p || idx >= 0) != old_enabled_p)
6184 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6186 else
6188 item = NULL;
6189 HIToolbarCreateItemWithIdentifier (toolbar,
6190 TOOLBAR_ICON_ITEM_IDENTIFIER,
6191 NULL, &item);
6192 if (item)
6194 HIToolbarItemSetImage (item, cg_image);
6195 HIToolbarItemSetLabel (item, label);
6196 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6197 HIToolbarAppendItem (toolbar, item);
6198 CFRelease (item);
6202 CFRelease (label);
6203 if (item)
6205 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6206 pos++;
6210 CFRelease (old_items);
6212 while (pos < old_count)
6213 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6215 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6216 !win_gravity && f == mac_focus_frame (dpyinfo));
6217 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6218 toolbar visibility change. */
6219 mac_handle_origin_change (f);
6220 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6222 mac_move_window_with_gravity (f, win_gravity, left, top);
6223 /* If the title bar is completely outside the screen, adjust the
6224 position. */
6225 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6226 kWindowConstrainMoveRegardlessOfFit
6227 | kWindowConstrainAllowPartial, NULL, NULL);
6228 f->output_data.mac->toolbar_win_gravity = 0;
6231 out:
6232 UNBLOCK_INPUT;
6235 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6236 doesn't deallocate the resources. */
6238 void
6239 free_frame_tool_bar (f)
6240 FRAME_PTR f;
6242 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6244 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6246 BLOCK_INPUT;
6247 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
6248 (NILP (Fsymbol_value
6249 (intern ("frame-notice-user-settings")))
6250 && f == mac_focus_frame (dpyinfo)));
6251 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6252 on toolbar visibility change. */
6253 mac_handle_origin_change (f);
6254 UNBLOCK_INPUT;
6258 static void
6259 mac_tool_bar_note_mouse_movement (f, event)
6260 struct frame *f;
6261 EventRef event;
6263 OSStatus err;
6264 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6265 int mouse_down_p;
6266 HIViewRef item_view;
6267 UInt32 command_id;
6269 mouse_down_p = (dpyinfo->grabbed
6270 && f == last_mouse_frame
6271 && FRAME_LIVE_P (f));
6272 if (mouse_down_p)
6273 return;
6275 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6276 event, &item_view);
6277 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6278 toolbar item view seems to have the same command ID with that of
6279 the toolbar item. */
6280 if (err == noErr)
6281 err = GetControlCommandID (item_view, &command_id);
6282 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6284 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6286 if (i < f->n_tool_bar_items)
6288 HIRect bounds;
6289 HIViewRef content_view;
6291 err = HIViewGetBounds (item_view, &bounds);
6292 if (err == noErr)
6293 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6294 kHIViewWindowContentID, &content_view);
6295 if (err == noErr)
6296 err = HIViewConvertRect (&bounds, item_view, content_view);
6297 if (err == noErr)
6298 SetRect (&last_mouse_glyph,
6299 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6300 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6302 help_echo_object = help_echo_window = Qnil;
6303 help_echo_pos = -1;
6304 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6305 if (NILP (help_echo_string))
6306 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6311 static OSStatus
6312 mac_handle_toolbar_command_event (next_handler, event, data)
6313 EventHandlerCallRef next_handler;
6314 EventRef event;
6315 void *data;
6317 OSStatus err, result = eventNotHandledErr;
6318 struct frame *f = (struct frame *) data;
6319 HICommand command;
6321 err = GetEventParameter (event, kEventParamDirectObject,
6322 typeHICommand, NULL,
6323 sizeof (HICommand), NULL, &command);
6324 if (err != noErr)
6325 return result;
6327 switch (GetEventKind (event))
6329 case kEventCommandProcess:
6330 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6331 result = CallNextEventHandler (next_handler, event);
6332 else
6334 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6336 if (i < f->n_tool_bar_items
6337 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6339 Lisp_Object frame;
6340 struct input_event buf;
6342 EVENT_INIT (buf);
6344 XSETFRAME (frame, f);
6345 buf.kind = TOOL_BAR_EVENT;
6346 buf.frame_or_window = frame;
6347 buf.arg = frame;
6348 kbd_buffer_store_event (&buf);
6350 buf.kind = TOOL_BAR_EVENT;
6351 buf.frame_or_window = frame;
6352 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6353 buf.modifiers = mac_event_to_emacs_modifiers (event);
6354 kbd_buffer_store_event (&buf);
6356 result = noErr;
6359 break;
6361 default:
6362 abort ();
6364 #undef PROP
6366 return result;
6368 #endif /* USE_MAC_TOOLBAR */
6371 /***********************************************************************
6372 Text Cursor
6373 ***********************************************************************/
6375 /* Set clipping for output in glyph row ROW. W is the window in which
6376 we operate. GC is the graphics context to set clipping in.
6378 ROW may be a text row or, e.g., a mode line. Text rows must be
6379 clipped to the interior of the window dedicated to text display,
6380 mode lines must be clipped to the whole window. */
6382 static void
6383 x_clip_to_row (w, row, area, gc)
6384 struct window *w;
6385 struct glyph_row *row;
6386 int area;
6387 GC gc;
6389 struct frame *f = XFRAME (WINDOW_FRAME (w));
6390 Rect clip_rect;
6391 int window_x, window_y, window_width;
6393 window_box (w, area, &window_x, &window_y, &window_width, 0);
6395 clip_rect.left = window_x;
6396 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6397 clip_rect.top = max (clip_rect.top, window_y);
6398 clip_rect.right = clip_rect.left + window_width;
6399 clip_rect.bottom = clip_rect.top + row->visible_height;
6401 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
6405 /* Draw a hollow box cursor on window W in glyph row ROW. */
6407 static void
6408 x_draw_hollow_cursor (w, row)
6409 struct window *w;
6410 struct glyph_row *row;
6412 struct frame *f = XFRAME (WINDOW_FRAME (w));
6413 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6414 Display *dpy = FRAME_MAC_DISPLAY (f);
6415 int x, y, wd, h;
6416 XGCValues xgcv;
6417 struct glyph *cursor_glyph;
6418 GC gc;
6420 /* Get the glyph the cursor is on. If we can't tell because
6421 the current matrix is invalid or such, give up. */
6422 cursor_glyph = get_phys_cursor_glyph (w);
6423 if (cursor_glyph == NULL)
6424 return;
6426 /* Compute frame-relative coordinates for phys cursor. */
6427 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
6428 wd = w->phys_cursor_width;
6430 /* The foreground of cursor_gc is typically the same as the normal
6431 background color, which can cause the cursor box to be invisible. */
6432 xgcv.foreground = f->output_data.mac->cursor_pixel;
6433 if (dpyinfo->scratch_cursor_gc)
6434 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6435 else
6436 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6437 GCForeground, &xgcv);
6438 gc = dpyinfo->scratch_cursor_gc;
6440 /* Set clipping, draw the rectangle, and reset clipping again. */
6441 x_clip_to_row (w, row, TEXT_AREA, gc);
6442 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
6443 mac_reset_clip_rectangles (dpy, gc);
6447 /* Draw a bar cursor on window W in glyph row ROW.
6449 Implementation note: One would like to draw a bar cursor with an
6450 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6451 Unfortunately, I didn't find a font yet that has this property set.
6452 --gerd. */
6454 static void
6455 x_draw_bar_cursor (w, row, width, kind)
6456 struct window *w;
6457 struct glyph_row *row;
6458 int width;
6459 enum text_cursor_kinds kind;
6461 struct frame *f = XFRAME (w->frame);
6462 struct glyph *cursor_glyph;
6464 /* If cursor is out of bounds, don't draw garbage. This can happen
6465 in mini-buffer windows when switching between echo area glyphs
6466 and mini-buffer. */
6467 cursor_glyph = get_phys_cursor_glyph (w);
6468 if (cursor_glyph == NULL)
6469 return;
6471 /* If on an image, draw like a normal cursor. That's usually better
6472 visible than drawing a bar, esp. if the image is large so that
6473 the bar might not be in the window. */
6474 if (cursor_glyph->type == IMAGE_GLYPH)
6476 struct glyph_row *row;
6477 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6478 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6480 else
6482 Display *dpy = FRAME_MAC_DISPLAY (f);
6483 Window window = FRAME_MAC_WINDOW (f);
6484 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6485 unsigned long mask = GCForeground | GCBackground;
6486 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
6487 XGCValues xgcv;
6489 /* If the glyph's background equals the color we normally draw
6490 the bar cursor in, the bar cursor in its normal color is
6491 invisible. Use the glyph's foreground color instead in this
6492 case, on the assumption that the glyph's colors are chosen so
6493 that the glyph is legible. */
6494 if (face->background == f->output_data.mac->cursor_pixel)
6495 xgcv.background = xgcv.foreground = face->foreground;
6496 else
6497 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
6499 if (gc)
6500 XChangeGC (dpy, gc, mask, &xgcv);
6501 else
6503 gc = XCreateGC (dpy, window, mask, &xgcv);
6504 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6507 if (width < 0)
6508 width = FRAME_CURSOR_WIDTH (f);
6509 width = min (cursor_glyph->pixel_width, width);
6511 w->phys_cursor_width = width;
6512 x_clip_to_row (w, row, TEXT_AREA, gc);
6514 if (kind == BAR_CURSOR)
6515 mac_fill_rectangle (f, gc,
6516 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6517 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6518 width, row->height);
6519 else
6520 mac_fill_rectangle (f, gc,
6521 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6522 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6523 row->height - width),
6524 cursor_glyph->pixel_width,
6525 width);
6527 mac_reset_clip_rectangles (f, gc);
6532 /* RIF: Define cursor CURSOR on frame F. */
6534 static void
6535 mac_define_frame_cursor (f, cursor)
6536 struct frame *f;
6537 Cursor cursor;
6539 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6541 if (dpyinfo->x_focus_frame == f)
6542 SetThemeCursor (cursor);
6546 /* RIF: Clear area on frame F. */
6548 static void
6549 mac_clear_frame_area (f, x, y, width, height)
6550 struct frame *f;
6551 int x, y, width, height;
6553 mac_clear_area (f, x, y, width, height);
6557 /* RIF: Draw cursor on window W. */
6559 static void
6560 mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
6561 struct window *w;
6562 struct glyph_row *glyph_row;
6563 int x, y;
6564 int cursor_type, cursor_width;
6565 int on_p, active_p;
6567 if (on_p)
6569 w->phys_cursor_type = cursor_type;
6570 w->phys_cursor_on_p = 1;
6572 if (glyph_row->exact_window_width_line_p
6573 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6575 glyph_row->cursor_in_fringe_p = 1;
6576 draw_fringe_bitmap (w, glyph_row, 0);
6578 else
6579 switch (cursor_type)
6581 case HOLLOW_BOX_CURSOR:
6582 x_draw_hollow_cursor (w, glyph_row);
6583 break;
6585 case FILLED_BOX_CURSOR:
6586 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
6587 break;
6589 case BAR_CURSOR:
6590 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6591 break;
6593 case HBAR_CURSOR:
6594 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
6595 break;
6597 case NO_CURSOR:
6598 w->phys_cursor_width = 0;
6599 break;
6601 default:
6602 abort ();
6608 /* Icons. */
6610 #if 0 /* MAC_TODO: no icon support yet. */
6612 x_bitmap_icon (f, icon)
6613 struct frame *f;
6614 Lisp_Object icon;
6616 HANDLE hicon;
6618 if (FRAME_W32_WINDOW (f) == 0)
6619 return 1;
6621 if (NILP (icon))
6622 hicon = LoadIcon (hinst, EMACS_CLASS);
6623 else if (STRINGP (icon))
6624 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
6625 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6626 else if (SYMBOLP (icon))
6628 LPCTSTR name;
6630 if (EQ (icon, intern ("application")))
6631 name = (LPCTSTR) IDI_APPLICATION;
6632 else if (EQ (icon, intern ("hand")))
6633 name = (LPCTSTR) IDI_HAND;
6634 else if (EQ (icon, intern ("question")))
6635 name = (LPCTSTR) IDI_QUESTION;
6636 else if (EQ (icon, intern ("exclamation")))
6637 name = (LPCTSTR) IDI_EXCLAMATION;
6638 else if (EQ (icon, intern ("asterisk")))
6639 name = (LPCTSTR) IDI_ASTERISK;
6640 else if (EQ (icon, intern ("winlogo")))
6641 name = (LPCTSTR) IDI_WINLOGO;
6642 else
6643 return 1;
6645 hicon = LoadIcon (NULL, name);
6647 else
6648 return 1;
6650 if (hicon == NULL)
6651 return 1;
6653 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6654 (LPARAM) hicon);
6656 return 0;
6658 #endif /* MAC_TODO */
6660 /************************************************************************
6661 Handling X errors
6662 ************************************************************************/
6664 /* Display Error Handling functions not used on W32. Listing them here
6665 helps diff stay in step when comparing w32term.c with xterm.c.
6667 x_error_catcher (display, error)
6668 x_catch_errors (dpy)
6669 x_catch_errors_unwind (old_val)
6670 x_check_errors (dpy, format)
6671 x_had_errors_p (dpy)
6672 x_clear_errors (dpy)
6673 x_uncatch_errors (dpy, count)
6674 x_trace_wire ()
6675 x_connection_signal (signalnum)
6676 x_connection_closed (dpy, error_message)
6677 x_error_quitter (display, error)
6678 x_error_handler (display, error)
6679 x_io_error_quitter (display)
6684 /* Changing the font of the frame. */
6686 /* Give frame F the font named FONTNAME as its default font, and
6687 return the full name of that font. FONTNAME may be a wildcard
6688 pattern; in that case, we choose some font that fits the pattern.
6689 The return value shows which font we chose. */
6691 Lisp_Object
6692 x_new_font (f, fontname)
6693 struct frame *f;
6694 register char *fontname;
6696 struct font_info *fontp
6697 = FS_LOAD_FONT (f, fontname);
6699 if (!fontp)
6700 return Qnil;
6702 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
6703 /* This font is already set in frame F. There's nothing more to
6704 do. */
6705 return build_string (fontp->full_name);
6707 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6708 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6709 FRAME_FONTSET (f) = -1;
6711 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6712 FRAME_SPACE_WIDTH (f) = fontp->space_width;
6713 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6715 compute_fringe_widths (f, 1);
6717 /* Compute the scroll bar width in character columns. */
6718 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6720 int wid = FRAME_COLUMN_WIDTH (f);
6721 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6722 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
6724 else
6726 int wid = FRAME_COLUMN_WIDTH (f);
6727 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6730 /* Now make the frame display the given font. */
6731 if (FRAME_MAC_WINDOW (f) != 0)
6733 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
6734 FRAME_FONT (f));
6735 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
6736 FRAME_FONT (f));
6737 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
6738 FRAME_FONT (f));
6740 /* Don't change the size of a tip frame; there's no point in
6741 doing it because it's done in Fx_show_tip, and it leads to
6742 problems because the tip frame has no widget. */
6743 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
6744 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6747 return build_string (fontp->full_name);
6750 /* Give frame F the fontset named FONTSETNAME as its default fontset,
6751 and return the full name of that fontset. FONTSETNAME may be a
6752 wildcard pattern; in that case, we choose some fontset that fits
6753 the pattern. FONTSETNAME may be a font name for ASCII characters;
6754 in that case, we create a fontset from that font name.
6756 The return value shows which fontset we chose.
6757 If FONTSETNAME specifies the default fontset, return Qt.
6758 If an ASCII font in the specified fontset can't be loaded, return
6759 Qnil. */
6761 Lisp_Object
6762 x_new_fontset (f, fontsetname)
6763 struct frame *f;
6764 Lisp_Object fontsetname;
6766 int fontset = fs_query_fontset (fontsetname, 0);
6767 Lisp_Object result;
6769 if (fontset > 0 && FRAME_FONTSET(f) == fontset)
6770 /* This fontset is already set in frame F. There's nothing more
6771 to do. */
6772 return fontset_name (fontset);
6773 else if (fontset == 0)
6774 /* The default fontset can't be the default font. */
6775 return Qt;
6777 if (fontset > 0)
6778 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6779 else
6780 result = x_new_font (f, SDATA (fontsetname));
6782 if (!STRINGP (result))
6783 /* Can't load ASCII font. */
6784 return Qnil;
6786 if (fontset < 0)
6787 fontset = new_fontset_from_font_name (result);
6789 /* Since x_new_font doesn't update any fontset information, do it now. */
6790 FRAME_FONTSET (f) = fontset;
6792 return fontset_name (fontset);
6796 /***********************************************************************
6797 TODO: W32 Input Methods
6798 ***********************************************************************/
6799 /* Listing missing functions from xterm.c helps diff stay in step.
6801 xim_destroy_callback (xim, client_data, call_data)
6802 xim_open_dpy (dpyinfo, resource_name)
6803 struct xim_inst_t
6804 xim_instantiate_callback (display, client_data, call_data)
6805 xim_initialize (dpyinfo, resource_name)
6806 xim_close_dpy (dpyinfo)
6811 void
6812 mac_get_window_bounds (f, inner, outer)
6813 struct frame *f;
6814 Rect *inner, *outer;
6816 #if TARGET_API_MAC_CARBON
6817 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6818 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6819 #else /* not TARGET_API_MAC_CARBON */
6820 RgnHandle region = NewRgn ();
6822 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6823 *inner = (*region)->rgnBBox;
6824 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6825 *outer = (*region)->rgnBBox;
6826 DisposeRgn (region);
6827 #endif /* not TARGET_API_MAC_CARBON */
6830 static void
6831 mac_handle_origin_change (f)
6832 struct frame *f;
6834 x_real_positions (f, &f->left_pos, &f->top_pos);
6837 static void
6838 mac_handle_size_change (f, pixelwidth, pixelheight)
6839 struct frame *f;
6840 int pixelwidth, pixelheight;
6842 int cols, rows;
6844 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6845 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6847 if (cols != FRAME_COLS (f)
6848 || rows != FRAME_LINES (f)
6849 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6850 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6852 /* We pass 1 for DELAY since we can't run Lisp code inside of
6853 a BLOCK_INPUT. */
6854 change_frame_size (f, rows, cols, 0, 1, 0);
6855 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6856 FRAME_PIXEL_HEIGHT (f) = pixelheight;
6858 /* If cursor was outside the new size, mark it as off. */
6859 mark_window_cursors_off (XWINDOW (f->root_window));
6861 /* Clear out any recollection of where the mouse highlighting
6862 was, since it might be in a place that's outside the new
6863 frame size. Actually checking whether it is outside is a
6864 pain in the neck, so don't try--just let the highlighting be
6865 done afresh with new size. */
6866 cancel_mouse_face (f);
6868 #if TARGET_API_MAC_CARBON
6869 if (f->output_data.mac->hourglass_control)
6871 #if USE_CG_DRAWING
6872 mac_prepare_for_quickdraw (f);
6873 #endif
6874 MoveControl (f->output_data.mac->hourglass_control,
6875 pixelwidth - HOURGLASS_WIDTH, 0);
6877 #endif
6882 /* Calculate the absolute position in frame F
6883 from its current recorded position values and gravity. */
6885 void
6886 x_calc_absolute_position (f)
6887 struct frame *f;
6889 int flags = f->size_hint_flags;
6890 Rect inner, outer;
6892 /* We have nothing to do if the current position
6893 is already for the top-left corner. */
6894 if (! ((flags & XNegative) || (flags & YNegative)))
6895 return;
6897 /* Find the offsets of the outside upper-left corner of
6898 the inner window, with respect to the outer window. */
6899 BLOCK_INPUT;
6900 mac_get_window_bounds (f, &inner, &outer);
6901 UNBLOCK_INPUT;
6903 /* Treat negative positions as relative to the leftmost bottommost
6904 position that fits on the screen. */
6905 if (flags & XNegative)
6906 f->left_pos += (FRAME_MAC_DISPLAY_INFO (f)->width
6907 - (outer.right - outer.left));
6909 if (flags & YNegative)
6910 f->top_pos += (FRAME_MAC_DISPLAY_INFO (f)->height
6911 - (outer.bottom - outer.top));
6913 /* The left_pos and top_pos
6914 are now relative to the top and left screen edges,
6915 so the flags should correspond. */
6916 f->size_hint_flags &= ~ (XNegative | YNegative);
6919 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6920 to really change the position, and 0 when calling from
6921 x_make_frame_visible (in that case, XOFF and YOFF are the current
6922 position values). It is -1 when calling from x_set_frame_parameters,
6923 which means, do adjust for borders but don't change the gravity. */
6925 void
6926 x_set_offset (f, xoff, yoff, change_gravity)
6927 struct frame *f;
6928 register int xoff, yoff;
6929 int change_gravity;
6931 if (change_gravity > 0)
6933 f->top_pos = yoff;
6934 f->left_pos = xoff;
6935 f->size_hint_flags &= ~ (XNegative | YNegative);
6936 if (xoff < 0)
6937 f->size_hint_flags |= XNegative;
6938 if (yoff < 0)
6939 f->size_hint_flags |= YNegative;
6940 f->win_gravity = NorthWestGravity;
6942 x_calc_absolute_position (f);
6944 BLOCK_INPUT;
6945 x_wm_set_size_hint (f, (long) 0, 0);
6947 #if TARGET_API_MAC_CARBON
6948 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6949 /* If the title bar is completely outside the screen, adjust the
6950 position. */
6951 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6952 kWindowConstrainMoveRegardlessOfFit
6953 | kWindowConstrainAllowPartial, NULL, NULL);
6954 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
6955 mac_handle_origin_change (f);
6956 #else
6958 Rect inner, outer, screen_rect, dummy;
6959 RgnHandle region = NewRgn ();
6961 mac_get_window_bounds (f, &inner, &outer);
6962 f->x_pixels_diff = inner.left - outer.left;
6963 f->y_pixels_diff = inner.top - outer.top;
6964 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6965 f->top_pos + f->y_pixels_diff, false);
6967 /* If the title bar is completely outside the screen, adjust the
6968 position. The variable `outer' holds the title bar rectangle.
6969 The variable `inner' holds slightly smaller one than `outer',
6970 so that the calculation of overlapping may not become too
6971 strict. */
6972 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6973 outer = (*region)->rgnBBox;
6974 DisposeRgn (region);
6975 inner = outer;
6976 InsetRect (&inner, 8, 8);
6977 screen_rect = qd.screenBits.bounds;
6978 screen_rect.top += GetMBarHeight ();
6980 if (!SectRect (&inner, &screen_rect, &dummy))
6982 if (inner.right <= screen_rect.left)
6983 f->left_pos = screen_rect.left;
6984 else if (inner.left >= screen_rect.right)
6985 f->left_pos = screen_rect.right - (outer.right - outer.left);
6987 if (inner.bottom <= screen_rect.top)
6988 f->top_pos = screen_rect.top;
6989 else if (inner.top >= screen_rect.bottom)
6990 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6992 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6993 f->top_pos + f->y_pixels_diff, false);
6996 #endif
6998 UNBLOCK_INPUT;
7001 /* Call this to change the size of frame F's x-window.
7002 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
7003 for this size change and subsequent size changes.
7004 Otherwise we leave the window gravity unchanged. */
7006 void
7007 x_set_window_size (f, change_gravity, cols, rows)
7008 struct frame *f;
7009 int change_gravity;
7010 int cols, rows;
7012 int pixelwidth, pixelheight;
7014 BLOCK_INPUT;
7016 check_frame_size (f, &rows, &cols);
7017 f->scroll_bar_actual_width
7018 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
7020 compute_fringe_widths (f, 0);
7022 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
7023 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
7025 f->win_gravity = NorthWestGravity;
7026 x_wm_set_size_hint (f, (long) 0, 0);
7028 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
7030 #if TARGET_API_MAC_CARBON
7031 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
7032 #endif
7033 mac_handle_size_change (f, pixelwidth, pixelheight);
7035 if (f->output_data.mac->internal_border_width
7036 != FRAME_INTERNAL_BORDER_WIDTH (f))
7038 mac_clear_window (f);
7039 f->output_data.mac->internal_border_width
7040 = FRAME_INTERNAL_BORDER_WIDTH (f);
7043 SET_FRAME_GARBAGED (f);
7045 UNBLOCK_INPUT;
7048 /* Mouse warping. */
7050 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
7052 void
7053 x_set_mouse_position (f, x, y)
7054 struct frame *f;
7055 int x, y;
7057 int pix_x, pix_y;
7059 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
7060 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
7062 if (pix_x < 0) pix_x = 0;
7063 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
7065 if (pix_y < 0) pix_y = 0;
7066 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
7068 x_set_mouse_pixel_position (f, pix_x, pix_y);
7071 void
7072 x_set_mouse_pixel_position (f, pix_x, pix_y)
7073 struct frame *f;
7074 int pix_x, pix_y;
7076 #ifdef MAC_OSX
7077 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
7078 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
7080 BLOCK_INPUT;
7081 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
7082 UNBLOCK_INPUT;
7083 #else
7084 #if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
7085 BLOCK_INPUT;
7087 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
7088 0, 0, 0, 0, pix_x, pix_y);
7089 UNBLOCK_INPUT;
7090 #endif
7091 #endif
7094 /* focus shifting, raising and lowering. */
7096 void
7097 x_focus_on_frame (f)
7098 struct frame *f;
7100 #if 0 /* This proves to be unpleasant. */
7101 x_raise_frame (f);
7102 #endif
7103 #if 0
7104 /* I don't think that the ICCCM allows programs to do things like this
7105 without the interaction of the window manager. Whatever you end up
7106 doing with this code, do it to x_unfocus_frame too. */
7107 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7108 RevertToPointerRoot, CurrentTime);
7109 #endif /* ! 0 */
7112 void
7113 x_unfocus_frame (f)
7114 struct frame *f;
7118 /* Raise frame F. */
7120 void
7121 x_raise_frame (f)
7122 struct frame *f;
7124 if (f->async_visible)
7126 BLOCK_INPUT;
7127 BringToFront (FRAME_MAC_WINDOW (f));
7128 UNBLOCK_INPUT;
7132 /* Lower frame F. */
7134 void
7135 x_lower_frame (f)
7136 struct frame *f;
7138 if (f->async_visible)
7140 BLOCK_INPUT;
7141 SendBehind (FRAME_MAC_WINDOW (f), NULL);
7142 UNBLOCK_INPUT;
7146 static void
7147 XTframe_raise_lower (f, raise_flag)
7148 FRAME_PTR f;
7149 int raise_flag;
7151 if (raise_flag)
7152 x_raise_frame (f);
7153 else
7154 x_lower_frame (f);
7157 /* Change of visibility. */
7159 static void
7160 mac_handle_visibility_change (f)
7161 struct frame *f;
7163 WindowRef wp = FRAME_MAC_WINDOW (f);
7164 int visible = 0, iconified = 0;
7165 struct input_event buf;
7167 if (IsWindowVisible (wp))
7169 if (IsWindowCollapsed (wp))
7170 iconified = 1;
7171 else
7172 visible = 1;
7175 if (!f->async_visible && visible)
7177 if (f->iconified)
7179 /* wait_reading_process_output will notice this and update
7180 the frame's display structures. If we were made
7181 invisible, we should not set garbaged, because that stops
7182 redrawing on Update events. */
7183 SET_FRAME_GARBAGED (f);
7185 EVENT_INIT (buf);
7186 buf.kind = DEICONIFY_EVENT;
7187 XSETFRAME (buf.frame_or_window, f);
7188 buf.arg = Qnil;
7189 kbd_buffer_store_event (&buf);
7191 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7192 /* Force a redisplay sooner or later to update the
7193 frame titles in case this is the second frame. */
7194 record_asynch_buffer_change ();
7196 else if (f->async_visible && !visible)
7197 if (iconified)
7199 EVENT_INIT (buf);
7200 buf.kind = ICONIFY_EVENT;
7201 XSETFRAME (buf.frame_or_window, f);
7202 buf.arg = Qnil;
7203 kbd_buffer_store_event (&buf);
7206 f->async_visible = visible;
7207 f->async_iconified = iconified;
7210 /* This tries to wait until the frame is really visible.
7211 However, if the window manager asks the user where to position
7212 the frame, this will return before the user finishes doing that.
7213 The frame will not actually be visible at that time,
7214 but it will become visible later when the window manager
7215 finishes with it. */
7217 void
7218 x_make_frame_visible (f)
7219 struct frame *f;
7221 BLOCK_INPUT;
7223 if (! FRAME_VISIBLE_P (f))
7225 /* We test FRAME_GARBAGED_P here to make sure we don't
7226 call x_set_offset a second time
7227 if we get to x_make_frame_visible a second time
7228 before the window gets really visible. */
7229 if (! FRAME_ICONIFIED_P (f)
7230 && ! f->output_data.mac->asked_for_visible)
7231 x_set_offset (f, f->left_pos, f->top_pos, 0);
7233 f->output_data.mac->asked_for_visible = 1;
7235 CollapseWindow (FRAME_MAC_WINDOW (f), false);
7236 ShowWindow (FRAME_MAC_WINDOW (f));
7239 XFlush (FRAME_MAC_DISPLAY (f));
7241 /* Synchronize to ensure Emacs knows the frame is visible
7242 before we do anything else. We do this loop with input not blocked
7243 so that incoming events are handled. */
7245 Lisp_Object frame;
7246 int count;
7248 /* This must come after we set COUNT. */
7249 UNBLOCK_INPUT;
7251 XSETFRAME (frame, f);
7253 /* Wait until the frame is visible. Process X events until a
7254 MapNotify event has been seen, or until we think we won't get a
7255 MapNotify at all.. */
7256 for (count = input_signal_count + 10;
7257 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7259 /* Force processing of queued events. */
7260 x_sync (f);
7262 /* Machines that do polling rather than SIGIO have been
7263 observed to go into a busy-wait here. So we'll fake an
7264 alarm signal to let the handler know that there's something
7265 to be read. We used to raise a real alarm, but it seems
7266 that the handler isn't always enabled here. This is
7267 probably a bug. */
7268 if (input_polling_used ())
7270 /* It could be confusing if a real alarm arrives while
7271 processing the fake one. Turn it off and let the
7272 handler reset it. */
7273 extern void poll_for_input_1 P_ ((void));
7274 int old_poll_suppress_count = poll_suppress_count;
7275 poll_suppress_count = 1;
7276 poll_for_input_1 ();
7277 poll_suppress_count = old_poll_suppress_count;
7280 /* See if a MapNotify event has been processed. */
7281 FRAME_SAMPLE_VISIBILITY (f);
7286 /* Change from mapped state to withdrawn state. */
7288 /* Make the frame visible (mapped and not iconified). */
7290 void
7291 x_make_frame_invisible (f)
7292 struct frame *f;
7294 /* A deactivate event does not occur when the last visible frame is
7295 made invisible. So if we clear the highlight here, it will not
7296 be rehighlighted when it is made visible. */
7297 #if 0
7298 /* Don't keep the highlight on an invisible frame. */
7299 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7300 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7301 #endif
7303 BLOCK_INPUT;
7305 #if !TARGET_API_MAC_CARBON
7306 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7307 that the current position of the window is user-specified, rather than
7308 program-specified, so that when the window is mapped again, it will be
7309 placed at the same location, without forcing the user to position it
7310 by hand again (they have already done that once for this window.) */
7311 x_wm_set_size_hint (f, (long) 0, 1);
7312 #endif
7314 HideWindow (FRAME_MAC_WINDOW (f));
7316 UNBLOCK_INPUT;
7318 #if !TARGET_API_MAC_CARBON
7319 mac_handle_visibility_change (f);
7320 #endif
7323 /* Change window state from mapped to iconified. */
7325 void
7326 x_iconify_frame (f)
7327 struct frame *f;
7329 OSStatus err;
7331 /* A deactivate event does not occur when the last visible frame is
7332 iconified. So if we clear the highlight here, it will not be
7333 rehighlighted when it is deiconified. */
7334 #if 0
7335 /* Don't keep the highlight on an invisible frame. */
7336 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7337 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7338 #endif
7340 if (f->async_iconified)
7341 return;
7343 BLOCK_INPUT;
7345 FRAME_SAMPLE_VISIBILITY (f);
7347 if (! FRAME_VISIBLE_P (f))
7348 ShowWindow (FRAME_MAC_WINDOW (f));
7350 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
7352 UNBLOCK_INPUT;
7354 if (err != noErr)
7355 error ("Can't notify window manager of iconification");
7357 #if !TARGET_API_MAC_CARBON
7358 mac_handle_visibility_change (f);
7359 #endif
7363 /* Free X resources of frame F. */
7365 void
7366 x_free_frame_resources (f)
7367 struct frame *f;
7369 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7370 WindowRef wp = FRAME_MAC_WINDOW (f);
7372 BLOCK_INPUT;
7374 if (wp != tip_window)
7375 remove_window_handler (wp);
7377 #if USE_CG_DRAWING
7378 mac_prepare_for_quickdraw (f);
7379 #endif
7380 DisposeWindow (wp);
7381 if (wp == tip_window)
7382 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7383 closed' event. So we reset tip_window here. */
7384 tip_window = NULL;
7386 free_frame_menubar (f);
7388 if (FRAME_FACE_CACHE (f))
7389 free_frame_faces (f);
7391 x_free_gcs (f);
7393 if (FRAME_SIZE_HINTS (f))
7394 xfree (FRAME_SIZE_HINTS (f));
7396 xfree (f->output_data.mac);
7397 f->output_data.mac = NULL;
7399 if (f == dpyinfo->x_focus_frame)
7401 dpyinfo->x_focus_frame = 0;
7402 #if USE_MAC_FONT_PANEL
7403 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7404 #endif
7406 if (f == dpyinfo->x_focus_event_frame)
7407 dpyinfo->x_focus_event_frame = 0;
7408 if (f == dpyinfo->x_highlight_frame)
7409 dpyinfo->x_highlight_frame = 0;
7411 if (f == dpyinfo->mouse_face_mouse_frame)
7413 dpyinfo->mouse_face_beg_row
7414 = dpyinfo->mouse_face_beg_col = -1;
7415 dpyinfo->mouse_face_end_row
7416 = dpyinfo->mouse_face_end_col = -1;
7417 dpyinfo->mouse_face_window = Qnil;
7418 dpyinfo->mouse_face_deferred_gc = 0;
7419 dpyinfo->mouse_face_mouse_frame = 0;
7422 UNBLOCK_INPUT;
7426 /* Destroy the X window of frame F. */
7428 void
7429 x_destroy_window (f)
7430 struct frame *f;
7432 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7434 x_free_frame_resources (f);
7436 dpyinfo->reference_count--;
7440 /* Setting window manager hints. */
7442 /* Set the normal size hints for the window manager, for frame F.
7443 FLAGS is the flags word to use--or 0 meaning preserve the flags
7444 that the window now has.
7445 If USER_POSITION is nonzero, we set the USPosition
7446 flag (this is useful when FLAGS is 0). */
7447 void
7448 x_wm_set_size_hint (f, flags, user_position)
7449 struct frame *f;
7450 long flags;
7451 int user_position;
7453 int base_width, base_height, width_inc, height_inc;
7454 int min_rows = 0, min_cols = 0;
7455 XSizeHints *size_hints;
7457 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7458 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7459 width_inc = FRAME_COLUMN_WIDTH (f);
7460 height_inc = FRAME_LINE_HEIGHT (f);
7462 check_frame_size (f, &min_rows, &min_cols);
7464 size_hints = FRAME_SIZE_HINTS (f);
7465 if (size_hints == NULL)
7467 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7468 bzero (size_hints, sizeof (XSizeHints));
7471 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7472 size_hints->width_inc = width_inc;
7473 size_hints->height_inc = height_inc;
7474 size_hints->min_width = base_width + min_cols * width_inc;
7475 size_hints->min_height = base_height + min_rows * height_inc;
7476 size_hints->base_width = base_width;
7477 size_hints->base_height = base_height;
7479 if (flags)
7480 size_hints->flags = flags;
7481 else if (user_position)
7483 size_hints->flags &= ~ PPosition;
7484 size_hints->flags |= USPosition;
7488 #if 0 /* MAC_TODO: hide application instead of iconify? */
7489 /* Used for IconicState or NormalState */
7491 void
7492 x_wm_set_window_state (f, state)
7493 struct frame *f;
7494 int state;
7496 #ifdef USE_X_TOOLKIT
7497 Arg al[1];
7499 XtSetArg (al[0], XtNinitialState, state);
7500 XtSetValues (f->output_data.x->widget, al, 1);
7501 #else /* not USE_X_TOOLKIT */
7502 Window window = FRAME_X_WINDOW (f);
7504 f->output_data.x->wm_hints.flags |= StateHint;
7505 f->output_data.x->wm_hints.initial_state = state;
7507 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7508 #endif /* not USE_X_TOOLKIT */
7511 void
7512 x_wm_set_icon_pixmap (f, pixmap_id)
7513 struct frame *f;
7514 int pixmap_id;
7516 Pixmap icon_pixmap;
7518 #ifndef USE_X_TOOLKIT
7519 Window window = FRAME_X_WINDOW (f);
7520 #endif
7522 if (pixmap_id > 0)
7524 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7525 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7527 else
7529 /* It seems there is no way to turn off use of an icon pixmap.
7530 The following line does it, only if no icon has yet been created,
7531 for some window managers. But with mwm it crashes.
7532 Some people say it should clear the IconPixmapHint bit in this case,
7533 but that doesn't work, and the X consortium said it isn't the
7534 right thing at all. Since there is no way to win,
7535 best to explicitly give up. */
7536 #if 0
7537 f->output_data.x->wm_hints.icon_pixmap = None;
7538 #else
7539 return;
7540 #endif
7543 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7546 Arg al[1];
7547 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7548 XtSetValues (f->output_data.x->widget, al, 1);
7551 #else /* not USE_X_TOOLKIT */
7553 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7554 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7556 #endif /* not USE_X_TOOLKIT */
7559 #endif /* MAC_TODO */
7561 void
7562 x_wm_set_icon_position (f, icon_x, icon_y)
7563 struct frame *f;
7564 int icon_x, icon_y;
7566 #if 0 /* MAC_TODO: no icons on Mac */
7567 #ifdef USE_X_TOOLKIT
7568 Window window = XtWindow (f->output_data.x->widget);
7569 #else
7570 Window window = FRAME_X_WINDOW (f);
7571 #endif
7573 f->output_data.x->wm_hints.flags |= IconPositionHint;
7574 f->output_data.x->wm_hints.icon_x = icon_x;
7575 f->output_data.x->wm_hints.icon_y = icon_y;
7577 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7578 #endif /* MAC_TODO */
7582 /***********************************************************************
7583 XLFD Pattern Match
7584 ***********************************************************************/
7586 /* An XLFD pattern is divided into blocks delimited by '*'. This
7587 structure holds information for each block. */
7588 struct xlfdpat_block
7590 /* Length of the pattern string in this block. Non-zero except for
7591 the first and the last blocks. */
7592 int len;
7594 /* Pattern string except the last character in this block. The last
7595 character is replaced with NUL in order to use it as a
7596 sentinel. */
7597 unsigned char *pattern;
7599 /* Last character of the pattern string. Must not be '?'. */
7600 unsigned char last_char;
7602 /* One of the tables for the Boyer-Moore string search. It
7603 specifies the number of positions to proceed for each character
7604 with which the match fails. */
7605 int skip[256];
7607 /* The skip value for the last character in the above `skip' is
7608 assigned to `infinity' in order to simplify a loop condition.
7609 The original value is saved here. */
7610 int last_char_skip;
7613 struct xlfdpat
7615 /* Normalized pattern string. "Normalized" means that capital
7616 letters are lowered, blocks are not empty except the first and
7617 the last ones, and trailing '?'s in a block that is not the last
7618 one are moved to the next one. The last character in each block
7619 is replaced with NUL. */
7620 unsigned char *buf;
7622 /* Number of characters except '*'s and trailing '?'s in the
7623 normalized pattern string. */
7624 int nchars;
7626 /* Number of trailing '?'s in the normalized pattern string. */
7627 int trailing_anychars;
7629 /* Number of blocks and information for each block. The latter is
7630 NULL if the pattern is exact (no '*' or '?' in it). */
7631 int nblocks;
7632 struct xlfdpat_block *blocks;
7635 static void
7636 xlfdpat_destroy (pat)
7637 struct xlfdpat *pat;
7639 if (pat)
7641 if (pat->buf)
7643 if (pat->blocks)
7644 xfree (pat->blocks);
7645 xfree (pat->buf);
7647 xfree (pat);
7651 static struct xlfdpat *
7652 xlfdpat_create (pattern)
7653 const char *pattern;
7655 struct xlfdpat *pat;
7656 int nblocks, i, skip;
7657 unsigned char last_char, *p, *q, *anychar_head;
7658 const unsigned char *ptr;
7659 struct xlfdpat_block *blk;
7661 pat = xmalloc (sizeof (struct xlfdpat));
7662 pat->buf = xmalloc (strlen (pattern) + 1);
7664 /* Normalize the pattern string and store it to `pat->buf'. */
7665 nblocks = 0;
7666 anychar_head = NULL;
7667 q = pat->buf;
7668 last_char = '\0';
7669 for (ptr = pattern; *ptr; ptr++)
7671 unsigned char c = *ptr;
7673 if (c == '*')
7674 if (last_char == '*')
7675 /* ...a** -> ...a* */
7676 continue;
7677 else
7679 if (last_char == '?')
7681 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7682 /* ...*??* -> ...*?? */
7683 continue;
7684 else
7685 /* ...a??* -> ...a*?? */
7687 *anychar_head++ = '*';
7688 c = '?';
7691 nblocks++;
7693 else if (c == '?')
7695 if (last_char != '?')
7696 anychar_head = q;
7698 else
7699 /* On Mac OS X 10.3, tolower also converts non-ASCII
7700 characters for some locales. */
7701 if (isascii (c))
7702 c = tolower (c);
7704 *q++ = last_char = c;
7706 *q = '\0';
7707 nblocks++;
7708 pat->nblocks = nblocks;
7709 if (last_char != '?')
7710 pat->trailing_anychars = 0;
7711 else
7713 pat->trailing_anychars = q - anychar_head;
7714 q = anychar_head;
7716 pat->nchars = q - pat->buf - (nblocks - 1);
7718 if (anychar_head == NULL && nblocks == 1)
7720 /* The pattern is exact. */
7721 pat->blocks = NULL;
7722 return pat;
7725 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
7727 /* Divide the normalized pattern into blocks. */
7728 p = pat->buf;
7729 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7731 blk->pattern = p;
7732 while (*p != '*')
7733 p++;
7734 blk->len = p - blk->pattern;
7735 p++;
7737 blk->pattern = p;
7738 blk->len = q - blk->pattern;
7740 /* Setup a table for the Boyer-Moore string search. */
7741 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7742 if (blk->len != 0)
7744 blk->last_char = blk->pattern[blk->len - 1];
7745 blk->pattern[blk->len - 1] = '\0';
7747 for (skip = 1; skip < blk->len; skip++)
7748 if (blk->pattern[blk->len - skip - 1] == '?')
7749 break;
7751 for (i = 0; i < 256; i++)
7752 blk->skip[i] = skip;
7754 p = blk->pattern + (blk->len - skip);
7755 while (--skip > 0)
7756 blk->skip[*p++] = skip;
7758 blk->last_char_skip = blk->skip[blk->last_char];
7761 return pat;
7764 static INLINE int
7765 xlfdpat_exact_p (pat)
7766 struct xlfdpat *pat;
7768 return pat->blocks == NULL;
7771 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
7772 that the pattern in *BLK matches with its prefix. Return NULL
7773 there is no such strings. STRING must be lowered in advance. */
7775 static const char *
7776 xlfdpat_block_match_1 (blk, string, start_max)
7777 struct xlfdpat_block *blk;
7778 const unsigned char *string;
7779 int start_max;
7781 int start, infinity;
7782 unsigned char *p;
7783 const unsigned char *s;
7785 xassert (blk->len > 0);
7786 xassert (start_max + blk->len <= strlen (string));
7787 xassert (blk->last_char != '?');
7789 /* See the comments in the function `boyer_moore' (search.c) for the
7790 use of `infinity'. */
7791 infinity = start_max + blk->len + 1;
7792 blk->skip[blk->last_char] = infinity;
7794 start = 0;
7797 /* Check the last character of the pattern. */
7798 s = string + blk->len - 1;
7801 start += blk->skip[*(s + start)];
7803 while (start <= start_max);
7805 if (start < infinity)
7806 /* Couldn't find the last character. */
7807 return NULL;
7809 /* No less than `infinity' means we could find the last
7810 character at `s[start - infinity]'. */
7811 start -= infinity;
7813 /* Check the remaining characters. We prefer making no-'?'
7814 cases faster because the use of '?' is really rare. */
7815 p = blk->pattern;
7816 s = string + start;
7819 while (*p++ == *s++)
7822 while (*(p - 1) == '?');
7824 if (*(p - 1) == '\0')
7825 /* Matched. */
7826 return string + start;
7828 /* Didn't match. */
7829 start += blk->last_char_skip;
7831 while (start <= start_max);
7833 return NULL;
7836 #define xlfdpat_block_match(b, s, m) \
7837 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7838 : xlfdpat_block_match_1 (b, s, m))
7840 /* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
7841 matches with STRING. STRING must be lowered in advance. */
7843 static int
7844 xlfdpat_match (pat, string)
7845 struct xlfdpat *pat;
7846 const unsigned char *string;
7848 int str_len, nblocks, i, start_max;
7849 struct xlfdpat_block *blk;
7850 const unsigned char *s;
7852 xassert (pat->nblocks > 0);
7854 if (xlfdpat_exact_p (pat))
7855 return strcmp (pat->buf, string) == 0;
7857 /* The number of the characters in the string must not be smaller
7858 than that in the pattern. */
7859 str_len = strlen (string);
7860 if (str_len < pat->nchars + pat->trailing_anychars)
7861 return 0;
7863 /* Chop off the trailing '?'s. */
7864 str_len -= pat->trailing_anychars;
7866 /* The last block. When it is non-empty, it must match at the end
7867 of the string. */
7868 nblocks = pat->nblocks;
7869 blk = pat->blocks + (nblocks - 1);
7870 if (nblocks == 1)
7871 /* The last block is also the first one. */
7872 return (str_len == blk->len
7873 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7874 else if (blk->len != 0)
7875 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7876 return 0;
7878 /* The first block. When it is non-empty, it must match at the
7879 beginning of the string. */
7880 blk = pat->blocks;
7881 if (blk->len != 0)
7883 s = xlfdpat_block_match (blk, string, 0);
7884 if (s == NULL)
7885 return 0;
7886 string = s + blk->len;
7889 /* The rest of the blocks. */
7890 start_max = str_len - pat->nchars;
7891 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7893 s = xlfdpat_block_match (blk, string, start_max);
7894 if (s == NULL)
7895 return 0;
7896 start_max -= s - string;
7897 string = s + blk->len;
7900 return 1;
7904 /***********************************************************************
7905 Fonts
7906 ***********************************************************************/
7908 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7910 struct font_info *
7911 x_get_font_info (f, font_idx)
7912 FRAME_PTR f;
7913 int font_idx;
7915 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7918 /* the global font name table */
7919 static char **font_name_table = NULL;
7920 static int font_name_table_size = 0;
7921 static int font_name_count = 0;
7923 /* Alist linking font family names to Font Manager font family
7924 references (which can also be used as QuickDraw font IDs). We use
7925 an alist because hash tables are not ready when the terminal frame
7926 for Mac OS Classic is created. */
7927 static Lisp_Object fm_font_family_alist;
7928 #if USE_ATSUI
7929 /* Hash table linking font family names to ATSU font IDs. */
7930 static Lisp_Object atsu_font_id_hash;
7931 /* Alist linking Font Manager style to face attributes. */
7932 static Lisp_Object fm_style_face_attributes_alist;
7933 extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
7934 #endif
7936 /* Alist linking character set strings to Mac text encoding and Emacs
7937 coding system. */
7938 static Lisp_Object Vmac_charset_info_alist;
7940 static Lisp_Object
7941 create_text_encoding_info_alist ()
7943 Lisp_Object result = Qnil, rest;
7945 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7947 Lisp_Object charset_info = XCAR (rest);
7948 Lisp_Object charset, coding_system, text_encoding;
7949 Lisp_Object existing_info;
7951 if (!(CONSP (charset_info)
7952 && (charset = XCAR (charset_info),
7953 STRINGP (charset))
7954 && CONSP (XCDR (charset_info))
7955 && (text_encoding = XCAR (XCDR (charset_info)),
7956 INTEGERP (text_encoding))
7957 && CONSP (XCDR (XCDR (charset_info)))
7958 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7959 SYMBOLP (coding_system))))
7960 continue;
7962 existing_info = assq_no_quit (text_encoding, result);
7963 if (NILP (existing_info))
7964 result = Fcons (list3 (text_encoding, coding_system, charset),
7965 result);
7966 else
7967 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7968 XSETCDR (XCDR (existing_info),
7969 Fcons (charset, XCDR (XCDR (existing_info))));
7972 return result;
7976 static void
7977 decode_mac_font_name (name, size, coding_system)
7978 char *name;
7979 int size;
7980 Lisp_Object coding_system;
7982 struct coding_system coding;
7983 char *buf, *p;
7985 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7987 for (p = name; *p; p++)
7988 if (!isascii (*p) || iscntrl (*p))
7989 break;
7991 if (*p)
7993 setup_coding_system (coding_system, &coding);
7994 coding.src_multibyte = 0;
7995 coding.dst_multibyte = 1;
7996 coding.mode |= CODING_MODE_LAST_BLOCK;
7997 coding.dst_bytes = size;
7998 coding.destination = (unsigned char *) alloca (coding.dst_bytes);
8000 decode_coding_c_string (&coding, name, strlen (name), Qnil);
8001 bcopy (coding.destination, name, min (coding.produced, size));
8002 name[min (coding.produced, size)] = '\0';
8006 /* If there's just one occurrence of '-' in the family name, it is
8007 replaced with '_'. (More than one occurrence of '-' means a
8008 "FOUNDRY-FAMILY-CHARSET"-style name.) */
8009 p = strchr (name, '-');
8010 if (p && strchr (p + 1, '-') == NULL)
8011 *p = '_';
8013 for (p = name; *p; p++)
8014 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8015 for some locales. */
8016 if (isascii (*p))
8017 *p = tolower (*p);
8021 static char *
8022 mac_to_x_fontname (name, size, style, charset)
8023 const char *name;
8024 int size;
8025 Style style;
8026 char *charset;
8028 Str31 foundry, cs;
8029 Str255 family;
8030 char xf[256], *result;
8031 unsigned char *p;
8033 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
8034 charset = cs;
8035 else
8037 strcpy(foundry, "Apple");
8038 strcpy(family, name);
8041 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
8042 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
8043 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
8045 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
8046 sprintf (result, "-%s-%s-%s", foundry, family, xf);
8047 for (p = result; *p; p++)
8048 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8049 for some locales. */
8050 if (isascii (*p))
8051 *p = tolower (*p);
8052 return result;
8056 /* Parse fully-specified and instantiated X11 font spec XF, and store
8057 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
8058 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
8059 caller must allocate at least 256 and 32 bytes respectively. For
8060 ordinary Mac fonts, the value stored to FAMILY should just be their
8061 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
8062 intlfonts collection contain their charset designation in their
8063 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
8064 types of font names are handled accordingly. */
8066 const int kDefaultFontSize = 12;
8068 static int
8069 parse_x_font_name (xf, family, size, style, charset)
8070 const char *xf;
8071 char *family;
8072 int *size;
8073 Style *style;
8074 char *charset;
8076 Str31 foundry, weight;
8077 int point_size, avgwidth;
8078 char slant[2], *p;
8080 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8081 foundry, family, weight, slant, size,
8082 &point_size, &avgwidth, charset) != 8
8083 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8084 foundry, family, weight, slant, size,
8085 &point_size, &avgwidth, charset) != 8)
8086 return 0;
8088 if (*size == 0)
8090 if (point_size > 0)
8091 *size = point_size / 10;
8092 else if (avgwidth > 0)
8093 *size = avgwidth / 10;
8095 if (*size == 0)
8096 *size = kDefaultFontSize;
8098 *style = normal;
8099 if (strcmp (weight, "bold") == 0)
8100 *style |= bold;
8101 if (*slant == 'i')
8102 *style |= italic;
8104 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
8106 int foundry_len = strlen (foundry), family_len = strlen (family);
8108 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
8110 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
8111 but take overlap into account. */
8112 memmove (family + foundry_len + 1, family, family_len);
8113 memcpy (family, foundry, foundry_len);
8114 family[foundry_len] = '-';
8115 family[foundry_len + 1 + family_len] = '-';
8116 strcpy (family + foundry_len + 1 + family_len + 1, charset);
8118 else
8119 return 0;
8122 for (p = family; *p; p++)
8123 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8124 for some locales. */
8125 if (isascii (*p))
8126 *p = tolower (*p);
8128 return 1;
8132 static void
8133 add_font_name_table_entry (char *font_name)
8135 if (font_name_table_size == 0)
8137 font_name_table_size = 256;
8138 font_name_table = (char **)
8139 xmalloc (font_name_table_size * sizeof (char *));
8141 else if (font_name_count + 1 >= font_name_table_size)
8143 font_name_table_size *= 2;
8144 font_name_table = (char **)
8145 xrealloc (font_name_table,
8146 font_name_table_size * sizeof (char *));
8149 font_name_table[font_name_count++] = font_name;
8152 static void
8153 add_mac_font_name (name, size, style, charset)
8154 const char *name;
8155 int size;
8156 Style style;
8157 const char *charset;
8159 if (size > 0)
8160 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8161 else
8163 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8164 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8165 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8166 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8167 charset));
8171 #if USE_ATSUI
8172 static FMFontStyle
8173 fm_get_style_from_font (font)
8174 FMFont font;
8176 OSStatus err;
8177 FMFontStyle style = normal;
8178 ByteCount len;
8179 UInt16 mac_style;
8180 FMFontFamily font_family;
8181 #define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8183 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8184 some font (e.g., Optima) even if it is `bold'. */
8185 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8186 sizeof (mac_style), &mac_style, &len);
8187 if (err == noErr
8188 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8189 style = EndianU16_BtoN (mac_style);
8190 else
8191 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8193 return style;
8196 static ATSUFontID
8197 atsu_find_font_from_family_name (family)
8198 const char *family;
8200 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8201 unsigned hash_code;
8202 int i;
8203 Lisp_Object rest, best;
8204 FMFontStyle min_style, style;
8206 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8207 &hash_code);
8208 if (i < 0)
8209 return kATSUInvalidFontID;
8211 rest = HASH_VALUE (h, i);
8212 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8213 return cons_to_long (rest);
8215 rest = Fnreverse (rest);
8216 best = XCAR (rest);
8217 rest = XCDR (rest);
8218 if (!NILP (rest)
8219 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8222 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8223 if (style < min_style)
8225 best = XCAR (rest);
8226 if (style == normal)
8227 break;
8228 else
8229 min_style = style;
8231 rest = XCDR (rest);
8233 while (!NILP (rest));
8235 HASH_VALUE (h, i) = best;
8236 return cons_to_long (best);
8239 static Lisp_Object
8240 fm_style_to_face_attributes (fm_style)
8241 FMFontStyle fm_style;
8243 Lisp_Object tem;
8245 fm_style &= (bold | italic);
8246 tem = assq_no_quit (make_number (fm_style),
8247 fm_style_face_attributes_alist);
8248 if (!NILP (tem))
8249 return XCDR (tem);
8251 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8252 QCslant, fm_style & italic ? Qitalic : Qnormal);
8253 fm_style_face_attributes_alist =
8254 Fcons (Fcons (make_number (fm_style), tem),
8255 fm_style_face_attributes_alist);
8257 return tem;
8260 static Lisp_Object
8261 atsu_find_font_family_name (font_id)
8262 ATSUFontID font_id;
8264 OSStatus err;
8265 ByteCount len;
8266 Lisp_Object family = Qnil;
8268 err = ATSUFindFontName (font_id, kFontFamilyName,
8269 kFontMacintoshPlatform, kFontNoScript,
8270 kFontNoLanguage, 0, NULL, &len, NULL);
8271 if (err == noErr)
8273 family = make_uninit_string (len);
8274 err = ATSUFindFontName (font_id, kFontFamilyName,
8275 kFontMacintoshPlatform, kFontNoScript,
8276 kFontNoLanguage, len, SDATA (family),
8277 NULL, NULL);
8279 if (err == noErr)
8280 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8282 return family;
8285 Lisp_Object
8286 mac_atsu_font_face_attributes (font_id)
8287 ATSUFontID font_id;
8289 Lisp_Object family, style_attrs;
8291 family = atsu_find_font_family_name (font_id);
8292 if (NILP (family))
8293 return Qnil;
8294 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8295 return Fcons (QCfamily, Fcons (family, style_attrs));
8297 #endif
8299 /* Sets up the table font_name_table to contain the list of all fonts
8300 in the system the first time the table is used so that the Resource
8301 Manager need not be accessed every time this information is
8302 needed. */
8304 static void
8305 init_font_name_table ()
8307 #if TARGET_API_MAC_CARBON
8308 FMFontFamilyIterator ffi;
8309 FMFontFamilyInstanceIterator ffii;
8310 FMFontFamily ff;
8311 Lisp_Object text_encoding_info_alist;
8312 struct gcpro gcpro1;
8314 text_encoding_info_alist = create_text_encoding_info_alist ();
8316 #if USE_ATSUI
8317 #if USE_CG_TEXT_DRAWING
8318 init_cg_text_anti_aliasing_threshold ();
8319 #endif
8320 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8321 text_encoding_info_alist)))
8323 OSStatus err;
8324 struct Lisp_Hash_Table *h;
8325 unsigned hash_code;
8326 ItemCount nfonts, i;
8327 ATSUFontID *font_ids = NULL;
8328 Lisp_Object prev_family = Qnil;
8329 int j;
8331 atsu_font_id_hash =
8332 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8333 make_float (DEFAULT_REHASH_SIZE),
8334 make_float (DEFAULT_REHASH_THRESHOLD),
8335 Qnil, Qnil, Qnil);
8336 h = XHASH_TABLE (atsu_font_id_hash);
8338 err = ATSUFontCount (&nfonts);
8339 if (err == noErr)
8341 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8342 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8344 if (err == noErr)
8345 for (i = 0; i < nfonts; i++)
8347 Lisp_Object family;
8349 family = atsu_find_font_family_name (font_ids[i]);
8350 if (NILP (family) || SREF (family, 0) == '.')
8351 continue;
8352 if (!NILP (Fequal (prev_family, family)))
8353 family = prev_family;
8354 else
8355 j = hash_lookup (h, family, &hash_code);
8356 if (j < 0)
8358 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8359 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8360 Qnil), hash_code);
8362 else if (EQ (prev_family, family))
8363 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8364 HASH_VALUE (h, j));
8365 prev_family = family;
8367 if (font_ids)
8368 xfree (font_ids);
8370 #endif
8372 /* Create a dummy instance iterator here to avoid creating and
8373 destroying it in the loop. */
8374 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8375 return;
8376 /* Create an iterator to enumerate the font families. */
8377 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8378 != noErr)
8380 FMDisposeFontFamilyInstanceIterator (&ffii);
8381 return;
8384 GCPRO1 (text_encoding_info_alist);
8386 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
8388 Str255 name;
8389 FMFont font;
8390 FMFontStyle style;
8391 FMFontSize size;
8392 TextEncoding encoding;
8393 TextEncodingBase sc;
8394 Lisp_Object text_encoding_info, family;
8396 if (FMGetFontFamilyName (ff, name) != noErr)
8397 continue;
8398 p2cstr (name);
8399 if (*name == '.')
8400 continue;
8402 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
8403 continue;
8404 sc = GetTextEncodingBase (encoding);
8405 text_encoding_info = assq_no_quit (make_number (sc),
8406 text_encoding_info_alist);
8407 if (NILP (text_encoding_info))
8408 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8409 text_encoding_info_alist);
8410 decode_mac_font_name (name, sizeof (name),
8411 XCAR (XCDR (text_encoding_info)));
8412 family = build_string (name);
8413 if (!NILP (Fassoc (family, fm_font_family_alist)))
8414 continue;
8415 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
8416 fm_font_family_alist);
8418 /* Point the instance iterator at the current font family. */
8419 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
8420 continue;
8422 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8423 == noErr)
8425 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8427 if (size > 0 || style == normal)
8428 for (; CONSP (rest); rest = XCDR (rest))
8429 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
8433 UNGCPRO;
8435 /* Dispose of the iterators. */
8436 FMDisposeFontFamilyIterator (&ffi);
8437 FMDisposeFontFamilyInstanceIterator (&ffii);
8438 #else /* !TARGET_API_MAC_CARBON */
8439 GrafPtr port;
8440 SInt16 fontnum, old_fontnum;
8441 int num_mac_fonts = CountResources('FOND');
8442 int i, j;
8443 Handle font_handle, font_handle_2;
8444 short id, scriptcode;
8445 ResType type;
8446 Str255 name;
8447 struct FontAssoc *fat;
8448 struct AsscEntry *assc_entry;
8449 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
8450 struct gcpro gcpro1;
8452 GetPort (&port); /* save the current font number used */
8453 old_fontnum = port->txFont;
8455 text_encoding_info_alist = create_text_encoding_info_alist ();
8457 GCPRO1 (text_encoding_info_alist);
8459 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
8461 font_handle = GetIndResource ('FOND', i);
8462 if (!font_handle)
8463 continue;
8465 GetResInfo (font_handle, &id, &type, name);
8466 GetFNum (name, &fontnum);
8467 p2cstr (name);
8468 if (fontnum == 0 || *name == '.')
8469 continue;
8471 TextFont (fontnum);
8472 scriptcode = FontToScript (fontnum);
8473 text_encoding_info = assq_no_quit (make_number (scriptcode),
8474 text_encoding_info_alist);
8475 if (NILP (text_encoding_info))
8476 text_encoding_info = assq_no_quit (make_number (smRoman),
8477 text_encoding_info_alist);
8478 decode_mac_font_name (name, sizeof (name),
8479 XCAR (XCDR (text_encoding_info)));
8480 family = build_string (name);
8481 if (!NILP (Fassoc (family, fm_font_family_alist)))
8482 continue;
8483 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
8484 fm_font_family_alist);
8487 HLock (font_handle);
8489 if (GetResourceSizeOnDisk (font_handle)
8490 >= sizeof (struct FamRec))
8492 fat = (struct FontAssoc *) (*font_handle
8493 + sizeof (struct FamRec));
8494 assc_entry
8495 = (struct AsscEntry *) (*font_handle
8496 + sizeof (struct FamRec)
8497 + sizeof (struct FontAssoc));
8499 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
8501 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8503 for (; CONSP (rest); rest = XCDR (rest))
8504 add_mac_font_name (name, assc_entry->fontSize,
8505 assc_entry->fontStyle,
8506 SDATA (XCAR (rest)));
8510 HUnlock (font_handle);
8511 font_handle_2 = GetNextFOND (font_handle);
8512 ReleaseResource (font_handle);
8513 font_handle = font_handle_2;
8515 while (ResError () == noErr && font_handle);
8518 UNGCPRO;
8520 TextFont (old_fontnum);
8521 #endif /* !TARGET_API_MAC_CARBON */
8525 void
8526 mac_clear_font_name_table ()
8528 int i;
8530 for (i = 0; i < font_name_count; i++)
8531 xfree (font_name_table[i]);
8532 xfree (font_name_table);
8533 font_name_table = NULL;
8534 font_name_table_size = font_name_count = 0;
8535 fm_font_family_alist = Qnil;
8539 enum xlfd_scalable_field_index
8541 XLFD_SCL_PIXEL_SIZE,
8542 XLFD_SCL_POINT_SIZE,
8543 XLFD_SCL_AVGWIDTH,
8544 XLFD_SCL_LAST
8547 static const int xlfd_scalable_fields[] =
8549 6, /* PIXEL_SIZE */
8550 7, /* POINT_SIZE */
8551 11, /* AVGWIDTH */
8555 static Lisp_Object
8556 mac_do_list_fonts (pattern, maxnames)
8557 const char *pattern;
8558 int maxnames;
8560 int i, n_fonts = 0;
8561 Lisp_Object font_list = Qnil;
8562 struct xlfdpat *pat;
8563 char *scaled;
8564 const char *ptr;
8565 int scl_val[XLFD_SCL_LAST], *val;
8566 const int *field;
8567 int exact;
8569 if (font_name_table == NULL) /* Initialize when first used. */
8570 init_font_name_table ();
8572 for (i = 0; i < XLFD_SCL_LAST; i++)
8573 scl_val[i] = -1;
8575 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8576 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8577 fonts are scaled according to the specified size. */
8578 ptr = pattern;
8579 i = 0;
8580 field = xlfd_scalable_fields;
8581 val = scl_val;
8582 if (*ptr == '-')
8585 ptr++;
8586 if (i == *field)
8588 if ('0' <= *ptr && *ptr <= '9')
8590 *val = *ptr++ - '0';
8591 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8592 *val = *val * 10 + *ptr++ - '0';
8593 if (*ptr != '-')
8594 *val = -1;
8596 field++;
8597 val++;
8599 ptr = strchr (ptr, '-');
8600 i++;
8602 while (ptr && i < 14);
8604 if (i == 14 && ptr == NULL)
8606 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8607 scl_val[XLFD_SCL_PIXEL_SIZE] =
8608 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8609 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8610 : -1));
8611 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8612 scl_val[XLFD_SCL_POINT_SIZE] =
8613 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8614 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8615 : -1));
8616 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8617 scl_val[XLFD_SCL_AVGWIDTH] =
8618 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8619 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8620 : -1));
8622 else
8623 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8625 pat = xlfdpat_create (pattern);
8626 if (pat == NULL)
8627 return Qnil;
8629 exact = xlfdpat_exact_p (pat);
8631 for (i = 0; i < font_name_count; i++)
8633 if (xlfdpat_match (pat, font_name_table[i]))
8635 font_list = Fcons (build_string (font_name_table[i]), font_list);
8636 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8637 break;
8639 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
8640 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
8642 int former_len = ptr - font_name_table[i];
8644 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
8645 memcpy (scaled, font_name_table[i], former_len);
8646 sprintf (scaled + former_len,
8647 "-%d-%d-72-72-m-%d-%s",
8648 scl_val[XLFD_SCL_PIXEL_SIZE],
8649 scl_val[XLFD_SCL_POINT_SIZE],
8650 scl_val[XLFD_SCL_AVGWIDTH],
8651 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
8653 if (xlfdpat_match (pat, scaled))
8655 font_list = Fcons (build_string (scaled), font_list);
8656 xfree (scaled);
8657 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8658 break;
8660 else
8661 xfree (scaled);
8665 xlfdpat_destroy (pat);
8667 return font_list;
8670 /* Return a list of names of available fonts matching PATTERN on frame F.
8672 Frame F null means we have not yet created any frame on Mac, and
8673 consult the first display in x_display_list. MAXNAMES sets a limit
8674 on how many fonts to match. */
8676 Lisp_Object
8677 x_list_fonts (f, pattern, size, maxnames)
8678 struct frame *f;
8679 Lisp_Object pattern;
8680 int size, maxnames;
8682 Lisp_Object list = Qnil, patterns, tem, key;
8683 struct mac_display_info *dpyinfo
8684 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
8686 xassert (size <= 0);
8688 patterns = Fassoc (pattern, Valternate_fontname_alist);
8689 if (NILP (patterns))
8690 patterns = Fcons (pattern, Qnil);
8692 for (; CONSP (patterns); patterns = XCDR (patterns))
8694 pattern = XCAR (patterns);
8696 if (!STRINGP (pattern))
8697 continue;
8699 tem = XCAR (XCDR (dpyinfo->name_list_element));
8700 key = Fcons (pattern, make_number (maxnames));
8702 list = Fassoc (key, tem);
8703 if (!NILP (list))
8705 list = Fcdr_safe (list);
8706 /* We have a cashed list. Don't have to get the list again. */
8707 goto label_cached;
8710 BLOCK_INPUT;
8711 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8712 UNBLOCK_INPUT;
8714 /* MAC_TODO: add code for matching outline fonts here */
8716 /* Now store the result in the cache. */
8717 XSETCAR (XCDR (dpyinfo->name_list_element),
8718 Fcons (Fcons (key, list),
8719 XCAR (XCDR (dpyinfo->name_list_element))));
8721 label_cached:
8722 if (NILP (list)) continue; /* Try the remaining alternatives. */
8725 return list;
8729 #if GLYPH_DEBUG
8731 /* Check that FONT is valid on frame F. It is if it can be found in F's
8732 font table. */
8734 static void
8735 x_check_font (f, font)
8736 struct frame *f;
8737 XFontStruct *font;
8739 int i;
8740 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8742 xassert (font != NULL);
8744 for (i = 0; i < dpyinfo->n_fonts; i++)
8745 if (dpyinfo->font_table[i].name
8746 && font == dpyinfo->font_table[i].font)
8747 break;
8749 xassert (i < dpyinfo->n_fonts);
8752 #endif /* GLYPH_DEBUG != 0 */
8754 /* Set *W to the minimum width, *H to the minimum font height of FONT.
8755 Note: There are (broken) X fonts out there with invalid XFontStruct
8756 min_bounds contents. For example, handa@etl.go.jp reports that
8757 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8758 have font->min_bounds.width == 0. */
8760 static INLINE void
8761 x_font_min_bounds (font, w, h)
8762 MacFontStruct *font;
8763 int *w, *h;
8765 *h = FONT_HEIGHT (font);
8766 *w = font->min_bounds.width;
8770 /* Compute the smallest character width and smallest font height over
8771 all fonts available on frame F. Set the members smallest_char_width
8772 and smallest_font_height in F's x_display_info structure to
8773 the values computed. Value is non-zero if smallest_font_height or
8774 smallest_char_width become smaller than they were before. */
8776 static int
8777 x_compute_min_glyph_bounds (f)
8778 struct frame *f;
8780 int i;
8781 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8782 MacFontStruct *font;
8783 int old_width = dpyinfo->smallest_char_width;
8784 int old_height = dpyinfo->smallest_font_height;
8786 dpyinfo->smallest_font_height = 100000;
8787 dpyinfo->smallest_char_width = 100000;
8789 for (i = 0; i < dpyinfo->n_fonts; ++i)
8790 if (dpyinfo->font_table[i].name)
8792 struct font_info *fontp = dpyinfo->font_table + i;
8793 int w, h;
8795 font = (MacFontStruct *) fontp->font;
8796 xassert (font != (MacFontStruct *) ~0);
8797 x_font_min_bounds (font, &w, &h);
8799 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8800 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8803 xassert (dpyinfo->smallest_char_width > 0
8804 && dpyinfo->smallest_font_height > 0);
8806 return (dpyinfo->n_fonts == 1
8807 || dpyinfo->smallest_char_width < old_width
8808 || dpyinfo->smallest_font_height < old_height);
8812 /* Determine whether given string is a fully-specified XLFD: all 14
8813 fields are present, none is '*'. */
8815 static int
8816 is_fully_specified_xlfd (p)
8817 const char *p;
8819 int i;
8820 char *q;
8822 if (*p != '-')
8823 return 0;
8825 for (i = 0; i < 13; i++)
8827 q = strchr (p + 1, '-');
8828 if (q == NULL)
8829 return 0;
8830 if (q - p == 2 && *(p + 1) == '*')
8831 return 0;
8832 p = q;
8835 if (strchr (p + 1, '-') != NULL)
8836 return 0;
8838 if (*(p + 1) == '*' && *(p + 2) == '\0')
8839 return 0;
8841 return 1;
8845 /* mac_load_query_font creates and returns an internal representation
8846 for a font in a MacFontStruct struct. There is really no concept
8847 corresponding to "loading" a font on the Mac. But we check its
8848 existence and find the font number and all other information for it
8849 and store them in the returned MacFontStruct. */
8851 static MacFontStruct *
8852 mac_load_query_font (f, fontname)
8853 struct frame *f;
8854 char *fontname;
8856 int size;
8857 char *name;
8858 Str255 family;
8859 Str31 charset;
8860 SInt16 fontnum;
8861 #if USE_ATSUI
8862 static ATSUFontID font_id;
8863 ATSUStyle mac_style = NULL;
8864 #endif
8865 Style fontface;
8866 #if TARGET_API_MAC_CARBON
8867 TextEncoding encoding;
8868 int scriptcode;
8869 #else
8870 short scriptcode;
8871 #endif
8872 MacFontStruct *font;
8873 XCharStruct *space_bounds = NULL, *pcm;
8875 if (is_fully_specified_xlfd (fontname))
8876 name = fontname;
8877 else
8879 Lisp_Object matched_fonts;
8881 matched_fonts = mac_do_list_fonts (fontname, 1);
8882 if (NILP (matched_fonts))
8883 return NULL;
8884 name = SDATA (XCAR (matched_fonts));
8887 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8888 return NULL;
8890 #if USE_ATSUI
8891 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8893 OSStatus err;
8894 static const ATSUAttributeTag tags[] =
8895 {kATSUFontTag, kATSUSizeTag,
8896 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8897 static const ByteCount sizes[] =
8898 {sizeof (ATSUFontID), sizeof (Fixed),
8899 sizeof (Boolean), sizeof (Boolean)};
8900 static Fixed size_fixed;
8901 static Boolean bold_p, italic_p;
8902 static const ATSUAttributeValuePtr values[] =
8903 {&font_id, &size_fixed,
8904 &bold_p, &italic_p};
8905 static const ATSUFontFeatureType types[] =
8906 {kAllTypographicFeaturesType, kDiacriticsType};
8907 static const ATSUFontFeatureSelector selectors[] =
8908 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
8909 FMFontStyle style;
8911 font_id = atsu_find_font_from_family_name (family);
8912 if (font_id == kATSUInvalidFontID)
8913 return NULL;
8914 size_fixed = Long2Fix (size);
8915 bold_p = (fontface & bold) != 0;
8916 italic_p = (fontface & italic) != 0;
8917 err = ATSUCreateStyle (&mac_style);
8918 if (err != noErr)
8919 return NULL;
8920 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8921 types, selectors);
8922 if (err != noErr)
8923 return NULL;
8924 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8925 tags, sizes, values);
8926 if (err != noErr)
8927 return NULL;
8928 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8929 if (err != noErr)
8930 fontnum = -1;
8931 scriptcode = kTextEncodingMacUnicode;
8933 else
8934 #endif
8936 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8938 if (NILP (tmp))
8939 return NULL;
8940 fontnum = XINT (XCDR (tmp));
8941 #if TARGET_API_MAC_CARBON
8942 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8943 return NULL;
8944 scriptcode = GetTextEncodingBase (encoding);
8945 #else
8946 scriptcode = FontToScript (fontnum);
8947 #endif
8950 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
8952 font->mac_fontnum = fontnum;
8953 font->mac_fontsize = size;
8954 font->mac_fontface = fontface;
8955 font->mac_scriptcode = scriptcode;
8956 #if USE_ATSUI
8957 font->mac_style = mac_style;
8958 #if USE_CG_TEXT_DRAWING
8959 font->cg_font = NULL;
8960 font->cg_glyphs = NULL;
8961 #endif
8962 #endif
8964 /* Apple Japanese (SJIS) font is listed as both
8965 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
8966 (Roman script) in init_font_name_table (). The latter should be
8967 treated as a one-byte font. */
8968 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8969 font->mac_scriptcode = smRoman;
8971 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
8973 #if USE_ATSUI
8974 if (font->mac_style)
8976 OSStatus err;
8977 UniChar c;
8979 font->min_byte1 = 0;
8980 font->max_byte1 = 0xff;
8981 font->min_char_or_byte2 = 0;
8982 font->max_char_or_byte2 = 0xff;
8984 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8985 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8986 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8987 pcm_init (font->bounds.rows[0], 0x100);
8989 #if USE_CG_TEXT_DRAWING
8990 if (fontnum != -1)
8992 FMFontStyle style;
8993 ATSFontRef ats_font;
8995 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
8996 &font_id, &style);
8997 /* Use CG text drawing if italic/bold is not synthesized. */
8998 if (err == noErr && style == fontface)
9000 ats_font = FMGetATSFontRefFromFont (font_id);
9001 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
9005 if (font->cg_font)
9007 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
9008 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
9010 #endif
9011 space_bounds = font->bounds.rows[0] + 0x20;
9012 err = mac_query_char_extents (font->mac_style, 0x20,
9013 &font->ascent, &font->descent,
9014 space_bounds,
9015 #if USE_CG_TEXT_DRAWING
9016 (font->cg_glyphs ? font->cg_glyphs + 0x20
9017 : NULL)
9018 #else
9019 NULL
9020 #endif
9022 if (err != noErr
9023 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
9025 mac_unload_font (&one_mac_display_info, font);
9026 return NULL;
9029 pcm = font->bounds.rows[0];
9030 for (c = 0x21; c <= 0xff; c++)
9032 if (c == 0xad)
9033 /* Soft hyphen is not supported in ATSUI. */
9034 continue;
9035 else if (c == 0x7f)
9037 #if USE_CG_TEXT_DRAWING
9038 if (font->cg_glyphs)
9040 c = 0x9f;
9041 pcm = NULL;
9042 continue;
9044 #endif
9045 break;
9048 mac_query_char_extents (font->mac_style, c, NULL, NULL,
9049 pcm ? pcm + c : NULL,
9050 #if USE_CG_TEXT_DRAWING
9051 (font->cg_glyphs ? font->cg_glyphs + c
9052 : NULL)
9053 #else
9054 NULL
9055 #endif
9058 #if USE_CG_TEXT_DRAWING
9059 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
9061 /* Don't use CG text drawing if font substitution occurs in
9062 ASCII or Latin-1 characters. */
9063 CGFontRelease (font->cg_font);
9064 font->cg_font = NULL;
9065 xfree (font->cg_glyphs);
9066 font->cg_glyphs = NULL;
9067 if (pcm == NULL)
9068 break;
9070 #endif
9073 else
9074 #endif
9076 OSStatus err;
9077 FontInfo the_fontinfo;
9078 int is_two_byte_font;
9080 #if USE_CG_DRAWING
9081 mac_prepare_for_quickdraw (f);
9082 #endif
9083 SetPortWindowPort (FRAME_MAC_WINDOW (f));
9085 TextFont (fontnum);
9086 TextSize (size);
9087 TextFace (fontface);
9089 GetFontInfo (&the_fontinfo);
9091 font->ascent = the_fontinfo.ascent;
9092 font->descent = the_fontinfo.descent;
9094 is_two_byte_font = (font->mac_scriptcode == smJapanese
9095 || font->mac_scriptcode == smTradChinese
9096 || font->mac_scriptcode == smSimpChinese
9097 || font->mac_scriptcode == smKorean);
9099 if (is_two_byte_font)
9101 int char_width;
9103 font->min_byte1 = 0xa1;
9104 font->max_byte1 = 0xfe;
9105 font->min_char_or_byte2 = 0xa1;
9106 font->max_char_or_byte2 = 0xfe;
9108 /* Use the width of an "ideographic space" of that font
9109 because the_fontinfo.widMax returns the wrong width for
9110 some fonts. */
9111 switch (font->mac_scriptcode)
9113 case smJapanese:
9114 font->min_byte1 = 0x81;
9115 font->max_byte1 = 0xfc;
9116 font->min_char_or_byte2 = 0x40;
9117 font->max_char_or_byte2 = 0xfc;
9118 char_width = StringWidth("\p\x81\x40");
9119 break;
9120 case smTradChinese:
9121 font->min_char_or_byte2 = 0x40;
9122 char_width = StringWidth("\p\xa1\x40");
9123 break;
9124 case smSimpChinese:
9125 char_width = StringWidth("\p\xa1\xa1");
9126 break;
9127 case smKorean:
9128 char_width = StringWidth("\p\xa1\xa1");
9129 break;
9132 font->bounds.per_char = NULL;
9134 if (fontface & italic)
9135 font->max_bounds.rbearing = char_width + 1;
9136 else
9137 font->max_bounds.rbearing = char_width;
9138 font->max_bounds.lbearing = 0;
9139 font->max_bounds.width = char_width;
9140 font->max_bounds.ascent = the_fontinfo.ascent;
9141 font->max_bounds.descent = the_fontinfo.descent;
9143 font->min_bounds = font->max_bounds;
9145 else
9147 int c;
9149 font->min_byte1 = font->max_byte1 = 0;
9150 font->min_char_or_byte2 = 0x20;
9151 font->max_char_or_byte2 = 0xff;
9153 font->bounds.per_char =
9154 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
9155 bzero (font->bounds.per_char,
9156 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9158 space_bounds = font->bounds.per_char;
9159 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9160 &font->descent, space_bounds, NULL);
9161 if (err != noErr || space_bounds->width <= 0)
9163 mac_unload_font (&one_mac_display_info, font);
9164 return NULL;
9167 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9168 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
9172 if (space_bounds)
9174 int c;
9176 font->min_bounds = font->max_bounds = *space_bounds;
9177 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9178 if (pcm->width > 0)
9180 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9181 pcm->lbearing);
9182 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9183 pcm->rbearing);
9184 font->min_bounds.width = min (font->min_bounds.width,
9185 pcm->width);
9186 font->min_bounds.ascent = min (font->min_bounds.ascent,
9187 pcm->ascent);
9188 font->min_bounds.descent = min (font->min_bounds.descent,
9189 pcm->descent);
9191 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9192 pcm->lbearing);
9193 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9194 pcm->rbearing);
9195 font->max_bounds.width = max (font->max_bounds.width,
9196 pcm->width);
9197 font->max_bounds.ascent = max (font->max_bounds.ascent,
9198 pcm->ascent);
9199 font->max_bounds.descent = max (font->max_bounds.descent,
9200 pcm->descent);
9202 if (
9203 #if USE_ATSUI
9204 font->mac_style == NULL &&
9205 #endif
9206 font->max_bounds.width == font->min_bounds.width
9207 && font->min_bounds.lbearing >= 0
9208 && font->max_bounds.rbearing <= font->max_bounds.width)
9210 /* Fixed width and no overhangs. */
9211 xfree (font->bounds.per_char);
9212 font->bounds.per_char = NULL;
9216 #if !defined (MAC_OS8) || USE_ATSUI
9217 /* AppKit and WebKit do some adjustment to the heights of Courier,
9218 Helvetica, and Times. This only works on the environments where
9219 srcCopy text transfer mode is never used. */
9220 if (
9221 #ifdef MAC_OS8 /* implies USE_ATSUI */
9222 font->mac_style &&
9223 #endif
9224 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9225 || strcmp (family, "times") == 0))
9226 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9227 #endif
9229 return font;
9233 void
9234 mac_unload_font (dpyinfo, font)
9235 struct mac_display_info *dpyinfo;
9236 XFontStruct *font;
9238 xfree (font->full_name);
9239 #if USE_ATSUI
9240 if (font->mac_style)
9242 int i;
9244 for (i = font->min_byte1; i <= font->max_byte1; i++)
9245 if (font->bounds.rows[i])
9246 xfree (font->bounds.rows[i]);
9247 xfree (font->bounds.rows);
9248 ATSUDisposeStyle (font->mac_style);
9250 else
9251 #endif
9252 if (font->bounds.per_char)
9253 xfree (font->bounds.per_char);
9254 #if USE_CG_TEXT_DRAWING
9255 if (font->cg_font)
9256 CGFontRelease (font->cg_font);
9257 if (font->cg_glyphs)
9258 xfree (font->cg_glyphs);
9259 #endif
9260 xfree (font);
9264 /* Load font named FONTNAME of the size SIZE for frame F, and return a
9265 pointer to the structure font_info while allocating it dynamically.
9266 If SIZE is 0, load any size of font.
9267 If loading is failed, return NULL. */
9269 struct font_info *
9270 x_load_font (f, fontname, size)
9271 struct frame *f;
9272 register char *fontname;
9273 int size;
9275 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9276 Lisp_Object font_names;
9278 /* Get a list of all the fonts that match this name. Once we
9279 have a list of matching fonts, we compare them against the fonts
9280 we already have by comparing names. */
9281 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9283 if (!NILP (font_names))
9285 Lisp_Object tail;
9286 int i;
9288 for (i = 0; i < dpyinfo->n_fonts; i++)
9289 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9290 if (dpyinfo->font_table[i].name
9291 && (!strcmp (dpyinfo->font_table[i].name,
9292 SDATA (XCAR (tail)))
9293 || !strcmp (dpyinfo->font_table[i].full_name,
9294 SDATA (XCAR (tail)))))
9295 return (dpyinfo->font_table + i);
9297 else
9298 return NULL;
9300 /* Load the font and add it to the table. */
9302 struct MacFontStruct *font;
9303 struct font_info *fontp;
9304 int i;
9306 fontname = (char *) SDATA (XCAR (font_names));
9308 BLOCK_INPUT;
9309 font = mac_load_query_font (f, fontname);
9310 UNBLOCK_INPUT;
9311 if (!font)
9312 return NULL;
9314 /* Find a free slot in the font table. */
9315 for (i = 0; i < dpyinfo->n_fonts; ++i)
9316 if (dpyinfo->font_table[i].name == NULL)
9317 break;
9319 /* If no free slot found, maybe enlarge the font table. */
9320 if (i == dpyinfo->n_fonts
9321 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9323 int sz;
9324 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9325 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9326 dpyinfo->font_table
9327 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9330 fontp = dpyinfo->font_table + i;
9331 if (i == dpyinfo->n_fonts)
9332 ++dpyinfo->n_fonts;
9334 /* Now fill in the slots of *FONTP. */
9335 BLOCK_INPUT;
9336 bzero (fontp, sizeof (*fontp));
9337 fontp->font = font;
9338 fontp->font_idx = i;
9339 fontp->charset = -1; /* fs_load_font sets it. */
9340 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9341 bcopy (fontname, fontp->name, strlen (fontname) + 1);
9343 if (font->min_bounds.width == font->max_bounds.width)
9345 /* Fixed width font. */
9346 fontp->average_width = fontp->space_width = font->min_bounds.width;
9348 else
9350 XChar2b char2b;
9351 XCharStruct *pcm;
9353 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9354 pcm = mac_per_char_metric (font, &char2b, 0);
9355 if (pcm)
9356 fontp->space_width = pcm->width;
9357 else
9358 fontp->space_width = FONT_WIDTH (font);
9360 if (pcm)
9362 int width = pcm->width;
9363 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9364 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9365 width += pcm->width;
9366 fontp->average_width = width / 95;
9368 else
9369 fontp->average_width = FONT_WIDTH (font);
9372 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9373 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
9375 fontp->size = font->max_bounds.width;
9376 fontp->height = FONT_HEIGHT (font);
9378 /* For some font, ascent and descent in max_bounds field is
9379 larger than the above value. */
9380 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9381 if (max_height > fontp->height)
9382 fontp->height = max_height;
9385 /* MAC_TODO: The script encoding is irrelevant in unicode? */
9386 /* The slot `encoding' specifies how to map a character
9387 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9388 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9389 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9390 2:0xA020..0xFF7F). For the moment, we don't know which charset
9391 uses this font. So, we set information in fontp->encoding_type
9392 which is never used by any charset. If mapping can't be
9393 decided, set FONT_ENCODING_NOT_DECIDED. */
9394 if (font->mac_scriptcode == smJapanese)
9395 fontp->encoding_type = 4;
9396 else
9398 fontp->encoding_type
9399 = (font->max_byte1 == 0
9400 /* 1-byte font */
9401 ? (font->min_char_or_byte2 < 0x80
9402 ? (font->max_char_or_byte2 < 0x80
9403 ? 0 /* 0x20..0x7F */
9404 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9405 : 1) /* 0xA0..0xFF */
9406 /* 2-byte font */
9407 : (font->min_byte1 < 0x80
9408 ? (font->max_byte1 < 0x80
9409 ? (font->min_char_or_byte2 < 0x80
9410 ? (font->max_char_or_byte2 < 0x80
9411 ? 0 /* 0x2020..0x7F7F */
9412 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9413 : 3) /* 0x20A0..0x7FFF */
9414 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9415 : (font->min_char_or_byte2 < 0x80
9416 ? (font->max_char_or_byte2 < 0x80
9417 ? 2 /* 0xA020..0xFF7F */
9418 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9419 : 1))); /* 0xA0A0..0xFFFF */
9422 #if 0 /* MAC_TODO: fill these out with more reasonably values */
9423 fontp->baseline_offset
9424 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9425 ? (long) value : 0);
9426 fontp->relative_compose
9427 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9428 ? (long) value : 0);
9429 fontp->default_ascent
9430 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9431 ? (long) value : 0);
9432 #else
9433 fontp->baseline_offset = 0;
9434 fontp->relative_compose = 0;
9435 fontp->default_ascent = 0;
9436 #endif
9438 /* Set global flag fonts_changed_p to non-zero if the font loaded
9439 has a character with a smaller width than any other character
9440 before, or if the font loaded has a smaller height than any
9441 other font loaded before. If this happens, it will make a
9442 glyph matrix reallocation necessary. */
9443 fonts_changed_p |= x_compute_min_glyph_bounds (f);
9444 UNBLOCK_INPUT;
9445 return fontp;
9450 /* Return a pointer to struct font_info of a font named FONTNAME for
9451 frame F. If no such font is loaded, return NULL. */
9453 struct font_info *
9454 x_query_font (f, fontname)
9455 struct frame *f;
9456 register char *fontname;
9458 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9459 int i;
9461 for (i = 0; i < dpyinfo->n_fonts; i++)
9462 if (dpyinfo->font_table[i].name
9463 && (!xstrcasecmp (dpyinfo->font_table[i].name, fontname)
9464 || !xstrcasecmp (dpyinfo->font_table[i].full_name, fontname)))
9465 return (dpyinfo->font_table + i);
9466 return NULL;
9470 /* Find a CCL program for a font specified by FONTP, and set the member
9471 `encoder' of the structure. */
9473 void
9474 x_find_ccl_program (fontp)
9475 struct font_info *fontp;
9477 Lisp_Object list, elt;
9479 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9481 elt = XCAR (list);
9482 if (CONSP (elt)
9483 && STRINGP (XCAR (elt))
9484 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9485 >= 0))
9486 break;
9488 if (! NILP (list))
9490 struct ccl_program *ccl
9491 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9493 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9494 xfree (ccl);
9495 else
9496 fontp->font_encoder = ccl;
9500 #if USE_MAC_FONT_PANEL
9501 /* Whether Font Panel has been shown before. The first call to font
9502 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9503 slow. This variable is used for deferring such a call as much as
9504 possible. */
9505 static int font_panel_shown_p = 0;
9507 extern Lisp_Object Qfont;
9508 static Lisp_Object Qpanel_closed, Qselection;
9510 static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9511 Lisp_Object,
9512 Lisp_Object,
9513 EventRef, UInt32,
9514 const EventParamName *,
9515 const EventParamType *));
9518 mac_font_panel_visible_p ()
9520 return font_panel_shown_p && FPIsFontPanelVisible ();
9523 static pascal OSStatus
9524 mac_handle_font_event (next_handler, event, data)
9525 EventHandlerCallRef next_handler;
9526 EventRef event;
9527 void *data;
9529 OSStatus result, err;
9530 Lisp_Object id_key;
9531 int num_params;
9532 const EventParamName *names;
9533 const EventParamType *types;
9534 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9535 kEventParamATSUFontSize,
9536 kEventParamFMFontFamily,
9537 kEventParamFMFontStyle,
9538 kEventParamFMFontSize,
9539 kEventParamFontColor};
9540 static const EventParamType types_sel[] = {typeATSUFontID,
9541 typeATSUSize,
9542 typeFMFontFamily,
9543 typeFMFontStyle,
9544 typeFMFontSize,
9545 typeFontColor};
9547 result = CallNextEventHandler (next_handler, event);
9548 if (result != eventNotHandledErr)
9549 return result;
9551 switch (GetEventKind (event))
9553 case kEventFontPanelClosed:
9554 id_key = Qpanel_closed;
9555 num_params = 0;
9556 names = NULL;
9557 types = NULL;
9558 break;
9560 case kEventFontSelection:
9561 id_key = Qselection;
9562 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9563 names = names_sel;
9564 types = types_sel;
9565 break;
9568 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9569 event, num_params,
9570 names, types);
9571 if (err == noErr)
9572 result = noErr;
9574 return result;
9577 OSStatus
9578 mac_show_hide_font_panel ()
9580 if (!font_panel_shown_p)
9582 OSStatus err;
9584 static const EventTypeSpec specs[] =
9585 {{kEventClassFont, kEventFontPanelClosed},
9586 {kEventClassFont, kEventFontSelection}};
9588 err = InstallApplicationEventHandler (mac_handle_font_event,
9589 GetEventTypeCount (specs),
9590 specs, NULL, NULL);
9591 if (err != noErr)
9592 return err;
9594 font_panel_shown_p = 1;
9597 return FPShowHideFontPanel ();
9600 OSStatus
9601 mac_set_font_info_for_selection (f, face_id, c)
9602 struct frame *f;
9603 int face_id, c;
9605 OSStatus err;
9606 EventTargetRef target = NULL;
9607 XFontStruct *font = NULL;
9609 if (!mac_font_panel_visible_p ())
9610 return noErr;
9612 if (f)
9614 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
9616 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9618 struct face *face;
9620 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9621 face = FACE_FROM_ID (f, face_id);
9622 font = face->font;
9626 if (font == NULL)
9627 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9628 else
9630 if (font->mac_fontnum != -1)
9632 FontSelectionQDStyle qd_style;
9634 qd_style.version = kFontSelectionQDStyleVersionZero;
9635 qd_style.instance.fontFamily = font->mac_fontnum;
9636 qd_style.instance.fontStyle = font->mac_fontface;
9637 qd_style.size = font->mac_fontsize;
9638 qd_style.hasColor = false;
9640 err = SetFontInfoForSelection (kFontSelectionQDType,
9641 1, &qd_style, target);
9643 else
9644 err = SetFontInfoForSelection (kFontSelectionATSUIType,
9645 1, &font->mac_style, target);
9648 return err;
9650 #endif
9653 /* The Mac Event loop code */
9655 #if !TARGET_API_MAC_CARBON
9656 #include <Events.h>
9657 #include <Quickdraw.h>
9658 #include <Balloons.h>
9659 #include <Devices.h>
9660 #include <Fonts.h>
9661 #include <Gestalt.h>
9662 #include <Menus.h>
9663 #include <Processes.h>
9664 #include <Sound.h>
9665 #include <ToolUtils.h>
9666 #include <TextUtils.h>
9667 #include <Dialogs.h>
9668 #include <Script.h>
9669 #include <Types.h>
9670 #include <Resources.h>
9672 #if __MWERKS__
9673 #include <unix.h>
9674 #endif
9675 #endif /* ! TARGET_API_MAC_CARBON */
9677 #define M_APPLE 234
9678 #define I_ABOUT 1
9680 #define DEFAULT_NUM_COLS 80
9682 #define MIN_DOC_SIZE 64
9683 #define MAX_DOC_SIZE 32767
9685 #define EXTRA_STACK_ALLOC (256 * 1024)
9687 #define ARGV_STRING_LIST_ID 129
9688 #define ABOUT_ALERT_ID 128
9689 #define RAM_TOO_LARGE_ALERT_ID 129
9691 /* Contains the string "reverse", which is a constant for mouse button emu.*/
9692 Lisp_Object Qreverse;
9695 /* Modifier associated with the control key, or nil to ignore. */
9696 Lisp_Object Vmac_control_modifier;
9698 /* Modifier associated with the option key, or nil to ignore. */
9699 Lisp_Object Vmac_option_modifier;
9701 /* Modifier associated with the command key, or nil to ignore. */
9702 Lisp_Object Vmac_command_modifier;
9704 /* Modifier associated with the function key, or nil to ignore. */
9705 Lisp_Object Vmac_function_modifier;
9707 /* True if the option and command modifiers should be used to emulate
9708 a three button mouse */
9709 Lisp_Object Vmac_emulate_three_button_mouse;
9711 #if TARGET_API_MAC_CARBON
9712 /* Non-zero if the mouse wheel button (i.e. button 4) should map to
9713 mouse-2, instead of mouse-3. */
9714 int mac_wheel_button_is_mouse_2;
9716 /* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
9717 for processing before Emacs sees it. */
9718 int mac_pass_command_to_system;
9720 /* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
9721 for processing before Emacs sees it. */
9722 int mac_pass_control_to_system;
9723 #endif
9725 /* Points to the variable `inev' in the function XTread_socket. It is
9726 used for passing an input event to the function back from
9727 Carbon/Apple event handlers. */
9728 static struct input_event *read_socket_inev = NULL;
9730 /* Whether or not the screen configuration has changed. */
9731 static int mac_screen_config_changed = 0;
9733 Point saved_menu_event_location;
9735 /* Apple Events */
9736 #if TARGET_API_MAC_CARBON
9737 static Lisp_Object Qhi_command;
9738 #ifdef MAC_OSX
9739 extern Lisp_Object Qwindow;
9740 static Lisp_Object Qtoolbar_switch_mode;
9741 #endif
9742 #if USE_MAC_TSM
9743 static TSMDocumentID tsm_document_id;
9744 Lisp_Object Qtext_input;
9745 Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
9746 Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
9747 extern Lisp_Object Qbefore_string;
9748 static Lisp_Object Vmac_ts_script_language_on_focus;
9749 static Lisp_Object saved_ts_script_language_on_focus;
9750 static ScriptLanguageRecord saved_ts_language;
9751 static Component saved_ts_component;
9752 #endif
9753 #endif /* TARGET_API_MAC_CARBON */
9754 extern int mac_ready_for_apple_events;
9755 extern Lisp_Object Qundefined;
9756 extern void init_apple_event_handler P_ ((void));
9757 extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9758 Lisp_Object *, Lisp_Object *,
9759 Lisp_Object *));
9760 extern OSErr init_coercion_handler P_ ((void));
9762 /* Drag and Drop */
9763 extern OSErr install_drag_handler P_ ((WindowRef));
9764 extern void remove_drag_handler P_ ((WindowRef));
9766 #if TARGET_API_MAC_CARBON
9767 /* Showing help echo string during menu tracking */
9768 extern OSStatus install_menu_target_item_handler P_ ((void));
9770 #ifdef MAC_OSX
9771 extern OSStatus install_service_handler ();
9772 Lisp_Object Qservice, Qpaste, Qperform;
9773 Lisp_Object Qmouse_drag_overlay;
9774 #endif
9775 #endif
9777 extern void init_emacs_passwd_dir ();
9778 extern int emacs_main (int, char **, char **);
9780 extern void initialize_applescript();
9781 extern void terminate_applescript();
9783 /* Table for translating Mac keycode to X keysym values. Contributed
9784 by Sudhir Shenoy.
9785 Mapping for special keys is now identical to that in Apple X11
9786 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9787 on the right of the Cmd key on laptops, and fn + `enter' (->
9788 <linefeed>). */
9789 static const unsigned char keycode_to_xkeysym_table[] = {
9790 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9791 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9792 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9794 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9795 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9796 /*0x38*/ 0, 0, 0, 0,
9797 /*0x3C*/ 0, 0, 0, 0,
9799 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9800 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9801 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9802 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9804 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9805 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9806 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9807 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9809 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9810 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9811 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9812 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9814 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9815 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9816 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9817 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9820 #ifdef MAC_OSX
9821 /* Table for translating Mac keycode with the laptop `fn' key to that
9822 without it. Destination symbols in comments are keys on US
9823 keyboard, and they may not be the same on other types of keyboards.
9824 If the destination is identical to the source (f1 ... f12), it
9825 doesn't map `fn' key to a modifier. */
9826 static const unsigned char fn_keycode_to_keycode_table[] = {
9827 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9828 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9829 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9831 /*0x30*/ 0, 0, 0, 0,
9832 /*0x34*/ 0, 0, 0, 0,
9833 /*0x38*/ 0, 0, 0, 0,
9834 /*0x3C*/ 0, 0, 0, 0,
9836 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9837 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9838 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9839 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9841 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9842 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9843 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9844 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9846 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9847 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9848 /*0x68*/ 0, 0, 0, 0,
9849 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9851 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9852 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9853 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9854 /*0x7C*/ 0, 0, 0, 0
9856 #endif /* MAC_OSX */
9858 static int
9859 #if TARGET_API_MAC_CARBON
9860 mac_to_emacs_modifiers (UInt32 mods)
9861 #else
9862 mac_to_emacs_modifiers (EventModifiers mods)
9863 #endif
9865 unsigned int result = 0;
9866 if (mods & shiftKey)
9867 result |= shift_modifier;
9869 /* Deactivated to simplify configuration:
9870 if Vmac_option_modifier is non-NIL, we fully process the Option
9871 key. Otherwise, we only process it if an additional Ctrl or Command
9872 is pressed. That way the system may convert the character to a
9873 composed one.
9874 if ((mods & optionKey) &&
9875 (( !NILP(Vmac_option_modifier) ||
9876 ((mods & cmdKey) || (mods & controlKey))))) */
9878 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
9879 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9880 if (INTEGERP(val))
9881 result |= XUINT(val);
9883 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9884 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9885 if (INTEGERP(val))
9886 result |= XUINT(val);
9888 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9889 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9890 if (INTEGERP(val))
9891 result |= XUINT(val);
9894 #ifdef MAC_OSX
9895 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9896 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9897 if (INTEGERP(val))
9898 result |= XUINT(val);
9900 #endif
9902 return result;
9905 static UInt32
9906 mac_mapped_modifiers (modifiers)
9907 UInt32 modifiers;
9909 UInt32 mapped_modifiers_all =
9910 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9911 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9912 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9914 #ifdef MAC_OSX
9915 mapped_modifiers_all |=
9916 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9917 #endif
9919 return mapped_modifiers_all & modifiers;
9922 static int
9923 mac_get_emulated_btn ( UInt32 modifiers )
9925 int result = 0;
9926 if (!NILP (Vmac_emulate_three_button_mouse)) {
9927 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
9928 if (modifiers & cmdKey)
9929 result = cmdIs3 ? 2 : 1;
9930 else if (modifiers & optionKey)
9931 result = cmdIs3 ? 1 : 2;
9933 return result;
9936 #ifdef MAC_OSX
9937 void
9938 mac_get_selected_range (w, range)
9939 struct window *w;
9940 CFRange *range;
9942 Lisp_Object overlay = find_symbol_value (Qmouse_drag_overlay);
9943 struct buffer *b = XBUFFER (w->buffer);
9944 int begv = BUF_BEGV (b), zv = BUF_ZV (b);
9945 int start, end;
9947 if (OVERLAYP (overlay)
9948 && EQ (Foverlay_buffer (overlay), w->buffer)
9949 && (start = XINT (Foverlay_start (overlay)),
9950 end = XINT (Foverlay_end (overlay)),
9951 start != end))
9953 else
9955 if (w == XWINDOW (selected_window) && b == current_buffer)
9956 start = PT;
9957 else
9958 start = marker_position (w->pointm);
9960 if (NILP (Vtransient_mark_mode) || NILP (b->mark_active))
9961 end = start;
9962 else
9964 int mark_pos = marker_position (b->mark);
9966 if (start <= mark_pos)
9967 end = mark_pos;
9968 else
9970 end = start;
9971 start = mark_pos;
9976 if (start != end)
9978 if (start < begv)
9979 start = begv;
9980 else if (start > zv)
9981 start = zv;
9983 if (end < begv)
9984 end = begv;
9985 else if (end > zv)
9986 end = zv;
9989 range->location = start - begv;
9990 range->length = end - start;
9993 /* Store the text of the buffer BUF from START to END as Unicode
9994 characters in CHARACTERS. Return non-zero if successful. */
9997 mac_store_buffer_text_to_unicode_chars (buf, start, end, characters)
9998 struct buffer *buf;
9999 int start, end;
10000 UniChar *characters;
10002 int start_byte, end_byte, char_count, byte_count;
10003 struct coding_system coding;
10004 unsigned char *dst = (unsigned char *) characters;
10006 start_byte = buf_charpos_to_bytepos (buf, start);
10007 end_byte = buf_charpos_to_bytepos (buf, end);
10008 char_count = end - start;
10009 byte_count = end_byte - start_byte;
10011 if (setup_coding_system (
10012 #ifdef WORDS_BIG_ENDIAN
10013 intern ("utf-16be")
10014 #else
10015 intern ("utf-16le")
10016 #endif
10017 , &coding) < 0)
10018 return 0;
10020 coding.src_multibyte = !NILP (buf->enable_multibyte_characters);
10021 coding.dst_multibyte = 0;
10022 coding.mode |= CODING_MODE_LAST_BLOCK;
10023 coding.composing = COMPOSITION_DISABLED;
10025 if (BUF_GPT_BYTE (buf) <= start_byte || end_byte <= BUF_GPT_BYTE (buf))
10026 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10027 byte_count, char_count * sizeof (UniChar));
10028 else
10030 int first_byte_count = BUF_GPT_BYTE (buf) - start_byte;
10032 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10033 first_byte_count, char_count * sizeof (UniChar));
10034 if (coding.result == CODING_FINISH_NORMAL)
10035 encode_coding (&coding,
10036 BUF_BYTE_ADDRESS (buf, start_byte + first_byte_count),
10037 dst + coding.produced,
10038 byte_count - first_byte_count,
10039 char_count * sizeof (UniChar) - coding.produced);
10042 if (coding.result != CODING_FINISH_NORMAL)
10043 return 0;
10045 return 1;
10048 void
10049 mac_ax_selected_text_range (f, range)
10050 struct frame *f;
10051 CFRange *range;
10053 mac_get_selected_range (XWINDOW (f->selected_window), range);
10056 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
10057 unsigned int
10058 mac_ax_number_of_characters (f)
10059 struct frame *f;
10061 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
10063 return BUF_ZV (b) - BUF_BEGV (b);
10065 #endif
10066 #endif
10068 #if USE_MAC_TSM
10069 OSStatus
10070 mac_restore_keyboard_input_source ()
10072 OSStatus err = noErr;
10073 ScriptLanguageRecord slrec, *slptr = NULL;
10075 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10076 && EQ (saved_ts_script_language_on_focus, Qt))
10077 slptr = &saved_ts_language;
10078 else if (CONSP (Vmac_ts_script_language_on_focus)
10079 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10080 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10081 && CONSP (saved_ts_script_language_on_focus)
10082 && EQ (XCAR (saved_ts_script_language_on_focus),
10083 XCAR (Vmac_ts_script_language_on_focus))
10084 && EQ (XCDR (saved_ts_script_language_on_focus),
10085 XCDR (Vmac_ts_script_language_on_focus)))
10087 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10088 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10089 slptr = &slrec;
10092 if (slptr)
10094 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10095 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10096 kKeyboardInputMethodClass);
10097 #else
10098 err = SetDefaultInputMethod (saved_ts_component, slptr);
10099 #endif
10100 if (err == noErr)
10101 err = SetTextServiceLanguage (slptr);
10103 /* Seems to be needed on Mac OS X 10.2. */
10104 if (err == noErr)
10105 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10108 return err;
10111 void
10112 mac_save_keyboard_input_source ()
10114 OSStatus err;
10115 ScriptLanguageRecord slrec, *slptr = NULL;
10117 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10119 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10121 err = GetTextServiceLanguage (&saved_ts_language);
10122 if (err == noErr)
10123 slptr = &saved_ts_language;
10125 else if (CONSP (Vmac_ts_script_language_on_focus)
10126 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10127 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10129 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10130 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10131 slptr = &slrec;
10134 if (slptr)
10136 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10137 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10138 kKeyboardInputMethodClass);
10139 #else
10140 GetDefaultInputMethod (&saved_ts_component, slptr);
10141 #endif
10144 #endif
10146 #if TARGET_API_MAC_CARBON
10147 /***** Code to handle C-g testing *****/
10148 extern int quit_char;
10149 extern int make_ctrl_char P_ ((int));
10152 mac_quit_char_key_p (modifiers, key_code)
10153 UInt32 modifiers, key_code;
10155 UInt32 char_code;
10156 unsigned long some_state = 0;
10157 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10158 int c, emacs_modifiers;
10160 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
10161 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
10162 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
10163 if (char_code & ~0xff)
10164 return 0;
10166 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
10167 if (emacs_modifiers & ctrl_modifier)
10168 c = make_ctrl_char (char_code);
10170 c |= (emacs_modifiers
10171 & (meta_modifier | alt_modifier
10172 | hyper_modifier | super_modifier));
10174 return c == quit_char;
10176 #endif
10178 #if TARGET_API_MAC_CARBON
10179 /* Obtains the event modifiers from the event ref and then calls
10180 mac_to_emacs_modifiers. */
10181 static int
10182 mac_event_to_emacs_modifiers (EventRef eventRef)
10184 UInt32 mods = 0, class;
10186 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
10187 sizeof (UInt32), NULL, &mods);
10188 class = GetEventClass (eventRef);
10189 if (!NILP (Vmac_emulate_three_button_mouse) &&
10190 (class == kEventClassMouse || class == kEventClassCommand))
10192 mods &= ~(optionKey | cmdKey);
10194 return mac_to_emacs_modifiers (mods);
10197 /* Given an event ref, return the code to use for the mouse button
10198 code in the emacs input_event. */
10199 static int
10200 mac_get_mouse_btn (EventRef ref)
10202 EventMouseButton result = kEventMouseButtonPrimary;
10203 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
10204 sizeof (EventMouseButton), NULL, &result);
10205 switch (result)
10207 case kEventMouseButtonPrimary:
10208 if (NILP (Vmac_emulate_three_button_mouse))
10209 return 0;
10210 else {
10211 UInt32 mods = 0;
10212 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
10213 sizeof (UInt32), NULL, &mods);
10214 return mac_get_emulated_btn(mods);
10216 case kEventMouseButtonSecondary:
10217 return mac_wheel_button_is_mouse_2 ? 2 : 1;
10218 case kEventMouseButtonTertiary:
10219 case 4: /* 4 is the number for the mouse wheel button */
10220 return mac_wheel_button_is_mouse_2 ? 1 : 2;
10221 default:
10222 return 0;
10226 /* Normally, ConvertEventRefToEventRecord will correctly handle all
10227 events. However the click of the mouse wheel is not converted to a
10228 mouseDown or mouseUp event. Likewise for dead key events. This
10229 calls ConvertEventRefToEventRecord, but then checks to see if it is
10230 a mouse up/down, or a dead key Carbon event that has not been
10231 converted, and if so, converts it by hand (to be picked up in the
10232 XTread_socket loop). */
10233 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
10235 OSStatus err;
10236 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
10237 EventKind action;
10239 if (result)
10240 return result;
10242 switch (GetEventClass (eventRef))
10244 case kEventClassMouse:
10245 switch (GetEventKind (eventRef))
10247 case kEventMouseDown:
10248 eventRec->what = mouseDown;
10249 result = 1;
10250 break;
10252 case kEventMouseUp:
10253 eventRec->what = mouseUp;
10254 result = 1;
10255 break;
10257 default:
10258 break;
10260 break;
10262 case kEventClassKeyboard:
10263 switch (GetEventKind (eventRef))
10265 case kEventRawKeyDown:
10266 action = keyDown;
10267 goto keystroke_common;
10268 case kEventRawKeyRepeat:
10269 action = autoKey;
10270 goto keystroke_common;
10271 case kEventRawKeyUp:
10272 action = keyUp;
10273 keystroke_common:
10275 unsigned char char_codes;
10276 UInt32 key_code;
10278 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
10279 typeChar, NULL, sizeof (char),
10280 NULL, &char_codes);
10281 if (err == noErr)
10282 err = GetEventParameter (eventRef, kEventParamKeyCode,
10283 typeUInt32, NULL, sizeof (UInt32),
10284 NULL, &key_code);
10285 if (err == noErr)
10287 eventRec->what = action;
10288 eventRec->message = char_codes | ((key_code & 0xff) << 8);
10289 result = 1;
10292 break;
10294 default:
10295 break;
10297 break;
10299 default:
10300 break;
10303 if (result)
10305 /* Need where and when. */
10306 UInt32 mods = 0;
10308 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
10309 NULL, sizeof (Point), NULL, &eventRec->where);
10310 /* Use two step process because new event modifiers are 32-bit
10311 and old are 16-bit. Currently, only loss is NumLock & Fn. */
10312 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
10313 NULL, sizeof (UInt32), NULL, &mods);
10314 eventRec->modifiers = mods;
10316 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
10319 return result;
10322 #endif
10324 #ifdef MAC_OS8
10325 static void
10326 do_get_menus (void)
10328 Handle menubar_handle;
10329 MenuRef menu;
10331 menubar_handle = GetNewMBar (128);
10332 if(menubar_handle == NULL)
10333 abort ();
10334 SetMenuBar (menubar_handle);
10335 DrawMenuBar ();
10337 #if !TARGET_API_MAC_CARBON
10338 menu = GetMenuRef (M_APPLE);
10339 if (menu != NULL)
10340 AppendResMenu (menu, 'DRVR');
10341 else
10342 abort ();
10343 #endif
10347 static void
10348 do_init_managers (void)
10350 #if !TARGET_API_MAC_CARBON
10351 InitGraf (&qd.thePort);
10352 InitFonts ();
10353 FlushEvents (everyEvent, 0);
10354 InitWindows ();
10355 InitMenus ();
10356 TEInit ();
10357 InitDialogs (NULL);
10358 #endif /* !TARGET_API_MAC_CARBON */
10359 InitCursor ();
10361 #if !TARGET_API_MAC_CARBON
10362 /* set up some extra stack space for use by emacs */
10363 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10365 /* MaxApplZone must be called for AppleScript to execute more
10366 complicated scripts */
10367 MaxApplZone ();
10368 MoreMasters ();
10369 #endif /* !TARGET_API_MAC_CARBON */
10372 static void
10373 do_check_ram_size (void)
10375 SInt32 physical_ram_size, logical_ram_size;
10377 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10378 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
10379 || physical_ram_size > (1 << VALBITS)
10380 || logical_ram_size > (1 << VALBITS))
10382 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10383 exit (1);
10386 #endif /* MAC_OS8 */
10388 static void
10389 do_window_update (WindowRef win)
10391 struct frame *f = mac_window_to_frame (win);
10393 BeginUpdate (win);
10395 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10396 below. */
10397 if (win != tip_window)
10399 if (f->async_visible == 0)
10401 /* Update events may occur when a frame gets iconified. */
10402 #if 0
10403 f->async_visible = 1;
10404 f->async_iconified = 0;
10405 SET_FRAME_GARBAGED (f);
10406 #endif
10408 else
10410 Rect r;
10411 #if TARGET_API_MAC_CARBON
10412 RgnHandle region = NewRgn ();
10414 GetPortVisibleRegion (GetWindowPort (win), region);
10415 GetRegionBounds (region, &r);
10416 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10417 #if USE_CG_DRAWING
10418 mac_prepare_for_quickdraw (f);
10419 #endif
10420 UpdateControls (win, region);
10421 DisposeRgn (region);
10422 #else
10423 r = (*win->visRgn)->rgnBBox;
10424 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10425 UpdateControls (win, win->visRgn);
10426 #endif
10430 EndUpdate (win);
10433 static int
10434 is_emacs_window (WindowRef win)
10436 Lisp_Object tail, frame;
10438 if (!win)
10439 return 0;
10441 FOR_EACH_FRAME (tail, frame)
10442 if (FRAME_MAC_P (XFRAME (frame)))
10443 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10444 return 1;
10446 return 0;
10449 #if USE_MAC_TSM
10450 static OSStatus
10451 mac_tsm_resume ()
10453 OSStatus err;
10454 ScriptLanguageRecord slrec, *slptr = NULL;
10456 err = ActivateTSMDocument (tsm_document_id);
10458 if (err == noErr)
10460 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10461 && EQ (saved_ts_script_language_on_focus, Qt))
10462 slptr = &saved_ts_language;
10463 else if (CONSP (Vmac_ts_script_language_on_focus)
10464 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10465 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10466 && CONSP (saved_ts_script_language_on_focus)
10467 && EQ (XCAR (saved_ts_script_language_on_focus),
10468 XCAR (Vmac_ts_script_language_on_focus))
10469 && EQ (XCDR (saved_ts_script_language_on_focus),
10470 XCDR (Vmac_ts_script_language_on_focus)))
10472 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10473 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10474 slptr = &slrec;
10478 if (slptr)
10480 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10481 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10482 kKeyboardInputMethodClass);
10483 #else
10484 err = SetDefaultInputMethod (saved_ts_component, slptr);
10485 #endif
10486 if (err == noErr)
10487 err = SetTextServiceLanguage (slptr);
10489 /* Seems to be needed on Mac OS X 10.2. */
10490 if (err == noErr)
10491 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10494 return err;
10497 static OSStatus
10498 mac_tsm_suspend ()
10500 OSStatus err;
10501 ScriptLanguageRecord slrec, *slptr = NULL;
10503 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10505 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10507 err = GetTextServiceLanguage (&saved_ts_language);
10508 if (err == noErr)
10509 slptr = &saved_ts_language;
10511 else if (CONSP (Vmac_ts_script_language_on_focus)
10512 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10513 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10515 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10516 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10517 slptr = &slrec;
10520 if (slptr)
10522 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10523 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10524 kKeyboardInputMethodClass);
10525 #else
10526 GetDefaultInputMethod (&saved_ts_component, slptr);
10527 #endif
10530 err = DeactivateTSMDocument (tsm_document_id);
10532 return err;
10534 #endif
10536 #if !TARGET_API_MAC_CARBON
10537 void
10538 do_apple_menu (SInt16 menu_item)
10540 Str255 item_name;
10541 SInt16 da_driver_refnum;
10543 if (menu_item == I_ABOUT)
10544 NoteAlert (ABOUT_ALERT_ID, NULL);
10545 else
10547 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
10548 da_driver_refnum = OpenDeskAcc (item_name);
10551 #endif /* !TARGET_API_MAC_CARBON */
10553 /* Handle drags in size box. Based on code contributed by Ben
10554 Mesander and IM - Window Manager A. */
10556 static void
10557 do_grow_window (w, e)
10558 WindowRef w;
10559 const EventRecord *e;
10561 Rect limit_rect;
10562 int rows, columns, width, height;
10563 struct frame *f = mac_window_to_frame (w);
10564 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10565 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10566 #if TARGET_API_MAC_CARBON
10567 Rect new_rect;
10568 #else
10569 long grow_size;
10570 #endif
10572 if (size_hints->flags & PMinSize)
10574 min_width = size_hints->min_width;
10575 min_height = size_hints->min_height;
10577 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
10579 #if TARGET_API_MAC_CARBON
10580 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10581 return;
10582 height = new_rect.bottom - new_rect.top;
10583 width = new_rect.right - new_rect.left;
10584 #else
10585 grow_size = GrowWindow (w, e->where, &limit_rect);
10586 /* see if it really changed size */
10587 if (grow_size == 0)
10588 return;
10589 height = HiWord (grow_size);
10590 width = LoWord (grow_size);
10591 #endif
10593 if (width != FRAME_PIXEL_WIDTH (f)
10594 || height != FRAME_PIXEL_HEIGHT (f))
10596 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10597 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10599 x_set_window_size (f, 0, columns, rows);
10604 #if TARGET_API_MAC_CARBON
10605 static Point
10606 mac_get_ideal_size (f)
10607 struct frame *f;
10609 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10610 WindowRef w = FRAME_MAC_WINDOW (f);
10611 Point ideal_size;
10612 Rect standard_rect;
10613 int height, width, columns, rows;
10615 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10616 ideal_size.v = dpyinfo->height;
10617 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10618 /* Adjust the standard size according to character boundaries. */
10619 width = standard_rect.right - standard_rect.left;
10620 height = standard_rect.bottom - standard_rect.top;
10621 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10622 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10623 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10624 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10626 return ideal_size;
10628 #endif
10630 /* Handle clicks in zoom box. Calculation of "standard state" based
10631 on code in IM - Window Manager A and code contributed by Ben
10632 Mesander. The standard state of an Emacs window is 80-characters
10633 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10635 static void
10636 do_zoom_window (WindowRef w, int zoom_in_or_out)
10638 Rect zoom_rect, port_rect;
10639 int width, height;
10640 struct frame *f = mac_window_to_frame (w);
10641 #if TARGET_API_MAC_CARBON
10642 Point ideal_size = mac_get_ideal_size (f);
10644 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10645 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10646 && port_rect.left == zoom_rect.left
10647 && port_rect.top == zoom_rect.top)
10648 zoom_in_or_out = inZoomIn;
10649 else
10650 zoom_in_or_out = inZoomOut;
10652 #ifdef MAC_OS8
10653 mac_clear_window (f);
10654 #endif
10655 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
10656 #else /* not TARGET_API_MAC_CARBON */
10657 GrafPtr save_port;
10658 Point top_left;
10659 int w_title_height, rows;
10660 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10662 GetPort (&save_port);
10664 SetPortWindowPort (w);
10666 /* Clear window to avoid flicker. */
10667 EraseRect (&(w->portRect));
10668 if (zoom_in_or_out == inZoomOut)
10670 SetPt (&top_left, w->portRect.left, w->portRect.top);
10671 LocalToGlobal (&top_left);
10673 /* calculate height of window's title bar */
10674 w_title_height = top_left.v - 1
10675 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
10677 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10678 zoom_rect = qd.screenBits.bounds;
10679 zoom_rect.top += w_title_height;
10680 InsetRect (&zoom_rect, 8, 4); /* not too tight */
10682 zoom_rect.right = zoom_rect.left
10683 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10685 /* Adjust the standard size according to character boundaries. */
10686 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10687 zoom_rect.bottom =
10688 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10690 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10691 = zoom_rect;
10694 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
10696 SetPort (save_port);
10697 #endif /* not TARGET_API_MAC_CARBON */
10699 #if !TARGET_API_MAC_CARBON
10700 /* retrieve window size and update application values */
10701 port_rect = w->portRect;
10702 height = port_rect.bottom - port_rect.top;
10703 width = port_rect.right - port_rect.left;
10705 mac_handle_size_change (f, width, height);
10706 mac_handle_origin_change (f);
10707 #endif
10710 static void
10711 mac_set_unicode_keystroke_event (code, buf)
10712 UniChar code;
10713 struct input_event *buf;
10715 int charset_id, c1, c2;
10717 if (code < 0x80)
10719 buf->kind = ASCII_KEYSTROKE_EVENT;
10720 buf->code = code;
10722 else if (code < 0x100)
10724 if (code < 0xA0)
10725 charset_id = CHARSET_8_BIT_CONTROL;
10726 else
10727 charset_id = charset_latin_iso8859_1;
10728 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10729 buf->code = MAKE_CHAR (charset_id, code, 0);
10731 else
10733 if (code < 0x2500)
10734 charset_id = charset_mule_unicode_0100_24ff,
10735 code -= 0x100;
10736 else if (code < 0x33FF)
10737 charset_id = charset_mule_unicode_2500_33ff,
10738 code -= 0x2500;
10739 else if (code >= 0xE000)
10740 charset_id = charset_mule_unicode_e000_ffff,
10741 code -= 0xE000;
10742 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10743 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10744 buf->code = MAKE_CHAR (charset_id, c1, c2);
10748 static void
10749 do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10750 EventKind action;
10751 unsigned char char_code;
10752 UInt32 key_code, modifiers;
10753 unsigned long timestamp;
10754 struct input_event *buf;
10756 static SInt16 last_key_script = -1;
10757 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10758 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10760 #ifdef MAC_OSX
10761 if (mapped_modifiers & kEventKeyModifierFnMask
10762 && key_code <= 0x7f
10763 && fn_keycode_to_keycode_table[key_code])
10764 key_code = fn_keycode_to_keycode_table[key_code];
10765 #endif
10767 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10769 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10770 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10771 #ifdef MAC_OSX
10772 if (modifiers & kEventKeyModifierFnMask
10773 && key_code <= 0x7f
10774 && fn_keycode_to_keycode_table[key_code] == key_code)
10775 modifiers &= ~kEventKeyModifierFnMask;
10776 #endif
10778 else if (mapped_modifiers)
10780 /* translate the keycode back to determine the original key */
10781 #ifdef MAC_OSX
10782 UCKeyboardLayout *uchr_ptr = NULL;
10783 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10784 OSStatus err;
10785 KeyboardLayoutRef layout;
10787 err = KLGetCurrentKeyboardLayout (&layout);
10788 if (err == noErr)
10789 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10790 (const void **) &uchr_ptr);
10791 #else
10792 static SInt16 last_key_layout_id = 0;
10793 static Handle uchr_handle = (Handle)-1;
10794 SInt16 current_key_layout_id =
10795 GetScriptVariable (current_key_script, smScriptKeys);
10797 if (uchr_handle == (Handle)-1
10798 || last_key_layout_id != current_key_layout_id)
10800 uchr_handle = GetResource ('uchr', current_key_layout_id);
10801 last_key_layout_id = current_key_layout_id;
10803 if (uchr_handle)
10804 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10805 #endif
10807 if (uchr_ptr)
10809 OSStatus status;
10810 UInt16 key_action = action - keyDown;
10811 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10812 UInt32 keyboard_type = LMGetKbdType ();
10813 SInt32 dead_key_state = 0;
10814 UniChar code;
10815 UniCharCount actual_length;
10817 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10818 modifier_key_state, keyboard_type,
10819 kUCKeyTranslateNoDeadKeysMask,
10820 &dead_key_state,
10821 1, &actual_length, &code);
10822 if (status == noErr && actual_length == 1)
10823 mac_set_unicode_keystroke_event (code, buf);
10825 #endif /* MAC_OSX */
10827 if (buf->kind == NO_EVENT)
10829 /* This code comes from Keyboard Resource, Appendix C of IM
10830 - Text. This is necessary since shift is ignored in KCHR
10831 table translation when option or command is pressed. It
10832 also does not translate correctly control-shift chars
10833 like C-% so mask off shift here also. */
10834 /* Mask off modifier keys that are mapped to some Emacs
10835 modifiers. */
10836 int new_modifiers = modifiers & ~mapped_modifiers;
10837 /* set high byte of keycode to modifier high byte*/
10838 int new_key_code = key_code | new_modifiers;
10839 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10840 unsigned long some_state = 0;
10841 UInt32 new_char_code;
10843 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10844 if (new_char_code == 0)
10845 /* Seems like a dead key. Append up-stroke. */
10846 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10847 &some_state);
10848 if (new_char_code)
10850 buf->kind = ASCII_KEYSTROKE_EVENT;
10851 buf->code = new_char_code & 0xff;
10856 if (buf->kind == NO_EVENT)
10858 buf->kind = ASCII_KEYSTROKE_EVENT;
10859 buf->code = char_code;
10862 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10863 buf->modifiers |= (extra_keyboard_modifiers
10864 & (meta_modifier | alt_modifier
10865 | hyper_modifier | super_modifier));
10867 #if TARGET_API_MAC_CARBON
10868 if (buf->kind == ASCII_KEYSTROKE_EVENT
10869 && buf->code >= 0x80 && buf->modifiers)
10871 OSStatus err;
10872 TextEncoding encoding = kTextEncodingMacRoman;
10873 TextToUnicodeInfo ttu_info;
10875 UpgradeScriptInfoToTextEncoding (current_key_script,
10876 kTextLanguageDontCare,
10877 kTextRegionDontCare,
10878 NULL, &encoding);
10879 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10880 if (err == noErr)
10882 UniChar code;
10883 Str255 pstr;
10884 ByteCount unicode_len;
10886 pstr[0] = 1;
10887 pstr[1] = buf->code;
10888 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10889 sizeof (UniChar),
10890 &unicode_len, &code);
10891 if (err == noErr && unicode_len == sizeof (UniChar))
10892 mac_set_unicode_keystroke_event (code, buf);
10893 DisposeTextToUnicodeInfo (&ttu_info);
10896 #endif
10898 if (buf->kind == ASCII_KEYSTROKE_EVENT
10899 && buf->code >= 0x80
10900 && last_key_script != current_key_script)
10902 struct input_event event;
10904 EVENT_INIT (event);
10905 event.kind = LANGUAGE_CHANGE_EVENT;
10906 event.arg = Qnil;
10907 event.code = current_key_script;
10908 event.timestamp = timestamp;
10909 kbd_buffer_store_event (&event);
10910 last_key_script = current_key_script;
10914 void
10915 mac_store_apple_event (class, id, desc)
10916 Lisp_Object class, id;
10917 const AEDesc *desc;
10919 struct input_event buf;
10921 EVENT_INIT (buf);
10923 buf.kind = MAC_APPLE_EVENT;
10924 buf.x = class;
10925 buf.y = id;
10926 XSETFRAME (buf.frame_or_window,
10927 mac_focus_frame (&one_mac_display_info));
10928 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10929 is safe to use them during read_socket_hook. */
10930 buf.arg = mac_aedesc_to_lisp (desc);
10931 kbd_buffer_store_event (&buf);
10934 #if TARGET_API_MAC_CARBON
10935 static OSStatus
10936 mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10937 event, num_params, names, types)
10938 AEEventClass class;
10939 AEEventID id;
10940 Lisp_Object class_key, id_key;
10941 EventRef event;
10942 UInt32 num_params;
10943 const EventParamName *names;
10944 const EventParamType *types;
10946 OSStatus err = eventNotHandledErr;
10947 Lisp_Object binding;
10949 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10950 if (!NILP (binding) && !EQ (binding, Qundefined))
10952 if (INTEGERP (binding))
10953 err = XINT (binding);
10954 else
10956 AppleEvent apple_event;
10957 err = create_apple_event_from_event_ref (event, num_params,
10958 names, types,
10959 &apple_event);
10960 if (err == noErr)
10962 mac_store_apple_event (class_key, id_key, &apple_event);
10963 AEDisposeDesc (&apple_event);
10964 mac_wakeup_from_rne ();
10969 return err;
10972 void
10973 mac_store_drag_event (window, mouse_pos, modifiers, desc)
10974 WindowRef window;
10975 Point mouse_pos;
10976 SInt16 modifiers;
10977 const AEDesc *desc;
10979 struct input_event buf;
10981 EVENT_INIT (buf);
10983 buf.kind = DRAG_N_DROP_EVENT;
10984 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10985 buf.timestamp = TickCount () * (1000 / 60);
10986 XSETINT (buf.x, mouse_pos.h);
10987 XSETINT (buf.y, mouse_pos.v);
10988 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10989 buf.arg = mac_aedesc_to_lisp (desc);
10990 kbd_buffer_store_event (&buf);
10993 #ifdef MAC_OSX
10994 OSStatus
10995 mac_store_service_event (event)
10996 EventRef event;
10998 OSStatus err;
10999 Lisp_Object id_key;
11000 int num_params;
11001 const EventParamName *names;
11002 const EventParamType *types;
11003 static const EventParamName names_pfm[] =
11004 {kEventParamServiceMessageName, kEventParamServiceUserData};
11005 static const EventParamType types_pfm[] =
11006 {typeCFStringRef, typeCFStringRef};
11008 switch (GetEventKind (event))
11010 case kEventServicePaste:
11011 id_key = Qpaste;
11012 num_params = 0;
11013 names = NULL;
11014 types = NULL;
11015 break;
11017 case kEventServicePerform:
11018 id_key = Qperform;
11019 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
11020 names = names_pfm;
11021 types = types_pfm;
11022 break;
11024 default:
11025 abort ();
11028 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
11029 event, num_params,
11030 names, types);
11032 return err;
11034 #endif /* MAC_OSX */
11036 static pascal OSStatus
11037 mac_handle_window_event (next_handler, event, data)
11038 EventHandlerCallRef next_handler;
11039 EventRef event;
11040 void *data;
11042 WindowRef wp;
11043 OSStatus err, result = eventNotHandledErr;
11044 struct frame *f;
11045 UInt32 attributes;
11046 XSizeHints *size_hints;
11048 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
11049 NULL, sizeof (WindowRef), NULL, &wp);
11050 if (err != noErr)
11051 return eventNotHandledErr;
11053 f = mac_window_to_frame (wp);
11054 switch (GetEventKind (event))
11056 /* -- window refresh events -- */
11058 case kEventWindowUpdate:
11059 result = CallNextEventHandler (next_handler, event);
11060 if (result != eventNotHandledErr)
11061 break;
11063 do_window_update (wp);
11064 result = noErr;
11065 break;
11067 /* -- window state change events -- */
11069 case kEventWindowShowing:
11070 size_hints = FRAME_SIZE_HINTS (f);
11071 if (!(size_hints->flags & (USPosition | PPosition)))
11073 struct frame *sf = SELECTED_FRAME ();
11075 if (!(FRAME_MAC_P (sf) && sf->async_visible))
11076 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
11077 else
11079 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
11080 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
11081 kWindowCascadeStartAtParentWindowScreen
11082 #else
11083 kWindowCascadeOnParentWindowScreen
11084 #endif
11086 #if USE_MAC_TOOLBAR
11087 /* This is a workaround. RepositionWindow fails to put
11088 a window at the cascading position when its parent
11089 window has a Carbon HIToolbar. */
11090 if ((f->left_pos == sf->left_pos
11091 && f->top_pos == sf->top_pos)
11092 || (f->left_pos == sf->left_pos + 10 * 2
11093 && f->top_pos == sf->top_pos + 32 * 2))
11094 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
11095 #endif
11097 result = noErr;
11099 break;
11101 case kEventWindowHiding:
11102 /* Before unmapping the window, update the WM_SIZE_HINTS
11103 property to claim that the current position of the window is
11104 user-specified, rather than program-specified, so that when
11105 the window is mapped again, it will be placed at the same
11106 location, without forcing the user to position it by hand
11107 again (they have already done that once for this window.) */
11108 x_wm_set_size_hint (f, (long) 0, 1);
11109 result = noErr;
11110 break;
11112 case kEventWindowShown:
11113 case kEventWindowHidden:
11114 case kEventWindowCollapsed:
11115 case kEventWindowExpanded:
11116 mac_handle_visibility_change (f);
11117 result = noErr;
11118 break;
11120 case kEventWindowBoundsChanging:
11121 result = CallNextEventHandler (next_handler, event);
11122 if (result != eventNotHandledErr)
11123 break;
11125 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11126 NULL, sizeof (UInt32), NULL, &attributes);
11127 if (err != noErr)
11128 break;
11130 size_hints = FRAME_SIZE_HINTS (f);
11131 if ((attributes & kWindowBoundsChangeUserResize)
11132 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
11133 == (PResizeInc | PBaseSize | PMinSize)))
11135 Rect bounds;
11136 int width, height;
11138 err = GetEventParameter (event, kEventParamCurrentBounds,
11139 typeQDRectangle, NULL, sizeof (Rect),
11140 NULL, &bounds);
11141 if (err != noErr)
11142 break;
11144 width = bounds.right - bounds.left;
11145 height = bounds.bottom - bounds.top;
11147 if (width < size_hints->min_width)
11148 width = size_hints->min_width;
11149 else
11150 width = size_hints->base_width
11151 + (int) ((width - size_hints->base_width)
11152 / (float) size_hints->width_inc + .5)
11153 * size_hints->width_inc;
11155 if (height < size_hints->min_height)
11156 height = size_hints->min_height;
11157 else
11158 height = size_hints->base_height
11159 + (int) ((height - size_hints->base_height)
11160 / (float) size_hints->height_inc + .5)
11161 * size_hints->height_inc;
11163 bounds.right = bounds.left + width;
11164 bounds.bottom = bounds.top + height;
11165 SetEventParameter (event, kEventParamCurrentBounds,
11166 typeQDRectangle, sizeof (Rect), &bounds);
11167 result = noErr;
11169 break;
11171 case kEventWindowBoundsChanged:
11172 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11173 NULL, sizeof (UInt32), NULL, &attributes);
11174 if (err != noErr)
11175 break;
11177 if (attributes & kWindowBoundsChangeSizeChanged)
11179 Rect bounds;
11181 err = GetEventParameter (event, kEventParamCurrentBounds,
11182 typeQDRectangle, NULL, sizeof (Rect),
11183 NULL, &bounds);
11184 if (err == noErr)
11186 int width, height;
11188 width = bounds.right - bounds.left;
11189 height = bounds.bottom - bounds.top;
11190 mac_handle_size_change (f, width, height);
11191 mac_wakeup_from_rne ();
11195 if (attributes & kWindowBoundsChangeOriginChanged)
11196 mac_handle_origin_change (f);
11198 result = noErr;
11199 break;
11201 /* -- window action events -- */
11203 case kEventWindowClose:
11205 struct input_event buf;
11207 EVENT_INIT (buf);
11208 buf.kind = DELETE_WINDOW_EVENT;
11209 XSETFRAME (buf.frame_or_window, f);
11210 buf.arg = Qnil;
11211 kbd_buffer_store_event (&buf);
11213 result = noErr;
11214 break;
11216 case kEventWindowGetIdealSize:
11217 result = CallNextEventHandler (next_handler, event);
11218 if (result != eventNotHandledErr)
11219 break;
11222 Point ideal_size = mac_get_ideal_size (f);
11224 err = SetEventParameter (event, kEventParamDimensions,
11225 typeQDPoint, sizeof (Point), &ideal_size);
11226 if (err == noErr)
11227 result = noErr;
11229 break;
11231 #ifdef MAC_OSX
11232 case kEventWindowToolbarSwitchMode:
11234 static const EventParamName names[] = {kEventParamDirectObject,
11235 kEventParamWindowMouseLocation,
11236 kEventParamKeyModifiers,
11237 kEventParamMouseButton,
11238 kEventParamClickCount,
11239 kEventParamMouseChord};
11240 static const EventParamType types[] = {typeWindowRef,
11241 typeQDPoint,
11242 typeUInt32,
11243 typeMouseButton,
11244 typeUInt32,
11245 typeUInt32};
11246 int num_params = sizeof (names) / sizeof (names[0]);
11248 err = mac_store_event_ref_as_apple_event (0, 0,
11249 Qwindow,
11250 Qtoolbar_switch_mode,
11251 event, num_params,
11252 names, types);
11254 if (err == noErr)
11255 result = noErr;
11256 break;
11257 #endif
11259 #if USE_MAC_TSM
11260 /* -- window focus events -- */
11262 case kEventWindowFocusAcquired:
11263 err = mac_tsm_resume ();
11264 if (err == noErr)
11265 result = noErr;
11266 break;
11268 case kEventWindowFocusRelinquish:
11269 err = mac_tsm_suspend ();
11270 if (err == noErr)
11271 result = noErr;
11272 break;
11273 #endif
11275 default:
11276 abort ();
11279 return result;
11282 static pascal OSStatus
11283 mac_handle_application_event (next_handler, event, data)
11284 EventHandlerCallRef next_handler;
11285 EventRef event;
11286 void *data;
11288 OSStatus err, result = eventNotHandledErr;
11290 switch (GetEventKind (event))
11292 #if USE_MAC_TSM
11293 case kEventAppActivated:
11294 err = mac_tsm_resume ();
11295 break;
11297 case kEventAppDeactivated:
11298 err = mac_tsm_suspend ();
11299 break;
11300 #endif
11302 default:
11303 abort ();
11306 if (err == noErr)
11307 result = noErr;
11309 return result;
11312 static pascal OSStatus
11313 mac_handle_keyboard_event (next_handler, event, data)
11314 EventHandlerCallRef next_handler;
11315 EventRef event;
11316 void *data;
11318 OSStatus err, result = eventNotHandledErr;
11319 UInt32 event_kind, key_code, modifiers;
11320 unsigned char char_code;
11322 event_kind = GetEventKind (event);
11323 switch (event_kind)
11325 case kEventRawKeyDown:
11326 case kEventRawKeyRepeat:
11327 case kEventRawKeyUp:
11328 /* When using Carbon Events, we need to pass raw keyboard events
11329 to the TSM ourselves. If TSM handles it, it will pass back
11330 noErr, otherwise it will pass back "eventNotHandledErr" and
11331 we can process it normally. */
11332 result = CallNextEventHandler (next_handler, event);
11333 if (result != eventNotHandledErr)
11334 break;
11336 if (read_socket_inev == NULL)
11337 break;
11339 #if USE_MAC_TSM
11340 if (read_socket_inev->kind != NO_EVENT)
11342 result = noErr;
11343 break;
11345 #endif
11347 if (event_kind == kEventRawKeyUp)
11348 break;
11350 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11351 typeChar, NULL,
11352 sizeof (char), NULL, &char_code);
11353 if (err != noErr)
11354 break;
11356 err = GetEventParameter (event, kEventParamKeyCode,
11357 typeUInt32, NULL,
11358 sizeof (UInt32), NULL, &key_code);
11359 if (err != noErr)
11360 break;
11362 err = GetEventParameter (event, kEventParamKeyModifiers,
11363 typeUInt32, NULL,
11364 sizeof (UInt32), NULL, &modifiers);
11365 if (err != noErr)
11366 break;
11368 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
11369 char_code, key_code, modifiers,
11370 ((unsigned long)
11371 (GetEventTime (event) / kEventDurationMillisecond)),
11372 read_socket_inev);
11373 result = noErr;
11374 break;
11376 default:
11377 abort ();
11380 return result;
11383 static pascal OSStatus
11384 mac_handle_command_event (next_handler, event, data)
11385 EventHandlerCallRef next_handler;
11386 EventRef event;
11387 void *data;
11389 OSStatus err, result = eventNotHandledErr;
11390 HICommand command;
11391 static const EventParamName names[] =
11392 {kEventParamDirectObject, kEventParamKeyModifiers};
11393 static const EventParamType types[] =
11394 {typeHICommand, typeUInt32};
11395 int num_params = sizeof (names) / sizeof (names[0]);
11397 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11398 NULL, sizeof (HICommand), NULL, &command);
11399 if (err != noErr)
11400 return eventNotHandledErr;
11402 switch (GetEventKind (event))
11404 case kEventCommandProcess:
11405 result = CallNextEventHandler (next_handler, event);
11406 if (result != eventNotHandledErr)
11407 break;
11409 err = GetEventParameter (event, kEventParamDirectObject,
11410 typeHICommand, NULL,
11411 sizeof (HICommand), NULL, &command);
11413 if (err != noErr || command.commandID == 0)
11414 break;
11416 /* A HI command event is mapped to an Apple event whose event
11417 class symbol is `hi-command' and event ID is its command
11418 ID. */
11419 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11420 Qhi_command, Qnil,
11421 event, num_params,
11422 names, types);
11423 if (err == noErr)
11424 result = noErr;
11425 break;
11427 default:
11428 abort ();
11431 return result;
11434 static pascal OSStatus
11435 mac_handle_mouse_event (next_handler, event, data)
11436 EventHandlerCallRef next_handler;
11437 EventRef event;
11438 void *data;
11440 OSStatus err, result = eventNotHandledErr;
11442 switch (GetEventKind (event))
11444 case kEventMouseWheelMoved:
11446 WindowRef wp;
11447 struct frame *f;
11448 EventMouseWheelAxis axis;
11449 SInt32 delta;
11450 Point point;
11452 result = CallNextEventHandler (next_handler, event);
11453 if (result != eventNotHandledErr || read_socket_inev == NULL)
11454 break;
11456 f = mac_focus_frame (&one_mac_display_info);
11458 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11459 NULL, sizeof (WindowRef), NULL, &wp);
11460 if (err != noErr
11461 || wp != FRAME_MAC_WINDOW (f))
11462 break;
11464 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11465 typeMouseWheelAxis, NULL,
11466 sizeof (EventMouseWheelAxis), NULL, &axis);
11467 if (err != noErr || axis != kEventMouseWheelAxisY)
11468 break;
11470 err = GetEventParameter (event, kEventParamMouseLocation,
11471 typeQDPoint, NULL, sizeof (Point),
11472 NULL, &point);
11473 if (err != noErr)
11474 break;
11476 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11477 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
11478 if (point.h < 0 || point.v < 0
11479 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11480 f->tool_bar_window))
11481 break;
11483 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11484 typeSInt32, NULL, sizeof (SInt32),
11485 NULL, &delta);
11486 if (err != noErr)
11487 break;
11489 read_socket_inev->kind = WHEEL_EVENT;
11490 read_socket_inev->code = 0;
11491 read_socket_inev->modifiers =
11492 (mac_event_to_emacs_modifiers (event)
11493 | ((delta < 0) ? down_modifier : up_modifier));
11494 XSETINT (read_socket_inev->x, point.h);
11495 XSETINT (read_socket_inev->y, point.v);
11496 XSETFRAME (read_socket_inev->frame_or_window, f);
11498 result = noErr;
11500 break;
11502 default:
11503 abort ();
11506 return result;
11509 #if USE_MAC_TSM
11510 static pascal OSStatus
11511 mac_handle_text_input_event (next_handler, event, data)
11512 EventHandlerCallRef next_handler;
11513 EventRef event;
11514 void *data;
11516 OSStatus err, result;
11517 Lisp_Object id_key = Qnil;
11518 int num_params;
11519 const EventParamName *names;
11520 const EventParamType *types;
11521 static UInt32 seqno_uaia = 0;
11522 static const EventParamName names_uaia[] =
11523 {kEventParamTextInputSendComponentInstance,
11524 kEventParamTextInputSendRefCon,
11525 kEventParamTextInputSendSLRec,
11526 kEventParamTextInputSendFixLen,
11527 kEventParamTextInputSendText,
11528 kEventParamTextInputSendUpdateRng,
11529 kEventParamTextInputSendHiliteRng,
11530 kEventParamTextInputSendClauseRng,
11531 kEventParamTextInputSendPinRng,
11532 kEventParamTextInputSendTextServiceEncoding,
11533 kEventParamTextInputSendTextServiceMacEncoding,
11534 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
11535 static const EventParamType types_uaia[] =
11536 {typeComponentInstance,
11537 typeLongInteger,
11538 typeIntlWritingCode,
11539 typeLongInteger,
11540 #ifdef MAC_OSX
11541 typeUnicodeText,
11542 #else
11543 typeChar,
11544 #endif
11545 typeTextRangeArray,
11546 typeTextRangeArray,
11547 typeOffsetArray,
11548 typeTextRange,
11549 typeUInt32,
11550 typeUInt32,
11551 typeUInt32};
11552 static const EventParamName names_ufke[] =
11553 {kEventParamTextInputSendComponentInstance,
11554 kEventParamTextInputSendRefCon,
11555 kEventParamTextInputSendSLRec,
11556 kEventParamTextInputSendText};
11557 static const EventParamType types_ufke[] =
11558 {typeComponentInstance,
11559 typeLongInteger,
11560 typeIntlWritingCode,
11561 typeUnicodeText};
11563 result = CallNextEventHandler (next_handler, event);
11564 if (result != eventNotHandledErr)
11565 return result;
11567 switch (GetEventKind (event))
11569 case kEventTextInputUpdateActiveInputArea:
11570 id_key = Qupdate_active_input_area;
11571 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11572 names = names_uaia;
11573 types = types_uaia;
11574 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11575 typeUInt32, sizeof (UInt32), &seqno_uaia);
11576 seqno_uaia++;
11577 result = noErr;
11578 break;
11580 case kEventTextInputUnicodeForKeyEvent:
11582 EventRef kbd_event;
11583 UInt32 actual_size, modifiers;
11585 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11586 typeEventRef, NULL, sizeof (EventRef), NULL,
11587 &kbd_event);
11588 if (err == noErr)
11589 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11590 typeUInt32, NULL,
11591 sizeof (UInt32), NULL, &modifiers);
11592 if (err == noErr && mac_mapped_modifiers (modifiers))
11593 /* There're mapped modifier keys. Process it in
11594 do_keystroke. */
11595 break;
11596 if (err == noErr)
11597 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11598 typeUnicodeText, NULL, 0, &actual_size,
11599 NULL);
11600 if (err == noErr && actual_size == sizeof (UniChar))
11602 UniChar code;
11604 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11605 typeUnicodeText, NULL,
11606 sizeof (UniChar), NULL, &code);
11607 if (err == noErr && code < 0x80)
11609 /* ASCII character. Process it in do_keystroke. */
11610 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
11612 UInt32 key_code;
11614 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11615 typeUInt32, NULL, sizeof (UInt32),
11616 NULL, &key_code);
11617 if (!(err == noErr && key_code <= 0x7f
11618 && keycode_to_xkeysym_table [key_code]))
11620 struct frame *f =
11621 mac_focus_frame (&one_mac_display_info);
11623 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11624 read_socket_inev->code = code;
11625 read_socket_inev->modifiers =
11626 mac_to_emacs_modifiers (modifiers);
11627 read_socket_inev->modifiers |=
11628 (extra_keyboard_modifiers
11629 & (meta_modifier | alt_modifier
11630 | hyper_modifier | super_modifier));
11631 XSETFRAME (read_socket_inev->frame_or_window, f);
11634 break;
11637 if (err == noErr)
11639 /* Non-ASCII keystrokes without mapped modifiers are
11640 processed at the Lisp level. */
11641 id_key = Qunicode_for_key_event;
11642 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11643 names = names_ufke;
11644 types = types_ufke;
11645 result = noErr;
11648 break;
11650 case kEventTextInputOffsetToPos:
11652 struct frame *f;
11653 struct window *w;
11654 Point p;
11656 if (!OVERLAYP (Vmac_ts_active_input_overlay))
11657 break;
11659 /* Strictly speaking, this is not always correct because
11660 previous events may change some states about display. */
11661 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11663 /* Active input area is displayed around the current point. */
11664 f = SELECTED_FRAME ();
11665 w = XWINDOW (f->selected_window);
11667 else if (WINDOWP (echo_area_window))
11669 /* Active input area is displayed in the echo area. */
11670 w = XWINDOW (echo_area_window);
11671 f = WINDOW_XFRAME (w);
11673 else
11674 break;
11676 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
11677 + WINDOW_LEFT_FRINGE_WIDTH (w)
11678 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
11679 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
11680 + FONT_BASE (FRAME_FONT (f))
11681 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
11682 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11683 typeQDPoint, sizeof (typeQDPoint), &p);
11684 if (err == noErr)
11685 result = noErr;
11687 break;
11689 default:
11690 abort ();
11693 if (!NILP (id_key))
11694 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11695 event, num_params,
11696 names, types);
11697 return result;
11699 #endif
11700 #endif /* TARGET_API_MAC_CARBON */
11703 OSStatus
11704 install_window_handler (window)
11705 WindowRef window;
11707 OSStatus err = noErr;
11709 #if TARGET_API_MAC_CARBON
11710 if (err == noErr)
11712 static const EventTypeSpec specs[] =
11714 /* -- window refresh events -- */
11715 {kEventClassWindow, kEventWindowUpdate},
11716 /* -- window state change events -- */
11717 {kEventClassWindow, kEventWindowShowing},
11718 {kEventClassWindow, kEventWindowHiding},
11719 {kEventClassWindow, kEventWindowShown},
11720 {kEventClassWindow, kEventWindowHidden},
11721 {kEventClassWindow, kEventWindowCollapsed},
11722 {kEventClassWindow, kEventWindowExpanded},
11723 {kEventClassWindow, kEventWindowBoundsChanging},
11724 {kEventClassWindow, kEventWindowBoundsChanged},
11725 /* -- window action events -- */
11726 {kEventClassWindow, kEventWindowClose},
11727 {kEventClassWindow, kEventWindowGetIdealSize},
11728 #ifdef MAC_OSX
11729 {kEventClassWindow, kEventWindowToolbarSwitchMode},
11730 #endif
11731 #if USE_MAC_TSM
11732 /* -- window focus events -- */
11733 {kEventClassWindow, kEventWindowFocusAcquired},
11734 {kEventClassWindow, kEventWindowFocusRelinquish},
11735 #endif
11737 static EventHandlerUPP handle_window_eventUPP = NULL;
11739 if (handle_window_eventUPP == NULL)
11740 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
11742 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11743 GetEventTypeCount (specs),
11744 specs, NULL, NULL);
11746 #endif
11748 if (err == noErr)
11749 err = install_drag_handler (window);
11751 return err;
11754 void
11755 remove_window_handler (window)
11756 WindowRef window;
11758 remove_drag_handler (window);
11761 #if TARGET_API_MAC_CARBON
11762 static OSStatus
11763 install_application_handler ()
11765 OSStatus err = noErr;
11767 if (err == noErr)
11769 static const EventTypeSpec specs[] = {
11770 #if USE_MAC_TSM
11771 {kEventClassApplication, kEventAppActivated},
11772 {kEventClassApplication, kEventAppDeactivated},
11773 #endif
11776 err = InstallApplicationEventHandler (NewEventHandlerUPP
11777 (mac_handle_application_event),
11778 GetEventTypeCount (specs),
11779 specs, NULL, NULL);
11782 if (err == noErr)
11784 static const EventTypeSpec specs[] =
11785 {{kEventClassKeyboard, kEventRawKeyDown},
11786 {kEventClassKeyboard, kEventRawKeyRepeat},
11787 {kEventClassKeyboard, kEventRawKeyUp}};
11789 err = InstallApplicationEventHandler (NewEventHandlerUPP
11790 (mac_handle_keyboard_event),
11791 GetEventTypeCount (specs),
11792 specs, NULL, NULL);
11795 if (err == noErr)
11797 static const EventTypeSpec specs[] =
11798 {{kEventClassCommand, kEventCommandProcess}};
11800 err = InstallApplicationEventHandler (NewEventHandlerUPP
11801 (mac_handle_command_event),
11802 GetEventTypeCount (specs),
11803 specs, NULL, NULL);
11806 if (err == noErr)
11808 static const EventTypeSpec specs[] =
11809 {{kEventClassMouse, kEventMouseWheelMoved}};
11811 err = InstallApplicationEventHandler (NewEventHandlerUPP
11812 (mac_handle_mouse_event),
11813 GetEventTypeCount (specs),
11814 specs, NULL, NULL);
11817 #if USE_MAC_TSM
11818 if (err == noErr)
11820 static const EventTypeSpec spec[] =
11821 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11822 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11823 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11825 err = InstallApplicationEventHandler (NewEventHandlerUPP
11826 (mac_handle_text_input_event),
11827 GetEventTypeCount (spec),
11828 spec, NULL, NULL);
11830 #endif
11832 if (err == noErr)
11833 err = install_menu_target_item_handler ();
11835 #ifdef MAC_OSX
11836 if (err == noErr)
11837 err = install_service_handler ();
11838 #endif
11840 return err;
11842 #endif
11844 static pascal void
11845 mac_handle_dm_notification (event)
11846 AppleEvent *event;
11848 mac_screen_config_changed = 1;
11851 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11852 static void
11853 mac_handle_cg_display_reconfig (display, flags, user_info)
11854 CGDirectDisplayID display;
11855 CGDisplayChangeSummaryFlags flags;
11856 void *user_info;
11858 mac_screen_config_changed = 1;
11860 #endif
11862 static OSErr
11863 init_dm_notification_handler ()
11865 OSErr err = noErr;
11867 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11868 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11869 if (CGDisplayRegisterReconfigurationCallback != NULL)
11870 #endif
11872 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11873 NULL);
11875 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11876 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11877 #endif
11878 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11879 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11881 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11882 ProcessSerialNumber psn;
11884 if (handle_dm_notificationUPP == NULL)
11885 handle_dm_notificationUPP =
11886 NewDMNotificationUPP (mac_handle_dm_notification);
11888 err = GetCurrentProcess (&psn);
11889 if (err == noErr)
11890 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11892 #endif
11894 return err;
11897 static void
11898 mac_get_screen_info (dpyinfo)
11899 struct mac_display_info *dpyinfo;
11901 #ifdef MAC_OSX
11902 /* HasDepth returns true if it is possible to have a 32 bit display,
11903 but this may not be what is actually used. Mac OSX can do better. */
11904 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11905 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11907 CGDisplayErr err;
11908 CGDisplayCount ndisps;
11909 CGDirectDisplayID *displays;
11911 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11912 if (err == noErr)
11914 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11915 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11917 if (err == noErr)
11919 CGRect bounds = CGRectZero;
11921 while (ndisps-- > 0)
11922 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11923 dpyinfo->height = CGRectGetHeight (bounds);
11924 dpyinfo->width = CGRectGetWidth (bounds);
11926 else
11928 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11929 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11932 #else /* !MAC_OSX */
11934 GDHandle gdh = GetMainDevice ();
11935 Rect rect = (**gdh).gdRect;
11937 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11938 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11939 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11940 break;
11942 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11943 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11944 UnionRect (&rect, &(**gdh).gdRect, &rect);
11946 dpyinfo->height = rect.bottom - rect.top;
11947 dpyinfo->width = rect.right - rect.left;
11949 #endif /* !MAC_OSX */
11953 #if __profile__
11954 void
11955 profiler_exit_proc ()
11957 ProfilerDump ("\pEmacs.prof");
11958 ProfilerTerm ();
11960 #endif
11962 /* These few functions implement Emacs as a normal Mac application
11963 (almost): set up the heap and the Toolbox, handle necessary system
11964 events plus a few simple menu events. They also set up Emacs's
11965 access to functions defined in the rest of this file. Emacs uses
11966 function hooks to perform all its terminal I/O. A complete list of
11967 these functions appear in termhooks.h. For what they do, read the
11968 comments there and see also w32term.c and xterm.c. What's
11969 noticeably missing here is the event loop, which is normally
11970 present in most Mac application. After performing the necessary
11971 Mac initializations, main passes off control to emacs_main
11972 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11973 (defined further below) to read input. This is where
11974 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
11976 #ifdef MAC_OS8
11977 #undef main
11979 main (void)
11981 #if __profile__ /* is the profiler on? */
11982 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11983 exit(1);
11984 #endif
11986 #if __MWERKS__
11987 /* set creator and type for files created by MSL */
11988 _fcreator = MAC_EMACS_CREATOR_CODE;
11989 _ftype = 'TEXT';
11990 #endif
11992 do_init_managers ();
11994 do_get_menus ();
11996 #ifndef USE_LSB_TAG
11997 do_check_ram_size ();
11998 #endif
12000 init_emacs_passwd_dir ();
12002 init_environ ();
12004 init_coercion_handler ();
12006 initialize_applescript ();
12008 init_apple_event_handler ();
12010 init_dm_notification_handler ();
12013 char **argv;
12014 int argc = 0;
12016 /* set up argv array from STR# resource */
12017 get_string_list (&argv, ARGV_STRING_LIST_ID);
12018 while (argv[argc])
12019 argc++;
12021 /* free up AppleScript resources on exit */
12022 atexit (terminate_applescript);
12024 #if __profile__ /* is the profiler on? */
12025 atexit (profiler_exit_proc);
12026 #endif
12028 /* 3rd param "envp" never used in emacs_main */
12029 (void) emacs_main (argc, argv, 0);
12032 /* Never reached - real exit in Fkill_emacs */
12033 return 0;
12035 #endif
12037 #if !TARGET_API_MAC_CARBON
12038 static RgnHandle mouse_region = NULL;
12040 Boolean
12041 mac_wait_next_event (er, sleep_time, dequeue)
12042 EventRecord *er;
12043 UInt32 sleep_time;
12044 Boolean dequeue;
12046 static EventRecord er_buf = {nullEvent};
12047 UInt32 target_tick, current_tick;
12048 EventMask event_mask;
12050 if (mouse_region == NULL)
12051 mouse_region = NewRgn ();
12053 event_mask = everyEvent;
12054 if (!mac_ready_for_apple_events)
12055 event_mask -= highLevelEventMask;
12057 current_tick = TickCount ();
12058 target_tick = current_tick + sleep_time;
12060 if (er_buf.what == nullEvent)
12061 while (!WaitNextEvent (event_mask, &er_buf,
12062 target_tick - current_tick, mouse_region))
12064 current_tick = TickCount ();
12065 if (target_tick <= current_tick)
12066 return false;
12069 *er = er_buf;
12070 if (dequeue)
12071 er_buf.what = nullEvent;
12072 return true;
12074 #endif /* not TARGET_API_MAC_CARBON */
12076 #if TARGET_API_MAC_CARBON
12077 OSStatus
12078 mac_post_mouse_moved_event ()
12080 EventRef event = NULL;
12081 OSStatus err;
12083 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
12084 kEventAttributeNone, &event);
12085 if (err == noErr)
12087 Point mouse_pos;
12089 GetGlobalMouse (&mouse_pos);
12090 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
12091 sizeof (Point), &mouse_pos);
12093 if (err == noErr)
12095 UInt32 modifiers = GetCurrentKeyModifiers ();
12097 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
12098 sizeof (UInt32), &modifiers);
12100 if (err == noErr)
12101 err = PostEventToQueue (GetCurrentEventQueue (), event,
12102 kEventPriorityStandard);
12103 if (event)
12104 ReleaseEvent (event);
12106 return err;
12108 #endif
12110 /* Emacs calls this whenever it wants to read an input event from the
12111 user. */
12113 XTread_socket (sd, expected, hold_quit)
12114 int sd, expected;
12115 struct input_event *hold_quit;
12117 struct input_event inev;
12118 int count = 0;
12119 #if TARGET_API_MAC_CARBON
12120 EventRef eventRef;
12121 EventTargetRef toolbox_dispatcher;
12122 #endif
12123 EventRecord er;
12124 struct mac_display_info *dpyinfo = &one_mac_display_info;
12126 if (interrupt_input_blocked)
12128 interrupt_input_pending = 1;
12129 return -1;
12132 interrupt_input_pending = 0;
12133 BLOCK_INPUT;
12135 /* So people can tell when we have read the available input. */
12136 input_signal_count++;
12138 ++handling_signal;
12140 #if TARGET_API_MAC_CARBON
12141 toolbox_dispatcher = GetEventDispatcherTarget ();
12143 while (
12144 #if USE_CG_DRAWING
12145 mac_prepare_for_quickdraw (NULL),
12146 #endif
12147 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
12148 kEventRemoveFromQueue, &eventRef))
12149 #else /* !TARGET_API_MAC_CARBON */
12150 while (mac_wait_next_event (&er, 0, true))
12151 #endif /* !TARGET_API_MAC_CARBON */
12153 int do_help = 0;
12154 struct frame *f;
12155 unsigned long timestamp;
12157 EVENT_INIT (inev);
12158 inev.kind = NO_EVENT;
12159 inev.arg = Qnil;
12161 #if TARGET_API_MAC_CARBON
12162 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
12164 if (!mac_convert_event_ref (eventRef, &er))
12165 goto OTHER;
12166 #else /* !TARGET_API_MAC_CARBON */
12167 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12168 #endif /* !TARGET_API_MAC_CARBON */
12170 switch (er.what)
12172 case mouseDown:
12173 case mouseUp:
12175 WindowRef window_ptr;
12176 ControlPartCode part_code;
12177 int tool_bar_p = 0;
12179 #if TARGET_API_MAC_CARBON
12180 OSStatus err;
12182 /* This is needed to send mouse events like aqua window
12183 buttons to the correct handler. */
12184 read_socket_inev = &inev;
12185 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12186 read_socket_inev = NULL;
12187 if (err != eventNotHandledErr)
12188 break;
12189 #endif
12190 last_mouse_glyph_frame = 0;
12192 if (dpyinfo->grabbed && last_mouse_frame
12193 && FRAME_LIVE_P (last_mouse_frame))
12195 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
12196 part_code = inContent;
12198 else
12200 part_code = FindWindow (er.where, &window_ptr);
12201 if (tip_window && window_ptr == tip_window)
12203 HideWindow (tip_window);
12204 part_code = FindWindow (er.where, &window_ptr);
12208 if (er.what != mouseDown &&
12209 (part_code != inContent || dpyinfo->grabbed == 0))
12210 break;
12212 switch (part_code)
12214 case inMenuBar:
12215 f = mac_focus_frame (dpyinfo);
12216 saved_menu_event_location = er.where;
12217 inev.kind = MENU_BAR_ACTIVATE_EVENT;
12218 XSETFRAME (inev.frame_or_window, f);
12219 break;
12221 case inContent:
12222 if (
12223 #if TARGET_API_MAC_CARBON
12224 FrontNonFloatingWindow ()
12225 #else
12226 FrontWindow ()
12227 #endif
12228 != window_ptr
12229 || (mac_window_to_frame (window_ptr)
12230 != dpyinfo->x_focus_frame))
12231 SelectWindow (window_ptr);
12232 else
12234 ControlPartCode control_part_code;
12235 ControlRef ch;
12236 Point mouse_loc;
12237 #ifdef MAC_OSX
12238 ControlKind control_kind;
12239 #endif
12241 f = mac_window_to_frame (window_ptr);
12242 /* convert to local coordinates of new window */
12243 mouse_loc.h = (er.where.h
12244 - (f->left_pos
12245 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12246 mouse_loc.v = (er.where.v
12247 - (f->top_pos
12248 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12249 #if TARGET_API_MAC_CARBON
12250 ch = FindControlUnderMouse (mouse_loc, window_ptr,
12251 &control_part_code);
12252 #ifdef MAC_OSX
12253 if (ch)
12254 GetControlKind (ch, &control_kind);
12255 #endif
12256 #else
12257 control_part_code = FindControl (mouse_loc, window_ptr,
12258 &ch);
12259 #endif
12261 #if TARGET_API_MAC_CARBON
12262 inev.code = mac_get_mouse_btn (eventRef);
12263 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
12264 #else
12265 inev.code = mac_get_emulated_btn (er.modifiers);
12266 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
12267 #endif
12268 XSETINT (inev.x, mouse_loc.h);
12269 XSETINT (inev.y, mouse_loc.v);
12271 if ((dpyinfo->grabbed && tracked_scroll_bar)
12272 || (ch != 0
12273 #ifndef USE_TOOLKIT_SCROLL_BARS
12274 /* control_part_code becomes kControlNoPart if
12275 a progress indicator is clicked. */
12276 && control_part_code != kControlNoPart
12277 #else /* USE_TOOLKIT_SCROLL_BARS */
12278 #ifdef MAC_OSX
12279 && control_kind.kind == kControlKindScrollBar
12280 #endif /* MAC_OSX */
12281 #endif /* USE_TOOLKIT_SCROLL_BARS */
12284 struct scroll_bar *bar;
12286 if (dpyinfo->grabbed && tracked_scroll_bar)
12288 bar = tracked_scroll_bar;
12289 #ifndef USE_TOOLKIT_SCROLL_BARS
12290 control_part_code = kControlIndicatorPart;
12291 #endif
12293 else
12294 bar = (struct scroll_bar *) GetControlReference (ch);
12295 #ifdef USE_TOOLKIT_SCROLL_BARS
12296 /* Make the "Ctrl-Mouse-2 splits window" work
12297 for toolkit scroll bars. */
12298 if (inev.modifiers & ctrl_modifier)
12299 x_scroll_bar_handle_click (bar, control_part_code,
12300 &er, &inev);
12301 else if (er.what == mouseDown)
12302 x_scroll_bar_handle_press (bar, control_part_code,
12303 mouse_loc, &inev);
12304 else
12305 x_scroll_bar_handle_release (bar, &inev);
12306 #else /* not USE_TOOLKIT_SCROLL_BARS */
12307 x_scroll_bar_handle_click (bar, control_part_code,
12308 &er, &inev);
12309 if (er.what == mouseDown
12310 && control_part_code == kControlIndicatorPart)
12311 tracked_scroll_bar = bar;
12312 else
12313 tracked_scroll_bar = NULL;
12314 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12316 else
12318 Lisp_Object window;
12319 int x = mouse_loc.h;
12320 int y = mouse_loc.v;
12322 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
12323 if (EQ (window, f->tool_bar_window))
12325 if (er.what == mouseDown)
12326 handle_tool_bar_click (f, x, y, 1, 0);
12327 else
12328 handle_tool_bar_click (f, x, y, 0,
12329 inev.modifiers);
12330 tool_bar_p = 1;
12332 else
12334 XSETFRAME (inev.frame_or_window, f);
12335 inev.kind = MOUSE_CLICK_EVENT;
12339 if (er.what == mouseDown)
12341 dpyinfo->grabbed |= (1 << inev.code);
12342 last_mouse_frame = f;
12344 if (!tool_bar_p)
12345 last_tool_bar_item = -1;
12347 else
12349 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
12350 /* If a button is released though it was not
12351 previously pressed, that would be because
12352 of multi-button emulation. */
12353 dpyinfo->grabbed = 0;
12354 else
12355 dpyinfo->grabbed &= ~(1 << inev.code);
12358 /* Ignore any mouse motion that happened before
12359 this event; any subsequent mouse-movement Emacs
12360 events should reflect only motion after the
12361 ButtonPress. */
12362 if (f != 0)
12363 f->mouse_moved = 0;
12365 #ifdef USE_TOOLKIT_SCROLL_BARS
12366 if (inev.kind == MOUSE_CLICK_EVENT
12367 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12368 && (inev.modifiers & ctrl_modifier)))
12369 #endif
12370 switch (er.what)
12372 case mouseDown:
12373 inev.modifiers |= down_modifier;
12374 break;
12375 case mouseUp:
12376 inev.modifiers |= up_modifier;
12377 break;
12380 break;
12382 case inDrag:
12383 #if TARGET_API_MAC_CARBON
12384 case inProxyIcon:
12385 if (IsWindowPathSelectClick (window_ptr, &er))
12387 WindowPathSelect (window_ptr, NULL, NULL);
12388 break;
12390 if (part_code == inProxyIcon
12391 && (TrackWindowProxyDrag (window_ptr, er.where)
12392 != errUserWantsToDragWindow))
12393 break;
12394 DragWindow (window_ptr, er.where, NULL);
12395 #else /* not TARGET_API_MAC_CARBON */
12396 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
12397 /* Update the frame parameters. */
12399 struct frame *f = mac_window_to_frame (window_ptr);
12401 if (f && !f->async_iconified)
12402 mac_handle_origin_change (f);
12404 #endif /* not TARGET_API_MAC_CARBON */
12405 break;
12407 case inGoAway:
12408 if (TrackGoAway (window_ptr, er.where))
12410 inev.kind = DELETE_WINDOW_EVENT;
12411 XSETFRAME (inev.frame_or_window,
12412 mac_window_to_frame (window_ptr));
12414 break;
12416 /* window resize handling added --ben */
12417 case inGrow:
12418 do_grow_window (window_ptr, &er);
12419 break;
12421 /* window zoom handling added --ben */
12422 case inZoomIn:
12423 case inZoomOut:
12424 if (TrackBox (window_ptr, er.where, part_code))
12425 do_zoom_window (window_ptr, part_code);
12426 break;
12428 #if USE_MAC_TOOLBAR
12429 case inStructure:
12431 OSStatus err;
12432 HIViewRef ch;
12434 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12435 eventRef, &ch);
12436 /* This doesn't work on Mac OS X 10.2. */
12437 if (err == noErr)
12438 HIViewClick (ch, eventRef);
12440 break;
12441 #endif /* USE_MAC_TOOLBAR */
12443 default:
12444 break;
12447 break;
12449 #if !TARGET_API_MAC_CARBON
12450 case updateEvt:
12451 do_window_update ((WindowRef) er.message);
12452 break;
12453 #endif
12455 case osEvt:
12456 switch ((er.message >> 24) & 0x000000FF)
12458 case mouseMovedMessage:
12459 #if !TARGET_API_MAC_CARBON
12460 SetRectRgn (mouse_region, er.where.h, er.where.v,
12461 er.where.h + 1, er.where.v + 1);
12462 #endif
12463 previous_help_echo_string = help_echo_string;
12464 help_echo_string = Qnil;
12466 if (dpyinfo->grabbed && last_mouse_frame
12467 && FRAME_LIVE_P (last_mouse_frame))
12468 f = last_mouse_frame;
12469 else
12470 f = dpyinfo->x_focus_frame;
12472 if (dpyinfo->mouse_face_hidden)
12474 dpyinfo->mouse_face_hidden = 0;
12475 clear_mouse_face (dpyinfo);
12478 if (f)
12480 WindowRef wp = FRAME_MAC_WINDOW (f);
12481 Point mouse_pos;
12483 mouse_pos.h = (er.where.h
12484 - (f->left_pos
12485 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12486 mouse_pos.v = (er.where.v
12487 - (f->top_pos
12488 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12489 if (dpyinfo->grabbed && tracked_scroll_bar)
12490 #ifdef USE_TOOLKIT_SCROLL_BARS
12491 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
12492 mouse_pos, &inev);
12493 #else /* not USE_TOOLKIT_SCROLL_BARS */
12494 x_scroll_bar_note_movement (tracked_scroll_bar,
12495 mouse_pos.v
12496 - XINT (tracked_scroll_bar->top),
12497 er.when * (1000 / 60));
12498 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12499 else
12501 /* Generate SELECT_WINDOW_EVENTs when needed. */
12502 if (!NILP (Vmouse_autoselect_window))
12504 Lisp_Object window;
12506 window = window_from_coordinates (f,
12507 mouse_pos.h,
12508 mouse_pos.v,
12509 0, 0, 0, 0);
12511 /* Window will be selected only when it is
12512 not selected now and last mouse movement
12513 event was not in it. Minibuffer window
12514 will be selected only when it is active. */
12515 if (WINDOWP (window)
12516 && !EQ (window, last_window)
12517 && !EQ (window, selected_window)
12518 /* For click-to-focus window managers
12519 create event iff we don't leave the
12520 selected frame. */
12521 && (focus_follows_mouse
12522 || (EQ (XWINDOW (window)->frame,
12523 XWINDOW (selected_window)->frame))))
12525 inev.kind = SELECT_WINDOW_EVENT;
12526 inev.frame_or_window = window;
12529 last_window=window;
12531 if (!note_mouse_movement (f, &mouse_pos))
12532 help_echo_string = previous_help_echo_string;
12533 #if USE_MAC_TOOLBAR
12534 else
12535 mac_tool_bar_note_mouse_movement (f, eventRef);
12536 #endif
12540 /* If the contents of the global variable
12541 help_echo_string has changed, generate a
12542 HELP_EVENT. */
12543 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12544 do_help = 1;
12545 break;
12547 default:
12548 goto OTHER;
12550 break;
12552 case activateEvt:
12554 WindowRef window_ptr = (WindowRef) er.message;
12555 OSErr err;
12556 ControlRef root_control;
12558 if (window_ptr == tip_window)
12560 HideWindow (tip_window);
12561 break;
12564 if (!is_emacs_window (window_ptr))
12565 goto OTHER;
12567 f = mac_window_to_frame (window_ptr);
12569 if ((er.modifiers & activeFlag) != 0)
12571 /* A window has been activated */
12572 Point mouse_loc;
12574 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12575 if (err == noErr)
12576 ActivateControl (root_control);
12578 x_detect_focus_change (dpyinfo, &er, &inev);
12580 mouse_loc.h = (er.where.h
12581 - (f->left_pos
12582 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12583 mouse_loc.v = (er.where.v
12584 - (f->top_pos
12585 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12586 /* Window-activated event counts as mouse movement,
12587 so update things that depend on mouse position. */
12588 note_mouse_movement (f, &mouse_loc);
12590 else
12592 /* A window has been deactivated */
12593 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12594 if (err == noErr)
12595 DeactivateControl (root_control);
12597 #ifdef USE_TOOLKIT_SCROLL_BARS
12598 if (dpyinfo->grabbed && tracked_scroll_bar)
12600 struct input_event event;
12602 EVENT_INIT (event);
12603 event.kind = NO_EVENT;
12604 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
12605 if (event.kind != NO_EVENT)
12607 event.timestamp = timestamp;
12608 kbd_buffer_store_event_hold (&event, hold_quit);
12609 count++;
12612 #endif
12613 dpyinfo->grabbed = 0;
12615 x_detect_focus_change (dpyinfo, &er, &inev);
12617 if (f == dpyinfo->mouse_face_mouse_frame)
12619 /* If we move outside the frame, then we're
12620 certainly no longer on any text in the
12621 frame. */
12622 clear_mouse_face (dpyinfo);
12623 dpyinfo->mouse_face_mouse_frame = 0;
12626 /* Generate a nil HELP_EVENT to cancel a help-echo.
12627 Do it only if there's something to cancel.
12628 Otherwise, the startup message is cleared when the
12629 mouse leaves the frame. */
12630 if (any_help_event_p)
12631 do_help = -1;
12634 break;
12636 case keyDown:
12637 case keyUp:
12638 case autoKey:
12639 ObscureCursor ();
12641 f = mac_focus_frame (dpyinfo);
12642 XSETFRAME (inev.frame_or_window, f);
12644 /* If mouse-highlight is an integer, input clears out mouse
12645 highlighting. */
12646 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12647 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12649 clear_mouse_face (dpyinfo);
12650 dpyinfo->mouse_face_hidden = 1;
12654 UInt32 modifiers = er.modifiers, mapped_modifiers;
12656 #ifdef MAC_OSX
12657 GetEventParameter (eventRef, kEventParamKeyModifiers,
12658 typeUInt32, NULL,
12659 sizeof (UInt32), NULL, &modifiers);
12660 #endif
12661 mapped_modifiers = mac_mapped_modifiers (modifiers);
12663 #if TARGET_API_MAC_CARBON
12664 if (!(mapped_modifiers
12665 & ~(mac_pass_command_to_system ? cmdKey : 0)
12666 & ~(mac_pass_control_to_system ? controlKey : 0)))
12667 goto OTHER;
12668 else
12669 #endif
12670 if (er.what != keyUp)
12671 do_keystroke (er.what, er.message & charCodeMask,
12672 (er.message & keyCodeMask) >> 8,
12673 modifiers, timestamp, &inev);
12675 break;
12677 case kHighLevelEvent:
12678 AEProcessAppleEvent (&er);
12679 break;
12681 default:
12682 OTHER:
12683 #if TARGET_API_MAC_CARBON
12685 OSStatus err;
12687 read_socket_inev = &inev;
12688 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12689 read_socket_inev = NULL;
12691 #endif
12692 break;
12694 #if TARGET_API_MAC_CARBON
12695 ReleaseEvent (eventRef);
12696 #endif
12698 if (inev.kind != NO_EVENT)
12700 inev.timestamp = timestamp;
12701 kbd_buffer_store_event_hold (&inev, hold_quit);
12702 count++;
12705 if (do_help
12706 && !(hold_quit && hold_quit->kind != NO_EVENT))
12708 Lisp_Object frame;
12710 if (f)
12711 XSETFRAME (frame, f);
12712 else
12713 frame = Qnil;
12715 if (do_help > 0)
12717 any_help_event_p = 1;
12718 gen_help_event (help_echo_string, frame, help_echo_window,
12719 help_echo_object, help_echo_pos);
12721 else
12723 help_echo_string = Qnil;
12724 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12726 count++;
12730 /* If the focus was just given to an autoraising frame,
12731 raise it now. */
12732 /* ??? This ought to be able to handle more than one such frame. */
12733 if (pending_autoraise_frame)
12735 x_raise_frame (pending_autoraise_frame);
12736 pending_autoraise_frame = 0;
12739 if (mac_screen_config_changed)
12741 mac_get_screen_info (dpyinfo);
12742 mac_screen_config_changed = 0;
12745 #if !TARGET_API_MAC_CARBON
12746 /* Check which frames are still visible. We do this here because
12747 there doesn't seem to be any direct notification from the Window
12748 Manager that the visibility of a window has changed (at least,
12749 not in all cases). */
12751 Lisp_Object tail, frame;
12753 FOR_EACH_FRAME (tail, frame)
12755 struct frame *f = XFRAME (frame);
12757 /* The tooltip has been drawn already. Avoid the
12758 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12759 if (EQ (frame, tip_frame))
12760 continue;
12762 if (FRAME_MAC_P (f))
12763 mac_handle_visibility_change (f);
12766 #endif
12768 --handling_signal;
12769 UNBLOCK_INPUT;
12770 return count;
12774 /* Need to override CodeWarrior's input function so no conversion is
12775 done on newlines Otherwise compiled functions in .elc files will be
12776 read incorrectly. Defined in ...:MSL C:MSL
12777 Common:Source:buffer_io.c. */
12778 #ifdef __MWERKS__
12779 void
12780 __convert_to_newlines (unsigned char * p, size_t * n)
12782 #pragma unused(p,n)
12785 void
12786 __convert_from_newlines (unsigned char * p, size_t * n)
12788 #pragma unused(p,n)
12790 #endif
12792 #ifdef MAC_OS8
12793 void
12794 make_mac_terminal_frame (struct frame *f)
12796 Lisp_Object frame;
12797 Rect r;
12799 XSETFRAME (frame, f);
12801 f->output_method = output_mac;
12802 f->output_data.mac = (struct mac_output *)
12803 xmalloc (sizeof (struct mac_output));
12804 bzero (f->output_data.mac, sizeof (struct mac_output));
12806 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12808 FRAME_COLS (f) = 96;
12809 FRAME_LINES (f) = 4;
12811 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12812 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12814 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
12816 f->output_data.mac->cursor_pixel = 0;
12817 f->output_data.mac->border_pixel = 0x00ff00;
12818 f->output_data.mac->mouse_pixel = 0xff00ff;
12819 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12821 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12822 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12823 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12824 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12825 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12826 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
12828 FRAME_FONTSET (f) = -1;
12829 f->output_data.mac->explicit_parent = 0;
12830 f->left_pos = 8;
12831 f->top_pos = 32;
12832 f->border_width = 0;
12834 f->internal_border_width = 0;
12836 f->auto_raise = 1;
12837 f->auto_lower = 1;
12839 f->new_text_cols = 0;
12840 f->new_text_lines = 0;
12842 SetRect (&r, f->left_pos, f->top_pos,
12843 f->left_pos + FRAME_PIXEL_WIDTH (f),
12844 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12846 BLOCK_INPUT;
12848 if (!(FRAME_MAC_WINDOW (f) =
12849 NewCWindow (NULL, &r, "\p", true, dBoxProc,
12850 (WindowRef) -1, 1, (long) f->output_data.mac)))
12851 abort ();
12852 /* so that update events can find this mac_output struct */
12853 f->output_data.mac->mFP = f; /* point back to emacs frame */
12855 UNBLOCK_INPUT;
12857 x_make_gc (f);
12859 /* Need to be initialized for unshow_buffer in window.c. */
12860 selected_window = f->selected_window;
12862 Fmodify_frame_parameters (frame,
12863 Fcons (Fcons (Qfont,
12864 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12865 Fmodify_frame_parameters (frame,
12866 Fcons (Fcons (Qforeground_color,
12867 build_string ("black")), Qnil));
12868 Fmodify_frame_parameters (frame,
12869 Fcons (Fcons (Qbackground_color,
12870 build_string ("white")), Qnil));
12872 #endif
12875 /***********************************************************************
12876 Initialization
12877 ***********************************************************************/
12879 static int mac_initialized = 0;
12881 static XrmDatabase
12882 mac_make_rdb (xrm_option)
12883 const char *xrm_option;
12885 XrmDatabase database;
12887 database = xrm_get_preference_database (NULL);
12888 if (xrm_option)
12889 xrm_merge_string_database (database, xrm_option);
12891 return database;
12894 struct mac_display_info *
12895 mac_term_init (display_name, xrm_option, resource_name)
12896 Lisp_Object display_name;
12897 char *xrm_option;
12898 char *resource_name;
12900 struct mac_display_info *dpyinfo;
12901 struct terminal *terminal;
12903 BLOCK_INPUT;
12905 if (!mac_initialized)
12907 mac_initialize ();
12908 mac_initialized = 1;
12911 if (x_display_list)
12912 error ("Sorry, this version can only handle one display");
12914 dpyinfo = &one_mac_display_info;
12915 bzero (dpyinfo, sizeof (*dpyinfo));
12917 terminal = mac_create_terminal (dpyinfo);
12919 /* Set the name of the terminal. */
12920 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12921 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12922 terminal->name[SBYTES (display_name)] = 0;
12924 #ifdef MAC_OSX
12925 dpyinfo->mac_id_name
12926 = (char *) xmalloc (SCHARS (Vinvocation_name)
12927 + SCHARS (Vsystem_name)
12928 + 2);
12929 sprintf (dpyinfo->mac_id_name, "%s@%s",
12930 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12931 #else
12932 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12933 strcpy (dpyinfo->mac_id_name, "Mac Display");
12934 #endif
12936 dpyinfo->reference_count = 0;
12937 dpyinfo->resx = 72.0;
12938 dpyinfo->resy = 72.0;
12940 mac_get_screen_info (dpyinfo);
12942 dpyinfo->grabbed = 0;
12943 dpyinfo->root_window = NULL;
12944 dpyinfo->terminal->image_cache = make_image_cache ();
12946 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12947 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12948 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12949 dpyinfo->mouse_face_window = Qnil;
12950 dpyinfo->mouse_face_overlay = Qnil;
12951 dpyinfo->mouse_face_hidden = 0;
12953 dpyinfo->xrdb = mac_make_rdb (xrm_option);
12955 /* Put this display on the chain. */
12956 dpyinfo->next = x_display_list;
12957 x_display_list = dpyinfo;
12959 /* Put it on x_display_name_list. */
12960 x_display_name_list = Fcons (Fcons (display_name,
12961 Fcons (Qnil, dpyinfo->xrdb)),
12962 x_display_name_list);
12963 dpyinfo->name_list_element = XCAR (x_display_name_list);
12965 /* FIXME: Untested.
12966 Add the default keyboard. */
12967 add_keyboard_wait_descriptor (0);
12969 #if USE_CG_DRAWING
12970 mac_init_fringe (terminal->rif);
12971 #endif
12973 UNBLOCK_INPUT;
12975 return dpyinfo;
12978 /* Get rid of display DPYINFO, assuming all frames are already gone. */
12980 void
12981 x_delete_display (dpyinfo)
12982 struct mac_display_info *dpyinfo;
12984 int i;
12986 /* Discard this display from x_display_name_list and x_display_list.
12987 We can't use Fdelq because that can quit. */
12988 if (! NILP (x_display_name_list)
12989 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12990 x_display_name_list = XCDR (x_display_name_list);
12991 else
12993 Lisp_Object tail;
12995 tail = x_display_name_list;
12996 while (CONSP (tail) && CONSP (XCDR (tail)))
12998 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
13000 XSETCDR (tail, XCDR (XCDR (tail)));
13001 break;
13003 tail = XCDR (tail);
13007 if (x_display_list == dpyinfo)
13008 x_display_list = dpyinfo->next;
13009 else
13011 struct x_display_info *tail;
13013 for (tail = x_display_list; tail; tail = tail->next)
13014 if (tail->next == dpyinfo)
13015 tail->next = tail->next->next;
13018 /* Free the font names in the font table. */
13019 for (i = 0; i < dpyinfo->n_fonts; i++)
13020 if (dpyinfo->font_table[i].name)
13022 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
13023 xfree (dpyinfo->font_table[i].full_name);
13024 xfree (dpyinfo->font_table[i].name);
13027 if (dpyinfo->font_table)
13029 if (dpyinfo->font_table->font_encoder)
13030 xfree (dpyinfo->font_table->font_encoder);
13031 xfree (dpyinfo->font_table);
13033 if (dpyinfo->mac_id_name)
13034 xfree (dpyinfo->mac_id_name);
13036 if (x_display_list == 0)
13038 mac_clear_font_name_table ();
13039 bzero (dpyinfo, sizeof (*dpyinfo));
13044 static void
13045 init_menu_bar ()
13047 #ifdef MAC_OSX
13048 OSStatus err;
13049 MenuRef menu;
13050 MenuItemIndex menu_index;
13052 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
13053 &menu, &menu_index);
13054 if (err == noErr)
13055 SetMenuItemCommandKey (menu, menu_index, false, 0);
13056 EnableMenuCommand (NULL, kHICommandPreferences);
13057 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
13058 &menu, &menu_index);
13059 if (err == noErr)
13061 SetMenuItemCommandKey (menu, menu_index, false, 0);
13062 InsertMenuItemTextWithCFString (menu, NULL,
13063 0, kMenuItemAttrSeparator, 0);
13064 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
13065 0, 0, kHICommandAbout);
13067 #else /* !MAC_OSX */
13068 #if TARGET_API_MAC_CARBON
13069 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
13070 #endif
13071 #endif
13074 #if USE_MAC_TSM
13075 static void
13076 init_tsm ()
13078 #ifdef MAC_OSX
13079 static InterfaceTypeList types = {kUnicodeDocument};
13080 #else
13081 static InterfaceTypeList types = {kTextService};
13082 #endif
13084 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
13085 &tsm_document_id, 0);
13087 #endif
13089 /* Set up use of X before we make the first connection. */
13091 extern frame_parm_handler mac_frame_parm_handlers[];
13093 static struct redisplay_interface x_redisplay_interface =
13095 mac_frame_parm_handlers,
13096 x_produce_glyphs,
13097 x_write_glyphs,
13098 x_insert_glyphs,
13099 x_clear_end_of_line,
13100 x_scroll_run,
13101 x_after_update_window_line,
13102 x_update_window_begin,
13103 x_update_window_end,
13104 x_cursor_to,
13105 x_flush,
13106 #if USE_CG_DRAWING
13107 mac_flush_display_optional,
13108 #else
13109 0, /* flush_display_optional */
13110 #endif
13111 x_clear_window_mouse_face,
13112 x_get_glyph_overhangs,
13113 x_fix_overlapping_area,
13114 x_draw_fringe_bitmap,
13115 #if USE_CG_DRAWING
13116 mac_define_fringe_bitmap,
13117 mac_destroy_fringe_bitmap,
13118 #else
13119 0, /* define_fringe_bitmap */
13120 0, /* destroy_fringe_bitmap */
13121 #endif
13122 mac_per_char_metric,
13123 mac_encode_char,
13124 mac_compute_glyph_string_overhangs,
13125 x_draw_glyph_string,
13126 mac_define_frame_cursor,
13127 mac_clear_frame_area,
13128 mac_draw_window_cursor,
13129 mac_draw_vertical_window_border,
13130 mac_shift_glyphs_for_insert
13133 static struct terminal *
13134 mac_create_terminal (struct mac_display_info *dpyinfo)
13136 struct terminal *terminal;
13138 terminal = create_terminal ();
13140 terminal->type = output_mac;
13141 terminal->display_info.mac = dpyinfo;
13142 dpyinfo->terminal = terminal;
13144 terminal->clear_frame_hook = x_clear_frame;
13145 terminal->ins_del_lines_hook = x_ins_del_lines;
13146 terminal->delete_glyphs_hook = x_delete_glyphs;
13147 terminal->ring_bell_hook = XTring_bell;
13148 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
13149 terminal->set_terminal_modes_hook = XTset_terminal_modes;
13150 terminal->update_begin_hook = x_update_begin;
13151 terminal->update_end_hook = x_update_end;
13152 terminal->set_terminal_window_hook = XTset_terminal_window;
13153 terminal->read_socket_hook = XTread_socket;
13154 terminal->frame_up_to_date_hook = XTframe_up_to_date;
13155 terminal->mouse_position_hook = XTmouse_position;
13156 terminal->frame_rehighlight_hook = XTframe_rehighlight;
13157 terminal->frame_raise_lower_hook = XTframe_raise_lower;
13158 /* terminal->fullscreen_hook = XTfullscreen_hook; */
13159 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13160 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13161 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
13162 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
13163 terminal->delete_frame_hook = x_destroy_window;
13164 /* terminal->delete_terminal_hook = x_delete_terminal; */
13166 terminal->rif = &x_redisplay_interface;
13167 #if 0
13168 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
13169 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
13170 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
13171 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
13172 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
13173 scrolls off the
13174 bottom */
13175 #else
13176 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
13177 terminal->char_ins_del_ok = 1;
13178 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
13179 terminal->fast_clear_end_of_line = 1; /* X does this well. */
13180 terminal->memory_below_frame = 0; /* We don't remember what scrolls
13181 off the bottom. */
13183 #endif
13185 /* FIXME: This keyboard setup is 100% untested, just copied from
13186 w32_create_terminal in order to set window-system now that it's
13187 a keyboard object. */
13188 /* We don't yet support separate terminals on Mac, so don't try to share
13189 keyboards between virtual terminals that are on the same physical
13190 terminal like X does. */
13191 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13192 init_kboard (terminal->kboard);
13193 terminal->kboard->Vwindow_system = intern ("mac");
13194 terminal->kboard->next_kboard = all_kboards;
13195 all_kboards = terminal->kboard;
13196 /* Don't let the initial kboard remain current longer than necessary.
13197 That would cause problems if a file loaded on startup tries to
13198 prompt in the mini-buffer. */
13199 if (current_kboard == initial_kboard)
13200 current_kboard = terminal->kboard;
13201 terminal->kboard->reference_count++;
13203 return terminal;
13206 static void
13207 mac_initialize ()
13210 baud_rate = 19200;
13212 last_tool_bar_item = -1;
13213 any_help_event_p = 0;
13215 /* Try to use interrupt input; if we can't, then start polling. */
13216 Fset_input_interrupt_mode (Qt);
13218 BLOCK_INPUT;
13220 #if TARGET_API_MAC_CARBON
13222 install_application_handler ();
13224 init_menu_bar ();
13226 #if USE_MAC_TSM
13227 init_tsm ();
13228 #endif
13230 #ifdef MAC_OSX
13231 init_coercion_handler ();
13233 init_apple_event_handler ();
13235 init_dm_notification_handler ();
13237 if (!inhibit_window_system)
13239 static const ProcessSerialNumber psn = {0, kCurrentProcess};
13241 SetFrontProcess (&psn);
13243 #endif
13244 #endif
13246 #if USE_CG_DRAWING
13247 init_cg_color ();
13248 #endif
13250 UNBLOCK_INPUT;
13255 void
13256 syms_of_macterm ()
13258 #if 0
13259 staticpro (&x_error_message_string);
13260 x_error_message_string = Qnil;
13261 #endif
13263 Qcontrol = intern ("control"); staticpro (&Qcontrol);
13264 Qmeta = intern ("meta"); staticpro (&Qmeta);
13265 Qalt = intern ("alt"); staticpro (&Qalt);
13266 Qhyper = intern ("hyper"); staticpro (&Qhyper);
13267 Qsuper = intern ("super"); staticpro (&Qsuper);
13268 Qmodifier_value = intern ("modifier-value");
13269 staticpro (&Qmodifier_value);
13271 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
13272 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
13273 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
13274 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
13275 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
13277 #if TARGET_API_MAC_CARBON
13278 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
13279 #ifdef MAC_OSX
13280 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
13281 staticpro (&Qtoolbar_switch_mode);
13282 #if USE_MAC_FONT_PANEL
13283 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
13284 Qselection = intern ("selection"); staticpro (&Qselection);
13285 #endif
13287 Qservice = intern ("service"); staticpro (&Qservice);
13288 Qpaste = intern ("paste"); staticpro (&Qpaste);
13289 Qperform = intern ("perform"); staticpro (&Qperform);
13291 Qmouse_drag_overlay = intern ("mouse-drag-overlay");
13292 staticpro (&Qmouse_drag_overlay);
13293 #endif
13294 #if USE_MAC_TSM
13295 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
13296 Qupdate_active_input_area = intern ("update-active-input-area");
13297 staticpro (&Qupdate_active_input_area);
13298 Qunicode_for_key_event = intern ("unicode-for-key-event");
13299 staticpro (&Qunicode_for_key_event);
13300 #endif
13301 #endif
13303 #ifdef MAC_OSX
13304 Fprovide (intern ("mac-carbon"), Qnil);
13305 #endif
13307 staticpro (&Qreverse);
13308 Qreverse = intern ("reverse");
13310 staticpro (&x_display_name_list);
13311 x_display_name_list = Qnil;
13313 staticpro (&last_mouse_scroll_bar);
13314 last_mouse_scroll_bar = Qnil;
13316 staticpro (&fm_font_family_alist);
13317 fm_font_family_alist = Qnil;
13319 #if USE_ATSUI
13320 staticpro (&atsu_font_id_hash);
13321 atsu_font_id_hash = Qnil;
13323 staticpro (&fm_style_face_attributes_alist);
13324 fm_style_face_attributes_alist = Qnil;
13325 #endif
13327 #if USE_MAC_TSM
13328 staticpro (&saved_ts_script_language_on_focus);
13329 saved_ts_script_language_on_focus = Qnil;
13330 #endif
13332 /* We don't yet support this, but defining this here avoids whining
13333 from cus-start.el and other places, like "M-x set-variable". */
13334 DEFVAR_BOOL ("x-use-underline-position-properties",
13335 &x_use_underline_position_properties,
13336 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
13337 A value of nil means ignore them. If you encounter fonts with bogus
13338 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
13339 to 4.1, set this to nil.
13341 NOTE: Not supported on Mac yet. */);
13342 x_use_underline_position_properties = 0;
13344 DEFVAR_BOOL ("x-underline-at-descent-line",
13345 &x_underline_at_descent_line,
13346 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
13347 A value of nil means to draw the underline according to the value of the
13348 variable `x-use-underline-position-properties', which is usually at the
13349 baseline level. The default value is nil. */);
13350 x_underline_at_descent_line = 0;
13352 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
13353 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
13354 #ifdef USE_TOOLKIT_SCROLL_BARS
13355 Vx_toolkit_scroll_bars = Qt;
13356 #else
13357 Vx_toolkit_scroll_bars = Qnil;
13358 #endif
13360 staticpro (&last_mouse_motion_frame);
13361 last_mouse_motion_frame = Qnil;
13363 /* Variables to configure modifier key assignment. */
13365 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
13366 doc: /* *Modifier key assumed when the Mac control key is pressed.
13367 The value can be `control', `meta', `alt', `hyper', or `super' for the
13368 respective modifier. The default is `control'. */);
13369 Vmac_control_modifier = Qcontrol;
13371 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
13372 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13373 The value can be `control', `meta', `alt', `hyper', or `super' for the
13374 respective modifier. If the value is nil then the key will act as the
13375 normal Mac control modifier, and the option key can be used to compose
13376 characters depending on the chosen Mac keyboard setting. */);
13377 Vmac_option_modifier = Qnil;
13379 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
13380 doc: /* *Modifier key assumed when the Mac command key is pressed.
13381 The value can be `control', `meta', `alt', `hyper', or `super' for the
13382 respective modifier. The default is `meta'. */);
13383 Vmac_command_modifier = Qmeta;
13385 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
13386 doc: /* *Modifier key assumed when the Mac function key is pressed.
13387 The value can be `control', `meta', `alt', `hyper', or `super' for the
13388 respective modifier. Note that remapping the function key may lead to
13389 unexpected results for some keys on non-US/GB keyboards. */);
13390 Vmac_function_modifier = Qnil;
13392 DEFVAR_LISP ("mac-emulate-three-button-mouse",
13393 &Vmac_emulate_three_button_mouse,
13394 doc: /* *Specify a way of three button mouse emulation.
13395 The value can be nil, t, or the symbol `reverse'.
13396 A value of nil means that no emulation should be done and the modifiers
13397 should be placed on the mouse-1 event.
13398 t means that when the option-key is held down while pressing the mouse
13399 button, the click will register as mouse-2 and while the command-key
13400 is held down, the click will register as mouse-3.
13401 The symbol `reverse' means that the option-key will register for
13402 mouse-3 and the command-key will register for mouse-2. */);
13403 Vmac_emulate_three_button_mouse = Qnil;
13405 #if TARGET_API_MAC_CARBON
13406 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
13407 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
13408 Otherwise, the right click will be treated as mouse-2 and the wheel
13409 button will be mouse-3. */);
13410 mac_wheel_button_is_mouse_2 = 1;
13412 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
13413 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
13414 mac_pass_command_to_system = 1;
13416 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
13417 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
13418 mac_pass_control_to_system = 1;
13420 #endif
13422 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
13423 doc: /* *If non-nil, allow anti-aliasing.
13424 The text will be rendered using Core Graphics text rendering which
13425 may anti-alias the text. */);
13426 #if USE_CG_DRAWING
13427 mac_use_core_graphics = 1;
13428 #else
13429 mac_use_core_graphics = 0;
13430 #endif
13432 /* Register an entry for `mac-roman' so that it can be used when
13433 creating the terminal frame on Mac OS 9 before loading
13434 term/mac-win.elc. */
13435 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
13436 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
13437 Each entry should be of the form:
13439 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13441 where CHARSET-NAME is a string used in font names to identify the
13442 charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13443 CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
13444 Vmac_charset_info_alist =
13445 Fcons (list3 (build_string ("mac-roman"),
13446 make_number (smRoman), Qnil), Qnil);
13448 #if USE_MAC_TSM
13449 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13450 doc: /* Overlay used to display Mac TSM active input area. */);
13451 Vmac_ts_active_input_overlay = Qnil;
13453 DEFVAR_LISP ("mac-ts-active-input-buf", &Vmac_ts_active_input_buf,
13454 doc: /* Byte sequence of the current Mac TSM active input area. */);
13455 /* `empty_string' is not ready yet on Mac OS Classic. */
13456 Vmac_ts_active_input_buf = build_string ("");
13458 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13459 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13460 If the value is t, the input script and language are restored to those
13461 used in the last focus frame. If the value is a pair of integers, the
13462 input script and language codes, which are defined in the Script
13463 Manager, are set to its car and cdr parts, respectively. Otherwise,
13464 Emacs doesn't set them and thus follows the system default behavior. */);
13465 Vmac_ts_script_language_on_focus = Qnil;
13466 #endif
13469 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13470 (do not change this comment) */