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