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