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