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