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