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