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