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