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