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