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