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