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