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