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