(Qfont_spec, Qfont_entity, Qfont_object): Extern them.
[bpt/emacs.git] / src / macterm.c
1 /* Implementation of GUI terminal on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22 /* Contributed by Andrew Choi (akochoi@mac.com). */
23
24 #include <config.h>
25 #include <signal.h>
26
27 #include <stdio.h>
28
29 #include "lisp.h"
30 #include "blockinput.h"
31
32 #include "macterm.h"
33
34 #ifndef MAC_OSX
35 #include <alloca.h>
36 #endif
37
38 #if !TARGET_API_MAC_CARBON
39 #include <Quickdraw.h>
40 #include <ToolUtils.h>
41 #include <Sound.h>
42 #include <Events.h>
43 #include <Script.h>
44 #include <Resources.h>
45 #include <Fonts.h>
46 #include <TextUtils.h>
47 #include <LowMem.h>
48 #include <Controls.h>
49 #include <Windows.h>
50 #include <Displays.h>
51 #if defined (__MRC__) || (__MSL__ >= 0x6000)
52 #include <ControlDefinitions.h>
53 #endif
54
55 #if __profile__
56 #include <profiler.h>
57 #endif
58 #endif /* not TARGET_API_MAC_CARBON */
59
60 #include "systty.h"
61 #include "systime.h"
62
63 #include <ctype.h>
64 #include <errno.h>
65 #include <setjmp.h>
66 #include <sys/stat.h>
67
68 #include "charset.h"
69 #include "coding.h"
70 #include "frame.h"
71 #include "dispextern.h"
72 #include "fontset.h"
73 #include "termhooks.h"
74 #include "termopts.h"
75 #include "termchar.h"
76 #include "disptab.h"
77 #include "buffer.h"
78 #include "window.h"
79 #include "keyboard.h"
80 #include "intervals.h"
81 #include "atimer.h"
82 #include "keymap.h"
83 #include "character.h"
84 #include "ccl.h"
85
86 \f
87
88 /* Non-nil means Emacs uses toolkit scroll bars. */
89
90 Lisp_Object Vx_toolkit_scroll_bars;
91
92 /* If non-zero, the text will be rendered using Core Graphics text
93 rendering which may anti-alias the text. */
94 int mac_use_core_graphics;
95
96
97 /* Non-zero means that a HELP_EVENT has been generated since Emacs
98 start. */
99
100 static int any_help_event_p;
101
102 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
103 static Lisp_Object last_window;
104
105 /* Non-zero means make use of UNDERLINE_POSITION font properties.
106 (Not yet supported.) */
107 int x_use_underline_position_properties;
108
109 /* Non-zero means to draw the underline at the same place as the descent line. */
110
111 int x_underline_at_descent_line;
112
113 /* This is a chain of structures for all the X displays currently in
114 use. */
115
116 struct x_display_info *x_display_list;
117
118 /* This is a list of cons cells, each of the form (NAME
119 FONT-LIST-CACHE . RESOURCE-DATABASE), one for each element of
120 x_display_list and in the same order. NAME is the name of the
121 frame. FONT-LIST-CACHE records previous values returned by
122 x-list-fonts. RESOURCE-DATABASE preserves the X Resource Database
123 equivalent, which is implemented with a Lisp object, for the
124 display. */
125
126 Lisp_Object x_display_name_list;
127
128 /* This is display since Mac does not support multiple ones. */
129 struct mac_display_info one_mac_display_info;
130
131 /* Frame being updated by update_frame. This is declared in term.c.
132 This is set by update_begin and looked at by all the XT functions.
133 It is zero while not inside an update. In that case, the XT
134 functions assume that `selected_frame' is the frame to apply to. */
135
136 extern struct frame *updating_frame;
137
138 /* This is a frame waiting to be auto-raised, within XTread_socket. */
139
140 struct frame *pending_autoraise_frame;
141
142 /* Mouse movement.
143
144 Formerly, we used PointerMotionHintMask (in standard_event_mask)
145 so that we would have to call XQueryPointer after each MotionNotify
146 event to ask for another such event. However, this made mouse tracking
147 slow, and there was a bug that made it eventually stop.
148
149 Simply asking for MotionNotify all the time seems to work better.
150
151 In order to avoid asking for motion events and then throwing most
152 of them away or busy-polling the server for mouse positions, we ask
153 the server for pointer motion hints. This means that we get only
154 one event per group of mouse movements. "Groups" are delimited by
155 other kinds of events (focus changes and button clicks, for
156 example), or by XQueryPointer calls; when one of these happens, we
157 get another MotionNotify event the next time the mouse moves. This
158 is at least as efficient as getting motion events when mouse
159 tracking is on, and I suspect only negligibly worse when tracking
160 is off. */
161
162 /* Where the mouse was last time we reported a mouse event. */
163
164 static Rect last_mouse_glyph;
165 static FRAME_PTR last_mouse_glyph_frame;
166
167 /* The scroll bar in which the last X motion event occurred.
168
169 If the last X motion event occurred in a scroll bar, we set this so
170 XTmouse_position can know whether to report a scroll bar motion or
171 an ordinary motion.
172
173 If the last X motion event didn't occur in a scroll bar, we set
174 this to Qnil, to tell XTmouse_position to return an ordinary motion
175 event. */
176
177 static Lisp_Object last_mouse_scroll_bar;
178
179 /* This is a hack. We would really prefer that XTmouse_position would
180 return the time associated with the position it returns, but there
181 doesn't seem to be any way to wrest the time-stamp from the server
182 along with the position query. So, we just keep track of the time
183 of the last movement we received, and return that in hopes that
184 it's somewhat accurate. */
185
186 static Time last_mouse_movement_time;
187
188 struct scroll_bar *tracked_scroll_bar = NULL;
189
190 /* Incremented by XTread_socket whenever it really tries to read
191 events. */
192
193 #ifdef __STDC__
194 static int volatile input_signal_count;
195 #else
196 static int input_signal_count;
197 #endif
198
199 extern Lisp_Object Vsystem_name;
200
201 extern Lisp_Object Qeql;
202
203 /* A mask of extra modifier bits to put into every keyboard char. */
204
205 extern EMACS_INT extra_keyboard_modifiers;
206
207 /* The keysyms to use for the various modifiers. */
208
209 static Lisp_Object Qalt, Qhyper, Qsuper, Qcontrol, Qmeta, Qmodifier_value;
210
211 extern int inhibit_window_system;
212
213 #if __MRC__ && !TARGET_API_MAC_CARBON
214 QDGlobals qd; /* QuickDraw global information structure. */
215 #endif
216
217 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
218
219 struct mac_display_info *mac_display_info_for_display (Display *);
220 static void x_update_window_end P_ ((struct window *, int, int));
221 int x_catch_errors P_ ((Display *));
222 void x_uncatch_errors P_ ((Display *, int));
223 void x_lower_frame P_ ((struct frame *));
224 void x_scroll_bar_clear P_ ((struct frame *));
225 int x_had_errors_p P_ ((Display *));
226 void x_wm_set_size_hint P_ ((struct frame *, long, int));
227 void x_raise_frame P_ ((struct frame *));
228 void x_set_window_size P_ ((struct frame *, int, int, int));
229 void x_wm_set_window_state P_ ((struct frame *, int));
230 void x_wm_set_icon_pixmap P_ ((struct frame *, int));
231 static void mac_initialize P_ ((void));
232 static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
233 static int x_compute_min_glyph_bounds P_ ((struct frame *));
234 static void x_update_end P_ ((struct frame *));
235 static void XTframe_up_to_date P_ ((struct frame *));
236 static void XTset_terminal_modes P_ ((struct terminal *));
237 static void XTreset_terminal_modes P_ ((struct terminal *));
238 static void x_clear_frame P_ ((struct frame *));
239 static void frame_highlight P_ ((struct frame *));
240 static void frame_unhighlight P_ ((struct frame *));
241 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
242 static void mac_focus_changed P_ ((int, struct mac_display_info *,
243 struct frame *, struct input_event *));
244 static void x_detect_focus_change P_ ((struct mac_display_info *,
245 const EventRecord *,
246 struct input_event *));
247 static void XTframe_rehighlight P_ ((struct frame *));
248 static void x_frame_rehighlight P_ ((struct x_display_info *));
249 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
250 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
251 enum text_cursor_kinds));
252
253 static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
254 static void x_flush P_ ((struct frame *f));
255 static void x_update_begin P_ ((struct frame *));
256 static void x_update_window_begin P_ ((struct window *));
257 static void x_after_update_window_line P_ ((struct glyph_row *));
258 static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
259 enum scroll_bar_part *,
260 Lisp_Object *, Lisp_Object *,
261 unsigned long *));
262
263 static int is_emacs_window P_ ((WindowRef));
264 static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int));
265 static void XSetFont P_ ((Display *, GC, XFontStruct *));
266 static struct terminal *mac_create_terminal P_ ((struct mac_display_info *dpyinfo));
267
268
269 #define GC_FORE_COLOR(gc) (&(gc)->fore_color)
270 #define GC_BACK_COLOR(gc) (&(gc)->back_color)
271 #define GC_FONT(gc) ((gc)->xgcv.font)
272 #define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
273
274 #define CG_SET_FILL_COLOR(context, color) \
275 CGContextSetRGBFillColor (context, \
276 RED_FROM_ULONG (color) / 255.0f, \
277 GREEN_FROM_ULONG (color) / 255.0f, \
278 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
279 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
280 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
281 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
282 do { \
283 if (CGColorGetTypeID != NULL) \
284 CGContextSetFillColorWithColor (context, cg_color); \
285 else \
286 CG_SET_FILL_COLOR (context, color); \
287 } while (0)
288 #else
289 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
290 CGContextSetFillColorWithColor (context, cg_color)
291 #endif
292 #else
293 #define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
294 CG_SET_FILL_COLOR (context, color)
295 #endif
296 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, gc) \
297 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
298 (gc)->cg_fore_color)
299 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, gc) \
300 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.background, \
301 (gc)->cg_back_color)
302
303
304 #define CG_SET_STROKE_COLOR(context, color) \
305 CGContextSetRGBStrokeColor (context, \
306 RED_FROM_ULONG (color) / 255.0f, \
307 GREEN_FROM_ULONG (color) / 255.0f, \
308 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
309 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
310 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
311 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
312 do { \
313 if (CGColorGetTypeID != NULL) \
314 CGContextSetStrokeColorWithColor (context, cg_color); \
315 else \
316 CG_SET_STROKE_COLOR (context, color); \
317 } while (0)
318 #else
319 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
320 CGContextSetStrokeColorWithColor (context, cg_color)
321 #endif
322 #else
323 #define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
324 CG_SET_STROKE_COLOR (context, color)
325 #endif
326 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, gc) \
327 CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
328 (gc)->cg_fore_color)
329
330 #if USE_CG_DRAWING
331 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
332
333 /* Fringe bitmaps. */
334
335 static int max_fringe_bmp = 0;
336 static CGImageRef *fringe_bmp = 0;
337
338 CGColorSpaceRef mac_cg_color_space_rgb;
339 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
340 static CGColorRef mac_cg_color_black;
341 #endif
342
343 static void
344 init_cg_color ()
345 {
346 mac_cg_color_space_rgb = CGColorSpaceCreateDeviceRGB ();
347 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
348 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
349 /* Don't check the availability of CGColorCreate; this symbol is
350 defined even in Mac OS X 10.1. */
351 if (CGColorGetTypeID != NULL)
352 #endif
353 {
354 CGFloat rgba[] = {0.0f, 0.0f, 0.0f, 1.0f};
355
356 mac_cg_color_black = CGColorCreate (mac_cg_color_space_rgb, rgba);
357 }
358 #endif
359 }
360
361 static CGContextRef
362 mac_begin_cg_clip (f, gc)
363 struct frame *f;
364 GC gc;
365 {
366 CGContextRef context = FRAME_CG_CONTEXT (f);
367
368 if (!context)
369 {
370 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
371 FRAME_CG_CONTEXT (f) = context;
372 }
373
374 CGContextSaveGState (context);
375 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
376 CGContextScaleCTM (context, 1, -1);
377 if (gc && gc->n_clip_rects)
378 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
379
380 return context;
381 }
382
383 static void
384 mac_end_cg_clip (f)
385 struct frame *f;
386 {
387 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
388 }
389
390 void
391 mac_prepare_for_quickdraw (f)
392 struct frame *f;
393 {
394 if (f == NULL)
395 {
396 Lisp_Object rest, frame;
397 FOR_EACH_FRAME (rest, frame)
398 if (FRAME_MAC_P (XFRAME (frame)))
399 mac_prepare_for_quickdraw (XFRAME (frame));
400 }
401 else
402 {
403 CGContextRef context = FRAME_CG_CONTEXT (f);
404
405 if (context)
406 {
407 CGContextSynchronize (context);
408 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
409 &FRAME_CG_CONTEXT (f));
410 }
411 }
412 }
413 #endif
414
415 static RgnHandle saved_port_clip_region = NULL;
416
417 static void
418 mac_begin_clip (f, gc)
419 struct frame *f;
420 GC gc;
421 {
422 static RgnHandle new_region = NULL;
423
424 if (saved_port_clip_region == NULL)
425 saved_port_clip_region = NewRgn ();
426 if (new_region == NULL)
427 new_region = NewRgn ();
428
429 #if USE_CG_DRAWING
430 mac_prepare_for_quickdraw (f);
431 #endif
432 SetPortWindowPort (FRAME_MAC_WINDOW (f));
433
434 if (gc->n_clip_rects)
435 {
436 GetClip (saved_port_clip_region);
437 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
438 SetClip (new_region);
439 }
440 }
441
442 static void
443 mac_end_clip (gc)
444 GC gc;
445 {
446 if (gc->n_clip_rects)
447 SetClip (saved_port_clip_region);
448 }
449
450
451 /* X display function emulation */
452
453 /* Mac version of XDrawLine. */
454
455 static void
456 mac_draw_line (f, gc, x1, y1, x2, y2)
457 struct frame *f;
458 GC gc;
459 int x1, y1, x2, y2;
460 {
461 #if USE_CG_DRAWING
462 CGContextRef context;
463 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
464
465 if (y1 != y2)
466 gx1 += 0.5f, gx2 += 0.5f;
467 if (x1 != x2)
468 gy1 += 0.5f, gy2 += 0.5f;
469
470 context = mac_begin_cg_clip (f, gc);
471 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
472 CGContextBeginPath (context);
473 CGContextMoveToPoint (context, gx1, gy1);
474 CGContextAddLineToPoint (context, gx2, gy2);
475 CGContextClosePath (context);
476 CGContextStrokePath (context);
477 mac_end_cg_clip (f);
478 #else
479 if (x1 == x2)
480 {
481 if (y1 > y2)
482 y1--;
483 else if (y2 > y1)
484 y2--;
485 }
486 else if (y1 == y2)
487 {
488 if (x1 > x2)
489 x1--;
490 else
491 x2--;
492 }
493
494 mac_begin_clip (f, gc);
495 RGBForeColor (GC_FORE_COLOR (gc));
496 MoveTo (x1, y1);
497 LineTo (x2, y2);
498 mac_end_clip (gc);
499 #endif
500 }
501
502 /* Mac version of XDrawLine (to Pixmap). */
503
504 void
505 XDrawLine (display, p, gc, x1, y1, x2, y2)
506 Display *display;
507 Pixmap p;
508 GC gc;
509 int x1, y1, x2, y2;
510 {
511 #if USE_MAC_IMAGE_IO
512 CGContextRef context;
513 XImagePtr ximg = p;
514 CGColorSpaceRef color_space;
515 CGImageAlphaInfo alpha_info;
516 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
517
518 if (y1 != y2)
519 gx1 += 0.5f, gx2 += 0.5f;
520 if (x1 != x2)
521 gy1 += 0.5f, gy2 += 0.5f;
522
523 if (ximg->bits_per_pixel == 32)
524 {
525 color_space = mac_cg_color_space_rgb;
526 alpha_info = (kCGImageAlphaNoneSkipFirst
527 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
528 | kCGBitmapByteOrder32Host
529 #endif
530 );
531 }
532 else
533 {
534 color_space = NULL;
535 alpha_info = kCGImageAlphaOnly;
536 }
537 if (color_space == NULL)
538 return;
539 context = CGBitmapContextCreate (ximg->data, ximg->width,
540 ximg->height, 8,
541 ximg->bytes_per_line, color_space,
542 alpha_info);
543 if (ximg->bits_per_pixel == 32)
544 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
545 else
546 CGContextSetGrayStrokeColor (context, gc->xgcv.foreground / 255.0f, 1.0);
547 CGContextMoveToPoint (context, gx1, gy1);
548 CGContextAddLineToPoint (context, gx2, gy2);
549 CGContextClosePath (context);
550 CGContextStrokePath (context);
551 CGContextRelease (context);
552 #else
553 CGrafPtr old_port;
554 GDHandle old_gdh;
555
556 if (x1 == x2)
557 {
558 if (y1 > y2)
559 y1--;
560 else if (y2 > y1)
561 y2--;
562 }
563 else if (y1 == y2)
564 {
565 if (x1 > x2)
566 x1--;
567 else
568 x2--;
569 }
570
571 GetGWorld (&old_port, &old_gdh);
572 SetGWorld (p, NULL);
573
574 RGBForeColor (GC_FORE_COLOR (gc));
575
576 LockPixels (GetGWorldPixMap (p));
577 MoveTo (x1, y1);
578 LineTo (x2, y2);
579 UnlockPixels (GetGWorldPixMap (p));
580
581 SetGWorld (old_port, old_gdh);
582 #endif
583 }
584
585
586 static void
587 mac_erase_rectangle (f, gc, x, y, width, height)
588 struct frame *f;
589 GC gc;
590 int x, y;
591 unsigned int width, height;
592 {
593 #if USE_CG_DRAWING
594 {
595 CGContextRef context;
596
597 context = mac_begin_cg_clip (f, gc);
598 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
599 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
600 mac_end_cg_clip (f);
601 }
602 #else
603 {
604 Rect r;
605
606 mac_begin_clip (f, gc);
607 RGBBackColor (GC_BACK_COLOR (gc));
608 SetRect (&r, x, y, x + width, y + height);
609 EraseRect (&r);
610 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
611 mac_end_clip (gc);
612 }
613 #endif
614 }
615
616
617 /* Mac version of XClearArea. */
618
619 void
620 mac_clear_area (f, x, y, width, height)
621 struct frame *f;
622 int x, y;
623 unsigned int width, height;
624 {
625 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
626 }
627
628 /* Mac version of XClearWindow. */
629
630 static void
631 mac_clear_window (f)
632 struct frame *f;
633 {
634 #if USE_CG_DRAWING
635 {
636 CGContextRef context;
637 GC gc = FRAME_NORMAL_GC (f);
638
639 context = mac_begin_cg_clip (f, NULL);
640 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
641 CGContextFillRect (context, CGRectMake (0, 0, FRAME_PIXEL_WIDTH (f),
642 FRAME_PIXEL_HEIGHT (f)));
643 mac_end_cg_clip (f);
644 }
645 #else /* !USE_CG_DRAWING */
646 SetPortWindowPort (FRAME_MAC_WINDOW (f));
647
648 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
649
650 #if TARGET_API_MAC_CARBON
651 {
652 Rect r;
653
654 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
655 EraseRect (&r);
656 }
657 #else /* not TARGET_API_MAC_CARBON */
658 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
659 #endif /* not TARGET_API_MAC_CARBON */
660 #endif
661 }
662
663
664 /* Mac replacement for XCopyArea. */
665
666 #if USE_CG_DRAWING
667 static void
668 mac_draw_cg_image (image, f, gc, src_x, src_y, width, height,
669 dest_x, dest_y, overlay_p)
670 CGImageRef image;
671 struct frame *f;
672 GC gc;
673 int src_x, src_y;
674 unsigned int width, height;
675 int dest_x, dest_y, overlay_p;
676 {
677 CGContextRef context;
678 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
679 CGRect dest_rect = mac_rect_make (f, dest_x, dest_y, width, height);
680
681 context = mac_begin_cg_clip (f, gc);
682 if (!overlay_p)
683 {
684 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
685 CGContextFillRect (context, dest_rect);
686 }
687 CGContextClipToRect (context, dest_rect);
688 CGContextScaleCTM (context, 1, -1);
689 CGContextTranslateCTM (context, 0, -port_height);
690 if (CGImageIsMask (image))
691 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
692 CGContextDrawImage (context,
693 mac_rect_make (f, dest_x - src_x,
694 port_height - (dest_y - src_y
695 + CGImageGetHeight (image)),
696 CGImageGetWidth (image),
697 CGImageGetHeight (image)),
698 image);
699 mac_end_cg_clip (f);
700 }
701
702 #else /* !USE_CG_DRAWING */
703
704 static void
705 mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
706 struct frame *f;
707 GC gc;
708 int x, y, width, height;
709 unsigned short *bits;
710 int overlay_p;
711 {
712 BitMap bitmap;
713 Rect r;
714
715 bitmap.rowBytes = sizeof(unsigned short);
716 bitmap.baseAddr = (char *)bits;
717 SetRect (&(bitmap.bounds), 0, 0, width, height);
718
719 mac_begin_clip (f, gc);
720 RGBForeColor (GC_FORE_COLOR (gc));
721 RGBBackColor (GC_BACK_COLOR (gc));
722 SetRect (&r, x, y, x + width, y + height);
723 #if TARGET_API_MAC_CARBON
724 {
725 CGrafPtr port;
726
727 GetPort (&port);
728 LockPortBits (port);
729 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
730 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
731 UnlockPortBits (port);
732 }
733 #else /* not TARGET_API_MAC_CARBON */
734 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
735 overlay_p ? srcOr : srcCopy, 0);
736 #endif /* not TARGET_API_MAC_CARBON */
737 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
738 mac_end_clip (gc);
739 }
740 #endif /* !USE_CG_DRAWING */
741
742
743 /* Mac replacement for XCreateBitmapFromBitmapData. */
744
745 static void
746 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
747 BitMap *bitmap;
748 char *bits;
749 int w, h;
750 {
751 static const unsigned char swap_nibble[16]
752 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
753 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
754 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
755 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
756 int i, j, w1;
757 char *p;
758
759 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
760 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
761 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
762 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
763 for (i = 0; i < h; i++)
764 {
765 p = bitmap->baseAddr + i * bitmap->rowBytes;
766 for (j = 0; j < w1; j++)
767 {
768 /* Bitswap XBM bytes to match how Mac does things. */
769 unsigned char c = *bits++;
770 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
771 | (swap_nibble[(c>>4) & 0xf]));
772 }
773 }
774
775 SetRect (&(bitmap->bounds), 0, 0, w, h);
776 }
777
778
779 static void
780 mac_free_bitmap (bitmap)
781 BitMap *bitmap;
782 {
783 xfree (bitmap->baseAddr);
784 }
785
786
787 Pixmap
788 XCreatePixmap (display, w, width, height, depth)
789 Display *display;
790 Window w;
791 unsigned int width, height;
792 unsigned int depth;
793 {
794 #if USE_MAC_IMAGE_IO
795 XImagePtr ximg;
796
797 ximg = xmalloc (sizeof (*ximg));
798 ximg->width = width;
799 ximg->height = height;
800 ximg->bits_per_pixel = depth == 1 ? 8 : 32;
801 ximg->bytes_per_line = width * (ximg->bits_per_pixel / 8);
802 ximg->data = xmalloc (ximg->bytes_per_line * height);
803 return ximg;
804 #else
805 Pixmap pixmap;
806 Rect r;
807 QDErr err;
808
809 #ifdef MAC_OS8
810 SetPortWindowPort (w);
811 #endif
812 SetRect (&r, 0, 0, width, height);
813 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
814 if (depth == 1)
815 #endif
816 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
817 #if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
818 else
819 /* CreateCGImageFromPixMaps requires ARGB format. */
820 err = QTNewGWorld (&pixmap, k32ARGBPixelFormat, &r, NULL, NULL, 0);
821 #endif
822 if (err != noErr)
823 return NULL;
824 return pixmap;
825 #endif
826 }
827
828
829 Pixmap
830 XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
831 Display *display;
832 Window w;
833 char *data;
834 unsigned int width, height;
835 unsigned long fg, bg;
836 unsigned int depth;
837 {
838 Pixmap pixmap;
839 BitMap bitmap;
840 #if USE_MAC_IMAGE_IO
841 CGDataProviderRef provider;
842 CGImageRef image_mask;
843 CGContextRef context;
844
845 pixmap = XCreatePixmap (display, w, width, height, depth);
846 if (pixmap == NULL)
847 return NULL;
848
849 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
850 provider = CGDataProviderCreateWithData (NULL, bitmap.baseAddr,
851 bitmap.rowBytes * height, NULL);
852 image_mask = CGImageMaskCreate (width, height, 1, 1, bitmap.rowBytes,
853 provider, NULL, 0);
854 CGDataProviderRelease (provider);
855
856 context = CGBitmapContextCreate (pixmap->data, width, height, 8,
857 pixmap->bytes_per_line,
858 mac_cg_color_space_rgb,
859 kCGImageAlphaNoneSkipFirst
860 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
861 | kCGBitmapByteOrder32Host
862 #endif
863 );
864
865 CG_SET_FILL_COLOR (context, fg);
866 CGContextFillRect (context, CGRectMake (0, 0, width, height));
867 CG_SET_FILL_COLOR (context, bg);
868 CGContextDrawImage (context, CGRectMake (0, 0, width, height), image_mask);
869 CGContextRelease (context);
870 CGImageRelease (image_mask);
871 #else
872 CGrafPtr old_port;
873 GDHandle old_gdh;
874 static GC gc = NULL;
875
876 if (gc == NULL)
877 gc = XCreateGC (display, w, 0, NULL);
878
879 pixmap = XCreatePixmap (display, w, width, height, depth);
880 if (pixmap == NULL)
881 return NULL;
882
883 GetGWorld (&old_port, &old_gdh);
884 SetGWorld (pixmap, NULL);
885 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
886 XSetForeground (display, gc, fg);
887 XSetBackground (display, gc, bg);
888 RGBForeColor (GC_FORE_COLOR (gc));
889 RGBBackColor (GC_BACK_COLOR (gc));
890 LockPixels (GetGWorldPixMap (pixmap));
891 #if TARGET_API_MAC_CARBON
892 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
893 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
894 #else /* not TARGET_API_MAC_CARBON */
895 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
896 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
897 #endif /* not TARGET_API_MAC_CARBON */
898 UnlockPixels (GetGWorldPixMap (pixmap));
899 SetGWorld (old_port, old_gdh);
900 #endif
901 mac_free_bitmap (&bitmap);
902
903 return pixmap;
904 }
905
906
907 void
908 XFreePixmap (display, pixmap)
909 Display *display;
910 Pixmap pixmap;
911 {
912 #if USE_MAC_IMAGE_IO
913 if (pixmap)
914 {
915 if (pixmap->data)
916 xfree (pixmap->data);
917 xfree (pixmap);
918 }
919 #else
920 DisposeGWorld (pixmap);
921 #endif
922 }
923
924
925 /* Mac replacement for XFillRectangle. */
926
927 static void
928 mac_fill_rectangle (f, gc, x, y, width, height)
929 struct frame *f;
930 GC gc;
931 int x, y;
932 unsigned int width, height;
933 {
934 #if USE_CG_DRAWING
935 CGContextRef context;
936
937 context = mac_begin_cg_clip (f, gc);
938 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
939 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
940 mac_end_cg_clip (f);
941 #else
942 Rect r;
943
944 mac_begin_clip (f, gc);
945 RGBForeColor (GC_FORE_COLOR (gc));
946 SetRect (&r, x, y, x + width, y + height);
947 PaintRect (&r); /* using foreground color of gc */
948 mac_end_clip (gc);
949 #endif
950 }
951
952
953 /* Mac replacement for XDrawRectangle: dest is a window. */
954
955 static void
956 mac_draw_rectangle (f, gc, x, y, width, height)
957 struct frame *f;
958 GC gc;
959 int x, y;
960 unsigned int width, height;
961 {
962 #if USE_CG_DRAWING
963 CGContextRef context;
964
965 context = mac_begin_cg_clip (f, gc);
966 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
967 CGContextStrokeRect (context,
968 CGRectMake (x + 0.5f, y + 0.5f, width, height));
969 mac_end_cg_clip (f);
970 #else
971 Rect r;
972
973 mac_begin_clip (f, gc);
974 RGBForeColor (GC_FORE_COLOR (gc));
975 SetRect (&r, x, y, x + width + 1, y + height + 1);
976 FrameRect (&r); /* using foreground color of gc */
977 mac_end_clip (gc);
978 #endif
979 }
980
981
982 static void
983 mac_invert_rectangle (f, x, y, width, height)
984 struct frame *f;
985 int x, y;
986 unsigned int width, height;
987 {
988 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
989 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
990 if (CGContextSetBlendMode != NULL)
991 #endif
992 {
993 CGContextRef context;
994
995 context = mac_begin_cg_clip (f, NULL);
996 CGContextSetRGBFillColor (context, 1.0f, 1.0f, 1.0f, 1.0f);
997 CGContextSetBlendMode (context, kCGBlendModeDifference);
998 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
999 mac_end_cg_clip (f);
1000 }
1001 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
1002 else /* CGContextSetBlendMode == NULL */
1003 #endif
1004 #endif /* USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 */
1005 #if !USE_CG_DRAWING || MAC_OS_X_VERSION_MAX_ALLOWED < 1040 || (MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020)
1006 {
1007 Rect r;
1008
1009 #if USE_CG_DRAWING
1010 mac_prepare_for_quickdraw (f);
1011 #endif
1012 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1013
1014 SetRect (&r, x, y, x + width, y + height);
1015
1016 InvertRect (&r);
1017 }
1018
1019
1020 #if USE_ATSUI
1021 static OSStatus
1022 atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
1023 ConstUniCharArrayPtr text;
1024 UniCharCount text_length;
1025 ATSUStyle style;
1026 ATSUTextLayout *text_layout;
1027 {
1028 OSStatus err;
1029 static ATSUTextLayout saved_text_layout = NULL;
1030
1031 if (saved_text_layout == NULL)
1032 {
1033 static const UniCharCount lengths[] = {kATSUToTextEnd};
1034 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
1035 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
1036 static ATSLineLayoutOptions line_layout =
1037 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1038 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
1039 | kATSLineUseQDRendering
1040 #else
1041 kATSLineIsDisplayOnly | kATSLineFractDisable
1042 #endif
1043 ;
1044 static const ATSUAttributeValuePtr values[] = {&line_layout};
1045
1046 err = ATSUCreateTextLayoutWithTextPtr (text,
1047 kATSUFromTextBeginning,
1048 kATSUToTextEnd,
1049 text_length,
1050 1, lengths, &style,
1051 &saved_text_layout);
1052 if (err == noErr)
1053 err = ATSUSetLayoutControls (saved_text_layout,
1054 sizeof (tags) / sizeof (tags[0]),
1055 tags, sizes, values);
1056 if (err == noErr)
1057 err = ATSUSetTransientFontMatching (saved_text_layout, true);
1058 }
1059 else
1060 {
1061 err = ATSUSetRunStyle (saved_text_layout, style,
1062 kATSUFromTextBeginning, kATSUToTextEnd);
1063 if (err == noErr)
1064 err = ATSUSetTextPointerLocation (saved_text_layout, text,
1065 kATSUFromTextBeginning,
1066 kATSUToTextEnd,
1067 text_length);
1068 }
1069
1070 if (err == noErr)
1071 *text_layout = saved_text_layout;
1072 return err;
1073 }
1074
1075
1076 static void
1077 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1078 overstrike_p, bytes_per_char)
1079 struct frame *f;
1080 GC gc;
1081 int x, y;
1082 char *buf;
1083 int nchars, bg_width, overstrike_p, bytes_per_char;
1084 {
1085 OSStatus err;
1086 ATSUTextLayout text_layout;
1087
1088 xassert (bytes_per_char == 2);
1089
1090 #ifndef WORDS_BIG_ENDIAN
1091 {
1092 int i;
1093 UniChar *text = (UniChar *)buf;
1094
1095 for (i = 0; i < nchars; i++)
1096 text[i] = EndianU16_BtoN (text[i]);
1097 }
1098 #endif
1099 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
1100 nchars,
1101 GC_FONT (gc)->mac_style,
1102 &text_layout);
1103 if (err != noErr)
1104 return;
1105 #ifdef MAC_OSX
1106 if (!mac_use_core_graphics)
1107 {
1108 #endif
1109 mac_begin_clip (f, gc);
1110 RGBForeColor (GC_FORE_COLOR (gc));
1111 if (bg_width)
1112 {
1113 Rect r;
1114
1115 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1116 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1117 RGBBackColor (GC_BACK_COLOR (gc));
1118 EraseRect (&r);
1119 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1120 }
1121 MoveTo (x, y);
1122 ATSUDrawText (text_layout,
1123 kATSUFromTextBeginning, kATSUToTextEnd,
1124 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1125 if (overstrike_p)
1126 {
1127 MoveTo (x + 1, y);
1128 ATSUDrawText (text_layout,
1129 kATSUFromTextBeginning, kATSUToTextEnd,
1130 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1131 }
1132 mac_end_clip (gc);
1133 #ifdef MAC_OSX
1134 }
1135 else
1136 {
1137 static CGContextRef context;
1138 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
1139 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1140 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1141 static const ATSUAttributeValuePtr values[] = {&context};
1142
1143 #if USE_CG_DRAWING
1144 context = mac_begin_cg_clip (f, gc);
1145 #else
1146 CGrafPtr port;
1147
1148 GetPort (&port);
1149 QDBeginCGContext (port, &context);
1150 if (gc->n_clip_rects || bg_width)
1151 {
1152 CGContextTranslateCTM (context, 0, port_height);
1153 CGContextScaleCTM (context, 1, -1);
1154 if (gc->n_clip_rects)
1155 CGContextClipToRects (context, gc->clip_rects,
1156 gc->n_clip_rects);
1157 #endif
1158 if (bg_width)
1159 {
1160 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1161 CGContextFillRect (context,
1162 mac_rect_make (f,
1163 x, y - FONT_BASE (GC_FONT (gc)),
1164 bg_width,
1165 FONT_HEIGHT (GC_FONT (gc))));
1166 }
1167 CGContextScaleCTM (context, 1, -1);
1168 CGContextTranslateCTM (context, 0, -port_height);
1169 #if !USE_CG_DRAWING
1170 }
1171 #endif
1172 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1173 err = ATSUSetLayoutControls (text_layout,
1174 sizeof (tags) / sizeof (tags[0]),
1175 tags, sizes, values);
1176 if (err == noErr)
1177 {
1178 ATSUDrawText (text_layout,
1179 kATSUFromTextBeginning, kATSUToTextEnd,
1180 Long2Fix (x), Long2Fix (port_height - y));
1181 if (overstrike_p)
1182 ATSUDrawText (text_layout,
1183 kATSUFromTextBeginning, kATSUToTextEnd,
1184 Long2Fix (x + 1), Long2Fix (port_height - y));
1185 }
1186 #if USE_CG_DRAWING
1187 mac_end_cg_clip (f);
1188 context = NULL;
1189 #else
1190 CGContextSynchronize (context);
1191 QDEndCGContext (port, &context);
1192 #endif
1193 #if 0
1194 /* This doesn't work on Mac OS X 10.1. */
1195 ATSUClearLayoutControls (text_layout,
1196 sizeof (tags) / sizeof (tags[0]), tags);
1197 #else
1198 ATSUSetLayoutControls (text_layout,
1199 sizeof (tags) / sizeof (tags[0]),
1200 tags, sizes, values);
1201 #endif
1202 }
1203 #endif /* MAC_OSX */
1204 }
1205 #endif /* USE_ATSUI */
1206
1207
1208 static void
1209 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1210 overstrike_p, bytes_per_char)
1211 struct frame *f;
1212 GC gc;
1213 int x, y;
1214 char *buf;
1215 int nchars, bg_width, overstrike_p, bytes_per_char;
1216 {
1217 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1218 UInt32 savedFlags;
1219 #endif
1220
1221 mac_begin_clip (f, gc);
1222 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1223 if (mac_use_core_graphics)
1224 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
1225 #endif
1226 RGBForeColor (GC_FORE_COLOR (gc));
1227 #ifdef MAC_OS8
1228 if (bg_width)
1229 {
1230 RGBBackColor (GC_BACK_COLOR (gc));
1231 TextMode (srcCopy);
1232 }
1233 else
1234 TextMode (srcOr);
1235 #else
1236 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1237 because:
1238 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1239 into an offscreen graphics world first. So performance gain
1240 cannot be expected.)
1241 - It lowers rendering quality.
1242 - Some fonts leave garbage on cursor movement. */
1243 if (bg_width)
1244 {
1245 Rect r;
1246
1247 RGBBackColor (GC_BACK_COLOR (gc));
1248 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1249 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1250 EraseRect (&r);
1251 }
1252 TextMode (srcOr);
1253 #endif
1254 TextFont (GC_FONT (gc)->mac_fontnum);
1255 TextSize (GC_FONT (gc)->mac_fontsize);
1256 TextFace (GC_FONT (gc)->mac_fontface);
1257 MoveTo (x, y);
1258 DrawText (buf, 0, nchars * bytes_per_char);
1259 if (overstrike_p)
1260 {
1261 TextMode (srcOr);
1262 MoveTo (x + 1, y);
1263 DrawText (buf, 0, nchars * bytes_per_char);
1264 }
1265 if (bg_width)
1266 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1267 mac_end_clip (gc);
1268
1269 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1270 if (mac_use_core_graphics)
1271 SwapQDTextFlags(savedFlags);
1272 #endif
1273 }
1274
1275
1276 static INLINE void
1277 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1278 overstrike_p, bytes_per_char)
1279 struct frame *f;
1280 GC gc;
1281 int x, y;
1282 char *buf;
1283 int nchars, bg_width, overstrike_p, bytes_per_char;
1284 {
1285 #if USE_ATSUI
1286 if (GC_FONT (gc)->mac_style)
1287 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1288 overstrike_p, bytes_per_char);
1289 else
1290 #endif /* USE_ATSUI */
1291 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1292 overstrike_p, bytes_per_char);
1293 }
1294
1295
1296 /* Mac replacement for XDrawImageString. */
1297
1298 static void
1299 mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1300 struct frame *f;
1301 GC gc;
1302 int x, y;
1303 char *buf;
1304 int nchars, bg_width, overstrike_p;
1305 {
1306 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1307 overstrike_p, 1);
1308 }
1309
1310
1311 /* Mac replacement for XDrawImageString16. */
1312
1313 static void
1314 mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1315 struct frame *f;
1316 GC gc;
1317 int x, y;
1318 XChar2b *buf;
1319 int nchars, bg_width, overstrike_p;
1320 {
1321 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1322 overstrike_p, 2);
1323 }
1324
1325
1326 /* Mac replacement for XQueryTextExtents, but takes a character. If
1327 STYLE is NULL, measurement is done by QuickDraw Text routines for
1328 the font of the current graphics port. If CG_GLYPH is not NULL,
1329 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1330
1331 static OSStatus
1332 mac_query_char_extents (style, c,
1333 font_ascent_return, font_descent_return,
1334 overall_return, cg_glyph)
1335 #if USE_ATSUI
1336 ATSUStyle style;
1337 #else
1338 void *style;
1339 #endif
1340 int c;
1341 int *font_ascent_return, *font_descent_return;
1342 XCharStruct *overall_return;
1343 #if USE_CG_TEXT_DRAWING
1344 CGGlyph *cg_glyph;
1345 #else
1346 void *cg_glyph;
1347 #endif
1348 {
1349 OSStatus err = noErr;
1350 int width;
1351 Rect char_bounds;
1352
1353 #if USE_ATSUI
1354 if (style)
1355 {
1356 ATSUTextLayout text_layout;
1357 UniChar ch = c;
1358
1359 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
1360 if (err == noErr
1361 && (font_ascent_return || font_descent_return || overall_return))
1362 {
1363 ATSTrapezoid glyph_bounds;
1364
1365 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1366 kATSUFromTextBeginning, kATSUToTextEnd,
1367 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1368 kATSUseFractionalOrigins,
1369 #else
1370 kATSUseDeviceOrigins,
1371 #endif
1372 1, &glyph_bounds, NULL);
1373 if (err == noErr)
1374 {
1375 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1376 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1377
1378 width = Fix2Long (glyph_bounds.upperRight.x
1379 - glyph_bounds.upperLeft.x);
1380 if (font_ascent_return)
1381 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1382 if (font_descent_return)
1383 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1384 }
1385 }
1386 if (err == noErr && overall_return)
1387 {
1388 err = ATSUMeasureTextImage (text_layout,
1389 kATSUFromTextBeginning, kATSUToTextEnd,
1390 0, 0, &char_bounds);
1391 if (err == noErr)
1392 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1393 #if USE_CG_TEXT_DRAWING
1394 if (err == noErr && cg_glyph)
1395 {
1396 OSStatus err1;
1397 ATSUGlyphInfoArray glyph_info_array;
1398 ByteCount count = sizeof (ATSUGlyphInfoArray);
1399
1400 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1401 kATSUToTextEnd, NULL, NULL, NULL);
1402 if (err1 == noErr)
1403 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1404 kATSUToTextEnd, &count,
1405 &glyph_info_array);
1406 if (err1 == noErr
1407 /* Make sure that we don't have to make layout
1408 adjustments. */
1409 && glyph_info_array.glyphs[0].deltaY == 0.0f
1410 && glyph_info_array.glyphs[0].idealX == 0.0f
1411 && glyph_info_array.glyphs[0].screenX == 0)
1412 {
1413 xassert (glyph_info_array.glyphs[0].glyphID);
1414 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1415 }
1416 else
1417 *cg_glyph = 0;
1418 }
1419 #endif
1420 }
1421 }
1422 else
1423 #endif
1424 {
1425 if (font_ascent_return || font_descent_return)
1426 {
1427 FontInfo font_info;
1428
1429 GetFontInfo (&font_info);
1430 if (font_ascent_return)
1431 *font_ascent_return = font_info.ascent;
1432 if (font_descent_return)
1433 *font_descent_return = font_info.descent;
1434 }
1435 if (overall_return)
1436 {
1437 char ch = c;
1438
1439 width = CharWidth (ch);
1440 QDTextBounds (1, &ch, &char_bounds);
1441 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1442 }
1443 }
1444
1445 return err;
1446 }
1447
1448
1449 /* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1450
1451 static int
1452 mac_text_extents_16 (font_struct, string, nchars, overall_return)
1453 XFontStruct *font_struct;
1454 XChar2b *string;
1455 int nchars;
1456 XCharStruct *overall_return;
1457 {
1458 int i;
1459 short width = 0, lbearing = 0, rbearing = 0;
1460 XCharStruct *pcm;
1461
1462 for (i = 0; i < nchars; i++)
1463 {
1464 pcm = mac_per_char_metric (font_struct, string, 0);
1465 if (pcm == NULL)
1466 width += FONT_WIDTH (font_struct);
1467 else
1468 {
1469 lbearing = min (lbearing, width + pcm->lbearing);
1470 rbearing = max (rbearing, width + pcm->rbearing);
1471 width += pcm->width;
1472 }
1473 string++;
1474 }
1475
1476 overall_return->lbearing = lbearing;
1477 overall_return->rbearing = rbearing;
1478 overall_return->width = width;
1479
1480 /* What's the meaning of the return value of XTextExtents16? */
1481 }
1482
1483
1484 #if USE_CG_TEXT_DRAWING
1485 static int cg_text_anti_aliasing_threshold = 8;
1486
1487 static void
1488 init_cg_text_anti_aliasing_threshold ()
1489 {
1490 int threshold;
1491 Boolean valid_p;
1492
1493 threshold =
1494 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1495 kCFPreferencesCurrentApplication,
1496 &valid_p);
1497 if (valid_p)
1498 cg_text_anti_aliasing_threshold = threshold;
1499 }
1500
1501 static int
1502 mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
1503 struct frame *f;
1504 GC gc;
1505 int x, y;
1506 XChar2b *buf;
1507 int nchars, bg_width, overstrike_p;
1508 {
1509 CGFloat port_height, gx, gy;
1510 int i;
1511 CGContextRef context;
1512 CGGlyph *glyphs;
1513 CGSize *advances;
1514
1515 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
1516 return 0;
1517
1518 port_height = FRAME_PIXEL_HEIGHT (f);
1519 gx = x;
1520 gy = port_height - y;
1521 glyphs = (CGGlyph *)buf;
1522 advances = alloca (sizeof (CGSize) * nchars);
1523 if (advances == NULL)
1524 return 0;
1525 for (i = 0; i < nchars; i++)
1526 {
1527 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1528
1529 advances[i].width = pcm->width;
1530 advances[i].height = 0;
1531 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1532 buf++;
1533 }
1534
1535 #if USE_CG_DRAWING
1536 context = mac_begin_cg_clip (f, gc);
1537 #else
1538 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1539 if (gc->n_clip_rects || bg_width)
1540 {
1541 CGContextTranslateCTM (context, 0, port_height);
1542 CGContextScaleCTM (context, 1, -1);
1543 if (gc->n_clip_rects)
1544 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1545 #endif
1546 if (bg_width)
1547 {
1548 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1549 CGContextFillRect
1550 (context,
1551 mac_rect_make (f, gx, y - FONT_BASE (GC_FONT (gc)),
1552 bg_width, FONT_HEIGHT (GC_FONT (gc))));
1553 }
1554 CGContextScaleCTM (context, 1, -1);
1555 CGContextTranslateCTM (context, 0, -port_height);
1556 #if !USE_CG_DRAWING
1557 }
1558 #endif
1559 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1560 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1561 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
1562 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1563 CGContextSetShouldAntialias (context, false);
1564 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1565 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1566 if (CGContextShowGlyphsWithAdvances != NULL)
1567 #endif
1568 {
1569 CGContextSetTextPosition (context, gx, gy);
1570 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1571 if (overstrike_p)
1572 {
1573 CGContextSetTextPosition (context, gx + 1.0f, gy);
1574 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1575 }
1576 }
1577 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1578 else /* CGContextShowGlyphsWithAdvances == NULL */
1579 #endif
1580 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1581 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1582 {
1583 for (i = 0; i < nchars; i++)
1584 {
1585 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1586 if (overstrike_p)
1587 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1588 gx += advances[i].width;
1589 }
1590 }
1591 #endif
1592 #if USE_CG_DRAWING
1593 mac_end_cg_clip (f);
1594 #else
1595 CGContextSynchronize (context);
1596 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1597 #endif
1598
1599 return 1;
1600 }
1601 #endif
1602
1603
1604 #if !USE_CG_DRAWING
1605 /* Mac replacement for XCopyArea: dest must be window. */
1606
1607 static void
1608 mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1609 Pixmap src;
1610 struct frame *f;
1611 GC gc;
1612 int src_x, src_y;
1613 unsigned int width, height;
1614 int dest_x, dest_y;
1615 {
1616 Rect src_r, dest_r;
1617
1618 mac_begin_clip (f, gc);
1619
1620 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1621 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1622
1623 ForeColor (blackColor);
1624 BackColor (whiteColor);
1625
1626 LockPixels (GetGWorldPixMap (src));
1627 #if TARGET_API_MAC_CARBON
1628 {
1629 CGrafPtr port;
1630
1631 GetPort (&port);
1632 LockPortBits (port);
1633 CopyBits (GetPortBitMapForCopyBits (src),
1634 GetPortBitMapForCopyBits (port),
1635 &src_r, &dest_r, srcCopy, 0);
1636 UnlockPortBits (port);
1637 }
1638 #else /* not TARGET_API_MAC_CARBON */
1639 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
1640 &src_r, &dest_r, srcCopy, 0);
1641 #endif /* not TARGET_API_MAC_CARBON */
1642 UnlockPixels (GetGWorldPixMap (src));
1643
1644 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1645
1646 mac_end_clip (gc);
1647 }
1648
1649
1650 static void
1651 mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
1652 width, height, dest_x, dest_y)
1653 Pixmap src, mask;
1654 struct frame *f;
1655 GC gc;
1656 int src_x, src_y;
1657 unsigned int width, height;
1658 int dest_x, dest_y;
1659 {
1660 Rect src_r, dest_r;
1661
1662 mac_begin_clip (f, gc);
1663
1664 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1665 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1666
1667 ForeColor (blackColor);
1668 BackColor (whiteColor);
1669
1670 LockPixels (GetGWorldPixMap (src));
1671 LockPixels (GetGWorldPixMap (mask));
1672 #if TARGET_API_MAC_CARBON
1673 {
1674 CGrafPtr port;
1675
1676 GetPort (&port);
1677 LockPortBits (port);
1678 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1679 GetPortBitMapForCopyBits (port),
1680 &src_r, &src_r, &dest_r);
1681 UnlockPortBits (port);
1682 }
1683 #else /* not TARGET_API_MAC_CARBON */
1684 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
1685 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
1686 #endif /* not TARGET_API_MAC_CARBON */
1687 UnlockPixels (GetGWorldPixMap (mask));
1688 UnlockPixels (GetGWorldPixMap (src));
1689
1690 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1691
1692 mac_end_clip (gc);
1693 }
1694 #endif /* !USE_CG_DRAWING */
1695
1696
1697 /* Mac replacement for XCopyArea: used only for scrolling. */
1698
1699 static void
1700 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1701 struct frame *f;
1702 GC gc;
1703 int src_x, src_y;
1704 unsigned int width, height;
1705 int dest_x, dest_y;
1706 {
1707 #if TARGET_API_MAC_CARBON
1708 Rect src_r;
1709 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1710
1711 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1712 #if USE_CG_DRAWING
1713 mac_prepare_for_quickdraw (f);
1714 #endif
1715 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1716 &src_r, dest_x - src_x, dest_y - src_y,
1717 kScrollWindowNoOptions, dummy);
1718 DisposeRgn (dummy);
1719 #else /* not TARGET_API_MAC_CARBON */
1720 Rect src_r, dest_r;
1721 WindowRef w = FRAME_MAC_WINDOW (f);
1722
1723 mac_begin_clip (f, gc);
1724
1725 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1726 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1727
1728 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1729 color mapping in CopyBits. Otherwise, it will be slow. */
1730 ForeColor (blackColor);
1731 BackColor (whiteColor);
1732 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
1733
1734 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1735
1736 mac_end_clip (gc);
1737 #endif /* not TARGET_API_MAC_CARBON */
1738 }
1739
1740
1741 /* Mac replacement for XChangeGC. */
1742
1743 static void
1744 XChangeGC (display, gc, mask, xgcv)
1745 Display *display;
1746 GC gc;
1747 unsigned long mask;
1748 XGCValues *xgcv;
1749 {
1750 if (mask & GCForeground)
1751 XSetForeground (display, gc, xgcv->foreground);
1752 if (mask & GCBackground)
1753 XSetBackground (display, gc, xgcv->background);
1754 if (mask & GCFont)
1755 XSetFont (display, gc, xgcv->font);
1756 }
1757
1758
1759 /* Mac replacement for XCreateGC. */
1760
1761 GC
1762 XCreateGC (display, d, mask, xgcv)
1763 Display *display;
1764 void *d;
1765 unsigned long mask;
1766 XGCValues *xgcv;
1767 {
1768 GC gc = xmalloc (sizeof (*gc));
1769
1770 bzero (gc, sizeof (*gc));
1771 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1772 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1773 if (CGColorGetTypeID != NULL)
1774 #endif
1775 {
1776 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1777 CGColorRetain (gc->cg_fore_color);
1778 CGColorRetain (gc->cg_back_color);
1779 }
1780 #endif
1781 XChangeGC (display, gc, mask, xgcv);
1782
1783 return gc;
1784 }
1785
1786
1787 /* Used in xfaces.c. */
1788
1789 void
1790 XFreeGC (display, gc)
1791 Display *display;
1792 GC gc;
1793 {
1794 if (gc->clip_region)
1795 DisposeRgn (gc->clip_region);
1796 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1797 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1798 if (CGColorGetTypeID != NULL)
1799 #endif
1800 {
1801 CGColorRelease (gc->cg_fore_color);
1802 CGColorRelease (gc->cg_back_color);
1803 }
1804 #endif
1805 xfree (gc);
1806 }
1807
1808
1809 /* Mac replacement for XGetGCValues. */
1810
1811 static void
1812 XGetGCValues (display, gc, mask, xgcv)
1813 Display *display;
1814 GC gc;
1815 unsigned long mask;
1816 XGCValues *xgcv;
1817 {
1818 if (mask & GCForeground)
1819 xgcv->foreground = gc->xgcv.foreground;
1820 if (mask & GCBackground)
1821 xgcv->background = gc->xgcv.background;
1822 if (mask & GCFont)
1823 xgcv->font = gc->xgcv.font;
1824 }
1825
1826
1827 /* Mac replacement for XSetForeground. */
1828
1829 void
1830 XSetForeground (display, gc, color)
1831 Display *display;
1832 GC gc;
1833 unsigned long color;
1834 {
1835 if (gc->xgcv.foreground != color)
1836 {
1837 gc->xgcv.foreground = color;
1838 gc->fore_color.red = RED16_FROM_ULONG (color);
1839 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1840 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
1841 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1842 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1843 if (CGColorGetTypeID != NULL)
1844 #endif
1845 {
1846 CGColorRelease (gc->cg_fore_color);
1847 if (color == 0)
1848 {
1849 gc->cg_fore_color = mac_cg_color_black;
1850 CGColorRetain (gc->cg_fore_color);
1851 }
1852 else
1853 {
1854 CGFloat rgba[4];
1855
1856 rgba[0] = gc->fore_color.red / 65535.0f;
1857 rgba[1] = gc->fore_color.green / 65535.0f;
1858 rgba[2] = gc->fore_color.blue / 65535.0f;
1859 rgba[3] = 1.0f;
1860 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1861 }
1862 }
1863 #endif
1864 }
1865 }
1866
1867
1868 /* Mac replacement for XSetBackground. */
1869
1870 void
1871 XSetBackground (display, gc, color)
1872 Display *display;
1873 GC gc;
1874 unsigned long color;
1875 {
1876 if (gc->xgcv.background != color)
1877 {
1878 gc->xgcv.background = color;
1879 gc->back_color.red = RED16_FROM_ULONG (color);
1880 gc->back_color.green = GREEN16_FROM_ULONG (color);
1881 gc->back_color.blue = BLUE16_FROM_ULONG (color);
1882 #if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1883 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1884 if (CGColorGetTypeID != NULL)
1885 #endif
1886 {
1887 CGColorRelease (gc->cg_back_color);
1888 if (color == 0)
1889 {
1890 gc->cg_back_color = mac_cg_color_black;
1891 CGColorRetain (gc->cg_back_color);
1892 }
1893 else
1894 {
1895 CGFloat rgba[4];
1896
1897 rgba[0] = gc->back_color.red / 65535.0f;
1898 rgba[1] = gc->back_color.green / 65535.0f;
1899 rgba[2] = gc->back_color.blue / 65535.0f;
1900 rgba[3] = 1.0f;
1901 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1902 }
1903 }
1904 #endif
1905 }
1906 }
1907
1908
1909 /* Mac replacement for XSetFont. */
1910
1911 static void
1912 XSetFont (display, gc, font)
1913 Display *display;
1914 GC gc;
1915 XFontStruct *font;
1916 {
1917 gc->xgcv.font = font;
1918 }
1919
1920
1921 /* Mac replacement for XSetClipRectangles. */
1922
1923 static void
1924 mac_set_clip_rectangles (f, gc, rectangles, n)
1925 struct frame *f;
1926 GC gc;
1927 Rect *rectangles;
1928 int n;
1929 {
1930 int i;
1931
1932 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1933
1934 gc->n_clip_rects = n;
1935 if (n > 0)
1936 {
1937 if (gc->clip_region == NULL)
1938 gc->clip_region = NewRgn ();
1939 RectRgn (gc->clip_region, rectangles);
1940 if (n > 1)
1941 {
1942 RgnHandle region = NewRgn ();
1943
1944 for (i = 1; i < n; i++)
1945 {
1946 RectRgn (region, rectangles + i);
1947 UnionRgn (gc->clip_region, region, gc->clip_region);
1948 }
1949 DisposeRgn (region);
1950 }
1951 }
1952 #if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1953 for (i = 0; i < n; i++)
1954 {
1955 Rect *rect = rectangles + i;
1956
1957 gc->clip_rects[i] = mac_rect_make (f, rect->left, rect->top,
1958 rect->right - rect->left,
1959 rect->bottom - rect->top);
1960 }
1961 #endif
1962 }
1963
1964
1965 /* Mac replacement for XSetClipMask. */
1966
1967 static INLINE void
1968 mac_reset_clip_rectangles (f, gc)
1969 struct frame *f;
1970 GC gc;
1971 {
1972 gc->n_clip_rects = 0;
1973 }
1974
1975
1976 /* Mac replacement for XSetWindowBackground. */
1977
1978 void
1979 XSetWindowBackground (display, w, color)
1980 Display *display;
1981 WindowRef w;
1982 unsigned long color;
1983 {
1984 #if !TARGET_API_MAC_CARBON
1985 AuxWinHandle aw_handle;
1986 CTabHandle ctab_handle;
1987 ColorSpecPtr ct_table;
1988 short ct_size;
1989 #endif
1990 RGBColor bg_color;
1991
1992 bg_color.red = RED16_FROM_ULONG (color);
1993 bg_color.green = GREEN16_FROM_ULONG (color);
1994 bg_color.blue = BLUE16_FROM_ULONG (color);
1995
1996 #if TARGET_API_MAC_CARBON
1997 SetWindowContentColor (w, &bg_color);
1998 #else
1999 if (GetAuxWin (w, &aw_handle))
2000 {
2001 ctab_handle = (*aw_handle)->awCTable;
2002 HandToHand ((Handle *) &ctab_handle);
2003 ct_table = (*ctab_handle)->ctTable;
2004 ct_size = (*ctab_handle)->ctSize;
2005 while (ct_size > -1)
2006 {
2007 if (ct_table->value == 0)
2008 {
2009 ct_table->rgb = bg_color;
2010 CTabChanged (ctab_handle);
2011 SetWinColor (w, (WCTabHandle) ctab_handle);
2012 }
2013 ct_size--;
2014 }
2015 }
2016 #endif
2017 }
2018
2019 /* Flush display of frame F, or of all frames if F is null. */
2020
2021 static void
2022 x_flush (f)
2023 struct frame *f;
2024 {
2025 #if TARGET_API_MAC_CARBON
2026 BLOCK_INPUT;
2027 #if USE_CG_DRAWING
2028 mac_prepare_for_quickdraw (f);
2029 #endif
2030 if (f)
2031 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
2032 else
2033 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
2034 UNBLOCK_INPUT;
2035 #endif
2036 }
2037
2038
2039 /* Remove calls to XFlush by defining XFlush to an empty replacement.
2040 Calls to XFlush should be unnecessary because the X output buffer
2041 is flushed automatically as needed by calls to XPending,
2042 XNextEvent, or XWindowEvent according to the XFlush man page.
2043 XTread_socket calls XPending. Removing XFlush improves
2044 performance. */
2045
2046 #define XFlush(DISPLAY) (void) 0
2047
2048 #if USE_CG_DRAWING
2049 static void
2050 mac_flush_display_optional (f)
2051 struct frame *f;
2052 {
2053 BLOCK_INPUT;
2054 mac_prepare_for_quickdraw (f);
2055 UNBLOCK_INPUT;
2056 }
2057 #endif
2058 \f
2059 /***********************************************************************
2060 Starting and ending an update
2061 ***********************************************************************/
2062
2063 /* Start an update of frame F. This function is installed as a hook
2064 for update_begin, i.e. it is called when update_begin is called.
2065 This function is called prior to calls to x_update_window_begin for
2066 each window being updated. */
2067
2068 static void
2069 x_update_begin (f)
2070 struct frame *f;
2071 {
2072 #if TARGET_API_MAC_CARBON
2073 /* During update of a frame, availability of input events is
2074 periodically checked with ReceiveNextEvent if
2075 redisplay-dont-pause is nil. That normally flushes window buffer
2076 changes for every check, and thus screen update looks waving even
2077 if no input is available. So we disable screen updates during
2078 update of a frame. */
2079 BLOCK_INPUT;
2080 DisableScreenUpdates ();
2081 UNBLOCK_INPUT;
2082 #endif
2083 }
2084
2085
2086 /* Start update of window W. Set the global variable updated_window
2087 to the window being updated and set output_cursor to the cursor
2088 position of W. */
2089
2090 static void
2091 x_update_window_begin (w)
2092 struct window *w;
2093 {
2094 struct frame *f = XFRAME (WINDOW_FRAME (w));
2095 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
2096
2097 updated_window = w;
2098 set_output_cursor (&w->cursor);
2099
2100 BLOCK_INPUT;
2101
2102 if (f == display_info->mouse_face_mouse_frame)
2103 {
2104 /* Don't do highlighting for mouse motion during the update. */
2105 display_info->mouse_face_defer = 1;
2106
2107 /* If F needs to be redrawn, simply forget about any prior mouse
2108 highlighting. */
2109 if (FRAME_GARBAGED_P (f))
2110 display_info->mouse_face_window = Qnil;
2111
2112 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
2113 their mouse_face_p flag set, which means that they are always
2114 unequal to rows in a desired matrix which never have that
2115 flag set. So, rows containing mouse-face glyphs are never
2116 scrolled, and we don't have to switch the mouse highlight off
2117 here to prevent it from being scrolled. */
2118
2119 /* Can we tell that this update does not affect the window
2120 where the mouse highlight is? If so, no need to turn off.
2121 Likewise, don't do anything if the frame is garbaged;
2122 in that case, the frame's current matrix that we would use
2123 is all wrong, and we will redisplay that line anyway. */
2124 if (!NILP (display_info->mouse_face_window)
2125 && w == XWINDOW (display_info->mouse_face_window))
2126 {
2127 int i;
2128
2129 for (i = 0; i < w->desired_matrix->nrows; ++i)
2130 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2131 break;
2132
2133 if (i < w->desired_matrix->nrows)
2134 clear_mouse_face (display_info);
2135 }
2136 #endif /* 0 */
2137 }
2138
2139 UNBLOCK_INPUT;
2140 }
2141
2142
2143 /* Draw a vertical window border from (x,y0) to (x,y1) */
2144
2145 static void
2146 mac_draw_vertical_window_border (w, x, y0, y1)
2147 struct window *w;
2148 int x, y0, y1;
2149 {
2150 struct frame *f = XFRAME (WINDOW_FRAME (w));
2151 struct face *face;
2152
2153 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2154 if (face)
2155 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2156 face->foreground);
2157
2158 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
2159 }
2160
2161 /* End update of window W (which is equal to updated_window).
2162
2163 Draw vertical borders between horizontally adjacent windows, and
2164 display W's cursor if CURSOR_ON_P is non-zero.
2165
2166 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2167 glyphs in mouse-face were overwritten. In that case we have to
2168 make sure that the mouse-highlight is properly redrawn.
2169
2170 W may be a menu bar pseudo-window in case we don't have X toolkit
2171 support. Such windows don't have a cursor, so don't display it
2172 here. */
2173
2174 static void
2175 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2176 struct window *w;
2177 int cursor_on_p, mouse_face_overwritten_p;
2178 {
2179 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
2180
2181 if (!w->pseudo_window_p)
2182 {
2183 BLOCK_INPUT;
2184
2185 if (cursor_on_p)
2186 display_and_set_cursor (w, 1, output_cursor.hpos,
2187 output_cursor.vpos,
2188 output_cursor.x, output_cursor.y);
2189
2190 if (draw_window_fringes (w, 1))
2191 x_draw_vertical_border (w);
2192
2193 UNBLOCK_INPUT;
2194 }
2195
2196 /* If a row with mouse-face was overwritten, arrange for
2197 XTframe_up_to_date to redisplay the mouse highlight. */
2198 if (mouse_face_overwritten_p)
2199 {
2200 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2201 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2202 dpyinfo->mouse_face_window = Qnil;
2203 }
2204
2205 updated_window = NULL;
2206 }
2207
2208
2209 /* End update of frame F. This function is installed as a hook in
2210 update_end. */
2211
2212 static void
2213 x_update_end (f)
2214 struct frame *f;
2215 {
2216 /* Mouse highlight may be displayed again. */
2217 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2218
2219 BLOCK_INPUT;
2220 #if TARGET_API_MAC_CARBON
2221 EnableScreenUpdates ();
2222 #endif
2223 XFlush (FRAME_MAC_DISPLAY (f));
2224 UNBLOCK_INPUT;
2225 }
2226
2227
2228 /* This function is called from various places in xdisp.c whenever a
2229 complete update has been performed. The global variable
2230 updated_window is not available here. */
2231
2232 static void
2233 XTframe_up_to_date (f)
2234 struct frame *f;
2235 {
2236 if (FRAME_MAC_P (f))
2237 {
2238 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2239
2240 if (dpyinfo->mouse_face_deferred_gc
2241 || f == dpyinfo->mouse_face_mouse_frame)
2242 {
2243 BLOCK_INPUT;
2244 if (dpyinfo->mouse_face_mouse_frame)
2245 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2246 dpyinfo->mouse_face_mouse_x,
2247 dpyinfo->mouse_face_mouse_y);
2248 dpyinfo->mouse_face_deferred_gc = 0;
2249 UNBLOCK_INPUT;
2250 }
2251 }
2252 }
2253
2254
2255 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
2256 arrow bitmaps, or clear the fringes if no bitmaps are required
2257 before DESIRED_ROW is made current. The window being updated is
2258 found in updated_window. This function is called from
2259 update_window_line only if it is known that there are differences
2260 between bitmaps to be drawn between current row and DESIRED_ROW. */
2261
2262 static void
2263 x_after_update_window_line (desired_row)
2264 struct glyph_row *desired_row;
2265 {
2266 struct window *w = updated_window;
2267 struct frame *f;
2268 int width, height;
2269
2270 xassert (w);
2271
2272 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2273 desired_row->redraw_fringe_bitmaps_p = 1;
2274
2275 /* When a window has disappeared, make sure that no rest of
2276 full-width rows stays visible in the internal border. Could
2277 check here if updated_window is the leftmost/rightmost window,
2278 but I guess it's not worth doing since vertically split windows
2279 are almost never used, internal border is rarely set, and the
2280 overhead is very small. */
2281 if (windows_or_buffers_changed
2282 && desired_row->full_width_p
2283 && (f = XFRAME (w->frame),
2284 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2285 width != 0)
2286 && (height = desired_row->visible_height,
2287 height > 0))
2288 {
2289 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2290
2291 /* Internal border is drawn below the tool bar. */
2292 if (WINDOWP (f->tool_bar_window)
2293 && w == XWINDOW (f->tool_bar_window))
2294 y -= width;
2295
2296 BLOCK_INPUT;
2297 mac_clear_area (f, 0, y, width, height);
2298 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
2299 UNBLOCK_INPUT;
2300 }
2301 }
2302
2303
2304 /* Draw the bitmap WHICH in one of the left or right fringes of
2305 window W. ROW is the glyph row for which to display the bitmap; it
2306 determines the vertical position at which the bitmap has to be
2307 drawn. */
2308
2309 static void
2310 x_draw_fringe_bitmap (w, row, p)
2311 struct window *w;
2312 struct glyph_row *row;
2313 struct draw_fringe_bitmap_params *p;
2314 {
2315 struct frame *f = XFRAME (WINDOW_FRAME (w));
2316 Display *display = FRAME_MAC_DISPLAY (f);
2317 struct face *face = p->face;
2318 int rowY;
2319 int overlay_p = p->overlay_p;
2320
2321 #ifdef MAC_OSX
2322 if (!overlay_p)
2323 {
2324 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2325
2326 #if 0 /* MAC_TODO: stipple */
2327 /* In case the same realized face is used for fringes and
2328 for something displayed in the text (e.g. face `region' on
2329 mono-displays, the fill style may have been changed to
2330 FillSolid in x_draw_glyph_string_background. */
2331 if (face->stipple)
2332 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2333 else
2334 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2335 #endif
2336
2337 /* If the fringe is adjacent to the left (right) scroll bar of a
2338 leftmost (rightmost, respectively) window, then extend its
2339 background to the gap between the fringe and the bar. */
2340 if ((WINDOW_LEFTMOST_P (w)
2341 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2342 || (WINDOW_RIGHTMOST_P (w)
2343 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2344 {
2345 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2346
2347 if (sb_width > 0)
2348 {
2349 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2350 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2351 * FRAME_COLUMN_WIDTH (f));
2352
2353 if (bx < 0
2354 && (left + width == p->x
2355 || p->x + p->wd == left))
2356 {
2357 /* Bitmap fills the fringe and we need background
2358 extension. */
2359 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2360
2361 bx = p->x;
2362 nx = p->wd;
2363 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2364 row->y));
2365 ny = row->visible_height;
2366 }
2367
2368 if (bx >= 0)
2369 {
2370 if (left + width == bx)
2371 {
2372 bx = left + sb_width;
2373 nx += width - sb_width;
2374 }
2375 else if (bx + nx == left)
2376 nx += width - sb_width;
2377 }
2378 }
2379 }
2380
2381 if (bx >= 0)
2382 {
2383 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2384 /* The fringe background has already been filled. */
2385 overlay_p = 1;
2386 }
2387
2388 #if 0 /* MAC_TODO: stipple */
2389 if (!face->stipple)
2390 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2391 #endif
2392 }
2393 #endif /* MAC_OSX */
2394
2395 /* Must clip because of partially visible lines. */
2396 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2397 if (p->y < rowY)
2398 {
2399 /* Adjust position of "bottom aligned" bitmap on partially
2400 visible last row. */
2401 int oldY = row->y;
2402 int oldVH = row->visible_height;
2403 row->visible_height = p->h;
2404 row->y -= rowY - p->y;
2405 x_clip_to_row (w, row, -1, face->gc);
2406 row->y = oldY;
2407 row->visible_height = oldVH;
2408 }
2409 else
2410 x_clip_to_row (w, row, -1, face->gc);
2411
2412 #ifndef MAC_OSX
2413 if (p->bx >= 0 && !p->overlay_p)
2414 {
2415 #if 0 /* MAC_TODO: stipple */
2416 /* In case the same realized face is used for fringes and
2417 for something displayed in the text (e.g. face `region' on
2418 mono-displays, the fill style may have been changed to
2419 FillSolid in x_draw_glyph_string_background. */
2420 if (face->stipple)
2421 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2422 else
2423 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2424 #endif
2425
2426 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
2427
2428 #if 0 /* MAC_TODO: stipple */
2429 if (!face->stipple)
2430 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2431 #endif
2432 }
2433 #endif /* !MAC_OSX */
2434
2435 if (p->which
2436 #if USE_CG_DRAWING
2437 && p->which < max_fringe_bmp
2438 #endif
2439 )
2440 {
2441 XGCValues gcv;
2442
2443 XGetGCValues (display, face->gc, GCForeground, &gcv);
2444 XSetForeground (display, face->gc,
2445 (p->cursor_p
2446 ? (p->overlay_p ? face->background
2447 : f->output_data.mac->cursor_pixel)
2448 : face->foreground));
2449 #if USE_CG_DRAWING
2450 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
2451 p->wd, p->h, p->x, p->y, overlay_p);
2452 #else
2453 mac_draw_bitmap (f, face->gc, p->x, p->y,
2454 p->wd, p->h, p->bits + p->dh, overlay_p);
2455 #endif
2456 XSetForeground (display, face->gc, gcv.foreground);
2457 }
2458
2459 mac_reset_clip_rectangles (f, face->gc);
2460 }
2461
2462 #if USE_CG_DRAWING
2463 static void
2464 mac_define_fringe_bitmap (which, bits, h, wd)
2465 int which;
2466 unsigned short *bits;
2467 int h, wd;
2468 {
2469 int i;
2470 CGDataProviderRef provider;
2471
2472 if (which >= max_fringe_bmp)
2473 {
2474 i = max_fringe_bmp;
2475 max_fringe_bmp = which + 20;
2476 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2477 while (i < max_fringe_bmp)
2478 fringe_bmp[i++] = 0;
2479 }
2480
2481 for (i = 0; i < h; i++)
2482 bits[i] = ~bits[i];
2483
2484 BLOCK_INPUT;
2485
2486 provider = CGDataProviderCreateWithData (NULL, bits,
2487 sizeof (unsigned short) * h, NULL);
2488 if (provider)
2489 {
2490 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2491 sizeof (unsigned short),
2492 provider, NULL, 0);
2493 CGDataProviderRelease (provider);
2494 }
2495
2496 UNBLOCK_INPUT;
2497 }
2498
2499 static void
2500 mac_destroy_fringe_bitmap (which)
2501 int which;
2502 {
2503 if (which >= max_fringe_bmp)
2504 return;
2505
2506 if (fringe_bmp[which])
2507 {
2508 BLOCK_INPUT;
2509 CGImageRelease (fringe_bmp[which]);
2510 UNBLOCK_INPUT;
2511 }
2512 fringe_bmp[which] = 0;
2513 }
2514 #endif
2515 \f
2516
2517 /* This is called when starting Emacs and when restarting after
2518 suspend. When starting Emacs, no window is mapped. And nothing
2519 must be done to Emacs's own window if it is suspended (though that
2520 rarely happens). */
2521
2522 static void
2523 XTset_terminal_modes (struct terminal *t)
2524 {
2525 }
2526
2527 /* This is called when exiting or suspending Emacs. Exiting will make
2528 the windows go away, and suspending requires no action. */
2529
2530 static void
2531 XTreset_terminal_modes (struct terminal *t)
2532 {
2533 }
2534
2535
2536 \f
2537 /***********************************************************************
2538 Display Iterator
2539 ***********************************************************************/
2540
2541 /* Function prototypes of this page. */
2542
2543 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
2544 static int mac_encode_char P_ ((int, XChar2b *, struct font_info *,
2545 struct charset *, int *));
2546
2547
2548 static void
2549 pcm_init (pcm, count)
2550 XCharStruct *pcm;
2551 int count;
2552 {
2553 bzero (pcm, sizeof (XCharStruct) * count);
2554 while (--count >= 0)
2555 {
2556 pcm->descent = PCM_INVALID;
2557 pcm++;
2558 }
2559 }
2560
2561 static enum pcm_status
2562 pcm_get_status (pcm)
2563 const XCharStruct *pcm;
2564 {
2565 int height = pcm->ascent + pcm->descent;
2566
2567 /* Negative height means some special status. */
2568 return height >= 0 ? PCM_VALID : height;
2569 }
2570
2571 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2572 is not contained in the font. */
2573
2574 static INLINE XCharStruct *
2575 x_per_char_metric (font, char2b)
2576 XFontStruct *font;
2577 XChar2b *char2b;
2578 {
2579 /* The result metric information. */
2580 XCharStruct *pcm = NULL;
2581
2582 xassert (font && char2b);
2583
2584 #if USE_ATSUI
2585 if (font->mac_style)
2586 {
2587 XCharStruct **row = font->bounds.rows + char2b->byte1;
2588
2589 if (*row == NULL)
2590 {
2591 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2592 pcm_init (*row, 0x100);
2593 }
2594 pcm = *row + char2b->byte2;
2595 if (pcm_get_status (pcm) != PCM_VALID)
2596 {
2597 BLOCK_INPUT;
2598 mac_query_char_extents (font->mac_style,
2599 (char2b->byte1 << 8) + char2b->byte2,
2600 NULL, NULL, pcm, NULL);
2601 UNBLOCK_INPUT;
2602 }
2603 }
2604 else
2605 {
2606 #endif
2607 if (font->bounds.per_char != NULL)
2608 {
2609 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2610 {
2611 /* min_char_or_byte2 specifies the linear character index
2612 corresponding to the first element of the per_char array,
2613 max_char_or_byte2 is the index of the last character. A
2614 character with non-zero CHAR2B->byte1 is not in the font.
2615 A character with byte2 less than min_char_or_byte2 or
2616 greater max_char_or_byte2 is not in the font. */
2617 if (char2b->byte1 == 0
2618 && char2b->byte2 >= font->min_char_or_byte2
2619 && char2b->byte2 <= font->max_char_or_byte2)
2620 pcm = font->bounds.per_char
2621 + (char2b->byte2 - font->min_char_or_byte2);
2622 }
2623 else
2624 {
2625 /* If either min_byte1 or max_byte1 are nonzero, both
2626 min_char_or_byte2 and max_char_or_byte2 are less than
2627 256, and the 2-byte character index values corresponding
2628 to the per_char array element N (counting from 0) are:
2629
2630 byte1 = N/D + min_byte1
2631 byte2 = N\D + min_char_or_byte2
2632
2633 where:
2634
2635 D = max_char_or_byte2 - min_char_or_byte2 + 1
2636 / = integer division
2637 \ = integer modulus */
2638 if (char2b->byte1 >= font->min_byte1
2639 && char2b->byte1 <= font->max_byte1
2640 && char2b->byte2 >= font->min_char_or_byte2
2641 && char2b->byte2 <= font->max_char_or_byte2)
2642 {
2643 pcm = (font->bounds.per_char
2644 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2645 * (char2b->byte1 - font->min_byte1))
2646 + (char2b->byte2 - font->min_char_or_byte2));
2647 }
2648 }
2649 }
2650 else
2651 {
2652 /* If the per_char pointer is null, all glyphs between the first
2653 and last character indexes inclusive have the same
2654 information, as given by both min_bounds and max_bounds. */
2655 if (char2b->byte2 >= font->min_char_or_byte2
2656 && char2b->byte2 <= font->max_char_or_byte2)
2657 pcm = &font->max_bounds;
2658 }
2659 #if USE_ATSUI
2660 }
2661 #endif
2662
2663 return ((pcm == NULL
2664 || (pcm->width == 0
2665 #if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2666 && (pcm->rbearing - pcm->lbearing) == 0
2667 #endif
2668 ))
2669 ? NULL : pcm);
2670 }
2671
2672 /* RIF:
2673 */
2674
2675 static XCharStruct *
2676 mac_per_char_metric (font, char2b, font_type)
2677 XFontStruct *font;
2678 XChar2b *char2b;
2679 int font_type;
2680 {
2681 return x_per_char_metric (font, char2b);
2682 }
2683
2684 /* RIF:
2685 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
2686 the two-byte form of C. Encoding is returned in *CHAR2B. */
2687
2688 static int
2689 mac_encode_char (c, char2b, font_info, charset, two_byte_p)
2690 int c;
2691 XChar2b *char2b;
2692 struct font_info *font_info;
2693 struct charset *charset;
2694 int *two_byte_p;
2695 {
2696 XFontStruct *font = font_info->font;
2697
2698 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2699 This may be either a program in a special encoder language or a
2700 fixed encoding. */
2701 if (font_info->font_encoder)
2702 {
2703 /* It's a program. */
2704 struct ccl_program *ccl = font_info->font_encoder;
2705
2706 check_ccl_update (ccl);
2707 if (CHARSET_DIMENSION (charset) == 1)
2708 {
2709 ccl->reg[0] = CHARSET_ID (charset);
2710 ccl->reg[1] = XCHAR2B_BYTE2 (char2b);
2711 ccl->reg[2] = -1;
2712 }
2713 else
2714 {
2715 ccl->reg[0] = CHARSET_ID (charset);
2716 ccl->reg[1] = XCHAR2B_BYTE1 (char2b);
2717 ccl->reg[2] = XCHAR2B_BYTE2 (char2b);
2718 }
2719
2720 ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
2721
2722 /* We assume that MSBs are appropriately set/reset by CCL
2723 program. */
2724 if (font->max_byte1 == 0) /* 1-byte font */
2725 STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
2726 else
2727 STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
2728 }
2729 else if (font_info->encoding_type)
2730 {
2731 /* Fixed encoding scheme. See fontset.h for the meaning of the
2732 encoding numbers. */
2733 unsigned char enc = font_info->encoding_type;
2734
2735 if ((enc == 1 || enc == 2)
2736 && CHARSET_DIMENSION (charset) == 2)
2737 char2b->byte1 |= 0x80;
2738
2739 if (enc == 1 || enc == 3)
2740 char2b->byte2 |= 0x80;
2741
2742 if (enc == 4)
2743 {
2744 int code = (char2b->byte1 << 8) | char2b->byte2;
2745
2746 JIS_TO_SJIS (code);
2747 STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
2748 }
2749 }
2750
2751 if (two_byte_p)
2752 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
2753
2754 return FONT_TYPE_UNKNOWN;
2755 }
2756
2757
2758 \f
2759 /***********************************************************************
2760 Glyph display
2761 ***********************************************************************/
2762
2763
2764
2765 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2766 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2767 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2768 int));
2769 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2770 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2771 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2772 static void x_draw_glyph_string P_ ((struct glyph_string *));
2773 static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2774 static void x_set_cursor_gc P_ ((struct glyph_string *));
2775 static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2776 static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2777 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2778 unsigned long *, double, int));*/
2779 static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2780 double, int, unsigned long));
2781 static void x_setup_relief_colors P_ ((struct glyph_string *));
2782 static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2783 static void x_draw_image_relief P_ ((struct glyph_string *));
2784 static void x_draw_image_foreground P_ ((struct glyph_string *));
2785 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2786 int, int, int));
2787 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2788 int, int, int, int, int, int,
2789 Rect *));
2790 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2791 int, int, int, Rect *));
2792
2793 #if GLYPH_DEBUG
2794 static void x_check_font P_ ((struct frame *, XFontStruct *));
2795 #endif
2796
2797
2798 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
2799 face. */
2800
2801 static void
2802 x_set_cursor_gc (s)
2803 struct glyph_string *s;
2804 {
2805 if (s->font == FRAME_FONT (s->f)
2806 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2807 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2808 && !s->cmp)
2809 s->gc = s->f->output_data.mac->cursor_gc;
2810 else
2811 {
2812 /* Cursor on non-default face: must merge. */
2813 XGCValues xgcv;
2814 unsigned long mask;
2815
2816 xgcv.background = s->f->output_data.mac->cursor_pixel;
2817 xgcv.foreground = s->face->background;
2818
2819 /* If the glyph would be invisible, try a different foreground. */
2820 if (xgcv.foreground == xgcv.background)
2821 xgcv.foreground = s->face->foreground;
2822 if (xgcv.foreground == xgcv.background)
2823 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2824 if (xgcv.foreground == xgcv.background)
2825 xgcv.foreground = s->face->foreground;
2826
2827 /* Make sure the cursor is distinct from text in this face. */
2828 if (xgcv.background == s->face->background
2829 && xgcv.foreground == s->face->foreground)
2830 {
2831 xgcv.background = s->face->foreground;
2832 xgcv.foreground = s->face->background;
2833 }
2834
2835 IF_DEBUG (x_check_font (s->f, s->font));
2836 xgcv.font = s->font;
2837 mask = GCForeground | GCBackground | GCFont;
2838
2839 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2840 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2841 mask, &xgcv);
2842 else
2843 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2844 = XCreateGC (s->display, s->window, mask, &xgcv);
2845
2846 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2847 }
2848 }
2849
2850
2851 /* Set up S->gc of glyph string S for drawing text in mouse face. */
2852
2853 static void
2854 x_set_mouse_face_gc (s)
2855 struct glyph_string *s;
2856 {
2857 int face_id;
2858 struct face *face;
2859
2860 /* What face has to be used last for the mouse face? */
2861 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2862 face = FACE_FROM_ID (s->f, face_id);
2863 if (face == NULL)
2864 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2865
2866 if (s->first_glyph->type == CHAR_GLYPH)
2867 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
2868 else
2869 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
2870 s->face = FACE_FROM_ID (s->f, face_id);
2871 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2872
2873 /* If font in this face is same as S->font, use it. */
2874 if (s->font == s->face->font)
2875 s->gc = s->face->gc;
2876 else
2877 {
2878 /* Otherwise construct scratch_cursor_gc with values from FACE
2879 but font FONT. */
2880 XGCValues xgcv;
2881 unsigned long mask;
2882
2883 xgcv.background = s->face->background;
2884 xgcv.foreground = s->face->foreground;
2885 IF_DEBUG (x_check_font (s->f, s->font));
2886 xgcv.font = s->font;
2887 mask = GCForeground | GCBackground | GCFont;
2888
2889 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2890 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2891 mask, &xgcv);
2892 else
2893 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2894 = XCreateGC (s->display, s->window, mask, &xgcv);
2895
2896 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2897 }
2898
2899 xassert (s->gc != 0);
2900 }
2901
2902
2903 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2904 Faces to use in the mode line have already been computed when the
2905 matrix was built, so there isn't much to do, here. */
2906
2907 static INLINE void
2908 x_set_mode_line_face_gc (s)
2909 struct glyph_string *s;
2910 {
2911 s->gc = s->face->gc;
2912 }
2913
2914
2915 /* Set S->gc of glyph string S for drawing that glyph string. Set
2916 S->stippled_p to a non-zero value if the face of S has a stipple
2917 pattern. */
2918
2919 static INLINE void
2920 x_set_glyph_string_gc (s)
2921 struct glyph_string *s;
2922 {
2923 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2924
2925 if (s->hl == DRAW_NORMAL_TEXT)
2926 {
2927 s->gc = s->face->gc;
2928 s->stippled_p = s->face->stipple != 0;
2929 }
2930 else if (s->hl == DRAW_INVERSE_VIDEO)
2931 {
2932 x_set_mode_line_face_gc (s);
2933 s->stippled_p = s->face->stipple != 0;
2934 }
2935 else if (s->hl == DRAW_CURSOR)
2936 {
2937 x_set_cursor_gc (s);
2938 s->stippled_p = 0;
2939 }
2940 else if (s->hl == DRAW_MOUSE_FACE)
2941 {
2942 x_set_mouse_face_gc (s);
2943 s->stippled_p = s->face->stipple != 0;
2944 }
2945 else if (s->hl == DRAW_IMAGE_RAISED
2946 || s->hl == DRAW_IMAGE_SUNKEN)
2947 {
2948 s->gc = s->face->gc;
2949 s->stippled_p = s->face->stipple != 0;
2950 }
2951 else
2952 {
2953 s->gc = s->face->gc;
2954 s->stippled_p = s->face->stipple != 0;
2955 }
2956
2957 /* GC must have been set. */
2958 xassert (s->gc != 0);
2959 }
2960
2961
2962 /* Set clipping for output of glyph string S. S may be part of a mode
2963 line or menu if we don't have X toolkit support. */
2964
2965 static INLINE void
2966 x_set_glyph_string_clipping (s)
2967 struct glyph_string *s;
2968 {
2969 Rect rects[MAX_CLIP_RECTS];
2970 int n;
2971
2972 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
2973 mac_set_clip_rectangles (s->f, s->gc, rects, n);
2974 }
2975
2976
2977 /* RIF:
2978 Compute left and right overhang of glyph string S. If S is a glyph
2979 string for a composition, assume overhangs don't exist. */
2980
2981 static void
2982 mac_compute_glyph_string_overhangs (s)
2983 struct glyph_string *s;
2984 {
2985 if (!(s->cmp == NULL
2986 && s->first_glyph->type == CHAR_GLYPH))
2987 return;
2988
2989 if (!s->two_byte_p
2990 #if USE_ATSUI
2991 || s->font->mac_style
2992 #endif
2993 )
2994 {
2995 XCharStruct cs;
2996
2997 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2998 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2999 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
3000 }
3001 else
3002 {
3003 Rect r;
3004 MacFontStruct *font = s->font;
3005
3006 #if USE_CG_DRAWING
3007 mac_prepare_for_quickdraw (s->f);
3008 #endif
3009 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
3010
3011 TextFont (font->mac_fontnum);
3012 TextSize (font->mac_fontsize);
3013 TextFace (font->mac_fontface);
3014
3015 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
3016
3017 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
3018 s->left_overhang = r.left < 0 ? -r.left : 0;
3019 }
3020 }
3021
3022
3023 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
3024
3025 static INLINE void
3026 x_clear_glyph_string_rect (s, x, y, w, h)
3027 struct glyph_string *s;
3028 int x, y, w, h;
3029 {
3030 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
3031 }
3032
3033
3034 /* Draw the background of glyph_string S. If S->background_filled_p
3035 is non-zero don't draw it. FORCE_P non-zero means draw the
3036 background even if it wouldn't be drawn normally. This is used
3037 when a string preceding S draws into the background of S, or S
3038 contains the first component of a composition. */
3039
3040 static void
3041 x_draw_glyph_string_background (s, force_p)
3042 struct glyph_string *s;
3043 int force_p;
3044 {
3045 /* Nothing to do if background has already been drawn or if it
3046 shouldn't be drawn in the first place. */
3047 if (!s->background_filled_p)
3048 {
3049 int box_line_width = max (s->face->box_line_width, 0);
3050
3051 #if 0 /* MAC_TODO: stipple */
3052 if (s->stippled_p)
3053 {
3054 /* Fill background with a stipple pattern. */
3055 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3056 XFillRectangle (s->display, s->window, s->gc, s->x,
3057 s->y + box_line_width,
3058 s->background_width,
3059 s->height - 2 * box_line_width);
3060 XSetFillStyle (s->display, s->gc, FillSolid);
3061 s->background_filled_p = 1;
3062 }
3063 else
3064 #endif
3065 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3066 || s->font_not_found_p
3067 || s->extends_to_end_of_line_p
3068 || force_p)
3069 {
3070 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
3071 s->background_width,
3072 s->height - 2 * box_line_width);
3073 s->background_filled_p = 1;
3074 }
3075 }
3076 }
3077
3078
3079 /* Draw the foreground of glyph string S. */
3080
3081 static void
3082 x_draw_glyph_string_foreground (s)
3083 struct glyph_string *s;
3084 {
3085 int i, x, bg_width;
3086
3087 /* If first glyph of S has a left box line, start drawing the text
3088 of S to the right of that box line. */
3089 if (s->face->box != FACE_NO_BOX
3090 && s->first_glyph->left_box_line_p)
3091 x = s->x + eabs (s->face->box_line_width);
3092 else
3093 x = s->x;
3094
3095 /* Draw characters of S as rectangles if S's font could not be
3096 loaded. */
3097 if (s->font_not_found_p)
3098 {
3099 for (i = 0; i < s->nchars; ++i)
3100 {
3101 struct glyph *g = s->first_glyph + i;
3102 mac_draw_rectangle (s->f, s->gc, x, s->y,
3103 g->pixel_width - 1, s->height - 1);
3104 x += g->pixel_width;
3105 }
3106 }
3107 else
3108 {
3109 char *char1b = (char *) s->char2b;
3110 int boff = s->font_info->baseline_offset;
3111
3112 if (s->font_info->vertical_centering)
3113 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3114
3115 /* If we can use 8-bit functions, condense S->char2b. */
3116 if (!s->two_byte_p
3117 #if USE_ATSUI
3118 && GC_FONT (s->gc)->mac_style == NULL
3119 #endif
3120 )
3121 for (i = 0; i < s->nchars; ++i)
3122 char1b[i] = s->char2b[i].byte2;
3123
3124 /* Draw text with XDrawString if background has already been
3125 filled. Otherwise, use XDrawImageString. (Note that
3126 XDrawImageString is usually faster than XDrawString.) Always
3127 use XDrawImageString when drawing the cursor so that there is
3128 no chance that characters under a box cursor are invisible. */
3129 if (s->for_overlaps
3130 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3131 bg_width = 0; /* Corresponds to XDrawString. */
3132 else
3133 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3134
3135 if (s->two_byte_p
3136 #if USE_ATSUI
3137 || GC_FONT (s->gc)->mac_style
3138 #endif
3139 )
3140 #if USE_CG_TEXT_DRAWING
3141 if (!s->two_byte_p
3142 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
3143 s->char2b, s->nchars, bg_width,
3144 s->face->overstrike))
3145 ;
3146 else
3147 #endif
3148 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
3149 s->char2b, s->nchars, bg_width,
3150 s->face->overstrike);
3151 else
3152 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
3153 char1b, s->nchars, bg_width,
3154 s->face->overstrike);
3155 }
3156 }
3157
3158 /* Draw the foreground of composite glyph string S. */
3159
3160 static void
3161 x_draw_composite_glyph_string_foreground (s)
3162 struct glyph_string *s;
3163 {
3164 int i, x;
3165
3166 /* If first glyph of S has a left box line, start drawing the text
3167 of S to the right of that box line. */
3168 if (s->face->box != FACE_NO_BOX
3169 && s->first_glyph->left_box_line_p)
3170 x = s->x + eabs (s->face->box_line_width);
3171 else
3172 x = s->x;
3173
3174 /* S is a glyph string for a composition. S->gidx is the index of
3175 the first character drawn for glyphs of this composition.
3176 S->gidx == 0 means we are drawing the very first character of
3177 this composition. */
3178
3179 /* Draw a rectangle for the composition if the font for the very
3180 first character of the composition could not be loaded. */
3181 if (s->font_not_found_p)
3182 {
3183 if (s->gidx == 0)
3184 mac_draw_rectangle (s->f, s->gc, x, s->y,
3185 s->width - 1, s->height - 1);
3186 }
3187 else
3188 {
3189 for (i = 0; i < s->nchars; i++, ++s->gidx)
3190 if (mac_per_char_metric (GC_FONT (s->gc), s->char2b + i, 0) == NULL)
3191 /* This is a nonexistent or zero-width glyph such as a
3192 combining diacritic. Draw a rectangle. */
3193 mac_draw_rectangle (s->f, s->gc,
3194 x + s->cmp->offsets[s->gidx * 2], s->y,
3195 FONT_WIDTH (GC_FONT (s->gc)) - 1, s->height - 1);
3196 else
3197 mac_draw_image_string_16 (s->f, s->gc,
3198 x + s->cmp->offsets[s->gidx * 2],
3199 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3200 s->char2b + i, 1, 0, s->face->overstrike);
3201 }
3202 }
3203
3204
3205 #ifdef USE_X_TOOLKIT
3206
3207 static struct frame *x_frame_of_widget P_ ((Widget));
3208
3209
3210 /* Return the frame on which widget WIDGET is used.. Abort if frame
3211 cannot be determined. */
3212
3213 static struct frame *
3214 x_frame_of_widget (widget)
3215 Widget widget;
3216 {
3217 struct x_display_info *dpyinfo;
3218 Lisp_Object tail;
3219 struct frame *f;
3220
3221 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3222
3223 /* Find the top-level shell of the widget. Note that this function
3224 can be called when the widget is not yet realized, so XtWindow
3225 (widget) == 0. That's the reason we can't simply use
3226 x_any_window_to_frame. */
3227 while (!XtIsTopLevelShell (widget))
3228 widget = XtParent (widget);
3229
3230 /* Look for a frame with that top-level widget. Allocate the color
3231 on that frame to get the right gamma correction value. */
3232 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
3233 if (FRAMEP (XCAR (tail))
3234 && (f = XFRAME (XCAR (tail)),
3235 (f->output_data.nothing != 1
3236 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3237 && f->output_data.x->widget == widget)
3238 return f;
3239
3240 abort ();
3241 }
3242
3243
3244 /* Allocate the color COLOR->pixel on the screen and display of
3245 widget WIDGET in colormap CMAP. If an exact match cannot be
3246 allocated, try the nearest color available. Value is non-zero
3247 if successful. This is called from lwlib. */
3248
3249 int
3250 x_alloc_nearest_color_for_widget (widget, cmap, color)
3251 Widget widget;
3252 Colormap cmap;
3253 XColor *color;
3254 {
3255 struct frame *f = x_frame_of_widget (widget);
3256 return x_alloc_nearest_color (f, cmap, color);
3257 }
3258
3259
3260 #endif /* USE_X_TOOLKIT */
3261
3262 #if 0 /* MAC_TODO */
3263
3264 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3265 CMAP. If an exact match can't be allocated, try the nearest color
3266 available. Value is non-zero if successful. Set *COLOR to the
3267 color allocated. */
3268
3269 int
3270 x_alloc_nearest_color (f, cmap, color)
3271 struct frame *f;
3272 Colormap cmap;
3273 XColor *color;
3274 {
3275 Display *display = FRAME_X_DISPLAY (f);
3276 Screen *screen = FRAME_X_SCREEN (f);
3277 int rc;
3278
3279 gamma_correct (f, color);
3280 rc = XAllocColor (display, cmap, color);
3281 if (rc == 0)
3282 {
3283 /* If we got to this point, the colormap is full, so we're going
3284 to try to get the next closest color. The algorithm used is
3285 a least-squares matching, which is what X uses for closest
3286 color matching with StaticColor visuals. */
3287 int nearest, i;
3288 unsigned long nearest_delta = ~0;
3289 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3290 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3291
3292 for (i = 0; i < ncells; ++i)
3293 cells[i].pixel = i;
3294 XQueryColors (display, cmap, cells, ncells);
3295
3296 for (nearest = i = 0; i < ncells; ++i)
3297 {
3298 long dred = (color->red >> 8) - (cells[i].red >> 8);
3299 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3300 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3301 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3302
3303 if (delta < nearest_delta)
3304 {
3305 nearest = i;
3306 nearest_delta = delta;
3307 }
3308 }
3309
3310 color->red = cells[nearest].red;
3311 color->green = cells[nearest].green;
3312 color->blue = cells[nearest].blue;
3313 rc = XAllocColor (display, cmap, color);
3314 }
3315
3316 #ifdef DEBUG_X_COLORS
3317 if (rc)
3318 register_color (color->pixel);
3319 #endif /* DEBUG_X_COLORS */
3320
3321 return rc;
3322 }
3323
3324
3325 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3326 It's necessary to do this instead of just using PIXEL directly to
3327 get color reference counts right. */
3328
3329 unsigned long
3330 x_copy_color (f, pixel)
3331 struct frame *f;
3332 unsigned long pixel;
3333 {
3334 XColor color;
3335
3336 color.pixel = pixel;
3337 BLOCK_INPUT;
3338 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3339 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3340 UNBLOCK_INPUT;
3341 #ifdef DEBUG_X_COLORS
3342 register_color (pixel);
3343 #endif
3344 return color.pixel;
3345 }
3346
3347
3348 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3349 It's necessary to do this instead of just using PIXEL directly to
3350 get color reference counts right. */
3351
3352 unsigned long
3353 x_copy_dpy_color (dpy, cmap, pixel)
3354 Display *dpy;
3355 Colormap cmap;
3356 unsigned long pixel;
3357 {
3358 XColor color;
3359
3360 color.pixel = pixel;
3361 BLOCK_INPUT;
3362 XQueryColor (dpy, cmap, &color);
3363 XAllocColor (dpy, cmap, &color);
3364 UNBLOCK_INPUT;
3365 #ifdef DEBUG_X_COLORS
3366 register_color (pixel);
3367 #endif
3368 return color.pixel;
3369 }
3370
3371 #endif /* MAC_TODO */
3372
3373
3374 /* Brightness beyond which a color won't have its highlight brightness
3375 boosted.
3376
3377 Nominally, highlight colors for `3d' faces are calculated by
3378 brightening an object's color by a constant scale factor, but this
3379 doesn't yield good results for dark colors, so for colors who's
3380 brightness is less than this value (on a scale of 0-255) have to
3381 use an additional additive factor.
3382
3383 The value here is set so that the default menu-bar/mode-line color
3384 (grey75) will not have its highlights changed at all. */
3385 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3386
3387
3388 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
3389 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3390 If this produces the same color as COLOR, try a color where all RGB
3391 values have DELTA added. Return the allocated color in *COLOR.
3392 DISPLAY is the X display, CMAP is the colormap to operate on.
3393 Value is non-zero if successful. */
3394
3395 static int
3396 mac_alloc_lighter_color (f, color, factor, delta)
3397 struct frame *f;
3398 unsigned long *color;
3399 double factor;
3400 int delta;
3401 {
3402 unsigned long new;
3403 long bright;
3404
3405 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3406 delta /= 256;
3407
3408 /* Change RGB values by specified FACTOR. Avoid overflow! */
3409 xassert (factor >= 0);
3410 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3411 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3412 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3413
3414 /* Calculate brightness of COLOR. */
3415 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3416 + BLUE_FROM_ULONG (*color)) / 6;
3417
3418 /* We only boost colors that are darker than
3419 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3420 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3421 /* Make an additive adjustment to NEW, because it's dark enough so
3422 that scaling by FACTOR alone isn't enough. */
3423 {
3424 /* How far below the limit this color is (0 - 1, 1 being darker). */
3425 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3426 /* The additive adjustment. */
3427 int min_delta = delta * dimness * factor / 2;
3428
3429 if (factor < 1)
3430 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3431 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3432 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3433 else
3434 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3435 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3436 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3437 }
3438
3439 if (new == *color)
3440 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3441 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3442 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3443
3444 /* MAC_TODO: Map to palette and retry with delta if same? */
3445 /* MAC_TODO: Free colors (if using palette)? */
3446
3447 if (new == *color)
3448 return 0;
3449
3450 *color = new;
3451
3452 return 1;
3453 }
3454
3455
3456 /* Set up the foreground color for drawing relief lines of glyph
3457 string S. RELIEF is a pointer to a struct relief containing the GC
3458 with which lines will be drawn. Use a color that is FACTOR or
3459 DELTA lighter or darker than the relief's background which is found
3460 in S->f->output_data.x->relief_background. If such a color cannot
3461 be allocated, use DEFAULT_PIXEL, instead. */
3462
3463 static void
3464 x_setup_relief_color (f, relief, factor, delta, default_pixel)
3465 struct frame *f;
3466 struct relief *relief;
3467 double factor;
3468 int delta;
3469 unsigned long default_pixel;
3470 {
3471 XGCValues xgcv;
3472 struct mac_output *di = f->output_data.mac;
3473 unsigned long mask = GCForeground;
3474 unsigned long pixel;
3475 unsigned long background = di->relief_background;
3476 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3477
3478 /* MAC_TODO: Free colors (if using palette)? */
3479
3480 /* Allocate new color. */
3481 xgcv.foreground = default_pixel;
3482 pixel = background;
3483 if (dpyinfo->n_planes != 1
3484 && mac_alloc_lighter_color (f, &pixel, factor, delta))
3485 {
3486 relief->allocated_p = 1;
3487 xgcv.foreground = relief->pixel = pixel;
3488 }
3489
3490 if (relief->gc == 0)
3491 {
3492 #if 0 /* MAC_TODO: stipple */
3493 xgcv.stipple = dpyinfo->gray;
3494 mask |= GCStipple;
3495 #endif
3496 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3497 }
3498 else
3499 XChangeGC (NULL, relief->gc, mask, &xgcv);
3500 }
3501
3502
3503 /* Set up colors for the relief lines around glyph string S. */
3504
3505 static void
3506 x_setup_relief_colors (s)
3507 struct glyph_string *s;
3508 {
3509 struct mac_output *di = s->f->output_data.mac;
3510 unsigned long color;
3511
3512 if (s->face->use_box_color_for_shadows_p)
3513 color = s->face->box_color;
3514 else if (s->first_glyph->type == IMAGE_GLYPH
3515 && s->img->pixmap
3516 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3517 color = IMAGE_BACKGROUND (s->img, s->f, 0);
3518 else
3519 {
3520 XGCValues xgcv;
3521
3522 /* Get the background color of the face. */
3523 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3524 color = xgcv.background;
3525 }
3526
3527 if (di->white_relief.gc == 0
3528 || color != di->relief_background)
3529 {
3530 di->relief_background = color;
3531 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3532 WHITE_PIX_DEFAULT (s->f));
3533 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3534 BLACK_PIX_DEFAULT (s->f));
3535 }
3536 }
3537
3538
3539 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
3540 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3541 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3542 relief. LEFT_P non-zero means draw a relief on the left side of
3543 the rectangle. RIGHT_P non-zero means draw a relief on the right
3544 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3545 when drawing. */
3546
3547 static void
3548 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3549 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
3550 struct frame *f;
3551 int left_x, top_y, right_x, bottom_y, width;
3552 int top_p, bot_p, left_p, right_p, raised_p;
3553 Rect *clip_rect;
3554 {
3555 Display *dpy = FRAME_MAC_DISPLAY (f);
3556 int i;
3557 GC gc;
3558
3559 if (raised_p)
3560 gc = f->output_data.mac->white_relief.gc;
3561 else
3562 gc = f->output_data.mac->black_relief.gc;
3563 mac_set_clip_rectangles (f, gc, clip_rect, 1);
3564
3565 /* Top. */
3566 if (top_p)
3567 for (i = 0; i < width; ++i)
3568 mac_draw_line (f, gc,
3569 left_x + i * left_p, top_y + i,
3570 right_x + 1 - i * right_p, top_y + i);
3571
3572 /* Left. */
3573 if (left_p)
3574 for (i = 0; i < width; ++i)
3575 mac_draw_line (f, gc,
3576 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
3577
3578 mac_reset_clip_rectangles (f, gc);
3579 if (raised_p)
3580 gc = f->output_data.mac->black_relief.gc;
3581 else
3582 gc = f->output_data.mac->white_relief.gc;
3583 mac_set_clip_rectangles (f, gc, clip_rect, 1);
3584
3585 /* Bottom. */
3586 if (bot_p)
3587 for (i = 0; i < width; ++i)
3588 mac_draw_line (f, gc,
3589 left_x + i * left_p, bottom_y - i,
3590 right_x + 1 - i * right_p, bottom_y - i);
3591
3592 /* Right. */
3593 if (right_p)
3594 for (i = 0; i < width; ++i)
3595 mac_draw_line (f, gc,
3596 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3597
3598 mac_reset_clip_rectangles (f, gc);
3599 }
3600
3601
3602 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3603 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3604 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3605 left side of the rectangle. RIGHT_P non-zero means draw a line
3606 on the right side of the rectangle. CLIP_RECT is the clipping
3607 rectangle to use when drawing. */
3608
3609 static void
3610 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3611 left_p, right_p, clip_rect)
3612 struct glyph_string *s;
3613 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
3614 Rect *clip_rect;
3615 {
3616 XGCValues xgcv;
3617
3618 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3619 XSetForeground (s->display, s->gc, s->face->box_color);
3620 mac_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
3621
3622 /* Top. */
3623 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3624 right_x - left_x + 1, width);
3625
3626 /* Left. */
3627 if (left_p)
3628 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3629 width, bottom_y - top_y + 1);
3630
3631 /* Bottom. */
3632 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3633 right_x - left_x + 1, width);
3634
3635 /* Right. */
3636 if (right_p)
3637 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3638 top_y, width, bottom_y - top_y + 1);
3639
3640 XSetForeground (s->display, s->gc, xgcv.foreground);
3641 mac_reset_clip_rectangles (s->f, s->gc);
3642 }
3643
3644
3645 /* Draw a box around glyph string S. */
3646
3647 static void
3648 x_draw_glyph_string_box (s)
3649 struct glyph_string *s;
3650 {
3651 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3652 int left_p, right_p;
3653 struct glyph *last_glyph;
3654 Rect clip_rect;
3655
3656 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3657 ? WINDOW_RIGHT_EDGE_X (s->w)
3658 : window_box_right (s->w, s->area));
3659
3660 /* The glyph that may have a right box line. */
3661 last_glyph = (s->cmp || s->img
3662 ? s->first_glyph
3663 : s->first_glyph + s->nchars - 1);
3664
3665 width = eabs (s->face->box_line_width);
3666 raised_p = s->face->box == FACE_RAISED_BOX;
3667 left_x = s->x;
3668 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3669 ? last_x - 1
3670 : min (last_x, s->x + s->background_width) - 1);
3671 top_y = s->y;
3672 bottom_y = top_y + s->height - 1;
3673
3674 left_p = (s->first_glyph->left_box_line_p
3675 || (s->hl == DRAW_MOUSE_FACE
3676 && (s->prev == NULL
3677 || s->prev->hl != s->hl)));
3678 right_p = (last_glyph->right_box_line_p
3679 || (s->hl == DRAW_MOUSE_FACE
3680 && (s->next == NULL
3681 || s->next->hl != s->hl)));
3682
3683 get_glyph_string_clip_rect (s, &clip_rect);
3684
3685 if (s->face->box == FACE_SIMPLE_BOX)
3686 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3687 left_p, right_p, &clip_rect);
3688 else
3689 {
3690 x_setup_relief_colors (s);
3691 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3692 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
3693 }
3694 }
3695
3696
3697 /* Draw foreground of image glyph string S. */
3698
3699 static void
3700 x_draw_image_foreground (s)
3701 struct glyph_string *s;
3702 {
3703 int x = s->x;
3704 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3705
3706 /* If first glyph of S has a left box line, start drawing it to the
3707 right of that line. */
3708 if (s->face->box != FACE_NO_BOX
3709 && s->first_glyph->left_box_line_p
3710 && s->slice.x == 0)
3711 x += eabs (s->face->box_line_width);
3712
3713 /* If there is a margin around the image, adjust x- and y-position
3714 by that margin. */
3715 if (s->slice.x == 0)
3716 x += s->img->hmargin;
3717 if (s->slice.y == 0)
3718 y += s->img->vmargin;
3719
3720 if (s->img->pixmap)
3721 {
3722 x_set_glyph_string_clipping (s);
3723
3724 #if USE_CG_DRAWING
3725 mac_draw_cg_image (s->img->data.ptr_val,
3726 s->f, s->gc, s->slice.x, s->slice.y,
3727 s->slice.width, s->slice.height, x, y, 1);
3728 #endif
3729 if (s->img->mask)
3730 #if !USE_CG_DRAWING
3731 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3732 s->f, s->gc, s->slice.x, s->slice.y,
3733 s->slice.width, s->slice.height, x, y);
3734 #else
3735 ;
3736 #endif
3737 else
3738 {
3739 #if !USE_CG_DRAWING
3740 mac_copy_area (s->img->pixmap,
3741 s->f, s->gc, s->slice.x, s->slice.y,
3742 s->slice.width, s->slice.height, x, y);
3743 #endif
3744
3745 /* When the image has a mask, we can expect that at
3746 least part of a mouse highlight or a block cursor will
3747 be visible. If the image doesn't have a mask, make
3748 a block cursor visible by drawing a rectangle around
3749 the image. I believe it's looking better if we do
3750 nothing here for mouse-face. */
3751 if (s->hl == DRAW_CURSOR)
3752 {
3753 int r = s->img->relief;
3754 if (r < 0) r = -r;
3755 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
3756 s->slice.width + r*2 - 1,
3757 s->slice.height + r*2 - 1);
3758 }
3759 }
3760 }
3761 else
3762 /* Draw a rectangle if image could not be loaded. */
3763 mac_draw_rectangle (s->f, s->gc, x, y,
3764 s->slice.width - 1, s->slice.height - 1);
3765 }
3766
3767
3768 /* Draw a relief around the image glyph string S. */
3769
3770 static void
3771 x_draw_image_relief (s)
3772 struct glyph_string *s;
3773 {
3774 int x0, y0, x1, y1, thick, raised_p;
3775 Rect r;
3776 int x = s->x;
3777 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3778
3779 /* If first glyph of S has a left box line, start drawing it to the
3780 right of that line. */
3781 if (s->face->box != FACE_NO_BOX
3782 && s->first_glyph->left_box_line_p
3783 && s->slice.x == 0)
3784 x += eabs (s->face->box_line_width);
3785
3786 /* If there is a margin around the image, adjust x- and y-position
3787 by that margin. */
3788 if (s->slice.x == 0)
3789 x += s->img->hmargin;
3790 if (s->slice.y == 0)
3791 y += s->img->vmargin;
3792
3793 if (s->hl == DRAW_IMAGE_SUNKEN
3794 || s->hl == DRAW_IMAGE_RAISED)
3795 {
3796 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3797 raised_p = s->hl == DRAW_IMAGE_RAISED;
3798 }
3799 else
3800 {
3801 thick = eabs (s->img->relief);
3802 raised_p = s->img->relief > 0;
3803 }
3804
3805 x0 = x - thick;
3806 y0 = y - thick;
3807 x1 = x + s->slice.width + thick - 1;
3808 y1 = y + s->slice.height + thick - 1;
3809
3810 x_setup_relief_colors (s);
3811 get_glyph_string_clip_rect (s, &r);
3812 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3813 s->slice.y == 0,
3814 s->slice.y + s->slice.height == s->img->height,
3815 s->slice.x == 0,
3816 s->slice.x + s->slice.width == s->img->width,
3817 &r);
3818 }
3819
3820
3821 /* Draw part of the background of glyph string S. X, Y, W, and H
3822 give the rectangle to draw. */
3823
3824 static void
3825 x_draw_glyph_string_bg_rect (s, x, y, w, h)
3826 struct glyph_string *s;
3827 int x, y, w, h;
3828 {
3829 #if 0 /* MAC_TODO: stipple */
3830 if (s->stippled_p)
3831 {
3832 /* Fill background with a stipple pattern. */
3833 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3834 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3835 XSetFillStyle (s->display, s->gc, FillSolid);
3836 }
3837 else
3838 #endif /* MAC_TODO */
3839 x_clear_glyph_string_rect (s, x, y, w, h);
3840 }
3841
3842
3843 /* Draw image glyph string S.
3844
3845 s->y
3846 s->x +-------------------------
3847 | s->face->box
3848 |
3849 | +-------------------------
3850 | | s->img->margin
3851 | |
3852 | | +-------------------
3853 | | | the image
3854
3855 */
3856
3857 static void
3858 x_draw_image_glyph_string (s)
3859 struct glyph_string *s;
3860 {
3861 int x, y;
3862 int box_line_hwidth = eabs (s->face->box_line_width);
3863 int box_line_vwidth = max (s->face->box_line_width, 0);
3864 int height;
3865
3866 height = s->height - 2 * box_line_vwidth;
3867
3868
3869 /* Fill background with face under the image. Do it only if row is
3870 taller than image or if image has a clip mask to reduce
3871 flickering. */
3872 s->stippled_p = s->face->stipple != 0;
3873 if (height > s->slice.height
3874 || s->img->hmargin
3875 || s->img->vmargin
3876 || s->img->mask
3877 || s->img->pixmap == 0
3878 || s->width != s->background_width)
3879 {
3880 x = s->x;
3881 if (s->first_glyph->left_box_line_p
3882 && s->slice.x == 0)
3883 x += box_line_hwidth;
3884
3885 y = s->y;
3886 if (s->slice.y == 0)
3887 y += box_line_vwidth;
3888
3889 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3890
3891 s->background_filled_p = 1;
3892 }
3893
3894 /* Draw the foreground. */
3895 x_draw_image_foreground (s);
3896
3897 /* If we must draw a relief around the image, do it. */
3898 if (s->img->relief
3899 || s->hl == DRAW_IMAGE_RAISED
3900 || s->hl == DRAW_IMAGE_SUNKEN)
3901 x_draw_image_relief (s);
3902 }
3903
3904
3905 /* Draw stretch glyph string S. */
3906
3907 static void
3908 x_draw_stretch_glyph_string (s)
3909 struct glyph_string *s;
3910 {
3911 xassert (s->first_glyph->type == STRETCH_GLYPH);
3912
3913 if (s->hl == DRAW_CURSOR
3914 && !x_stretch_cursor_p)
3915 {
3916 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3917 as wide as the stretch glyph. */
3918 int width, background_width = s->background_width;
3919 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3920
3921 if (x < left_x)
3922 {
3923 background_width -= left_x - x;
3924 x = left_x;
3925 }
3926 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3927
3928 /* Draw cursor. */
3929 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3930
3931 /* Clear rest using the GC of the original non-cursor face. */
3932 if (width < background_width)
3933 {
3934 int y = s->y;
3935 int w = background_width - width, h = s->height;
3936 Rect r;
3937 GC gc;
3938
3939 x += width;
3940 if (s->row->mouse_face_p
3941 && cursor_in_mouse_face_p (s->w))
3942 {
3943 x_set_mouse_face_gc (s);
3944 gc = s->gc;
3945 }
3946 else
3947 gc = s->face->gc;
3948
3949 get_glyph_string_clip_rect (s, &r);
3950 mac_set_clip_rectangles (s->f, gc, &r, 1);
3951
3952 #if 0 /* MAC_TODO: stipple */
3953 if (s->face->stipple)
3954 {
3955 /* Fill background with a stipple pattern. */
3956 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3957 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3958 XSetFillStyle (s->display, gc, FillSolid);
3959 }
3960 else
3961 #endif /* MAC_TODO */
3962 mac_erase_rectangle (s->f, gc, x, y, w, h);
3963 }
3964 }
3965 else if (!s->background_filled_p)
3966 {
3967 int background_width = s->background_width;
3968 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3969
3970 /* Don't draw into left margin, fringe or scrollbar area
3971 except for header line and mode line. */
3972 if (x < left_x && !s->row->mode_line_p)
3973 {
3974 background_width -= left_x - x;
3975 x = left_x;
3976 }
3977 if (background_width > 0)
3978 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3979 }
3980
3981 s->background_filled_p = 1;
3982 }
3983
3984
3985 /* Draw glyph string S. */
3986
3987 static void
3988 x_draw_glyph_string (s)
3989 struct glyph_string *s;
3990 {
3991 int relief_drawn_p = 0;
3992
3993 /* If S draws into the background of its successor that does not
3994 draw a cursor, draw the background of the successor first so that
3995 S can draw into it. This makes S->next use XDrawString instead
3996 of XDrawImageString. */
3997 if (s->next && s->right_overhang && !s->for_overlaps
3998 && s->next->hl != DRAW_CURSOR)
3999 {
4000 xassert (s->next->img == NULL);
4001 x_set_glyph_string_gc (s->next);
4002 x_set_glyph_string_clipping (s->next);
4003 x_draw_glyph_string_background (s->next, 1);
4004 }
4005
4006 /* Set up S->gc, set clipping and draw S. */
4007 x_set_glyph_string_gc (s);
4008
4009 /* Draw relief (if any) in advance for char/composition so that the
4010 glyph string can be drawn over it. */
4011 if (!s->for_overlaps
4012 && s->face->box != FACE_NO_BOX
4013 && (s->first_glyph->type == CHAR_GLYPH
4014 || s->first_glyph->type == COMPOSITE_GLYPH))
4015
4016 {
4017 x_set_glyph_string_clipping (s);
4018 x_draw_glyph_string_background (s, 1);
4019 x_draw_glyph_string_box (s);
4020 x_set_glyph_string_clipping (s);
4021 relief_drawn_p = 1;
4022 }
4023 else
4024 x_set_glyph_string_clipping (s);
4025
4026 switch (s->first_glyph->type)
4027 {
4028 case IMAGE_GLYPH:
4029 x_draw_image_glyph_string (s);
4030 break;
4031
4032 case STRETCH_GLYPH:
4033 x_draw_stretch_glyph_string (s);
4034 break;
4035
4036 case CHAR_GLYPH:
4037 if (s->for_overlaps)
4038 s->background_filled_p = 1;
4039 else
4040 x_draw_glyph_string_background (s, 0);
4041 x_draw_glyph_string_foreground (s);
4042 break;
4043
4044 case COMPOSITE_GLYPH:
4045 if (s->for_overlaps || s->gidx > 0)
4046 s->background_filled_p = 1;
4047 else
4048 x_draw_glyph_string_background (s, 1);
4049 x_draw_composite_glyph_string_foreground (s);
4050 break;
4051
4052 default:
4053 abort ();
4054 }
4055
4056 if (!s->for_overlaps)
4057 {
4058 /* Draw underline. */
4059 if (s->face->underline_p)
4060 {
4061 unsigned long tem, h;
4062 int y;
4063
4064 #if 0
4065 /* Get the underline thickness. Default is 1 pixel. */
4066 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4067 #endif
4068 h = 1;
4069
4070 y = s->y + s->height - h;
4071 if (!x_underline_at_descent_line)
4072 {
4073 /* Get the underline position. This is the recommended
4074 vertical offset in pixels from the baseline to the top of
4075 the underline. This is a signed value according to the
4076 specs, and its default is
4077
4078 ROUND ((maximum descent) / 2), with
4079 ROUND(x) = floor (x + 0.5) */
4080
4081 #if 0
4082 if (x_use_underline_position_properties
4083 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4084 y = s->ybase + (long) tem;
4085 else
4086 #endif
4087 if (s->face->font)
4088 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4089 }
4090
4091 if (s->face->underline_defaulted_p)
4092 mac_fill_rectangle (s->f, s->gc, s->x, y,
4093 s->background_width, h);
4094 else
4095 {
4096 XGCValues xgcv;
4097 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4098 XSetForeground (s->display, s->gc, s->face->underline_color);
4099 mac_fill_rectangle (s->f, s->gc, s->x, y,
4100 s->background_width, h);
4101 XSetForeground (s->display, s->gc, xgcv.foreground);
4102 }
4103 }
4104
4105 /* Draw overline. */
4106 if (s->face->overline_p)
4107 {
4108 unsigned long dy = 0, h = 1;
4109
4110 if (s->face->overline_color_defaulted_p)
4111 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4112 s->background_width, h);
4113 else
4114 {
4115 XGCValues xgcv;
4116 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4117 XSetForeground (s->display, s->gc, s->face->overline_color);
4118 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4119 s->background_width, h);
4120 XSetForeground (s->display, s->gc, xgcv.foreground);
4121 }
4122 }
4123
4124 /* Draw strike-through. */
4125 if (s->face->strike_through_p)
4126 {
4127 unsigned long h = 1;
4128 unsigned long dy = (s->height - h) / 2;
4129
4130 if (s->face->strike_through_color_defaulted_p)
4131 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4132 s->width, h);
4133 else
4134 {
4135 XGCValues xgcv;
4136 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4137 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4138 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4139 s->width, h);
4140 XSetForeground (s->display, s->gc, xgcv.foreground);
4141 }
4142 }
4143
4144 /* Draw relief if not yet drawn. */
4145 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
4146 x_draw_glyph_string_box (s);
4147 }
4148
4149 /* Reset clipping. */
4150 mac_reset_clip_rectangles (s->f, s->gc);
4151 }
4152
4153 /* Shift display to make room for inserted glyphs. */
4154
4155 void
4156 mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4157 struct frame *f;
4158 int x, y, width, height, shift_by;
4159 {
4160 mac_scroll_area (f, f->output_data.mac->normal_gc,
4161 x, y, width, height,
4162 x + shift_by, y);
4163 }
4164
4165 /* Delete N glyphs at the nominal cursor position. Not implemented
4166 for X frames. */
4167
4168 static void
4169 x_delete_glyphs (n)
4170 register int n;
4171 {
4172 abort ();
4173 }
4174
4175
4176 /* Clear entire frame. If updating_frame is non-null, clear that
4177 frame. Otherwise clear the selected frame. */
4178
4179 static void
4180 x_clear_frame (struct frame *f)
4181 {
4182 /* Clearing the frame will erase any cursor, so mark them all as no
4183 longer visible. */
4184 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4185 output_cursor.hpos = output_cursor.vpos = 0;
4186 output_cursor.x = -1;
4187
4188 /* We don't set the output cursor here because there will always
4189 follow an explicit cursor_to. */
4190 BLOCK_INPUT;
4191 mac_clear_window (f);
4192
4193 /* We have to clear the scroll bars, too. If we have changed
4194 colors or something like that, then they should be notified. */
4195 x_scroll_bar_clear (f);
4196
4197 XFlush (FRAME_MAC_DISPLAY (f));
4198 UNBLOCK_INPUT;
4199 }
4200
4201
4202 \f
4203 /* Invert the middle quarter of the frame for .15 sec. */
4204
4205 /* We use the select system call to do the waiting, so we have to make
4206 sure it's available. If it isn't, we just won't do visual bells. */
4207
4208 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4209
4210
4211 /* Subtract the `struct timeval' values X and Y, storing the result in
4212 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4213
4214 static int
4215 timeval_subtract (result, x, y)
4216 struct timeval *result, x, y;
4217 {
4218 /* Perform the carry for the later subtraction by updating y. This
4219 is safer because on some systems the tv_sec member is unsigned. */
4220 if (x.tv_usec < y.tv_usec)
4221 {
4222 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4223 y.tv_usec -= 1000000 * nsec;
4224 y.tv_sec += nsec;
4225 }
4226
4227 if (x.tv_usec - y.tv_usec > 1000000)
4228 {
4229 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4230 y.tv_usec += 1000000 * nsec;
4231 y.tv_sec -= nsec;
4232 }
4233
4234 /* Compute the time remaining to wait. tv_usec is certainly
4235 positive. */
4236 result->tv_sec = x.tv_sec - y.tv_sec;
4237 result->tv_usec = x.tv_usec - y.tv_usec;
4238
4239 /* Return indication of whether the result should be considered
4240 negative. */
4241 return x.tv_sec < y.tv_sec;
4242 }
4243
4244 void
4245 XTflash (f)
4246 struct frame *f;
4247 {
4248 /* Get the height not including a menu bar widget. */
4249 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4250 /* Height of each line to flash. */
4251 int flash_height = FRAME_LINE_HEIGHT (f);
4252 /* These will be the left and right margins of the rectangles. */
4253 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4254 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4255
4256 int width;
4257
4258 /* Don't flash the area between a scroll bar and the frame
4259 edge it is next to. */
4260 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4261 {
4262 case vertical_scroll_bar_left:
4263 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4264 break;
4265
4266 case vertical_scroll_bar_right:
4267 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4268 break;
4269
4270 default:
4271 break;
4272 }
4273
4274 width = flash_right - flash_left;
4275
4276 BLOCK_INPUT;
4277
4278 /* If window is tall, flash top and bottom line. */
4279 if (height > 3 * FRAME_LINE_HEIGHT (f))
4280 {
4281 mac_invert_rectangle (f, flash_left,
4282 (FRAME_INTERNAL_BORDER_WIDTH (f)
4283 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4284 width, flash_height);
4285 mac_invert_rectangle (f, flash_left,
4286 (height - flash_height
4287 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4288 width, flash_height);
4289 }
4290 else
4291 /* If it is short, flash it all. */
4292 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4293 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4294
4295 x_flush (f);
4296
4297 {
4298 struct timeval wakeup;
4299
4300 EMACS_GET_TIME (wakeup);
4301
4302 /* Compute time to wait until, propagating carry from usecs. */
4303 wakeup.tv_usec += 150000;
4304 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4305 wakeup.tv_usec %= 1000000;
4306
4307 /* Keep waiting until past the time wakeup or any input gets
4308 available. */
4309 while (! detect_input_pending ())
4310 {
4311 struct timeval current;
4312 struct timeval timeout;
4313
4314 EMACS_GET_TIME (current);
4315
4316 /* Break if result would be negative. */
4317 if (timeval_subtract (&current, wakeup, current))
4318 break;
4319
4320 /* How long `select' should wait. */
4321 timeout.tv_sec = 0;
4322 timeout.tv_usec = 10000;
4323
4324 /* Try to wait that long--but we might wake up sooner. */
4325 select (0, NULL, NULL, NULL, &timeout);
4326 }
4327 }
4328
4329 /* If window is tall, flash top and bottom line. */
4330 if (height > 3 * FRAME_LINE_HEIGHT (f))
4331 {
4332 mac_invert_rectangle (f, flash_left,
4333 (FRAME_INTERNAL_BORDER_WIDTH (f)
4334 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4335 width, flash_height);
4336 mac_invert_rectangle (f, flash_left,
4337 (height - flash_height
4338 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4339 width, flash_height);
4340 }
4341 else
4342 /* If it is short, flash it all. */
4343 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4344 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4345
4346 x_flush (f);
4347
4348 UNBLOCK_INPUT;
4349 }
4350
4351 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4352
4353
4354 /* Make audible bell. */
4355
4356 void
4357 XTring_bell ()
4358 {
4359 struct frame *f = SELECTED_FRAME ();
4360
4361 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4362 if (visible_bell)
4363 XTflash (f);
4364 else
4365 #endif
4366 {
4367 BLOCK_INPUT;
4368 SysBeep (1);
4369 XFlush (FRAME_MAC_DISPLAY (f));
4370 UNBLOCK_INPUT;
4371 }
4372 }
4373
4374 \f
4375 /* Specify how many text lines, from the top of the window,
4376 should be affected by insert-lines and delete-lines operations.
4377 This, and those operations, are used only within an update
4378 that is bounded by calls to x_update_begin and x_update_end. */
4379
4380 static void
4381 XTset_terminal_window (n)
4382 register int n;
4383 {
4384 /* This function intentionally left blank. */
4385 }
4386
4387
4388 \f
4389 /***********************************************************************
4390 Line Dance
4391 ***********************************************************************/
4392
4393 /* Perform an insert-lines or delete-lines operation, inserting N
4394 lines or deleting -N lines at vertical position VPOS. */
4395
4396 static void
4397 x_ins_del_lines (vpos, n)
4398 int vpos, n;
4399 {
4400 abort ();
4401 }
4402
4403
4404 /* Scroll part of the display as described by RUN. */
4405
4406 static void
4407 x_scroll_run (w, run)
4408 struct window *w;
4409 struct run *run;
4410 {
4411 struct frame *f = XFRAME (w->frame);
4412 int x, y, width, height, from_y, to_y, bottom_y;
4413
4414 /* Get frame-relative bounding box of the text display area of W,
4415 without mode lines. Include in this box the left and right
4416 fringe of W. */
4417 window_box (w, -1, &x, &y, &width, &height);
4418
4419 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4420 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4421 bottom_y = y + height;
4422
4423 if (to_y < from_y)
4424 {
4425 /* Scrolling up. Make sure we don't copy part of the mode
4426 line at the bottom. */
4427 if (from_y + run->height > bottom_y)
4428 height = bottom_y - from_y;
4429 else
4430 height = run->height;
4431 }
4432 else
4433 {
4434 /* Scolling down. Make sure we don't copy over the mode line.
4435 at the bottom. */
4436 if (to_y + run->height > bottom_y)
4437 height = bottom_y - to_y;
4438 else
4439 height = run->height;
4440 }
4441
4442 BLOCK_INPUT;
4443
4444 /* Cursor off. Will be switched on again in x_update_window_end. */
4445 updated_window = w;
4446 x_clear_cursor (w);
4447
4448 mac_scroll_area (f, f->output_data.mac->normal_gc,
4449 x, from_y,
4450 width, height,
4451 x, to_y);
4452
4453 UNBLOCK_INPUT;
4454 }
4455
4456
4457 \f
4458 /***********************************************************************
4459 Exposure Events
4460 ***********************************************************************/
4461
4462 \f
4463 static void
4464 frame_highlight (f)
4465 struct frame *f;
4466 {
4467 x_update_cursor (f, 1);
4468 }
4469
4470 static void
4471 frame_unhighlight (f)
4472 struct frame *f;
4473 {
4474 x_update_cursor (f, 1);
4475 }
4476
4477 /* The focus has changed. Update the frames as necessary to reflect
4478 the new situation. Note that we can't change the selected frame
4479 here, because the Lisp code we are interrupting might become confused.
4480 Each event gets marked with the frame in which it occurred, so the
4481 Lisp code can tell when the switch took place by examining the events. */
4482
4483 static void
4484 x_new_focus_frame (dpyinfo, frame)
4485 struct x_display_info *dpyinfo;
4486 struct frame *frame;
4487 {
4488 struct frame *old_focus = dpyinfo->x_focus_frame;
4489
4490 if (frame != dpyinfo->x_focus_frame)
4491 {
4492 /* Set this before calling other routines, so that they see
4493 the correct value of x_focus_frame. */
4494 dpyinfo->x_focus_frame = frame;
4495
4496 if (old_focus && old_focus->auto_lower)
4497 x_lower_frame (old_focus);
4498
4499 #if 0
4500 selected_frame = frame;
4501 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4502 selected_frame);
4503 Fselect_window (selected_frame->selected_window, Qnil);
4504 choose_minibuf_frame ();
4505 #endif /* ! 0 */
4506
4507 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4508 pending_autoraise_frame = dpyinfo->x_focus_frame;
4509 else
4510 pending_autoraise_frame = 0;
4511
4512 #if USE_MAC_FONT_PANEL
4513 if (frame)
4514 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
4515 #endif
4516 }
4517
4518 x_frame_rehighlight (dpyinfo);
4519 }
4520
4521 /* Handle FocusIn and FocusOut state changes for FRAME.
4522 If FRAME has focus and there exists more than one frame, puts
4523 a FOCUS_IN_EVENT into *BUFP. */
4524
4525 static void
4526 mac_focus_changed (type, dpyinfo, frame, bufp)
4527 int type;
4528 struct mac_display_info *dpyinfo;
4529 struct frame *frame;
4530 struct input_event *bufp;
4531 {
4532 if (type == activeFlag)
4533 {
4534 if (dpyinfo->x_focus_event_frame != frame)
4535 {
4536 x_new_focus_frame (dpyinfo, frame);
4537 dpyinfo->x_focus_event_frame = frame;
4538
4539 /* Don't stop displaying the initial startup message
4540 for a switch-frame event we don't need. */
4541 if (NILP (Vterminal_frame)
4542 && CONSP (Vframe_list)
4543 && !NILP (XCDR (Vframe_list)))
4544 {
4545 bufp->kind = FOCUS_IN_EVENT;
4546 XSETFRAME (bufp->frame_or_window, frame);
4547 }
4548 }
4549 }
4550 else
4551 {
4552 if (dpyinfo->x_focus_event_frame == frame)
4553 {
4554 dpyinfo->x_focus_event_frame = 0;
4555 x_new_focus_frame (dpyinfo, 0);
4556 }
4557 }
4558 }
4559
4560 /* The focus may have changed. Figure out if it is a real focus change,
4561 by checking both FocusIn/Out and Enter/LeaveNotify events.
4562
4563 Returns FOCUS_IN_EVENT event in *BUFP. */
4564
4565 static void
4566 x_detect_focus_change (dpyinfo, event, bufp)
4567 struct mac_display_info *dpyinfo;
4568 const EventRecord *event;
4569 struct input_event *bufp;
4570 {
4571 struct frame *frame;
4572
4573 frame = mac_window_to_frame ((WindowRef) event->message);
4574 if (! frame)
4575 return;
4576
4577 /* On Mac, this is only called from focus events, so no switch needed. */
4578 mac_focus_changed ((event->modifiers & activeFlag),
4579 dpyinfo, frame, bufp);
4580 }
4581
4582
4583 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4584
4585 void
4586 x_mouse_leave (dpyinfo)
4587 struct x_display_info *dpyinfo;
4588 {
4589 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4590 }
4591
4592 /* The focus has changed, or we have redirected a frame's focus to
4593 another frame (this happens when a frame uses a surrogate
4594 mini-buffer frame). Shift the highlight as appropriate.
4595
4596 The FRAME argument doesn't necessarily have anything to do with which
4597 frame is being highlighted or un-highlighted; we only use it to find
4598 the appropriate X display info. */
4599
4600 static void
4601 XTframe_rehighlight (frame)
4602 struct frame *frame;
4603 {
4604 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4605 }
4606
4607 static void
4608 x_frame_rehighlight (dpyinfo)
4609 struct x_display_info *dpyinfo;
4610 {
4611 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4612
4613 if (dpyinfo->x_focus_frame)
4614 {
4615 dpyinfo->x_highlight_frame
4616 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4617 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4618 : dpyinfo->x_focus_frame);
4619 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4620 {
4621 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4622 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4623 }
4624 }
4625 else
4626 dpyinfo->x_highlight_frame = 0;
4627
4628 if (dpyinfo->x_highlight_frame != old_highlight)
4629 {
4630 if (old_highlight)
4631 frame_unhighlight (old_highlight);
4632 if (dpyinfo->x_highlight_frame)
4633 frame_highlight (dpyinfo->x_highlight_frame);
4634 }
4635 }
4636
4637
4638 \f
4639 /* Convert a keysym to its name. */
4640
4641 char *
4642 x_get_keysym_name (keysym)
4643 int keysym;
4644 {
4645 char *value;
4646
4647 BLOCK_INPUT;
4648 #if 0
4649 value = XKeysymToString (keysym);
4650 #else
4651 value = 0;
4652 #endif
4653 UNBLOCK_INPUT;
4654
4655 return value;
4656 }
4657
4658
4659 \f
4660 /* Function to report a mouse movement to the mainstream Emacs code.
4661 The input handler calls this.
4662
4663 We have received a mouse movement event, which is given in *event.
4664 If the mouse is over a different glyph than it was last time, tell
4665 the mainstream emacs code by setting mouse_moved. If not, ask for
4666 another motion event, so we can check again the next time it moves. */
4667
4668 static Point last_mouse_motion_position;
4669 static Lisp_Object last_mouse_motion_frame;
4670
4671 static int
4672 note_mouse_movement (frame, pos)
4673 FRAME_PTR frame;
4674 Point *pos;
4675 {
4676 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4677 #if TARGET_API_MAC_CARBON
4678 Rect r;
4679 #endif
4680
4681 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4682 last_mouse_motion_position = *pos;
4683 XSETFRAME (last_mouse_motion_frame, frame);
4684
4685 if (frame == dpyinfo->mouse_face_mouse_frame
4686 #if TARGET_API_MAC_CARBON
4687 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
4688 #else
4689 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
4690 #endif
4691 )
4692 {
4693 /* This case corresponds to LeaveNotify in X11. If we move
4694 outside the frame, then we're certainly no longer on any text
4695 in the frame. */
4696 clear_mouse_face (dpyinfo);
4697 dpyinfo->mouse_face_mouse_frame = 0;
4698 if (!dpyinfo->grabbed)
4699 FRAME_RIF (frame)->define_frame_cursor (frame,
4700 frame->output_data.mac->nontext_cursor);
4701 }
4702
4703 /* Has the mouse moved off the glyph it was on at the last sighting? */
4704 if (frame != last_mouse_glyph_frame
4705 || !PtInRect (*pos, &last_mouse_glyph))
4706 {
4707 frame->mouse_moved = 1;
4708 last_mouse_scroll_bar = Qnil;
4709 note_mouse_highlight (frame, pos->h, pos->v);
4710 /* Remember which glyph we're now on. */
4711 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
4712 last_mouse_glyph_frame = frame;
4713 return 1;
4714 }
4715
4716 return 0;
4717 }
4718
4719 \f
4720 /************************************************************************
4721 Mouse Face
4722 ************************************************************************/
4723
4724 /* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4725
4726 static void
4727 redo_mouse_highlight ()
4728 {
4729 if (!NILP (last_mouse_motion_frame)
4730 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4731 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4732 last_mouse_motion_position.h,
4733 last_mouse_motion_position.v);
4734 }
4735
4736
4737 static struct frame *
4738 mac_focus_frame (dpyinfo)
4739 struct mac_display_info *dpyinfo;
4740 {
4741 if (dpyinfo->x_focus_frame)
4742 return dpyinfo->x_focus_frame;
4743 else
4744 /* Mac version may get events, such as a menu bar click, even when
4745 all the frames are invisible. In this case, we regard the
4746 event came to the selected frame. */
4747 return SELECTED_FRAME ();
4748 }
4749
4750
4751 /* Return the current position of the mouse.
4752 *FP should be a frame which indicates which display to ask about.
4753
4754 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4755 and *PART to the frame, window, and scroll bar part that the mouse
4756 is over. Set *X and *Y to the portion and whole of the mouse's
4757 position on the scroll bar.
4758
4759 If the mouse movement started elsewhere, set *FP to the frame the
4760 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4761 the mouse is over.
4762
4763 Set *TIME to the server time-stamp for the time at which the mouse
4764 was at this position.
4765
4766 Don't store anything if we don't have a valid set of values to report.
4767
4768 This clears the mouse_moved flag, so we can wait for the next mouse
4769 movement. */
4770
4771 static void
4772 XTmouse_position (fp, insist, bar_window, part, x, y, time)
4773 FRAME_PTR *fp;
4774 int insist;
4775 Lisp_Object *bar_window;
4776 enum scroll_bar_part *part;
4777 Lisp_Object *x, *y;
4778 unsigned long *time;
4779 {
4780 FRAME_PTR f1;
4781
4782 BLOCK_INPUT;
4783
4784 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4785 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4786 else
4787 {
4788 Lisp_Object frame, tail;
4789
4790 /* Clear the mouse-moved flag for every frame on this display. */
4791 FOR_EACH_FRAME (tail, frame)
4792 XFRAME (frame)->mouse_moved = 0;
4793
4794 last_mouse_scroll_bar = Qnil;
4795
4796 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4797 && FRAME_LIVE_P (last_mouse_frame))
4798 f1 = last_mouse_frame;
4799 else
4800 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
4801
4802 if (f1)
4803 {
4804 /* Ok, we found a frame. Store all the values.
4805 last_mouse_glyph is a rectangle used to reduce the
4806 generation of mouse events. To not miss any motion
4807 events, we must divide the frame into rectangles of the
4808 size of the smallest character that could be displayed
4809 on it, i.e. into the same rectangles that matrices on
4810 the frame are divided into. */
4811 Point mouse_pos;
4812
4813 #if TARGET_API_MAC_CARBON
4814 GetGlobalMouse (&mouse_pos);
4815 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4816 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4817 #else
4818 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4819 GetMouse (&mouse_pos);
4820 #endif
4821 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4822 &last_mouse_glyph);
4823 last_mouse_glyph_frame = f1;
4824
4825 *bar_window = Qnil;
4826 *part = 0;
4827 *fp = f1;
4828 XSETINT (*x, mouse_pos.h);
4829 XSETINT (*y, mouse_pos.v);
4830 *time = last_mouse_movement_time;
4831 }
4832 }
4833
4834 UNBLOCK_INPUT;
4835 }
4836
4837 \f
4838 /************************************************************************
4839 Toolkit scroll bars
4840 ************************************************************************/
4841
4842 #ifdef USE_TOOLKIT_SCROLL_BARS
4843
4844 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4845 static OSStatus install_scroll_bar_timer P_ ((void));
4846 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
4847 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
4848 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
4849 struct input_event *));
4850 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
4851 Rect *));
4852 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
4853 ControlPartCode, Point,
4854 struct input_event *));
4855 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
4856 struct input_event *));
4857 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
4858 Point, struct input_event *));
4859 static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4860 int, int, int));
4861
4862 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
4863
4864 static int last_scroll_bar_part;
4865
4866 static EventLoopTimerRef scroll_bar_timer;
4867
4868 static int scroll_bar_timer_event_posted_p;
4869
4870 #define SCROLL_BAR_FIRST_DELAY 0.5
4871 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4872
4873 static pascal void
4874 scroll_bar_timer_callback (timer, data)
4875 EventLoopTimerRef timer;
4876 void *data;
4877 {
4878 OSStatus err;
4879
4880 err = mac_post_mouse_moved_event ();
4881 if (err == noErr)
4882 scroll_bar_timer_event_posted_p = 1;
4883 }
4884
4885 static OSStatus
4886 install_scroll_bar_timer ()
4887 {
4888 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4889
4890 if (scroll_bar_timer_callbackUPP == NULL)
4891 scroll_bar_timer_callbackUPP =
4892 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4893
4894 if (scroll_bar_timer == NULL)
4895 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4896 kEventDurationForever as delays. */
4897 return
4898 InstallEventLoopTimer (GetCurrentEventLoop (),
4899 kEventDurationForever, kEventDurationForever,
4900 scroll_bar_timer_callbackUPP, NULL,
4901 &scroll_bar_timer);
4902 }
4903
4904 static OSStatus
4905 set_scroll_bar_timer (delay)
4906 EventTimerInterval delay;
4907 {
4908 if (scroll_bar_timer == NULL)
4909 install_scroll_bar_timer ();
4910
4911 scroll_bar_timer_event_posted_p = 0;
4912
4913 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4914 }
4915
4916 static int
4917 control_part_code_to_scroll_bar_part (part_code)
4918 ControlPartCode part_code;
4919 {
4920 switch (part_code)
4921 {
4922 case kControlUpButtonPart: return scroll_bar_up_arrow;
4923 case kControlDownButtonPart: return scroll_bar_down_arrow;
4924 case kControlPageUpPart: return scroll_bar_above_handle;
4925 case kControlPageDownPart: return scroll_bar_below_handle;
4926 case kControlIndicatorPart: return scroll_bar_handle;
4927 }
4928
4929 return -1;
4930 }
4931
4932 static void
4933 construct_scroll_bar_click (bar, part, bufp)
4934 struct scroll_bar *bar;
4935 int part;
4936 struct input_event *bufp;
4937 {
4938 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4939 bufp->frame_or_window = bar->window;
4940 bufp->arg = Qnil;
4941 bufp->part = part;
4942 bufp->code = 0;
4943 XSETINT (bufp->x, 0);
4944 XSETINT (bufp->y, 0);
4945 bufp->modifiers = 0;
4946 }
4947
4948 static OSStatus
4949 get_control_part_bounds (ch, part_code, rect)
4950 ControlRef ch;
4951 ControlPartCode part_code;
4952 Rect *rect;
4953 {
4954 RgnHandle region = NewRgn ();
4955 OSStatus err;
4956
4957 err = GetControlRegion (ch, part_code, region);
4958 if (err == noErr)
4959 GetRegionBounds (region, rect);
4960 DisposeRgn (region);
4961
4962 return err;
4963 }
4964
4965 static void
4966 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
4967 struct scroll_bar *bar;
4968 ControlPartCode part_code;
4969 Point mouse_pos;
4970 struct input_event *bufp;
4971 {
4972 int part = control_part_code_to_scroll_bar_part (part_code);
4973
4974 if (part < 0)
4975 return;
4976
4977 if (part != scroll_bar_handle)
4978 {
4979 construct_scroll_bar_click (bar, part, bufp);
4980 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
4981 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
4982 bar->dragging = Qnil;
4983 }
4984 else
4985 {
4986 Rect r;
4987
4988 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
4989 kControlIndicatorPart, &r);
4990 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
4991 }
4992
4993 last_scroll_bar_part = part;
4994 tracked_scroll_bar = bar;
4995 }
4996
4997 static void
4998 x_scroll_bar_handle_release (bar, bufp)
4999 struct scroll_bar *bar;
5000 struct input_event *bufp;
5001 {
5002 if (last_scroll_bar_part != scroll_bar_handle
5003 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
5004 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
5005
5006 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5007 set_scroll_bar_timer (kEventDurationForever);
5008
5009 last_scroll_bar_part = -1;
5010 bar->dragging = Qnil;
5011 tracked_scroll_bar = NULL;
5012 }
5013
5014 static void
5015 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
5016 WindowRef win;
5017 struct scroll_bar *bar;
5018 Point mouse_pos;
5019 struct input_event *bufp;
5020 {
5021 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5022
5023 if (last_scroll_bar_part == scroll_bar_handle)
5024 {
5025 int top, top_range;
5026 Rect r;
5027
5028 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
5029 kControlIndicatorPart, &r);
5030
5031 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
5032 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
5033
5034 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
5035 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
5036
5037 if (top < 0)
5038 top = 0;
5039 if (top > top_range)
5040 top = top_range;
5041
5042 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
5043 XSETINT (bufp->x, top);
5044 XSETINT (bufp->y, top_range);
5045 }
5046 else
5047 {
5048 ControlPartCode part_code;
5049 int unhilite_p = 0, part;
5050
5051 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
5052 unhilite_p = 1;
5053 else
5054 {
5055 part = control_part_code_to_scroll_bar_part (part_code);
5056
5057 switch (last_scroll_bar_part)
5058 {
5059 case scroll_bar_above_handle:
5060 case scroll_bar_below_handle:
5061 if (part != scroll_bar_above_handle
5062 && part != scroll_bar_below_handle)
5063 unhilite_p = 1;
5064 break;
5065
5066 case scroll_bar_up_arrow:
5067 case scroll_bar_down_arrow:
5068 if (part != scroll_bar_up_arrow
5069 && part != scroll_bar_down_arrow)
5070 unhilite_p = 1;
5071 break;
5072 }
5073 }
5074
5075 if (unhilite_p)
5076 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5077 else if (part != last_scroll_bar_part
5078 || scroll_bar_timer_event_posted_p)
5079 {
5080 construct_scroll_bar_click (bar, part, bufp);
5081 last_scroll_bar_part = part;
5082 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5083 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
5084 }
5085 }
5086 }
5087
5088 /* Set the thumb size and position of scroll bar BAR. We are currently
5089 displaying PORTION out of a whole WHOLE, and our position POSITION. */
5090
5091 static void
5092 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
5093 struct scroll_bar *bar;
5094 int portion, position, whole;
5095 {
5096 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5097 int value, viewsize, maximum;
5098
5099 if (XINT (bar->track_height) == 0)
5100 return;
5101
5102 if (whole <= portion)
5103 value = 0, viewsize = 1, maximum = 0;
5104 else
5105 {
5106 float scale;
5107
5108 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
5109 scale = (float) maximum / (whole - portion);
5110 value = position * scale + 0.5f;
5111 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
5112 }
5113
5114 BLOCK_INPUT;
5115
5116 if (GetControlViewSize (ch) != viewsize
5117 || GetControl32BitValue (ch) != value
5118 || GetControl32BitMaximum (ch) != maximum)
5119 {
5120 /* Temporarily hide the scroll bar to avoid multiple redraws. */
5121 SetControlVisibility (ch, false, false);
5122
5123 SetControl32BitMaximum (ch, maximum);
5124 SetControl32BitValue (ch, value);
5125 SetControlViewSize (ch, viewsize);
5126
5127 SetControlVisibility (ch, true, true);
5128 }
5129
5130 UNBLOCK_INPUT;
5131 }
5132
5133 #endif /* USE_TOOLKIT_SCROLL_BARS */
5134
5135
5136 \f
5137 /************************************************************************
5138 Scroll bars, general
5139 ************************************************************************/
5140
5141 /* Create a scroll bar and return the scroll bar vector for it. W is
5142 the Emacs window on which to create the scroll bar. TOP, LEFT,
5143 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
5144 scroll bar. */
5145
5146 static struct scroll_bar *
5147 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5148 struct window *w;
5149 int top, left, width, height, disp_top, disp_height;
5150 {
5151 struct frame *f = XFRAME (w->frame);
5152 struct scroll_bar *bar
5153 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5154 Rect r;
5155 ControlRef ch;
5156
5157 BLOCK_INPUT;
5158
5159 r.left = left;
5160 r.top = disp_top;
5161 r.right = left + width;
5162 r.bottom = disp_top + disp_height;
5163
5164 #if USE_CG_DRAWING
5165 mac_prepare_for_quickdraw (f);
5166 #endif
5167 #if TARGET_API_MAC_CARBON
5168 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
5169 #ifdef USE_TOOLKIT_SCROLL_BARS
5170 false,
5171 #else
5172 width < disp_height,
5173 #endif
5174 0, 0, 0, kControlScrollBarProc, (long) bar);
5175 #else
5176 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5177 0, 0, 0, scrollBarProc, (long) bar);
5178 #endif
5179 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
5180
5181 XSETWINDOW (bar->window, w);
5182 XSETINT (bar->top, top);
5183 XSETINT (bar->left, left);
5184 XSETINT (bar->width, width);
5185 XSETINT (bar->height, height);
5186 XSETINT (bar->start, 0);
5187 XSETINT (bar->end, 0);
5188 bar->dragging = Qnil;
5189 #ifdef MAC_OSX
5190 bar->fringe_extended_p = Qnil;
5191 #endif
5192 bar->redraw_needed_p = Qnil;
5193 #ifdef USE_TOOLKIT_SCROLL_BARS
5194 bar->track_top = Qnil;
5195 bar->track_height = Qnil;
5196 bar->min_handle = Qnil;
5197 #endif
5198
5199 /* Add bar to its frame's list of scroll bars. */
5200 bar->next = FRAME_SCROLL_BARS (f);
5201 bar->prev = Qnil;
5202 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5203 if (!NILP (bar->next))
5204 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5205
5206 UNBLOCK_INPUT;
5207 return bar;
5208 }
5209
5210
5211 /* Draw BAR's handle in the proper position.
5212
5213 If the handle is already drawn from START to END, don't bother
5214 redrawing it, unless REBUILD is non-zero; in that case, always
5215 redraw it. (REBUILD is handy for drawing the handle after expose
5216 events.)
5217
5218 Normally, we want to constrain the start and end of the handle to
5219 fit inside its rectangle, but if the user is dragging the scroll
5220 bar handle, we want to let them drag it down all the way, so that
5221 the bar's top is as far down as it goes; otherwise, there's no way
5222 to move to the very end of the buffer. */
5223
5224 #ifndef USE_TOOLKIT_SCROLL_BARS
5225
5226 static void
5227 x_scroll_bar_set_handle (bar, start, end, rebuild)
5228 struct scroll_bar *bar;
5229 int start, end;
5230 int rebuild;
5231 {
5232 int dragging = ! NILP (bar->dragging);
5233 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5234 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5235 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5236 int length = end - start;
5237
5238 /* If the display is already accurate, do nothing. */
5239 if (! rebuild
5240 && start == XINT (bar->start)
5241 && end == XINT (bar->end))
5242 return;
5243
5244 BLOCK_INPUT;
5245
5246 /* Make sure the values are reasonable, and try to preserve the
5247 distance between start and end. */
5248 if (start < 0)
5249 start = 0;
5250 else if (start > top_range)
5251 start = top_range;
5252 end = start + length;
5253
5254 if (end < start)
5255 end = start;
5256 else if (end > top_range && ! dragging)
5257 end = top_range;
5258
5259 /* Store the adjusted setting in the scroll bar. */
5260 XSETINT (bar->start, start);
5261 XSETINT (bar->end, end);
5262
5263 /* Clip the end position, just for display. */
5264 if (end > top_range)
5265 end = top_range;
5266
5267 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5268 top positions, to make sure the handle is always at least that
5269 many pixels tall. */
5270 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5271
5272 SetControlMinimum (ch, 0);
5273 /* Don't inadvertently activate deactivated scroll bars */
5274 if (GetControlMaximum (ch) != -1)
5275 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5276 - (end - start));
5277 SetControlValue (ch, start);
5278 #if TARGET_API_MAC_CARBON
5279 SetControlViewSize (ch, end - start);
5280 #endif
5281
5282 UNBLOCK_INPUT;
5283 }
5284
5285 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5286
5287 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5288 nil. */
5289
5290 static void
5291 x_scroll_bar_remove (bar)
5292 struct scroll_bar *bar;
5293 {
5294 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5295
5296 BLOCK_INPUT;
5297
5298 #if USE_CG_DRAWING
5299 mac_prepare_for_quickdraw (f);
5300 #endif
5301 /* Destroy the Mac scroll bar control */
5302 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
5303
5304 /* Disassociate this scroll bar from its window. */
5305 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5306
5307 UNBLOCK_INPUT;
5308 }
5309
5310
5311 /* Set the handle of the vertical scroll bar for WINDOW to indicate
5312 that we are displaying PORTION characters out of a total of WHOLE
5313 characters, starting at POSITION. If WINDOW has no scroll bar,
5314 create one. */
5315
5316 static void
5317 XTset_vertical_scroll_bar (w, portion, whole, position)
5318 struct window *w;
5319 int portion, whole, position;
5320 {
5321 struct frame *f = XFRAME (w->frame);
5322 struct scroll_bar *bar;
5323 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
5324 int window_y, window_height;
5325 #ifdef MAC_OSX
5326 int fringe_extended_p;
5327 #endif
5328
5329 /* Get window dimensions. */
5330 window_box (w, -1, 0, &window_y, 0, &window_height);
5331 top = window_y;
5332 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
5333 height = window_height;
5334
5335 /* Compute the left edge of the scroll bar area. */
5336 left = WINDOW_SCROLL_BAR_AREA_X (w);
5337
5338 /* Compute the width of the scroll bar which might be less than
5339 the width of the area reserved for the scroll bar. */
5340 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5341 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
5342 else
5343 sb_width = width;
5344
5345 /* Compute the left edge of the scroll bar. */
5346 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
5347 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
5348 else
5349 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
5350
5351 /* Adjustments according to Inside Macintosh to make it look nice */
5352 disp_top = top;
5353 disp_height = height;
5354 #ifdef MAC_OS8
5355 if (disp_top == 0)
5356 {
5357 disp_top = -1;
5358 disp_height++;
5359 }
5360 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
5361 {
5362 disp_top++;
5363 disp_height--;
5364 }
5365
5366 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
5367 sb_left++;
5368 #endif
5369
5370 #ifdef MAC_OSX
5371 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5372 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5373 && WINDOW_LEFT_FRINGE_WIDTH (w)
5374 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5375 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5376 else
5377 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5378 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5379 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5380 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5381 #endif
5382
5383 /* Does the scroll bar exist yet? */
5384 if (NILP (w->vertical_scroll_bar))
5385 {
5386 BLOCK_INPUT;
5387 #ifdef MAC_OSX
5388 if (fringe_extended_p)
5389 mac_clear_area (f, sb_left, top, sb_width, height);
5390 else
5391 #endif
5392 mac_clear_area (f, left, top, width, height);
5393 UNBLOCK_INPUT;
5394 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5395 disp_height);
5396 XSETVECTOR (w->vertical_scroll_bar, bar);
5397 }
5398 else
5399 {
5400 /* It may just need to be moved and resized. */
5401 ControlRef ch;
5402
5403 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5404 ch = SCROLL_BAR_CONTROL_REF (bar);
5405
5406 BLOCK_INPUT;
5407
5408 /* If already correctly positioned, do nothing. */
5409 if (XINT (bar->left) == sb_left
5410 && XINT (bar->top) == top
5411 && XINT (bar->width) == sb_width
5412 && XINT (bar->height) == height
5413 #ifdef MAC_OSX
5414 && !NILP (bar->fringe_extended_p) == fringe_extended_p
5415 #endif
5416 )
5417 {
5418 if (!NILP (bar->redraw_needed_p))
5419 {
5420 #if USE_CG_DRAWING
5421 mac_prepare_for_quickdraw (f);
5422 #endif
5423 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
5424 }
5425 }
5426 else
5427 {
5428 /* Since toolkit scroll bars are smaller than the space reserved
5429 for them on the frame, we have to clear "under" them. */
5430 #ifdef MAC_OSX
5431 if (fringe_extended_p)
5432 mac_clear_area (f, sb_left, top, sb_width, height);
5433 else
5434 #endif
5435 mac_clear_area (f, left, top, width, height);
5436
5437 #if USE_CG_DRAWING
5438 mac_prepare_for_quickdraw (f);
5439 #endif
5440 HideControl (ch);
5441 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5442 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5443 disp_height);
5444 #ifndef USE_TOOLKIT_SCROLL_BARS
5445 if (sb_width < disp_height)
5446 ShowControl (ch);
5447 #endif
5448
5449 /* Remember new settings. */
5450 XSETINT (bar->left, sb_left);
5451 XSETINT (bar->top, top);
5452 XSETINT (bar->width, sb_width);
5453 XSETINT (bar->height, height);
5454 #ifdef USE_TOOLKIT_SCROLL_BARS
5455 bar->track_top = Qnil;
5456 bar->track_height = Qnil;
5457 bar->min_handle = Qnil;
5458 #endif
5459 }
5460
5461 UNBLOCK_INPUT;
5462 }
5463
5464 #ifdef MAC_OSX
5465 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5466 #endif
5467
5468 bar->redraw_needed_p = Qnil;
5469
5470 #ifdef USE_TOOLKIT_SCROLL_BARS
5471 if (NILP (bar->track_top))
5472 {
5473 if (sb_width >= disp_height
5474 #ifdef MAC_OSX
5475 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5476 #endif
5477 )
5478 {
5479 XSETINT (bar->track_top, 0);
5480 XSETINT (bar->track_height, 0);
5481 XSETINT (bar->min_handle, 0);
5482 }
5483 else
5484 {
5485 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5486 Rect r0, r1;
5487
5488 BLOCK_INPUT;
5489
5490 SetControl32BitMinimum (ch, 0);
5491 SetControl32BitMaximum (ch, 1 << 30);
5492 SetControlViewSize (ch, 1);
5493
5494 /* Move the scroll bar thumb to the top. */
5495 SetControl32BitValue (ch, 0);
5496 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5497
5498 /* Move the scroll bar thumb to the bottom. */
5499 SetControl32BitValue (ch, 1 << 30);
5500 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5501
5502 UnionRect (&r0, &r1, &r0);
5503 XSETINT (bar->track_top, r0.top);
5504 XSETINT (bar->track_height, r0.bottom - r0.top);
5505 XSETINT (bar->min_handle, r1.bottom - r1.top);
5506
5507 /* Don't show the scroll bar if its height is not enough to
5508 display the scroll bar thumb. */
5509 if (r0.bottom - r0.top > 0)
5510 ShowControl (ch);
5511
5512 UNBLOCK_INPUT;
5513 }
5514 }
5515
5516 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5517 #else /* not USE_TOOLKIT_SCROLL_BARS */
5518 /* Set the scroll bar's current state, unless we're currently being
5519 dragged. */
5520 if (NILP (bar->dragging))
5521 {
5522 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5523
5524 if (whole == 0)
5525 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5526 else
5527 {
5528 int start = ((double) position * top_range) / whole;
5529 int end = ((double) (position + portion) * top_range) / whole;
5530 x_scroll_bar_set_handle (bar, start, end, 0);
5531 }
5532 }
5533 #endif /* not USE_TOOLKIT_SCROLL_BARS */
5534 }
5535
5536
5537 /* The following three hooks are used when we're doing a thorough
5538 redisplay of the frame. We don't explicitly know which scroll bars
5539 are going to be deleted, because keeping track of when windows go
5540 away is a real pain - "Can you say set-window-configuration, boys
5541 and girls?" Instead, we just assert at the beginning of redisplay
5542 that *all* scroll bars are to be removed, and then save a scroll bar
5543 from the fiery pit when we actually redisplay its window. */
5544
5545 /* Arrange for all scroll bars on FRAME to be removed at the next call
5546 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5547 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5548
5549 static void
5550 XTcondemn_scroll_bars (frame)
5551 FRAME_PTR frame;
5552 {
5553 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5554 while (! NILP (FRAME_SCROLL_BARS (frame)))
5555 {
5556 Lisp_Object bar;
5557 bar = FRAME_SCROLL_BARS (frame);
5558 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5559 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5560 XSCROLL_BAR (bar)->prev = Qnil;
5561 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5562 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5563 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5564 }
5565 }
5566
5567
5568 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5569 Note that WINDOW isn't necessarily condemned at all. */
5570
5571 static void
5572 XTredeem_scroll_bar (window)
5573 struct window *window;
5574 {
5575 struct scroll_bar *bar;
5576 struct frame *f;
5577
5578 /* We can't redeem this window's scroll bar if it doesn't have one. */
5579 if (NILP (window->vertical_scroll_bar))
5580 abort ();
5581
5582 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5583
5584 /* Unlink it from the condemned list. */
5585 f = XFRAME (WINDOW_FRAME (window));
5586 if (NILP (bar->prev))
5587 {
5588 /* If the prev pointer is nil, it must be the first in one of
5589 the lists. */
5590 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5591 /* It's not condemned. Everything's fine. */
5592 return;
5593 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5594 window->vertical_scroll_bar))
5595 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5596 else
5597 /* If its prev pointer is nil, it must be at the front of
5598 one or the other! */
5599 abort ();
5600 }
5601 else
5602 XSCROLL_BAR (bar->prev)->next = bar->next;
5603
5604 if (! NILP (bar->next))
5605 XSCROLL_BAR (bar->next)->prev = bar->prev;
5606
5607 bar->next = FRAME_SCROLL_BARS (f);
5608 bar->prev = Qnil;
5609 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5610 if (! NILP (bar->next))
5611 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5612 }
5613
5614 /* Remove all scroll bars on FRAME that haven't been saved since the
5615 last call to `*condemn_scroll_bars_hook'. */
5616
5617 static void
5618 XTjudge_scroll_bars (f)
5619 FRAME_PTR f;
5620 {
5621 Lisp_Object bar, next;
5622
5623 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5624
5625 /* Clear out the condemned list now so we won't try to process any
5626 more events on the hapless scroll bars. */
5627 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5628
5629 for (; ! NILP (bar); bar = next)
5630 {
5631 struct scroll_bar *b = XSCROLL_BAR (bar);
5632
5633 x_scroll_bar_remove (b);
5634
5635 next = b->next;
5636 b->next = b->prev = Qnil;
5637 }
5638
5639 /* Now there should be no references to the condemned scroll bars,
5640 and they should get garbage-collected. */
5641 }
5642
5643
5644 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
5645 is set to something other than NO_EVENT, it is enqueued.
5646
5647 This may be called from a signal handler, so we have to ignore GC
5648 mark bits. */
5649
5650 static void
5651 x_scroll_bar_handle_click (bar, part_code, er, bufp)
5652 struct scroll_bar *bar;
5653 ControlPartCode part_code;
5654 const EventRecord *er;
5655 struct input_event *bufp;
5656 {
5657 int win_y, top_range;
5658
5659 if (! WINDOWP (bar->window))
5660 abort ();
5661
5662 bufp->kind = SCROLL_BAR_CLICK_EVENT;
5663 bufp->frame_or_window = bar->window;
5664 bufp->arg = Qnil;
5665
5666 bar->dragging = Qnil;
5667
5668 switch (part_code)
5669 {
5670 case kControlUpButtonPart:
5671 bufp->part = scroll_bar_up_arrow;
5672 break;
5673 case kControlDownButtonPart:
5674 bufp->part = scroll_bar_down_arrow;
5675 break;
5676 case kControlPageUpPart:
5677 bufp->part = scroll_bar_above_handle;
5678 break;
5679 case kControlPageDownPart:
5680 bufp->part = scroll_bar_below_handle;
5681 break;
5682 #if TARGET_API_MAC_CARBON
5683 default:
5684 #else
5685 case kControlIndicatorPart:
5686 #endif
5687 if (er->what == mouseDown)
5688 bar->dragging = make_number (0);
5689 XSETVECTOR (last_mouse_scroll_bar, bar);
5690 bufp->part = scroll_bar_handle;
5691 break;
5692 }
5693
5694 win_y = XINT (bufp->y) - XINT (bar->top);
5695 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5696
5697 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5698
5699 win_y -= 24;
5700
5701 if (! NILP (bar->dragging))
5702 win_y -= XINT (bar->dragging);
5703
5704 if (win_y < 0)
5705 win_y = 0;
5706 if (win_y > top_range)
5707 win_y = top_range;
5708
5709 XSETINT (bufp->x, win_y);
5710 XSETINT (bufp->y, top_range);
5711 }
5712
5713 #ifndef USE_TOOLKIT_SCROLL_BARS
5714
5715 /* Handle some mouse motion while someone is dragging the scroll bar.
5716
5717 This may be called from a signal handler, so we have to ignore GC
5718 mark bits. */
5719
5720 static void
5721 x_scroll_bar_note_movement (bar, y_pos, t)
5722 struct scroll_bar *bar;
5723 int y_pos;
5724 Time t;
5725 {
5726 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5727
5728 last_mouse_movement_time = t;
5729
5730 f->mouse_moved = 1;
5731 XSETVECTOR (last_mouse_scroll_bar, bar);
5732
5733 /* If we're dragging the bar, display it. */
5734 if (! NILP (bar->dragging))
5735 {
5736 /* Where should the handle be now? */
5737 int new_start = y_pos - 24;
5738
5739 if (new_start != XINT (bar->start))
5740 {
5741 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5742
5743 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5744 }
5745 }
5746 }
5747
5748 #endif /* !USE_TOOLKIT_SCROLL_BARS */
5749
5750 /* Return information to the user about the current position of the mouse
5751 on the scroll bar. */
5752
5753 static void
5754 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5755 FRAME_PTR *fp;
5756 Lisp_Object *bar_window;
5757 enum scroll_bar_part *part;
5758 Lisp_Object *x, *y;
5759 unsigned long *time;
5760 {
5761 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
5762 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5763 #if TARGET_API_MAC_CARBON
5764 WindowRef wp = GetControlOwner (ch);
5765 #else
5766 WindowRef wp = (*ch)->contrlOwner;
5767 #endif
5768 Point mouse_pos;
5769 struct frame *f = mac_window_to_frame (wp);
5770 int win_y, top_range;
5771
5772 #if TARGET_API_MAC_CARBON
5773 GetGlobalMouse (&mouse_pos);
5774 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5775 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5776 #else
5777 SetPortWindowPort (wp);
5778 GetMouse (&mouse_pos);
5779 #endif
5780
5781 win_y = mouse_pos.v - XINT (bar->top);
5782 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5783
5784 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5785
5786 win_y -= 24;
5787
5788 if (! NILP (bar->dragging))
5789 win_y -= XINT (bar->dragging);
5790
5791 if (win_y < 0)
5792 win_y = 0;
5793 if (win_y > top_range)
5794 win_y = top_range;
5795
5796 *fp = f;
5797 *bar_window = bar->window;
5798
5799 if (! NILP (bar->dragging))
5800 *part = scroll_bar_handle;
5801 else if (win_y < XINT (bar->start))
5802 *part = scroll_bar_above_handle;
5803 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5804 *part = scroll_bar_handle;
5805 else
5806 *part = scroll_bar_below_handle;
5807
5808 XSETINT (*x, win_y);
5809 XSETINT (*y, top_range);
5810
5811 f->mouse_moved = 0;
5812 last_mouse_scroll_bar = Qnil;
5813
5814 *time = last_mouse_movement_time;
5815 }
5816
5817
5818 /* The screen has been cleared so we may have changed foreground or
5819 background colors, and the scroll bars may need to be redrawn.
5820 Clear out the scroll bars, and ask for expose events, so we can
5821 redraw them. */
5822
5823 void
5824 x_scroll_bar_clear (f)
5825 FRAME_PTR f;
5826 {
5827 Lisp_Object bar;
5828
5829 /* We can have scroll bars even if this is 0,
5830 if we just turned off scroll bar mode.
5831 But in that case we should not clear them. */
5832 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5833 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5834 bar = XSCROLL_BAR (bar)->next)
5835 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
5836 }
5837
5838 \f
5839 /***********************************************************************
5840 Tool-bars
5841 ***********************************************************************/
5842 #if USE_MAC_TOOLBAR
5843
5844 /* In identifiers such as function/variable names, Emacs tool bar is
5845 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5846
5847 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5848 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5849
5850 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5851 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5852 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5853 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5854 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5855 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5856 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5857
5858 static int mac_event_to_emacs_modifiers P_ ((EventRef));
5859 static void mac_handle_origin_change P_ ((struct frame *));
5860 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5861 EventRef, void *));
5862
5863 static void
5864 mac_move_window_with_gravity (f, win_gravity, left, top)
5865 struct frame *f;
5866 int win_gravity;
5867 short left, top;
5868 {
5869 Rect inner, outer;
5870
5871 mac_get_window_bounds (f, &inner, &outer);
5872
5873 switch (win_gravity)
5874 {
5875 case NorthWestGravity:
5876 case WestGravity:
5877 case SouthWestGravity:
5878 left += inner.left - outer.left;
5879 break;
5880
5881 case NorthGravity:
5882 case CenterGravity:
5883 case SouthGravity:
5884 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5885 break;
5886
5887 case NorthEastGravity:
5888 case EastGravity:
5889 case SouthEastGravity:
5890 left += inner.right - outer.right;
5891 break;
5892 }
5893
5894 switch (win_gravity)
5895 {
5896 case NorthWestGravity:
5897 case NorthGravity:
5898 case NorthEastGravity:
5899 top += inner.top - outer.top;
5900 break;
5901
5902 case WestGravity:
5903 case CenterGravity:
5904 case EastGravity:
5905 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5906 break;
5907
5908 case SouthWestGravity:
5909 case SouthGravity:
5910 case SouthEastGravity:
5911 top += inner.bottom - outer.bottom;
5912 break;
5913 }
5914
5915 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5916 }
5917
5918 static void
5919 mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5920 struct frame *f;
5921 int win_gravity;
5922 short *left, *top;
5923 {
5924 Rect inner, outer;
5925
5926 mac_get_window_bounds (f, &inner, &outer);
5927
5928 switch (win_gravity)
5929 {
5930 case NorthWestGravity:
5931 case WestGravity:
5932 case SouthWestGravity:
5933 *left = outer.left;
5934 break;
5935
5936 case NorthGravity:
5937 case CenterGravity:
5938 case SouthGravity:
5939 *left = outer.left + ((outer.right - outer.left)
5940 - (inner.right - inner.left)) / 2;
5941 break;
5942
5943 case NorthEastGravity:
5944 case EastGravity:
5945 case SouthEastGravity:
5946 *left = outer.right - (inner.right - inner.left);
5947 break;
5948 }
5949
5950 switch (win_gravity)
5951 {
5952 case NorthWestGravity:
5953 case NorthGravity:
5954 case NorthEastGravity:
5955 *top = outer.top;
5956 break;
5957
5958 case WestGravity:
5959 case CenterGravity:
5960 case EastGravity:
5961 *top = outer.top + ((outer.bottom - outer.top)
5962 - (inner.bottom - inner.top)) / 2;
5963 break;
5964
5965 case SouthWestGravity:
5966 case SouthGravity:
5967 case SouthEastGravity:
5968 *top = outer.bottom - (inner.bottom - inner.top);
5969 break;
5970 }
5971 }
5972
5973 static OSStatus
5974 mac_handle_toolbar_event (next_handler, event, data)
5975 EventHandlerCallRef next_handler;
5976 EventRef event;
5977 void *data;
5978 {
5979 OSStatus err, result = eventNotHandledErr;
5980
5981 switch (GetEventKind (event))
5982 {
5983 case kEventToolbarGetDefaultIdentifiers:
5984 result = noErr;
5985 break;
5986
5987 case kEventToolbarGetAllowedIdentifiers:
5988 {
5989 CFMutableArrayRef array;
5990
5991 GetEventParameter (event, kEventParamMutableArray,
5992 typeCFMutableArrayRef, NULL,
5993 sizeof (CFMutableArrayRef), NULL, &array);
5994 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5995 result = noErr;
5996 }
5997 break;
5998
5999 case kEventToolbarCreateItemWithIdentifier:
6000 {
6001 CFStringRef identifier;
6002 HIToolbarItemRef item = NULL;
6003
6004 GetEventParameter (event, kEventParamToolbarItemIdentifier,
6005 typeCFStringRef, NULL,
6006 sizeof (CFStringRef), NULL, &identifier);
6007
6008 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
6009 == kCFCompareEqualTo)
6010 HIToolbarItemCreate (identifier,
6011 kHIToolbarItemAllowDuplicates
6012 | kHIToolbarItemCantBeRemoved, &item);
6013
6014 if (item)
6015 {
6016 SetEventParameter (event, kEventParamToolbarItem,
6017 typeHIToolbarItemRef,
6018 sizeof (HIToolbarItemRef), &item);
6019 result = noErr;
6020 }
6021 }
6022 break;
6023
6024 default:
6025 abort ();
6026 }
6027
6028 return result;
6029 }
6030
6031 static CGImageRef
6032 mac_image_spec_to_cg_image (f, image)
6033 struct frame *f;
6034 Lisp_Object image;
6035 {
6036 if (!valid_image_p (image))
6037 return NULL;
6038 else
6039 {
6040 int img_id = lookup_image (f, image);
6041 struct image *img = IMAGE_FROM_ID (f, img_id);
6042
6043 prepare_image_for_display (f, img);
6044
6045 return img->data.ptr_val;
6046 }
6047 }
6048
6049 /* Create a tool bar for frame F. */
6050
6051 static OSStatus
6052 mac_create_frame_tool_bar (f)
6053 FRAME_PTR f;
6054 {
6055 OSStatus err;
6056 HIToolbarRef toolbar;
6057
6058 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
6059 &toolbar);
6060 if (err == noErr)
6061 {
6062 static const EventTypeSpec specs[] =
6063 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
6064 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
6065 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
6066
6067 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
6068 mac_handle_toolbar_event,
6069 GetEventTypeCount (specs), specs,
6070 f, NULL);
6071 }
6072
6073 if (err == noErr)
6074 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
6075 if (err == noErr)
6076 {
6077 static const EventTypeSpec specs[] =
6078 {{kEventClassCommand, kEventCommandProcess}};
6079
6080 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
6081 mac_handle_toolbar_command_event,
6082 GetEventTypeCount (specs),
6083 specs, f, NULL);
6084 }
6085 if (err == noErr)
6086 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
6087
6088 if (toolbar)
6089 CFRelease (toolbar);
6090
6091 return err;
6092 }
6093
6094 /* Update the tool bar for frame F. Add new buttons and remove old. */
6095
6096 void
6097 update_frame_tool_bar (f)
6098 FRAME_PTR f;
6099 {
6100 HIToolbarRef toolbar = NULL;
6101 short left, top;
6102 CFArrayRef old_items = NULL;
6103 CFIndex old_count;
6104 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
6105 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6106
6107 BLOCK_INPUT;
6108
6109 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6110 if (toolbar == NULL)
6111 {
6112 mac_create_frame_tool_bar (f);
6113 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6114 if (toolbar == NULL)
6115 goto out;
6116 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6117 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6118 }
6119
6120 HIToolbarCopyItems (toolbar, &old_items);
6121 if (old_items == NULL)
6122 goto out;
6123
6124 old_count = CFArrayGetCount (old_items);
6125 pos = 0;
6126 for (i = 0; i < f->n_tool_bar_items; ++i)
6127 {
6128 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6129
6130 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6131 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6132 int idx;
6133 Lisp_Object image;
6134 CGImageRef cg_image;
6135 CFStringRef label;
6136 HIToolbarItemRef item;
6137
6138 /* If image is a vector, choose the image according to the
6139 button state. */
6140 image = PROP (TOOL_BAR_ITEM_IMAGES);
6141 if (VECTORP (image))
6142 {
6143 if (enabled_p)
6144 idx = (selected_p
6145 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6146 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6147 else
6148 idx = (selected_p
6149 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6150 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6151
6152 xassert (ASIZE (image) >= idx);
6153 image = AREF (image, idx);
6154 }
6155 else
6156 idx = -1;
6157
6158 cg_image = mac_image_spec_to_cg_image (f, image);
6159 /* Ignore invalid image specifications. */
6160 if (cg_image == NULL)
6161 continue;
6162
6163 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6164 if (label == NULL)
6165 label = CFSTR ("");
6166
6167 if (pos < old_count)
6168 {
6169 CGImageRef old_cg_image = NULL;
6170 CFStringRef old_label = NULL;
6171 Boolean old_enabled_p;
6172
6173 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6174
6175 HIToolbarItemCopyImage (item, &old_cg_image);
6176 if (cg_image != old_cg_image)
6177 HIToolbarItemSetImage (item, cg_image);
6178 CGImageRelease (old_cg_image);
6179
6180 HIToolbarItemCopyLabel (item, &old_label);
6181 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6182 HIToolbarItemSetLabel (item, label);
6183 CFRelease (old_label);
6184
6185 old_enabled_p = HIToolbarItemIsEnabled (item);
6186 if ((enabled_p || idx >= 0) != old_enabled_p)
6187 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6188 }
6189 else
6190 {
6191 item = NULL;
6192 HIToolbarCreateItemWithIdentifier (toolbar,
6193 TOOLBAR_ICON_ITEM_IDENTIFIER,
6194 NULL, &item);
6195 if (item)
6196 {
6197 HIToolbarItemSetImage (item, cg_image);
6198 HIToolbarItemSetLabel (item, label);
6199 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6200 HIToolbarAppendItem (toolbar, item);
6201 CFRelease (item);
6202 }
6203 }
6204
6205 CFRelease (label);
6206 if (item)
6207 {
6208 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6209 pos++;
6210 }
6211 }
6212
6213 CFRelease (old_items);
6214
6215 while (pos < old_count)
6216 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6217
6218 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6219 !win_gravity && f == mac_focus_frame (dpyinfo));
6220 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6221 toolbar visibility change. */
6222 mac_handle_origin_change (f);
6223 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6224 {
6225 mac_move_window_with_gravity (f, win_gravity, left, top);
6226 /* If the title bar is completely outside the screen, adjust the
6227 position. */
6228 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6229 kWindowConstrainMoveRegardlessOfFit
6230 | kWindowConstrainAllowPartial, NULL, NULL);
6231 f->output_data.mac->toolbar_win_gravity = 0;
6232 }
6233
6234 out:
6235 UNBLOCK_INPUT;
6236 }
6237
6238 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6239 doesn't deallocate the resources. */
6240
6241 void
6242 free_frame_tool_bar (f)
6243 FRAME_PTR f;
6244 {
6245 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6246 {
6247 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6248
6249 BLOCK_INPUT;
6250 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
6251 (NILP (Fsymbol_value
6252 (intern ("frame-notice-user-settings")))
6253 && f == mac_focus_frame (dpyinfo)));
6254 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6255 on toolbar visibility change. */
6256 mac_handle_origin_change (f);
6257 UNBLOCK_INPUT;
6258 }
6259 }
6260
6261 static void
6262 mac_tool_bar_note_mouse_movement (f, event)
6263 struct frame *f;
6264 EventRef event;
6265 {
6266 OSStatus err;
6267 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6268 int mouse_down_p;
6269 HIViewRef item_view;
6270 UInt32 command_id;
6271
6272 mouse_down_p = (dpyinfo->grabbed
6273 && f == last_mouse_frame
6274 && FRAME_LIVE_P (f));
6275 if (mouse_down_p)
6276 return;
6277
6278 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6279 event, &item_view);
6280 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6281 toolbar item view seems to have the same command ID with that of
6282 the toolbar item. */
6283 if (err == noErr)
6284 err = GetControlCommandID (item_view, &command_id);
6285 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6286 {
6287 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6288
6289 if (i < f->n_tool_bar_items)
6290 {
6291 HIRect bounds;
6292 HIViewRef content_view;
6293
6294 err = HIViewGetBounds (item_view, &bounds);
6295 if (err == noErr)
6296 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6297 kHIViewWindowContentID, &content_view);
6298 if (err == noErr)
6299 err = HIViewConvertRect (&bounds, item_view, content_view);
6300 if (err == noErr)
6301 SetRect (&last_mouse_glyph,
6302 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6303 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6304
6305 help_echo_object = help_echo_window = Qnil;
6306 help_echo_pos = -1;
6307 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6308 if (NILP (help_echo_string))
6309 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6310 }
6311 }
6312 }
6313
6314 static OSStatus
6315 mac_handle_toolbar_command_event (next_handler, event, data)
6316 EventHandlerCallRef next_handler;
6317 EventRef event;
6318 void *data;
6319 {
6320 OSStatus err, result = eventNotHandledErr;
6321 struct frame *f = (struct frame *) data;
6322 HICommand command;
6323
6324 err = GetEventParameter (event, kEventParamDirectObject,
6325 typeHICommand, NULL,
6326 sizeof (HICommand), NULL, &command);
6327 if (err != noErr)
6328 return result;
6329
6330 switch (GetEventKind (event))
6331 {
6332 case kEventCommandProcess:
6333 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6334 result = CallNextEventHandler (next_handler, event);
6335 else
6336 {
6337 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6338
6339 if (i < f->n_tool_bar_items
6340 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6341 {
6342 Lisp_Object frame;
6343 struct input_event buf;
6344
6345 EVENT_INIT (buf);
6346
6347 XSETFRAME (frame, f);
6348 buf.kind = TOOL_BAR_EVENT;
6349 buf.frame_or_window = frame;
6350 buf.arg = frame;
6351 kbd_buffer_store_event (&buf);
6352
6353 buf.kind = TOOL_BAR_EVENT;
6354 buf.frame_or_window = frame;
6355 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6356 buf.modifiers = mac_event_to_emacs_modifiers (event);
6357 kbd_buffer_store_event (&buf);
6358
6359 result = noErr;
6360 }
6361 }
6362 break;
6363
6364 default:
6365 abort ();
6366 }
6367 #undef PROP
6368
6369 return result;
6370 }
6371 #endif /* USE_MAC_TOOLBAR */
6372
6373 \f
6374 /***********************************************************************
6375 Text Cursor
6376 ***********************************************************************/
6377
6378 /* Set clipping for output in glyph row ROW. W is the window in which
6379 we operate. GC is the graphics context to set clipping in.
6380
6381 ROW may be a text row or, e.g., a mode line. Text rows must be
6382 clipped to the interior of the window dedicated to text display,
6383 mode lines must be clipped to the whole window. */
6384
6385 static void
6386 x_clip_to_row (w, row, area, gc)
6387 struct window *w;
6388 struct glyph_row *row;
6389 int area;
6390 GC gc;
6391 {
6392 struct frame *f = XFRAME (WINDOW_FRAME (w));
6393 Rect clip_rect;
6394 int window_x, window_y, window_width;
6395
6396 window_box (w, area, &window_x, &window_y, &window_width, 0);
6397
6398 clip_rect.left = window_x;
6399 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6400 clip_rect.top = max (clip_rect.top, window_y);
6401 clip_rect.right = clip_rect.left + window_width;
6402 clip_rect.bottom = clip_rect.top + row->visible_height;
6403
6404 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
6405 }
6406
6407
6408 /* Draw a hollow box cursor on window W in glyph row ROW. */
6409
6410 static void
6411 x_draw_hollow_cursor (w, row)
6412 struct window *w;
6413 struct glyph_row *row;
6414 {
6415 struct frame *f = XFRAME (WINDOW_FRAME (w));
6416 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6417 Display *dpy = FRAME_MAC_DISPLAY (f);
6418 int x, y, wd, h;
6419 XGCValues xgcv;
6420 struct glyph *cursor_glyph;
6421 GC gc;
6422
6423 /* Get the glyph the cursor is on. If we can't tell because
6424 the current matrix is invalid or such, give up. */
6425 cursor_glyph = get_phys_cursor_glyph (w);
6426 if (cursor_glyph == NULL)
6427 return;
6428
6429 /* Compute frame-relative coordinates for phys cursor. */
6430 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
6431 wd = w->phys_cursor_width;
6432
6433 /* The foreground of cursor_gc is typically the same as the normal
6434 background color, which can cause the cursor box to be invisible. */
6435 xgcv.foreground = f->output_data.mac->cursor_pixel;
6436 if (dpyinfo->scratch_cursor_gc)
6437 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6438 else
6439 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6440 GCForeground, &xgcv);
6441 gc = dpyinfo->scratch_cursor_gc;
6442
6443 /* Set clipping, draw the rectangle, and reset clipping again. */
6444 x_clip_to_row (w, row, TEXT_AREA, gc);
6445 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
6446 mac_reset_clip_rectangles (dpy, gc);
6447 }
6448
6449
6450 /* Draw a bar cursor on window W in glyph row ROW.
6451
6452 Implementation note: One would like to draw a bar cursor with an
6453 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6454 Unfortunately, I didn't find a font yet that has this property set.
6455 --gerd. */
6456
6457 static void
6458 x_draw_bar_cursor (w, row, width, kind)
6459 struct window *w;
6460 struct glyph_row *row;
6461 int width;
6462 enum text_cursor_kinds kind;
6463 {
6464 struct frame *f = XFRAME (w->frame);
6465 struct glyph *cursor_glyph;
6466
6467 /* If cursor is out of bounds, don't draw garbage. This can happen
6468 in mini-buffer windows when switching between echo area glyphs
6469 and mini-buffer. */
6470 cursor_glyph = get_phys_cursor_glyph (w);
6471 if (cursor_glyph == NULL)
6472 return;
6473
6474 /* If on an image, draw like a normal cursor. That's usually better
6475 visible than drawing a bar, esp. if the image is large so that
6476 the bar might not be in the window. */
6477 if (cursor_glyph->type == IMAGE_GLYPH)
6478 {
6479 struct glyph_row *row;
6480 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6481 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6482 }
6483 else
6484 {
6485 Display *dpy = FRAME_MAC_DISPLAY (f);
6486 Window window = FRAME_MAC_WINDOW (f);
6487 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6488 unsigned long mask = GCForeground | GCBackground;
6489 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
6490 XGCValues xgcv;
6491
6492 /* If the glyph's background equals the color we normally draw
6493 the bar cursor in, the bar cursor in its normal color is
6494 invisible. Use the glyph's foreground color instead in this
6495 case, on the assumption that the glyph's colors are chosen so
6496 that the glyph is legible. */
6497 if (face->background == f->output_data.mac->cursor_pixel)
6498 xgcv.background = xgcv.foreground = face->foreground;
6499 else
6500 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
6501
6502 if (gc)
6503 XChangeGC (dpy, gc, mask, &xgcv);
6504 else
6505 {
6506 gc = XCreateGC (dpy, window, mask, &xgcv);
6507 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6508 }
6509
6510 if (width < 0)
6511 width = FRAME_CURSOR_WIDTH (f);
6512 width = min (cursor_glyph->pixel_width, width);
6513
6514 w->phys_cursor_width = width;
6515 x_clip_to_row (w, row, TEXT_AREA, gc);
6516
6517 if (kind == BAR_CURSOR)
6518 mac_fill_rectangle (f, gc,
6519 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6520 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6521 width, row->height);
6522 else
6523 mac_fill_rectangle (f, gc,
6524 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6525 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6526 row->height - width),
6527 cursor_glyph->pixel_width,
6528 width);
6529
6530 mac_reset_clip_rectangles (f, gc);
6531 }
6532 }
6533
6534
6535 /* RIF: Define cursor CURSOR on frame F. */
6536
6537 static void
6538 mac_define_frame_cursor (f, cursor)
6539 struct frame *f;
6540 Cursor cursor;
6541 {
6542 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6543
6544 if (dpyinfo->x_focus_frame == f)
6545 SetThemeCursor (cursor);
6546 }
6547
6548
6549 /* RIF: Clear area on frame F. */
6550
6551 static void
6552 mac_clear_frame_area (f, x, y, width, height)
6553 struct frame *f;
6554 int x, y, width, height;
6555 {
6556 mac_clear_area (f, x, y, width, height);
6557 }
6558
6559
6560 /* RIF: Draw cursor on window W. */
6561
6562 static void
6563 mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
6564 struct window *w;
6565 struct glyph_row *glyph_row;
6566 int x, y;
6567 int cursor_type, cursor_width;
6568 int on_p, active_p;
6569 {
6570 if (on_p)
6571 {
6572 w->phys_cursor_type = cursor_type;
6573 w->phys_cursor_on_p = 1;
6574
6575 if (glyph_row->exact_window_width_line_p
6576 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6577 {
6578 glyph_row->cursor_in_fringe_p = 1;
6579 draw_fringe_bitmap (w, glyph_row, 0);
6580 }
6581 else
6582 switch (cursor_type)
6583 {
6584 case HOLLOW_BOX_CURSOR:
6585 x_draw_hollow_cursor (w, glyph_row);
6586 break;
6587
6588 case FILLED_BOX_CURSOR:
6589 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
6590 break;
6591
6592 case BAR_CURSOR:
6593 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6594 break;
6595
6596 case HBAR_CURSOR:
6597 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
6598 break;
6599
6600 case NO_CURSOR:
6601 w->phys_cursor_width = 0;
6602 break;
6603
6604 default:
6605 abort ();
6606 }
6607 }
6608 }
6609
6610 \f
6611 /* Icons. */
6612
6613 #if 0 /* MAC_TODO: no icon support yet. */
6614 int
6615 x_bitmap_icon (f, icon)
6616 struct frame *f;
6617 Lisp_Object icon;
6618 {
6619 HANDLE hicon;
6620
6621 if (FRAME_W32_WINDOW (f) == 0)
6622 return 1;
6623
6624 if (NILP (icon))
6625 hicon = LoadIcon (hinst, EMACS_CLASS);
6626 else if (STRINGP (icon))
6627 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
6628 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6629 else if (SYMBOLP (icon))
6630 {
6631 LPCTSTR name;
6632
6633 if (EQ (icon, intern ("application")))
6634 name = (LPCTSTR) IDI_APPLICATION;
6635 else if (EQ (icon, intern ("hand")))
6636 name = (LPCTSTR) IDI_HAND;
6637 else if (EQ (icon, intern ("question")))
6638 name = (LPCTSTR) IDI_QUESTION;
6639 else if (EQ (icon, intern ("exclamation")))
6640 name = (LPCTSTR) IDI_EXCLAMATION;
6641 else if (EQ (icon, intern ("asterisk")))
6642 name = (LPCTSTR) IDI_ASTERISK;
6643 else if (EQ (icon, intern ("winlogo")))
6644 name = (LPCTSTR) IDI_WINLOGO;
6645 else
6646 return 1;
6647
6648 hicon = LoadIcon (NULL, name);
6649 }
6650 else
6651 return 1;
6652
6653 if (hicon == NULL)
6654 return 1;
6655
6656 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6657 (LPARAM) hicon);
6658
6659 return 0;
6660 }
6661 #endif /* MAC_TODO */
6662 \f
6663 /************************************************************************
6664 Handling X errors
6665 ************************************************************************/
6666
6667 /* Display Error Handling functions not used on W32. Listing them here
6668 helps diff stay in step when comparing w32term.c with xterm.c.
6669
6670 x_error_catcher (display, error)
6671 x_catch_errors (dpy)
6672 x_catch_errors_unwind (old_val)
6673 x_check_errors (dpy, format)
6674 x_had_errors_p (dpy)
6675 x_clear_errors (dpy)
6676 x_uncatch_errors (dpy, count)
6677 x_trace_wire ()
6678 x_connection_signal (signalnum)
6679 x_connection_closed (dpy, error_message)
6680 x_error_quitter (display, error)
6681 x_error_handler (display, error)
6682 x_io_error_quitter (display)
6683
6684 */
6685
6686 \f
6687 /* Changing the font of the frame. */
6688
6689 /* Give frame F the font named FONTNAME as its default font, and
6690 return the full name of that font. FONTNAME may be a wildcard
6691 pattern; in that case, we choose some font that fits the pattern.
6692 The return value shows which font we chose. */
6693
6694 Lisp_Object
6695 x_new_font (f, fontname)
6696 struct frame *f;
6697 register char *fontname;
6698 {
6699 struct font_info *fontp
6700 = FS_LOAD_FONT (f, fontname);
6701
6702 if (!fontp)
6703 return Qnil;
6704
6705 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
6706 /* This font is already set in frame F. There's nothing more to
6707 do. */
6708 return build_string (fontp->full_name);
6709
6710 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6711 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6712 FRAME_FONTSET (f) = -1;
6713
6714 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6715 FRAME_SPACE_WIDTH (f) = fontp->space_width;
6716 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6717
6718 compute_fringe_widths (f, 1);
6719
6720 /* Compute the scroll bar width in character columns. */
6721 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6722 {
6723 int wid = FRAME_COLUMN_WIDTH (f);
6724 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6725 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
6726 }
6727 else
6728 {
6729 int wid = FRAME_COLUMN_WIDTH (f);
6730 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6731 }
6732
6733 /* Now make the frame display the given font. */
6734 if (FRAME_MAC_WINDOW (f) != 0)
6735 {
6736 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
6737 FRAME_FONT (f));
6738 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
6739 FRAME_FONT (f));
6740 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
6741 FRAME_FONT (f));
6742
6743 /* Don't change the size of a tip frame; there's no point in
6744 doing it because it's done in Fx_show_tip, and it leads to
6745 problems because the tip frame has no widget. */
6746 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
6747 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6748 }
6749
6750 return build_string (fontp->full_name);
6751 }
6752 \f
6753 /* Give frame F the fontset named FONTSETNAME as its default fontset,
6754 and return the full name of that fontset. FONTSETNAME may be a
6755 wildcard pattern; in that case, we choose some fontset that fits
6756 the pattern. FONTSETNAME may be a font name for ASCII characters;
6757 in that case, we create a fontset from that font name.
6758
6759 The return value shows which fontset we chose.
6760 If FONTSETNAME specifies the default fontset, return Qt.
6761 If an ASCII font in the specified fontset can't be loaded, return
6762 Qnil. */
6763
6764 Lisp_Object
6765 x_new_fontset (f, fontsetname)
6766 struct frame *f;
6767 Lisp_Object fontsetname;
6768 {
6769 int fontset = fs_query_fontset (fontsetname, 0);
6770 Lisp_Object result;
6771
6772 if (fontset > 0 && FRAME_FONTSET(f) == fontset)
6773 /* This fontset is already set in frame F. There's nothing more
6774 to do. */
6775 return fontset_name (fontset);
6776 else if (fontset == 0)
6777 /* The default fontset can't be the default font. */
6778 return Qt;
6779
6780 if (fontset > 0)
6781 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6782 else
6783 result = x_new_font (f, SDATA (fontsetname));
6784
6785 if (!STRINGP (result))
6786 /* Can't load ASCII font. */
6787 return Qnil;
6788
6789 if (fontset < 0)
6790 fontset = new_fontset_from_font_name (result);
6791
6792 /* Since x_new_font doesn't update any fontset information, do it now. */
6793 FRAME_FONTSET (f) = fontset;
6794
6795 return fontset_name (fontset);
6796 }
6797
6798 \f
6799 /***********************************************************************
6800 TODO: W32 Input Methods
6801 ***********************************************************************/
6802 /* Listing missing functions from xterm.c helps diff stay in step.
6803
6804 xim_destroy_callback (xim, client_data, call_data)
6805 xim_open_dpy (dpyinfo, resource_name)
6806 struct xim_inst_t
6807 xim_instantiate_callback (display, client_data, call_data)
6808 xim_initialize (dpyinfo, resource_name)
6809 xim_close_dpy (dpyinfo)
6810
6811 */
6812
6813 \f
6814 void
6815 mac_get_window_bounds (f, inner, outer)
6816 struct frame *f;
6817 Rect *inner, *outer;
6818 {
6819 #if TARGET_API_MAC_CARBON
6820 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6821 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6822 #else /* not TARGET_API_MAC_CARBON */
6823 RgnHandle region = NewRgn ();
6824
6825 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6826 *inner = (*region)->rgnBBox;
6827 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6828 *outer = (*region)->rgnBBox;
6829 DisposeRgn (region);
6830 #endif /* not TARGET_API_MAC_CARBON */
6831 }
6832
6833 static void
6834 mac_handle_origin_change (f)
6835 struct frame *f;
6836 {
6837 x_real_positions (f, &f->left_pos, &f->top_pos);
6838 }
6839
6840 static void
6841 mac_handle_size_change (f, pixelwidth, pixelheight)
6842 struct frame *f;
6843 int pixelwidth, pixelheight;
6844 {
6845 int cols, rows;
6846
6847 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6848 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6849
6850 if (cols != FRAME_COLS (f)
6851 || rows != FRAME_LINES (f)
6852 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6853 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6854 {
6855 /* We pass 1 for DELAY since we can't run Lisp code inside of
6856 a BLOCK_INPUT. */
6857 change_frame_size (f, rows, cols, 0, 1, 0);
6858 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6859 FRAME_PIXEL_HEIGHT (f) = pixelheight;
6860
6861 /* If cursor was outside the new size, mark it as off. */
6862 mark_window_cursors_off (XWINDOW (f->root_window));
6863
6864 /* Clear out any recollection of where the mouse highlighting
6865 was, since it might be in a place that's outside the new
6866 frame size. Actually checking whether it is outside is a
6867 pain in the neck, so don't try--just let the highlighting be
6868 done afresh with new size. */
6869 cancel_mouse_face (f);
6870
6871 #if TARGET_API_MAC_CARBON
6872 if (f->output_data.mac->hourglass_control)
6873 {
6874 #if USE_CG_DRAWING
6875 mac_prepare_for_quickdraw (f);
6876 #endif
6877 MoveControl (f->output_data.mac->hourglass_control,
6878 pixelwidth - HOURGLASS_WIDTH, 0);
6879 }
6880 #endif
6881 }
6882 }
6883
6884 \f
6885 /* Calculate the absolute position in frame F
6886 from its current recorded position values and gravity. */
6887
6888 void
6889 x_calc_absolute_position (f)
6890 struct frame *f;
6891 {
6892 int flags = f->size_hint_flags;
6893 Rect inner, outer;
6894
6895 /* We have nothing to do if the current position
6896 is already for the top-left corner. */
6897 if (! ((flags & XNegative) || (flags & YNegative)))
6898 return;
6899
6900 /* Find the offsets of the outside upper-left corner of
6901 the inner window, with respect to the outer window. */
6902 BLOCK_INPUT;
6903 mac_get_window_bounds (f, &inner, &outer);
6904 UNBLOCK_INPUT;
6905
6906 /* Treat negative positions as relative to the leftmost bottommost
6907 position that fits on the screen. */
6908 if (flags & XNegative)
6909 f->left_pos += (FRAME_MAC_DISPLAY_INFO (f)->width
6910 - (outer.right - outer.left));
6911
6912 if (flags & YNegative)
6913 f->top_pos += (FRAME_MAC_DISPLAY_INFO (f)->height
6914 - (outer.bottom - outer.top));
6915
6916 /* The left_pos and top_pos
6917 are now relative to the top and left screen edges,
6918 so the flags should correspond. */
6919 f->size_hint_flags &= ~ (XNegative | YNegative);
6920 }
6921
6922 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6923 to really change the position, and 0 when calling from
6924 x_make_frame_visible (in that case, XOFF and YOFF are the current
6925 position values). It is -1 when calling from x_set_frame_parameters,
6926 which means, do adjust for borders but don't change the gravity. */
6927
6928 void
6929 x_set_offset (f, xoff, yoff, change_gravity)
6930 struct frame *f;
6931 register int xoff, yoff;
6932 int change_gravity;
6933 {
6934 if (change_gravity > 0)
6935 {
6936 f->top_pos = yoff;
6937 f->left_pos = xoff;
6938 f->size_hint_flags &= ~ (XNegative | YNegative);
6939 if (xoff < 0)
6940 f->size_hint_flags |= XNegative;
6941 if (yoff < 0)
6942 f->size_hint_flags |= YNegative;
6943 f->win_gravity = NorthWestGravity;
6944 }
6945 x_calc_absolute_position (f);
6946
6947 BLOCK_INPUT;
6948 x_wm_set_size_hint (f, (long) 0, 0);
6949
6950 #if TARGET_API_MAC_CARBON
6951 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6952 /* If the title bar is completely outside the screen, adjust the
6953 position. */
6954 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6955 kWindowConstrainMoveRegardlessOfFit
6956 | kWindowConstrainAllowPartial, NULL, NULL);
6957 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
6958 mac_handle_origin_change (f);
6959 #else
6960 {
6961 Rect inner, outer, screen_rect, dummy;
6962 RgnHandle region = NewRgn ();
6963
6964 mac_get_window_bounds (f, &inner, &outer);
6965 f->x_pixels_diff = inner.left - outer.left;
6966 f->y_pixels_diff = inner.top - outer.top;
6967 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6968 f->top_pos + f->y_pixels_diff, false);
6969
6970 /* If the title bar is completely outside the screen, adjust the
6971 position. The variable `outer' holds the title bar rectangle.
6972 The variable `inner' holds slightly smaller one than `outer',
6973 so that the calculation of overlapping may not become too
6974 strict. */
6975 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6976 outer = (*region)->rgnBBox;
6977 DisposeRgn (region);
6978 inner = outer;
6979 InsetRect (&inner, 8, 8);
6980 screen_rect = qd.screenBits.bounds;
6981 screen_rect.top += GetMBarHeight ();
6982
6983 if (!SectRect (&inner, &screen_rect, &dummy))
6984 {
6985 if (inner.right <= screen_rect.left)
6986 f->left_pos = screen_rect.left;
6987 else if (inner.left >= screen_rect.right)
6988 f->left_pos = screen_rect.right - (outer.right - outer.left);
6989
6990 if (inner.bottom <= screen_rect.top)
6991 f->top_pos = screen_rect.top;
6992 else if (inner.top >= screen_rect.bottom)
6993 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6994
6995 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6996 f->top_pos + f->y_pixels_diff, false);
6997 }
6998 }
6999 #endif
7000
7001 UNBLOCK_INPUT;
7002 }
7003
7004 /* Call this to change the size of frame F's x-window.
7005 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
7006 for this size change and subsequent size changes.
7007 Otherwise we leave the window gravity unchanged. */
7008
7009 void
7010 x_set_window_size (f, change_gravity, cols, rows)
7011 struct frame *f;
7012 int change_gravity;
7013 int cols, rows;
7014 {
7015 int pixelwidth, pixelheight;
7016
7017 BLOCK_INPUT;
7018
7019 check_frame_size (f, &rows, &cols);
7020 f->scroll_bar_actual_width
7021 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
7022
7023 compute_fringe_widths (f, 0);
7024
7025 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
7026 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
7027
7028 f->win_gravity = NorthWestGravity;
7029 x_wm_set_size_hint (f, (long) 0, 0);
7030
7031 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
7032
7033 #if TARGET_API_MAC_CARBON
7034 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
7035 #endif
7036 mac_handle_size_change (f, pixelwidth, pixelheight);
7037
7038 if (f->output_data.mac->internal_border_width
7039 != FRAME_INTERNAL_BORDER_WIDTH (f))
7040 {
7041 mac_clear_window (f);
7042 f->output_data.mac->internal_border_width
7043 = FRAME_INTERNAL_BORDER_WIDTH (f);
7044 }
7045
7046 SET_FRAME_GARBAGED (f);
7047
7048 UNBLOCK_INPUT;
7049 }
7050 \f
7051 /* Mouse warping. */
7052
7053 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
7054
7055 void
7056 x_set_mouse_position (f, x, y)
7057 struct frame *f;
7058 int x, y;
7059 {
7060 int pix_x, pix_y;
7061
7062 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
7063 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
7064
7065 if (pix_x < 0) pix_x = 0;
7066 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
7067
7068 if (pix_y < 0) pix_y = 0;
7069 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
7070
7071 x_set_mouse_pixel_position (f, pix_x, pix_y);
7072 }
7073
7074 void
7075 x_set_mouse_pixel_position (f, pix_x, pix_y)
7076 struct frame *f;
7077 int pix_x, pix_y;
7078 {
7079 #ifdef MAC_OSX
7080 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
7081 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
7082
7083 BLOCK_INPUT;
7084 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
7085 UNBLOCK_INPUT;
7086 #else
7087 #if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
7088 BLOCK_INPUT;
7089
7090 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
7091 0, 0, 0, 0, pix_x, pix_y);
7092 UNBLOCK_INPUT;
7093 #endif
7094 #endif
7095 }
7096 \f
7097 /* focus shifting, raising and lowering. */
7098
7099 void
7100 x_focus_on_frame (f)
7101 struct frame *f;
7102 {
7103 #if 0 /* This proves to be unpleasant. */
7104 x_raise_frame (f);
7105 #endif
7106 #if 0
7107 /* I don't think that the ICCCM allows programs to do things like this
7108 without the interaction of the window manager. Whatever you end up
7109 doing with this code, do it to x_unfocus_frame too. */
7110 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7111 RevertToPointerRoot, CurrentTime);
7112 #endif /* ! 0 */
7113 }
7114
7115 void
7116 x_unfocus_frame (f)
7117 struct frame *f;
7118 {
7119 }
7120
7121 /* Raise frame F. */
7122
7123 void
7124 x_raise_frame (f)
7125 struct frame *f;
7126 {
7127 if (f->async_visible)
7128 {
7129 BLOCK_INPUT;
7130 BringToFront (FRAME_MAC_WINDOW (f));
7131 UNBLOCK_INPUT;
7132 }
7133 }
7134
7135 /* Lower frame F. */
7136
7137 void
7138 x_lower_frame (f)
7139 struct frame *f;
7140 {
7141 if (f->async_visible)
7142 {
7143 BLOCK_INPUT;
7144 SendBehind (FRAME_MAC_WINDOW (f), NULL);
7145 UNBLOCK_INPUT;
7146 }
7147 }
7148
7149 static void
7150 XTframe_raise_lower (f, raise_flag)
7151 FRAME_PTR f;
7152 int raise_flag;
7153 {
7154 if (raise_flag)
7155 x_raise_frame (f);
7156 else
7157 x_lower_frame (f);
7158 }
7159 \f
7160 /* Change of visibility. */
7161
7162 static void
7163 mac_handle_visibility_change (f)
7164 struct frame *f;
7165 {
7166 WindowRef wp = FRAME_MAC_WINDOW (f);
7167 int visible = 0, iconified = 0;
7168 struct input_event buf;
7169
7170 if (IsWindowVisible (wp))
7171 {
7172 if (IsWindowCollapsed (wp))
7173 iconified = 1;
7174 else
7175 visible = 1;
7176 }
7177
7178 if (!f->async_visible && visible)
7179 {
7180 if (f->iconified)
7181 {
7182 /* wait_reading_process_output will notice this and update
7183 the frame's display structures. If we were made
7184 invisible, we should not set garbaged, because that stops
7185 redrawing on Update events. */
7186 SET_FRAME_GARBAGED (f);
7187
7188 EVENT_INIT (buf);
7189 buf.kind = DEICONIFY_EVENT;
7190 XSETFRAME (buf.frame_or_window, f);
7191 buf.arg = Qnil;
7192 kbd_buffer_store_event (&buf);
7193 }
7194 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7195 /* Force a redisplay sooner or later to update the
7196 frame titles in case this is the second frame. */
7197 record_asynch_buffer_change ();
7198 }
7199 else if (f->async_visible && !visible)
7200 if (iconified)
7201 {
7202 EVENT_INIT (buf);
7203 buf.kind = ICONIFY_EVENT;
7204 XSETFRAME (buf.frame_or_window, f);
7205 buf.arg = Qnil;
7206 kbd_buffer_store_event (&buf);
7207 }
7208
7209 f->async_visible = visible;
7210 f->async_iconified = iconified;
7211 }
7212
7213 /* This tries to wait until the frame is really visible.
7214 However, if the window manager asks the user where to position
7215 the frame, this will return before the user finishes doing that.
7216 The frame will not actually be visible at that time,
7217 but it will become visible later when the window manager
7218 finishes with it. */
7219
7220 void
7221 x_make_frame_visible (f)
7222 struct frame *f;
7223 {
7224 BLOCK_INPUT;
7225
7226 if (! FRAME_VISIBLE_P (f))
7227 {
7228 /* We test FRAME_GARBAGED_P here to make sure we don't
7229 call x_set_offset a second time
7230 if we get to x_make_frame_visible a second time
7231 before the window gets really visible. */
7232 if (! FRAME_ICONIFIED_P (f)
7233 && ! f->output_data.mac->asked_for_visible)
7234 x_set_offset (f, f->left_pos, f->top_pos, 0);
7235
7236 f->output_data.mac->asked_for_visible = 1;
7237
7238 CollapseWindow (FRAME_MAC_WINDOW (f), false);
7239 ShowWindow (FRAME_MAC_WINDOW (f));
7240 }
7241
7242 XFlush (FRAME_MAC_DISPLAY (f));
7243
7244 /* Synchronize to ensure Emacs knows the frame is visible
7245 before we do anything else. We do this loop with input not blocked
7246 so that incoming events are handled. */
7247 {
7248 Lisp_Object frame;
7249 int count;
7250
7251 /* This must come after we set COUNT. */
7252 UNBLOCK_INPUT;
7253
7254 XSETFRAME (frame, f);
7255
7256 /* Wait until the frame is visible. Process X events until a
7257 MapNotify event has been seen, or until we think we won't get a
7258 MapNotify at all.. */
7259 for (count = input_signal_count + 10;
7260 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7261 {
7262 /* Force processing of queued events. */
7263 x_sync (f);
7264
7265 /* Machines that do polling rather than SIGIO have been
7266 observed to go into a busy-wait here. So we'll fake an
7267 alarm signal to let the handler know that there's something
7268 to be read. We used to raise a real alarm, but it seems
7269 that the handler isn't always enabled here. This is
7270 probably a bug. */
7271 if (input_polling_used ())
7272 {
7273 /* It could be confusing if a real alarm arrives while
7274 processing the fake one. Turn it off and let the
7275 handler reset it. */
7276 extern void poll_for_input_1 P_ ((void));
7277 int old_poll_suppress_count = poll_suppress_count;
7278 poll_suppress_count = 1;
7279 poll_for_input_1 ();
7280 poll_suppress_count = old_poll_suppress_count;
7281 }
7282
7283 /* See if a MapNotify event has been processed. */
7284 FRAME_SAMPLE_VISIBILITY (f);
7285 }
7286 }
7287 }
7288
7289 /* Change from mapped state to withdrawn state. */
7290
7291 /* Make the frame visible (mapped and not iconified). */
7292
7293 void
7294 x_make_frame_invisible (f)
7295 struct frame *f;
7296 {
7297 /* A deactivate event does not occur when the last visible frame is
7298 made invisible. So if we clear the highlight here, it will not
7299 be rehighlighted when it is made visible. */
7300 #if 0
7301 /* Don't keep the highlight on an invisible frame. */
7302 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7303 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7304 #endif
7305
7306 BLOCK_INPUT;
7307
7308 #if !TARGET_API_MAC_CARBON
7309 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7310 that the current position of the window is user-specified, rather than
7311 program-specified, so that when the window is mapped again, it will be
7312 placed at the same location, without forcing the user to position it
7313 by hand again (they have already done that once for this window.) */
7314 x_wm_set_size_hint (f, (long) 0, 1);
7315 #endif
7316
7317 HideWindow (FRAME_MAC_WINDOW (f));
7318
7319 UNBLOCK_INPUT;
7320
7321 #if !TARGET_API_MAC_CARBON
7322 mac_handle_visibility_change (f);
7323 #endif
7324 }
7325
7326 /* Change window state from mapped to iconified. */
7327
7328 void
7329 x_iconify_frame (f)
7330 struct frame *f;
7331 {
7332 OSStatus err;
7333
7334 /* A deactivate event does not occur when the last visible frame is
7335 iconified. So if we clear the highlight here, it will not be
7336 rehighlighted when it is deiconified. */
7337 #if 0
7338 /* Don't keep the highlight on an invisible frame. */
7339 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7340 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
7341 #endif
7342
7343 if (f->async_iconified)
7344 return;
7345
7346 BLOCK_INPUT;
7347
7348 FRAME_SAMPLE_VISIBILITY (f);
7349
7350 if (! FRAME_VISIBLE_P (f))
7351 ShowWindow (FRAME_MAC_WINDOW (f));
7352
7353 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
7354
7355 UNBLOCK_INPUT;
7356
7357 if (err != noErr)
7358 error ("Can't notify window manager of iconification");
7359
7360 #if !TARGET_API_MAC_CARBON
7361 mac_handle_visibility_change (f);
7362 #endif
7363 }
7364
7365 \f
7366 /* Free X resources of frame F. */
7367
7368 void
7369 x_free_frame_resources (f)
7370 struct frame *f;
7371 {
7372 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7373 WindowRef wp = FRAME_MAC_WINDOW (f);
7374
7375 BLOCK_INPUT;
7376
7377 if (wp != tip_window)
7378 remove_window_handler (wp);
7379
7380 #if USE_CG_DRAWING
7381 mac_prepare_for_quickdraw (f);
7382 #endif
7383 DisposeWindow (wp);
7384 if (wp == tip_window)
7385 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7386 closed' event. So we reset tip_window here. */
7387 tip_window = NULL;
7388
7389 free_frame_menubar (f);
7390
7391 if (FRAME_FACE_CACHE (f))
7392 free_frame_faces (f);
7393
7394 x_free_gcs (f);
7395
7396 if (FRAME_SIZE_HINTS (f))
7397 xfree (FRAME_SIZE_HINTS (f));
7398
7399 xfree (f->output_data.mac);
7400 f->output_data.mac = NULL;
7401
7402 if (f == dpyinfo->x_focus_frame)
7403 {
7404 dpyinfo->x_focus_frame = 0;
7405 #if USE_MAC_FONT_PANEL
7406 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7407 #endif
7408 }
7409 if (f == dpyinfo->x_focus_event_frame)
7410 dpyinfo->x_focus_event_frame = 0;
7411 if (f == dpyinfo->x_highlight_frame)
7412 dpyinfo->x_highlight_frame = 0;
7413
7414 if (f == dpyinfo->mouse_face_mouse_frame)
7415 {
7416 dpyinfo->mouse_face_beg_row
7417 = dpyinfo->mouse_face_beg_col = -1;
7418 dpyinfo->mouse_face_end_row
7419 = dpyinfo->mouse_face_end_col = -1;
7420 dpyinfo->mouse_face_window = Qnil;
7421 dpyinfo->mouse_face_deferred_gc = 0;
7422 dpyinfo->mouse_face_mouse_frame = 0;
7423 }
7424
7425 UNBLOCK_INPUT;
7426 }
7427
7428
7429 /* Destroy the X window of frame F. */
7430
7431 void
7432 x_destroy_window (f)
7433 struct frame *f;
7434 {
7435 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7436
7437 x_free_frame_resources (f);
7438
7439 dpyinfo->reference_count--;
7440 }
7441
7442 \f
7443 /* Setting window manager hints. */
7444
7445 /* Set the normal size hints for the window manager, for frame F.
7446 FLAGS is the flags word to use--or 0 meaning preserve the flags
7447 that the window now has.
7448 If USER_POSITION is nonzero, we set the USPosition
7449 flag (this is useful when FLAGS is 0). */
7450 void
7451 x_wm_set_size_hint (f, flags, user_position)
7452 struct frame *f;
7453 long flags;
7454 int user_position;
7455 {
7456 int base_width, base_height, width_inc, height_inc;
7457 int min_rows = 0, min_cols = 0;
7458 XSizeHints *size_hints;
7459
7460 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7461 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7462 width_inc = FRAME_COLUMN_WIDTH (f);
7463 height_inc = FRAME_LINE_HEIGHT (f);
7464
7465 check_frame_size (f, &min_rows, &min_cols);
7466
7467 size_hints = FRAME_SIZE_HINTS (f);
7468 if (size_hints == NULL)
7469 {
7470 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7471 bzero (size_hints, sizeof (XSizeHints));
7472 }
7473
7474 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7475 size_hints->width_inc = width_inc;
7476 size_hints->height_inc = height_inc;
7477 size_hints->min_width = base_width + min_cols * width_inc;
7478 size_hints->min_height = base_height + min_rows * height_inc;
7479 size_hints->base_width = base_width;
7480 size_hints->base_height = base_height;
7481
7482 if (flags)
7483 size_hints->flags = flags;
7484 else if (user_position)
7485 {
7486 size_hints->flags &= ~ PPosition;
7487 size_hints->flags |= USPosition;
7488 }
7489 }
7490
7491 #if 0 /* MAC_TODO: hide application instead of iconify? */
7492 /* Used for IconicState or NormalState */
7493
7494 void
7495 x_wm_set_window_state (f, state)
7496 struct frame *f;
7497 int state;
7498 {
7499 #ifdef USE_X_TOOLKIT
7500 Arg al[1];
7501
7502 XtSetArg (al[0], XtNinitialState, state);
7503 XtSetValues (f->output_data.x->widget, al, 1);
7504 #else /* not USE_X_TOOLKIT */
7505 Window window = FRAME_X_WINDOW (f);
7506
7507 f->output_data.x->wm_hints.flags |= StateHint;
7508 f->output_data.x->wm_hints.initial_state = state;
7509
7510 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7511 #endif /* not USE_X_TOOLKIT */
7512 }
7513
7514 void
7515 x_wm_set_icon_pixmap (f, pixmap_id)
7516 struct frame *f;
7517 int pixmap_id;
7518 {
7519 Pixmap icon_pixmap;
7520
7521 #ifndef USE_X_TOOLKIT
7522 Window window = FRAME_X_WINDOW (f);
7523 #endif
7524
7525 if (pixmap_id > 0)
7526 {
7527 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7528 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7529 }
7530 else
7531 {
7532 /* It seems there is no way to turn off use of an icon pixmap.
7533 The following line does it, only if no icon has yet been created,
7534 for some window managers. But with mwm it crashes.
7535 Some people say it should clear the IconPixmapHint bit in this case,
7536 but that doesn't work, and the X consortium said it isn't the
7537 right thing at all. Since there is no way to win,
7538 best to explicitly give up. */
7539 #if 0
7540 f->output_data.x->wm_hints.icon_pixmap = None;
7541 #else
7542 return;
7543 #endif
7544 }
7545
7546 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7547
7548 {
7549 Arg al[1];
7550 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7551 XtSetValues (f->output_data.x->widget, al, 1);
7552 }
7553
7554 #else /* not USE_X_TOOLKIT */
7555
7556 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7557 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7558
7559 #endif /* not USE_X_TOOLKIT */
7560 }
7561
7562 #endif /* MAC_TODO */
7563
7564 void
7565 x_wm_set_icon_position (f, icon_x, icon_y)
7566 struct frame *f;
7567 int icon_x, icon_y;
7568 {
7569 #if 0 /* MAC_TODO: no icons on Mac */
7570 #ifdef USE_X_TOOLKIT
7571 Window window = XtWindow (f->output_data.x->widget);
7572 #else
7573 Window window = FRAME_X_WINDOW (f);
7574 #endif
7575
7576 f->output_data.x->wm_hints.flags |= IconPositionHint;
7577 f->output_data.x->wm_hints.icon_x = icon_x;
7578 f->output_data.x->wm_hints.icon_y = icon_y;
7579
7580 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7581 #endif /* MAC_TODO */
7582 }
7583
7584 \f
7585 /***********************************************************************
7586 XLFD Pattern Match
7587 ***********************************************************************/
7588
7589 /* An XLFD pattern is divided into blocks delimited by '*'. This
7590 structure holds information for each block. */
7591 struct xlfdpat_block
7592 {
7593 /* Length of the pattern string in this block. Non-zero except for
7594 the first and the last blocks. */
7595 int len;
7596
7597 /* Pattern string except the last character in this block. The last
7598 character is replaced with NUL in order to use it as a
7599 sentinel. */
7600 unsigned char *pattern;
7601
7602 /* Last character of the pattern string. Must not be '?'. */
7603 unsigned char last_char;
7604
7605 /* One of the tables for the Boyer-Moore string search. It
7606 specifies the number of positions to proceed for each character
7607 with which the match fails. */
7608 int skip[256];
7609
7610 /* The skip value for the last character in the above `skip' is
7611 assigned to `infinity' in order to simplify a loop condition.
7612 The original value is saved here. */
7613 int last_char_skip;
7614 };
7615
7616 struct xlfdpat
7617 {
7618 /* Normalized pattern string. "Normalized" means that capital
7619 letters are lowered, blocks are not empty except the first and
7620 the last ones, and trailing '?'s in a block that is not the last
7621 one are moved to the next one. The last character in each block
7622 is replaced with NUL. */
7623 unsigned char *buf;
7624
7625 /* Number of characters except '*'s and trailing '?'s in the
7626 normalized pattern string. */
7627 int nchars;
7628
7629 /* Number of trailing '?'s in the normalized pattern string. */
7630 int trailing_anychars;
7631
7632 /* Number of blocks and information for each block. The latter is
7633 NULL if the pattern is exact (no '*' or '?' in it). */
7634 int nblocks;
7635 struct xlfdpat_block *blocks;
7636 };
7637
7638 static void
7639 xlfdpat_destroy (pat)
7640 struct xlfdpat *pat;
7641 {
7642 if (pat)
7643 {
7644 if (pat->buf)
7645 {
7646 if (pat->blocks)
7647 xfree (pat->blocks);
7648 xfree (pat->buf);
7649 }
7650 xfree (pat);
7651 }
7652 }
7653
7654 static struct xlfdpat *
7655 xlfdpat_create (pattern)
7656 const char *pattern;
7657 {
7658 struct xlfdpat *pat;
7659 int nblocks, i, skip;
7660 unsigned char last_char, *p, *q, *anychar_head;
7661 const unsigned char *ptr;
7662 struct xlfdpat_block *blk;
7663
7664 pat = xmalloc (sizeof (struct xlfdpat));
7665 pat->buf = xmalloc (strlen (pattern) + 1);
7666
7667 /* Normalize the pattern string and store it to `pat->buf'. */
7668 nblocks = 0;
7669 anychar_head = NULL;
7670 q = pat->buf;
7671 last_char = '\0';
7672 for (ptr = pattern; *ptr; ptr++)
7673 {
7674 unsigned char c = *ptr;
7675
7676 if (c == '*')
7677 if (last_char == '*')
7678 /* ...a** -> ...a* */
7679 continue;
7680 else
7681 {
7682 if (last_char == '?')
7683 {
7684 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7685 /* ...*??* -> ...*?? */
7686 continue;
7687 else
7688 /* ...a??* -> ...a*?? */
7689 {
7690 *anychar_head++ = '*';
7691 c = '?';
7692 }
7693 }
7694 nblocks++;
7695 }
7696 else if (c == '?')
7697 {
7698 if (last_char != '?')
7699 anychar_head = q;
7700 }
7701 else
7702 /* On Mac OS X 10.3, tolower also converts non-ASCII
7703 characters for some locales. */
7704 if (isascii (c))
7705 c = tolower (c);
7706
7707 *q++ = last_char = c;
7708 }
7709 *q = '\0';
7710 nblocks++;
7711 pat->nblocks = nblocks;
7712 if (last_char != '?')
7713 pat->trailing_anychars = 0;
7714 else
7715 {
7716 pat->trailing_anychars = q - anychar_head;
7717 q = anychar_head;
7718 }
7719 pat->nchars = q - pat->buf - (nblocks - 1);
7720
7721 if (anychar_head == NULL && nblocks == 1)
7722 {
7723 /* The pattern is exact. */
7724 pat->blocks = NULL;
7725 return pat;
7726 }
7727
7728 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
7729
7730 /* Divide the normalized pattern into blocks. */
7731 p = pat->buf;
7732 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7733 {
7734 blk->pattern = p;
7735 while (*p != '*')
7736 p++;
7737 blk->len = p - blk->pattern;
7738 p++;
7739 }
7740 blk->pattern = p;
7741 blk->len = q - blk->pattern;
7742
7743 /* Setup a table for the Boyer-Moore string search. */
7744 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7745 if (blk->len != 0)
7746 {
7747 blk->last_char = blk->pattern[blk->len - 1];
7748 blk->pattern[blk->len - 1] = '\0';
7749
7750 for (skip = 1; skip < blk->len; skip++)
7751 if (blk->pattern[blk->len - skip - 1] == '?')
7752 break;
7753
7754 for (i = 0; i < 256; i++)
7755 blk->skip[i] = skip;
7756
7757 p = blk->pattern + (blk->len - skip);
7758 while (--skip > 0)
7759 blk->skip[*p++] = skip;
7760
7761 blk->last_char_skip = blk->skip[blk->last_char];
7762 }
7763
7764 return pat;
7765 }
7766
7767 static INLINE int
7768 xlfdpat_exact_p (pat)
7769 struct xlfdpat *pat;
7770 {
7771 return pat->blocks == NULL;
7772 }
7773
7774 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
7775 that the pattern in *BLK matches with its prefix. Return NULL
7776 there is no such strings. STRING must be lowered in advance. */
7777
7778 static const char *
7779 xlfdpat_block_match_1 (blk, string, start_max)
7780 struct xlfdpat_block *blk;
7781 const unsigned char *string;
7782 int start_max;
7783 {
7784 int start, infinity;
7785 unsigned char *p;
7786 const unsigned char *s;
7787
7788 xassert (blk->len > 0);
7789 xassert (start_max + blk->len <= strlen (string));
7790 xassert (blk->last_char != '?');
7791
7792 /* See the comments in the function `boyer_moore' (search.c) for the
7793 use of `infinity'. */
7794 infinity = start_max + blk->len + 1;
7795 blk->skip[blk->last_char] = infinity;
7796
7797 start = 0;
7798 do
7799 {
7800 /* Check the last character of the pattern. */
7801 s = string + blk->len - 1;
7802 do
7803 {
7804 start += blk->skip[*(s + start)];
7805 }
7806 while (start <= start_max);
7807
7808 if (start < infinity)
7809 /* Couldn't find the last character. */
7810 return NULL;
7811
7812 /* No less than `infinity' means we could find the last
7813 character at `s[start - infinity]'. */
7814 start -= infinity;
7815
7816 /* Check the remaining characters. We prefer making no-'?'
7817 cases faster because the use of '?' is really rare. */
7818 p = blk->pattern;
7819 s = string + start;
7820 do
7821 {
7822 while (*p++ == *s++)
7823 ;
7824 }
7825 while (*(p - 1) == '?');
7826
7827 if (*(p - 1) == '\0')
7828 /* Matched. */
7829 return string + start;
7830
7831 /* Didn't match. */
7832 start += blk->last_char_skip;
7833 }
7834 while (start <= start_max);
7835
7836 return NULL;
7837 }
7838
7839 #define xlfdpat_block_match(b, s, m) \
7840 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7841 : xlfdpat_block_match_1 (b, s, m))
7842
7843 /* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
7844 matches with STRING. STRING must be lowered in advance. */
7845
7846 static int
7847 xlfdpat_match (pat, string)
7848 struct xlfdpat *pat;
7849 const unsigned char *string;
7850 {
7851 int str_len, nblocks, i, start_max;
7852 struct xlfdpat_block *blk;
7853 const unsigned char *s;
7854
7855 xassert (pat->nblocks > 0);
7856
7857 if (xlfdpat_exact_p (pat))
7858 return strcmp (pat->buf, string) == 0;
7859
7860 /* The number of the characters in the string must not be smaller
7861 than that in the pattern. */
7862 str_len = strlen (string);
7863 if (str_len < pat->nchars + pat->trailing_anychars)
7864 return 0;
7865
7866 /* Chop off the trailing '?'s. */
7867 str_len -= pat->trailing_anychars;
7868
7869 /* The last block. When it is non-empty, it must match at the end
7870 of the string. */
7871 nblocks = pat->nblocks;
7872 blk = pat->blocks + (nblocks - 1);
7873 if (nblocks == 1)
7874 /* The last block is also the first one. */
7875 return (str_len == blk->len
7876 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7877 else if (blk->len != 0)
7878 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7879 return 0;
7880
7881 /* The first block. When it is non-empty, it must match at the
7882 beginning of the string. */
7883 blk = pat->blocks;
7884 if (blk->len != 0)
7885 {
7886 s = xlfdpat_block_match (blk, string, 0);
7887 if (s == NULL)
7888 return 0;
7889 string = s + blk->len;
7890 }
7891
7892 /* The rest of the blocks. */
7893 start_max = str_len - pat->nchars;
7894 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7895 {
7896 s = xlfdpat_block_match (blk, string, start_max);
7897 if (s == NULL)
7898 return 0;
7899 start_max -= s - string;
7900 string = s + blk->len;
7901 }
7902
7903 return 1;
7904 }
7905
7906 \f
7907 /***********************************************************************
7908 Fonts
7909 ***********************************************************************/
7910
7911 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7912
7913 struct font_info *
7914 x_get_font_info (f, font_idx)
7915 FRAME_PTR f;
7916 int font_idx;
7917 {
7918 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7919 }
7920
7921 /* the global font name table */
7922 static char **font_name_table = NULL;
7923 static int font_name_table_size = 0;
7924 static int font_name_count = 0;
7925
7926 /* Alist linking font family names to Font Manager font family
7927 references (which can also be used as QuickDraw font IDs). We use
7928 an alist because hash tables are not ready when the terminal frame
7929 for Mac OS Classic is created. */
7930 static Lisp_Object fm_font_family_alist;
7931 #if USE_ATSUI
7932 /* Hash table linking font family names to ATSU font IDs. */
7933 static Lisp_Object atsu_font_id_hash;
7934 /* Alist linking Font Manager style to face attributes. */
7935 static Lisp_Object fm_style_face_attributes_alist;
7936 extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
7937 #endif
7938
7939 /* Alist linking character set strings to Mac text encoding and Emacs
7940 coding system. */
7941 static Lisp_Object Vmac_charset_info_alist;
7942
7943 static Lisp_Object
7944 create_text_encoding_info_alist ()
7945 {
7946 Lisp_Object result = Qnil, rest;
7947
7948 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7949 {
7950 Lisp_Object charset_info = XCAR (rest);
7951 Lisp_Object charset, coding_system, text_encoding;
7952 Lisp_Object existing_info;
7953
7954 if (!(CONSP (charset_info)
7955 && (charset = XCAR (charset_info),
7956 STRINGP (charset))
7957 && CONSP (XCDR (charset_info))
7958 && (text_encoding = XCAR (XCDR (charset_info)),
7959 INTEGERP (text_encoding))
7960 && CONSP (XCDR (XCDR (charset_info)))
7961 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7962 SYMBOLP (coding_system))))
7963 continue;
7964
7965 existing_info = assq_no_quit (text_encoding, result);
7966 if (NILP (existing_info))
7967 result = Fcons (list3 (text_encoding, coding_system, charset),
7968 result);
7969 else
7970 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7971 XSETCDR (XCDR (existing_info),
7972 Fcons (charset, XCDR (XCDR (existing_info))));
7973 }
7974
7975 return result;
7976 }
7977
7978
7979 static void
7980 decode_mac_font_name (name, size, coding_system)
7981 char *name;
7982 int size;
7983 Lisp_Object coding_system;
7984 {
7985 struct coding_system coding;
7986 char *buf, *p;
7987
7988 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7989 {
7990 for (p = name; *p; p++)
7991 if (!isascii (*p) || iscntrl (*p))
7992 break;
7993
7994 if (*p)
7995 {
7996 setup_coding_system (coding_system, &coding);
7997 coding.src_multibyte = 0;
7998 coding.dst_multibyte = 1;
7999 coding.mode |= CODING_MODE_LAST_BLOCK;
8000 coding.dst_bytes = size;
8001 coding.destination = (unsigned char *) alloca (coding.dst_bytes);
8002
8003 decode_coding_c_string (&coding, name, strlen (name), Qnil);
8004 bcopy (coding.destination, name, min (coding.produced, size));
8005 name[min (coding.produced, size)] = '\0';
8006 }
8007 }
8008
8009 /* If there's just one occurrence of '-' in the family name, it is
8010 replaced with '_'. (More than one occurrence of '-' means a
8011 "FOUNDRY-FAMILY-CHARSET"-style name.) */
8012 p = strchr (name, '-');
8013 if (p && strchr (p + 1, '-') == NULL)
8014 *p = '_';
8015
8016 for (p = name; *p; p++)
8017 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8018 for some locales. */
8019 if (isascii (*p))
8020 *p = tolower (*p);
8021 }
8022
8023
8024 static char *
8025 mac_to_x_fontname (name, size, style, charset)
8026 const char *name;
8027 int size;
8028 Style style;
8029 char *charset;
8030 {
8031 Str31 foundry, cs;
8032 Str255 family;
8033 char xf[256], *result;
8034 unsigned char *p;
8035
8036 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
8037 charset = cs;
8038 else
8039 {
8040 strcpy(foundry, "Apple");
8041 strcpy(family, name);
8042 }
8043
8044 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
8045 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
8046 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
8047
8048 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
8049 sprintf (result, "-%s-%s-%s", foundry, family, xf);
8050 for (p = result; *p; p++)
8051 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8052 for some locales. */
8053 if (isascii (*p))
8054 *p = tolower (*p);
8055 return result;
8056 }
8057
8058
8059 /* Parse fully-specified and instantiated X11 font spec XF, and store
8060 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
8061 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
8062 caller must allocate at least 256 and 32 bytes respectively. For
8063 ordinary Mac fonts, the value stored to FAMILY should just be their
8064 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
8065 intlfonts collection contain their charset designation in their
8066 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
8067 types of font names are handled accordingly. */
8068
8069 const int kDefaultFontSize = 12;
8070
8071 static int
8072 parse_x_font_name (xf, family, size, style, charset)
8073 const char *xf;
8074 char *family;
8075 int *size;
8076 Style *style;
8077 char *charset;
8078 {
8079 Str31 foundry, weight;
8080 int point_size, avgwidth;
8081 char slant[2], *p;
8082
8083 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8084 foundry, family, weight, slant, size,
8085 &point_size, &avgwidth, charset) != 8
8086 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8087 foundry, family, weight, slant, size,
8088 &point_size, &avgwidth, charset) != 8)
8089 return 0;
8090
8091 if (*size == 0)
8092 {
8093 if (point_size > 0)
8094 *size = point_size / 10;
8095 else if (avgwidth > 0)
8096 *size = avgwidth / 10;
8097 }
8098 if (*size == 0)
8099 *size = kDefaultFontSize;
8100
8101 *style = normal;
8102 if (strcmp (weight, "bold") == 0)
8103 *style |= bold;
8104 if (*slant == 'i')
8105 *style |= italic;
8106
8107 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
8108 {
8109 int foundry_len = strlen (foundry), family_len = strlen (family);
8110
8111 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
8112 {
8113 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
8114 but take overlap into account. */
8115 memmove (family + foundry_len + 1, family, family_len);
8116 memcpy (family, foundry, foundry_len);
8117 family[foundry_len] = '-';
8118 family[foundry_len + 1 + family_len] = '-';
8119 strcpy (family + foundry_len + 1 + family_len + 1, charset);
8120 }
8121 else
8122 return 0;
8123 }
8124
8125 for (p = family; *p; p++)
8126 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8127 for some locales. */
8128 if (isascii (*p))
8129 *p = tolower (*p);
8130
8131 return 1;
8132 }
8133
8134
8135 static void
8136 add_font_name_table_entry (char *font_name)
8137 {
8138 if (font_name_table_size == 0)
8139 {
8140 font_name_table_size = 256;
8141 font_name_table = (char **)
8142 xmalloc (font_name_table_size * sizeof (char *));
8143 }
8144 else if (font_name_count + 1 >= font_name_table_size)
8145 {
8146 font_name_table_size *= 2;
8147 font_name_table = (char **)
8148 xrealloc (font_name_table,
8149 font_name_table_size * sizeof (char *));
8150 }
8151
8152 font_name_table[font_name_count++] = font_name;
8153 }
8154
8155 static void
8156 add_mac_font_name (name, size, style, charset)
8157 const char *name;
8158 int size;
8159 Style style;
8160 const char *charset;
8161 {
8162 if (size > 0)
8163 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8164 else
8165 {
8166 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8167 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8168 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8169 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8170 charset));
8171 }
8172 }
8173
8174 #if USE_ATSUI
8175 static FMFontStyle
8176 fm_get_style_from_font (font)
8177 FMFont font;
8178 {
8179 OSStatus err;
8180 FMFontStyle style = normal;
8181 ByteCount len;
8182 UInt16 mac_style;
8183 FMFontFamily font_family;
8184 #define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8185
8186 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8187 some font (e.g., Optima) even if it is `bold'. */
8188 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8189 sizeof (mac_style), &mac_style, &len);
8190 if (err == noErr
8191 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8192 style = EndianU16_BtoN (mac_style);
8193 else
8194 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8195
8196 return style;
8197 }
8198
8199 static ATSUFontID
8200 atsu_find_font_from_family_name (family)
8201 const char *family;
8202 {
8203 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8204 unsigned hash_code;
8205 int i;
8206 Lisp_Object rest, best;
8207 FMFontStyle min_style, style;
8208
8209 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8210 &hash_code);
8211 if (i < 0)
8212 return kATSUInvalidFontID;
8213
8214 rest = HASH_VALUE (h, i);
8215 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8216 return cons_to_long (rest);
8217
8218 rest = Fnreverse (rest);
8219 best = XCAR (rest);
8220 rest = XCDR (rest);
8221 if (!NILP (rest)
8222 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8223 do
8224 {
8225 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8226 if (style < min_style)
8227 {
8228 best = XCAR (rest);
8229 if (style == normal)
8230 break;
8231 else
8232 min_style = style;
8233 }
8234 rest = XCDR (rest);
8235 }
8236 while (!NILP (rest));
8237
8238 HASH_VALUE (h, i) = best;
8239 return cons_to_long (best);
8240 }
8241
8242 static Lisp_Object
8243 fm_style_to_face_attributes (fm_style)
8244 FMFontStyle fm_style;
8245 {
8246 Lisp_Object tem;
8247
8248 fm_style &= (bold | italic);
8249 tem = assq_no_quit (make_number (fm_style),
8250 fm_style_face_attributes_alist);
8251 if (!NILP (tem))
8252 return XCDR (tem);
8253
8254 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8255 QCslant, fm_style & italic ? Qitalic : Qnormal);
8256 fm_style_face_attributes_alist =
8257 Fcons (Fcons (make_number (fm_style), tem),
8258 fm_style_face_attributes_alist);
8259
8260 return tem;
8261 }
8262
8263 static Lisp_Object
8264 atsu_find_font_family_name (font_id)
8265 ATSUFontID font_id;
8266 {
8267 OSStatus err;
8268 ByteCount len;
8269 Lisp_Object family = Qnil;
8270
8271 err = ATSUFindFontName (font_id, kFontFamilyName,
8272 kFontMacintoshPlatform, kFontNoScript,
8273 kFontNoLanguage, 0, NULL, &len, NULL);
8274 if (err == noErr)
8275 {
8276 family = make_uninit_string (len);
8277 err = ATSUFindFontName (font_id, kFontFamilyName,
8278 kFontMacintoshPlatform, kFontNoScript,
8279 kFontNoLanguage, len, SDATA (family),
8280 NULL, NULL);
8281 }
8282 if (err == noErr)
8283 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8284
8285 return family;
8286 }
8287
8288 Lisp_Object
8289 mac_atsu_font_face_attributes (font_id)
8290 ATSUFontID font_id;
8291 {
8292 Lisp_Object family, style_attrs;
8293
8294 family = atsu_find_font_family_name (font_id);
8295 if (NILP (family))
8296 return Qnil;
8297 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8298 return Fcons (QCfamily, Fcons (family, style_attrs));
8299 }
8300 #endif
8301
8302 /* Sets up the table font_name_table to contain the list of all fonts
8303 in the system the first time the table is used so that the Resource
8304 Manager need not be accessed every time this information is
8305 needed. */
8306
8307 static void
8308 init_font_name_table ()
8309 {
8310 #if TARGET_API_MAC_CARBON
8311 FMFontFamilyIterator ffi;
8312 FMFontFamilyInstanceIterator ffii;
8313 FMFontFamily ff;
8314 Lisp_Object text_encoding_info_alist;
8315 struct gcpro gcpro1;
8316
8317 text_encoding_info_alist = create_text_encoding_info_alist ();
8318
8319 #if USE_ATSUI
8320 #if USE_CG_TEXT_DRAWING
8321 init_cg_text_anti_aliasing_threshold ();
8322 #endif
8323 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8324 text_encoding_info_alist)))
8325 {
8326 OSStatus err;
8327 struct Lisp_Hash_Table *h;
8328 unsigned hash_code;
8329 ItemCount nfonts, i;
8330 ATSUFontID *font_ids = NULL;
8331 Lisp_Object prev_family = Qnil;
8332 int j;
8333
8334 atsu_font_id_hash =
8335 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8336 make_float (DEFAULT_REHASH_SIZE),
8337 make_float (DEFAULT_REHASH_THRESHOLD),
8338 Qnil, Qnil, Qnil);
8339 h = XHASH_TABLE (atsu_font_id_hash);
8340
8341 err = ATSUFontCount (&nfonts);
8342 if (err == noErr)
8343 {
8344 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8345 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8346 }
8347 if (err == noErr)
8348 for (i = 0; i < nfonts; i++)
8349 {
8350 Lisp_Object family;
8351
8352 family = atsu_find_font_family_name (font_ids[i]);
8353 if (NILP (family) || SREF (family, 0) == '.')
8354 continue;
8355 if (!NILP (Fequal (prev_family, family)))
8356 family = prev_family;
8357 else
8358 j = hash_lookup (h, family, &hash_code);
8359 if (j < 0)
8360 {
8361 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8362 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8363 Qnil), hash_code);
8364 }
8365 else if (EQ (prev_family, family))
8366 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8367 HASH_VALUE (h, j));
8368 prev_family = family;
8369 }
8370 if (font_ids)
8371 xfree (font_ids);
8372 }
8373 #endif
8374
8375 /* Create a dummy instance iterator here to avoid creating and
8376 destroying it in the loop. */
8377 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8378 return;
8379 /* Create an iterator to enumerate the font families. */
8380 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8381 != noErr)
8382 {
8383 FMDisposeFontFamilyInstanceIterator (&ffii);
8384 return;
8385 }
8386
8387 GCPRO1 (text_encoding_info_alist);
8388
8389 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
8390 {
8391 Str255 name;
8392 FMFont font;
8393 FMFontStyle style;
8394 FMFontSize size;
8395 TextEncoding encoding;
8396 TextEncodingBase sc;
8397 Lisp_Object text_encoding_info, family;
8398
8399 if (FMGetFontFamilyName (ff, name) != noErr)
8400 continue;
8401 p2cstr (name);
8402 if (*name == '.')
8403 continue;
8404
8405 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
8406 continue;
8407 sc = GetTextEncodingBase (encoding);
8408 text_encoding_info = assq_no_quit (make_number (sc),
8409 text_encoding_info_alist);
8410 if (NILP (text_encoding_info))
8411 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8412 text_encoding_info_alist);
8413 decode_mac_font_name (name, sizeof (name),
8414 XCAR (XCDR (text_encoding_info)));
8415 family = build_string (name);
8416 if (!NILP (Fassoc (family, fm_font_family_alist)))
8417 continue;
8418 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
8419 fm_font_family_alist);
8420
8421 /* Point the instance iterator at the current font family. */
8422 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
8423 continue;
8424
8425 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8426 == noErr)
8427 {
8428 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8429
8430 if (size > 0 || style == normal)
8431 for (; CONSP (rest); rest = XCDR (rest))
8432 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
8433 }
8434 }
8435
8436 UNGCPRO;
8437
8438 /* Dispose of the iterators. */
8439 FMDisposeFontFamilyIterator (&ffi);
8440 FMDisposeFontFamilyInstanceIterator (&ffii);
8441 #else /* !TARGET_API_MAC_CARBON */
8442 GrafPtr port;
8443 SInt16 fontnum, old_fontnum;
8444 int num_mac_fonts = CountResources('FOND');
8445 int i, j;
8446 Handle font_handle, font_handle_2;
8447 short id, scriptcode;
8448 ResType type;
8449 Str255 name;
8450 struct FontAssoc *fat;
8451 struct AsscEntry *assc_entry;
8452 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
8453 struct gcpro gcpro1;
8454
8455 GetPort (&port); /* save the current font number used */
8456 old_fontnum = port->txFont;
8457
8458 text_encoding_info_alist = create_text_encoding_info_alist ();
8459
8460 GCPRO1 (text_encoding_info_alist);
8461
8462 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
8463 {
8464 font_handle = GetIndResource ('FOND', i);
8465 if (!font_handle)
8466 continue;
8467
8468 GetResInfo (font_handle, &id, &type, name);
8469 GetFNum (name, &fontnum);
8470 p2cstr (name);
8471 if (fontnum == 0 || *name == '.')
8472 continue;
8473
8474 TextFont (fontnum);
8475 scriptcode = FontToScript (fontnum);
8476 text_encoding_info = assq_no_quit (make_number (scriptcode),
8477 text_encoding_info_alist);
8478 if (NILP (text_encoding_info))
8479 text_encoding_info = assq_no_quit (make_number (smRoman),
8480 text_encoding_info_alist);
8481 decode_mac_font_name (name, sizeof (name),
8482 XCAR (XCDR (text_encoding_info)));
8483 family = build_string (name);
8484 if (!NILP (Fassoc (family, fm_font_family_alist)))
8485 continue;
8486 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
8487 fm_font_family_alist);
8488 do
8489 {
8490 HLock (font_handle);
8491
8492 if (GetResourceSizeOnDisk (font_handle)
8493 >= sizeof (struct FamRec))
8494 {
8495 fat = (struct FontAssoc *) (*font_handle
8496 + sizeof (struct FamRec));
8497 assc_entry
8498 = (struct AsscEntry *) (*font_handle
8499 + sizeof (struct FamRec)
8500 + sizeof (struct FontAssoc));
8501
8502 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
8503 {
8504 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8505
8506 for (; CONSP (rest); rest = XCDR (rest))
8507 add_mac_font_name (name, assc_entry->fontSize,
8508 assc_entry->fontStyle,
8509 SDATA (XCAR (rest)));
8510 }
8511 }
8512
8513 HUnlock (font_handle);
8514 font_handle_2 = GetNextFOND (font_handle);
8515 ReleaseResource (font_handle);
8516 font_handle = font_handle_2;
8517 }
8518 while (ResError () == noErr && font_handle);
8519 }
8520
8521 UNGCPRO;
8522
8523 TextFont (old_fontnum);
8524 #endif /* !TARGET_API_MAC_CARBON */
8525 }
8526
8527
8528 void
8529 mac_clear_font_name_table ()
8530 {
8531 int i;
8532
8533 for (i = 0; i < font_name_count; i++)
8534 xfree (font_name_table[i]);
8535 xfree (font_name_table);
8536 font_name_table = NULL;
8537 font_name_table_size = font_name_count = 0;
8538 fm_font_family_alist = Qnil;
8539 }
8540
8541
8542 enum xlfd_scalable_field_index
8543 {
8544 XLFD_SCL_PIXEL_SIZE,
8545 XLFD_SCL_POINT_SIZE,
8546 XLFD_SCL_AVGWIDTH,
8547 XLFD_SCL_LAST
8548 };
8549
8550 static const int xlfd_scalable_fields[] =
8551 {
8552 6, /* PIXEL_SIZE */
8553 7, /* POINT_SIZE */
8554 11, /* AVGWIDTH */
8555 -1
8556 };
8557
8558 static Lisp_Object
8559 mac_do_list_fonts (pattern, maxnames)
8560 const char *pattern;
8561 int maxnames;
8562 {
8563 int i, n_fonts = 0;
8564 Lisp_Object font_list = Qnil;
8565 struct xlfdpat *pat;
8566 char *scaled;
8567 const char *ptr;
8568 int scl_val[XLFD_SCL_LAST], *val;
8569 const int *field;
8570 int exact;
8571
8572 if (font_name_table == NULL) /* Initialize when first used. */
8573 init_font_name_table ();
8574
8575 for (i = 0; i < XLFD_SCL_LAST; i++)
8576 scl_val[i] = -1;
8577
8578 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8579 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8580 fonts are scaled according to the specified size. */
8581 ptr = pattern;
8582 i = 0;
8583 field = xlfd_scalable_fields;
8584 val = scl_val;
8585 if (*ptr == '-')
8586 do
8587 {
8588 ptr++;
8589 if (i == *field)
8590 {
8591 if ('0' <= *ptr && *ptr <= '9')
8592 {
8593 *val = *ptr++ - '0';
8594 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8595 *val = *val * 10 + *ptr++ - '0';
8596 if (*ptr != '-')
8597 *val = -1;
8598 }
8599 field++;
8600 val++;
8601 }
8602 ptr = strchr (ptr, '-');
8603 i++;
8604 }
8605 while (ptr && i < 14);
8606
8607 if (i == 14 && ptr == NULL)
8608 {
8609 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8610 scl_val[XLFD_SCL_PIXEL_SIZE] =
8611 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8612 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8613 : -1));
8614 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8615 scl_val[XLFD_SCL_POINT_SIZE] =
8616 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8617 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8618 : -1));
8619 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8620 scl_val[XLFD_SCL_AVGWIDTH] =
8621 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8622 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8623 : -1));
8624 }
8625 else
8626 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8627
8628 pat = xlfdpat_create (pattern);
8629 if (pat == NULL)
8630 return Qnil;
8631
8632 exact = xlfdpat_exact_p (pat);
8633
8634 for (i = 0; i < font_name_count; i++)
8635 {
8636 if (xlfdpat_match (pat, font_name_table[i]))
8637 {
8638 font_list = Fcons (build_string (font_name_table[i]), font_list);
8639 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8640 break;
8641 }
8642 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
8643 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
8644 {
8645 int former_len = ptr - font_name_table[i];
8646
8647 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
8648 memcpy (scaled, font_name_table[i], former_len);
8649 sprintf (scaled + former_len,
8650 "-%d-%d-72-72-m-%d-%s",
8651 scl_val[XLFD_SCL_PIXEL_SIZE],
8652 scl_val[XLFD_SCL_POINT_SIZE],
8653 scl_val[XLFD_SCL_AVGWIDTH],
8654 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
8655
8656 if (xlfdpat_match (pat, scaled))
8657 {
8658 font_list = Fcons (build_string (scaled), font_list);
8659 xfree (scaled);
8660 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
8661 break;
8662 }
8663 else
8664 xfree (scaled);
8665 }
8666 }
8667
8668 xlfdpat_destroy (pat);
8669
8670 return font_list;
8671 }
8672
8673 /* Return a list of names of available fonts matching PATTERN on frame F.
8674
8675 Frame F null means we have not yet created any frame on Mac, and
8676 consult the first display in x_display_list. MAXNAMES sets a limit
8677 on how many fonts to match. */
8678
8679 Lisp_Object
8680 x_list_fonts (f, pattern, size, maxnames)
8681 struct frame *f;
8682 Lisp_Object pattern;
8683 int size, maxnames;
8684 {
8685 Lisp_Object list = Qnil, patterns, tem, key;
8686 struct mac_display_info *dpyinfo
8687 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
8688
8689 xassert (size <= 0);
8690
8691 patterns = Fassoc (pattern, Valternate_fontname_alist);
8692 if (NILP (patterns))
8693 patterns = Fcons (pattern, Qnil);
8694
8695 for (; CONSP (patterns); patterns = XCDR (patterns))
8696 {
8697 pattern = XCAR (patterns);
8698
8699 if (!STRINGP (pattern))
8700 continue;
8701
8702 tem = XCAR (XCDR (dpyinfo->name_list_element));
8703 key = Fcons (pattern, make_number (maxnames));
8704
8705 list = Fassoc (key, tem);
8706 if (!NILP (list))
8707 {
8708 list = Fcdr_safe (list);
8709 /* We have a cashed list. Don't have to get the list again. */
8710 goto label_cached;
8711 }
8712
8713 BLOCK_INPUT;
8714 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8715 UNBLOCK_INPUT;
8716
8717 /* MAC_TODO: add code for matching outline fonts here */
8718
8719 /* Now store the result in the cache. */
8720 XSETCAR (XCDR (dpyinfo->name_list_element),
8721 Fcons (Fcons (key, list),
8722 XCAR (XCDR (dpyinfo->name_list_element))));
8723
8724 label_cached:
8725 if (NILP (list)) continue; /* Try the remaining alternatives. */
8726 }
8727
8728 return list;
8729 }
8730
8731
8732 #if GLYPH_DEBUG
8733
8734 /* Check that FONT is valid on frame F. It is if it can be found in F's
8735 font table. */
8736
8737 static void
8738 x_check_font (f, font)
8739 struct frame *f;
8740 XFontStruct *font;
8741 {
8742 int i;
8743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8744
8745 xassert (font != NULL);
8746
8747 for (i = 0; i < dpyinfo->n_fonts; i++)
8748 if (dpyinfo->font_table[i].name
8749 && font == dpyinfo->font_table[i].font)
8750 break;
8751
8752 xassert (i < dpyinfo->n_fonts);
8753 }
8754
8755 #endif /* GLYPH_DEBUG != 0 */
8756
8757 /* Set *W to the minimum width, *H to the minimum font height of FONT.
8758 Note: There are (broken) X fonts out there with invalid XFontStruct
8759 min_bounds contents. For example, handa@etl.go.jp reports that
8760 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8761 have font->min_bounds.width == 0. */
8762
8763 static INLINE void
8764 x_font_min_bounds (font, w, h)
8765 MacFontStruct *font;
8766 int *w, *h;
8767 {
8768 *h = FONT_HEIGHT (font);
8769 *w = font->min_bounds.width;
8770 }
8771
8772
8773 /* Compute the smallest character width and smallest font height over
8774 all fonts available on frame F. Set the members smallest_char_width
8775 and smallest_font_height in F's x_display_info structure to
8776 the values computed. Value is non-zero if smallest_font_height or
8777 smallest_char_width become smaller than they were before. */
8778
8779 static int
8780 x_compute_min_glyph_bounds (f)
8781 struct frame *f;
8782 {
8783 int i;
8784 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8785 MacFontStruct *font;
8786 int old_width = dpyinfo->smallest_char_width;
8787 int old_height = dpyinfo->smallest_font_height;
8788
8789 dpyinfo->smallest_font_height = 100000;
8790 dpyinfo->smallest_char_width = 100000;
8791
8792 for (i = 0; i < dpyinfo->n_fonts; ++i)
8793 if (dpyinfo->font_table[i].name)
8794 {
8795 struct font_info *fontp = dpyinfo->font_table + i;
8796 int w, h;
8797
8798 font = (MacFontStruct *) fontp->font;
8799 xassert (font != (MacFontStruct *) ~0);
8800 x_font_min_bounds (font, &w, &h);
8801
8802 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8803 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8804 }
8805
8806 xassert (dpyinfo->smallest_char_width > 0
8807 && dpyinfo->smallest_font_height > 0);
8808
8809 return (dpyinfo->n_fonts == 1
8810 || dpyinfo->smallest_char_width < old_width
8811 || dpyinfo->smallest_font_height < old_height);
8812 }
8813
8814
8815 /* Determine whether given string is a fully-specified XLFD: all 14
8816 fields are present, none is '*'. */
8817
8818 static int
8819 is_fully_specified_xlfd (p)
8820 const char *p;
8821 {
8822 int i;
8823 char *q;
8824
8825 if (*p != '-')
8826 return 0;
8827
8828 for (i = 0; i < 13; i++)
8829 {
8830 q = strchr (p + 1, '-');
8831 if (q == NULL)
8832 return 0;
8833 if (q - p == 2 && *(p + 1) == '*')
8834 return 0;
8835 p = q;
8836 }
8837
8838 if (strchr (p + 1, '-') != NULL)
8839 return 0;
8840
8841 if (*(p + 1) == '*' && *(p + 2) == '\0')
8842 return 0;
8843
8844 return 1;
8845 }
8846
8847
8848 /* mac_load_query_font creates and returns an internal representation
8849 for a font in a MacFontStruct struct. There is really no concept
8850 corresponding to "loading" a font on the Mac. But we check its
8851 existence and find the font number and all other information for it
8852 and store them in the returned MacFontStruct. */
8853
8854 static MacFontStruct *
8855 mac_load_query_font (f, fontname)
8856 struct frame *f;
8857 char *fontname;
8858 {
8859 int size;
8860 char *name;
8861 Str255 family;
8862 Str31 charset;
8863 SInt16 fontnum;
8864 #if USE_ATSUI
8865 static ATSUFontID font_id;
8866 ATSUStyle mac_style = NULL;
8867 #endif
8868 Style fontface;
8869 #if TARGET_API_MAC_CARBON
8870 TextEncoding encoding;
8871 int scriptcode;
8872 #else
8873 short scriptcode;
8874 #endif
8875 MacFontStruct *font;
8876 XCharStruct *space_bounds = NULL, *pcm;
8877
8878 if (is_fully_specified_xlfd (fontname))
8879 name = fontname;
8880 else
8881 {
8882 Lisp_Object matched_fonts;
8883
8884 matched_fonts = mac_do_list_fonts (fontname, 1);
8885 if (NILP (matched_fonts))
8886 return NULL;
8887 name = SDATA (XCAR (matched_fonts));
8888 }
8889
8890 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8891 return NULL;
8892
8893 #if USE_ATSUI
8894 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8895 {
8896 OSStatus err;
8897 static const ATSUAttributeTag tags[] =
8898 {kATSUFontTag, kATSUSizeTag,
8899 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8900 static const ByteCount sizes[] =
8901 {sizeof (ATSUFontID), sizeof (Fixed),
8902 sizeof (Boolean), sizeof (Boolean)};
8903 static Fixed size_fixed;
8904 static Boolean bold_p, italic_p;
8905 static const ATSUAttributeValuePtr values[] =
8906 {&font_id, &size_fixed,
8907 &bold_p, &italic_p};
8908 static const ATSUFontFeatureType types[] =
8909 {kAllTypographicFeaturesType, kDiacriticsType};
8910 static const ATSUFontFeatureSelector selectors[] =
8911 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
8912 FMFontStyle style;
8913
8914 font_id = atsu_find_font_from_family_name (family);
8915 if (font_id == kATSUInvalidFontID)
8916 return NULL;
8917 size_fixed = Long2Fix (size);
8918 bold_p = (fontface & bold) != 0;
8919 italic_p = (fontface & italic) != 0;
8920 err = ATSUCreateStyle (&mac_style);
8921 if (err != noErr)
8922 return NULL;
8923 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8924 types, selectors);
8925 if (err != noErr)
8926 return NULL;
8927 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8928 tags, sizes, values);
8929 if (err != noErr)
8930 return NULL;
8931 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8932 if (err != noErr)
8933 fontnum = -1;
8934 scriptcode = kTextEncodingMacUnicode;
8935 }
8936 else
8937 #endif
8938 {
8939 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8940
8941 if (NILP (tmp))
8942 return NULL;
8943 fontnum = XINT (XCDR (tmp));
8944 #if TARGET_API_MAC_CARBON
8945 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8946 return NULL;
8947 scriptcode = GetTextEncodingBase (encoding);
8948 #else
8949 scriptcode = FontToScript (fontnum);
8950 #endif
8951 }
8952
8953 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
8954
8955 font->mac_fontnum = fontnum;
8956 font->mac_fontsize = size;
8957 font->mac_fontface = fontface;
8958 font->mac_scriptcode = scriptcode;
8959 #if USE_ATSUI
8960 font->mac_style = mac_style;
8961 #if USE_CG_TEXT_DRAWING
8962 font->cg_font = NULL;
8963 font->cg_glyphs = NULL;
8964 #endif
8965 #endif
8966
8967 /* Apple Japanese (SJIS) font is listed as both
8968 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
8969 (Roman script) in init_font_name_table (). The latter should be
8970 treated as a one-byte font. */
8971 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8972 font->mac_scriptcode = smRoman;
8973
8974 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
8975
8976 #if USE_ATSUI
8977 if (font->mac_style)
8978 {
8979 OSStatus err;
8980 UniChar c;
8981
8982 font->min_byte1 = 0;
8983 font->max_byte1 = 0xff;
8984 font->min_char_or_byte2 = 0;
8985 font->max_char_or_byte2 = 0xff;
8986
8987 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8988 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8989 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8990 pcm_init (font->bounds.rows[0], 0x100);
8991
8992 #if USE_CG_TEXT_DRAWING
8993 if (fontnum != -1)
8994 {
8995 FMFontStyle style;
8996 ATSFontRef ats_font;
8997
8998 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
8999 &font_id, &style);
9000 /* Use CG text drawing if italic/bold is not synthesized. */
9001 if (err == noErr && style == fontface)
9002 {
9003 ats_font = FMGetATSFontRefFromFont (font_id);
9004 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
9005 }
9006 }
9007
9008 if (font->cg_font)
9009 {
9010 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
9011 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
9012 }
9013 #endif
9014 space_bounds = font->bounds.rows[0] + 0x20;
9015 err = mac_query_char_extents (font->mac_style, 0x20,
9016 &font->ascent, &font->descent,
9017 space_bounds,
9018 #if USE_CG_TEXT_DRAWING
9019 (font->cg_glyphs ? font->cg_glyphs + 0x20
9020 : NULL)
9021 #else
9022 NULL
9023 #endif
9024 );
9025 if (err != noErr
9026 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
9027 {
9028 mac_unload_font (&one_mac_display_info, font);
9029 return NULL;
9030 }
9031
9032 pcm = font->bounds.rows[0];
9033 for (c = 0x21; c <= 0xff; c++)
9034 {
9035 if (c == 0xad)
9036 /* Soft hyphen is not supported in ATSUI. */
9037 continue;
9038 else if (c == 0x7f)
9039 {
9040 #if USE_CG_TEXT_DRAWING
9041 if (font->cg_glyphs)
9042 {
9043 c = 0x9f;
9044 pcm = NULL;
9045 continue;
9046 }
9047 #endif
9048 break;
9049 }
9050
9051 mac_query_char_extents (font->mac_style, c, NULL, NULL,
9052 pcm ? pcm + c : NULL,
9053 #if USE_CG_TEXT_DRAWING
9054 (font->cg_glyphs ? font->cg_glyphs + c
9055 : NULL)
9056 #else
9057 NULL
9058 #endif
9059 );
9060
9061 #if USE_CG_TEXT_DRAWING
9062 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
9063 {
9064 /* Don't use CG text drawing if font substitution occurs in
9065 ASCII or Latin-1 characters. */
9066 CGFontRelease (font->cg_font);
9067 font->cg_font = NULL;
9068 xfree (font->cg_glyphs);
9069 font->cg_glyphs = NULL;
9070 if (pcm == NULL)
9071 break;
9072 }
9073 #endif
9074 }
9075 }
9076 else
9077 #endif
9078 {
9079 OSStatus err;
9080 FontInfo the_fontinfo;
9081 int is_two_byte_font;
9082
9083 #if USE_CG_DRAWING
9084 mac_prepare_for_quickdraw (f);
9085 #endif
9086 SetPortWindowPort (FRAME_MAC_WINDOW (f));
9087
9088 TextFont (fontnum);
9089 TextSize (size);
9090 TextFace (fontface);
9091
9092 GetFontInfo (&the_fontinfo);
9093
9094 font->ascent = the_fontinfo.ascent;
9095 font->descent = the_fontinfo.descent;
9096
9097 is_two_byte_font = (font->mac_scriptcode == smJapanese
9098 || font->mac_scriptcode == smTradChinese
9099 || font->mac_scriptcode == smSimpChinese
9100 || font->mac_scriptcode == smKorean);
9101
9102 if (is_two_byte_font)
9103 {
9104 int char_width;
9105
9106 font->min_byte1 = 0xa1;
9107 font->max_byte1 = 0xfe;
9108 font->min_char_or_byte2 = 0xa1;
9109 font->max_char_or_byte2 = 0xfe;
9110
9111 /* Use the width of an "ideographic space" of that font
9112 because the_fontinfo.widMax returns the wrong width for
9113 some fonts. */
9114 switch (font->mac_scriptcode)
9115 {
9116 case smJapanese:
9117 font->min_byte1 = 0x81;
9118 font->max_byte1 = 0xfc;
9119 font->min_char_or_byte2 = 0x40;
9120 font->max_char_or_byte2 = 0xfc;
9121 char_width = StringWidth("\p\x81\x40");
9122 break;
9123 case smTradChinese:
9124 font->min_char_or_byte2 = 0x40;
9125 char_width = StringWidth("\p\xa1\x40");
9126 break;
9127 case smSimpChinese:
9128 char_width = StringWidth("\p\xa1\xa1");
9129 break;
9130 case smKorean:
9131 char_width = StringWidth("\p\xa1\xa1");
9132 break;
9133 }
9134
9135 font->bounds.per_char = NULL;
9136
9137 if (fontface & italic)
9138 font->max_bounds.rbearing = char_width + 1;
9139 else
9140 font->max_bounds.rbearing = char_width;
9141 font->max_bounds.lbearing = 0;
9142 font->max_bounds.width = char_width;
9143 font->max_bounds.ascent = the_fontinfo.ascent;
9144 font->max_bounds.descent = the_fontinfo.descent;
9145
9146 font->min_bounds = font->max_bounds;
9147 }
9148 else
9149 {
9150 int c;
9151
9152 font->min_byte1 = font->max_byte1 = 0;
9153 font->min_char_or_byte2 = 0x20;
9154 font->max_char_or_byte2 = 0xff;
9155
9156 font->bounds.per_char =
9157 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
9158 bzero (font->bounds.per_char,
9159 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9160
9161 space_bounds = font->bounds.per_char;
9162 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9163 &font->descent, space_bounds, NULL);
9164 if (err != noErr || space_bounds->width <= 0)
9165 {
9166 mac_unload_font (&one_mac_display_info, font);
9167 return NULL;
9168 }
9169
9170 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9171 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
9172 }
9173 }
9174
9175 if (space_bounds)
9176 {
9177 int c;
9178
9179 font->min_bounds = font->max_bounds = *space_bounds;
9180 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9181 if (pcm->width > 0)
9182 {
9183 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9184 pcm->lbearing);
9185 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9186 pcm->rbearing);
9187 font->min_bounds.width = min (font->min_bounds.width,
9188 pcm->width);
9189 font->min_bounds.ascent = min (font->min_bounds.ascent,
9190 pcm->ascent);
9191 font->min_bounds.descent = min (font->min_bounds.descent,
9192 pcm->descent);
9193
9194 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9195 pcm->lbearing);
9196 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9197 pcm->rbearing);
9198 font->max_bounds.width = max (font->max_bounds.width,
9199 pcm->width);
9200 font->max_bounds.ascent = max (font->max_bounds.ascent,
9201 pcm->ascent);
9202 font->max_bounds.descent = max (font->max_bounds.descent,
9203 pcm->descent);
9204 }
9205 if (
9206 #if USE_ATSUI
9207 font->mac_style == NULL &&
9208 #endif
9209 font->max_bounds.width == font->min_bounds.width
9210 && font->min_bounds.lbearing >= 0
9211 && font->max_bounds.rbearing <= font->max_bounds.width)
9212 {
9213 /* Fixed width and no overhangs. */
9214 xfree (font->bounds.per_char);
9215 font->bounds.per_char = NULL;
9216 }
9217 }
9218
9219 #if !defined (MAC_OS8) || USE_ATSUI
9220 /* AppKit and WebKit do some adjustment to the heights of Courier,
9221 Helvetica, and Times. This only works on the environments where
9222 srcCopy text transfer mode is never used. */
9223 if (
9224 #ifdef MAC_OS8 /* implies USE_ATSUI */
9225 font->mac_style &&
9226 #endif
9227 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9228 || strcmp (family, "times") == 0))
9229 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9230 #endif
9231
9232 return font;
9233 }
9234
9235
9236 void
9237 mac_unload_font (dpyinfo, font)
9238 struct mac_display_info *dpyinfo;
9239 XFontStruct *font;
9240 {
9241 xfree (font->full_name);
9242 #if USE_ATSUI
9243 if (font->mac_style)
9244 {
9245 int i;
9246
9247 for (i = font->min_byte1; i <= font->max_byte1; i++)
9248 if (font->bounds.rows[i])
9249 xfree (font->bounds.rows[i]);
9250 xfree (font->bounds.rows);
9251 ATSUDisposeStyle (font->mac_style);
9252 }
9253 else
9254 #endif
9255 if (font->bounds.per_char)
9256 xfree (font->bounds.per_char);
9257 #if USE_CG_TEXT_DRAWING
9258 if (font->cg_font)
9259 CGFontRelease (font->cg_font);
9260 if (font->cg_glyphs)
9261 xfree (font->cg_glyphs);
9262 #endif
9263 xfree (font);
9264 }
9265
9266
9267 /* Load font named FONTNAME of the size SIZE for frame F, and return a
9268 pointer to the structure font_info while allocating it dynamically.
9269 If SIZE is 0, load any size of font.
9270 If loading is failed, return NULL. */
9271
9272 struct font_info *
9273 x_load_font (f, fontname, size)
9274 struct frame *f;
9275 register char *fontname;
9276 int size;
9277 {
9278 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9279 Lisp_Object font_names;
9280
9281 /* Get a list of all the fonts that match this name. Once we
9282 have a list of matching fonts, we compare them against the fonts
9283 we already have by comparing names. */
9284 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9285
9286 if (!NILP (font_names))
9287 {
9288 Lisp_Object tail;
9289 int i;
9290
9291 for (i = 0; i < dpyinfo->n_fonts; i++)
9292 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9293 if (dpyinfo->font_table[i].name
9294 && (!strcmp (dpyinfo->font_table[i].name,
9295 SDATA (XCAR (tail)))
9296 || !strcmp (dpyinfo->font_table[i].full_name,
9297 SDATA (XCAR (tail)))))
9298 return (dpyinfo->font_table + i);
9299 }
9300 else
9301 return NULL;
9302
9303 /* Load the font and add it to the table. */
9304 {
9305 struct MacFontStruct *font;
9306 struct font_info *fontp;
9307 int i;
9308
9309 fontname = (char *) SDATA (XCAR (font_names));
9310
9311 BLOCK_INPUT;
9312 font = mac_load_query_font (f, fontname);
9313 UNBLOCK_INPUT;
9314 if (!font)
9315 return NULL;
9316
9317 /* Find a free slot in the font table. */
9318 for (i = 0; i < dpyinfo->n_fonts; ++i)
9319 if (dpyinfo->font_table[i].name == NULL)
9320 break;
9321
9322 /* If no free slot found, maybe enlarge the font table. */
9323 if (i == dpyinfo->n_fonts
9324 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9325 {
9326 int sz;
9327 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9328 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9329 dpyinfo->font_table
9330 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9331 }
9332
9333 fontp = dpyinfo->font_table + i;
9334 if (i == dpyinfo->n_fonts)
9335 ++dpyinfo->n_fonts;
9336
9337 /* Now fill in the slots of *FONTP. */
9338 BLOCK_INPUT;
9339 bzero (fontp, sizeof (*fontp));
9340 fontp->font = font;
9341 fontp->font_idx = i;
9342 fontp->charset = -1; /* fs_load_font sets it. */
9343 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9344 bcopy (fontname, fontp->name, strlen (fontname) + 1);
9345
9346 if (font->min_bounds.width == font->max_bounds.width)
9347 {
9348 /* Fixed width font. */
9349 fontp->average_width = fontp->space_width = font->min_bounds.width;
9350 }
9351 else
9352 {
9353 XChar2b char2b;
9354 XCharStruct *pcm;
9355
9356 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9357 pcm = mac_per_char_metric (font, &char2b, 0);
9358 if (pcm)
9359 fontp->space_width = pcm->width;
9360 else
9361 fontp->space_width = FONT_WIDTH (font);
9362
9363 if (pcm)
9364 {
9365 int width = pcm->width;
9366 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9367 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9368 width += pcm->width;
9369 fontp->average_width = width / 95;
9370 }
9371 else
9372 fontp->average_width = FONT_WIDTH (font);
9373 }
9374
9375 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9376 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
9377
9378 fontp->size = font->max_bounds.width;
9379 fontp->height = FONT_HEIGHT (font);
9380 {
9381 /* For some font, ascent and descent in max_bounds field is
9382 larger than the above value. */
9383 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9384 if (max_height > fontp->height)
9385 fontp->height = max_height;
9386 }
9387
9388 /* MAC_TODO: The script encoding is irrelevant in unicode? */
9389 /* The slot `encoding' specifies how to map a character
9390 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9391 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9392 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9393 2:0xA020..0xFF7F). For the moment, we don't know which charset
9394 uses this font. So, we set information in fontp->encoding_type
9395 which is never used by any charset. If mapping can't be
9396 decided, set FONT_ENCODING_NOT_DECIDED. */
9397 if (font->mac_scriptcode == smJapanese)
9398 fontp->encoding_type = 4;
9399 else
9400 {
9401 fontp->encoding_type
9402 = (font->max_byte1 == 0
9403 /* 1-byte font */
9404 ? (font->min_char_or_byte2 < 0x80
9405 ? (font->max_char_or_byte2 < 0x80
9406 ? 0 /* 0x20..0x7F */
9407 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9408 : 1) /* 0xA0..0xFF */
9409 /* 2-byte font */
9410 : (font->min_byte1 < 0x80
9411 ? (font->max_byte1 < 0x80
9412 ? (font->min_char_or_byte2 < 0x80
9413 ? (font->max_char_or_byte2 < 0x80
9414 ? 0 /* 0x2020..0x7F7F */
9415 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9416 : 3) /* 0x20A0..0x7FFF */
9417 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9418 : (font->min_char_or_byte2 < 0x80
9419 ? (font->max_char_or_byte2 < 0x80
9420 ? 2 /* 0xA020..0xFF7F */
9421 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9422 : 1))); /* 0xA0A0..0xFFFF */
9423 }
9424
9425 #if 0 /* MAC_TODO: fill these out with more reasonably values */
9426 fontp->baseline_offset
9427 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9428 ? (long) value : 0);
9429 fontp->relative_compose
9430 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9431 ? (long) value : 0);
9432 fontp->default_ascent
9433 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9434 ? (long) value : 0);
9435 #else
9436 fontp->baseline_offset = 0;
9437 fontp->relative_compose = 0;
9438 fontp->default_ascent = 0;
9439 #endif
9440
9441 /* Set global flag fonts_changed_p to non-zero if the font loaded
9442 has a character with a smaller width than any other character
9443 before, or if the font loaded has a smaller height than any
9444 other font loaded before. If this happens, it will make a
9445 glyph matrix reallocation necessary. */
9446 fonts_changed_p |= x_compute_min_glyph_bounds (f);
9447 UNBLOCK_INPUT;
9448 return fontp;
9449 }
9450 }
9451
9452
9453 /* Return a pointer to struct font_info of a font named FONTNAME for
9454 frame F. If no such font is loaded, return NULL. */
9455
9456 struct font_info *
9457 x_query_font (f, fontname)
9458 struct frame *f;
9459 register char *fontname;
9460 {
9461 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9462 int i;
9463
9464 for (i = 0; i < dpyinfo->n_fonts; i++)
9465 if (dpyinfo->font_table[i].name
9466 && (!xstricmp (dpyinfo->font_table[i].name, fontname)
9467 || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
9468 return (dpyinfo->font_table + i);
9469 return NULL;
9470 }
9471
9472
9473 /* Find a CCL program for a font specified by FONTP, and set the member
9474 `encoder' of the structure. */
9475
9476 void
9477 x_find_ccl_program (fontp)
9478 struct font_info *fontp;
9479 {
9480 Lisp_Object list, elt;
9481
9482 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9483 {
9484 elt = XCAR (list);
9485 if (CONSP (elt)
9486 && STRINGP (XCAR (elt))
9487 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9488 >= 0))
9489 break;
9490 }
9491 if (! NILP (list))
9492 {
9493 struct ccl_program *ccl
9494 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9495
9496 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9497 xfree (ccl);
9498 else
9499 fontp->font_encoder = ccl;
9500 }
9501 }
9502
9503 #if USE_MAC_FONT_PANEL
9504 /* Whether Font Panel has been shown before. The first call to font
9505 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9506 slow. This variable is used for deferring such a call as much as
9507 possible. */
9508 static int font_panel_shown_p = 0;
9509
9510 extern Lisp_Object Qfont;
9511 static Lisp_Object Qpanel_closed, Qselection;
9512
9513 static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9514 Lisp_Object,
9515 Lisp_Object,
9516 EventRef, UInt32,
9517 const EventParamName *,
9518 const EventParamType *));
9519
9520 int
9521 mac_font_panel_visible_p ()
9522 {
9523 return font_panel_shown_p && FPIsFontPanelVisible ();
9524 }
9525
9526 static pascal OSStatus
9527 mac_handle_font_event (next_handler, event, data)
9528 EventHandlerCallRef next_handler;
9529 EventRef event;
9530 void *data;
9531 {
9532 OSStatus result, err;
9533 Lisp_Object id_key;
9534 int num_params;
9535 const EventParamName *names;
9536 const EventParamType *types;
9537 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9538 kEventParamATSUFontSize,
9539 kEventParamFMFontFamily,
9540 kEventParamFMFontStyle,
9541 kEventParamFMFontSize,
9542 kEventParamFontColor};
9543 static const EventParamType types_sel[] = {typeATSUFontID,
9544 typeATSUSize,
9545 typeFMFontFamily,
9546 typeFMFontStyle,
9547 typeFMFontSize,
9548 typeFontColor};
9549
9550 result = CallNextEventHandler (next_handler, event);
9551 if (result != eventNotHandledErr)
9552 return result;
9553
9554 switch (GetEventKind (event))
9555 {
9556 case kEventFontPanelClosed:
9557 id_key = Qpanel_closed;
9558 num_params = 0;
9559 names = NULL;
9560 types = NULL;
9561 break;
9562
9563 case kEventFontSelection:
9564 id_key = Qselection;
9565 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9566 names = names_sel;
9567 types = types_sel;
9568 break;
9569 }
9570
9571 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9572 event, num_params,
9573 names, types);
9574 if (err == noErr)
9575 result = noErr;
9576
9577 return result;
9578 }
9579
9580 OSStatus
9581 mac_show_hide_font_panel ()
9582 {
9583 if (!font_panel_shown_p)
9584 {
9585 OSStatus err;
9586
9587 static const EventTypeSpec specs[] =
9588 {{kEventClassFont, kEventFontPanelClosed},
9589 {kEventClassFont, kEventFontSelection}};
9590
9591 err = InstallApplicationEventHandler (mac_handle_font_event,
9592 GetEventTypeCount (specs),
9593 specs, NULL, NULL);
9594 if (err != noErr)
9595 return err;
9596
9597 font_panel_shown_p = 1;
9598 }
9599
9600 return FPShowHideFontPanel ();
9601 }
9602
9603 OSStatus
9604 mac_set_font_info_for_selection (f, face_id, c)
9605 struct frame *f;
9606 int face_id, c;
9607 {
9608 OSStatus err;
9609 EventTargetRef target = NULL;
9610 XFontStruct *font = NULL;
9611
9612 if (!mac_font_panel_visible_p ())
9613 return noErr;
9614
9615 if (f)
9616 {
9617 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
9618
9619 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9620 {
9621 struct face *face;
9622
9623 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9624 face = FACE_FROM_ID (f, face_id);
9625 font = face->font;
9626 }
9627 }
9628
9629 if (font == NULL)
9630 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9631 else
9632 {
9633 if (font->mac_fontnum != -1)
9634 {
9635 FontSelectionQDStyle qd_style;
9636
9637 qd_style.version = kFontSelectionQDStyleVersionZero;
9638 qd_style.instance.fontFamily = font->mac_fontnum;
9639 qd_style.instance.fontStyle = font->mac_fontface;
9640 qd_style.size = font->mac_fontsize;
9641 qd_style.hasColor = false;
9642
9643 err = SetFontInfoForSelection (kFontSelectionQDType,
9644 1, &qd_style, target);
9645 }
9646 else
9647 err = SetFontInfoForSelection (kFontSelectionATSUIType,
9648 1, &font->mac_style, target);
9649 }
9650
9651 return err;
9652 }
9653 #endif
9654
9655 \f
9656 /* The Mac Event loop code */
9657
9658 #if !TARGET_API_MAC_CARBON
9659 #include <Events.h>
9660 #include <Quickdraw.h>
9661 #include <Balloons.h>
9662 #include <Devices.h>
9663 #include <Fonts.h>
9664 #include <Gestalt.h>
9665 #include <Menus.h>
9666 #include <Processes.h>
9667 #include <Sound.h>
9668 #include <ToolUtils.h>
9669 #include <TextUtils.h>
9670 #include <Dialogs.h>
9671 #include <Script.h>
9672 #include <Types.h>
9673 #include <Resources.h>
9674
9675 #if __MWERKS__
9676 #include <unix.h>
9677 #endif
9678 #endif /* ! TARGET_API_MAC_CARBON */
9679
9680 #define M_APPLE 234
9681 #define I_ABOUT 1
9682
9683 #define DEFAULT_NUM_COLS 80
9684
9685 #define MIN_DOC_SIZE 64
9686 #define MAX_DOC_SIZE 32767
9687
9688 #define EXTRA_STACK_ALLOC (256 * 1024)
9689
9690 #define ARGV_STRING_LIST_ID 129
9691 #define ABOUT_ALERT_ID 128
9692 #define RAM_TOO_LARGE_ALERT_ID 129
9693
9694 /* Contains the string "reverse", which is a constant for mouse button emu.*/
9695 Lisp_Object Qreverse;
9696
9697
9698 /* Modifier associated with the control key, or nil to ignore. */
9699 Lisp_Object Vmac_control_modifier;
9700
9701 /* Modifier associated with the option key, or nil to ignore. */
9702 Lisp_Object Vmac_option_modifier;
9703
9704 /* Modifier associated with the command key, or nil to ignore. */
9705 Lisp_Object Vmac_command_modifier;
9706
9707 /* Modifier associated with the function key, or nil to ignore. */
9708 Lisp_Object Vmac_function_modifier;
9709
9710 /* True if the option and command modifiers should be used to emulate
9711 a three button mouse */
9712 Lisp_Object Vmac_emulate_three_button_mouse;
9713
9714 #if TARGET_API_MAC_CARBON
9715 /* Non-zero if the mouse wheel button (i.e. button 4) should map to
9716 mouse-2, instead of mouse-3. */
9717 int mac_wheel_button_is_mouse_2;
9718
9719 /* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
9720 for processing before Emacs sees it. */
9721 int mac_pass_command_to_system;
9722
9723 /* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
9724 for processing before Emacs sees it. */
9725 int mac_pass_control_to_system;
9726 #endif
9727
9728 /* Points to the variable `inev' in the function XTread_socket. It is
9729 used for passing an input event to the function back from
9730 Carbon/Apple event handlers. */
9731 static struct input_event *read_socket_inev = NULL;
9732
9733 /* Whether or not the screen configuration has changed. */
9734 static int mac_screen_config_changed = 0;
9735
9736 Point saved_menu_event_location;
9737
9738 /* Apple Events */
9739 #if TARGET_API_MAC_CARBON
9740 static Lisp_Object Qhi_command;
9741 #ifdef MAC_OSX
9742 extern Lisp_Object Qwindow;
9743 static Lisp_Object Qtoolbar_switch_mode;
9744 #endif
9745 #if USE_MAC_TSM
9746 static TSMDocumentID tsm_document_id;
9747 Lisp_Object Qtext_input;
9748 Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
9749 Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
9750 extern Lisp_Object Qbefore_string;
9751 static Lisp_Object Vmac_ts_script_language_on_focus;
9752 static Lisp_Object saved_ts_script_language_on_focus;
9753 static ScriptLanguageRecord saved_ts_language;
9754 static Component saved_ts_component;
9755 #endif
9756 #endif /* TARGET_API_MAC_CARBON */
9757 extern int mac_ready_for_apple_events;
9758 extern Lisp_Object Qundefined;
9759 extern void init_apple_event_handler P_ ((void));
9760 extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9761 Lisp_Object *, Lisp_Object *,
9762 Lisp_Object *));
9763 extern OSErr init_coercion_handler P_ ((void));
9764
9765 /* Drag and Drop */
9766 extern OSErr install_drag_handler P_ ((WindowRef));
9767 extern void remove_drag_handler P_ ((WindowRef));
9768
9769 #if TARGET_API_MAC_CARBON
9770 /* Showing help echo string during menu tracking */
9771 extern OSStatus install_menu_target_item_handler P_ ((void));
9772
9773 #ifdef MAC_OSX
9774 extern OSStatus install_service_handler ();
9775 Lisp_Object Qservice, Qpaste, Qperform;
9776 Lisp_Object Qmouse_drag_overlay;
9777 #endif
9778 #endif
9779
9780 extern void init_emacs_passwd_dir ();
9781 extern int emacs_main (int, char **, char **);
9782
9783 extern void initialize_applescript();
9784 extern void terminate_applescript();
9785
9786 /* Table for translating Mac keycode to X keysym values. Contributed
9787 by Sudhir Shenoy.
9788 Mapping for special keys is now identical to that in Apple X11
9789 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9790 on the right of the Cmd key on laptops, and fn + `enter' (->
9791 <linefeed>). */
9792 static const unsigned char keycode_to_xkeysym_table[] = {
9793 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9794 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9795 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9796
9797 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9798 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9799 /*0x38*/ 0, 0, 0, 0,
9800 /*0x3C*/ 0, 0, 0, 0,
9801
9802 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9803 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9804 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9805 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9806
9807 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9808 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9809 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9810 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9811
9812 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9813 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9814 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9815 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9816
9817 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9818 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9819 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9820 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9821 };
9822
9823 #ifdef MAC_OSX
9824 /* Table for translating Mac keycode with the laptop `fn' key to that
9825 without it. Destination symbols in comments are keys on US
9826 keyboard, and they may not be the same on other types of keyboards.
9827 If the destination is identical to the source (f1 ... f12), it
9828 doesn't map `fn' key to a modifier. */
9829 static const unsigned char fn_keycode_to_keycode_table[] = {
9830 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9831 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9832 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9833
9834 /*0x30*/ 0, 0, 0, 0,
9835 /*0x34*/ 0, 0, 0, 0,
9836 /*0x38*/ 0, 0, 0, 0,
9837 /*0x3C*/ 0, 0, 0, 0,
9838
9839 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9840 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9841 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9842 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9843
9844 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9845 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9846 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9847 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9848
9849 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9850 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9851 /*0x68*/ 0, 0, 0, 0,
9852 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9853
9854 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9855 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9856 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9857 /*0x7C*/ 0, 0, 0, 0
9858 };
9859 #endif /* MAC_OSX */
9860
9861 static int
9862 #if TARGET_API_MAC_CARBON
9863 mac_to_emacs_modifiers (UInt32 mods)
9864 #else
9865 mac_to_emacs_modifiers (EventModifiers mods)
9866 #endif
9867 {
9868 unsigned int result = 0;
9869 if (mods & shiftKey)
9870 result |= shift_modifier;
9871
9872 /* Deactivated to simplify configuration:
9873 if Vmac_option_modifier is non-NIL, we fully process the Option
9874 key. Otherwise, we only process it if an additional Ctrl or Command
9875 is pressed. That way the system may convert the character to a
9876 composed one.
9877 if ((mods & optionKey) &&
9878 (( !NILP(Vmac_option_modifier) ||
9879 ((mods & cmdKey) || (mods & controlKey))))) */
9880
9881 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
9882 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9883 if (INTEGERP(val))
9884 result |= XUINT(val);
9885 }
9886 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9887 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9888 if (INTEGERP(val))
9889 result |= XUINT(val);
9890 }
9891 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9892 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9893 if (INTEGERP(val))
9894 result |= XUINT(val);
9895 }
9896
9897 #ifdef MAC_OSX
9898 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9899 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9900 if (INTEGERP(val))
9901 result |= XUINT(val);
9902 }
9903 #endif
9904
9905 return result;
9906 }
9907
9908 static UInt32
9909 mac_mapped_modifiers (modifiers)
9910 UInt32 modifiers;
9911 {
9912 UInt32 mapped_modifiers_all =
9913 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9914 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9915 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9916
9917 #ifdef MAC_OSX
9918 mapped_modifiers_all |=
9919 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9920 #endif
9921
9922 return mapped_modifiers_all & modifiers;
9923 }
9924
9925 static int
9926 mac_get_emulated_btn ( UInt32 modifiers )
9927 {
9928 int result = 0;
9929 if (!NILP (Vmac_emulate_three_button_mouse)) {
9930 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
9931 if (modifiers & cmdKey)
9932 result = cmdIs3 ? 2 : 1;
9933 else if (modifiers & optionKey)
9934 result = cmdIs3 ? 1 : 2;
9935 }
9936 return result;
9937 }
9938
9939 #ifdef MAC_OSX
9940 void
9941 mac_get_selected_range (w, range)
9942 struct window *w;
9943 CFRange *range;
9944 {
9945 Lisp_Object overlay = find_symbol_value (Qmouse_drag_overlay);
9946 struct buffer *b = XBUFFER (w->buffer);
9947 int begv = BUF_BEGV (b), zv = BUF_ZV (b);
9948 int start, end;
9949
9950 if (OVERLAYP (overlay)
9951 && EQ (Foverlay_buffer (overlay), w->buffer)
9952 && (start = XINT (Foverlay_start (overlay)),
9953 end = XINT (Foverlay_end (overlay)),
9954 start != end))
9955 ;
9956 else
9957 {
9958 if (w == XWINDOW (selected_window) && b == current_buffer)
9959 start = PT;
9960 else
9961 start = marker_position (w->pointm);
9962
9963 if (NILP (Vtransient_mark_mode) || NILP (b->mark_active))
9964 end = start;
9965 else
9966 {
9967 int mark_pos = marker_position (b->mark);
9968
9969 if (start <= mark_pos)
9970 end = mark_pos;
9971 else
9972 {
9973 end = start;
9974 start = mark_pos;
9975 }
9976 }
9977 }
9978
9979 if (start != end)
9980 {
9981 if (start < begv)
9982 start = begv;
9983 else if (start > zv)
9984 start = zv;
9985
9986 if (end < begv)
9987 end = begv;
9988 else if (end > zv)
9989 end = zv;
9990 }
9991
9992 range->location = start - begv;
9993 range->length = end - start;
9994 }
9995
9996 /* Store the text of the buffer BUF from START to END as Unicode
9997 characters in CHARACTERS. Return non-zero if successful. */
9998
9999 int
10000 mac_store_buffer_text_to_unicode_chars (buf, start, end, characters)
10001 struct buffer *buf;
10002 int start, end;
10003 UniChar *characters;
10004 {
10005 int start_byte, end_byte, char_count, byte_count;
10006 struct coding_system coding;
10007 unsigned char *dst = (unsigned char *) characters;
10008
10009 start_byte = buf_charpos_to_bytepos (buf, start);
10010 end_byte = buf_charpos_to_bytepos (buf, end);
10011 char_count = end - start;
10012 byte_count = end_byte - start_byte;
10013
10014 if (setup_coding_system (
10015 #ifdef WORDS_BIG_ENDIAN
10016 intern ("utf-16be")
10017 #else
10018 intern ("utf-16le")
10019 #endif
10020 , &coding) < 0)
10021 return 0;
10022
10023 coding.src_multibyte = !NILP (buf->enable_multibyte_characters);
10024 coding.dst_multibyte = 0;
10025 coding.mode |= CODING_MODE_LAST_BLOCK;
10026 coding.composing = COMPOSITION_DISABLED;
10027
10028 if (BUF_GPT_BYTE (buf) <= start_byte || end_byte <= BUF_GPT_BYTE (buf))
10029 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10030 byte_count, char_count * sizeof (UniChar));
10031 else
10032 {
10033 int first_byte_count = BUF_GPT_BYTE (buf) - start_byte;
10034
10035 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10036 first_byte_count, char_count * sizeof (UniChar));
10037 if (coding.result == CODING_FINISH_NORMAL)
10038 encode_coding (&coding,
10039 BUF_BYTE_ADDRESS (buf, start_byte + first_byte_count),
10040 dst + coding.produced,
10041 byte_count - first_byte_count,
10042 char_count * sizeof (UniChar) - coding.produced);
10043 }
10044
10045 if (coding.result != CODING_FINISH_NORMAL)
10046 return 0;
10047
10048 return 1;
10049 }
10050
10051 void
10052 mac_ax_selected_text_range (f, range)
10053 struct frame *f;
10054 CFRange *range;
10055 {
10056 mac_get_selected_range (XWINDOW (f->selected_window), range);
10057 }
10058
10059 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
10060 unsigned int
10061 mac_ax_number_of_characters (f)
10062 struct frame *f;
10063 {
10064 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
10065
10066 return BUF_ZV (b) - BUF_BEGV (b);
10067 }
10068 #endif
10069 #endif
10070
10071 #if USE_MAC_TSM
10072 OSStatus
10073 mac_restore_keyboard_input_source ()
10074 {
10075 OSStatus err = noErr;
10076 ScriptLanguageRecord slrec, *slptr = NULL;
10077
10078 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10079 && EQ (saved_ts_script_language_on_focus, Qt))
10080 slptr = &saved_ts_language;
10081 else if (CONSP (Vmac_ts_script_language_on_focus)
10082 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10083 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10084 && CONSP (saved_ts_script_language_on_focus)
10085 && EQ (XCAR (saved_ts_script_language_on_focus),
10086 XCAR (Vmac_ts_script_language_on_focus))
10087 && EQ (XCDR (saved_ts_script_language_on_focus),
10088 XCDR (Vmac_ts_script_language_on_focus)))
10089 {
10090 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10091 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10092 slptr = &slrec;
10093 }
10094
10095 if (slptr)
10096 {
10097 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10098 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10099 kKeyboardInputMethodClass);
10100 #else
10101 err = SetDefaultInputMethod (saved_ts_component, slptr);
10102 #endif
10103 if (err == noErr)
10104 err = SetTextServiceLanguage (slptr);
10105
10106 /* Seems to be needed on Mac OS X 10.2. */
10107 if (err == noErr)
10108 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10109 }
10110
10111 return err;
10112 }
10113
10114 void
10115 mac_save_keyboard_input_source ()
10116 {
10117 OSStatus err;
10118 ScriptLanguageRecord slrec, *slptr = NULL;
10119
10120 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10121
10122 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10123 {
10124 err = GetTextServiceLanguage (&saved_ts_language);
10125 if (err == noErr)
10126 slptr = &saved_ts_language;
10127 }
10128 else if (CONSP (Vmac_ts_script_language_on_focus)
10129 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10130 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10131 {
10132 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10133 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10134 slptr = &slrec;
10135 }
10136
10137 if (slptr)
10138 {
10139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10140 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10141 kKeyboardInputMethodClass);
10142 #else
10143 GetDefaultInputMethod (&saved_ts_component, slptr);
10144 #endif
10145 }
10146 }
10147 #endif
10148
10149 #if TARGET_API_MAC_CARBON
10150 /***** Code to handle C-g testing *****/
10151 extern int quit_char;
10152 extern int make_ctrl_char P_ ((int));
10153
10154 int
10155 mac_quit_char_key_p (modifiers, key_code)
10156 UInt32 modifiers, key_code;
10157 {
10158 UInt32 char_code;
10159 unsigned long some_state = 0;
10160 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10161 int c, emacs_modifiers;
10162
10163 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
10164 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
10165 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
10166 if (char_code & ~0xff)
10167 return 0;
10168
10169 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
10170 if (emacs_modifiers & ctrl_modifier)
10171 c = make_ctrl_char (char_code);
10172
10173 c |= (emacs_modifiers
10174 & (meta_modifier | alt_modifier
10175 | hyper_modifier | super_modifier));
10176
10177 return c == quit_char;
10178 }
10179 #endif
10180
10181 #if TARGET_API_MAC_CARBON
10182 /* Obtains the event modifiers from the event ref and then calls
10183 mac_to_emacs_modifiers. */
10184 static int
10185 mac_event_to_emacs_modifiers (EventRef eventRef)
10186 {
10187 UInt32 mods = 0, class;
10188
10189 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
10190 sizeof (UInt32), NULL, &mods);
10191 class = GetEventClass (eventRef);
10192 if (!NILP (Vmac_emulate_three_button_mouse) &&
10193 (class == kEventClassMouse || class == kEventClassCommand))
10194 {
10195 mods &= ~(optionKey | cmdKey);
10196 }
10197 return mac_to_emacs_modifiers (mods);
10198 }
10199
10200 /* Given an event ref, return the code to use for the mouse button
10201 code in the emacs input_event. */
10202 static int
10203 mac_get_mouse_btn (EventRef ref)
10204 {
10205 EventMouseButton result = kEventMouseButtonPrimary;
10206 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
10207 sizeof (EventMouseButton), NULL, &result);
10208 switch (result)
10209 {
10210 case kEventMouseButtonPrimary:
10211 if (NILP (Vmac_emulate_three_button_mouse))
10212 return 0;
10213 else {
10214 UInt32 mods = 0;
10215 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
10216 sizeof (UInt32), NULL, &mods);
10217 return mac_get_emulated_btn(mods);
10218 }
10219 case kEventMouseButtonSecondary:
10220 return mac_wheel_button_is_mouse_2 ? 2 : 1;
10221 case kEventMouseButtonTertiary:
10222 case 4: /* 4 is the number for the mouse wheel button */
10223 return mac_wheel_button_is_mouse_2 ? 1 : 2;
10224 default:
10225 return 0;
10226 }
10227 }
10228
10229 /* Normally, ConvertEventRefToEventRecord will correctly handle all
10230 events. However the click of the mouse wheel is not converted to a
10231 mouseDown or mouseUp event. Likewise for dead key events. This
10232 calls ConvertEventRefToEventRecord, but then checks to see if it is
10233 a mouse up/down, or a dead key Carbon event that has not been
10234 converted, and if so, converts it by hand (to be picked up in the
10235 XTread_socket loop). */
10236 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
10237 {
10238 OSStatus err;
10239 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
10240 EventKind action;
10241
10242 if (result)
10243 return result;
10244
10245 switch (GetEventClass (eventRef))
10246 {
10247 case kEventClassMouse:
10248 switch (GetEventKind (eventRef))
10249 {
10250 case kEventMouseDown:
10251 eventRec->what = mouseDown;
10252 result = 1;
10253 break;
10254
10255 case kEventMouseUp:
10256 eventRec->what = mouseUp;
10257 result = 1;
10258 break;
10259
10260 default:
10261 break;
10262 }
10263 break;
10264
10265 case kEventClassKeyboard:
10266 switch (GetEventKind (eventRef))
10267 {
10268 case kEventRawKeyDown:
10269 action = keyDown;
10270 goto keystroke_common;
10271 case kEventRawKeyRepeat:
10272 action = autoKey;
10273 goto keystroke_common;
10274 case kEventRawKeyUp:
10275 action = keyUp;
10276 keystroke_common:
10277 {
10278 unsigned char char_codes;
10279 UInt32 key_code;
10280
10281 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
10282 typeChar, NULL, sizeof (char),
10283 NULL, &char_codes);
10284 if (err == noErr)
10285 err = GetEventParameter (eventRef, kEventParamKeyCode,
10286 typeUInt32, NULL, sizeof (UInt32),
10287 NULL, &key_code);
10288 if (err == noErr)
10289 {
10290 eventRec->what = action;
10291 eventRec->message = char_codes | ((key_code & 0xff) << 8);
10292 result = 1;
10293 }
10294 }
10295 break;
10296
10297 default:
10298 break;
10299 }
10300 break;
10301
10302 default:
10303 break;
10304 }
10305
10306 if (result)
10307 {
10308 /* Need where and when. */
10309 UInt32 mods = 0;
10310
10311 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
10312 NULL, sizeof (Point), NULL, &eventRec->where);
10313 /* Use two step process because new event modifiers are 32-bit
10314 and old are 16-bit. Currently, only loss is NumLock & Fn. */
10315 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
10316 NULL, sizeof (UInt32), NULL, &mods);
10317 eventRec->modifiers = mods;
10318
10319 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
10320 }
10321
10322 return result;
10323 }
10324
10325 #endif
10326
10327 #ifdef MAC_OS8
10328 static void
10329 do_get_menus (void)
10330 {
10331 Handle menubar_handle;
10332 MenuRef menu;
10333
10334 menubar_handle = GetNewMBar (128);
10335 if(menubar_handle == NULL)
10336 abort ();
10337 SetMenuBar (menubar_handle);
10338 DrawMenuBar ();
10339
10340 #if !TARGET_API_MAC_CARBON
10341 menu = GetMenuRef (M_APPLE);
10342 if (menu != NULL)
10343 AppendResMenu (menu, 'DRVR');
10344 else
10345 abort ();
10346 #endif
10347 }
10348
10349
10350 static void
10351 do_init_managers (void)
10352 {
10353 #if !TARGET_API_MAC_CARBON
10354 InitGraf (&qd.thePort);
10355 InitFonts ();
10356 FlushEvents (everyEvent, 0);
10357 InitWindows ();
10358 InitMenus ();
10359 TEInit ();
10360 InitDialogs (NULL);
10361 #endif /* !TARGET_API_MAC_CARBON */
10362 InitCursor ();
10363
10364 #if !TARGET_API_MAC_CARBON
10365 /* set up some extra stack space for use by emacs */
10366 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10367
10368 /* MaxApplZone must be called for AppleScript to execute more
10369 complicated scripts */
10370 MaxApplZone ();
10371 MoreMasters ();
10372 #endif /* !TARGET_API_MAC_CARBON */
10373 }
10374
10375 static void
10376 do_check_ram_size (void)
10377 {
10378 SInt32 physical_ram_size, logical_ram_size;
10379
10380 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10381 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
10382 || physical_ram_size > (1 << VALBITS)
10383 || logical_ram_size > (1 << VALBITS))
10384 {
10385 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10386 exit (1);
10387 }
10388 }
10389 #endif /* MAC_OS8 */
10390
10391 static void
10392 do_window_update (WindowRef win)
10393 {
10394 struct frame *f = mac_window_to_frame (win);
10395
10396 BeginUpdate (win);
10397
10398 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10399 below. */
10400 if (win != tip_window)
10401 {
10402 if (f->async_visible == 0)
10403 {
10404 /* Update events may occur when a frame gets iconified. */
10405 #if 0
10406 f->async_visible = 1;
10407 f->async_iconified = 0;
10408 SET_FRAME_GARBAGED (f);
10409 #endif
10410 }
10411 else
10412 {
10413 Rect r;
10414 #if TARGET_API_MAC_CARBON
10415 RgnHandle region = NewRgn ();
10416
10417 GetPortVisibleRegion (GetWindowPort (win), region);
10418 GetRegionBounds (region, &r);
10419 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10420 #if USE_CG_DRAWING
10421 mac_prepare_for_quickdraw (f);
10422 #endif
10423 UpdateControls (win, region);
10424 DisposeRgn (region);
10425 #else
10426 r = (*win->visRgn)->rgnBBox;
10427 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
10428 UpdateControls (win, win->visRgn);
10429 #endif
10430 }
10431 }
10432
10433 EndUpdate (win);
10434 }
10435
10436 static int
10437 is_emacs_window (WindowRef win)
10438 {
10439 Lisp_Object tail, frame;
10440
10441 if (!win)
10442 return 0;
10443
10444 FOR_EACH_FRAME (tail, frame)
10445 if (FRAME_MAC_P (XFRAME (frame)))
10446 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10447 return 1;
10448
10449 return 0;
10450 }
10451
10452 #if USE_MAC_TSM
10453 static OSStatus
10454 mac_tsm_resume ()
10455 {
10456 OSStatus err;
10457 ScriptLanguageRecord slrec, *slptr = NULL;
10458
10459 err = ActivateTSMDocument (tsm_document_id);
10460
10461 if (err == noErr)
10462 {
10463 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10464 && EQ (saved_ts_script_language_on_focus, Qt))
10465 slptr = &saved_ts_language;
10466 else if (CONSP (Vmac_ts_script_language_on_focus)
10467 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10468 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10469 && CONSP (saved_ts_script_language_on_focus)
10470 && EQ (XCAR (saved_ts_script_language_on_focus),
10471 XCAR (Vmac_ts_script_language_on_focus))
10472 && EQ (XCDR (saved_ts_script_language_on_focus),
10473 XCDR (Vmac_ts_script_language_on_focus)))
10474 {
10475 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10476 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10477 slptr = &slrec;
10478 }
10479 }
10480
10481 if (slptr)
10482 {
10483 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10484 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10485 kKeyboardInputMethodClass);
10486 #else
10487 err = SetDefaultInputMethod (saved_ts_component, slptr);
10488 #endif
10489 if (err == noErr)
10490 err = SetTextServiceLanguage (slptr);
10491
10492 /* Seems to be needed on Mac OS X 10.2. */
10493 if (err == noErr)
10494 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10495 }
10496
10497 return err;
10498 }
10499
10500 static OSStatus
10501 mac_tsm_suspend ()
10502 {
10503 OSStatus err;
10504 ScriptLanguageRecord slrec, *slptr = NULL;
10505
10506 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10507
10508 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10509 {
10510 err = GetTextServiceLanguage (&saved_ts_language);
10511 if (err == noErr)
10512 slptr = &saved_ts_language;
10513 }
10514 else if (CONSP (Vmac_ts_script_language_on_focus)
10515 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10516 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10517 {
10518 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10519 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10520 slptr = &slrec;
10521 }
10522
10523 if (slptr)
10524 {
10525 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10526 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10527 kKeyboardInputMethodClass);
10528 #else
10529 GetDefaultInputMethod (&saved_ts_component, slptr);
10530 #endif
10531 }
10532
10533 err = DeactivateTSMDocument (tsm_document_id);
10534
10535 return err;
10536 }
10537 #endif
10538
10539 #if !TARGET_API_MAC_CARBON
10540 void
10541 do_apple_menu (SInt16 menu_item)
10542 {
10543 Str255 item_name;
10544 SInt16 da_driver_refnum;
10545
10546 if (menu_item == I_ABOUT)
10547 NoteAlert (ABOUT_ALERT_ID, NULL);
10548 else
10549 {
10550 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
10551 da_driver_refnum = OpenDeskAcc (item_name);
10552 }
10553 }
10554 #endif /* !TARGET_API_MAC_CARBON */
10555
10556 /* Handle drags in size box. Based on code contributed by Ben
10557 Mesander and IM - Window Manager A. */
10558
10559 static void
10560 do_grow_window (w, e)
10561 WindowRef w;
10562 const EventRecord *e;
10563 {
10564 Rect limit_rect;
10565 int rows, columns, width, height;
10566 struct frame *f = mac_window_to_frame (w);
10567 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10568 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10569 #if TARGET_API_MAC_CARBON
10570 Rect new_rect;
10571 #else
10572 long grow_size;
10573 #endif
10574
10575 if (size_hints->flags & PMinSize)
10576 {
10577 min_width = size_hints->min_width;
10578 min_height = size_hints->min_height;
10579 }
10580 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
10581
10582 #if TARGET_API_MAC_CARBON
10583 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10584 return;
10585 height = new_rect.bottom - new_rect.top;
10586 width = new_rect.right - new_rect.left;
10587 #else
10588 grow_size = GrowWindow (w, e->where, &limit_rect);
10589 /* see if it really changed size */
10590 if (grow_size == 0)
10591 return;
10592 height = HiWord (grow_size);
10593 width = LoWord (grow_size);
10594 #endif
10595
10596 if (width != FRAME_PIXEL_WIDTH (f)
10597 || height != FRAME_PIXEL_HEIGHT (f))
10598 {
10599 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10600 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10601
10602 x_set_window_size (f, 0, columns, rows);
10603 }
10604 }
10605
10606
10607 #if TARGET_API_MAC_CARBON
10608 static Point
10609 mac_get_ideal_size (f)
10610 struct frame *f;
10611 {
10612 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10613 WindowRef w = FRAME_MAC_WINDOW (f);
10614 Point ideal_size;
10615 Rect standard_rect;
10616 int height, width, columns, rows;
10617
10618 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10619 ideal_size.v = dpyinfo->height;
10620 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10621 /* Adjust the standard size according to character boundaries. */
10622 width = standard_rect.right - standard_rect.left;
10623 height = standard_rect.bottom - standard_rect.top;
10624 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10625 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10626 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10627 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10628
10629 return ideal_size;
10630 }
10631 #endif
10632
10633 /* Handle clicks in zoom box. Calculation of "standard state" based
10634 on code in IM - Window Manager A and code contributed by Ben
10635 Mesander. The standard state of an Emacs window is 80-characters
10636 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10637
10638 static void
10639 do_zoom_window (WindowRef w, int zoom_in_or_out)
10640 {
10641 Rect zoom_rect, port_rect;
10642 int width, height;
10643 struct frame *f = mac_window_to_frame (w);
10644 #if TARGET_API_MAC_CARBON
10645 Point ideal_size = mac_get_ideal_size (f);
10646
10647 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10648 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10649 && port_rect.left == zoom_rect.left
10650 && port_rect.top == zoom_rect.top)
10651 zoom_in_or_out = inZoomIn;
10652 else
10653 zoom_in_or_out = inZoomOut;
10654
10655 #ifdef MAC_OS8
10656 mac_clear_window (f);
10657 #endif
10658 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
10659 #else /* not TARGET_API_MAC_CARBON */
10660 GrafPtr save_port;
10661 Point top_left;
10662 int w_title_height, rows;
10663 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10664
10665 GetPort (&save_port);
10666
10667 SetPortWindowPort (w);
10668
10669 /* Clear window to avoid flicker. */
10670 EraseRect (&(w->portRect));
10671 if (zoom_in_or_out == inZoomOut)
10672 {
10673 SetPt (&top_left, w->portRect.left, w->portRect.top);
10674 LocalToGlobal (&top_left);
10675
10676 /* calculate height of window's title bar */
10677 w_title_height = top_left.v - 1
10678 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
10679
10680 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10681 zoom_rect = qd.screenBits.bounds;
10682 zoom_rect.top += w_title_height;
10683 InsetRect (&zoom_rect, 8, 4); /* not too tight */
10684
10685 zoom_rect.right = zoom_rect.left
10686 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10687
10688 /* Adjust the standard size according to character boundaries. */
10689 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10690 zoom_rect.bottom =
10691 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10692
10693 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10694 = zoom_rect;
10695 }
10696
10697 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
10698
10699 SetPort (save_port);
10700 #endif /* not TARGET_API_MAC_CARBON */
10701
10702 #if !TARGET_API_MAC_CARBON
10703 /* retrieve window size and update application values */
10704 port_rect = w->portRect;
10705 height = port_rect.bottom - port_rect.top;
10706 width = port_rect.right - port_rect.left;
10707
10708 mac_handle_size_change (f, width, height);
10709 mac_handle_origin_change (f);
10710 #endif
10711 }
10712
10713 static void
10714 mac_set_unicode_keystroke_event (code, buf)
10715 UniChar code;
10716 struct input_event *buf;
10717 {
10718 int charset_id, c1, c2;
10719
10720 if (code < 0x80)
10721 {
10722 buf->kind = ASCII_KEYSTROKE_EVENT;
10723 buf->code = code;
10724 }
10725 else if (code < 0x100)
10726 {
10727 if (code < 0xA0)
10728 charset_id = CHARSET_8_BIT_CONTROL;
10729 else
10730 charset_id = charset_latin_iso8859_1;
10731 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10732 buf->code = MAKE_CHAR (charset_id, code, 0);
10733 }
10734 else
10735 {
10736 if (code < 0x2500)
10737 charset_id = charset_mule_unicode_0100_24ff,
10738 code -= 0x100;
10739 else if (code < 0x33FF)
10740 charset_id = charset_mule_unicode_2500_33ff,
10741 code -= 0x2500;
10742 else if (code >= 0xE000)
10743 charset_id = charset_mule_unicode_e000_ffff,
10744 code -= 0xE000;
10745 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10746 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10747 buf->code = MAKE_CHAR (charset_id, c1, c2);
10748 }
10749 }
10750
10751 static void
10752 do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10753 EventKind action;
10754 unsigned char char_code;
10755 UInt32 key_code, modifiers;
10756 unsigned long timestamp;
10757 struct input_event *buf;
10758 {
10759 static SInt16 last_key_script = -1;
10760 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10761 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10762
10763 #ifdef MAC_OSX
10764 if (mapped_modifiers & kEventKeyModifierFnMask
10765 && key_code <= 0x7f
10766 && fn_keycode_to_keycode_table[key_code])
10767 key_code = fn_keycode_to_keycode_table[key_code];
10768 #endif
10769
10770 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10771 {
10772 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10773 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10774 #ifdef MAC_OSX
10775 if (modifiers & kEventKeyModifierFnMask
10776 && key_code <= 0x7f
10777 && fn_keycode_to_keycode_table[key_code] == key_code)
10778 modifiers &= ~kEventKeyModifierFnMask;
10779 #endif
10780 }
10781 else if (mapped_modifiers)
10782 {
10783 /* translate the keycode back to determine the original key */
10784 #ifdef MAC_OSX
10785 UCKeyboardLayout *uchr_ptr = NULL;
10786 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10787 OSStatus err;
10788 KeyboardLayoutRef layout;
10789
10790 err = KLGetCurrentKeyboardLayout (&layout);
10791 if (err == noErr)
10792 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10793 (const void **) &uchr_ptr);
10794 #else
10795 static SInt16 last_key_layout_id = 0;
10796 static Handle uchr_handle = (Handle)-1;
10797 SInt16 current_key_layout_id =
10798 GetScriptVariable (current_key_script, smScriptKeys);
10799
10800 if (uchr_handle == (Handle)-1
10801 || last_key_layout_id != current_key_layout_id)
10802 {
10803 uchr_handle = GetResource ('uchr', current_key_layout_id);
10804 last_key_layout_id = current_key_layout_id;
10805 }
10806 if (uchr_handle)
10807 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10808 #endif
10809
10810 if (uchr_ptr)
10811 {
10812 OSStatus status;
10813 UInt16 key_action = action - keyDown;
10814 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10815 UInt32 keyboard_type = LMGetKbdType ();
10816 SInt32 dead_key_state = 0;
10817 UniChar code;
10818 UniCharCount actual_length;
10819
10820 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10821 modifier_key_state, keyboard_type,
10822 kUCKeyTranslateNoDeadKeysMask,
10823 &dead_key_state,
10824 1, &actual_length, &code);
10825 if (status == noErr && actual_length == 1)
10826 mac_set_unicode_keystroke_event (code, buf);
10827 }
10828 #endif /* MAC_OSX */
10829
10830 if (buf->kind == NO_EVENT)
10831 {
10832 /* This code comes from Keyboard Resource, Appendix C of IM
10833 - Text. This is necessary since shift is ignored in KCHR
10834 table translation when option or command is pressed. It
10835 also does not translate correctly control-shift chars
10836 like C-% so mask off shift here also. */
10837 /* Mask off modifier keys that are mapped to some Emacs
10838 modifiers. */
10839 int new_modifiers = modifiers & ~mapped_modifiers;
10840 /* set high byte of keycode to modifier high byte*/
10841 int new_key_code = key_code | new_modifiers;
10842 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10843 unsigned long some_state = 0;
10844 UInt32 new_char_code;
10845
10846 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10847 if (new_char_code == 0)
10848 /* Seems like a dead key. Append up-stroke. */
10849 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10850 &some_state);
10851 if (new_char_code)
10852 {
10853 buf->kind = ASCII_KEYSTROKE_EVENT;
10854 buf->code = new_char_code & 0xff;
10855 }
10856 }
10857 }
10858
10859 if (buf->kind == NO_EVENT)
10860 {
10861 buf->kind = ASCII_KEYSTROKE_EVENT;
10862 buf->code = char_code;
10863 }
10864
10865 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10866 buf->modifiers |= (extra_keyboard_modifiers
10867 & (meta_modifier | alt_modifier
10868 | hyper_modifier | super_modifier));
10869
10870 #if TARGET_API_MAC_CARBON
10871 if (buf->kind == ASCII_KEYSTROKE_EVENT
10872 && buf->code >= 0x80 && buf->modifiers)
10873 {
10874 OSStatus err;
10875 TextEncoding encoding = kTextEncodingMacRoman;
10876 TextToUnicodeInfo ttu_info;
10877
10878 UpgradeScriptInfoToTextEncoding (current_key_script,
10879 kTextLanguageDontCare,
10880 kTextRegionDontCare,
10881 NULL, &encoding);
10882 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10883 if (err == noErr)
10884 {
10885 UniChar code;
10886 Str255 pstr;
10887 ByteCount unicode_len;
10888
10889 pstr[0] = 1;
10890 pstr[1] = buf->code;
10891 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10892 sizeof (UniChar),
10893 &unicode_len, &code);
10894 if (err == noErr && unicode_len == sizeof (UniChar))
10895 mac_set_unicode_keystroke_event (code, buf);
10896 DisposeTextToUnicodeInfo (&ttu_info);
10897 }
10898 }
10899 #endif
10900
10901 if (buf->kind == ASCII_KEYSTROKE_EVENT
10902 && buf->code >= 0x80
10903 && last_key_script != current_key_script)
10904 {
10905 struct input_event event;
10906
10907 EVENT_INIT (event);
10908 event.kind = LANGUAGE_CHANGE_EVENT;
10909 event.arg = Qnil;
10910 event.code = current_key_script;
10911 event.timestamp = timestamp;
10912 kbd_buffer_store_event (&event);
10913 last_key_script = current_key_script;
10914 }
10915 }
10916
10917 void
10918 mac_store_apple_event (class, id, desc)
10919 Lisp_Object class, id;
10920 const AEDesc *desc;
10921 {
10922 struct input_event buf;
10923
10924 EVENT_INIT (buf);
10925
10926 buf.kind = MAC_APPLE_EVENT;
10927 buf.x = class;
10928 buf.y = id;
10929 XSETFRAME (buf.frame_or_window,
10930 mac_focus_frame (&one_mac_display_info));
10931 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10932 is safe to use them during read_socket_hook. */
10933 buf.arg = mac_aedesc_to_lisp (desc);
10934 kbd_buffer_store_event (&buf);
10935 }
10936
10937 #if TARGET_API_MAC_CARBON
10938 static OSStatus
10939 mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10940 event, num_params, names, types)
10941 AEEventClass class;
10942 AEEventID id;
10943 Lisp_Object class_key, id_key;
10944 EventRef event;
10945 UInt32 num_params;
10946 const EventParamName *names;
10947 const EventParamType *types;
10948 {
10949 OSStatus err = eventNotHandledErr;
10950 Lisp_Object binding;
10951
10952 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10953 if (!NILP (binding) && !EQ (binding, Qundefined))
10954 {
10955 if (INTEGERP (binding))
10956 err = XINT (binding);
10957 else
10958 {
10959 AppleEvent apple_event;
10960 err = create_apple_event_from_event_ref (event, num_params,
10961 names, types,
10962 &apple_event);
10963 if (err == noErr)
10964 {
10965 mac_store_apple_event (class_key, id_key, &apple_event);
10966 AEDisposeDesc (&apple_event);
10967 mac_wakeup_from_rne ();
10968 }
10969 }
10970 }
10971
10972 return err;
10973 }
10974
10975 void
10976 mac_store_drag_event (window, mouse_pos, modifiers, desc)
10977 WindowRef window;
10978 Point mouse_pos;
10979 SInt16 modifiers;
10980 const AEDesc *desc;
10981 {
10982 struct input_event buf;
10983
10984 EVENT_INIT (buf);
10985
10986 buf.kind = DRAG_N_DROP_EVENT;
10987 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10988 buf.timestamp = TickCount () * (1000 / 60);
10989 XSETINT (buf.x, mouse_pos.h);
10990 XSETINT (buf.y, mouse_pos.v);
10991 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10992 buf.arg = mac_aedesc_to_lisp (desc);
10993 kbd_buffer_store_event (&buf);
10994 }
10995
10996 #ifdef MAC_OSX
10997 OSStatus
10998 mac_store_service_event (event)
10999 EventRef event;
11000 {
11001 OSStatus err;
11002 Lisp_Object id_key;
11003 int num_params;
11004 const EventParamName *names;
11005 const EventParamType *types;
11006 static const EventParamName names_pfm[] =
11007 {kEventParamServiceMessageName, kEventParamServiceUserData};
11008 static const EventParamType types_pfm[] =
11009 {typeCFStringRef, typeCFStringRef};
11010
11011 switch (GetEventKind (event))
11012 {
11013 case kEventServicePaste:
11014 id_key = Qpaste;
11015 num_params = 0;
11016 names = NULL;
11017 types = NULL;
11018 break;
11019
11020 case kEventServicePerform:
11021 id_key = Qperform;
11022 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
11023 names = names_pfm;
11024 types = types_pfm;
11025 break;
11026
11027 default:
11028 abort ();
11029 }
11030
11031 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
11032 event, num_params,
11033 names, types);
11034
11035 return err;
11036 }
11037 #endif /* MAC_OSX */
11038
11039 static pascal OSStatus
11040 mac_handle_window_event (next_handler, event, data)
11041 EventHandlerCallRef next_handler;
11042 EventRef event;
11043 void *data;
11044 {
11045 WindowRef wp;
11046 OSStatus err, result = eventNotHandledErr;
11047 struct frame *f;
11048 UInt32 attributes;
11049 XSizeHints *size_hints;
11050
11051 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
11052 NULL, sizeof (WindowRef), NULL, &wp);
11053 if (err != noErr)
11054 return eventNotHandledErr;
11055
11056 f = mac_window_to_frame (wp);
11057 switch (GetEventKind (event))
11058 {
11059 /* -- window refresh events -- */
11060
11061 case kEventWindowUpdate:
11062 result = CallNextEventHandler (next_handler, event);
11063 if (result != eventNotHandledErr)
11064 break;
11065
11066 do_window_update (wp);
11067 result = noErr;
11068 break;
11069
11070 /* -- window state change events -- */
11071
11072 case kEventWindowShowing:
11073 size_hints = FRAME_SIZE_HINTS (f);
11074 if (!(size_hints->flags & (USPosition | PPosition)))
11075 {
11076 struct frame *sf = SELECTED_FRAME ();
11077
11078 if (!(FRAME_MAC_P (sf) && sf->async_visible))
11079 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
11080 else
11081 {
11082 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
11083 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
11084 kWindowCascadeStartAtParentWindowScreen
11085 #else
11086 kWindowCascadeOnParentWindowScreen
11087 #endif
11088 );
11089 #if USE_MAC_TOOLBAR
11090 /* This is a workaround. RepositionWindow fails to put
11091 a window at the cascading position when its parent
11092 window has a Carbon HIToolbar. */
11093 if ((f->left_pos == sf->left_pos
11094 && f->top_pos == sf->top_pos)
11095 || (f->left_pos == sf->left_pos + 10 * 2
11096 && f->top_pos == sf->top_pos + 32 * 2))
11097 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
11098 #endif
11099 }
11100 result = noErr;
11101 }
11102 break;
11103
11104 case kEventWindowHiding:
11105 /* Before unmapping the window, update the WM_SIZE_HINTS
11106 property to claim that the current position of the window is
11107 user-specified, rather than program-specified, so that when
11108 the window is mapped again, it will be placed at the same
11109 location, without forcing the user to position it by hand
11110 again (they have already done that once for this window.) */
11111 x_wm_set_size_hint (f, (long) 0, 1);
11112 result = noErr;
11113 break;
11114
11115 case kEventWindowShown:
11116 case kEventWindowHidden:
11117 case kEventWindowCollapsed:
11118 case kEventWindowExpanded:
11119 mac_handle_visibility_change (f);
11120 result = noErr;
11121 break;
11122
11123 case kEventWindowBoundsChanging:
11124 result = CallNextEventHandler (next_handler, event);
11125 if (result != eventNotHandledErr)
11126 break;
11127
11128 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11129 NULL, sizeof (UInt32), NULL, &attributes);
11130 if (err != noErr)
11131 break;
11132
11133 size_hints = FRAME_SIZE_HINTS (f);
11134 if ((attributes & kWindowBoundsChangeUserResize)
11135 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
11136 == (PResizeInc | PBaseSize | PMinSize)))
11137 {
11138 Rect bounds;
11139 int width, height;
11140
11141 err = GetEventParameter (event, kEventParamCurrentBounds,
11142 typeQDRectangle, NULL, sizeof (Rect),
11143 NULL, &bounds);
11144 if (err != noErr)
11145 break;
11146
11147 width = bounds.right - bounds.left;
11148 height = bounds.bottom - bounds.top;
11149
11150 if (width < size_hints->min_width)
11151 width = size_hints->min_width;
11152 else
11153 width = size_hints->base_width
11154 + (int) ((width - size_hints->base_width)
11155 / (float) size_hints->width_inc + .5)
11156 * size_hints->width_inc;
11157
11158 if (height < size_hints->min_height)
11159 height = size_hints->min_height;
11160 else
11161 height = size_hints->base_height
11162 + (int) ((height - size_hints->base_height)
11163 / (float) size_hints->height_inc + .5)
11164 * size_hints->height_inc;
11165
11166 bounds.right = bounds.left + width;
11167 bounds.bottom = bounds.top + height;
11168 SetEventParameter (event, kEventParamCurrentBounds,
11169 typeQDRectangle, sizeof (Rect), &bounds);
11170 result = noErr;
11171 }
11172 break;
11173
11174 case kEventWindowBoundsChanged:
11175 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11176 NULL, sizeof (UInt32), NULL, &attributes);
11177 if (err != noErr)
11178 break;
11179
11180 if (attributes & kWindowBoundsChangeSizeChanged)
11181 {
11182 Rect bounds;
11183
11184 err = GetEventParameter (event, kEventParamCurrentBounds,
11185 typeQDRectangle, NULL, sizeof (Rect),
11186 NULL, &bounds);
11187 if (err == noErr)
11188 {
11189 int width, height;
11190
11191 width = bounds.right - bounds.left;
11192 height = bounds.bottom - bounds.top;
11193 mac_handle_size_change (f, width, height);
11194 mac_wakeup_from_rne ();
11195 }
11196 }
11197
11198 if (attributes & kWindowBoundsChangeOriginChanged)
11199 mac_handle_origin_change (f);
11200
11201 result = noErr;
11202 break;
11203
11204 /* -- window action events -- */
11205
11206 case kEventWindowClose:
11207 {
11208 struct input_event buf;
11209
11210 EVENT_INIT (buf);
11211 buf.kind = DELETE_WINDOW_EVENT;
11212 XSETFRAME (buf.frame_or_window, f);
11213 buf.arg = Qnil;
11214 kbd_buffer_store_event (&buf);
11215 }
11216 result = noErr;
11217 break;
11218
11219 case kEventWindowGetIdealSize:
11220 result = CallNextEventHandler (next_handler, event);
11221 if (result != eventNotHandledErr)
11222 break;
11223
11224 {
11225 Point ideal_size = mac_get_ideal_size (f);
11226
11227 err = SetEventParameter (event, kEventParamDimensions,
11228 typeQDPoint, sizeof (Point), &ideal_size);
11229 if (err == noErr)
11230 result = noErr;
11231 }
11232 break;
11233
11234 #ifdef MAC_OSX
11235 case kEventWindowToolbarSwitchMode:
11236 {
11237 static const EventParamName names[] = {kEventParamDirectObject,
11238 kEventParamWindowMouseLocation,
11239 kEventParamKeyModifiers,
11240 kEventParamMouseButton,
11241 kEventParamClickCount,
11242 kEventParamMouseChord};
11243 static const EventParamType types[] = {typeWindowRef,
11244 typeQDPoint,
11245 typeUInt32,
11246 typeMouseButton,
11247 typeUInt32,
11248 typeUInt32};
11249 int num_params = sizeof (names) / sizeof (names[0]);
11250
11251 err = mac_store_event_ref_as_apple_event (0, 0,
11252 Qwindow,
11253 Qtoolbar_switch_mode,
11254 event, num_params,
11255 names, types);
11256 }
11257 if (err == noErr)
11258 result = noErr;
11259 break;
11260 #endif
11261
11262 #if USE_MAC_TSM
11263 /* -- window focus events -- */
11264
11265 case kEventWindowFocusAcquired:
11266 err = mac_tsm_resume ();
11267 if (err == noErr)
11268 result = noErr;
11269 break;
11270
11271 case kEventWindowFocusRelinquish:
11272 err = mac_tsm_suspend ();
11273 if (err == noErr)
11274 result = noErr;
11275 break;
11276 #endif
11277
11278 default:
11279 abort ();
11280 }
11281
11282 return result;
11283 }
11284
11285 static pascal OSStatus
11286 mac_handle_application_event (next_handler, event, data)
11287 EventHandlerCallRef next_handler;
11288 EventRef event;
11289 void *data;
11290 {
11291 OSStatus err, result = eventNotHandledErr;
11292
11293 switch (GetEventKind (event))
11294 {
11295 #if USE_MAC_TSM
11296 case kEventAppActivated:
11297 err = mac_tsm_resume ();
11298 break;
11299
11300 case kEventAppDeactivated:
11301 err = mac_tsm_suspend ();
11302 break;
11303 #endif
11304
11305 default:
11306 abort ();
11307 }
11308
11309 if (err == noErr)
11310 result = noErr;
11311
11312 return result;
11313 }
11314
11315 static pascal OSStatus
11316 mac_handle_keyboard_event (next_handler, event, data)
11317 EventHandlerCallRef next_handler;
11318 EventRef event;
11319 void *data;
11320 {
11321 OSStatus err, result = eventNotHandledErr;
11322 UInt32 event_kind, key_code, modifiers;
11323 unsigned char char_code;
11324
11325 event_kind = GetEventKind (event);
11326 switch (event_kind)
11327 {
11328 case kEventRawKeyDown:
11329 case kEventRawKeyRepeat:
11330 case kEventRawKeyUp:
11331 /* When using Carbon Events, we need to pass raw keyboard events
11332 to the TSM ourselves. If TSM handles it, it will pass back
11333 noErr, otherwise it will pass back "eventNotHandledErr" and
11334 we can process it normally. */
11335 result = CallNextEventHandler (next_handler, event);
11336 if (result != eventNotHandledErr)
11337 break;
11338
11339 if (read_socket_inev == NULL)
11340 break;
11341
11342 #if USE_MAC_TSM
11343 if (read_socket_inev->kind != NO_EVENT)
11344 {
11345 result = noErr;
11346 break;
11347 }
11348 #endif
11349
11350 if (event_kind == kEventRawKeyUp)
11351 break;
11352
11353 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11354 typeChar, NULL,
11355 sizeof (char), NULL, &char_code);
11356 if (err != noErr)
11357 break;
11358
11359 err = GetEventParameter (event, kEventParamKeyCode,
11360 typeUInt32, NULL,
11361 sizeof (UInt32), NULL, &key_code);
11362 if (err != noErr)
11363 break;
11364
11365 err = GetEventParameter (event, kEventParamKeyModifiers,
11366 typeUInt32, NULL,
11367 sizeof (UInt32), NULL, &modifiers);
11368 if (err != noErr)
11369 break;
11370
11371 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
11372 char_code, key_code, modifiers,
11373 ((unsigned long)
11374 (GetEventTime (event) / kEventDurationMillisecond)),
11375 read_socket_inev);
11376 result = noErr;
11377 break;
11378
11379 default:
11380 abort ();
11381 }
11382
11383 return result;
11384 }
11385
11386 static pascal OSStatus
11387 mac_handle_command_event (next_handler, event, data)
11388 EventHandlerCallRef next_handler;
11389 EventRef event;
11390 void *data;
11391 {
11392 OSStatus err, result = eventNotHandledErr;
11393 HICommand command;
11394 static const EventParamName names[] =
11395 {kEventParamDirectObject, kEventParamKeyModifiers};
11396 static const EventParamType types[] =
11397 {typeHICommand, typeUInt32};
11398 int num_params = sizeof (names) / sizeof (names[0]);
11399
11400 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11401 NULL, sizeof (HICommand), NULL, &command);
11402 if (err != noErr)
11403 return eventNotHandledErr;
11404
11405 switch (GetEventKind (event))
11406 {
11407 case kEventCommandProcess:
11408 result = CallNextEventHandler (next_handler, event);
11409 if (result != eventNotHandledErr)
11410 break;
11411
11412 err = GetEventParameter (event, kEventParamDirectObject,
11413 typeHICommand, NULL,
11414 sizeof (HICommand), NULL, &command);
11415
11416 if (err != noErr || command.commandID == 0)
11417 break;
11418
11419 /* A HI command event is mapped to an Apple event whose event
11420 class symbol is `hi-command' and event ID is its command
11421 ID. */
11422 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11423 Qhi_command, Qnil,
11424 event, num_params,
11425 names, types);
11426 if (err == noErr)
11427 result = noErr;
11428 break;
11429
11430 default:
11431 abort ();
11432 }
11433
11434 return result;
11435 }
11436
11437 static pascal OSStatus
11438 mac_handle_mouse_event (next_handler, event, data)
11439 EventHandlerCallRef next_handler;
11440 EventRef event;
11441 void *data;
11442 {
11443 OSStatus err, result = eventNotHandledErr;
11444
11445 switch (GetEventKind (event))
11446 {
11447 case kEventMouseWheelMoved:
11448 {
11449 WindowRef wp;
11450 struct frame *f;
11451 EventMouseWheelAxis axis;
11452 SInt32 delta;
11453 Point point;
11454
11455 result = CallNextEventHandler (next_handler, event);
11456 if (result != eventNotHandledErr || read_socket_inev == NULL)
11457 break;
11458
11459 f = mac_focus_frame (&one_mac_display_info);
11460
11461 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11462 NULL, sizeof (WindowRef), NULL, &wp);
11463 if (err != noErr
11464 || wp != FRAME_MAC_WINDOW (f))
11465 break;
11466
11467 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11468 typeMouseWheelAxis, NULL,
11469 sizeof (EventMouseWheelAxis), NULL, &axis);
11470 if (err != noErr || axis != kEventMouseWheelAxisY)
11471 break;
11472
11473 err = GetEventParameter (event, kEventParamMouseLocation,
11474 typeQDPoint, NULL, sizeof (Point),
11475 NULL, &point);
11476 if (err != noErr)
11477 break;
11478
11479 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11480 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
11481 if (point.h < 0 || point.v < 0
11482 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11483 f->tool_bar_window))
11484 break;
11485
11486 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11487 typeSInt32, NULL, sizeof (SInt32),
11488 NULL, &delta);
11489 if (err != noErr)
11490 break;
11491
11492 read_socket_inev->kind = WHEEL_EVENT;
11493 read_socket_inev->code = 0;
11494 read_socket_inev->modifiers =
11495 (mac_event_to_emacs_modifiers (event)
11496 | ((delta < 0) ? down_modifier : up_modifier));
11497 XSETINT (read_socket_inev->x, point.h);
11498 XSETINT (read_socket_inev->y, point.v);
11499 XSETFRAME (read_socket_inev->frame_or_window, f);
11500
11501 result = noErr;
11502 }
11503 break;
11504
11505 default:
11506 abort ();
11507 }
11508
11509 return result;
11510 }
11511
11512 #if USE_MAC_TSM
11513 static pascal OSStatus
11514 mac_handle_text_input_event (next_handler, event, data)
11515 EventHandlerCallRef next_handler;
11516 EventRef event;
11517 void *data;
11518 {
11519 OSStatus err, result;
11520 Lisp_Object id_key = Qnil;
11521 int num_params;
11522 const EventParamName *names;
11523 const EventParamType *types;
11524 static UInt32 seqno_uaia = 0;
11525 static const EventParamName names_uaia[] =
11526 {kEventParamTextInputSendComponentInstance,
11527 kEventParamTextInputSendRefCon,
11528 kEventParamTextInputSendSLRec,
11529 kEventParamTextInputSendFixLen,
11530 kEventParamTextInputSendText,
11531 kEventParamTextInputSendUpdateRng,
11532 kEventParamTextInputSendHiliteRng,
11533 kEventParamTextInputSendClauseRng,
11534 kEventParamTextInputSendPinRng,
11535 kEventParamTextInputSendTextServiceEncoding,
11536 kEventParamTextInputSendTextServiceMacEncoding,
11537 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
11538 static const EventParamType types_uaia[] =
11539 {typeComponentInstance,
11540 typeLongInteger,
11541 typeIntlWritingCode,
11542 typeLongInteger,
11543 #ifdef MAC_OSX
11544 typeUnicodeText,
11545 #else
11546 typeChar,
11547 #endif
11548 typeTextRangeArray,
11549 typeTextRangeArray,
11550 typeOffsetArray,
11551 typeTextRange,
11552 typeUInt32,
11553 typeUInt32,
11554 typeUInt32};
11555 static const EventParamName names_ufke[] =
11556 {kEventParamTextInputSendComponentInstance,
11557 kEventParamTextInputSendRefCon,
11558 kEventParamTextInputSendSLRec,
11559 kEventParamTextInputSendText};
11560 static const EventParamType types_ufke[] =
11561 {typeComponentInstance,
11562 typeLongInteger,
11563 typeIntlWritingCode,
11564 typeUnicodeText};
11565
11566 result = CallNextEventHandler (next_handler, event);
11567 if (result != eventNotHandledErr)
11568 return result;
11569
11570 switch (GetEventKind (event))
11571 {
11572 case kEventTextInputUpdateActiveInputArea:
11573 id_key = Qupdate_active_input_area;
11574 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11575 names = names_uaia;
11576 types = types_uaia;
11577 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11578 typeUInt32, sizeof (UInt32), &seqno_uaia);
11579 seqno_uaia++;
11580 result = noErr;
11581 break;
11582
11583 case kEventTextInputUnicodeForKeyEvent:
11584 {
11585 EventRef kbd_event;
11586 UInt32 actual_size, modifiers;
11587
11588 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11589 typeEventRef, NULL, sizeof (EventRef), NULL,
11590 &kbd_event);
11591 if (err == noErr)
11592 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11593 typeUInt32, NULL,
11594 sizeof (UInt32), NULL, &modifiers);
11595 if (err == noErr && mac_mapped_modifiers (modifiers))
11596 /* There're mapped modifier keys. Process it in
11597 do_keystroke. */
11598 break;
11599 if (err == noErr)
11600 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11601 typeUnicodeText, NULL, 0, &actual_size,
11602 NULL);
11603 if (err == noErr && actual_size == sizeof (UniChar))
11604 {
11605 UniChar code;
11606
11607 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11608 typeUnicodeText, NULL,
11609 sizeof (UniChar), NULL, &code);
11610 if (err == noErr && code < 0x80)
11611 {
11612 /* ASCII character. Process it in do_keystroke. */
11613 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
11614 {
11615 UInt32 key_code;
11616
11617 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11618 typeUInt32, NULL, sizeof (UInt32),
11619 NULL, &key_code);
11620 if (!(err == noErr && key_code <= 0x7f
11621 && keycode_to_xkeysym_table [key_code]))
11622 {
11623 struct frame *f =
11624 mac_focus_frame (&one_mac_display_info);
11625
11626 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11627 read_socket_inev->code = code;
11628 read_socket_inev->modifiers =
11629 mac_to_emacs_modifiers (modifiers);
11630 read_socket_inev->modifiers |=
11631 (extra_keyboard_modifiers
11632 & (meta_modifier | alt_modifier
11633 | hyper_modifier | super_modifier));
11634 XSETFRAME (read_socket_inev->frame_or_window, f);
11635 }
11636 }
11637 break;
11638 }
11639 }
11640 if (err == noErr)
11641 {
11642 /* Non-ASCII keystrokes without mapped modifiers are
11643 processed at the Lisp level. */
11644 id_key = Qunicode_for_key_event;
11645 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11646 names = names_ufke;
11647 types = types_ufke;
11648 result = noErr;
11649 }
11650 }
11651 break;
11652
11653 case kEventTextInputOffsetToPos:
11654 {
11655 struct frame *f;
11656 struct window *w;
11657 Point p;
11658
11659 if (!OVERLAYP (Vmac_ts_active_input_overlay))
11660 break;
11661
11662 /* Strictly speaking, this is not always correct because
11663 previous events may change some states about display. */
11664 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11665 {
11666 /* Active input area is displayed around the current point. */
11667 f = SELECTED_FRAME ();
11668 w = XWINDOW (f->selected_window);
11669 }
11670 else if (WINDOWP (echo_area_window))
11671 {
11672 /* Active input area is displayed in the echo area. */
11673 w = XWINDOW (echo_area_window);
11674 f = WINDOW_XFRAME (w);
11675 }
11676 else
11677 break;
11678
11679 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
11680 + WINDOW_LEFT_FRINGE_WIDTH (w)
11681 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
11682 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
11683 + FONT_BASE (FRAME_FONT (f))
11684 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
11685 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11686 typeQDPoint, sizeof (typeQDPoint), &p);
11687 if (err == noErr)
11688 result = noErr;
11689 }
11690 break;
11691
11692 default:
11693 abort ();
11694 }
11695
11696 if (!NILP (id_key))
11697 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11698 event, num_params,
11699 names, types);
11700 return result;
11701 }
11702 #endif
11703 #endif /* TARGET_API_MAC_CARBON */
11704
11705
11706 OSStatus
11707 install_window_handler (window)
11708 WindowRef window;
11709 {
11710 OSStatus err = noErr;
11711
11712 #if TARGET_API_MAC_CARBON
11713 if (err == noErr)
11714 {
11715 static const EventTypeSpec specs[] =
11716 {
11717 /* -- window refresh events -- */
11718 {kEventClassWindow, kEventWindowUpdate},
11719 /* -- window state change events -- */
11720 {kEventClassWindow, kEventWindowShowing},
11721 {kEventClassWindow, kEventWindowHiding},
11722 {kEventClassWindow, kEventWindowShown},
11723 {kEventClassWindow, kEventWindowHidden},
11724 {kEventClassWindow, kEventWindowCollapsed},
11725 {kEventClassWindow, kEventWindowExpanded},
11726 {kEventClassWindow, kEventWindowBoundsChanging},
11727 {kEventClassWindow, kEventWindowBoundsChanged},
11728 /* -- window action events -- */
11729 {kEventClassWindow, kEventWindowClose},
11730 {kEventClassWindow, kEventWindowGetIdealSize},
11731 #ifdef MAC_OSX
11732 {kEventClassWindow, kEventWindowToolbarSwitchMode},
11733 #endif
11734 #if USE_MAC_TSM
11735 /* -- window focus events -- */
11736 {kEventClassWindow, kEventWindowFocusAcquired},
11737 {kEventClassWindow, kEventWindowFocusRelinquish},
11738 #endif
11739 };
11740 static EventHandlerUPP handle_window_eventUPP = NULL;
11741
11742 if (handle_window_eventUPP == NULL)
11743 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
11744
11745 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11746 GetEventTypeCount (specs),
11747 specs, NULL, NULL);
11748 }
11749 #endif
11750
11751 if (err == noErr)
11752 err = install_drag_handler (window);
11753
11754 return err;
11755 }
11756
11757 void
11758 remove_window_handler (window)
11759 WindowRef window;
11760 {
11761 remove_drag_handler (window);
11762 }
11763
11764 #if TARGET_API_MAC_CARBON
11765 static OSStatus
11766 install_application_handler ()
11767 {
11768 OSStatus err = noErr;
11769
11770 if (err == noErr)
11771 {
11772 static const EventTypeSpec specs[] = {
11773 #if USE_MAC_TSM
11774 {kEventClassApplication, kEventAppActivated},
11775 {kEventClassApplication, kEventAppDeactivated},
11776 #endif
11777 };
11778
11779 err = InstallApplicationEventHandler (NewEventHandlerUPP
11780 (mac_handle_application_event),
11781 GetEventTypeCount (specs),
11782 specs, NULL, NULL);
11783 }
11784
11785 if (err == noErr)
11786 {
11787 static const EventTypeSpec specs[] =
11788 {{kEventClassKeyboard, kEventRawKeyDown},
11789 {kEventClassKeyboard, kEventRawKeyRepeat},
11790 {kEventClassKeyboard, kEventRawKeyUp}};
11791
11792 err = InstallApplicationEventHandler (NewEventHandlerUPP
11793 (mac_handle_keyboard_event),
11794 GetEventTypeCount (specs),
11795 specs, NULL, NULL);
11796 }
11797
11798 if (err == noErr)
11799 {
11800 static const EventTypeSpec specs[] =
11801 {{kEventClassCommand, kEventCommandProcess}};
11802
11803 err = InstallApplicationEventHandler (NewEventHandlerUPP
11804 (mac_handle_command_event),
11805 GetEventTypeCount (specs),
11806 specs, NULL, NULL);
11807 }
11808
11809 if (err == noErr)
11810 {
11811 static const EventTypeSpec specs[] =
11812 {{kEventClassMouse, kEventMouseWheelMoved}};
11813
11814 err = InstallApplicationEventHandler (NewEventHandlerUPP
11815 (mac_handle_mouse_event),
11816 GetEventTypeCount (specs),
11817 specs, NULL, NULL);
11818 }
11819
11820 #if USE_MAC_TSM
11821 if (err == noErr)
11822 {
11823 static const EventTypeSpec spec[] =
11824 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11825 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11826 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11827
11828 err = InstallApplicationEventHandler (NewEventHandlerUPP
11829 (mac_handle_text_input_event),
11830 GetEventTypeCount (spec),
11831 spec, NULL, NULL);
11832 }
11833 #endif
11834
11835 if (err == noErr)
11836 err = install_menu_target_item_handler ();
11837
11838 #ifdef MAC_OSX
11839 if (err == noErr)
11840 err = install_service_handler ();
11841 #endif
11842
11843 return err;
11844 }
11845 #endif
11846
11847 static pascal void
11848 mac_handle_dm_notification (event)
11849 AppleEvent *event;
11850 {
11851 mac_screen_config_changed = 1;
11852 }
11853
11854 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11855 static void
11856 mac_handle_cg_display_reconfig (display, flags, user_info)
11857 CGDirectDisplayID display;
11858 CGDisplayChangeSummaryFlags flags;
11859 void *user_info;
11860 {
11861 mac_screen_config_changed = 1;
11862 }
11863 #endif
11864
11865 static OSErr
11866 init_dm_notification_handler ()
11867 {
11868 OSErr err = noErr;
11869
11870 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11871 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11872 if (CGDisplayRegisterReconfigurationCallback != NULL)
11873 #endif
11874 {
11875 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11876 NULL);
11877 }
11878 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11879 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11880 #endif
11881 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11882 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11883 {
11884 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11885 ProcessSerialNumber psn;
11886
11887 if (handle_dm_notificationUPP == NULL)
11888 handle_dm_notificationUPP =
11889 NewDMNotificationUPP (mac_handle_dm_notification);
11890
11891 err = GetCurrentProcess (&psn);
11892 if (err == noErr)
11893 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11894 }
11895 #endif
11896
11897 return err;
11898 }
11899
11900 static void
11901 mac_get_screen_info (dpyinfo)
11902 struct mac_display_info *dpyinfo;
11903 {
11904 #ifdef MAC_OSX
11905 /* HasDepth returns true if it is possible to have a 32 bit display,
11906 but this may not be what is actually used. Mac OSX can do better. */
11907 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11908 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11909 {
11910 CGDisplayErr err;
11911 CGDisplayCount ndisps;
11912 CGDirectDisplayID *displays;
11913
11914 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11915 if (err == noErr)
11916 {
11917 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11918 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11919 }
11920 if (err == noErr)
11921 {
11922 CGRect bounds = CGRectZero;
11923
11924 while (ndisps-- > 0)
11925 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11926 dpyinfo->height = CGRectGetHeight (bounds);
11927 dpyinfo->width = CGRectGetWidth (bounds);
11928 }
11929 else
11930 {
11931 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11932 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11933 }
11934 }
11935 #else /* !MAC_OSX */
11936 {
11937 GDHandle gdh = GetMainDevice ();
11938 Rect rect = (**gdh).gdRect;
11939
11940 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11941 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11942 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11943 break;
11944
11945 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11946 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11947 UnionRect (&rect, &(**gdh).gdRect, &rect);
11948
11949 dpyinfo->height = rect.bottom - rect.top;
11950 dpyinfo->width = rect.right - rect.left;
11951 }
11952 #endif /* !MAC_OSX */
11953 }
11954
11955
11956 #if __profile__
11957 void
11958 profiler_exit_proc ()
11959 {
11960 ProfilerDump ("\pEmacs.prof");
11961 ProfilerTerm ();
11962 }
11963 #endif
11964
11965 /* These few functions implement Emacs as a normal Mac application
11966 (almost): set up the heap and the Toolbox, handle necessary system
11967 events plus a few simple menu events. They also set up Emacs's
11968 access to functions defined in the rest of this file. Emacs uses
11969 function hooks to perform all its terminal I/O. A complete list of
11970 these functions appear in termhooks.h. For what they do, read the
11971 comments there and see also w32term.c and xterm.c. What's
11972 noticeably missing here is the event loop, which is normally
11973 present in most Mac application. After performing the necessary
11974 Mac initializations, main passes off control to emacs_main
11975 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11976 (defined further below) to read input. This is where
11977 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
11978
11979 #ifdef MAC_OS8
11980 #undef main
11981 int
11982 main (void)
11983 {
11984 #if __profile__ /* is the profiler on? */
11985 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11986 exit(1);
11987 #endif
11988
11989 #if __MWERKS__
11990 /* set creator and type for files created by MSL */
11991 _fcreator = MAC_EMACS_CREATOR_CODE;
11992 _ftype = 'TEXT';
11993 #endif
11994
11995 do_init_managers ();
11996
11997 do_get_menus ();
11998
11999 #ifndef USE_LSB_TAG
12000 do_check_ram_size ();
12001 #endif
12002
12003 init_emacs_passwd_dir ();
12004
12005 init_environ ();
12006
12007 init_coercion_handler ();
12008
12009 initialize_applescript ();
12010
12011 init_apple_event_handler ();
12012
12013 init_dm_notification_handler ();
12014
12015 {
12016 char **argv;
12017 int argc = 0;
12018
12019 /* set up argv array from STR# resource */
12020 get_string_list (&argv, ARGV_STRING_LIST_ID);
12021 while (argv[argc])
12022 argc++;
12023
12024 /* free up AppleScript resources on exit */
12025 atexit (terminate_applescript);
12026
12027 #if __profile__ /* is the profiler on? */
12028 atexit (profiler_exit_proc);
12029 #endif
12030
12031 /* 3rd param "envp" never used in emacs_main */
12032 (void) emacs_main (argc, argv, 0);
12033 }
12034
12035 /* Never reached - real exit in Fkill_emacs */
12036 return 0;
12037 }
12038 #endif
12039
12040 #if !TARGET_API_MAC_CARBON
12041 static RgnHandle mouse_region = NULL;
12042
12043 Boolean
12044 mac_wait_next_event (er, sleep_time, dequeue)
12045 EventRecord *er;
12046 UInt32 sleep_time;
12047 Boolean dequeue;
12048 {
12049 static EventRecord er_buf = {nullEvent};
12050 UInt32 target_tick, current_tick;
12051 EventMask event_mask;
12052
12053 if (mouse_region == NULL)
12054 mouse_region = NewRgn ();
12055
12056 event_mask = everyEvent;
12057 if (!mac_ready_for_apple_events)
12058 event_mask -= highLevelEventMask;
12059
12060 current_tick = TickCount ();
12061 target_tick = current_tick + sleep_time;
12062
12063 if (er_buf.what == nullEvent)
12064 while (!WaitNextEvent (event_mask, &er_buf,
12065 target_tick - current_tick, mouse_region))
12066 {
12067 current_tick = TickCount ();
12068 if (target_tick <= current_tick)
12069 return false;
12070 }
12071
12072 *er = er_buf;
12073 if (dequeue)
12074 er_buf.what = nullEvent;
12075 return true;
12076 }
12077 #endif /* not TARGET_API_MAC_CARBON */
12078
12079 #if TARGET_API_MAC_CARBON
12080 OSStatus
12081 mac_post_mouse_moved_event ()
12082 {
12083 EventRef event = NULL;
12084 OSStatus err;
12085
12086 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
12087 kEventAttributeNone, &event);
12088 if (err == noErr)
12089 {
12090 Point mouse_pos;
12091
12092 GetGlobalMouse (&mouse_pos);
12093 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
12094 sizeof (Point), &mouse_pos);
12095 }
12096 if (err == noErr)
12097 {
12098 UInt32 modifiers = GetCurrentKeyModifiers ();
12099
12100 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
12101 sizeof (UInt32), &modifiers);
12102 }
12103 if (err == noErr)
12104 err = PostEventToQueue (GetCurrentEventQueue (), event,
12105 kEventPriorityStandard);
12106 if (event)
12107 ReleaseEvent (event);
12108
12109 return err;
12110 }
12111 #endif
12112
12113 /* Emacs calls this whenever it wants to read an input event from the
12114 user. */
12115 int
12116 XTread_socket (sd, expected, hold_quit)
12117 int sd, expected;
12118 struct input_event *hold_quit;
12119 {
12120 struct input_event inev;
12121 int count = 0;
12122 #if TARGET_API_MAC_CARBON
12123 EventRef eventRef;
12124 EventTargetRef toolbox_dispatcher;
12125 #endif
12126 EventRecord er;
12127 struct mac_display_info *dpyinfo = &one_mac_display_info;
12128
12129 if (interrupt_input_blocked)
12130 {
12131 interrupt_input_pending = 1;
12132 return -1;
12133 }
12134
12135 interrupt_input_pending = 0;
12136 BLOCK_INPUT;
12137
12138 /* So people can tell when we have read the available input. */
12139 input_signal_count++;
12140
12141 ++handling_signal;
12142
12143 #if TARGET_API_MAC_CARBON
12144 toolbox_dispatcher = GetEventDispatcherTarget ();
12145
12146 while (
12147 #if USE_CG_DRAWING
12148 mac_prepare_for_quickdraw (NULL),
12149 #endif
12150 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
12151 kEventRemoveFromQueue, &eventRef))
12152 #else /* !TARGET_API_MAC_CARBON */
12153 while (mac_wait_next_event (&er, 0, true))
12154 #endif /* !TARGET_API_MAC_CARBON */
12155 {
12156 int do_help = 0;
12157 struct frame *f;
12158 unsigned long timestamp;
12159
12160 EVENT_INIT (inev);
12161 inev.kind = NO_EVENT;
12162 inev.arg = Qnil;
12163
12164 #if TARGET_API_MAC_CARBON
12165 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
12166
12167 if (!mac_convert_event_ref (eventRef, &er))
12168 goto OTHER;
12169 #else /* !TARGET_API_MAC_CARBON */
12170 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12171 #endif /* !TARGET_API_MAC_CARBON */
12172
12173 switch (er.what)
12174 {
12175 case mouseDown:
12176 case mouseUp:
12177 {
12178 WindowRef window_ptr;
12179 ControlPartCode part_code;
12180 int tool_bar_p = 0;
12181
12182 #if TARGET_API_MAC_CARBON
12183 OSStatus err;
12184
12185 /* This is needed to send mouse events like aqua window
12186 buttons to the correct handler. */
12187 read_socket_inev = &inev;
12188 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12189 read_socket_inev = NULL;
12190 if (err != eventNotHandledErr)
12191 break;
12192 #endif
12193 last_mouse_glyph_frame = 0;
12194
12195 if (dpyinfo->grabbed && last_mouse_frame
12196 && FRAME_LIVE_P (last_mouse_frame))
12197 {
12198 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
12199 part_code = inContent;
12200 }
12201 else
12202 {
12203 part_code = FindWindow (er.where, &window_ptr);
12204 if (tip_window && window_ptr == tip_window)
12205 {
12206 HideWindow (tip_window);
12207 part_code = FindWindow (er.where, &window_ptr);
12208 }
12209 }
12210
12211 if (er.what != mouseDown &&
12212 (part_code != inContent || dpyinfo->grabbed == 0))
12213 break;
12214
12215 switch (part_code)
12216 {
12217 case inMenuBar:
12218 f = mac_focus_frame (dpyinfo);
12219 saved_menu_event_location = er.where;
12220 inev.kind = MENU_BAR_ACTIVATE_EVENT;
12221 XSETFRAME (inev.frame_or_window, f);
12222 break;
12223
12224 case inContent:
12225 if (
12226 #if TARGET_API_MAC_CARBON
12227 FrontNonFloatingWindow ()
12228 #else
12229 FrontWindow ()
12230 #endif
12231 != window_ptr
12232 || (mac_window_to_frame (window_ptr)
12233 != dpyinfo->x_focus_frame))
12234 SelectWindow (window_ptr);
12235 else
12236 {
12237 ControlPartCode control_part_code;
12238 ControlRef ch;
12239 Point mouse_loc;
12240 #ifdef MAC_OSX
12241 ControlKind control_kind;
12242 #endif
12243
12244 f = mac_window_to_frame (window_ptr);
12245 /* convert to local coordinates of new window */
12246 mouse_loc.h = (er.where.h
12247 - (f->left_pos
12248 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12249 mouse_loc.v = (er.where.v
12250 - (f->top_pos
12251 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12252 #if TARGET_API_MAC_CARBON
12253 ch = FindControlUnderMouse (mouse_loc, window_ptr,
12254 &control_part_code);
12255 #ifdef MAC_OSX
12256 if (ch)
12257 GetControlKind (ch, &control_kind);
12258 #endif
12259 #else
12260 control_part_code = FindControl (mouse_loc, window_ptr,
12261 &ch);
12262 #endif
12263
12264 #if TARGET_API_MAC_CARBON
12265 inev.code = mac_get_mouse_btn (eventRef);
12266 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
12267 #else
12268 inev.code = mac_get_emulated_btn (er.modifiers);
12269 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
12270 #endif
12271 XSETINT (inev.x, mouse_loc.h);
12272 XSETINT (inev.y, mouse_loc.v);
12273
12274 if ((dpyinfo->grabbed && tracked_scroll_bar)
12275 || (ch != 0
12276 #ifndef USE_TOOLKIT_SCROLL_BARS
12277 /* control_part_code becomes kControlNoPart if
12278 a progress indicator is clicked. */
12279 && control_part_code != kControlNoPart
12280 #else /* USE_TOOLKIT_SCROLL_BARS */
12281 #ifdef MAC_OSX
12282 && control_kind.kind == kControlKindScrollBar
12283 #endif /* MAC_OSX */
12284 #endif /* USE_TOOLKIT_SCROLL_BARS */
12285 ))
12286 {
12287 struct scroll_bar *bar;
12288
12289 if (dpyinfo->grabbed && tracked_scroll_bar)
12290 {
12291 bar = tracked_scroll_bar;
12292 #ifndef USE_TOOLKIT_SCROLL_BARS
12293 control_part_code = kControlIndicatorPart;
12294 #endif
12295 }
12296 else
12297 bar = (struct scroll_bar *) GetControlReference (ch);
12298 #ifdef USE_TOOLKIT_SCROLL_BARS
12299 /* Make the "Ctrl-Mouse-2 splits window" work
12300 for toolkit scroll bars. */
12301 if (inev.modifiers & ctrl_modifier)
12302 x_scroll_bar_handle_click (bar, control_part_code,
12303 &er, &inev);
12304 else if (er.what == mouseDown)
12305 x_scroll_bar_handle_press (bar, control_part_code,
12306 mouse_loc, &inev);
12307 else
12308 x_scroll_bar_handle_release (bar, &inev);
12309 #else /* not USE_TOOLKIT_SCROLL_BARS */
12310 x_scroll_bar_handle_click (bar, control_part_code,
12311 &er, &inev);
12312 if (er.what == mouseDown
12313 && control_part_code == kControlIndicatorPart)
12314 tracked_scroll_bar = bar;
12315 else
12316 tracked_scroll_bar = NULL;
12317 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12318 }
12319 else
12320 {
12321 Lisp_Object window;
12322 int x = mouse_loc.h;
12323 int y = mouse_loc.v;
12324
12325 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
12326 if (EQ (window, f->tool_bar_window))
12327 {
12328 if (er.what == mouseDown)
12329 handle_tool_bar_click (f, x, y, 1, 0);
12330 else
12331 handle_tool_bar_click (f, x, y, 0,
12332 inev.modifiers);
12333 tool_bar_p = 1;
12334 }
12335 else
12336 {
12337 XSETFRAME (inev.frame_or_window, f);
12338 inev.kind = MOUSE_CLICK_EVENT;
12339 }
12340 }
12341
12342 if (er.what == mouseDown)
12343 {
12344 dpyinfo->grabbed |= (1 << inev.code);
12345 last_mouse_frame = f;
12346
12347 if (!tool_bar_p)
12348 last_tool_bar_item = -1;
12349 }
12350 else
12351 {
12352 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
12353 /* If a button is released though it was not
12354 previously pressed, that would be because
12355 of multi-button emulation. */
12356 dpyinfo->grabbed = 0;
12357 else
12358 dpyinfo->grabbed &= ~(1 << inev.code);
12359 }
12360
12361 /* Ignore any mouse motion that happened before
12362 this event; any subsequent mouse-movement Emacs
12363 events should reflect only motion after the
12364 ButtonPress. */
12365 if (f != 0)
12366 f->mouse_moved = 0;
12367
12368 #ifdef USE_TOOLKIT_SCROLL_BARS
12369 if (inev.kind == MOUSE_CLICK_EVENT
12370 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12371 && (inev.modifiers & ctrl_modifier)))
12372 #endif
12373 switch (er.what)
12374 {
12375 case mouseDown:
12376 inev.modifiers |= down_modifier;
12377 break;
12378 case mouseUp:
12379 inev.modifiers |= up_modifier;
12380 break;
12381 }
12382 }
12383 break;
12384
12385 case inDrag:
12386 #if TARGET_API_MAC_CARBON
12387 case inProxyIcon:
12388 if (IsWindowPathSelectClick (window_ptr, &er))
12389 {
12390 WindowPathSelect (window_ptr, NULL, NULL);
12391 break;
12392 }
12393 if (part_code == inProxyIcon
12394 && (TrackWindowProxyDrag (window_ptr, er.where)
12395 != errUserWantsToDragWindow))
12396 break;
12397 DragWindow (window_ptr, er.where, NULL);
12398 #else /* not TARGET_API_MAC_CARBON */
12399 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
12400 /* Update the frame parameters. */
12401 {
12402 struct frame *f = mac_window_to_frame (window_ptr);
12403
12404 if (f && !f->async_iconified)
12405 mac_handle_origin_change (f);
12406 }
12407 #endif /* not TARGET_API_MAC_CARBON */
12408 break;
12409
12410 case inGoAway:
12411 if (TrackGoAway (window_ptr, er.where))
12412 {
12413 inev.kind = DELETE_WINDOW_EVENT;
12414 XSETFRAME (inev.frame_or_window,
12415 mac_window_to_frame (window_ptr));
12416 }
12417 break;
12418
12419 /* window resize handling added --ben */
12420 case inGrow:
12421 do_grow_window (window_ptr, &er);
12422 break;
12423
12424 /* window zoom handling added --ben */
12425 case inZoomIn:
12426 case inZoomOut:
12427 if (TrackBox (window_ptr, er.where, part_code))
12428 do_zoom_window (window_ptr, part_code);
12429 break;
12430
12431 #if USE_MAC_TOOLBAR
12432 case inStructure:
12433 {
12434 OSStatus err;
12435 HIViewRef ch;
12436
12437 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12438 eventRef, &ch);
12439 /* This doesn't work on Mac OS X 10.2. */
12440 if (err == noErr)
12441 HIViewClick (ch, eventRef);
12442 }
12443 break;
12444 #endif /* USE_MAC_TOOLBAR */
12445
12446 default:
12447 break;
12448 }
12449 }
12450 break;
12451
12452 #if !TARGET_API_MAC_CARBON
12453 case updateEvt:
12454 do_window_update ((WindowRef) er.message);
12455 break;
12456 #endif
12457
12458 case osEvt:
12459 switch ((er.message >> 24) & 0x000000FF)
12460 {
12461 case mouseMovedMessage:
12462 #if !TARGET_API_MAC_CARBON
12463 SetRectRgn (mouse_region, er.where.h, er.where.v,
12464 er.where.h + 1, er.where.v + 1);
12465 #endif
12466 previous_help_echo_string = help_echo_string;
12467 help_echo_string = Qnil;
12468
12469 if (dpyinfo->grabbed && last_mouse_frame
12470 && FRAME_LIVE_P (last_mouse_frame))
12471 f = last_mouse_frame;
12472 else
12473 f = dpyinfo->x_focus_frame;
12474
12475 if (dpyinfo->mouse_face_hidden)
12476 {
12477 dpyinfo->mouse_face_hidden = 0;
12478 clear_mouse_face (dpyinfo);
12479 }
12480
12481 if (f)
12482 {
12483 WindowRef wp = FRAME_MAC_WINDOW (f);
12484 Point mouse_pos;
12485
12486 mouse_pos.h = (er.where.h
12487 - (f->left_pos
12488 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12489 mouse_pos.v = (er.where.v
12490 - (f->top_pos
12491 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12492 if (dpyinfo->grabbed && tracked_scroll_bar)
12493 #ifdef USE_TOOLKIT_SCROLL_BARS
12494 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
12495 mouse_pos, &inev);
12496 #else /* not USE_TOOLKIT_SCROLL_BARS */
12497 x_scroll_bar_note_movement (tracked_scroll_bar,
12498 mouse_pos.v
12499 - XINT (tracked_scroll_bar->top),
12500 er.when * (1000 / 60));
12501 #endif /* not USE_TOOLKIT_SCROLL_BARS */
12502 else
12503 {
12504 /* Generate SELECT_WINDOW_EVENTs when needed. */
12505 if (!NILP (Vmouse_autoselect_window))
12506 {
12507 Lisp_Object window;
12508
12509 window = window_from_coordinates (f,
12510 mouse_pos.h,
12511 mouse_pos.v,
12512 0, 0, 0, 0);
12513
12514 /* Window will be selected only when it is
12515 not selected now and last mouse movement
12516 event was not in it. Minibuffer window
12517 will be selected only when it is active. */
12518 if (WINDOWP (window)
12519 && !EQ (window, last_window)
12520 && !EQ (window, selected_window)
12521 /* For click-to-focus window managers
12522 create event iff we don't leave the
12523 selected frame. */
12524 && (focus_follows_mouse
12525 || (EQ (XWINDOW (window)->frame,
12526 XWINDOW (selected_window)->frame))))
12527 {
12528 inev.kind = SELECT_WINDOW_EVENT;
12529 inev.frame_or_window = window;
12530 }
12531
12532 last_window=window;
12533 }
12534 if (!note_mouse_movement (f, &mouse_pos))
12535 help_echo_string = previous_help_echo_string;
12536 #if USE_MAC_TOOLBAR
12537 else
12538 mac_tool_bar_note_mouse_movement (f, eventRef);
12539 #endif
12540 }
12541 }
12542
12543 /* If the contents of the global variable
12544 help_echo_string has changed, generate a
12545 HELP_EVENT. */
12546 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12547 do_help = 1;
12548 break;
12549
12550 default:
12551 goto OTHER;
12552 }
12553 break;
12554
12555 case activateEvt:
12556 {
12557 WindowRef window_ptr = (WindowRef) er.message;
12558 OSErr err;
12559 ControlRef root_control;
12560
12561 if (window_ptr == tip_window)
12562 {
12563 HideWindow (tip_window);
12564 break;
12565 }
12566
12567 if (!is_emacs_window (window_ptr))
12568 goto OTHER;
12569
12570 f = mac_window_to_frame (window_ptr);
12571
12572 if ((er.modifiers & activeFlag) != 0)
12573 {
12574 /* A window has been activated */
12575 Point mouse_loc;
12576
12577 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12578 if (err == noErr)
12579 ActivateControl (root_control);
12580
12581 x_detect_focus_change (dpyinfo, &er, &inev);
12582
12583 mouse_loc.h = (er.where.h
12584 - (f->left_pos
12585 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12586 mouse_loc.v = (er.where.v
12587 - (f->top_pos
12588 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
12589 /* Window-activated event counts as mouse movement,
12590 so update things that depend on mouse position. */
12591 note_mouse_movement (f, &mouse_loc);
12592 }
12593 else
12594 {
12595 /* A window has been deactivated */
12596 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12597 if (err == noErr)
12598 DeactivateControl (root_control);
12599
12600 #ifdef USE_TOOLKIT_SCROLL_BARS
12601 if (dpyinfo->grabbed && tracked_scroll_bar)
12602 {
12603 struct input_event event;
12604
12605 EVENT_INIT (event);
12606 event.kind = NO_EVENT;
12607 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
12608 if (event.kind != NO_EVENT)
12609 {
12610 event.timestamp = timestamp;
12611 kbd_buffer_store_event_hold (&event, hold_quit);
12612 count++;
12613 }
12614 }
12615 #endif
12616 dpyinfo->grabbed = 0;
12617
12618 x_detect_focus_change (dpyinfo, &er, &inev);
12619
12620 if (f == dpyinfo->mouse_face_mouse_frame)
12621 {
12622 /* If we move outside the frame, then we're
12623 certainly no longer on any text in the
12624 frame. */
12625 clear_mouse_face (dpyinfo);
12626 dpyinfo->mouse_face_mouse_frame = 0;
12627 }
12628
12629 /* Generate a nil HELP_EVENT to cancel a help-echo.
12630 Do it only if there's something to cancel.
12631 Otherwise, the startup message is cleared when the
12632 mouse leaves the frame. */
12633 if (any_help_event_p)
12634 do_help = -1;
12635 }
12636 }
12637 break;
12638
12639 case keyDown:
12640 case keyUp:
12641 case autoKey:
12642 ObscureCursor ();
12643
12644 f = mac_focus_frame (dpyinfo);
12645 XSETFRAME (inev.frame_or_window, f);
12646
12647 /* If mouse-highlight is an integer, input clears out mouse
12648 highlighting. */
12649 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12650 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12651 {
12652 clear_mouse_face (dpyinfo);
12653 dpyinfo->mouse_face_hidden = 1;
12654 }
12655
12656 {
12657 UInt32 modifiers = er.modifiers, mapped_modifiers;
12658
12659 #ifdef MAC_OSX
12660 GetEventParameter (eventRef, kEventParamKeyModifiers,
12661 typeUInt32, NULL,
12662 sizeof (UInt32), NULL, &modifiers);
12663 #endif
12664 mapped_modifiers = mac_mapped_modifiers (modifiers);
12665
12666 #if TARGET_API_MAC_CARBON
12667 if (!(mapped_modifiers
12668 & ~(mac_pass_command_to_system ? cmdKey : 0)
12669 & ~(mac_pass_control_to_system ? controlKey : 0)))
12670 goto OTHER;
12671 else
12672 #endif
12673 if (er.what != keyUp)
12674 do_keystroke (er.what, er.message & charCodeMask,
12675 (er.message & keyCodeMask) >> 8,
12676 modifiers, timestamp, &inev);
12677 }
12678 break;
12679
12680 case kHighLevelEvent:
12681 AEProcessAppleEvent (&er);
12682 break;
12683
12684 default:
12685 OTHER:
12686 #if TARGET_API_MAC_CARBON
12687 {
12688 OSStatus err;
12689
12690 read_socket_inev = &inev;
12691 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12692 read_socket_inev = NULL;
12693 }
12694 #endif
12695 break;
12696 }
12697 #if TARGET_API_MAC_CARBON
12698 ReleaseEvent (eventRef);
12699 #endif
12700
12701 if (inev.kind != NO_EVENT)
12702 {
12703 inev.timestamp = timestamp;
12704 kbd_buffer_store_event_hold (&inev, hold_quit);
12705 count++;
12706 }
12707
12708 if (do_help
12709 && !(hold_quit && hold_quit->kind != NO_EVENT))
12710 {
12711 Lisp_Object frame;
12712
12713 if (f)
12714 XSETFRAME (frame, f);
12715 else
12716 frame = Qnil;
12717
12718 if (do_help > 0)
12719 {
12720 any_help_event_p = 1;
12721 gen_help_event (help_echo_string, frame, help_echo_window,
12722 help_echo_object, help_echo_pos);
12723 }
12724 else
12725 {
12726 help_echo_string = Qnil;
12727 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12728 }
12729 count++;
12730 }
12731 }
12732
12733 /* If the focus was just given to an autoraising frame,
12734 raise it now. */
12735 /* ??? This ought to be able to handle more than one such frame. */
12736 if (pending_autoraise_frame)
12737 {
12738 x_raise_frame (pending_autoraise_frame);
12739 pending_autoraise_frame = 0;
12740 }
12741
12742 if (mac_screen_config_changed)
12743 {
12744 mac_get_screen_info (dpyinfo);
12745 mac_screen_config_changed = 0;
12746 }
12747
12748 #if !TARGET_API_MAC_CARBON
12749 /* Check which frames are still visible. We do this here because
12750 there doesn't seem to be any direct notification from the Window
12751 Manager that the visibility of a window has changed (at least,
12752 not in all cases). */
12753 {
12754 Lisp_Object tail, frame;
12755
12756 FOR_EACH_FRAME (tail, frame)
12757 {
12758 struct frame *f = XFRAME (frame);
12759
12760 /* The tooltip has been drawn already. Avoid the
12761 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12762 if (EQ (frame, tip_frame))
12763 continue;
12764
12765 if (FRAME_MAC_P (f))
12766 mac_handle_visibility_change (f);
12767 }
12768 }
12769 #endif
12770
12771 --handling_signal;
12772 UNBLOCK_INPUT;
12773 return count;
12774 }
12775
12776
12777 /* Need to override CodeWarrior's input function so no conversion is
12778 done on newlines Otherwise compiled functions in .elc files will be
12779 read incorrectly. Defined in ...:MSL C:MSL
12780 Common:Source:buffer_io.c. */
12781 #ifdef __MWERKS__
12782 void
12783 __convert_to_newlines (unsigned char * p, size_t * n)
12784 {
12785 #pragma unused(p,n)
12786 }
12787
12788 void
12789 __convert_from_newlines (unsigned char * p, size_t * n)
12790 {
12791 #pragma unused(p,n)
12792 }
12793 #endif
12794
12795 #ifdef MAC_OS8
12796 void
12797 make_mac_terminal_frame (struct frame *f)
12798 {
12799 Lisp_Object frame;
12800 Rect r;
12801
12802 XSETFRAME (frame, f);
12803
12804 f->output_method = output_mac;
12805 f->output_data.mac = (struct mac_output *)
12806 xmalloc (sizeof (struct mac_output));
12807 bzero (f->output_data.mac, sizeof (struct mac_output));
12808
12809 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12810
12811 FRAME_COLS (f) = 96;
12812 FRAME_LINES (f) = 4;
12813
12814 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12815 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12816
12817 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
12818
12819 f->output_data.mac->cursor_pixel = 0;
12820 f->output_data.mac->border_pixel = 0x00ff00;
12821 f->output_data.mac->mouse_pixel = 0xff00ff;
12822 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12823
12824 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12825 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12826 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12827 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12828 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12829 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
12830
12831 FRAME_FONTSET (f) = -1;
12832 f->output_data.mac->explicit_parent = 0;
12833 f->left_pos = 8;
12834 f->top_pos = 32;
12835 f->border_width = 0;
12836
12837 f->internal_border_width = 0;
12838
12839 f->auto_raise = 1;
12840 f->auto_lower = 1;
12841
12842 f->new_text_cols = 0;
12843 f->new_text_lines = 0;
12844
12845 SetRect (&r, f->left_pos, f->top_pos,
12846 f->left_pos + FRAME_PIXEL_WIDTH (f),
12847 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12848
12849 BLOCK_INPUT;
12850
12851 if (!(FRAME_MAC_WINDOW (f) =
12852 NewCWindow (NULL, &r, "\p", true, dBoxProc,
12853 (WindowRef) -1, 1, (long) f->output_data.mac)))
12854 abort ();
12855 /* so that update events can find this mac_output struct */
12856 f->output_data.mac->mFP = f; /* point back to emacs frame */
12857
12858 UNBLOCK_INPUT;
12859
12860 x_make_gc (f);
12861
12862 /* Need to be initialized for unshow_buffer in window.c. */
12863 selected_window = f->selected_window;
12864
12865 Fmodify_frame_parameters (frame,
12866 Fcons (Fcons (Qfont,
12867 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12868 Fmodify_frame_parameters (frame,
12869 Fcons (Fcons (Qforeground_color,
12870 build_string ("black")), Qnil));
12871 Fmodify_frame_parameters (frame,
12872 Fcons (Fcons (Qbackground_color,
12873 build_string ("white")), Qnil));
12874 }
12875 #endif
12876
12877 \f
12878 /***********************************************************************
12879 Initialization
12880 ***********************************************************************/
12881
12882 static int mac_initialized = 0;
12883
12884 static XrmDatabase
12885 mac_make_rdb (xrm_option)
12886 const char *xrm_option;
12887 {
12888 XrmDatabase database;
12889
12890 database = xrm_get_preference_database (NULL);
12891 if (xrm_option)
12892 xrm_merge_string_database (database, xrm_option);
12893
12894 return database;
12895 }
12896
12897 struct mac_display_info *
12898 mac_term_init (display_name, xrm_option, resource_name)
12899 Lisp_Object display_name;
12900 char *xrm_option;
12901 char *resource_name;
12902 {
12903 struct mac_display_info *dpyinfo;
12904 struct terminal *terminal;
12905
12906 BLOCK_INPUT;
12907
12908 if (!mac_initialized)
12909 {
12910 mac_initialize ();
12911 mac_initialized = 1;
12912 }
12913
12914 if (x_display_list)
12915 error ("Sorry, this version can only handle one display");
12916
12917 dpyinfo = &one_mac_display_info;
12918 bzero (dpyinfo, sizeof (*dpyinfo));
12919
12920 terminal = mac_create_terminal (dpyinfo);
12921
12922 /* Set the name of the terminal. */
12923 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12924 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12925 terminal->name[SBYTES (display_name)] = 0;
12926
12927 #ifdef MAC_OSX
12928 dpyinfo->mac_id_name
12929 = (char *) xmalloc (SCHARS (Vinvocation_name)
12930 + SCHARS (Vsystem_name)
12931 + 2);
12932 sprintf (dpyinfo->mac_id_name, "%s@%s",
12933 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12934 #else
12935 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12936 strcpy (dpyinfo->mac_id_name, "Mac Display");
12937 #endif
12938
12939 dpyinfo->reference_count = 0;
12940 dpyinfo->resx = 72.0;
12941 dpyinfo->resy = 72.0;
12942
12943 mac_get_screen_info (dpyinfo);
12944
12945 dpyinfo->grabbed = 0;
12946 dpyinfo->root_window = NULL;
12947 dpyinfo->terminal->image_cache = make_image_cache ();
12948
12949 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12950 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12951 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12952 dpyinfo->mouse_face_window = Qnil;
12953 dpyinfo->mouse_face_overlay = Qnil;
12954 dpyinfo->mouse_face_hidden = 0;
12955
12956 dpyinfo->xrdb = mac_make_rdb (xrm_option);
12957
12958 /* Put this display on the chain. */
12959 dpyinfo->next = x_display_list;
12960 x_display_list = dpyinfo;
12961
12962 /* Put it on x_display_name_list. */
12963 x_display_name_list = Fcons (Fcons (display_name,
12964 Fcons (Qnil, dpyinfo->xrdb)),
12965 x_display_name_list);
12966 dpyinfo->name_list_element = XCAR (x_display_name_list);
12967
12968 /* FIXME: Untested.
12969 Add the default keyboard. */
12970 add_keyboard_wait_descriptor (0);
12971
12972 #if USE_CG_DRAWING
12973 mac_init_fringe (terminal->rif);
12974 #endif
12975
12976 UNBLOCK_INPUT;
12977
12978 return dpyinfo;
12979 }
12980 \f
12981 /* Get rid of display DPYINFO, assuming all frames are already gone. */
12982
12983 void
12984 x_delete_display (dpyinfo)
12985 struct mac_display_info *dpyinfo;
12986 {
12987 int i;
12988
12989 /* Discard this display from x_display_name_list and x_display_list.
12990 We can't use Fdelq because that can quit. */
12991 if (! NILP (x_display_name_list)
12992 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12993 x_display_name_list = XCDR (x_display_name_list);
12994 else
12995 {
12996 Lisp_Object tail;
12997
12998 tail = x_display_name_list;
12999 while (CONSP (tail) && CONSP (XCDR (tail)))
13000 {
13001 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
13002 {
13003 XSETCDR (tail, XCDR (XCDR (tail)));
13004 break;
13005 }
13006 tail = XCDR (tail);
13007 }
13008 }
13009
13010 if (x_display_list == dpyinfo)
13011 x_display_list = dpyinfo->next;
13012 else
13013 {
13014 struct x_display_info *tail;
13015
13016 for (tail = x_display_list; tail; tail = tail->next)
13017 if (tail->next == dpyinfo)
13018 tail->next = tail->next->next;
13019 }
13020
13021 /* Free the font names in the font table. */
13022 for (i = 0; i < dpyinfo->n_fonts; i++)
13023 if (dpyinfo->font_table[i].name)
13024 {
13025 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
13026 xfree (dpyinfo->font_table[i].full_name);
13027 xfree (dpyinfo->font_table[i].name);
13028 }
13029
13030 if (dpyinfo->font_table)
13031 {
13032 if (dpyinfo->font_table->font_encoder)
13033 xfree (dpyinfo->font_table->font_encoder);
13034 xfree (dpyinfo->font_table);
13035 }
13036 if (dpyinfo->mac_id_name)
13037 xfree (dpyinfo->mac_id_name);
13038
13039 if (x_display_list == 0)
13040 {
13041 mac_clear_font_name_table ();
13042 bzero (dpyinfo, sizeof (*dpyinfo));
13043 }
13044 }
13045
13046 \f
13047 static void
13048 init_menu_bar ()
13049 {
13050 #ifdef MAC_OSX
13051 OSStatus err;
13052 MenuRef menu;
13053 MenuItemIndex menu_index;
13054
13055 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
13056 &menu, &menu_index);
13057 if (err == noErr)
13058 SetMenuItemCommandKey (menu, menu_index, false, 0);
13059 EnableMenuCommand (NULL, kHICommandPreferences);
13060 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
13061 &menu, &menu_index);
13062 if (err == noErr)
13063 {
13064 SetMenuItemCommandKey (menu, menu_index, false, 0);
13065 InsertMenuItemTextWithCFString (menu, NULL,
13066 0, kMenuItemAttrSeparator, 0);
13067 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
13068 0, 0, kHICommandAbout);
13069 }
13070 #else /* !MAC_OSX */
13071 #if TARGET_API_MAC_CARBON
13072 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
13073 #endif
13074 #endif
13075 }
13076
13077 #if USE_MAC_TSM
13078 static void
13079 init_tsm ()
13080 {
13081 #ifdef MAC_OSX
13082 static InterfaceTypeList types = {kUnicodeDocument};
13083 #else
13084 static InterfaceTypeList types = {kTextService};
13085 #endif
13086
13087 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
13088 &tsm_document_id, 0);
13089 }
13090 #endif
13091
13092 /* Set up use of X before we make the first connection. */
13093
13094 extern frame_parm_handler mac_frame_parm_handlers[];
13095
13096 static struct redisplay_interface x_redisplay_interface =
13097 {
13098 mac_frame_parm_handlers,
13099 x_produce_glyphs,
13100 x_write_glyphs,
13101 x_insert_glyphs,
13102 x_clear_end_of_line,
13103 x_scroll_run,
13104 x_after_update_window_line,
13105 x_update_window_begin,
13106 x_update_window_end,
13107 x_cursor_to,
13108 x_flush,
13109 #if USE_CG_DRAWING
13110 mac_flush_display_optional,
13111 #else
13112 0, /* flush_display_optional */
13113 #endif
13114 x_clear_window_mouse_face,
13115 x_get_glyph_overhangs,
13116 x_fix_overlapping_area,
13117 x_draw_fringe_bitmap,
13118 #if USE_CG_DRAWING
13119 mac_define_fringe_bitmap,
13120 mac_destroy_fringe_bitmap,
13121 #else
13122 0, /* define_fringe_bitmap */
13123 0, /* destroy_fringe_bitmap */
13124 #endif
13125 mac_per_char_metric,
13126 mac_encode_char,
13127 mac_compute_glyph_string_overhangs,
13128 x_draw_glyph_string,
13129 mac_define_frame_cursor,
13130 mac_clear_frame_area,
13131 mac_draw_window_cursor,
13132 mac_draw_vertical_window_border,
13133 mac_shift_glyphs_for_insert
13134 };
13135
13136 static struct terminal *
13137 mac_create_terminal (struct mac_display_info *dpyinfo)
13138 {
13139 struct terminal *terminal;
13140
13141 terminal = create_terminal ();
13142
13143 terminal->type = output_mac;
13144 terminal->display_info.mac = dpyinfo;
13145 dpyinfo->terminal = terminal;
13146
13147 terminal->clear_frame_hook = x_clear_frame;
13148 terminal->ins_del_lines_hook = x_ins_del_lines;
13149 terminal->delete_glyphs_hook = x_delete_glyphs;
13150 terminal->ring_bell_hook = XTring_bell;
13151 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
13152 terminal->set_terminal_modes_hook = XTset_terminal_modes;
13153 terminal->update_begin_hook = x_update_begin;
13154 terminal->update_end_hook = x_update_end;
13155 terminal->set_terminal_window_hook = XTset_terminal_window;
13156 terminal->read_socket_hook = XTread_socket;
13157 terminal->frame_up_to_date_hook = XTframe_up_to_date;
13158 terminal->mouse_position_hook = XTmouse_position;
13159 terminal->frame_rehighlight_hook = XTframe_rehighlight;
13160 terminal->frame_raise_lower_hook = XTframe_raise_lower;
13161 /* terminal->fullscreen_hook = XTfullscreen_hook; */
13162 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13163 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13164 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
13165 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
13166 terminal->delete_frame_hook = x_destroy_window;
13167 /* terminal->delete_terminal_hook = x_delete_terminal; */
13168
13169 terminal->rif = &x_redisplay_interface;
13170 #if 0
13171 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
13172 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
13173 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
13174 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
13175 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
13176 scrolls off the
13177 bottom */
13178 #else
13179 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
13180 terminal->char_ins_del_ok = 1;
13181 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
13182 terminal->fast_clear_end_of_line = 1; /* X does this well. */
13183 terminal->memory_below_frame = 0; /* We don't remember what scrolls
13184 off the bottom. */
13185
13186 #endif
13187
13188 /* FIXME: This keyboard setup is 100% untested, just copied from
13189 w32_create_terminal in order to set window-system now that it's
13190 a keyboard object. */
13191 /* We don't yet support separate terminals on Mac, so don't try to share
13192 keyboards between virtual terminals that are on the same physical
13193 terminal like X does. */
13194 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13195 init_kboard (terminal->kboard);
13196 terminal->kboard->Vwindow_system = intern ("mac");
13197 terminal->kboard->next_kboard = all_kboards;
13198 all_kboards = terminal->kboard;
13199 /* Don't let the initial kboard remain current longer than necessary.
13200 That would cause problems if a file loaded on startup tries to
13201 prompt in the mini-buffer. */
13202 if (current_kboard == initial_kboard)
13203 current_kboard = terminal->kboard;
13204 terminal->kboard->reference_count++;
13205
13206 return terminal;
13207 }
13208
13209 static void
13210 mac_initialize ()
13211 {
13212
13213 baud_rate = 19200;
13214
13215 last_tool_bar_item = -1;
13216 any_help_event_p = 0;
13217
13218 /* Try to use interrupt input; if we can't, then start polling. */
13219 Fset_input_interrupt_mode (Qt);
13220
13221 BLOCK_INPUT;
13222
13223 #if TARGET_API_MAC_CARBON
13224
13225 install_application_handler ();
13226
13227 init_menu_bar ();
13228
13229 #if USE_MAC_TSM
13230 init_tsm ();
13231 #endif
13232
13233 #ifdef MAC_OSX
13234 init_coercion_handler ();
13235
13236 init_apple_event_handler ();
13237
13238 init_dm_notification_handler ();
13239
13240 if (!inhibit_window_system)
13241 {
13242 static const ProcessSerialNumber psn = {0, kCurrentProcess};
13243
13244 SetFrontProcess (&psn);
13245 }
13246 #endif
13247 #endif
13248
13249 #if USE_CG_DRAWING
13250 init_cg_color ();
13251 #endif
13252
13253 UNBLOCK_INPUT;
13254
13255 }
13256
13257
13258 void
13259 syms_of_macterm ()
13260 {
13261 #if 0
13262 staticpro (&x_error_message_string);
13263 x_error_message_string = Qnil;
13264 #endif
13265
13266 Qcontrol = intern ("control"); staticpro (&Qcontrol);
13267 Qmeta = intern ("meta"); staticpro (&Qmeta);
13268 Qalt = intern ("alt"); staticpro (&Qalt);
13269 Qhyper = intern ("hyper"); staticpro (&Qhyper);
13270 Qsuper = intern ("super"); staticpro (&Qsuper);
13271 Qmodifier_value = intern ("modifier-value");
13272 staticpro (&Qmodifier_value);
13273
13274 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
13275 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
13276 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
13277 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
13278 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
13279
13280 #if TARGET_API_MAC_CARBON
13281 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
13282 #ifdef MAC_OSX
13283 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
13284 staticpro (&Qtoolbar_switch_mode);
13285 #if USE_MAC_FONT_PANEL
13286 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
13287 Qselection = intern ("selection"); staticpro (&Qselection);
13288 #endif
13289
13290 Qservice = intern ("service"); staticpro (&Qservice);
13291 Qpaste = intern ("paste"); staticpro (&Qpaste);
13292 Qperform = intern ("perform"); staticpro (&Qperform);
13293
13294 Qmouse_drag_overlay = intern ("mouse-drag-overlay");
13295 staticpro (&Qmouse_drag_overlay);
13296 #endif
13297 #if USE_MAC_TSM
13298 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
13299 Qupdate_active_input_area = intern ("update-active-input-area");
13300 staticpro (&Qupdate_active_input_area);
13301 Qunicode_for_key_event = intern ("unicode-for-key-event");
13302 staticpro (&Qunicode_for_key_event);
13303 #endif
13304 #endif
13305
13306 #ifdef MAC_OSX
13307 Fprovide (intern ("mac-carbon"), Qnil);
13308 #endif
13309
13310 staticpro (&Qreverse);
13311 Qreverse = intern ("reverse");
13312
13313 staticpro (&x_display_name_list);
13314 x_display_name_list = Qnil;
13315
13316 staticpro (&last_mouse_scroll_bar);
13317 last_mouse_scroll_bar = Qnil;
13318
13319 staticpro (&fm_font_family_alist);
13320 fm_font_family_alist = Qnil;
13321
13322 #if USE_ATSUI
13323 staticpro (&atsu_font_id_hash);
13324 atsu_font_id_hash = Qnil;
13325
13326 staticpro (&fm_style_face_attributes_alist);
13327 fm_style_face_attributes_alist = Qnil;
13328 #endif
13329
13330 #if USE_MAC_TSM
13331 staticpro (&saved_ts_script_language_on_focus);
13332 saved_ts_script_language_on_focus = Qnil;
13333 #endif
13334
13335 /* We don't yet support this, but defining this here avoids whining
13336 from cus-start.el and other places, like "M-x set-variable". */
13337 DEFVAR_BOOL ("x-use-underline-position-properties",
13338 &x_use_underline_position_properties,
13339 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
13340 A value of nil means ignore them. If you encounter fonts with bogus
13341 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
13342 to 4.1, set this to nil.
13343
13344 NOTE: Not supported on Mac yet. */);
13345 x_use_underline_position_properties = 0;
13346
13347 DEFVAR_BOOL ("x-underline-at-descent-line",
13348 &x_underline_at_descent_line,
13349 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
13350 A value of nil means to draw the underline according to the value of the
13351 variable `x-use-underline-position-properties', which is usually at the
13352 baseline level. The default value is nil. */);
13353 x_underline_at_descent_line = 0;
13354
13355 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
13356 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
13357 #ifdef USE_TOOLKIT_SCROLL_BARS
13358 Vx_toolkit_scroll_bars = Qt;
13359 #else
13360 Vx_toolkit_scroll_bars = Qnil;
13361 #endif
13362
13363 staticpro (&last_mouse_motion_frame);
13364 last_mouse_motion_frame = Qnil;
13365
13366 /* Variables to configure modifier key assignment. */
13367
13368 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
13369 doc: /* *Modifier key assumed when the Mac control key is pressed.
13370 The value can be `control', `meta', `alt', `hyper', or `super' for the
13371 respective modifier. The default is `control'. */);
13372 Vmac_control_modifier = Qcontrol;
13373
13374 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
13375 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13376 The value can be `control', `meta', `alt', `hyper', or `super' for the
13377 respective modifier. If the value is nil then the key will act as the
13378 normal Mac control modifier, and the option key can be used to compose
13379 characters depending on the chosen Mac keyboard setting. */);
13380 Vmac_option_modifier = Qnil;
13381
13382 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
13383 doc: /* *Modifier key assumed when the Mac command key is pressed.
13384 The value can be `control', `meta', `alt', `hyper', or `super' for the
13385 respective modifier. The default is `meta'. */);
13386 Vmac_command_modifier = Qmeta;
13387
13388 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
13389 doc: /* *Modifier key assumed when the Mac function key is pressed.
13390 The value can be `control', `meta', `alt', `hyper', or `super' for the
13391 respective modifier. Note that remapping the function key may lead to
13392 unexpected results for some keys on non-US/GB keyboards. */);
13393 Vmac_function_modifier = Qnil;
13394
13395 DEFVAR_LISP ("mac-emulate-three-button-mouse",
13396 &Vmac_emulate_three_button_mouse,
13397 doc: /* *Specify a way of three button mouse emulation.
13398 The value can be nil, t, or the symbol `reverse'.
13399 A value of nil means that no emulation should be done and the modifiers
13400 should be placed on the mouse-1 event.
13401 t means that when the option-key is held down while pressing the mouse
13402 button, the click will register as mouse-2 and while the command-key
13403 is held down, the click will register as mouse-3.
13404 The symbol `reverse' means that the option-key will register for
13405 mouse-3 and the command-key will register for mouse-2. */);
13406 Vmac_emulate_three_button_mouse = Qnil;
13407
13408 #if TARGET_API_MAC_CARBON
13409 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
13410 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
13411 Otherwise, the right click will be treated as mouse-2 and the wheel
13412 button will be mouse-3. */);
13413 mac_wheel_button_is_mouse_2 = 1;
13414
13415 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
13416 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
13417 mac_pass_command_to_system = 1;
13418
13419 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
13420 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
13421 mac_pass_control_to_system = 1;
13422
13423 #endif
13424
13425 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
13426 doc: /* *If non-nil, allow anti-aliasing.
13427 The text will be rendered using Core Graphics text rendering which
13428 may anti-alias the text. */);
13429 #if USE_CG_DRAWING
13430 mac_use_core_graphics = 1;
13431 #else
13432 mac_use_core_graphics = 0;
13433 #endif
13434
13435 /* Register an entry for `mac-roman' so that it can be used when
13436 creating the terminal frame on Mac OS 9 before loading
13437 term/mac-win.elc. */
13438 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
13439 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
13440 Each entry should be of the form:
13441
13442 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13443
13444 where CHARSET-NAME is a string used in font names to identify the
13445 charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13446 CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
13447 Vmac_charset_info_alist =
13448 Fcons (list3 (build_string ("mac-roman"),
13449 make_number (smRoman), Qnil), Qnil);
13450
13451 #if USE_MAC_TSM
13452 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13453 doc: /* Overlay used to display Mac TSM active input area. */);
13454 Vmac_ts_active_input_overlay = Qnil;
13455
13456 DEFVAR_LISP ("mac-ts-active-input-buf", &Vmac_ts_active_input_buf,
13457 doc: /* Byte sequence of the current Mac TSM active input area. */);
13458 /* `empty_string' is not ready yet on Mac OS Classic. */
13459 Vmac_ts_active_input_buf = build_string ("");
13460
13461 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13462 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13463 If the value is t, the input script and language are restored to those
13464 used in the last focus frame. If the value is a pair of integers, the
13465 input script and language codes, which are defined in the Script
13466 Manager, are set to its car and cdr parts, respectively. Otherwise,
13467 Emacs doesn't set them and thus follows the system default behavior. */);
13468 Vmac_ts_script_language_on_focus = Qnil;
13469 #endif
13470 }
13471
13472 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13473 (do not change this comment) */