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