(define-ibuffer-filter filename): If `dired-directory' is a list then
[emacs.git] / src / macterm.c
blobbabb009f0222b1dfa536b730b74ce97afdbfadf6
1 /* Implementation of GUI terminal on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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.
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.
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. */
22 /* Contributed by Andrew Choi (akochoi@mac.com). */
24 #include <config.h>
25 #include <signal.h>
27 #include <stdio.h>
29 #include "lisp.h"
30 #include "blockinput.h"
32 #include "macterm.h"
34 #ifndef MAC_OSX
35 #include <alloca.h>
36 #endif
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
59 #if __profile__
60 #include <profiler.h>
61 #endif
62 #endif /* not TARGET_API_MAC_CARBON */
64 #include "systty.h"
65 #include "systime.h"
67 #include <ctype.h>
68 #include <errno.h>
69 #include <setjmp.h>
70 #include <sys/stat.h>
71 #include <sys/param.h>
73 #include "charset.h"
74 #include "coding.h"
75 #include "frame.h"
76 #include "dispextern.h"
77 #include "fontset.h"
78 #include "termhooks.h"
79 #include "termopts.h"
80 #include "termchar.h"
81 #include "gnu.h"
82 #include "disptab.h"
83 #include "buffer.h"
84 #include "window.h"
85 #include "keyboard.h"
86 #include "intervals.h"
87 #include "atimer.h"
88 #include "keymap.h"
92 /* Non-nil means Emacs uses toolkit scroll bars. */
94 Lisp_Object Vx_toolkit_scroll_bars;
96 /* If Non-nil, the text will be rendered using Core Graphics text rendering which may anti-alias the text. */
97 Lisp_Object Vmac_use_core_graphics;
100 /* Non-zero means that a HELP_EVENT has been generated since Emacs
101 start. */
103 static int any_help_event_p;
105 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
106 static Lisp_Object last_window;
108 /* This is a chain of structures for all the X displays currently in
109 use. */
111 struct x_display_info *x_display_list;
113 /* This is a list of cons cells, each of the form (NAME
114 FONT-LIST-CACHE . RESOURCE-DATABASE), one for each element of
115 x_display_list and in the same order. NAME is the name of the
116 frame. FONT-LIST-CACHE records previous values returned by
117 x-list-fonts. RESOURCE-DATABASE preserves the X Resource Database
118 equivalent, which is implemented with a Lisp object, for the
119 display. */
121 Lisp_Object x_display_name_list;
123 /* This is display since Mac does not support multiple ones. */
124 struct mac_display_info one_mac_display_info;
126 /* Frame being updated by update_frame. This is declared in term.c.
127 This is set by update_begin and looked at by all the XT functions.
128 It is zero while not inside an update. In that case, the XT
129 functions assume that `selected_frame' is the frame to apply to. */
131 extern struct frame *updating_frame;
133 /* This is a frame waiting to be auto-raised, within XTread_socket. */
135 struct frame *pending_autoraise_frame;
137 /* Mouse movement.
139 Formerly, we used PointerMotionHintMask (in standard_event_mask)
140 so that we would have to call XQueryPointer after each MotionNotify
141 event to ask for another such event. However, this made mouse tracking
142 slow, and there was a bug that made it eventually stop.
144 Simply asking for MotionNotify all the time seems to work better.
146 In order to avoid asking for motion events and then throwing most
147 of them away or busy-polling the server for mouse positions, we ask
148 the server for pointer motion hints. This means that we get only
149 one event per group of mouse movements. "Groups" are delimited by
150 other kinds of events (focus changes and button clicks, for
151 example), or by XQueryPointer calls; when one of these happens, we
152 get another MotionNotify event the next time the mouse moves. This
153 is at least as efficient as getting motion events when mouse
154 tracking is on, and I suspect only negligibly worse when tracking
155 is off. */
157 /* Where the mouse was last time we reported a mouse event. */
159 static Rect last_mouse_glyph;
160 static FRAME_PTR last_mouse_glyph_frame;
162 /* The scroll bar in which the last X motion event occurred.
164 If the last X motion event occurred in a scroll bar, we set this so
165 XTmouse_position can know whether to report a scroll bar motion or
166 an ordinary motion.
168 If the last X motion event didn't occur in a scroll bar, we set
169 this to Qnil, to tell XTmouse_position to return an ordinary motion
170 event. */
172 static Lisp_Object last_mouse_scroll_bar;
174 /* This is a hack. We would really prefer that XTmouse_position would
175 return the time associated with the position it returns, but there
176 doesn't seem to be any way to wrest the time-stamp from the server
177 along with the position query. So, we just keep track of the time
178 of the last movement we received, and return that in hopes that
179 it's somewhat accurate. */
181 static Time last_mouse_movement_time;
183 struct scroll_bar *tracked_scroll_bar = NULL;
185 /* Incremented by XTread_socket whenever it really tries to read
186 events. */
188 #ifdef __STDC__
189 static int volatile input_signal_count;
190 #else
191 static int input_signal_count;
192 #endif
194 extern Lisp_Object Vsystem_name;
196 /* A mask of extra modifier bits to put into every keyboard char. */
198 extern EMACS_INT extra_keyboard_modifiers;
200 /* The keysyms to use for the various modifiers. */
202 static Lisp_Object Qalt, Qhyper, Qsuper, Qcontrol,
203 Qmeta, Qmodifier_value;
205 extern int inhibit_window_system;
207 #if __MRC__ && !TARGET_API_MAC_CARBON
208 QDGlobals qd; /* QuickDraw global information structure. */
209 #endif
211 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
213 struct mac_display_info *mac_display_info_for_display (Display *);
214 static void x_update_window_end P_ ((struct window *, int, int));
215 static int x_io_error_quitter P_ ((Display *));
216 int x_catch_errors P_ ((Display *));
217 void x_uncatch_errors P_ ((Display *, int));
218 void x_lower_frame P_ ((struct frame *));
219 void x_scroll_bar_clear P_ ((struct frame *));
220 int x_had_errors_p P_ ((Display *));
221 void x_wm_set_size_hint P_ ((struct frame *, long, int));
222 void x_raise_frame P_ ((struct frame *));
223 void x_set_window_size P_ ((struct frame *, int, int, int));
224 void x_wm_set_window_state P_ ((struct frame *, int));
225 void x_wm_set_icon_pixmap P_ ((struct frame *, int));
226 void mac_initialize P_ ((void));
227 static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
228 static int x_compute_min_glyph_bounds P_ ((struct frame *));
229 static void x_update_end P_ ((struct frame *));
230 static void XTframe_up_to_date P_ ((struct frame *));
231 static void XTset_terminal_modes P_ ((void));
232 static void XTreset_terminal_modes P_ ((void));
233 static void x_clear_frame P_ ((void));
234 static void frame_highlight P_ ((struct frame *));
235 static void frame_unhighlight P_ ((struct frame *));
236 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
237 static void mac_focus_changed P_ ((int, struct mac_display_info *,
238 struct frame *, struct input_event *));
239 static void x_detect_focus_change P_ ((struct mac_display_info *,
240 EventRecord *, struct input_event *));
241 static void XTframe_rehighlight P_ ((struct frame *));
242 static void x_frame_rehighlight P_ ((struct x_display_info *));
243 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
244 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
245 enum text_cursor_kinds));
247 static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
248 static void x_flush P_ ((struct frame *f));
249 static void x_update_begin P_ ((struct frame *));
250 static void x_update_window_begin P_ ((struct window *));
251 static void x_after_update_window_line P_ ((struct glyph_row *));
252 static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
253 enum scroll_bar_part *,
254 Lisp_Object *, Lisp_Object *,
255 unsigned long *));
257 static int is_emacs_window P_ ((WindowPtr));
259 static void XSetFont P_ ((Display *, GC, XFontStruct *));
261 /* Defined in macmenu.h. */
262 extern void menubar_selection_callback (FRAME_PTR, int);
264 #define GC_FORE_COLOR(gc) (&(gc)->fore_color)
265 #define GC_BACK_COLOR(gc) (&(gc)->back_color)
266 #define GC_FONT(gc) ((gc)->xgcv.font)
267 #define GC_CLIP_REGION(gc) ((gc)->clip_region)
268 #define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
270 static RgnHandle saved_port_clip_region = NULL;
272 static void
273 mac_begin_clip (region)
274 RgnHandle region;
276 static RgnHandle new_region = NULL;
278 if (saved_port_clip_region == NULL)
279 saved_port_clip_region = NewRgn ();
280 if (new_region == NULL)
281 new_region = NewRgn ();
283 if (region)
285 GetClip (saved_port_clip_region);
286 SectRgn (saved_port_clip_region, region, new_region);
287 SetClip (new_region);
291 static void
292 mac_end_clip (region)
293 RgnHandle region;
295 if (region)
296 SetClip (saved_port_clip_region);
300 /* X display function emulation */
302 void
303 XFreePixmap (display, pixmap)
304 Display *display; /* not used */
305 Pixmap pixmap;
307 DisposeGWorld (pixmap);
311 /* Mac version of XDrawLine. */
313 static void
314 mac_draw_line (f, gc, x1, y1, x2, y2)
315 struct frame *f;
316 GC gc;
317 int x1, y1, x2, y2;
319 SetPortWindowPort (FRAME_MAC_WINDOW (f));
321 RGBForeColor (GC_FORE_COLOR (gc));
323 mac_begin_clip (GC_CLIP_REGION (gc));
324 MoveTo (x1, y1);
325 LineTo (x2, y2);
326 mac_end_clip (GC_CLIP_REGION (gc));
329 void
330 mac_draw_line_to_pixmap (display, p, gc, x1, y1, x2, y2)
331 Display *display;
332 Pixmap p;
333 GC gc;
334 int x1, y1, x2, y2;
336 CGrafPtr old_port;
337 GDHandle old_gdh;
339 GetGWorld (&old_port, &old_gdh);
340 SetGWorld (p, NULL);
342 RGBForeColor (GC_FORE_COLOR (gc));
344 LockPixels (GetGWorldPixMap (p));
345 MoveTo (x1, y1);
346 LineTo (x2, y2);
347 UnlockPixels (GetGWorldPixMap (p));
349 SetGWorld (old_port, old_gdh);
353 static void
354 mac_erase_rectangle (f, gc, x, y, width, height)
355 struct frame *f;
356 GC gc;
357 int x, y;
358 unsigned int width, height;
360 Rect r;
362 SetPortWindowPort (FRAME_MAC_WINDOW (f));
364 RGBBackColor (GC_BACK_COLOR (gc));
365 SetRect (&r, x, y, x + width, y + height);
367 mac_begin_clip (GC_CLIP_REGION (gc));
368 EraseRect (&r);
369 mac_end_clip (GC_CLIP_REGION (gc));
371 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
375 /* Mac version of XClearArea. */
377 void
378 mac_clear_area (f, x, y, width, height)
379 struct frame *f;
380 int x, y;
381 unsigned int width, height;
383 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
386 /* Mac version of XClearWindow. */
388 static void
389 mac_clear_window (f)
390 struct frame *f;
392 SetPortWindowPort (FRAME_MAC_WINDOW (f));
394 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
396 #if TARGET_API_MAC_CARBON
398 Rect r;
400 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
401 EraseRect (&r);
403 #else /* not TARGET_API_MAC_CARBON */
404 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
405 #endif /* not TARGET_API_MAC_CARBON */
409 /* Mac replacement for XCopyArea. */
411 static void
412 mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
413 struct frame *f;
414 GC gc;
415 int x, y, width, height;
416 unsigned short *bits;
417 int overlay_p;
419 BitMap bitmap;
420 Rect r;
422 bitmap.rowBytes = sizeof(unsigned short);
423 bitmap.baseAddr = (char *)bits;
424 SetRect (&(bitmap.bounds), 0, 0, width, height);
426 SetPortWindowPort (FRAME_MAC_WINDOW (f));
428 RGBForeColor (GC_FORE_COLOR (gc));
429 RGBBackColor (GC_BACK_COLOR (gc));
430 SetRect (&r, x, y, x + width, y + height);
432 mac_begin_clip (GC_CLIP_REGION (gc));
433 #if TARGET_API_MAC_CARBON
435 CGrafPtr port;
437 GetPort (&port);
438 LockPortBits (port);
439 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
440 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
441 UnlockPortBits (port);
443 #else /* not TARGET_API_MAC_CARBON */
444 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
445 overlay_p ? srcOr : srcCopy, 0);
446 #endif /* not TARGET_API_MAC_CARBON */
447 mac_end_clip (GC_CLIP_REGION (gc));
449 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
453 /* Mac replacement for XCreateBitmapFromBitmapData. */
455 static void
456 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
457 BitMap *bitmap;
458 char *bits;
459 int w, h;
461 static unsigned char swap_nibble[16]
462 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
463 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
464 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
465 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
466 int i, j, w1;
467 char *p;
469 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
470 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
471 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
472 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
473 for (i = 0; i < h; i++)
475 p = bitmap->baseAddr + i * bitmap->rowBytes;
476 for (j = 0; j < w1; j++)
478 /* Bitswap XBM bytes to match how Mac does things. */
479 unsigned char c = *bits++;
480 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
481 | (swap_nibble[(c>>4) & 0xf]));;
485 SetRect (&(bitmap->bounds), 0, 0, w, h);
489 static void
490 mac_free_bitmap (bitmap)
491 BitMap *bitmap;
493 xfree (bitmap->baseAddr);
497 Pixmap
498 XCreatePixmap (display, w, width, height, depth)
499 Display *display; /* not used */
500 WindowPtr w;
501 unsigned int width, height;
502 unsigned int depth;
504 Pixmap pixmap;
505 Rect r;
506 QDErr err;
508 SetPortWindowPort (w);
510 SetRect (&r, 0, 0, width, height);
511 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
512 if (err != noErr)
513 return NULL;
514 return pixmap;
518 Pixmap
519 XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
520 Display *display; /* not used */
521 WindowPtr w;
522 char *data;
523 unsigned int width, height;
524 unsigned long fg, bg;
525 unsigned int depth;
527 Pixmap pixmap;
528 BitMap bitmap;
529 CGrafPtr old_port;
530 GDHandle old_gdh;
531 static GC gc = NULL; /* not reentrant */
533 if (gc == NULL)
534 gc = XCreateGC (display, w, 0, NULL);
536 pixmap = XCreatePixmap (display, w, width, height, depth);
537 if (pixmap == NULL)
538 return NULL;
540 GetGWorld (&old_port, &old_gdh);
541 SetGWorld (pixmap, NULL);
542 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
543 XSetForeground (display, gc, fg);
544 XSetBackground (display, gc, bg);
545 RGBForeColor (GC_FORE_COLOR (gc));
546 RGBBackColor (GC_BACK_COLOR (gc));
547 LockPixels (GetGWorldPixMap (pixmap));
548 #if TARGET_API_MAC_CARBON
549 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
550 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
551 #else /* not TARGET_API_MAC_CARBON */
552 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
553 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
554 #endif /* not TARGET_API_MAC_CARBON */
555 UnlockPixels (GetGWorldPixMap (pixmap));
556 SetGWorld (old_port, old_gdh);
557 mac_free_bitmap (&bitmap);
559 return pixmap;
563 /* Mac replacement for XFillRectangle. */
565 static void
566 mac_fill_rectangle (f, gc, x, y, width, height)
567 struct frame *f;
568 GC gc;
569 int x, y;
570 unsigned int width, height;
572 Rect r;
574 SetPortWindowPort (FRAME_MAC_WINDOW (f));
576 RGBForeColor (GC_FORE_COLOR (gc));
577 SetRect (&r, x, y, x + width, y + height);
579 mac_begin_clip (GC_CLIP_REGION (gc));
580 PaintRect (&r); /* using foreground color of gc */
581 mac_end_clip (GC_CLIP_REGION (gc));
585 /* Mac replacement for XDrawRectangle: dest is a window. */
587 static void
588 mac_draw_rectangle (f, gc, x, y, width, height)
589 struct frame *f;
590 GC gc;
591 int x, y;
592 unsigned int width, height;
594 Rect r;
596 SetPortWindowPort (FRAME_MAC_WINDOW (f));
598 RGBForeColor (GC_FORE_COLOR (gc));
599 SetRect (&r, x, y, x + width + 1, y + height + 1);
601 mac_begin_clip (GC_CLIP_REGION (gc));
602 FrameRect (&r); /* using foreground color of gc */
603 mac_end_clip (GC_CLIP_REGION (gc));
607 #if USE_ATSUI
608 static OSStatus
609 atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
610 ConstUniCharArrayPtr text;
611 UniCharCount text_length;
612 ATSUStyle style;
613 ATSUTextLayout *text_layout;
615 OSStatus err;
616 static ATSUTextLayout saved_text_layout = NULL; /* not reentrant */
618 if (saved_text_layout == NULL)
620 UniCharCount lengths[] = {kATSUToTextEnd};
621 ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
622 ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
623 static ATSLineLayoutOptions line_layout =
624 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
625 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
626 #else
627 kATSLineIsDisplayOnly | kATSLineFractDisable
628 #endif
630 ATSUAttributeValuePtr values[] = {&line_layout};
632 err = ATSUCreateTextLayoutWithTextPtr (text,
633 kATSUFromTextBeginning,
634 kATSUToTextEnd,
635 text_length,
636 1, lengths, &style,
637 &saved_text_layout);
638 if (err == noErr)
639 err = ATSUSetLayoutControls (saved_text_layout,
640 sizeof (tags) / sizeof (tags[0]),
641 tags, sizes, values);
642 /* XXX: Should we do this? */
643 if (err == noErr)
644 err = ATSUSetTransientFontMatching (saved_text_layout, true);
646 else
648 err = ATSUSetRunStyle (saved_text_layout, style,
649 kATSUFromTextBeginning, kATSUToTextEnd);
650 if (err == noErr)
651 err = ATSUSetTextPointerLocation (saved_text_layout, text,
652 kATSUFromTextBeginning,
653 kATSUToTextEnd,
654 text_length);
657 if (err == noErr)
658 *text_layout = saved_text_layout;
659 return err;
661 #endif
664 static void
665 mac_invert_rectangle (f, x, y, width, height)
666 struct frame *f;
667 int x, y;
668 unsigned int width, height;
670 Rect r;
672 SetPortWindowPort (FRAME_MAC_WINDOW (f));
674 SetRect (&r, x, y, x + width, y + height);
676 InvertRect (&r);
680 static void
681 mac_draw_string_common (f, gc, x, y, buf, nchars, mode, bytes_per_char)
682 struct frame *f;
683 GC gc;
684 int x, y;
685 char *buf;
686 int nchars, mode, bytes_per_char;
688 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
689 UInt32 textFlags, savedFlags;
690 if (!NILP(Vmac_use_core_graphics)) {
691 textFlags = kQDUseCGTextRendering;
692 savedFlags = SwapQDTextFlags(textFlags);
694 #endif
696 SetPortWindowPort (FRAME_MAC_WINDOW (f));
698 RGBForeColor (GC_FORE_COLOR (gc));
699 if (mode != srcOr)
700 RGBBackColor (GC_BACK_COLOR (gc));
702 #if USE_ATSUI
703 if (GC_FONT (gc)->mac_style)
705 OSErr err;
706 ATSUTextLayout text_layout;
708 xassert (bytes_per_char == 2);
710 #ifndef WORDS_BIG_ENDIAN
712 int i;
713 UniChar *text = (UniChar *)buf;
715 for (i = 0; i < nchars; i++)
716 text[i] = EndianU16_BtoN (text[i]);
718 #endif
719 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
720 nchars,
721 GC_FONT (gc)->mac_style,
722 &text_layout);
723 if (err == noErr)
725 #ifdef MAC_OSX
726 if (NILP (Vmac_use_core_graphics))
728 #endif
729 mac_begin_clip (GC_CLIP_REGION (gc));
730 MoveTo (x, y);
731 ATSUDrawText (text_layout,
732 kATSUFromTextBeginning, kATSUToTextEnd,
733 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
734 mac_end_clip (GC_CLIP_REGION (gc));
735 #ifdef MAC_OSX
737 else
739 CGrafPtr port;
740 CGContextRef context;
741 float port_height = FRAME_PIXEL_HEIGHT (f);
742 ATSUAttributeTag tags[] = {kATSUCGContextTag};
743 ByteCount sizes[] = {sizeof (CGContextRef)};
744 ATSUAttributeValuePtr values[] = {&context};
746 GetPort (&port);
747 QDBeginCGContext (port, &context);
748 if (gc->n_clip_rects)
750 CGContextTranslateCTM (context, 0, port_height);
751 CGContextScaleCTM (context, 1, -1);
752 CGContextClipToRects (context, gc->clip_rects,
753 gc->n_clip_rects);
754 CGContextScaleCTM (context, 1, -1);
755 CGContextTranslateCTM (context, 0, -port_height);
757 CGContextSetRGBFillColor
758 (context,
759 RED_FROM_ULONG (gc->xgcv.foreground) / 255.0,
760 GREEN_FROM_ULONG (gc->xgcv.foreground) / 255.0,
761 BLUE_FROM_ULONG (gc->xgcv.foreground) / 255.0,
762 1.0);
763 err = ATSUSetLayoutControls (text_layout,
764 sizeof (tags) / sizeof (tags[0]),
765 tags, sizes, values);
766 if (err == noErr)
767 ATSUDrawText (text_layout,
768 kATSUFromTextBeginning, kATSUToTextEnd,
769 Long2Fix (x), Long2Fix (port_height - y));
770 CGContextSynchronize (context);
771 QDEndCGContext (port, &context);
772 #if 0
773 /* This doesn't work on Mac OS X 10.1. */
774 ATSUClearLayoutControls (text_layout,
775 sizeof (tags) / sizeof (tags[0]),
776 tags);
777 #else
778 ATSUSetLayoutControls (text_layout,
779 sizeof (tags) / sizeof (tags[0]),
780 tags, sizes, values);
781 #endif
783 #endif
786 else
788 #endif
789 TextFont (GC_FONT (gc)->mac_fontnum);
790 TextSize (GC_FONT (gc)->mac_fontsize);
791 TextFace (GC_FONT (gc)->mac_fontface);
792 TextMode (mode);
794 mac_begin_clip (GC_CLIP_REGION (gc));
795 MoveTo (x, y);
796 DrawText (buf, 0, nchars * bytes_per_char);
797 mac_end_clip (GC_CLIP_REGION (gc));
798 #if USE_ATSUI
800 #endif
802 if (mode != srcOr)
803 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
804 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
805 if (!NILP(Vmac_use_core_graphics))
806 SwapQDTextFlags(savedFlags);
807 #endif
811 /* Mac replacement for XDrawString. */
813 static void
814 mac_draw_string (f, gc, x, y, buf, nchars)
815 struct frame *f;
816 GC gc;
817 int x, y;
818 char *buf;
819 int nchars;
821 mac_draw_string_common (f, gc, x, y, buf, nchars, srcOr, 1);
825 /* Mac replacement for XDrawString16. */
827 static void
828 mac_draw_string_16 (f, gc, x, y, buf, nchars)
829 struct frame *f;
830 GC gc;
831 int x, y;
832 XChar2b *buf;
833 int nchars;
835 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, srcOr, 2);
839 /* Mac replacement for XDrawImageString. */
841 static void
842 mac_draw_image_string (f, gc, x, y, buf, nchars)
843 struct frame *f;
844 GC gc;
845 int x, y;
846 char *buf;
847 int nchars;
849 mac_draw_string_common (f, gc, x, y, buf, nchars, srcCopy, 1);
853 /* Mac replacement for XDrawString16. */
855 static void
856 mac_draw_image_string_16 (f, gc, x, y, buf, nchars)
857 struct frame *f;
858 GC gc;
859 int x, y;
860 XChar2b *buf;
861 int nchars;
863 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, srcCopy, 2);
867 #if USE_CG_TEXT_DRAWING
868 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
870 static int cg_text_anti_aliasing_threshold = 8;
872 static void
873 init_cg_text_anti_aliasing_threshold ()
875 Lisp_Object val =
876 Fmac_get_preference (build_string ("AppleAntiAliasingThreshold"),
877 Qnil, Qnil, Qnil);
879 if (INTEGERP (val))
880 cg_text_anti_aliasing_threshold = XINT (val);
883 static int
884 mac_draw_string_cg (f, gc, x, y, buf, nchars)
885 struct frame *f;
886 GC gc;
887 int x, y;
888 XChar2b *buf;
889 int nchars;
891 CGrafPtr port;
892 float port_height, gx, gy;
893 int i;
894 CGContextRef context;
895 CGGlyph *glyphs;
896 CGSize *advances;
898 if (NILP (Vmac_use_core_graphics) || GC_FONT (gc)->cg_font == NULL)
899 return 0;
901 port = GetWindowPort (FRAME_MAC_WINDOW (f));
902 port_height = FRAME_PIXEL_HEIGHT (f);
903 gx = x;
904 gy = port_height - y;
905 glyphs = (CGGlyph *)buf;
906 advances = xmalloc (sizeof (CGSize) * nchars);
907 for (i = 0; i < nchars; i++)
909 advances[i].width = x_per_char_metric (GC_FONT (gc), buf)->width;
910 advances[i].height = 0;
911 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
912 buf++;
915 QDBeginCGContext (port, &context);
916 if (gc->n_clip_rects)
918 CGContextTranslateCTM (context, 0, port_height);
919 CGContextScaleCTM (context, 1, -1);
920 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
921 CGContextScaleCTM (context, 1, -1);
922 CGContextTranslateCTM (context, 0, -port_height);
924 CGContextSetRGBFillColor (context,
925 RED_FROM_ULONG (gc->xgcv.foreground) / 255.0,
926 GREEN_FROM_ULONG (gc->xgcv.foreground) / 255.0,
927 BLUE_FROM_ULONG (gc->xgcv.foreground) / 255.0,
928 1.0);
929 CGContextSetFont (context, GC_FONT (gc)->cg_font);
930 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
931 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
932 CGContextSetShouldAntialias (context, false);
933 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
934 CGContextSetTextPosition (context, gx, gy);
935 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
936 #else
937 for (i = 0; i < nchars; i++)
939 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
940 gx += advances[i].width;
942 #endif
943 CGContextSynchronize (context);
944 QDEndCGContext (port, &context);
946 xfree (advances);
948 return 1;
950 #endif
953 /* Mac replacement for XCopyArea: dest must be window. */
955 static void
956 mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
957 Pixmap src;
958 struct frame *f;
959 GC gc;
960 int src_x, src_y;
961 unsigned int width, height;
962 int dest_x, dest_y;
964 Rect src_r, dest_r;
966 SetPortWindowPort (FRAME_MAC_WINDOW (f));
968 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
969 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
971 ForeColor (blackColor);
972 BackColor (whiteColor);
974 mac_begin_clip (GC_CLIP_REGION (gc));
975 LockPixels (GetGWorldPixMap (src));
976 #if TARGET_API_MAC_CARBON
978 CGrafPtr port;
980 GetPort (&port);
981 LockPortBits (port);
982 CopyBits (GetPortBitMapForCopyBits (src),
983 GetPortBitMapForCopyBits (port),
984 &src_r, &dest_r, srcCopy, 0);
985 UnlockPortBits (port);
987 #else /* not TARGET_API_MAC_CARBON */
988 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
989 &src_r, &dest_r, srcCopy, 0);
990 #endif /* not TARGET_API_MAC_CARBON */
991 UnlockPixels (GetGWorldPixMap (src));
992 mac_end_clip (GC_CLIP_REGION (gc));
994 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
998 static void
999 mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
1000 width, height, dest_x, dest_y)
1001 Pixmap src, mask;
1002 struct frame *f;
1003 GC gc;
1004 int src_x, src_y;
1005 unsigned int width, height;
1006 int dest_x, dest_y;
1008 Rect src_r, dest_r;
1010 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1012 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1013 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1015 ForeColor (blackColor);
1016 BackColor (whiteColor);
1018 mac_begin_clip (GC_CLIP_REGION (gc));
1019 LockPixels (GetGWorldPixMap (src));
1020 LockPixels (GetGWorldPixMap (mask));
1021 #if TARGET_API_MAC_CARBON
1023 CGrafPtr port;
1025 GetPort (&port);
1026 LockPortBits (port);
1027 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1028 GetPortBitMapForCopyBits (port),
1029 &src_r, &src_r, &dest_r);
1030 UnlockPortBits (port);
1032 #else /* not TARGET_API_MAC_CARBON */
1033 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
1034 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
1035 #endif /* not TARGET_API_MAC_CARBON */
1036 UnlockPixels (GetGWorldPixMap (mask));
1037 UnlockPixels (GetGWorldPixMap (src));
1038 mac_end_clip (GC_CLIP_REGION (gc));
1040 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1044 /* Mac replacement for XCopyArea: used only for scrolling. */
1046 static void
1047 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1048 struct frame *f;
1049 GC gc;
1050 int src_x, src_y;
1051 unsigned int width, height;
1052 int dest_x, dest_y;
1054 #if TARGET_API_MAC_CARBON
1055 Rect src_r;
1056 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1058 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1059 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1060 &src_r, dest_x - src_x, dest_y - src_y,
1061 kScrollWindowNoOptions, dummy);
1062 DisposeRgn (dummy);
1063 #else /* not TARGET_API_MAC_CARBON */
1064 Rect src_r, dest_r;
1065 WindowPtr w = FRAME_MAC_WINDOW (f);
1067 SetPort (w);
1069 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1070 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1072 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1073 color mapping in CopyBits. Otherwise, it will be slow. */
1074 ForeColor (blackColor);
1075 BackColor (whiteColor);
1076 mac_begin_clip (GC_CLIP_REGION (gc));
1077 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
1078 mac_end_clip (GC_CLIP_REGION (gc));
1080 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1081 #endif /* not TARGET_API_MAC_CARBON */
1085 /* Mac replacement for XChangeGC. */
1087 static void
1088 XChangeGC (display, gc, mask, xgcv)
1089 Display *display;
1090 GC gc;
1091 unsigned long mask;
1092 XGCValues *xgcv;
1094 if (mask & GCForeground)
1095 XSetForeground (display, gc, xgcv->foreground);
1096 if (mask & GCBackground)
1097 XSetBackground (display, gc, xgcv->background);
1098 if (mask & GCFont)
1099 XSetFont (display, gc, xgcv->font);
1103 /* Mac replacement for XCreateGC. */
1106 XCreateGC (display, window, mask, xgcv)
1107 Display *display;
1108 Window window;
1109 unsigned long mask;
1110 XGCValues *xgcv;
1112 GC gc = xmalloc (sizeof (*gc));
1114 if (gc)
1116 bzero (gc, sizeof (*gc));
1117 XChangeGC (display, gc, mask, xgcv);
1120 return gc;
1124 /* Used in xfaces.c. */
1126 void
1127 XFreeGC (display, gc)
1128 Display *display;
1129 GC gc;
1131 if (gc->clip_region)
1132 DisposeRgn (gc->clip_region);
1133 xfree (gc);
1137 /* Mac replacement for XGetGCValues. */
1139 static void
1140 XGetGCValues (display, gc, mask, xgcv)
1141 Display *display;
1142 GC gc;
1143 unsigned long mask;
1144 XGCValues *xgcv;
1146 if (mask & GCForeground)
1147 xgcv->foreground = gc->xgcv.foreground;
1148 if (mask & GCBackground)
1149 xgcv->background = gc->xgcv.background;
1150 if (mask & GCFont)
1151 xgcv->font = gc->xgcv.font;
1155 /* Mac replacement for XSetForeground. */
1157 void
1158 XSetForeground (display, gc, color)
1159 Display *display;
1160 GC gc;
1161 unsigned long color;
1163 if (gc->xgcv.foreground != color)
1165 gc->xgcv.foreground = color;
1166 gc->fore_color.red = RED16_FROM_ULONG (color);
1167 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1168 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
1173 /* Mac replacement for XSetBackground. */
1175 void
1176 XSetBackground (display, gc, color)
1177 Display *display;
1178 GC gc;
1179 unsigned long color;
1181 if (gc->xgcv.background != color)
1183 gc->xgcv.background = color;
1184 gc->back_color.red = RED16_FROM_ULONG (color);
1185 gc->back_color.green = GREEN16_FROM_ULONG (color);
1186 gc->back_color.blue = BLUE16_FROM_ULONG (color);
1191 /* Mac replacement for XSetFont. */
1193 static void
1194 XSetFont (display, gc, font)
1195 Display *display;
1196 GC gc;
1197 XFontStruct *font;
1199 gc->xgcv.font = font;
1203 /* Mac replacement for XSetClipRectangles. */
1205 static void
1206 mac_set_clip_rectangles (display, gc, rectangles, n)
1207 Display *display;
1208 GC gc;
1209 Rect *rectangles;
1210 int n;
1212 int i;
1214 if (n < 0 || n > MAX_CLIP_RECTS)
1215 abort ();
1216 if (n == 0)
1218 if (gc->clip_region)
1220 DisposeRgn (gc->clip_region);
1221 gc->clip_region = NULL;
1224 else
1226 if (gc->clip_region == NULL)
1227 gc->clip_region = NewRgn ();
1228 RectRgn (gc->clip_region, rectangles);
1229 if (n > 1)
1231 RgnHandle region = NewRgn ();
1233 for (i = 1; i < n; i++)
1235 RectRgn (region, rectangles + i);
1236 UnionRgn (gc->clip_region, region, gc->clip_region);
1238 DisposeRgn (region);
1241 #if defined (MAC_OSX) && USE_ATSUI
1242 gc->n_clip_rects = n;
1244 for (i = 0; i < n; i++)
1246 Rect *rect = rectangles + i;
1248 gc->clip_rects[i] = CGRectMake (rect->left, rect->top,
1249 rect->right - rect->left,
1250 rect->bottom - rect->top);
1252 #endif
1256 /* Mac replacement for XSetClipMask. */
1258 static INLINE void
1259 mac_reset_clip_rectangles (display, gc)
1260 Display *display;
1261 GC gc;
1263 mac_set_clip_rectangles (display, gc, NULL, 0);
1267 /* Mac replacement for XSetWindowBackground. */
1269 void
1270 XSetWindowBackground (display, w, color)
1271 Display *display;
1272 WindowPtr w;
1273 unsigned long color;
1275 #if !TARGET_API_MAC_CARBON
1276 AuxWinHandle aw_handle;
1277 CTabHandle ctab_handle;
1278 ColorSpecPtr ct_table;
1279 short ct_size;
1280 #endif
1281 RGBColor bg_color;
1283 bg_color.red = RED16_FROM_ULONG (color);
1284 bg_color.green = GREEN16_FROM_ULONG (color);
1285 bg_color.blue = BLUE16_FROM_ULONG (color);
1287 #if TARGET_API_MAC_CARBON
1288 SetWindowContentColor (w, &bg_color);
1289 #else
1290 if (GetAuxWin (w, &aw_handle))
1292 ctab_handle = (*aw_handle)->awCTable;
1293 HandToHand ((Handle *) &ctab_handle);
1294 ct_table = (*ctab_handle)->ctTable;
1295 ct_size = (*ctab_handle)->ctSize;
1296 while (ct_size > -1)
1298 if (ct_table->value == 0)
1300 ct_table->rgb = bg_color;
1301 CTabChanged (ctab_handle);
1302 SetWinColor (w, (WCTabHandle) ctab_handle);
1304 ct_size--;
1307 #endif
1310 /* x_sync is a no-op on Mac. */
1311 void
1312 x_sync (f)
1313 void *f;
1318 /* Flush display of frame F, or of all frames if F is null. */
1320 static void
1321 x_flush (f)
1322 struct frame *f;
1324 #if TARGET_API_MAC_CARBON
1325 BLOCK_INPUT;
1326 if (f)
1327 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1328 else
1329 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1330 UNBLOCK_INPUT;
1331 #endif
1335 /* Remove calls to XFlush by defining XFlush to an empty replacement.
1336 Calls to XFlush should be unnecessary because the X output buffer
1337 is flushed automatically as needed by calls to XPending,
1338 XNextEvent, or XWindowEvent according to the XFlush man page.
1339 XTread_socket calls XPending. Removing XFlush improves
1340 performance. */
1342 #define XFlush(DISPLAY) (void) 0
1345 /* Return the struct mac_display_info corresponding to DPY. There's
1346 only one. */
1348 struct mac_display_info *
1349 mac_display_info_for_display (dpy)
1350 Display *dpy;
1352 return &one_mac_display_info;
1357 /***********************************************************************
1358 Starting and ending an update
1359 ***********************************************************************/
1361 /* Start an update of frame F. This function is installed as a hook
1362 for update_begin, i.e. it is called when update_begin is called.
1363 This function is called prior to calls to x_update_window_begin for
1364 each window being updated. */
1366 static void
1367 x_update_begin (f)
1368 struct frame *f;
1370 #if TARGET_API_MAC_CARBON
1371 /* During update of a frame, availability of input events is
1372 periodically checked with ReceiveNextEvent if
1373 redisplay-dont-pause is nil. That normally flushes window buffer
1374 changes for every check, and thus screen update looks waving even
1375 if no input is available. So we disable screen updates during
1376 update of a frame. */
1377 BLOCK_INPUT;
1378 DisableScreenUpdates ();
1379 UNBLOCK_INPUT;
1380 #endif
1384 /* Start update of window W. Set the global variable updated_window
1385 to the window being updated and set output_cursor to the cursor
1386 position of W. */
1388 static void
1389 x_update_window_begin (w)
1390 struct window *w;
1392 struct frame *f = XFRAME (WINDOW_FRAME (w));
1393 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
1395 updated_window = w;
1396 set_output_cursor (&w->cursor);
1398 BLOCK_INPUT;
1400 if (f == display_info->mouse_face_mouse_frame)
1402 /* Don't do highlighting for mouse motion during the update. */
1403 display_info->mouse_face_defer = 1;
1405 /* If F needs to be redrawn, simply forget about any prior mouse
1406 highlighting. */
1407 if (FRAME_GARBAGED_P (f))
1408 display_info->mouse_face_window = Qnil;
1410 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
1411 their mouse_face_p flag set, which means that they are always
1412 unequal to rows in a desired matrix which never have that
1413 flag set. So, rows containing mouse-face glyphs are never
1414 scrolled, and we don't have to switch the mouse highlight off
1415 here to prevent it from being scrolled. */
1417 /* Can we tell that this update does not affect the window
1418 where the mouse highlight is? If so, no need to turn off.
1419 Likewise, don't do anything if the frame is garbaged;
1420 in that case, the frame's current matrix that we would use
1421 is all wrong, and we will redisplay that line anyway. */
1422 if (!NILP (display_info->mouse_face_window)
1423 && w == XWINDOW (display_info->mouse_face_window))
1425 int i;
1427 for (i = 0; i < w->desired_matrix->nrows; ++i)
1428 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
1429 break;
1431 if (i < w->desired_matrix->nrows)
1432 clear_mouse_face (display_info);
1434 #endif /* 0 */
1437 UNBLOCK_INPUT;
1441 /* Draw a vertical window border from (x,y0) to (x,y1) */
1443 static void
1444 mac_draw_vertical_window_border (w, x, y0, y1)
1445 struct window *w;
1446 int x, y0, y1;
1448 struct frame *f = XFRAME (WINDOW_FRAME (w));
1449 struct face *face;
1451 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
1452 if (face)
1453 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
1454 face->foreground);
1456 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
1459 /* End update of window W (which is equal to updated_window).
1461 Draw vertical borders between horizontally adjacent windows, and
1462 display W's cursor if CURSOR_ON_P is non-zero.
1464 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
1465 glyphs in mouse-face were overwritten. In that case we have to
1466 make sure that the mouse-highlight is properly redrawn.
1468 W may be a menu bar pseudo-window in case we don't have X toolkit
1469 support. Such windows don't have a cursor, so don't display it
1470 here. */
1472 static void
1473 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
1474 struct window *w;
1475 int cursor_on_p, mouse_face_overwritten_p;
1477 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
1479 if (!w->pseudo_window_p)
1481 BLOCK_INPUT;
1483 if (cursor_on_p)
1484 display_and_set_cursor (w, 1, output_cursor.hpos,
1485 output_cursor.vpos,
1486 output_cursor.x, output_cursor.y);
1488 if (draw_window_fringes (w, 1))
1489 x_draw_vertical_border (w);
1491 UNBLOCK_INPUT;
1494 /* If a row with mouse-face was overwritten, arrange for
1495 XTframe_up_to_date to redisplay the mouse highlight. */
1496 if (mouse_face_overwritten_p)
1498 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1499 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1500 dpyinfo->mouse_face_window = Qnil;
1503 updated_window = NULL;
1507 /* End update of frame F. This function is installed as a hook in
1508 update_end. */
1510 static void
1511 x_update_end (f)
1512 struct frame *f;
1514 /* Mouse highlight may be displayed again. */
1515 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
1517 BLOCK_INPUT;
1518 #if TARGET_API_MAC_CARBON
1519 EnableScreenUpdates ();
1520 #endif
1521 XFlush (FRAME_MAC_DISPLAY (f));
1522 UNBLOCK_INPUT;
1526 /* This function is called from various places in xdisp.c whenever a
1527 complete update has been performed. The global variable
1528 updated_window is not available here. */
1530 static void
1531 XTframe_up_to_date (f)
1532 struct frame *f;
1534 if (FRAME_MAC_P (f))
1536 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1538 if (dpyinfo->mouse_face_deferred_gc
1539 || f == dpyinfo->mouse_face_mouse_frame)
1541 BLOCK_INPUT;
1542 if (dpyinfo->mouse_face_mouse_frame)
1543 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1544 dpyinfo->mouse_face_mouse_x,
1545 dpyinfo->mouse_face_mouse_y);
1546 dpyinfo->mouse_face_deferred_gc = 0;
1547 UNBLOCK_INPUT;
1553 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1554 arrow bitmaps, or clear the fringes if no bitmaps are required
1555 before DESIRED_ROW is made current. The window being updated is
1556 found in updated_window. This function is called from
1557 update_window_line only if it is known that there are differences
1558 between bitmaps to be drawn between current row and DESIRED_ROW. */
1560 static void
1561 x_after_update_window_line (desired_row)
1562 struct glyph_row *desired_row;
1564 struct window *w = updated_window;
1565 struct frame *f;
1566 int width, height;
1568 xassert (w);
1570 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1571 desired_row->redraw_fringe_bitmaps_p = 1;
1573 /* When a window has disappeared, make sure that no rest of
1574 full-width rows stays visible in the internal border. Could
1575 check here if updated_window is the leftmost/rightmost window,
1576 but I guess it's not worth doing since vertically split windows
1577 are almost never used, internal border is rarely set, and the
1578 overhead is very small. */
1579 if (windows_or_buffers_changed
1580 && desired_row->full_width_p
1581 && (f = XFRAME (w->frame),
1582 width = FRAME_INTERNAL_BORDER_WIDTH (f),
1583 width != 0)
1584 && (height = desired_row->visible_height,
1585 height > 0))
1587 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1589 /* Internal border is drawn below the tool bar. */
1590 if (WINDOWP (f->tool_bar_window)
1591 && w == XWINDOW (f->tool_bar_window))
1592 y -= width;
1594 BLOCK_INPUT;
1595 mac_clear_area (f, 0, y, width, height);
1596 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1597 UNBLOCK_INPUT;
1602 /* Draw the bitmap WHICH in one of the left or right fringes of
1603 window W. ROW is the glyph row for which to display the bitmap; it
1604 determines the vertical position at which the bitmap has to be
1605 drawn. */
1607 static void
1608 x_draw_fringe_bitmap (w, row, p)
1609 struct window *w;
1610 struct glyph_row *row;
1611 struct draw_fringe_bitmap_params *p;
1613 struct frame *f = XFRAME (WINDOW_FRAME (w));
1614 Display *display = FRAME_MAC_DISPLAY (f);
1615 struct face *face = p->face;
1616 int rowY;
1618 /* Must clip because of partially visible lines. */
1619 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
1620 if (p->y < rowY)
1622 /* Adjust position of "bottom aligned" bitmap on partially
1623 visible last row. */
1624 int oldY = row->y;
1625 int oldVH = row->visible_height;
1626 row->visible_height = p->h;
1627 row->y -= rowY - p->y;
1628 x_clip_to_row (w, row, -1, face->gc);
1629 row->y = oldY;
1630 row->visible_height = oldVH;
1632 else
1633 x_clip_to_row (w, row, -1, face->gc);
1635 if (p->bx >= 0 && !p->overlay_p)
1637 #if 0 /* MAC_TODO: stipple */
1638 /* In case the same realized face is used for fringes and
1639 for something displayed in the text (e.g. face `region' on
1640 mono-displays, the fill style may have been changed to
1641 FillSolid in x_draw_glyph_string_background. */
1642 if (face->stipple)
1643 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1644 else
1645 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
1646 #endif
1648 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
1650 #if 0 /* MAC_TODO: stipple */
1651 if (!face->stipple)
1652 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
1653 #endif
1656 if (p->which)
1658 unsigned short *bits = p->bits + p->dh;
1659 XGCValues gcv;
1661 XGetGCValues (display, face->gc, GCForeground, &gcv);
1662 XSetForeground (display, face->gc,
1663 (p->cursor_p
1664 ? (p->overlay_p ? face->background
1665 : f->output_data.mac->cursor_pixel)
1666 : face->foreground));
1667 mac_draw_bitmap (f, face->gc, p->x, p->y,
1668 p->wd, p->h, bits, p->overlay_p);
1669 XSetForeground (display, face->gc, gcv.foreground);
1672 mac_reset_clip_rectangles (display, face->gc);
1677 /* This is called when starting Emacs and when restarting after
1678 suspend. When starting Emacs, no window is mapped. And nothing
1679 must be done to Emacs's own window if it is suspended (though that
1680 rarely happens). */
1682 static void
1683 XTset_terminal_modes ()
1687 /* This is called when exiting or suspending Emacs. Exiting will make
1688 the windows go away, and suspending requires no action. */
1690 static void
1691 XTreset_terminal_modes ()
1697 /***********************************************************************
1698 Display Iterator
1699 ***********************************************************************/
1701 /* Function prototypes of this page. */
1703 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1704 static int mac_encode_char P_ ((int, XChar2b *, struct font_info *, int *));
1707 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1708 is not contained in the font. */
1710 static INLINE XCharStruct *
1711 x_per_char_metric (font, char2b)
1712 XFontStruct *font;
1713 XChar2b *char2b;
1715 /* The result metric information. */
1716 XCharStruct *pcm = NULL;
1718 xassert (font && char2b);
1720 #if USE_ATSUI
1721 if (font->mac_style)
1723 if (char2b->byte1 >= font->min_byte1
1724 && char2b->byte1 <= font->max_byte1
1725 && char2b->byte2 >= font->min_char_or_byte2
1726 && char2b->byte2 <= font->max_char_or_byte2)
1728 pcm = (font->per_char
1729 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1730 * (char2b->byte1 - font->min_byte1))
1731 + (char2b->byte2 - font->min_char_or_byte2));
1734 if (pcm && !pcm->valid_p)
1736 OSErr err;
1737 ATSUTextLayout text_layout;
1738 UniChar c;
1739 int char_width;
1740 ATSTrapezoid glyph_bounds;
1741 Rect char_bounds;
1743 c = (char2b->byte1 << 8) + char2b->byte2;
1744 BLOCK_INPUT;
1745 err = atsu_get_text_layout_with_text_ptr (&c, 1,
1746 font->mac_style,
1747 &text_layout);
1748 if (err == noErr)
1749 err = ATSUMeasureTextImage (text_layout,
1750 kATSUFromTextBeginning, kATSUToTextEnd,
1751 0, 0, &char_bounds);
1753 if (err == noErr)
1754 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1755 kATSUFromTextBeginning, kATSUToTextEnd,
1756 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1757 kATSUseFractionalOrigins,
1758 #else
1759 kATSUseDeviceOrigins,
1760 #endif
1761 1, &glyph_bounds, NULL);
1762 UNBLOCK_INPUT;
1763 if (err != noErr)
1764 pcm = NULL;
1765 else
1767 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1768 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1770 char_width = Fix2Long (glyph_bounds.upperRight.x
1771 - glyph_bounds.upperLeft.x);
1772 STORE_XCHARSTRUCT (*pcm, char_width, char_bounds);
1776 else
1778 #endif
1779 if (font->per_char != NULL)
1781 if (font->min_byte1 == 0 && font->max_byte1 == 0)
1783 /* min_char_or_byte2 specifies the linear character index
1784 corresponding to the first element of the per_char array,
1785 max_char_or_byte2 is the index of the last character. A
1786 character with non-zero CHAR2B->byte1 is not in the font.
1787 A character with byte2 less than min_char_or_byte2 or
1788 greater max_char_or_byte2 is not in the font. */
1789 if (char2b->byte1 == 0
1790 && char2b->byte2 >= font->min_char_or_byte2
1791 && char2b->byte2 <= font->max_char_or_byte2)
1792 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
1794 else
1796 /* If either min_byte1 or max_byte1 are nonzero, both
1797 min_char_or_byte2 and max_char_or_byte2 are less than
1798 256, and the 2-byte character index values corresponding
1799 to the per_char array element N (counting from 0) are:
1801 byte1 = N/D + min_byte1
1802 byte2 = N\D + min_char_or_byte2
1804 where:
1806 D = max_char_or_byte2 - min_char_or_byte2 + 1
1807 / = integer division
1808 \ = integer modulus */
1809 if (char2b->byte1 >= font->min_byte1
1810 && char2b->byte1 <= font->max_byte1
1811 && char2b->byte2 >= font->min_char_or_byte2
1812 && char2b->byte2 <= font->max_char_or_byte2)
1814 pcm = (font->per_char
1815 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1816 * (char2b->byte1 - font->min_byte1))
1817 + (char2b->byte2 - font->min_char_or_byte2));
1821 else
1823 /* If the per_char pointer is null, all glyphs between the first
1824 and last character indexes inclusive have the same
1825 information, as given by both min_bounds and max_bounds. */
1826 if (char2b->byte2 >= font->min_char_or_byte2
1827 && char2b->byte2 <= font->max_char_or_byte2)
1828 pcm = &font->max_bounds;
1830 #if USE_ATSUI
1832 #endif
1834 return ((pcm == NULL
1835 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
1836 ? NULL : pcm);
1839 /* RIF:
1842 static XCharStruct *
1843 mac_per_char_metric (font, char2b, font_type)
1844 XFontStruct *font;
1845 XChar2b *char2b;
1846 int font_type;
1848 return x_per_char_metric (font, char2b);
1851 /* RIF:
1852 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1853 the two-byte form of C. Encoding is returned in *CHAR2B. */
1855 static int
1856 mac_encode_char (c, char2b, font_info, two_byte_p)
1857 int c;
1858 XChar2b *char2b;
1859 struct font_info *font_info;
1860 int *two_byte_p;
1862 int charset = CHAR_CHARSET (c);
1863 XFontStruct *font = font_info->font;
1865 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1866 This may be either a program in a special encoder language or a
1867 fixed encoding. */
1868 if (font_info->font_encoder)
1870 /* It's a program. */
1871 struct ccl_program *ccl = font_info->font_encoder;
1873 check_ccl_update (ccl);
1874 if (CHARSET_DIMENSION (charset) == 1)
1876 ccl->reg[0] = charset;
1877 ccl->reg[1] = char2b->byte2;
1878 ccl->reg[2] = -1;
1880 else
1882 ccl->reg[0] = charset;
1883 ccl->reg[1] = char2b->byte1;
1884 ccl->reg[2] = char2b->byte2;
1887 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1889 /* We assume that MSBs are appropriately set/reset by CCL
1890 program. */
1891 if (font->max_byte1 == 0) /* 1-byte font */
1892 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
1893 else
1894 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1896 else if (font_info->encoding[charset])
1898 /* Fixed encoding scheme. See fontset.h for the meaning of the
1899 encoding numbers. */
1900 int enc = font_info->encoding[charset];
1902 if ((enc == 1 || enc == 2)
1903 && CHARSET_DIMENSION (charset) == 2)
1904 char2b->byte1 |= 0x80;
1906 if (enc == 1 || enc == 3)
1907 char2b->byte2 |= 0x80;
1909 if (enc == 4)
1911 int sjis1, sjis2;
1913 ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2);
1914 char2b->byte1 = sjis1;
1915 char2b->byte2 = sjis2;
1919 if (two_byte_p)
1920 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
1922 return FONT_TYPE_UNKNOWN;
1927 /***********************************************************************
1928 Glyph display
1929 ***********************************************************************/
1933 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
1934 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
1935 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
1936 int));
1937 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
1938 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
1939 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
1940 static void x_draw_glyph_string P_ ((struct glyph_string *));
1941 static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
1942 static void x_set_cursor_gc P_ ((struct glyph_string *));
1943 static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
1944 static void x_set_mouse_face_gc P_ ((struct glyph_string *));
1945 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
1946 unsigned long *, double, int));*/
1947 static void x_setup_relief_color P_ ((struct frame *, struct relief *,
1948 double, int, unsigned long));
1949 static void x_setup_relief_colors P_ ((struct glyph_string *));
1950 static void x_draw_image_glyph_string P_ ((struct glyph_string *));
1951 static void x_draw_image_relief P_ ((struct glyph_string *));
1952 static void x_draw_image_foreground P_ ((struct glyph_string *));
1953 static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
1954 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
1955 int, int, int));
1956 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
1957 int, int, int, int, int, int,
1958 Rect *));
1959 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
1960 int, int, int, Rect *));
1962 #if GLYPH_DEBUG
1963 static void x_check_font P_ ((struct frame *, XFontStruct *));
1964 #endif
1967 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
1968 face. */
1970 static void
1971 x_set_cursor_gc (s)
1972 struct glyph_string *s;
1974 if (s->font == FRAME_FONT (s->f)
1975 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1976 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
1977 && !s->cmp)
1978 s->gc = s->f->output_data.mac->cursor_gc;
1979 else
1981 /* Cursor on non-default face: must merge. */
1982 XGCValues xgcv;
1983 unsigned long mask;
1985 xgcv.background = s->f->output_data.mac->cursor_pixel;
1986 xgcv.foreground = s->face->background;
1988 /* If the glyph would be invisible, try a different foreground. */
1989 if (xgcv.foreground == xgcv.background)
1990 xgcv.foreground = s->face->foreground;
1991 if (xgcv.foreground == xgcv.background)
1992 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
1993 if (xgcv.foreground == xgcv.background)
1994 xgcv.foreground = s->face->foreground;
1996 /* Make sure the cursor is distinct from text in this face. */
1997 if (xgcv.background == s->face->background
1998 && xgcv.foreground == s->face->foreground)
2000 xgcv.background = s->face->foreground;
2001 xgcv.foreground = s->face->background;
2004 IF_DEBUG (x_check_font (s->f, s->font));
2005 xgcv.font = s->font;
2006 mask = GCForeground | GCBackground | GCFont;
2008 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2009 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2010 mask, &xgcv);
2011 else
2012 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2013 = XCreateGC (s->display, s->window, mask, &xgcv);
2015 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2020 /* Set up S->gc of glyph string S for drawing text in mouse face. */
2022 static void
2023 x_set_mouse_face_gc (s)
2024 struct glyph_string *s;
2026 int face_id;
2027 struct face *face;
2029 /* What face has to be used last for the mouse face? */
2030 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2031 face = FACE_FROM_ID (s->f, face_id);
2032 if (face == NULL)
2033 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2035 if (s->first_glyph->type == CHAR_GLYPH)
2036 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2037 else
2038 face_id = FACE_FOR_CHAR (s->f, face, 0);
2039 s->face = FACE_FROM_ID (s->f, face_id);
2040 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2042 /* If font in this face is same as S->font, use it. */
2043 if (s->font == s->face->font)
2044 s->gc = s->face->gc;
2045 else
2047 /* Otherwise construct scratch_cursor_gc with values from FACE
2048 but font FONT. */
2049 XGCValues xgcv;
2050 unsigned long mask;
2052 xgcv.background = s->face->background;
2053 xgcv.foreground = s->face->foreground;
2054 IF_DEBUG (x_check_font (s->f, s->font));
2055 xgcv.font = s->font;
2056 mask = GCForeground | GCBackground | GCFont;
2058 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2059 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2060 mask, &xgcv);
2061 else
2062 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2063 = XCreateGC (s->display, s->window, mask, &xgcv);
2065 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2068 xassert (s->gc != 0);
2072 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2073 Faces to use in the mode line have already been computed when the
2074 matrix was built, so there isn't much to do, here. */
2076 static INLINE void
2077 x_set_mode_line_face_gc (s)
2078 struct glyph_string *s;
2080 s->gc = s->face->gc;
2084 /* Set S->gc of glyph string S for drawing that glyph string. Set
2085 S->stippled_p to a non-zero value if the face of S has a stipple
2086 pattern. */
2088 static INLINE void
2089 x_set_glyph_string_gc (s)
2090 struct glyph_string *s;
2092 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2094 if (s->hl == DRAW_NORMAL_TEXT)
2096 s->gc = s->face->gc;
2097 s->stippled_p = s->face->stipple != 0;
2099 else if (s->hl == DRAW_INVERSE_VIDEO)
2101 x_set_mode_line_face_gc (s);
2102 s->stippled_p = s->face->stipple != 0;
2104 else if (s->hl == DRAW_CURSOR)
2106 x_set_cursor_gc (s);
2107 s->stippled_p = 0;
2109 else if (s->hl == DRAW_MOUSE_FACE)
2111 x_set_mouse_face_gc (s);
2112 s->stippled_p = s->face->stipple != 0;
2114 else if (s->hl == DRAW_IMAGE_RAISED
2115 || s->hl == DRAW_IMAGE_SUNKEN)
2117 s->gc = s->face->gc;
2118 s->stippled_p = s->face->stipple != 0;
2120 else
2122 s->gc = s->face->gc;
2123 s->stippled_p = s->face->stipple != 0;
2126 /* GC must have been set. */
2127 xassert (s->gc != 0);
2131 /* Set clipping for output of glyph string S. S may be part of a mode
2132 line or menu if we don't have X toolkit support. */
2134 static INLINE void
2135 x_set_glyph_string_clipping (s)
2136 struct glyph_string *s;
2138 Rect rects[MAX_CLIP_RECTS];
2139 int n;
2141 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
2142 mac_set_clip_rectangles (s->display, s->gc, rects, n);
2146 /* RIF:
2147 Compute left and right overhang of glyph string S. If S is a glyph
2148 string for a composition, assume overhangs don't exist. */
2150 static void
2151 mac_compute_glyph_string_overhangs (s)
2152 struct glyph_string *s;
2154 if (s->cmp == NULL
2155 && s->first_glyph->type == CHAR_GLYPH)
2157 Rect r;
2158 MacFontStruct *font = s->font;
2160 #if USE_ATSUI
2161 if (font->mac_style)
2163 OSErr err;
2164 ATSUTextLayout text_layout;
2165 UniChar *buf;
2166 int i;
2168 SetRect (&r, 0, 0, 0, 0);
2169 buf = xmalloc (sizeof (UniChar) * s->nchars);
2170 if (buf)
2172 for (i = 0; i < s->nchars; i++)
2173 buf[i] = (s->char2b[i].byte1 << 8) + s->char2b[i].byte2;
2175 err = atsu_get_text_layout_with_text_ptr (buf, s->nchars,
2176 font->mac_style,
2177 &text_layout);
2178 if (err == noErr)
2179 err = ATSUMeasureTextImage (text_layout,
2180 kATSUFromTextBeginning,
2181 kATSUToTextEnd,
2182 0, 0, &r);
2183 xfree (buf);
2186 else
2188 #endif
2189 TextFont (font->mac_fontnum);
2190 TextSize (font->mac_fontsize);
2191 TextFace (font->mac_fontface);
2193 if (s->two_byte_p)
2194 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
2195 else
2197 int i;
2198 char *buf = xmalloc (s->nchars);
2200 if (buf == NULL)
2201 SetRect (&r, 0, 0, 0, 0);
2202 else
2204 for (i = 0; i < s->nchars; ++i)
2205 buf[i] = s->char2b[i].byte2;
2206 QDTextBounds (s->nchars, buf, &r);
2207 xfree (buf);
2210 #if USE_ATSUI
2212 #endif
2214 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
2215 s->left_overhang = r.left < 0 ? -r.left : 0;
2220 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
2222 static INLINE void
2223 x_clear_glyph_string_rect (s, x, y, w, h)
2224 struct glyph_string *s;
2225 int x, y, w, h;
2227 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
2231 /* We prefer not to use XDrawImageString (srcCopy text transfer mode)
2232 on Mac OS X because:
2233 - Screen is double-buffered. (In srcCopy mode, a text is drawn
2234 into an offscreen graphics world first. So performance gain
2235 cannot be expected.)
2236 - It lowers rendering quality.
2237 - Some fonts leave garbage on cursor movement. */
2239 /* Draw the background of glyph_string S. If S->background_filled_p
2240 is non-zero don't draw it. FORCE_P non-zero means draw the
2241 background even if it wouldn't be drawn normally. This is used
2242 when a string preceding S draws into the background of S, or S
2243 contains the first component of a composition. */
2245 static void
2246 x_draw_glyph_string_background (s, force_p)
2247 struct glyph_string *s;
2248 int force_p;
2250 /* Nothing to do if background has already been drawn or if it
2251 shouldn't be drawn in the first place. */
2252 if (!s->background_filled_p)
2254 int box_line_width = max (s->face->box_line_width, 0);
2256 #if 0 /* MAC_TODO: stipple */
2257 if (s->stippled_p)
2259 /* Fill background with a stipple pattern. */
2260 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2261 XFillRectangle (s->display, s->window, s->gc, s->x,
2262 s->y + box_line_width,
2263 s->background_width,
2264 s->height - 2 * box_line_width);
2265 XSetFillStyle (s->display, s->gc, FillSolid);
2266 s->background_filled_p = 1;
2268 else
2269 #endif
2270 #if defined (MAC_OS8) && !USE_ATSUI
2271 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2272 || s->font_not_found_p
2273 || s->extends_to_end_of_line_p
2274 || force_p)
2275 #endif
2277 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
2278 s->background_width,
2279 s->height - 2 * box_line_width);
2280 s->background_filled_p = 1;
2286 /* Draw the foreground of glyph string S. */
2288 static void
2289 x_draw_glyph_string_foreground (s)
2290 struct glyph_string *s;
2292 int i, x;
2294 /* If first glyph of S has a left box line, start drawing the text
2295 of S to the right of that box line. */
2296 if (s->face->box != FACE_NO_BOX
2297 && s->first_glyph->left_box_line_p)
2298 x = s->x + abs (s->face->box_line_width);
2299 else
2300 x = s->x;
2302 /* Draw characters of S as rectangles if S's font could not be
2303 loaded. */
2304 if (s->font_not_found_p)
2306 for (i = 0; i < s->nchars; ++i)
2308 struct glyph *g = s->first_glyph + i;
2309 mac_draw_rectangle (s->f, s->gc, x, s->y,
2310 g->pixel_width - 1, s->height - 1);
2311 x += g->pixel_width;
2314 else
2316 char *char1b = (char *) s->char2b;
2317 int boff = s->font_info->baseline_offset;
2319 if (s->font_info->vertical_centering)
2320 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
2322 /* If we can use 8-bit functions, condense S->char2b. */
2323 if (!s->two_byte_p
2324 #if USE_ATSUI
2325 && GC_FONT (s->gc)->mac_style == NULL
2326 #endif
2328 for (i = 0; i < s->nchars; ++i)
2329 char1b[i] = s->char2b[i].byte2;
2331 #if defined (MAC_OS8) && !USE_ATSUI
2332 /* Draw text with XDrawString if background has already been
2333 filled. Otherwise, use XDrawImageString. (Note that
2334 XDrawImageString is usually faster than XDrawString.) Always
2335 use XDrawImageString when drawing the cursor so that there is
2336 no chance that characters under a box cursor are invisible. */
2337 if (s->for_overlaps
2338 || (s->background_filled_p && s->hl != DRAW_CURSOR))
2339 #endif
2341 /* Draw characters with 16-bit or 8-bit functions. */
2342 if (s->two_byte_p
2343 #if USE_ATSUI
2344 || GC_FONT (s->gc)->mac_style
2345 #endif
2347 #if USE_CG_TEXT_DRAWING
2348 if (!s->two_byte_p
2349 && mac_draw_string_cg (s->f, s->gc, x, s->ybase - boff,
2350 s->char2b, s->nchars))
2352 else
2353 #endif
2354 mac_draw_string_16 (s->f, s->gc, x, s->ybase - boff,
2355 s->char2b, s->nchars);
2356 else
2357 mac_draw_string (s->f, s->gc, x, s->ybase - boff,
2358 char1b, s->nchars);
2360 #if defined (MAC_OS8) && !USE_ATSUI
2361 else
2363 if (s->two_byte_p)
2364 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
2365 s->char2b, s->nchars);
2366 else
2367 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
2368 char1b, s->nchars);
2370 #endif
2374 /* Draw the foreground of composite glyph string S. */
2376 static void
2377 x_draw_composite_glyph_string_foreground (s)
2378 struct glyph_string *s;
2380 int i, x;
2382 /* If first glyph of S has a left box line, start drawing the text
2383 of S to the right of that box line. */
2384 if (s->face->box != FACE_NO_BOX
2385 && s->first_glyph->left_box_line_p)
2386 x = s->x + abs (s->face->box_line_width);
2387 else
2388 x = s->x;
2390 /* S is a glyph string for a composition. S->gidx is the index of
2391 the first character drawn for glyphs of this composition.
2392 S->gidx == 0 means we are drawing the very first character of
2393 this composition. */
2395 /* Draw a rectangle for the composition if the font for the very
2396 first character of the composition could not be loaded. */
2397 if (s->font_not_found_p)
2399 if (s->gidx == 0)
2400 mac_draw_rectangle (s->f, s->gc, x, s->y,
2401 s->width - 1, s->height - 1);
2403 else
2405 for (i = 0; i < s->nchars; i++, ++s->gidx)
2406 mac_draw_string_16 (s->f, s->gc,
2407 x + s->cmp->offsets[s->gidx * 2],
2408 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
2409 s->char2b + i, 1);
2414 #ifdef USE_X_TOOLKIT
2416 static struct frame *x_frame_of_widget P_ ((Widget));
2419 /* Return the frame on which widget WIDGET is used.. Abort if frame
2420 cannot be determined. */
2422 static struct frame *
2423 x_frame_of_widget (widget)
2424 Widget widget;
2426 struct x_display_info *dpyinfo;
2427 Lisp_Object tail;
2428 struct frame *f;
2430 dpyinfo = x_display_info_for_display (XtDisplay (widget));
2432 /* Find the top-level shell of the widget. Note that this function
2433 can be called when the widget is not yet realized, so XtWindow
2434 (widget) == 0. That's the reason we can't simply use
2435 x_any_window_to_frame. */
2436 while (!XtIsTopLevelShell (widget))
2437 widget = XtParent (widget);
2439 /* Look for a frame with that top-level widget. Allocate the color
2440 on that frame to get the right gamma correction value. */
2441 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
2442 if (GC_FRAMEP (XCAR (tail))
2443 && (f = XFRAME (XCAR (tail)),
2444 (f->output_data.nothing != 1
2445 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
2446 && f->output_data.x->widget == widget)
2447 return f;
2449 abort ();
2453 /* Allocate the color COLOR->pixel on the screen and display of
2454 widget WIDGET in colormap CMAP. If an exact match cannot be
2455 allocated, try the nearest color available. Value is non-zero
2456 if successful. This is called from lwlib. */
2459 x_alloc_nearest_color_for_widget (widget, cmap, color)
2460 Widget widget;
2461 Colormap cmap;
2462 XColor *color;
2464 struct frame *f = x_frame_of_widget (widget);
2465 return x_alloc_nearest_color (f, cmap, color);
2469 #endif /* USE_X_TOOLKIT */
2471 #if 0 /* MAC_TODO */
2473 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
2474 CMAP. If an exact match can't be allocated, try the nearest color
2475 available. Value is non-zero if successful. Set *COLOR to the
2476 color allocated. */
2479 x_alloc_nearest_color (f, cmap, color)
2480 struct frame *f;
2481 Colormap cmap;
2482 XColor *color;
2484 Display *display = FRAME_X_DISPLAY (f);
2485 Screen *screen = FRAME_X_SCREEN (f);
2486 int rc;
2488 gamma_correct (f, color);
2489 rc = XAllocColor (display, cmap, color);
2490 if (rc == 0)
2492 /* If we got to this point, the colormap is full, so we're going
2493 to try to get the next closest color. The algorithm used is
2494 a least-squares matching, which is what X uses for closest
2495 color matching with StaticColor visuals. */
2496 int nearest, i;
2497 unsigned long nearest_delta = ~0;
2498 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
2499 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
2501 for (i = 0; i < ncells; ++i)
2502 cells[i].pixel = i;
2503 XQueryColors (display, cmap, cells, ncells);
2505 for (nearest = i = 0; i < ncells; ++i)
2507 long dred = (color->red >> 8) - (cells[i].red >> 8);
2508 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
2509 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
2510 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
2512 if (delta < nearest_delta)
2514 nearest = i;
2515 nearest_delta = delta;
2519 color->red = cells[nearest].red;
2520 color->green = cells[nearest].green;
2521 color->blue = cells[nearest].blue;
2522 rc = XAllocColor (display, cmap, color);
2525 #ifdef DEBUG_X_COLORS
2526 if (rc)
2527 register_color (color->pixel);
2528 #endif /* DEBUG_X_COLORS */
2530 return rc;
2534 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
2535 It's necessary to do this instead of just using PIXEL directly to
2536 get color reference counts right. */
2538 unsigned long
2539 x_copy_color (f, pixel)
2540 struct frame *f;
2541 unsigned long pixel;
2543 XColor color;
2545 color.pixel = pixel;
2546 BLOCK_INPUT;
2547 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
2548 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
2549 UNBLOCK_INPUT;
2550 #ifdef DEBUG_X_COLORS
2551 register_color (pixel);
2552 #endif
2553 return color.pixel;
2557 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
2558 It's necessary to do this instead of just using PIXEL directly to
2559 get color reference counts right. */
2561 unsigned long
2562 x_copy_dpy_color (dpy, cmap, pixel)
2563 Display *dpy;
2564 Colormap cmap;
2565 unsigned long pixel;
2567 XColor color;
2569 color.pixel = pixel;
2570 BLOCK_INPUT;
2571 XQueryColor (dpy, cmap, &color);
2572 XAllocColor (dpy, cmap, &color);
2573 UNBLOCK_INPUT;
2574 #ifdef DEBUG_X_COLORS
2575 register_color (pixel);
2576 #endif
2577 return color.pixel;
2580 #endif /* MAC_TODO */
2583 /* Brightness beyond which a color won't have its highlight brightness
2584 boosted.
2586 Nominally, highlight colors for `3d' faces are calculated by
2587 brightening an object's color by a constant scale factor, but this
2588 doesn't yield good results for dark colors, so for colors who's
2589 brightness is less than this value (on a scale of 0-255) have to
2590 use an additional additive factor.
2592 The value here is set so that the default menu-bar/mode-line color
2593 (grey75) will not have its highlights changed at all. */
2594 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
2597 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
2598 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2599 If this produces the same color as COLOR, try a color where all RGB
2600 values have DELTA added. Return the allocated color in *COLOR.
2601 DISPLAY is the X display, CMAP is the colormap to operate on.
2602 Value is non-zero if successful. */
2604 static int
2605 mac_alloc_lighter_color (f, color, factor, delta)
2606 struct frame *f;
2607 unsigned long *color;
2608 double factor;
2609 int delta;
2611 unsigned long new;
2612 long bright;
2614 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
2615 delta /= 256;
2617 /* Change RGB values by specified FACTOR. Avoid overflow! */
2618 xassert (factor >= 0);
2619 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
2620 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
2621 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
2623 /* Calculate brightness of COLOR. */
2624 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
2625 + BLUE_FROM_ULONG (*color)) / 6;
2627 /* We only boost colors that are darker than
2628 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
2629 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
2630 /* Make an additive adjustment to NEW, because it's dark enough so
2631 that scaling by FACTOR alone isn't enough. */
2633 /* How far below the limit this color is (0 - 1, 1 being darker). */
2634 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
2635 /* The additive adjustment. */
2636 int min_delta = delta * dimness * factor / 2;
2638 if (factor < 1)
2639 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
2640 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
2641 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
2642 else
2643 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
2644 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
2645 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
2648 if (new == *color)
2649 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
2650 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
2651 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
2653 /* MAC_TODO: Map to palette and retry with delta if same? */
2654 /* MAC_TODO: Free colors (if using palette)? */
2656 if (new == *color)
2657 return 0;
2659 *color = new;
2661 return 1;
2665 /* Set up the foreground color for drawing relief lines of glyph
2666 string S. RELIEF is a pointer to a struct relief containing the GC
2667 with which lines will be drawn. Use a color that is FACTOR or
2668 DELTA lighter or darker than the relief's background which is found
2669 in S->f->output_data.x->relief_background. If such a color cannot
2670 be allocated, use DEFAULT_PIXEL, instead. */
2672 static void
2673 x_setup_relief_color (f, relief, factor, delta, default_pixel)
2674 struct frame *f;
2675 struct relief *relief;
2676 double factor;
2677 int delta;
2678 unsigned long default_pixel;
2680 XGCValues xgcv;
2681 struct mac_output *di = f->output_data.mac;
2682 unsigned long mask = GCForeground;
2683 unsigned long pixel;
2684 unsigned long background = di->relief_background;
2685 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2687 /* MAC_TODO: Free colors (if using palette)? */
2689 /* Allocate new color. */
2690 xgcv.foreground = default_pixel;
2691 pixel = background;
2692 if (dpyinfo->n_planes != 1
2693 && mac_alloc_lighter_color (f, &pixel, factor, delta))
2695 relief->allocated_p = 1;
2696 xgcv.foreground = relief->pixel = pixel;
2699 if (relief->gc == 0)
2701 #if 0 /* MAC_TODO: stipple */
2702 xgcv.stipple = dpyinfo->gray;
2703 mask |= GCStipple;
2704 #endif
2705 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
2707 else
2708 XChangeGC (NULL, relief->gc, mask, &xgcv);
2712 /* Set up colors for the relief lines around glyph string S. */
2714 static void
2715 x_setup_relief_colors (s)
2716 struct glyph_string *s;
2718 struct mac_output *di = s->f->output_data.mac;
2719 unsigned long color;
2721 if (s->face->use_box_color_for_shadows_p)
2722 color = s->face->box_color;
2723 else if (s->first_glyph->type == IMAGE_GLYPH
2724 && s->img->pixmap
2725 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2726 color = IMAGE_BACKGROUND (s->img, s->f, 0);
2727 else
2729 XGCValues xgcv;
2731 /* Get the background color of the face. */
2732 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
2733 color = xgcv.background;
2736 if (di->white_relief.gc == 0
2737 || color != di->relief_background)
2739 di->relief_background = color;
2740 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
2741 WHITE_PIX_DEFAULT (s->f));
2742 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
2743 BLACK_PIX_DEFAULT (s->f));
2748 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
2749 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
2750 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
2751 relief. LEFT_P non-zero means draw a relief on the left side of
2752 the rectangle. RIGHT_P non-zero means draw a relief on the right
2753 side of the rectangle. CLIP_RECT is the clipping rectangle to use
2754 when drawing. */
2756 static void
2757 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
2758 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
2759 struct frame *f;
2760 int left_x, top_y, right_x, bottom_y, width;
2761 int top_p, bot_p, left_p, right_p, raised_p;
2762 Rect *clip_rect;
2764 Display *dpy = FRAME_MAC_DISPLAY (f);
2765 int i;
2766 GC gc;
2768 if (raised_p)
2769 gc = f->output_data.mac->white_relief.gc;
2770 else
2771 gc = f->output_data.mac->black_relief.gc;
2772 mac_set_clip_rectangles (dpy, gc, clip_rect, 1);
2774 /* Top. */
2775 if (top_p)
2776 for (i = 0; i < width; ++i)
2777 mac_draw_line (f, gc,
2778 left_x + i * left_p, top_y + i,
2779 right_x - i * right_p, top_y + i);
2781 /* Left. */
2782 if (left_p)
2783 for (i = 0; i < width; ++i)
2784 mac_draw_line (f, gc,
2785 left_x + i, top_y + i, left_x + i, bottom_y - i);
2787 mac_reset_clip_rectangles (dpy, gc);
2788 if (raised_p)
2789 gc = f->output_data.mac->black_relief.gc;
2790 else
2791 gc = f->output_data.mac->white_relief.gc;
2792 mac_set_clip_rectangles (dpy, gc, clip_rect, 1);
2794 /* Bottom. */
2795 if (bot_p)
2796 for (i = 0; i < width; ++i)
2797 mac_draw_line (f, gc,
2798 left_x + i * left_p, bottom_y - i,
2799 right_x - i * right_p, bottom_y - i);
2801 /* Right. */
2802 if (right_p)
2803 for (i = 0; i < width; ++i)
2804 mac_draw_line (f, gc,
2805 right_x - i, top_y + i + 1, right_x - i, bottom_y - i - 1);
2807 mac_reset_clip_rectangles (dpy, gc);
2811 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
2812 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
2813 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
2814 left side of the rectangle. RIGHT_P non-zero means draw a line
2815 on the right side of the rectangle. CLIP_RECT is the clipping
2816 rectangle to use when drawing. */
2818 static void
2819 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2820 left_p, right_p, clip_rect)
2821 struct glyph_string *s;
2822 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
2823 Rect *clip_rect;
2825 XGCValues xgcv;
2827 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2828 XSetForeground (s->display, s->gc, s->face->box_color);
2829 mac_set_clip_rectangles (s->display, s->gc, clip_rect, 1);
2831 /* Top. */
2832 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
2833 right_x - left_x + 1, width);
2835 /* Left. */
2836 if (left_p)
2837 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
2838 width, bottom_y - top_y + 1);
2840 /* Bottom. */
2841 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
2842 right_x - left_x + 1, width);
2844 /* Right. */
2845 if (right_p)
2846 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
2847 top_y, width, bottom_y - top_y + 1);
2849 XSetForeground (s->display, s->gc, xgcv.foreground);
2850 mac_reset_clip_rectangles (s->display, s->gc);
2854 /* Draw a box around glyph string S. */
2856 static void
2857 x_draw_glyph_string_box (s)
2858 struct glyph_string *s;
2860 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
2861 int left_p, right_p;
2862 struct glyph *last_glyph;
2863 Rect clip_rect;
2865 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2866 ? WINDOW_RIGHT_EDGE_X (s->w)
2867 : window_box_right (s->w, s->area));
2869 /* The glyph that may have a right box line. */
2870 last_glyph = (s->cmp || s->img
2871 ? s->first_glyph
2872 : s->first_glyph + s->nchars - 1);
2874 width = abs (s->face->box_line_width);
2875 raised_p = s->face->box == FACE_RAISED_BOX;
2876 left_x = s->x;
2877 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
2878 ? last_x - 1
2879 : min (last_x, s->x + s->background_width) - 1);
2880 top_y = s->y;
2881 bottom_y = top_y + s->height - 1;
2883 left_p = (s->first_glyph->left_box_line_p
2884 || (s->hl == DRAW_MOUSE_FACE
2885 && (s->prev == NULL
2886 || s->prev->hl != s->hl)));
2887 right_p = (last_glyph->right_box_line_p
2888 || (s->hl == DRAW_MOUSE_FACE
2889 && (s->next == NULL
2890 || s->next->hl != s->hl)));
2892 get_glyph_string_clip_rect (s, &clip_rect);
2894 if (s->face->box == FACE_SIMPLE_BOX)
2895 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2896 left_p, right_p, &clip_rect);
2897 else
2899 x_setup_relief_colors (s);
2900 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
2901 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
2906 /* Draw foreground of image glyph string S. */
2908 static void
2909 x_draw_image_foreground (s)
2910 struct glyph_string *s;
2912 int x = s->x;
2913 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2915 /* If first glyph of S has a left box line, start drawing it to the
2916 right of that line. */
2917 if (s->face->box != FACE_NO_BOX
2918 && s->first_glyph->left_box_line_p
2919 && s->slice.x == 0)
2920 x += abs (s->face->box_line_width);
2922 /* If there is a margin around the image, adjust x- and y-position
2923 by that margin. */
2924 if (s->slice.x == 0)
2925 x += s->img->hmargin;
2926 if (s->slice.y == 0)
2927 y += s->img->vmargin;
2929 if (s->img->pixmap)
2931 x_set_glyph_string_clipping (s);
2933 if (s->img->mask)
2934 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
2935 s->f, s->gc, s->slice.x, s->slice.y,
2936 s->slice.width, s->slice.height, x, y);
2937 else
2939 mac_copy_area (s->img->pixmap,
2940 s->f, s->gc, s->slice.x, s->slice.y,
2941 s->slice.width, s->slice.height, x, y);
2943 /* When the image has a mask, we can expect that at
2944 least part of a mouse highlight or a block cursor will
2945 be visible. If the image doesn't have a mask, make
2946 a block cursor visible by drawing a rectangle around
2947 the image. I believe it's looking better if we do
2948 nothing here for mouse-face. */
2949 if (s->hl == DRAW_CURSOR)
2951 int r = s->img->relief;
2952 if (r < 0) r = -r;
2953 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
2954 s->slice.width + r*2 - 1,
2955 s->slice.height + r*2 - 1);
2959 else
2960 /* Draw a rectangle if image could not be loaded. */
2961 mac_draw_rectangle (s->f, s->gc, x, y,
2962 s->slice.width - 1, s->slice.height - 1);
2966 /* Draw a relief around the image glyph string S. */
2968 static void
2969 x_draw_image_relief (s)
2970 struct glyph_string *s;
2972 int x0, y0, x1, y1, thick, raised_p;
2973 Rect r;
2974 int x = s->x;
2975 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2977 /* If first glyph of S has a left box line, start drawing it to the
2978 right of that line. */
2979 if (s->face->box != FACE_NO_BOX
2980 && s->first_glyph->left_box_line_p
2981 && s->slice.x == 0)
2982 x += abs (s->face->box_line_width);
2984 /* If there is a margin around the image, adjust x- and y-position
2985 by that margin. */
2986 if (s->slice.x == 0)
2987 x += s->img->hmargin;
2988 if (s->slice.y == 0)
2989 y += s->img->vmargin;
2991 if (s->hl == DRAW_IMAGE_SUNKEN
2992 || s->hl == DRAW_IMAGE_RAISED)
2994 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2995 raised_p = s->hl == DRAW_IMAGE_RAISED;
2997 else
2999 thick = abs (s->img->relief);
3000 raised_p = s->img->relief > 0;
3003 x0 = x - thick;
3004 y0 = y - thick;
3005 x1 = x + s->slice.width + thick - 1;
3006 y1 = y + s->slice.height + thick - 1;
3008 x_setup_relief_colors (s);
3009 get_glyph_string_clip_rect (s, &r);
3010 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3011 s->slice.y == 0,
3012 s->slice.y + s->slice.height == s->img->height,
3013 s->slice.x == 0,
3014 s->slice.x + s->slice.width == s->img->width,
3015 &r);
3019 /* Draw part of the background of glyph string S. X, Y, W, and H
3020 give the rectangle to draw. */
3022 static void
3023 x_draw_glyph_string_bg_rect (s, x, y, w, h)
3024 struct glyph_string *s;
3025 int x, y, w, h;
3027 #if 0 /* MAC_TODO: stipple */
3028 if (s->stippled_p)
3030 /* Fill background with a stipple pattern. */
3031 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3032 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3033 XSetFillStyle (s->display, s->gc, FillSolid);
3035 else
3036 #endif /* MAC_TODO */
3037 x_clear_glyph_string_rect (s, x, y, w, h);
3041 /* Draw image glyph string S.
3043 s->y
3044 s->x +-------------------------
3045 | s->face->box
3047 | +-------------------------
3048 | | s->img->margin
3050 | | +-------------------
3051 | | | the image
3055 static void
3056 x_draw_image_glyph_string (s)
3057 struct glyph_string *s;
3059 int x, y;
3060 int box_line_hwidth = abs (s->face->box_line_width);
3061 int box_line_vwidth = max (s->face->box_line_width, 0);
3062 int height;
3063 Pixmap pixmap = 0;
3065 height = s->height - 2 * box_line_vwidth;
3068 /* Fill background with face under the image. Do it only if row is
3069 taller than image or if image has a clip mask to reduce
3070 flickering. */
3071 s->stippled_p = s->face->stipple != 0;
3072 if (height > s->slice.height
3073 || s->img->hmargin
3074 || s->img->vmargin
3075 || s->img->mask
3076 || s->img->pixmap == 0
3077 || s->width != s->background_width)
3079 x = s->x;
3080 if (s->first_glyph->left_box_line_p
3081 && s->slice.x == 0)
3082 x += box_line_hwidth;
3084 y = s->y;
3085 if (s->slice.y == 0)
3086 y += box_line_vwidth;
3088 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3090 s->background_filled_p = 1;
3093 /* Draw the foreground. */
3094 x_draw_image_foreground (s);
3096 /* If we must draw a relief around the image, do it. */
3097 if (s->img->relief
3098 || s->hl == DRAW_IMAGE_RAISED
3099 || s->hl == DRAW_IMAGE_SUNKEN)
3100 x_draw_image_relief (s);
3104 /* Draw stretch glyph string S. */
3106 static void
3107 x_draw_stretch_glyph_string (s)
3108 struct glyph_string *s;
3110 xassert (s->first_glyph->type == STRETCH_GLYPH);
3111 s->stippled_p = s->face->stipple != 0;
3113 if (s->hl == DRAW_CURSOR
3114 && !x_stretch_cursor_p)
3116 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3117 as wide as the stretch glyph. */
3118 int width = min (FRAME_COLUMN_WIDTH (s->f), s->background_width);
3120 /* Draw cursor. */
3121 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
3123 /* Clear rest using the GC of the original non-cursor face. */
3124 if (width < s->background_width)
3126 int x = s->x + width, y = s->y;
3127 int w = s->background_width - width, h = s->height;
3128 Rect r;
3129 GC gc;
3131 if (s->row->mouse_face_p
3132 && cursor_in_mouse_face_p (s->w))
3134 x_set_mouse_face_gc (s);
3135 gc = s->gc;
3137 else
3138 gc = s->face->gc;
3140 get_glyph_string_clip_rect (s, &r);
3141 mac_set_clip_rectangles (s->display, gc, &r, 1);
3143 #if 0 /* MAC_TODO: stipple */
3144 if (s->face->stipple)
3146 /* Fill background with a stipple pattern. */
3147 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3148 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3149 XSetFillStyle (s->display, gc, FillSolid);
3151 else
3152 #endif /* MAC_TODO */
3153 mac_erase_rectangle (s->f, gc, x, y, w, h);
3156 else if (!s->background_filled_p)
3157 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
3158 s->height);
3160 s->background_filled_p = 1;
3164 /* Draw glyph string S. */
3166 static void
3167 x_draw_glyph_string (s)
3168 struct glyph_string *s;
3170 int relief_drawn_p = 0;
3172 /* If S draws into the background of its successor that does not
3173 draw a cursor, draw the background of the successor first so that
3174 S can draw into it. This makes S->next use XDrawString instead
3175 of XDrawImageString. */
3176 if (s->next && s->right_overhang && !s->for_overlaps
3177 && s->next->hl != DRAW_CURSOR)
3179 xassert (s->next->img == NULL);
3180 x_set_glyph_string_gc (s->next);
3181 x_set_glyph_string_clipping (s->next);
3182 x_draw_glyph_string_background (s->next, 1);
3185 /* Set up S->gc, set clipping and draw S. */
3186 x_set_glyph_string_gc (s);
3188 /* Draw relief (if any) in advance for char/composition so that the
3189 glyph string can be drawn over it. */
3190 if (!s->for_overlaps
3191 && s->face->box != FACE_NO_BOX
3192 && (s->first_glyph->type == CHAR_GLYPH
3193 || s->first_glyph->type == COMPOSITE_GLYPH))
3196 x_set_glyph_string_clipping (s);
3197 x_draw_glyph_string_background (s, 1);
3198 x_draw_glyph_string_box (s);
3199 x_set_glyph_string_clipping (s);
3200 relief_drawn_p = 1;
3202 else
3203 x_set_glyph_string_clipping (s);
3205 switch (s->first_glyph->type)
3207 case IMAGE_GLYPH:
3208 x_draw_image_glyph_string (s);
3209 break;
3211 case STRETCH_GLYPH:
3212 x_draw_stretch_glyph_string (s);
3213 break;
3215 case CHAR_GLYPH:
3216 if (s->for_overlaps)
3217 s->background_filled_p = 1;
3218 else
3219 x_draw_glyph_string_background (s, 0);
3220 x_draw_glyph_string_foreground (s);
3221 break;
3223 case COMPOSITE_GLYPH:
3224 if (s->for_overlaps || s->gidx > 0)
3225 s->background_filled_p = 1;
3226 else
3227 x_draw_glyph_string_background (s, 1);
3228 x_draw_composite_glyph_string_foreground (s);
3229 break;
3231 default:
3232 abort ();
3235 if (!s->for_overlaps)
3237 /* Draw underline. */
3238 if (s->face->underline_p)
3240 unsigned long h = 1;
3241 unsigned long dy = s->height - h;
3243 if (s->face->underline_defaulted_p)
3244 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3245 s->width, h);
3246 else
3248 XGCValues xgcv;
3249 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3250 XSetForeground (s->display, s->gc, s->face->underline_color);
3251 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3252 s->width, h);
3253 XSetForeground (s->display, s->gc, xgcv.foreground);
3257 /* Draw overline. */
3258 if (s->face->overline_p)
3260 unsigned long dy = 0, h = 1;
3262 if (s->face->overline_color_defaulted_p)
3263 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3264 s->width, h);
3265 else
3267 XGCValues xgcv;
3268 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3269 XSetForeground (s->display, s->gc, s->face->overline_color);
3270 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3271 s->width, h);
3272 XSetForeground (s->display, s->gc, xgcv.foreground);
3276 /* Draw strike-through. */
3277 if (s->face->strike_through_p)
3279 unsigned long h = 1;
3280 unsigned long dy = (s->height - h) / 2;
3282 if (s->face->strike_through_color_defaulted_p)
3283 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3284 s->width, h);
3285 else
3287 XGCValues xgcv;
3288 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3289 XSetForeground (s->display, s->gc, s->face->strike_through_color);
3290 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3291 s->width, h);
3292 XSetForeground (s->display, s->gc, xgcv.foreground);
3296 /* Draw relief if not yet drawn. */
3297 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
3298 x_draw_glyph_string_box (s);
3301 /* Reset clipping. */
3302 mac_reset_clip_rectangles (s->display, s->gc);
3305 /* Shift display to make room for inserted glyphs. */
3307 void
3308 mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
3309 struct frame *f;
3310 int x, y, width, height, shift_by;
3312 mac_scroll_area (f, f->output_data.mac->normal_gc,
3313 x, y, width, height,
3314 x + shift_by, y);
3317 /* Delete N glyphs at the nominal cursor position. Not implemented
3318 for X frames. */
3320 static void
3321 x_delete_glyphs (n)
3322 register int n;
3324 abort ();
3328 /* Clear entire frame. If updating_frame is non-null, clear that
3329 frame. Otherwise clear the selected frame. */
3331 static void
3332 x_clear_frame ()
3334 struct frame *f;
3336 if (updating_frame)
3337 f = updating_frame;
3338 else
3339 f = SELECTED_FRAME ();
3341 /* Clearing the frame will erase any cursor, so mark them all as no
3342 longer visible. */
3343 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
3344 output_cursor.hpos = output_cursor.vpos = 0;
3345 output_cursor.x = -1;
3347 /* We don't set the output cursor here because there will always
3348 follow an explicit cursor_to. */
3349 BLOCK_INPUT;
3350 mac_clear_window (f);
3352 /* We have to clear the scroll bars, too. If we have changed
3353 colors or something like that, then they should be notified. */
3354 x_scroll_bar_clear (f);
3356 XFlush (FRAME_MAC_DISPLAY (f));
3357 UNBLOCK_INPUT;
3362 /* Invert the middle quarter of the frame for .15 sec. */
3364 /* We use the select system call to do the waiting, so we have to make
3365 sure it's available. If it isn't, we just won't do visual bells. */
3367 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
3370 /* Subtract the `struct timeval' values X and Y, storing the result in
3371 *RESULT. Return 1 if the difference is negative, otherwise 0. */
3373 static int
3374 timeval_subtract (result, x, y)
3375 struct timeval *result, x, y;
3377 /* Perform the carry for the later subtraction by updating y. This
3378 is safer because on some systems the tv_sec member is unsigned. */
3379 if (x.tv_usec < y.tv_usec)
3381 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
3382 y.tv_usec -= 1000000 * nsec;
3383 y.tv_sec += nsec;
3386 if (x.tv_usec - y.tv_usec > 1000000)
3388 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
3389 y.tv_usec += 1000000 * nsec;
3390 y.tv_sec -= nsec;
3393 /* Compute the time remaining to wait. tv_usec is certainly
3394 positive. */
3395 result->tv_sec = x.tv_sec - y.tv_sec;
3396 result->tv_usec = x.tv_usec - y.tv_usec;
3398 /* Return indication of whether the result should be considered
3399 negative. */
3400 return x.tv_sec < y.tv_sec;
3403 void
3404 XTflash (f)
3405 struct frame *f;
3407 /* Get the height not including a menu bar widget. */
3408 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
3409 /* Height of each line to flash. */
3410 int flash_height = FRAME_LINE_HEIGHT (f);
3411 /* These will be the left and right margins of the rectangles. */
3412 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
3413 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
3415 int width;
3417 /* Don't flash the area between a scroll bar and the frame
3418 edge it is next to. */
3419 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
3421 case vertical_scroll_bar_left:
3422 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
3423 break;
3425 case vertical_scroll_bar_right:
3426 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
3427 break;
3429 default:
3430 break;
3433 width = flash_right - flash_left;
3435 BLOCK_INPUT;
3437 /* If window is tall, flash top and bottom line. */
3438 if (height > 3 * FRAME_LINE_HEIGHT (f))
3440 mac_invert_rectangle (f, flash_left,
3441 (FRAME_INTERNAL_BORDER_WIDTH (f)
3442 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
3443 width, flash_height);
3444 mac_invert_rectangle (f, flash_left,
3445 (height - flash_height
3446 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3447 width, flash_height);
3449 else
3450 /* If it is short, flash it all. */
3451 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3452 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3454 x_flush (f);
3457 struct timeval wakeup;
3459 EMACS_GET_TIME (wakeup);
3461 /* Compute time to wait until, propagating carry from usecs. */
3462 wakeup.tv_usec += 150000;
3463 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
3464 wakeup.tv_usec %= 1000000;
3466 /* Keep waiting until past the time wakeup or any input gets
3467 available. */
3468 while (! detect_input_pending ())
3470 struct timeval current;
3471 struct timeval timeout;
3473 EMACS_GET_TIME (current);
3475 /* Break if result would be negative. */
3476 if (timeval_subtract (&current, wakeup, current))
3477 break;
3479 /* How long `select' should wait. */
3480 timeout.tv_sec = 0;
3481 timeout.tv_usec = 10000;
3483 /* Try to wait that long--but we might wake up sooner. */
3484 select (0, NULL, NULL, NULL, &timeout);
3488 /* If window is tall, flash top and bottom line. */
3489 if (height > 3 * FRAME_LINE_HEIGHT (f))
3491 mac_invert_rectangle (f, flash_left,
3492 (FRAME_INTERNAL_BORDER_WIDTH (f)
3493 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
3494 width, flash_height);
3495 mac_invert_rectangle (f, flash_left,
3496 (height - flash_height
3497 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3498 width, flash_height);
3500 else
3501 /* If it is short, flash it all. */
3502 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3503 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3505 x_flush (f);
3507 UNBLOCK_INPUT;
3510 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
3513 /* Make audible bell. */
3515 void
3516 XTring_bell ()
3518 struct frame *f = SELECTED_FRAME ();
3520 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
3521 if (visible_bell)
3522 XTflash (f);
3523 else
3524 #endif
3526 BLOCK_INPUT;
3527 SysBeep (1);
3528 XFlush (FRAME_MAC_DISPLAY (f));
3529 UNBLOCK_INPUT;
3534 /* Specify how many text lines, from the top of the window,
3535 should be affected by insert-lines and delete-lines operations.
3536 This, and those operations, are used only within an update
3537 that is bounded by calls to x_update_begin and x_update_end. */
3539 static void
3540 XTset_terminal_window (n)
3541 register int n;
3543 /* This function intentionally left blank. */
3548 /***********************************************************************
3549 Line Dance
3550 ***********************************************************************/
3552 /* Perform an insert-lines or delete-lines operation, inserting N
3553 lines or deleting -N lines at vertical position VPOS. */
3555 static void
3556 x_ins_del_lines (vpos, n)
3557 int vpos, n;
3559 abort ();
3563 /* Scroll part of the display as described by RUN. */
3565 static void
3566 x_scroll_run (w, run)
3567 struct window *w;
3568 struct run *run;
3570 struct frame *f = XFRAME (w->frame);
3571 int x, y, width, height, from_y, to_y, bottom_y;
3573 /* Get frame-relative bounding box of the text display area of W,
3574 without mode lines. Include in this box the left and right
3575 fringe of W. */
3576 window_box (w, -1, &x, &y, &width, &height);
3578 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
3579 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
3580 bottom_y = y + height;
3582 if (to_y < from_y)
3584 /* Scrolling up. Make sure we don't copy part of the mode
3585 line at the bottom. */
3586 if (from_y + run->height > bottom_y)
3587 height = bottom_y - from_y;
3588 else
3589 height = run->height;
3591 else
3593 /* Scolling down. Make sure we don't copy over the mode line.
3594 at the bottom. */
3595 if (to_y + run->height > bottom_y)
3596 height = bottom_y - to_y;
3597 else
3598 height = run->height;
3601 BLOCK_INPUT;
3603 /* Cursor off. Will be switched on again in x_update_window_end. */
3604 updated_window = w;
3605 x_clear_cursor (w);
3607 mac_scroll_area (f, f->output_data.mac->normal_gc,
3608 x, from_y,
3609 width, height,
3610 x, to_y);
3612 UNBLOCK_INPUT;
3617 /***********************************************************************
3618 Exposure Events
3619 ***********************************************************************/
3622 static void
3623 frame_highlight (f)
3624 struct frame *f;
3626 OSErr err;
3627 ControlRef root_control;
3629 BLOCK_INPUT;
3630 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
3631 if (err == noErr)
3632 ActivateControl (root_control);
3633 UNBLOCK_INPUT;
3634 x_update_cursor (f, 1);
3637 static void
3638 frame_unhighlight (f)
3639 struct frame *f;
3641 OSErr err;
3642 ControlRef root_control;
3644 BLOCK_INPUT;
3645 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
3646 if (err == noErr)
3647 DeactivateControl (root_control);
3648 UNBLOCK_INPUT;
3649 x_update_cursor (f, 1);
3652 /* The focus has changed. Update the frames as necessary to reflect
3653 the new situation. Note that we can't change the selected frame
3654 here, because the Lisp code we are interrupting might become confused.
3655 Each event gets marked with the frame in which it occurred, so the
3656 Lisp code can tell when the switch took place by examining the events. */
3658 static void
3659 x_new_focus_frame (dpyinfo, frame)
3660 struct x_display_info *dpyinfo;
3661 struct frame *frame;
3663 struct frame *old_focus = dpyinfo->x_focus_frame;
3665 if (frame != dpyinfo->x_focus_frame)
3667 /* Set this before calling other routines, so that they see
3668 the correct value of x_focus_frame. */
3669 dpyinfo->x_focus_frame = frame;
3671 if (old_focus && old_focus->auto_lower)
3672 x_lower_frame (old_focus);
3674 #if 0
3675 selected_frame = frame;
3676 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
3677 selected_frame);
3678 Fselect_window (selected_frame->selected_window, Qnil);
3679 choose_minibuf_frame ();
3680 #endif /* ! 0 */
3682 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
3683 pending_autoraise_frame = dpyinfo->x_focus_frame;
3684 else
3685 pending_autoraise_frame = 0;
3688 x_frame_rehighlight (dpyinfo);
3691 /* Handle FocusIn and FocusOut state changes for FRAME.
3692 If FRAME has focus and there exists more than one frame, puts
3693 a FOCUS_IN_EVENT into *BUFP. */
3695 static void
3696 mac_focus_changed (type, dpyinfo, frame, bufp)
3697 int type;
3698 struct mac_display_info *dpyinfo;
3699 struct frame *frame;
3700 struct input_event *bufp;
3702 if (type == activeFlag)
3704 if (dpyinfo->x_focus_event_frame != frame)
3706 x_new_focus_frame (dpyinfo, frame);
3707 dpyinfo->x_focus_event_frame = frame;
3709 /* Don't stop displaying the initial startup message
3710 for a switch-frame event we don't need. */
3711 if (GC_NILP (Vterminal_frame)
3712 && GC_CONSP (Vframe_list)
3713 && !GC_NILP (XCDR (Vframe_list)))
3715 bufp->kind = FOCUS_IN_EVENT;
3716 XSETFRAME (bufp->frame_or_window, frame);
3720 else
3722 if (dpyinfo->x_focus_event_frame == frame)
3724 dpyinfo->x_focus_event_frame = 0;
3725 x_new_focus_frame (dpyinfo, 0);
3730 /* The focus may have changed. Figure out if it is a real focus change,
3731 by checking both FocusIn/Out and Enter/LeaveNotify events.
3733 Returns FOCUS_IN_EVENT event in *BUFP. */
3735 static void
3736 x_detect_focus_change (dpyinfo, event, bufp)
3737 struct mac_display_info *dpyinfo;
3738 EventRecord *event;
3739 struct input_event *bufp;
3741 struct frame *frame;
3743 frame = mac_window_to_frame ((WindowPtr) event->message);
3744 if (! frame)
3745 return;
3747 /* On Mac, this is only called from focus events, so no switch needed. */
3748 mac_focus_changed ((event->modifiers & activeFlag),
3749 dpyinfo, frame, bufp);
3753 /* Handle an event saying the mouse has moved out of an Emacs frame. */
3755 void
3756 x_mouse_leave (dpyinfo)
3757 struct x_display_info *dpyinfo;
3759 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
3762 /* The focus has changed, or we have redirected a frame's focus to
3763 another frame (this happens when a frame uses a surrogate
3764 mini-buffer frame). Shift the highlight as appropriate.
3766 The FRAME argument doesn't necessarily have anything to do with which
3767 frame is being highlighted or un-highlighted; we only use it to find
3768 the appropriate X display info. */
3770 static void
3771 XTframe_rehighlight (frame)
3772 struct frame *frame;
3774 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
3777 static void
3778 x_frame_rehighlight (dpyinfo)
3779 struct x_display_info *dpyinfo;
3781 struct frame *old_highlight = dpyinfo->x_highlight_frame;
3783 if (dpyinfo->x_focus_frame)
3785 dpyinfo->x_highlight_frame
3786 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
3787 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
3788 : dpyinfo->x_focus_frame);
3789 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
3791 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
3792 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
3795 else
3796 dpyinfo->x_highlight_frame = 0;
3798 if (dpyinfo->x_highlight_frame != old_highlight)
3800 if (old_highlight)
3801 frame_unhighlight (old_highlight);
3802 if (dpyinfo->x_highlight_frame)
3803 frame_highlight (dpyinfo->x_highlight_frame);
3809 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
3811 #if 0 /* MAC_TODO */
3812 /* Initialize mode_switch_bit and modifier_meaning. */
3813 static void
3814 x_find_modifier_meanings (dpyinfo)
3815 struct x_display_info *dpyinfo;
3817 int min_code, max_code;
3818 KeySym *syms;
3819 int syms_per_code;
3820 XModifierKeymap *mods;
3822 dpyinfo->meta_mod_mask = 0;
3823 dpyinfo->shift_lock_mask = 0;
3824 dpyinfo->alt_mod_mask = 0;
3825 dpyinfo->super_mod_mask = 0;
3826 dpyinfo->hyper_mod_mask = 0;
3828 #ifdef HAVE_X11R4
3829 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
3830 #else
3831 min_code = dpyinfo->display->min_keycode;
3832 max_code = dpyinfo->display->max_keycode;
3833 #endif
3835 syms = XGetKeyboardMapping (dpyinfo->display,
3836 min_code, max_code - min_code + 1,
3837 &syms_per_code);
3838 mods = XGetModifierMapping (dpyinfo->display);
3840 /* Scan the modifier table to see which modifier bits the Meta and
3841 Alt keysyms are on. */
3843 int row, col; /* The row and column in the modifier table. */
3845 for (row = 3; row < 8; row++)
3846 for (col = 0; col < mods->max_keypermod; col++)
3848 KeyCode code
3849 = mods->modifiermap[(row * mods->max_keypermod) + col];
3851 /* Zeroes are used for filler. Skip them. */
3852 if (code == 0)
3853 continue;
3855 /* Are any of this keycode's keysyms a meta key? */
3857 int code_col;
3859 for (code_col = 0; code_col < syms_per_code; code_col++)
3861 int sym = syms[((code - min_code) * syms_per_code) + code_col];
3863 switch (sym)
3865 case XK_Meta_L:
3866 case XK_Meta_R:
3867 dpyinfo->meta_mod_mask |= (1 << row);
3868 break;
3870 case XK_Alt_L:
3871 case XK_Alt_R:
3872 dpyinfo->alt_mod_mask |= (1 << row);
3873 break;
3875 case XK_Hyper_L:
3876 case XK_Hyper_R:
3877 dpyinfo->hyper_mod_mask |= (1 << row);
3878 break;
3880 case XK_Super_L:
3881 case XK_Super_R:
3882 dpyinfo->super_mod_mask |= (1 << row);
3883 break;
3885 case XK_Shift_Lock:
3886 /* Ignore this if it's not on the lock modifier. */
3887 if ((1 << row) == LockMask)
3888 dpyinfo->shift_lock_mask = LockMask;
3889 break;
3896 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
3897 if (! dpyinfo->meta_mod_mask)
3899 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
3900 dpyinfo->alt_mod_mask = 0;
3903 /* If some keys are both alt and meta,
3904 make them just meta, not alt. */
3905 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
3907 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
3910 XFree ((char *) syms);
3911 XFreeModifiermap (mods);
3914 #endif /* MAC_TODO */
3916 /* Convert between the modifier bits X uses and the modifier bits
3917 Emacs uses. */
3919 static unsigned int
3920 x_mac_to_emacs_modifiers (dpyinfo, state)
3921 struct x_display_info *dpyinfo;
3922 unsigned short state;
3924 return (((state & shiftKey) ? shift_modifier : 0)
3925 | ((state & controlKey) ? ctrl_modifier : 0)
3926 | ((state & cmdKey) ? meta_modifier : 0)
3927 | ((state & optionKey) ? alt_modifier : 0));
3930 #if 0 /* MAC_TODO */
3931 static unsigned short
3932 x_emacs_to_x_modifiers (dpyinfo, state)
3933 struct x_display_info *dpyinfo;
3934 unsigned int state;
3936 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
3937 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
3938 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
3939 | ((state & shift_modifier) ? ShiftMask : 0)
3940 | ((state & ctrl_modifier) ? ControlMask : 0)
3941 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
3943 #endif /* MAC_TODO */
3945 /* Convert a keysym to its name. */
3947 char *
3948 x_get_keysym_name (keysym)
3949 int keysym;
3951 char *value;
3953 BLOCK_INPUT;
3954 #if 0
3955 value = XKeysymToString (keysym);
3956 #else
3957 value = 0;
3958 #endif
3959 UNBLOCK_INPUT;
3961 return value;
3966 /* Function to report a mouse movement to the mainstream Emacs code.
3967 The input handler calls this.
3969 We have received a mouse movement event, which is given in *event.
3970 If the mouse is over a different glyph than it was last time, tell
3971 the mainstream emacs code by setting mouse_moved. If not, ask for
3972 another motion event, so we can check again the next time it moves. */
3974 static Point last_mouse_motion_position;
3975 static Lisp_Object last_mouse_motion_frame;
3977 static int
3978 note_mouse_movement (frame, pos)
3979 FRAME_PTR frame;
3980 Point *pos;
3982 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
3983 #if TARGET_API_MAC_CARBON
3984 Rect r;
3985 #endif
3987 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
3988 last_mouse_motion_position = *pos;
3989 XSETFRAME (last_mouse_motion_frame, frame);
3991 #if TARGET_API_MAC_CARBON
3992 if (!PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r)))
3993 #else
3994 if (!PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect))
3995 #endif
3997 if (frame == dpyinfo->mouse_face_mouse_frame)
3998 /* This case corresponds to LeaveNotify in X11. */
4000 /* If we move outside the frame, then we're certainly no
4001 longer on any text in the frame. */
4002 clear_mouse_face (dpyinfo);
4003 dpyinfo->mouse_face_mouse_frame = 0;
4004 if (!dpyinfo->grabbed)
4005 rif->define_frame_cursor (frame,
4006 frame->output_data.mac->nontext_cursor);
4008 return 1;
4010 /* Has the mouse moved off the glyph it was on at the last sighting? */
4011 if (frame != last_mouse_glyph_frame
4012 || !PtInRect (*pos, &last_mouse_glyph))
4014 frame->mouse_moved = 1;
4015 last_mouse_scroll_bar = Qnil;
4016 note_mouse_highlight (frame, pos->h, pos->v);
4017 /* Remember which glyph we're now on. */
4018 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
4019 last_mouse_glyph_frame = frame;
4020 return 1;
4023 return 0;
4027 /************************************************************************
4028 Mouse Face
4029 ************************************************************************/
4031 /* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4033 static void
4034 redo_mouse_highlight ()
4036 if (!NILP (last_mouse_motion_frame)
4037 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4038 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4039 last_mouse_motion_position.h,
4040 last_mouse_motion_position.v);
4044 static struct frame *
4045 mac_focus_frame (dpyinfo)
4046 struct mac_display_info *dpyinfo;
4048 if (dpyinfo->x_focus_frame)
4049 return dpyinfo->x_focus_frame;
4050 else
4051 /* Mac version may get events, such as a menu bar click, even when
4052 all the frames are invisible. In this case, we regard the
4053 event came to the selected frame. */
4054 return SELECTED_FRAME ();
4058 /* Return the current position of the mouse.
4059 *FP should be a frame which indicates which display to ask about.
4061 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4062 and *PART to the frame, window, and scroll bar part that the mouse
4063 is over. Set *X and *Y to the portion and whole of the mouse's
4064 position on the scroll bar.
4066 If the mouse movement started elsewhere, set *FP to the frame the
4067 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4068 the mouse is over.
4070 Set *TIME to the server time-stamp for the time at which the mouse
4071 was at this position.
4073 Don't store anything if we don't have a valid set of values to report.
4075 This clears the mouse_moved flag, so we can wait for the next mouse
4076 movement. */
4078 static void
4079 XTmouse_position (fp, insist, bar_window, part, x, y, time)
4080 FRAME_PTR *fp;
4081 int insist;
4082 Lisp_Object *bar_window;
4083 enum scroll_bar_part *part;
4084 Lisp_Object *x, *y;
4085 unsigned long *time;
4087 FRAME_PTR f1;
4089 BLOCK_INPUT;
4091 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4092 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4093 else
4095 Lisp_Object frame, tail;
4097 /* Clear the mouse-moved flag for every frame on this display. */
4098 FOR_EACH_FRAME (tail, frame)
4099 XFRAME (frame)->mouse_moved = 0;
4101 last_mouse_scroll_bar = Qnil;
4103 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4104 && FRAME_LIVE_P (last_mouse_frame))
4105 f1 = last_mouse_frame;
4106 else
4107 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
4109 if (f1)
4111 /* Ok, we found a frame. Store all the values.
4112 last_mouse_glyph is a rectangle used to reduce the
4113 generation of mouse events. To not miss any motion
4114 events, we must divide the frame into rectangles of the
4115 size of the smallest character that could be displayed
4116 on it, i.e. into the same rectangles that matrices on
4117 the frame are divided into. */
4118 Point mouse_pos;
4120 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4121 GetMouse (&mouse_pos);
4122 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4123 &last_mouse_glyph);
4124 last_mouse_glyph_frame = f1;
4126 *bar_window = Qnil;
4127 *part = 0;
4128 *fp = f1;
4129 XSETINT (*x, mouse_pos.h);
4130 XSETINT (*y, mouse_pos.v);
4131 *time = last_mouse_movement_time;
4135 UNBLOCK_INPUT;
4139 /************************************************************************
4140 Toolkit scroll bars
4141 ************************************************************************/
4143 #ifdef USE_TOOLKIT_SCROLL_BARS
4145 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4146 static OSStatus install_scroll_bar_timer P_ ((void));
4147 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
4148 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
4149 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
4150 struct input_event *));
4151 static OSErr get_control_part_bounds P_ ((ControlHandle, ControlPartCode,
4152 Rect *));
4153 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
4154 ControlPartCode,
4155 struct input_event *));
4156 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
4157 struct input_event *));
4158 static void x_scroll_bar_handle_drag P_ ((WindowPtr, struct scroll_bar *,
4159 Point, struct input_event *));
4160 static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4161 int, int, int));
4163 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
4165 static int last_scroll_bar_part;
4167 static EventLoopTimerRef scroll_bar_timer;
4169 static int scroll_bar_timer_event_posted_p;
4171 #define SCROLL_BAR_FIRST_DELAY 0.5
4172 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4174 static pascal void
4175 scroll_bar_timer_callback (timer, data)
4176 EventLoopTimerRef timer;
4177 void *data;
4179 EventRef event = NULL;
4180 OSErr err;
4182 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
4183 kEventAttributeNone, &event);
4184 if (err == noErr)
4186 Point mouse_pos;
4188 GetMouse (&mouse_pos);
4189 LocalToGlobal (&mouse_pos);
4190 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
4191 sizeof (Point), &mouse_pos);
4193 if (err == noErr)
4195 UInt32 modifiers = GetCurrentKeyModifiers ();
4197 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
4198 sizeof (UInt32), &modifiers);
4200 if (err == noErr)
4201 err = PostEventToQueue (GetCurrentEventQueue (), event,
4202 kEventPriorityStandard);
4203 if (err == noErr)
4204 scroll_bar_timer_event_posted_p = 1;
4206 if (event)
4207 ReleaseEvent (event);
4210 static OSStatus
4211 install_scroll_bar_timer ()
4213 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4215 if (scroll_bar_timer_callbackUPP == NULL)
4216 scroll_bar_timer_callbackUPP =
4217 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4219 if (scroll_bar_timer == NULL)
4220 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4221 kEventDurationForever as delays. */
4222 return
4223 InstallEventLoopTimer (GetCurrentEventLoop (),
4224 kEventDurationForever, kEventDurationForever,
4225 scroll_bar_timer_callbackUPP, NULL,
4226 &scroll_bar_timer);
4229 static OSStatus
4230 set_scroll_bar_timer (delay)
4231 EventTimerInterval delay;
4233 if (scroll_bar_timer == NULL)
4234 install_scroll_bar_timer ();
4236 scroll_bar_timer_event_posted_p = 0;
4238 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4241 static int
4242 control_part_code_to_scroll_bar_part (part_code)
4243 ControlPartCode part_code;
4245 switch (part_code)
4247 case kControlUpButtonPart: return scroll_bar_up_arrow;
4248 case kControlDownButtonPart: return scroll_bar_down_arrow;
4249 case kControlPageUpPart: return scroll_bar_above_handle;
4250 case kControlPageDownPart: return scroll_bar_below_handle;
4251 case kControlIndicatorPart: return scroll_bar_handle;
4254 return -1;
4257 static void
4258 construct_scroll_bar_click (bar, part, bufp)
4259 struct scroll_bar *bar;
4260 int part;
4261 struct input_event *bufp;
4263 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4264 bufp->frame_or_window = bar->window;
4265 bufp->arg = Qnil;
4266 bufp->part = part;
4267 bufp->code = 0;
4268 XSETINT (bufp->x, 0);
4269 XSETINT (bufp->y, 0);
4270 bufp->modifiers = 0;
4273 static OSErr
4274 get_control_part_bounds (ch, part_code, rect)
4275 ControlHandle ch;
4276 ControlPartCode part_code;
4277 Rect *rect;
4279 RgnHandle region = NewRgn ();
4280 OSStatus err;
4282 err = GetControlRegion (ch, part_code, region);
4283 if (err == noErr)
4284 GetRegionBounds (region, rect);
4285 DisposeRgn (region);
4287 return err;
4290 static void
4291 x_scroll_bar_handle_press (bar, part_code, bufp)
4292 struct scroll_bar *bar;
4293 ControlPartCode part_code;
4294 struct input_event *bufp;
4296 int part = control_part_code_to_scroll_bar_part (part_code);
4298 if (part < 0)
4299 return;
4301 if (part != scroll_bar_handle)
4303 construct_scroll_bar_click (bar, part, bufp);
4304 HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), part_code);
4305 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
4308 last_scroll_bar_part = part;
4309 bar->dragging = Qnil;
4310 tracked_scroll_bar = bar;
4313 static void
4314 x_scroll_bar_handle_release (bar, bufp)
4315 struct scroll_bar *bar;
4316 struct input_event *bufp;
4318 if (last_scroll_bar_part != scroll_bar_handle
4319 || !GC_NILP (bar->dragging))
4320 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
4322 HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), 0);
4323 set_scroll_bar_timer (kEventDurationForever);
4325 last_scroll_bar_part = -1;
4326 bar->dragging = Qnil;
4327 tracked_scroll_bar = NULL;
4330 static void
4331 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
4332 WindowPtr win;
4333 struct scroll_bar *bar;
4334 Point mouse_pos;
4335 struct input_event *bufp;
4337 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
4339 if (last_scroll_bar_part == scroll_bar_handle)
4341 int top, top_range;
4342 Rect r;
4344 get_control_part_bounds (SCROLL_BAR_CONTROL_HANDLE (bar),
4345 kControlIndicatorPart, &r);
4347 if (GC_NILP (bar->dragging))
4348 XSETINT (bar->dragging, mouse_pos.v - r.top);
4350 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
4351 top_range = (XINT (bar->track_height) - (r.bottom - r.top)) *
4352 (1.0 + (float) GetControlViewSize (ch) / GetControl32BitMaximum (ch))
4353 + .5;
4355 if (top < 0)
4356 top = 0;
4357 if (top > top_range)
4358 top = top_range;
4360 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
4361 XSETINT (bufp->x, top);
4362 XSETINT (bufp->y, top_range);
4364 else
4366 ControlPartCode part_code;
4367 int unhilite_p = 0, part;
4369 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
4370 unhilite_p = 1;
4371 else
4373 part = control_part_code_to_scroll_bar_part (part_code);
4375 switch (last_scroll_bar_part)
4377 case scroll_bar_above_handle:
4378 case scroll_bar_below_handle:
4379 if (part != scroll_bar_above_handle
4380 && part != scroll_bar_below_handle)
4381 unhilite_p = 1;
4382 break;
4384 case scroll_bar_up_arrow:
4385 case scroll_bar_down_arrow:
4386 if (part != scroll_bar_up_arrow
4387 && part != scroll_bar_down_arrow)
4388 unhilite_p = 1;
4389 break;
4393 if (unhilite_p)
4394 HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), 0);
4395 else if (part != last_scroll_bar_part
4396 || scroll_bar_timer_event_posted_p)
4398 construct_scroll_bar_click (bar, part, bufp);
4399 last_scroll_bar_part = part;
4400 HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), part_code);
4401 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
4406 /* Set the thumb size and position of scroll bar BAR. We are currently
4407 displaying PORTION out of a whole WHOLE, and our position POSITION. */
4409 static void
4410 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
4411 struct scroll_bar *bar;
4412 int portion, position, whole;
4414 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
4416 int value, viewsize, maximum;
4418 if (whole == 0 || XINT (bar->track_height) == 0)
4419 value = 0, viewsize = 1, maximum = 0;
4420 else
4422 value = position;
4423 viewsize = portion;
4424 maximum = max (0, whole - portion);
4427 BLOCK_INPUT;
4429 SetControl32BitMinimum (ch, 0);
4430 SetControl32BitMaximum (ch, maximum);
4431 SetControl32BitValue (ch, value);
4432 SetControlViewSize (ch, viewsize);
4434 UNBLOCK_INPUT;
4437 #endif /* USE_TOOLKIT_SCROLL_BARS */
4441 /************************************************************************
4442 Scroll bars, general
4443 ************************************************************************/
4445 /* Create a scroll bar and return the scroll bar vector for it. W is
4446 the Emacs window on which to create the scroll bar. TOP, LEFT,
4447 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
4448 scroll bar. */
4450 static struct scroll_bar *
4451 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
4452 struct window *w;
4453 int top, left, width, height, disp_top, disp_height;
4455 struct frame *f = XFRAME (w->frame);
4456 struct scroll_bar *bar
4457 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
4458 Rect r;
4459 ControlHandle ch;
4461 BLOCK_INPUT;
4463 r.left = left;
4464 r.top = disp_top;
4465 r.right = left + width;
4466 r.bottom = disp_top + disp_height;
4468 #if TARGET_API_MAC_CARBON
4469 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
4470 0, 0, 0, kControlScrollBarProc, (long) bar);
4471 #else
4472 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
4473 0, 0, 0, scrollBarProc, (long) bar);
4474 #endif
4475 SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch);
4477 XSETWINDOW (bar->window, w);
4478 XSETINT (bar->top, top);
4479 XSETINT (bar->left, left);
4480 XSETINT (bar->width, width);
4481 XSETINT (bar->height, height);
4482 XSETINT (bar->start, 0);
4483 XSETINT (bar->end, 0);
4484 bar->dragging = Qnil;
4485 #ifdef USE_TOOLKIT_SCROLL_BARS
4486 bar->track_top = Qnil;
4487 bar->track_height = Qnil;
4488 #endif
4490 /* Add bar to its frame's list of scroll bars. */
4491 bar->next = FRAME_SCROLL_BARS (f);
4492 bar->prev = Qnil;
4493 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
4494 if (!NILP (bar->next))
4495 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4497 UNBLOCK_INPUT;
4498 return bar;
4502 /* Draw BAR's handle in the proper position.
4504 If the handle is already drawn from START to END, don't bother
4505 redrawing it, unless REBUILD is non-zero; in that case, always
4506 redraw it. (REBUILD is handy for drawing the handle after expose
4507 events.)
4509 Normally, we want to constrain the start and end of the handle to
4510 fit inside its rectangle, but if the user is dragging the scroll
4511 bar handle, we want to let them drag it down all the way, so that
4512 the bar's top is as far down as it goes; otherwise, there's no way
4513 to move to the very end of the buffer. */
4515 #ifndef USE_TOOLKIT_SCROLL_BARS
4517 static void
4518 x_scroll_bar_set_handle (bar, start, end, rebuild)
4519 struct scroll_bar *bar;
4520 int start, end;
4521 int rebuild;
4523 int dragging = ! NILP (bar->dragging);
4524 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
4525 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4526 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
4527 int length = end - start;
4529 /* If the display is already accurate, do nothing. */
4530 if (! rebuild
4531 && start == XINT (bar->start)
4532 && end == XINT (bar->end))
4533 return;
4535 BLOCK_INPUT;
4537 /* Make sure the values are reasonable, and try to preserve the
4538 distance between start and end. */
4539 if (start < 0)
4540 start = 0;
4541 else if (start > top_range)
4542 start = top_range;
4543 end = start + length;
4545 if (end < start)
4546 end = start;
4547 else if (end > top_range && ! dragging)
4548 end = top_range;
4550 /* Store the adjusted setting in the scroll bar. */
4551 XSETINT (bar->start, start);
4552 XSETINT (bar->end, end);
4554 /* Clip the end position, just for display. */
4555 if (end > top_range)
4556 end = top_range;
4558 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
4559 top positions, to make sure the handle is always at least that
4560 many pixels tall. */
4561 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
4563 SetControlMinimum (ch, 0);
4564 /* Don't inadvertently activate deactivated scroll bars */
4565 if (GetControlMaximum (ch) != -1)
4566 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
4567 - (end - start));
4568 SetControlValue (ch, start);
4569 #if TARGET_API_MAC_CARBON
4570 SetControlViewSize (ch, end - start);
4571 #endif
4573 UNBLOCK_INPUT;
4576 #endif /* !USE_TOOLKIT_SCROLL_BARS */
4578 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
4579 nil. */
4581 static void
4582 x_scroll_bar_remove (bar)
4583 struct scroll_bar *bar;
4585 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4587 BLOCK_INPUT;
4589 /* Destroy the Mac scroll bar control */
4590 DisposeControl (SCROLL_BAR_CONTROL_HANDLE (bar));
4592 /* Disassociate this scroll bar from its window. */
4593 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
4595 UNBLOCK_INPUT;
4599 /* Set the handle of the vertical scroll bar for WINDOW to indicate
4600 that we are displaying PORTION characters out of a total of WHOLE
4601 characters, starting at POSITION. If WINDOW has no scroll bar,
4602 create one. */
4604 static void
4605 XTset_vertical_scroll_bar (w, portion, whole, position)
4606 struct window *w;
4607 int portion, whole, position;
4609 struct frame *f = XFRAME (w->frame);
4610 struct scroll_bar *bar;
4611 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
4612 int window_y, window_height;
4614 /* Get window dimensions. */
4615 window_box (w, -1, 0, &window_y, 0, &window_height);
4616 top = window_y;
4617 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
4618 height = window_height;
4620 /* Compute the left edge of the scroll bar area. */
4621 left = WINDOW_SCROLL_BAR_AREA_X (w);
4623 /* Compute the width of the scroll bar which might be less than
4624 the width of the area reserved for the scroll bar. */
4625 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
4626 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
4627 else
4628 sb_width = width;
4630 /* Compute the left edge of the scroll bar. */
4631 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
4632 sb_left = left;
4633 else
4634 sb_left = left + width - sb_width;
4636 /* Adjustments according to Inside Macintosh to make it look nice */
4637 disp_top = top;
4638 disp_height = height;
4639 if (disp_top == 0)
4641 disp_top = -1;
4642 disp_height++;
4644 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
4646 disp_top++;
4647 disp_height--;
4650 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
4651 sb_left++;
4653 /* Does the scroll bar exist yet? */
4654 if (NILP (w->vertical_scroll_bar))
4656 BLOCK_INPUT;
4657 mac_clear_area (f, left, top, width, height);
4658 UNBLOCK_INPUT;
4659 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
4660 disp_height);
4661 XSETVECTOR (w->vertical_scroll_bar, bar);
4663 else
4665 /* It may just need to be moved and resized. */
4666 ControlHandle ch;
4668 bar = XSCROLL_BAR (w->vertical_scroll_bar);
4669 ch = SCROLL_BAR_CONTROL_HANDLE (bar);
4671 BLOCK_INPUT;
4673 /* If already correctly positioned, do nothing. */
4674 if (!(XINT (bar->left) == sb_left
4675 && XINT (bar->top) == top
4676 && XINT (bar->width) == sb_width
4677 && XINT (bar->height) == height))
4679 /* Since toolkit scroll bars are smaller than the space reserved
4680 for them on the frame, we have to clear "under" them. */
4681 mac_clear_area (f, left, top, width, height);
4683 HideControl (ch);
4684 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
4685 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
4686 disp_height);
4687 if (sb_width < disp_height)
4688 ShowControl (ch);
4690 /* Remember new settings. */
4691 XSETINT (bar->left, sb_left);
4692 XSETINT (bar->top, top);
4693 XSETINT (bar->width, sb_width);
4694 XSETINT (bar->height, height);
4695 #ifdef USE_TOOLKIT_SCROLL_BARS
4696 bar->track_top = Qnil;
4697 bar->track_height = Qnil;
4698 #endif
4701 UNBLOCK_INPUT;
4704 #ifdef USE_TOOLKIT_SCROLL_BARS
4705 if (NILP (bar->track_top))
4707 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
4708 Rect r0, r1;
4710 BLOCK_INPUT;
4712 SetControl32BitMinimum (ch, 0);
4713 SetControl32BitMaximum (ch, 1);
4714 SetControlViewSize (ch, 1);
4716 /* Move the scroll bar thumb to the top. */
4717 SetControl32BitValue (ch, 0);
4718 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
4720 /* Move the scroll bar thumb to the bottom. */
4721 SetControl32BitValue (ch, 1);
4722 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
4724 UnionRect (&r0, &r1, &r0);
4725 XSETINT (bar->track_top, r0.top);
4726 XSETINT (bar->track_height, r0.bottom - r0.top);
4728 UNBLOCK_INPUT;
4731 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
4732 #else /* not USE_TOOLKIT_SCROLL_BARS */
4733 /* Set the scroll bar's current state, unless we're currently being
4734 dragged. */
4735 if (NILP (bar->dragging))
4737 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
4739 if (whole == 0)
4740 x_scroll_bar_set_handle (bar, 0, top_range, 0);
4741 else
4743 int start = ((double) position * top_range) / whole;
4744 int end = ((double) (position + portion) * top_range) / whole;
4745 x_scroll_bar_set_handle (bar, start, end, 0);
4748 #endif /* not USE_TOOLKIT_SCROLL_BARS */
4752 /* The following three hooks are used when we're doing a thorough
4753 redisplay of the frame. We don't explicitly know which scroll bars
4754 are going to be deleted, because keeping track of when windows go
4755 away is a real pain - "Can you say set-window-configuration, boys
4756 and girls?" Instead, we just assert at the beginning of redisplay
4757 that *all* scroll bars are to be removed, and then save a scroll bar
4758 from the fiery pit when we actually redisplay its window. */
4760 /* Arrange for all scroll bars on FRAME to be removed at the next call
4761 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
4762 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
4764 static void
4765 XTcondemn_scroll_bars (frame)
4766 FRAME_PTR frame;
4768 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
4769 while (! NILP (FRAME_SCROLL_BARS (frame)))
4771 Lisp_Object bar;
4772 bar = FRAME_SCROLL_BARS (frame);
4773 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
4774 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
4775 XSCROLL_BAR (bar)->prev = Qnil;
4776 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
4777 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
4778 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
4783 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
4784 Note that WINDOW isn't necessarily condemned at all. */
4786 static void
4787 XTredeem_scroll_bar (window)
4788 struct window *window;
4790 struct scroll_bar *bar;
4791 struct frame *f;
4793 /* We can't redeem this window's scroll bar if it doesn't have one. */
4794 if (NILP (window->vertical_scroll_bar))
4795 abort ();
4797 bar = XSCROLL_BAR (window->vertical_scroll_bar);
4799 /* Unlink it from the condemned list. */
4800 f = XFRAME (WINDOW_FRAME (window));
4801 if (NILP (bar->prev))
4803 /* If the prev pointer is nil, it must be the first in one of
4804 the lists. */
4805 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
4806 /* It's not condemned. Everything's fine. */
4807 return;
4808 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4809 window->vertical_scroll_bar))
4810 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
4811 else
4812 /* If its prev pointer is nil, it must be at the front of
4813 one or the other! */
4814 abort ();
4816 else
4817 XSCROLL_BAR (bar->prev)->next = bar->next;
4819 if (! NILP (bar->next))
4820 XSCROLL_BAR (bar->next)->prev = bar->prev;
4822 bar->next = FRAME_SCROLL_BARS (f);
4823 bar->prev = Qnil;
4824 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
4825 if (! NILP (bar->next))
4826 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4829 /* Remove all scroll bars on FRAME that haven't been saved since the
4830 last call to `*condemn_scroll_bars_hook'. */
4832 static void
4833 XTjudge_scroll_bars (f)
4834 FRAME_PTR f;
4836 Lisp_Object bar, next;
4838 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
4840 /* Clear out the condemned list now so we won't try to process any
4841 more events on the hapless scroll bars. */
4842 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
4844 for (; ! NILP (bar); bar = next)
4846 struct scroll_bar *b = XSCROLL_BAR (bar);
4848 x_scroll_bar_remove (b);
4850 next = b->next;
4851 b->next = b->prev = Qnil;
4854 /* Now there should be no references to the condemned scroll bars,
4855 and they should get garbage-collected. */
4859 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
4860 is set to something other than NO_EVENT, it is enqueued.
4862 This may be called from a signal handler, so we have to ignore GC
4863 mark bits. */
4865 static void
4866 x_scroll_bar_handle_click (bar, part_code, er, bufp)
4867 struct scroll_bar *bar;
4868 ControlPartCode part_code;
4869 EventRecord *er;
4870 struct input_event *bufp;
4872 int win_y, top_range;
4874 if (! GC_WINDOWP (bar->window))
4875 abort ();
4877 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4878 bufp->frame_or_window = bar->window;
4879 bufp->arg = Qnil;
4881 bar->dragging = Qnil;
4883 switch (part_code)
4885 case kControlUpButtonPart:
4886 bufp->part = scroll_bar_up_arrow;
4887 break;
4888 case kControlDownButtonPart:
4889 bufp->part = scroll_bar_down_arrow;
4890 break;
4891 case kControlPageUpPart:
4892 bufp->part = scroll_bar_above_handle;
4893 break;
4894 case kControlPageDownPart:
4895 bufp->part = scroll_bar_below_handle;
4896 break;
4897 #if TARGET_API_MAC_CARBON
4898 default:
4899 #else
4900 case kControlIndicatorPart:
4901 #endif
4902 if (er->what == mouseDown)
4903 bar->dragging = make_number (0);
4904 XSETVECTOR (last_mouse_scroll_bar, bar);
4905 bufp->part = scroll_bar_handle;
4906 break;
4909 win_y = XINT (bufp->y) - XINT (bar->top);
4910 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
4912 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
4914 win_y -= 24;
4916 if (! NILP (bar->dragging))
4917 win_y -= XINT (bar->dragging);
4919 if (win_y < 0)
4920 win_y = 0;
4921 if (win_y > top_range)
4922 win_y = top_range;
4924 XSETINT (bufp->x, win_y);
4925 XSETINT (bufp->y, top_range);
4928 #ifndef USE_TOOLKIT_SCROLL_BARS
4930 /* Handle some mouse motion while someone is dragging the scroll bar.
4932 This may be called from a signal handler, so we have to ignore GC
4933 mark bits. */
4935 static void
4936 x_scroll_bar_note_movement (bar, y_pos, t)
4937 struct scroll_bar *bar;
4938 int y_pos;
4939 Time t;
4941 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
4943 last_mouse_movement_time = t;
4945 f->mouse_moved = 1;
4946 XSETVECTOR (last_mouse_scroll_bar, bar);
4948 /* If we're dragging the bar, display it. */
4949 if (! GC_NILP (bar->dragging))
4951 /* Where should the handle be now? */
4952 int new_start = y_pos - 24;
4954 if (new_start != XINT (bar->start))
4956 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
4958 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
4963 #endif /* !USE_TOOLKIT_SCROLL_BARS */
4965 /* Return information to the user about the current position of the mouse
4966 on the scroll bar. */
4968 static void
4969 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
4970 FRAME_PTR *fp;
4971 Lisp_Object *bar_window;
4972 enum scroll_bar_part *part;
4973 Lisp_Object *x, *y;
4974 unsigned long *time;
4976 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
4977 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
4978 #if TARGET_API_MAC_CARBON
4979 WindowPtr wp = GetControlOwner (ch);
4980 #else
4981 WindowPtr wp = (*ch)->contrlOwner;
4982 #endif
4983 Point mouse_pos;
4984 struct frame *f = mac_window_to_frame (wp);
4985 int win_y, top_range;
4987 SetPortWindowPort (wp);
4989 GetMouse (&mouse_pos);
4991 win_y = mouse_pos.v - XINT (bar->top);
4992 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
4994 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
4996 win_y -= 24;
4998 if (! NILP (bar->dragging))
4999 win_y -= XINT (bar->dragging);
5001 if (win_y < 0)
5002 win_y = 0;
5003 if (win_y > top_range)
5004 win_y = top_range;
5006 *fp = f;
5007 *bar_window = bar->window;
5009 if (! NILP (bar->dragging))
5010 *part = scroll_bar_handle;
5011 else if (win_y < XINT (bar->start))
5012 *part = scroll_bar_above_handle;
5013 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5014 *part = scroll_bar_handle;
5015 else
5016 *part = scroll_bar_below_handle;
5018 XSETINT (*x, win_y);
5019 XSETINT (*y, top_range);
5021 f->mouse_moved = 0;
5022 last_mouse_scroll_bar = Qnil;
5024 *time = last_mouse_movement_time;
5028 /* The screen has been cleared so we may have changed foreground or
5029 background colors, and the scroll bars may need to be redrawn.
5030 Clear out the scroll bars, and ask for expose events, so we can
5031 redraw them. */
5033 void
5034 x_scroll_bar_clear (f)
5035 FRAME_PTR f;
5037 XTcondemn_scroll_bars (f);
5038 XTjudge_scroll_bars (f);
5042 /***********************************************************************
5043 Text Cursor
5044 ***********************************************************************/
5046 /* Set clipping for output in glyph row ROW. W is the window in which
5047 we operate. GC is the graphics context to set clipping in.
5049 ROW may be a text row or, e.g., a mode line. Text rows must be
5050 clipped to the interior of the window dedicated to text display,
5051 mode lines must be clipped to the whole window. */
5053 static void
5054 x_clip_to_row (w, row, area, gc)
5055 struct window *w;
5056 struct glyph_row *row;
5057 int area;
5058 GC gc;
5060 struct frame *f = XFRAME (WINDOW_FRAME (w));
5061 Rect clip_rect;
5062 int window_x, window_y, window_width;
5064 window_box (w, area, &window_x, &window_y, &window_width, 0);
5066 clip_rect.left = window_x;
5067 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
5068 clip_rect.top = max (clip_rect.top, window_y);
5069 clip_rect.right = clip_rect.left + window_width;
5070 clip_rect.bottom = clip_rect.top + row->visible_height;
5072 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
5076 /* Draw a hollow box cursor on window W in glyph row ROW. */
5078 static void
5079 x_draw_hollow_cursor (w, row)
5080 struct window *w;
5081 struct glyph_row *row;
5083 struct frame *f = XFRAME (WINDOW_FRAME (w));
5084 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
5085 Display *dpy = FRAME_MAC_DISPLAY (f);
5086 int x, y, wd, h;
5087 XGCValues xgcv;
5088 struct glyph *cursor_glyph;
5089 GC gc;
5091 /* Get the glyph the cursor is on. If we can't tell because
5092 the current matrix is invalid or such, give up. */
5093 cursor_glyph = get_phys_cursor_glyph (w);
5094 if (cursor_glyph == NULL)
5095 return;
5097 /* Compute frame-relative coordinates for phys cursor. */
5098 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
5099 y = get_phys_cursor_geometry (w, row, cursor_glyph, &h);
5100 wd = w->phys_cursor_width;
5102 /* The foreground of cursor_gc is typically the same as the normal
5103 background color, which can cause the cursor box to be invisible. */
5104 xgcv.foreground = f->output_data.mac->cursor_pixel;
5105 if (dpyinfo->scratch_cursor_gc)
5106 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
5107 else
5108 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
5109 GCForeground, &xgcv);
5110 gc = dpyinfo->scratch_cursor_gc;
5112 /* Set clipping, draw the rectangle, and reset clipping again. */
5113 x_clip_to_row (w, row, TEXT_AREA, gc);
5114 mac_draw_rectangle (f, gc, x, y, wd, h);
5115 mac_reset_clip_rectangles (dpy, gc);
5119 /* Draw a bar cursor on window W in glyph row ROW.
5121 Implementation note: One would like to draw a bar cursor with an
5122 angle equal to the one given by the font property XA_ITALIC_ANGLE.
5123 Unfortunately, I didn't find a font yet that has this property set.
5124 --gerd. */
5126 static void
5127 x_draw_bar_cursor (w, row, width, kind)
5128 struct window *w;
5129 struct glyph_row *row;
5130 int width;
5131 enum text_cursor_kinds kind;
5133 struct frame *f = XFRAME (w->frame);
5134 struct glyph *cursor_glyph;
5136 /* If cursor is out of bounds, don't draw garbage. This can happen
5137 in mini-buffer windows when switching between echo area glyphs
5138 and mini-buffer. */
5139 cursor_glyph = get_phys_cursor_glyph (w);
5140 if (cursor_glyph == NULL)
5141 return;
5143 /* If on an image, draw like a normal cursor. That's usually better
5144 visible than drawing a bar, esp. if the image is large so that
5145 the bar might not be in the window. */
5146 if (cursor_glyph->type == IMAGE_GLYPH)
5148 struct glyph_row *row;
5149 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
5150 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
5152 else
5154 Display *dpy = FRAME_MAC_DISPLAY (f);
5155 Window window = FRAME_MAC_WINDOW (f);
5156 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
5157 unsigned long mask = GCForeground | GCBackground;
5158 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
5159 XGCValues xgcv;
5161 /* If the glyph's background equals the color we normally draw
5162 the bar cursor in, the bar cursor in its normal color is
5163 invisible. Use the glyph's foreground color instead in this
5164 case, on the assumption that the glyph's colors are chosen so
5165 that the glyph is legible. */
5166 if (face->background == f->output_data.mac->cursor_pixel)
5167 xgcv.background = xgcv.foreground = face->foreground;
5168 else
5169 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
5171 if (gc)
5172 XChangeGC (dpy, gc, mask, &xgcv);
5173 else
5175 gc = XCreateGC (dpy, window, mask, &xgcv);
5176 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
5179 if (width < 0)
5180 width = FRAME_CURSOR_WIDTH (f);
5181 width = min (cursor_glyph->pixel_width, width);
5183 w->phys_cursor_width = width;
5184 x_clip_to_row (w, row, TEXT_AREA, gc);
5186 if (kind == BAR_CURSOR)
5187 mac_fill_rectangle (f, gc,
5188 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
5189 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
5190 width, row->height);
5191 else
5192 mac_fill_rectangle (f, gc,
5193 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
5194 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
5195 row->height - width),
5196 cursor_glyph->pixel_width,
5197 width);
5199 mac_reset_clip_rectangles (dpy, gc);
5204 /* RIF: Define cursor CURSOR on frame F. */
5206 static void
5207 mac_define_frame_cursor (f, cursor)
5208 struct frame *f;
5209 Cursor cursor;
5211 SetThemeCursor (cursor);
5215 /* RIF: Clear area on frame F. */
5217 static void
5218 mac_clear_frame_area (f, x, y, width, height)
5219 struct frame *f;
5220 int x, y, width, height;
5222 mac_clear_area (f, x, y, width, height);
5226 /* RIF: Draw cursor on window W. */
5228 static void
5229 mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
5230 struct window *w;
5231 struct glyph_row *glyph_row;
5232 int x, y;
5233 int cursor_type, cursor_width;
5234 int on_p, active_p;
5236 if (on_p)
5238 w->phys_cursor_type = cursor_type;
5239 w->phys_cursor_on_p = 1;
5241 if (glyph_row->exact_window_width_line_p
5242 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
5244 glyph_row->cursor_in_fringe_p = 1;
5245 draw_fringe_bitmap (w, glyph_row, 0);
5247 else
5248 switch (cursor_type)
5250 case HOLLOW_BOX_CURSOR:
5251 x_draw_hollow_cursor (w, glyph_row);
5252 break;
5254 case FILLED_BOX_CURSOR:
5255 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
5256 break;
5258 case BAR_CURSOR:
5259 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
5260 break;
5262 case HBAR_CURSOR:
5263 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
5264 break;
5266 case NO_CURSOR:
5267 w->phys_cursor_width = 0;
5268 break;
5270 default:
5271 abort ();
5277 /* Icons. */
5279 #if 0 /* MAC_TODO: no icon support yet. */
5281 x_bitmap_icon (f, icon)
5282 struct frame *f;
5283 Lisp_Object icon;
5285 HANDLE hicon;
5287 if (FRAME_W32_WINDOW (f) == 0)
5288 return 1;
5290 if (NILP (icon))
5291 hicon = LoadIcon (hinst, EMACS_CLASS);
5292 else if (STRINGP (icon))
5293 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
5294 LR_DEFAULTSIZE | LR_LOADFROMFILE);
5295 else if (SYMBOLP (icon))
5297 LPCTSTR name;
5299 if (EQ (icon, intern ("application")))
5300 name = (LPCTSTR) IDI_APPLICATION;
5301 else if (EQ (icon, intern ("hand")))
5302 name = (LPCTSTR) IDI_HAND;
5303 else if (EQ (icon, intern ("question")))
5304 name = (LPCTSTR) IDI_QUESTION;
5305 else if (EQ (icon, intern ("exclamation")))
5306 name = (LPCTSTR) IDI_EXCLAMATION;
5307 else if (EQ (icon, intern ("asterisk")))
5308 name = (LPCTSTR) IDI_ASTERISK;
5309 else if (EQ (icon, intern ("winlogo")))
5310 name = (LPCTSTR) IDI_WINLOGO;
5311 else
5312 return 1;
5314 hicon = LoadIcon (NULL, name);
5316 else
5317 return 1;
5319 if (hicon == NULL)
5320 return 1;
5322 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
5323 (LPARAM) hicon);
5325 return 0;
5327 #endif /* MAC_TODO */
5329 /************************************************************************
5330 Handling X errors
5331 ************************************************************************/
5333 /* Display Error Handling functions not used on W32. Listing them here
5334 helps diff stay in step when comparing w32term.c with xterm.c.
5336 x_error_catcher (display, error)
5337 x_catch_errors (dpy)
5338 x_catch_errors_unwind (old_val)
5339 x_check_errors (dpy, format)
5340 x_had_errors_p (dpy)
5341 x_clear_errors (dpy)
5342 x_uncatch_errors (dpy, count)
5343 x_trace_wire ()
5344 x_connection_signal (signalnum)
5345 x_connection_closed (dpy, error_message)
5346 x_error_quitter (display, error)
5347 x_error_handler (display, error)
5348 x_io_error_quitter (display)
5353 /* Changing the font of the frame. */
5355 /* Give frame F the font named FONTNAME as its default font, and
5356 return the full name of that font. FONTNAME may be a wildcard
5357 pattern; in that case, we choose some font that fits the pattern.
5358 The return value shows which font we chose. */
5360 Lisp_Object
5361 x_new_font (f, fontname)
5362 struct frame *f;
5363 register char *fontname;
5365 struct font_info *fontp
5366 = FS_LOAD_FONT (f, 0, fontname, -1);
5368 if (!fontp)
5369 return Qnil;
5371 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
5372 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
5373 FRAME_FONTSET (f) = -1;
5375 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
5376 FRAME_SPACE_WIDTH (f) = fontp->space_width;
5377 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
5379 compute_fringe_widths (f, 1);
5381 /* Compute the scroll bar width in character columns. */
5382 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
5384 int wid = FRAME_COLUMN_WIDTH (f);
5385 FRAME_CONFIG_SCROLL_BAR_COLS (f)
5386 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
5388 else
5390 int wid = FRAME_COLUMN_WIDTH (f);
5391 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
5394 /* Now make the frame display the given font. */
5395 if (FRAME_MAC_WINDOW (f) != 0)
5397 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
5398 FRAME_FONT (f));
5399 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
5400 FRAME_FONT (f));
5401 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
5402 FRAME_FONT (f));
5404 /* Don't change the size of a tip frame; there's no point in
5405 doing it because it's done in Fx_show_tip, and it leads to
5406 problems because the tip frame has no widget. */
5407 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
5408 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
5411 return build_string (fontp->full_name);
5414 /* Give frame F the fontset named FONTSETNAME as its default font, and
5415 return the full name of that fontset. FONTSETNAME may be a wildcard
5416 pattern; in that case, we choose some fontset that fits the pattern.
5417 The return value shows which fontset we chose. */
5419 Lisp_Object
5420 x_new_fontset (f, fontsetname)
5421 struct frame *f;
5422 char *fontsetname;
5424 int fontset = fs_query_fontset (build_string (fontsetname), 0);
5425 Lisp_Object result;
5427 if (fontset < 0)
5428 return Qnil;
5430 if (FRAME_FONTSET (f) == fontset)
5431 /* This fontset is already set in frame F. There's nothing more
5432 to do. */
5433 return fontset_name (fontset);
5435 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
5437 if (!STRINGP (result))
5438 /* Can't load ASCII font. */
5439 return Qnil;
5441 /* Since x_new_font doesn't update any fontset information, do it now. */
5442 FRAME_FONTSET (f) = fontset;
5444 return build_string (fontsetname);
5448 /***********************************************************************
5449 TODO: W32 Input Methods
5450 ***********************************************************************/
5451 /* Listing missing functions from xterm.c helps diff stay in step.
5453 xim_destroy_callback (xim, client_data, call_data)
5454 xim_open_dpy (dpyinfo, resource_name)
5455 struct xim_inst_t
5456 xim_instantiate_callback (display, client_data, call_data)
5457 xim_initialize (dpyinfo, resource_name)
5458 xim_close_dpy (dpyinfo)
5463 void
5464 mac_get_window_bounds (f, inner, outer)
5465 struct frame *f;
5466 Rect *inner, *outer;
5468 #if TARGET_API_MAC_CARBON
5469 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
5470 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
5471 #else /* not TARGET_API_MAC_CARBON */
5472 RgnHandle region = NewRgn ();
5474 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
5475 *inner = (*region)->rgnBBox;
5476 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
5477 *outer = (*region)->rgnBBox;
5478 DisposeRgn (region);
5479 #endif /* not TARGET_API_MAC_CARBON */
5484 /* Calculate the absolute position in frame F
5485 from its current recorded position values and gravity. */
5487 void
5488 x_calc_absolute_position (f)
5489 struct frame *f;
5491 int width_diff = 0, height_diff = 0;
5492 int flags = f->size_hint_flags;
5493 Rect inner, outer;
5495 /* We have nothing to do if the current position
5496 is already for the top-left corner. */
5497 if (! ((flags & XNegative) || (flags & YNegative)))
5498 return;
5500 /* Find the offsets of the outside upper-left corner of
5501 the inner window, with respect to the outer window. */
5502 mac_get_window_bounds (f, &inner, &outer);
5504 width_diff = (outer.right - outer.left) - (inner.right - inner.left);
5505 height_diff = (outer.bottom - outer.top) - (inner.bottom - inner.top);
5507 /* Treat negative positions as relative to the leftmost bottommost
5508 position that fits on the screen. */
5509 if (flags & XNegative)
5510 f->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
5511 - width_diff
5512 - FRAME_PIXEL_WIDTH (f)
5513 + f->left_pos);
5515 if (flags & YNegative)
5516 f->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
5517 - height_diff
5518 - FRAME_PIXEL_HEIGHT (f)
5519 + f->top_pos);
5521 /* The left_pos and top_pos
5522 are now relative to the top and left screen edges,
5523 so the flags should correspond. */
5524 f->size_hint_flags &= ~ (XNegative | YNegative);
5527 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
5528 to really change the position, and 0 when calling from
5529 x_make_frame_visible (in that case, XOFF and YOFF are the current
5530 position values). It is -1 when calling from x_set_frame_parameters,
5531 which means, do adjust for borders but don't change the gravity. */
5533 void
5534 x_set_offset (f, xoff, yoff, change_gravity)
5535 struct frame *f;
5536 register int xoff, yoff;
5537 int change_gravity;
5539 if (change_gravity > 0)
5541 f->top_pos = yoff;
5542 f->left_pos = xoff;
5543 f->size_hint_flags &= ~ (XNegative | YNegative);
5544 if (xoff < 0)
5545 f->size_hint_flags |= XNegative;
5546 if (yoff < 0)
5547 f->size_hint_flags |= YNegative;
5548 f->win_gravity = NorthWestGravity;
5550 x_calc_absolute_position (f);
5552 BLOCK_INPUT;
5553 x_wm_set_size_hint (f, (long) 0, 0);
5555 #if TARGET_API_MAC_CARBON
5556 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
5557 /* If the title bar is completely outside the screen, adjust the
5558 position. */
5559 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
5560 kWindowConstrainMoveRegardlessOfFit
5561 | kWindowConstrainAllowPartial, NULL, NULL);
5562 x_real_positions (f, &f->left_pos, &f->top_pos);
5563 #else
5565 Rect inner, outer, screen_rect, dummy;
5566 RgnHandle region = NewRgn ();
5568 mac_get_window_bounds (f, &inner, &outer);
5569 f->x_pixels_diff = inner.left - outer.left;
5570 f->y_pixels_diff = inner.top - outer.top;
5571 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
5572 f->top_pos + f->y_pixels_diff, false);
5574 /* If the title bar is completely outside the screen, adjust the
5575 position. The variable `outer' holds the title bar rectangle.
5576 The variable `inner' holds slightly smaller one than `outer',
5577 so that the calculation of overlapping may not become too
5578 strict. */
5579 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
5580 outer = (*region)->rgnBBox;
5581 DisposeRgn (region);
5582 inner = outer;
5583 InsetRect (&inner, 8, 8);
5584 screen_rect = qd.screenBits.bounds;
5585 screen_rect.top += GetMBarHeight ();
5587 if (!SectRect (&inner, &screen_rect, &dummy))
5589 if (inner.right <= screen_rect.left)
5590 f->left_pos = screen_rect.left;
5591 else if (inner.left >= screen_rect.right)
5592 f->left_pos = screen_rect.right - (outer.right - outer.left);
5594 if (inner.bottom <= screen_rect.top)
5595 f->top_pos = screen_rect.top;
5596 else if (inner.top >= screen_rect.bottom)
5597 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
5599 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
5600 f->top_pos + f->y_pixels_diff, false);
5603 #endif
5605 UNBLOCK_INPUT;
5608 /* Call this to change the size of frame F's x-window.
5609 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
5610 for this size change and subsequent size changes.
5611 Otherwise we leave the window gravity unchanged. */
5613 void
5614 x_set_window_size (f, change_gravity, cols, rows)
5615 struct frame *f;
5616 int change_gravity;
5617 int cols, rows;
5619 int pixelwidth, pixelheight;
5621 BLOCK_INPUT;
5623 check_frame_size (f, &rows, &cols);
5624 f->scroll_bar_actual_width
5625 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
5627 compute_fringe_widths (f, 0);
5629 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
5630 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
5632 f->win_gravity = NorthWestGravity;
5633 x_wm_set_size_hint (f, (long) 0, 0);
5635 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
5636 #if TARGET_API_MAC_CARBON
5637 if (f->output_data.mac->hourglass_control)
5638 MoveControl (f->output_data.mac->hourglass_control,
5639 pixelwidth - HOURGLASS_WIDTH, 0);
5640 #endif
5642 /* Now, strictly speaking, we can't be sure that this is accurate,
5643 but the window manager will get around to dealing with the size
5644 change request eventually, and we'll hear how it went when the
5645 ConfigureNotify event gets here.
5647 We could just not bother storing any of this information here,
5648 and let the ConfigureNotify event set everything up, but that
5649 might be kind of confusing to the Lisp code, since size changes
5650 wouldn't be reported in the frame parameters until some random
5651 point in the future when the ConfigureNotify event arrives.
5653 We pass 1 for DELAY since we can't run Lisp code inside of
5654 a BLOCK_INPUT. */
5655 change_frame_size (f, rows, cols, 0, 1, 0);
5656 FRAME_PIXEL_WIDTH (f) = pixelwidth;
5657 FRAME_PIXEL_HEIGHT (f) = pixelheight;
5659 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
5660 receive in the ConfigureNotify event; if we get what we asked
5661 for, then the event won't cause the screen to become garbaged, so
5662 we have to make sure to do it here. */
5663 SET_FRAME_GARBAGED (f);
5665 XFlush (FRAME_X_DISPLAY (f));
5667 /* If cursor was outside the new size, mark it as off. */
5668 mark_window_cursors_off (XWINDOW (f->root_window));
5670 /* Clear out any recollection of where the mouse highlighting was,
5671 since it might be in a place that's outside the new frame size.
5672 Actually checking whether it is outside is a pain in the neck,
5673 so don't try--just let the highlighting be done afresh with new size. */
5674 cancel_mouse_face (f);
5676 UNBLOCK_INPUT;
5679 /* Mouse warping. */
5681 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
5683 void
5684 x_set_mouse_position (f, x, y)
5685 struct frame *f;
5686 int x, y;
5688 int pix_x, pix_y;
5690 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
5691 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
5693 if (pix_x < 0) pix_x = 0;
5694 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
5696 if (pix_y < 0) pix_y = 0;
5697 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
5699 x_set_mouse_pixel_position (f, pix_x, pix_y);
5702 void
5703 x_set_mouse_pixel_position (f, pix_x, pix_y)
5704 struct frame *f;
5705 int pix_x, pix_y;
5707 #if 0 /* MAC_TODO: CursorDeviceMoveTo is non-Carbon */
5708 BLOCK_INPUT;
5710 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
5711 0, 0, 0, 0, pix_x, pix_y);
5712 UNBLOCK_INPUT;
5713 #endif
5716 /* focus shifting, raising and lowering. */
5718 void
5719 x_focus_on_frame (f)
5720 struct frame *f;
5722 #if 0 /* This proves to be unpleasant. */
5723 x_raise_frame (f);
5724 #endif
5725 #if 0
5726 /* I don't think that the ICCCM allows programs to do things like this
5727 without the interaction of the window manager. Whatever you end up
5728 doing with this code, do it to x_unfocus_frame too. */
5729 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5730 RevertToPointerRoot, CurrentTime);
5731 #endif /* ! 0 */
5734 void
5735 x_unfocus_frame (f)
5736 struct frame *f;
5740 /* Raise frame F. */
5742 void
5743 x_raise_frame (f)
5744 struct frame *f;
5746 if (f->async_visible)
5748 BLOCK_INPUT;
5749 SelectWindow (FRAME_MAC_WINDOW (f));
5750 UNBLOCK_INPUT;
5754 /* Lower frame F. */
5756 void
5757 x_lower_frame (f)
5758 struct frame *f;
5760 if (f->async_visible)
5762 BLOCK_INPUT;
5763 SendBehind (FRAME_MAC_WINDOW (f), nil);
5764 UNBLOCK_INPUT;
5768 static void
5769 XTframe_raise_lower (f, raise_flag)
5770 FRAME_PTR f;
5771 int raise_flag;
5773 if (raise_flag)
5774 x_raise_frame (f);
5775 else
5776 x_lower_frame (f);
5779 /* Change of visibility. */
5781 static void
5782 mac_handle_visibility_change (f)
5783 struct frame *f;
5785 WindowPtr wp = FRAME_MAC_WINDOW (f);
5786 int visible = 0, iconified = 0;
5787 struct input_event buf;
5789 if (IsWindowVisible (wp))
5790 if (IsWindowCollapsed (wp))
5791 iconified = 1;
5792 else
5793 visible = 1;
5795 if (!f->async_visible && visible)
5797 if (f->iconified)
5799 /* wait_reading_process_output will notice this and update
5800 the frame's display structures. If we were made
5801 invisible, we should not set garbaged, because that stops
5802 redrawing on Update events. */
5803 SET_FRAME_GARBAGED (f);
5805 EVENT_INIT (buf);
5806 buf.kind = DEICONIFY_EVENT;
5807 XSETFRAME (buf.frame_or_window, f);
5808 kbd_buffer_store_event (&buf);
5810 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
5811 /* Force a redisplay sooner or later to update the
5812 frame titles in case this is the second frame. */
5813 record_asynch_buffer_change ();
5815 else if (f->async_visible && !visible)
5816 if (iconified)
5818 EVENT_INIT (buf);
5819 buf.kind = ICONIFY_EVENT;
5820 XSETFRAME (buf.frame_or_window, f);
5821 kbd_buffer_store_event (&buf);
5824 f->async_visible = visible;
5825 f->async_iconified = iconified;
5828 /* This tries to wait until the frame is really visible.
5829 However, if the window manager asks the user where to position
5830 the frame, this will return before the user finishes doing that.
5831 The frame will not actually be visible at that time,
5832 but it will become visible later when the window manager
5833 finishes with it. */
5835 void
5836 x_make_frame_visible (f)
5837 struct frame *f;
5839 Lisp_Object type;
5840 int original_top, original_left;
5842 BLOCK_INPUT;
5844 if (! FRAME_VISIBLE_P (f))
5846 /* We test FRAME_GARBAGED_P here to make sure we don't
5847 call x_set_offset a second time
5848 if we get to x_make_frame_visible a second time
5849 before the window gets really visible. */
5850 if (! FRAME_ICONIFIED_P (f)
5851 && ! f->output_data.mac->asked_for_visible)
5852 #if TARGET_API_MAC_CARBON
5853 if (!(FRAME_SIZE_HINTS (f)->flags & (USPosition | PPosition)))
5855 struct frame *sf = SELECTED_FRAME ();
5856 if (!FRAME_MAC_P (sf))
5857 RepositionWindow (FRAME_MAC_WINDOW (f), NULL,
5858 kWindowCenterOnMainScreen);
5859 else
5860 RepositionWindow (FRAME_MAC_WINDOW (f),
5861 FRAME_MAC_WINDOW (sf),
5862 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
5863 kWindowCascadeStartAtParentWindowScreen
5864 #else
5865 kWindowCascadeOnParentWindowScreen
5866 #endif
5868 x_real_positions (f, &f->left_pos, &f->top_pos);
5870 else
5871 #endif
5872 x_set_offset (f, f->left_pos, f->top_pos, 0);
5874 f->output_data.mac->asked_for_visible = 1;
5876 SelectWindow (FRAME_MAC_WINDOW (f));
5877 CollapseWindow (FRAME_MAC_WINDOW (f), false);
5878 ShowWindow (FRAME_MAC_WINDOW (f));
5881 XFlush (FRAME_MAC_DISPLAY (f));
5883 /* Synchronize to ensure Emacs knows the frame is visible
5884 before we do anything else. We do this loop with input not blocked
5885 so that incoming events are handled. */
5887 Lisp_Object frame;
5888 int count;
5890 /* This must come after we set COUNT. */
5891 UNBLOCK_INPUT;
5893 XSETFRAME (frame, f);
5895 /* Wait until the frame is visible. Process X events until a
5896 MapNotify event has been seen, or until we think we won't get a
5897 MapNotify at all.. */
5898 for (count = input_signal_count + 10;
5899 input_signal_count < count && !FRAME_VISIBLE_P (f);)
5901 /* Force processing of queued events. */
5902 x_sync (f);
5904 /* Machines that do polling rather than SIGIO have been
5905 observed to go into a busy-wait here. So we'll fake an
5906 alarm signal to let the handler know that there's something
5907 to be read. We used to raise a real alarm, but it seems
5908 that the handler isn't always enabled here. This is
5909 probably a bug. */
5910 if (input_polling_used ())
5912 /* It could be confusing if a real alarm arrives while
5913 processing the fake one. Turn it off and let the
5914 handler reset it. */
5915 extern void poll_for_input_1 P_ ((void));
5916 int old_poll_suppress_count = poll_suppress_count;
5917 poll_suppress_count = 1;
5918 poll_for_input_1 ();
5919 poll_suppress_count = old_poll_suppress_count;
5922 /* See if a MapNotify event has been processed. */
5923 FRAME_SAMPLE_VISIBILITY (f);
5928 /* Change from mapped state to withdrawn state. */
5930 /* Make the frame visible (mapped and not iconified). */
5932 void
5933 x_make_frame_invisible (f)
5934 struct frame *f;
5936 /* A deactivate event does not occur when the last visible frame is
5937 made invisible. So if we clear the highlight here, it will not
5938 be rehighlighted when it is made visible. */
5939 #if 0
5940 /* Don't keep the highlight on an invisible frame. */
5941 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
5942 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
5943 #endif
5945 BLOCK_INPUT;
5947 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5948 that the current position of the window is user-specified, rather than
5949 program-specified, so that when the window is mapped again, it will be
5950 placed at the same location, without forcing the user to position it
5951 by hand again (they have already done that once for this window.) */
5952 x_wm_set_size_hint (f, (long) 0, 1);
5954 HideWindow (FRAME_MAC_WINDOW (f));
5956 UNBLOCK_INPUT;
5958 #if !USE_CARBON_EVENTS
5959 mac_handle_visibility_change (f);
5960 #endif
5963 /* Change window state from mapped to iconified. */
5965 void
5966 x_iconify_frame (f)
5967 struct frame *f;
5969 OSErr err;
5971 /* A deactivate event does not occur when the last visible frame is
5972 iconified. So if we clear the highlight here, it will not be
5973 rehighlighted when it is deiconified. */
5974 #if 0
5975 /* Don't keep the highlight on an invisible frame. */
5976 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
5977 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
5978 #endif
5980 if (f->async_iconified)
5981 return;
5983 BLOCK_INPUT;
5985 FRAME_SAMPLE_VISIBILITY (f);
5987 if (! FRAME_VISIBLE_P (f))
5988 ShowWindow (FRAME_MAC_WINDOW (f));
5990 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
5992 UNBLOCK_INPUT;
5994 if (err != noErr)
5995 error ("Can't notify window manager of iconification");
5997 #if !USE_CARBON_EVENTS
5998 mac_handle_visibility_change (f);
5999 #endif
6003 /* Free X resources of frame F. */
6005 void
6006 x_free_frame_resources (f)
6007 struct frame *f;
6009 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6010 WindowPtr wp = FRAME_MAC_WINDOW (f);
6012 BLOCK_INPUT;
6014 if (wp != tip_window)
6015 remove_window_handler (wp);
6017 DisposeWindow (wp);
6018 if (wp == tip_window)
6019 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
6020 closed' event. So we reset tip_window here. */
6021 tip_window = NULL;
6023 free_frame_menubar (f);
6025 if (FRAME_FACE_CACHE (f))
6026 free_frame_faces (f);
6028 x_free_gcs (f);
6030 if (FRAME_SIZE_HINTS (f))
6031 xfree (FRAME_SIZE_HINTS (f));
6033 xfree (f->output_data.mac);
6034 f->output_data.mac = NULL;
6036 if (f == dpyinfo->x_focus_frame)
6037 dpyinfo->x_focus_frame = 0;
6038 if (f == dpyinfo->x_focus_event_frame)
6039 dpyinfo->x_focus_event_frame = 0;
6040 if (f == dpyinfo->x_highlight_frame)
6041 dpyinfo->x_highlight_frame = 0;
6043 if (f == dpyinfo->mouse_face_mouse_frame)
6045 dpyinfo->mouse_face_beg_row
6046 = dpyinfo->mouse_face_beg_col = -1;
6047 dpyinfo->mouse_face_end_row
6048 = dpyinfo->mouse_face_end_col = -1;
6049 dpyinfo->mouse_face_window = Qnil;
6050 dpyinfo->mouse_face_deferred_gc = 0;
6051 dpyinfo->mouse_face_mouse_frame = 0;
6054 UNBLOCK_INPUT;
6058 /* Destroy the X window of frame F. */
6060 void
6061 x_destroy_window (f)
6062 struct frame *f;
6064 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6066 x_free_frame_resources (f);
6068 dpyinfo->reference_count--;
6072 /* Setting window manager hints. */
6074 /* Set the normal size hints for the window manager, for frame F.
6075 FLAGS is the flags word to use--or 0 meaning preserve the flags
6076 that the window now has.
6077 If USER_POSITION is nonzero, we set the USPosition
6078 flag (this is useful when FLAGS is 0). */
6079 void
6080 x_wm_set_size_hint (f, flags, user_position)
6081 struct frame *f;
6082 long flags;
6083 int user_position;
6085 int base_width, base_height, width_inc, height_inc;
6086 int min_rows = 0, min_cols = 0;
6087 XSizeHints *size_hints;
6089 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
6090 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
6091 width_inc = FRAME_COLUMN_WIDTH (f);
6092 height_inc = FRAME_LINE_HEIGHT (f);
6094 check_frame_size (f, &min_rows, &min_cols);
6096 size_hints = FRAME_SIZE_HINTS (f);
6097 if (size_hints == NULL)
6099 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
6100 bzero (size_hints, sizeof (XSizeHints));
6103 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
6104 size_hints->width_inc = width_inc;
6105 size_hints->height_inc = height_inc;
6106 size_hints->min_width = base_width + min_cols * width_inc;
6107 size_hints->min_height = base_height + min_rows * height_inc;
6108 size_hints->base_width = base_width;
6109 size_hints->base_height = base_height;
6111 if (flags)
6112 size_hints->flags = flags;
6113 else if (user_position)
6115 size_hints->flags &= ~ PPosition;
6116 size_hints->flags |= USPosition;
6120 #if 0 /* MAC_TODO: hide application instead of iconify? */
6121 /* Used for IconicState or NormalState */
6123 void
6124 x_wm_set_window_state (f, state)
6125 struct frame *f;
6126 int state;
6128 #ifdef USE_X_TOOLKIT
6129 Arg al[1];
6131 XtSetArg (al[0], XtNinitialState, state);
6132 XtSetValues (f->output_data.x->widget, al, 1);
6133 #else /* not USE_X_TOOLKIT */
6134 Window window = FRAME_X_WINDOW (f);
6136 f->output_data.x->wm_hints.flags |= StateHint;
6137 f->output_data.x->wm_hints.initial_state = state;
6139 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
6140 #endif /* not USE_X_TOOLKIT */
6143 void
6144 x_wm_set_icon_pixmap (f, pixmap_id)
6145 struct frame *f;
6146 int pixmap_id;
6148 Pixmap icon_pixmap;
6150 #ifndef USE_X_TOOLKIT
6151 Window window = FRAME_X_WINDOW (f);
6152 #endif
6154 if (pixmap_id > 0)
6156 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
6157 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
6159 else
6161 /* It seems there is no way to turn off use of an icon pixmap.
6162 The following line does it, only if no icon has yet been created,
6163 for some window managers. But with mwm it crashes.
6164 Some people say it should clear the IconPixmapHint bit in this case,
6165 but that doesn't work, and the X consortium said it isn't the
6166 right thing at all. Since there is no way to win,
6167 best to explicitly give up. */
6168 #if 0
6169 f->output_data.x->wm_hints.icon_pixmap = None;
6170 #else
6171 return;
6172 #endif
6175 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
6178 Arg al[1];
6179 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
6180 XtSetValues (f->output_data.x->widget, al, 1);
6183 #else /* not USE_X_TOOLKIT */
6185 f->output_data.x->wm_hints.flags |= IconPixmapHint;
6186 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
6188 #endif /* not USE_X_TOOLKIT */
6191 #endif /* MAC_TODO */
6193 void
6194 x_wm_set_icon_position (f, icon_x, icon_y)
6195 struct frame *f;
6196 int icon_x, icon_y;
6198 #if 0 /* MAC_TODO: no icons on Mac */
6199 #ifdef USE_X_TOOLKIT
6200 Window window = XtWindow (f->output_data.x->widget);
6201 #else
6202 Window window = FRAME_X_WINDOW (f);
6203 #endif
6205 f->output_data.x->wm_hints.flags |= IconPositionHint;
6206 f->output_data.x->wm_hints.icon_x = icon_x;
6207 f->output_data.x->wm_hints.icon_y = icon_y;
6209 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
6210 #endif /* MAC_TODO */
6214 /***********************************************************************
6215 XLFD Pattern Match
6216 ***********************************************************************/
6218 /* An XLFD pattern is divided into blocks delimited by '*'. This
6219 structure holds information for each block. */
6220 struct xlfdpat_block
6222 /* Length of the pattern string in this block. Non-zero except for
6223 the first and the last blocks. */
6224 int len;
6226 /* Pattern string except the last character in this block. The last
6227 character is replaced with NUL in order to use it as a
6228 sentinel. */
6229 unsigned char *pattern;
6231 /* Last character of the pattern string. Must not be '?'. */
6232 unsigned char last_char;
6234 /* One of the tables for the Boyer-Moore string search. It
6235 specifies the number of positions to proceed for each character
6236 with which the match fails. */
6237 int skip[256];
6239 /* The skip value for the last character in the above `skip' is
6240 assigned to `infinity' in order to simplify a loop condition.
6241 The original value is saved here. */
6242 int last_char_skip;
6245 struct xlfdpat
6247 /* Normalized pattern string. "Normalized" means that capital
6248 letters are lowered, blocks are not empty except the first and
6249 the last ones, and trailing '?'s in a block that is not the last
6250 one are moved to the next one. The last character in each block
6251 is replaced with NUL. */
6252 unsigned char *buf;
6254 /* Number of characters except '*'s and trailing '?'s in the
6255 normalized pattern string. */
6256 int nchars;
6258 /* Number of trailing '?'s in the normalized pattern string. */
6259 int trailing_anychars;
6261 /* Number of blocks and information for each block. The latter is
6262 NULL if the pattern is exact (no '*' or '?' in it). */
6263 int nblocks;
6264 struct xlfdpat_block *blocks;
6267 static void
6268 xlfdpat_destroy (pat)
6269 struct xlfdpat *pat;
6271 if (pat)
6273 if (pat->buf)
6275 if (pat->blocks)
6276 xfree (pat->blocks);
6277 xfree (pat->buf);
6279 xfree (pat);
6283 static struct xlfdpat *
6284 xlfdpat_create (pattern)
6285 char *pattern;
6287 struct xlfdpat *pat;
6288 int nblocks, i, skip;
6289 unsigned char last_char, *p, *q, *anychar_head;
6290 struct xlfdpat_block *blk;
6292 pat = xmalloc (sizeof (struct xlfdpat));
6293 if (pat == NULL)
6294 goto error;
6296 pat->buf = xmalloc (strlen (pattern) + 1);
6297 if (pat->buf == NULL)
6298 goto error;
6300 /* Normalize the pattern string and store it to `pat->buf'. */
6301 nblocks = 0;
6302 anychar_head = NULL;
6303 q = pat->buf;
6304 last_char = '\0';
6305 for (p = pattern; *p; p++)
6307 unsigned char c = *p;
6309 if (c == '*')
6310 if (last_char == '*')
6311 /* ...a** -> ...a* */
6312 continue;
6313 else
6315 if (last_char == '?')
6316 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
6317 /* ...*??* -> ...*?? */
6318 continue;
6319 else
6320 /* ...a??* -> ...a*?? */
6322 *anychar_head++ = '*';
6323 c = '?';
6325 nblocks++;
6327 else if (c == '?')
6329 if (last_char != '?')
6330 anychar_head = q;
6332 else
6333 /* On Mac OS X 10.3, tolower also converts non-ASCII
6334 characters for some locales. */
6335 if (isascii (c))
6336 c = tolower (c);
6338 *q++ = last_char = c;
6340 *q = '\0';
6341 nblocks++;
6342 pat->nblocks = nblocks;
6343 if (last_char != '?')
6344 pat->trailing_anychars = 0;
6345 else
6347 pat->trailing_anychars = q - anychar_head;
6348 q = anychar_head;
6350 pat->nchars = q - pat->buf - (nblocks - 1);
6352 if (anychar_head == NULL && nblocks == 1)
6354 /* The pattern is exact. */
6355 pat->blocks = NULL;
6356 return pat;
6359 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
6360 if (pat->blocks == NULL)
6361 goto error;
6363 /* Divide the normalized pattern into blocks. */
6364 p = pat->buf;
6365 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
6367 blk->pattern = p;
6368 while (*p != '*')
6369 p++;
6370 blk->len = p - blk->pattern;
6371 p++;
6373 blk->pattern = p;
6374 blk->len = q - blk->pattern;
6376 /* Setup a table for the Boyer-Moore string search. */
6377 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
6378 if (blk->len != 0)
6380 blk->last_char = blk->pattern[blk->len - 1];
6381 blk->pattern[blk->len - 1] = '\0';
6383 for (skip = 1; skip < blk->len; skip++)
6384 if (blk->pattern[blk->len - skip - 1] == '?')
6385 break;
6387 for (i = 0; i < 256; i++)
6388 blk->skip[i] = skip;
6390 p = blk->pattern + (blk->len - skip);
6391 while (--skip > 0)
6392 blk->skip[*p++] = skip;
6394 blk->last_char_skip = blk->skip[blk->last_char];
6397 return pat;
6399 error:
6400 xlfdpat_destroy (pat);
6401 return NULL;
6404 static INLINE int
6405 xlfdpat_exact_p (pat)
6406 struct xlfdpat *pat;
6408 return pat->blocks == NULL;
6411 /* Return the first string in STRING + 0, ..., STRING + START_MAX such
6412 that the pattern in *BLK matches with its prefix. Return NULL
6413 there is no such strings. STRING must be lowered in advance. */
6415 static char *
6416 xlfdpat_block_match_1 (blk, string, start_max)
6417 struct xlfdpat_block *blk;
6418 unsigned char *string;
6419 int start_max;
6421 int start, infinity;
6422 unsigned char *p, *s;
6424 xassert (blk->len > 0);
6425 xassert (start_max + blk->len <= strlen (string));
6426 xassert (blk->last_char != '?');
6428 /* See the comments in the function `boyer_moore' (search.c) for the
6429 use of `infinity'. */
6430 infinity = start_max + blk->len + 1;
6431 blk->skip[blk->last_char] = infinity;
6433 start = 0;
6436 /* Check the last character of the pattern. */
6437 s = string + blk->len - 1;
6440 start += blk->skip[*(s + start)];
6442 while (start <= start_max);
6444 if (start < infinity)
6445 /* Couldn't find the last character. */
6446 return NULL;
6448 /* No less than `infinity' means we could find the last
6449 character at `s[start - infinity]'. */
6450 start -= infinity;
6452 /* Check the remaining characters. We prefer making no-'?'
6453 cases faster because the use of '?' is really rare. */
6454 p = blk->pattern;
6455 s = string + start;
6458 while (*p++ == *s++)
6461 while (*(p - 1) == '?');
6463 if (*(p - 1) == '\0')
6464 /* Matched. */
6465 return string + start;
6467 /* Didn't match. */
6468 start += blk->last_char_skip;
6470 while (start <= start_max);
6472 return NULL;
6475 #define xlfdpat_block_match(b, s, m) \
6476 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
6477 : xlfdpat_block_match_1 (b, s, m))
6479 /* Check if XLFD pattern PAT, which is generated by `xfldpat_create',
6480 matches with STRING. STRING must be lowered in advance. */
6482 static int
6483 xlfdpat_match (pat, string)
6484 struct xlfdpat *pat;
6485 unsigned char *string;
6487 int str_len, nblocks, i, start_max;
6488 struct xlfdpat_block *blk;
6489 unsigned char *s;
6491 xassert (pat->nblocks > 0);
6493 if (xlfdpat_exact_p (pat))
6494 return strcmp (pat->buf, string) == 0;
6496 /* The number of the characters in the string must not be smaller
6497 than that in the pattern. */
6498 str_len = strlen (string);
6499 if (str_len < pat->nchars + pat->trailing_anychars)
6500 return 0;
6502 /* Chop off the trailing '?'s. */
6503 str_len -= pat->trailing_anychars;
6505 /* The last block. When it is non-empty, it must match at the end
6506 of the string. */
6507 nblocks = pat->nblocks;
6508 blk = pat->blocks + (nblocks - 1);
6509 if (nblocks == 1)
6510 /* The last block is also the first one. */
6511 return (str_len == blk->len
6512 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
6513 else if (blk->len != 0)
6514 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
6515 return 0;
6517 /* The first block. When it is non-empty, it must match at the
6518 beginning of the string. */
6519 blk = pat->blocks;
6520 if (blk->len != 0)
6522 s = xlfdpat_block_match (blk, string, 0);
6523 if (s == NULL)
6524 return 0;
6525 string = s + blk->len;
6528 /* The rest of the blocks. */
6529 start_max = str_len - pat->nchars;
6530 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
6532 s = xlfdpat_block_match (blk, string, start_max);
6533 if (s == NULL)
6534 return 0;
6535 start_max -= s - string;
6536 string = s + blk->len;
6539 return 1;
6543 /***********************************************************************
6544 Fonts
6545 ***********************************************************************/
6547 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6549 struct font_info *
6550 x_get_font_info (f, font_idx)
6551 FRAME_PTR f;
6552 int font_idx;
6554 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
6557 /* the global font name table */
6558 static char **font_name_table = NULL;
6559 static int font_name_table_size = 0;
6560 static int font_name_count = 0;
6562 /* Alist linking font family names to Font Manager font family
6563 references (which can also be used as QuickDraw font IDs). We use
6564 an alist because hash tables are not ready when the terminal frame
6565 for Mac OS Classic is created. */
6566 static Lisp_Object fm_font_family_alist;
6567 #if USE_ATSUI
6568 /* Hash table linking font family names to ATSU font IDs. */
6569 static Lisp_Object atsu_font_id_hash;
6570 #endif
6572 /* Alist linking character set strings to Mac text encoding and Emacs
6573 coding system. */
6574 static Lisp_Object Vmac_charset_info_alist;
6576 static Lisp_Object
6577 create_text_encoding_info_alist ()
6579 Lisp_Object result = Qnil, rest;
6581 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6583 Lisp_Object charset_info = XCAR (rest);
6584 Lisp_Object charset, coding_system, text_encoding;
6585 Lisp_Object existing_info;
6587 if (!(CONSP (charset_info)
6588 && STRINGP (charset = XCAR (charset_info))
6589 && CONSP (XCDR (charset_info))
6590 && INTEGERP (text_encoding = XCAR (XCDR (charset_info)))
6591 && CONSP (XCDR (XCDR (charset_info)))
6592 && SYMBOLP (coding_system = XCAR (XCDR (XCDR (charset_info))))))
6593 continue;
6595 existing_info = assq_no_quit (text_encoding, result);
6596 if (NILP (existing_info))
6597 result = Fcons (list3 (text_encoding, coding_system, charset),
6598 result);
6599 else
6600 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
6601 XSETCDR (XCDR (existing_info),
6602 Fcons (charset, XCDR (XCDR (existing_info))));
6605 return result;
6609 static void
6610 decode_mac_font_name (name, size, coding_system)
6611 char *name;
6612 int size;
6613 Lisp_Object coding_system;
6615 struct coding_system coding;
6616 char *buf, *p;
6618 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
6620 for (p = name; *p; p++)
6621 if (!isascii (*p) || iscntrl (*p))
6622 break;
6624 if (*p)
6626 setup_coding_system (coding_system, &coding);
6627 coding.src_multibyte = 0;
6628 coding.dst_multibyte = 1;
6629 coding.mode |= CODING_MODE_LAST_BLOCK;
6630 coding.composing = COMPOSITION_DISABLED;
6631 buf = (char *) alloca (size);
6633 decode_coding (&coding, name, buf, strlen (name), size - 1);
6634 bcopy (buf, name, coding.produced);
6635 name[coding.produced] = '\0';
6639 /* If there's just one occurrence of '-' in the family name, it is
6640 replaced with '_'. (More than one occurrence of '-' means a
6641 "FOUNDRY-FAMILY-CHARSET"-style name.) */
6642 p = strchr (name, '-');
6643 if (p && strchr (p + 1, '-') == NULL)
6644 *p = '_';
6646 for (p = name; *p; p++)
6647 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
6648 for some locales. */
6649 if (isascii (*p))
6650 *p = tolower (*p);
6654 static char *
6655 mac_to_x_fontname (name, size, style, charset)
6656 char *name;
6657 int size;
6658 Style style;
6659 char *charset;
6661 Str31 foundry, cs;
6662 Str255 family;
6663 char xf[256], *result;
6664 unsigned char *p;
6666 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
6667 charset = cs;
6668 else
6670 strcpy(foundry, "Apple");
6671 strcpy(family, name);
6674 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
6675 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
6676 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
6678 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
6679 sprintf (result, "-%s-%s-%s", foundry, family, xf);
6680 for (p = result; *p; p++)
6681 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
6682 for some locales. */
6683 if (isascii (*p))
6684 *p = tolower (*p);
6685 return result;
6689 /* Parse fully-specified and instantiated X11 font spec XF, and store
6690 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
6691 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
6692 caller must allocate at least 256 and 32 bytes respectively. For
6693 ordinary Mac fonts, the value stored to FAMILY should just be their
6694 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
6695 intlfonts collection contain their charset designation in their
6696 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
6697 types of font names are handled accordingly. */
6699 const int kDefaultFontSize = 12;
6701 static int
6702 parse_x_font_name (xf, family, size, style, charset)
6703 char *xf, *family;
6704 int *size;
6705 Style *style;
6706 char *charset;
6708 Str31 foundry, weight;
6709 int point_size, avgwidth;
6710 char slant[2], *p;
6712 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
6713 foundry, family, weight, slant, size,
6714 &point_size, &avgwidth, charset) != 8
6715 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
6716 foundry, family, weight, slant, size,
6717 &point_size, &avgwidth, charset) != 8)
6718 return 0;
6720 if (*size == 0)
6722 if (point_size > 0)
6723 *size = point_size / 10;
6724 else if (avgwidth > 0)
6725 *size = avgwidth / 10;
6727 if (*size == 0)
6728 *size = kDefaultFontSize;
6730 *style = normal;
6731 if (strcmp (weight, "bold") == 0)
6732 *style |= bold;
6733 if (*slant == 'i')
6734 *style |= italic;
6736 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
6738 int foundry_len = strlen (foundry), family_len = strlen (family);
6740 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
6742 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
6743 but take overlap into account. */
6744 memmove (family + foundry_len + 1, family, family_len);
6745 memcpy (family, foundry, foundry_len);
6746 family[foundry_len] = '-';
6747 family[foundry_len + 1 + family_len] = '-';
6748 strcpy (family + foundry_len + 1 + family_len + 1, charset);
6750 else
6751 return 0;
6754 for (p = family; *p; p++)
6755 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
6756 for some locales. */
6757 if (isascii (*p))
6758 *p = tolower (*p);
6760 return 1;
6764 static void
6765 add_font_name_table_entry (char *font_name)
6767 if (font_name_table_size == 0)
6769 font_name_table_size = 256;
6770 font_name_table = (char **)
6771 xmalloc (font_name_table_size * sizeof (char *));
6773 else if (font_name_count + 1 >= font_name_table_size)
6775 font_name_table_size *= 2;
6776 font_name_table = (char **)
6777 xrealloc (font_name_table,
6778 font_name_table_size * sizeof (char *));
6781 font_name_table[font_name_count++] = font_name;
6784 /* Sets up the table font_name_table to contain the list of all fonts
6785 in the system the first time the table is used so that the Resource
6786 Manager need not be accessed every time this information is
6787 needed. */
6789 static void
6790 init_font_name_table ()
6792 #if TARGET_API_MAC_CARBON
6793 FMFontFamilyIterator ffi;
6794 FMFontFamilyInstanceIterator ffii;
6795 FMFontFamily ff;
6796 Lisp_Object text_encoding_info_alist;
6797 struct gcpro gcpro1;
6799 text_encoding_info_alist = create_text_encoding_info_alist ();
6801 #if USE_ATSUI
6802 #if USE_CG_TEXT_DRAWING
6803 init_cg_text_anti_aliasing_threshold ();
6804 #endif
6805 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
6806 text_encoding_info_alist)))
6808 OSErr err;
6809 ItemCount nfonts, i;
6810 ATSUFontID *font_ids = NULL;
6811 Ptr name, prev_name = NULL;
6812 ByteCount name_len;
6814 atsu_font_id_hash =
6815 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
6816 make_float (DEFAULT_REHASH_SIZE),
6817 make_float (DEFAULT_REHASH_THRESHOLD),
6818 Qnil, Qnil, Qnil);;
6819 err = ATSUFontCount (&nfonts);
6820 if (err == noErr)
6821 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
6822 if (font_ids)
6823 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
6824 if (err == noErr)
6825 for (i = 0; i < nfonts; i++)
6827 err = ATSUFindFontName (font_ids[i], kFontFamilyName,
6828 kFontMacintoshPlatform, kFontNoScript,
6829 kFontNoLanguage, 0, NULL, &name_len, NULL);
6830 if (err != noErr)
6831 continue;
6832 name = xmalloc (name_len + 1);
6833 if (name == NULL)
6834 continue;
6835 name[name_len] = '\0';
6836 err = ATSUFindFontName (font_ids[i], kFontFamilyName,
6837 kFontMacintoshPlatform, kFontNoScript,
6838 kFontNoLanguage, name_len, name,
6839 NULL, NULL);
6840 if (err == noErr)
6841 decode_mac_font_name (name, name_len + 1, Qnil);
6842 if (err == noErr
6843 && *name != '.'
6844 && (prev_name == NULL
6845 || strcmp (name, prev_name) != 0))
6847 static char *cs = "iso10646-1";
6849 add_font_name_table_entry (mac_to_x_fontname (name, 0,
6850 normal, cs));
6851 add_font_name_table_entry (mac_to_x_fontname (name, 0,
6852 italic, cs));
6853 add_font_name_table_entry (mac_to_x_fontname (name, 0,
6854 bold, cs));
6855 add_font_name_table_entry (mac_to_x_fontname (name, 0,
6856 italic | bold, cs));
6857 Fputhash (make_unibyte_string (name, name_len),
6858 long_to_cons (font_ids[i]), atsu_font_id_hash);
6859 xfree (prev_name);
6860 prev_name = name;
6862 else
6863 xfree (name);
6865 if (prev_name)
6866 xfree (prev_name);
6867 if (font_ids)
6868 xfree (font_ids);
6870 #endif
6872 /* Create a dummy instance iterator here to avoid creating and
6873 destroying it in the loop. */
6874 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
6875 return;
6876 /* Create an iterator to enumerate the font families. */
6877 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
6878 != noErr)
6880 FMDisposeFontFamilyInstanceIterator (&ffii);
6881 return;
6884 GCPRO1 (text_encoding_info_alist);
6886 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
6888 Str255 name;
6889 FMFont font;
6890 FMFontStyle style;
6891 FMFontSize size;
6892 TextEncoding encoding;
6893 TextEncodingBase sc;
6894 Lisp_Object text_encoding_info;
6896 if (FMGetFontFamilyName (ff, name) != noErr)
6897 break;
6898 p2cstr (name);
6899 if (*name == '.')
6900 continue;
6902 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
6903 break;
6904 sc = GetTextEncodingBase (encoding);
6905 text_encoding_info = assq_no_quit (make_number (sc),
6906 text_encoding_info_alist);
6907 if (NILP (text_encoding_info))
6908 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
6909 text_encoding_info_alist);
6910 decode_mac_font_name (name, sizeof (name),
6911 XCAR (XCDR (text_encoding_info)));
6912 fm_font_family_alist = Fcons (Fcons (build_string (name),
6913 make_number (ff)),
6914 fm_font_family_alist);
6916 /* Point the instance iterator at the current font family. */
6917 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
6918 break;
6920 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
6921 == noErr)
6923 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
6925 if (size > 0 || style == normal)
6926 for (; !NILP (rest); rest = XCDR (rest))
6928 char *cs = SDATA (XCAR (rest));
6930 if (size == 0)
6932 add_font_name_table_entry (mac_to_x_fontname (name, size,
6933 style, cs));
6934 add_font_name_table_entry (mac_to_x_fontname (name, size,
6935 italic, cs));
6936 add_font_name_table_entry (mac_to_x_fontname (name, size,
6937 bold, cs));
6938 add_font_name_table_entry (mac_to_x_fontname (name, size,
6939 italic | bold,
6940 cs));
6942 else
6944 add_font_name_table_entry (mac_to_x_fontname (name, size,
6945 style, cs));
6951 UNGCPRO;
6953 /* Dispose of the iterators. */
6954 FMDisposeFontFamilyIterator (&ffi);
6955 FMDisposeFontFamilyInstanceIterator (&ffii);
6956 #else /* !TARGET_API_MAC_CARBON */
6957 GrafPtr port;
6958 SInt16 fontnum, old_fontnum;
6959 int num_mac_fonts = CountResources('FOND');
6960 int i, j;
6961 Handle font_handle, font_handle_2;
6962 short id, scriptcode;
6963 ResType type;
6964 Str255 name;
6965 struct FontAssoc *fat;
6966 struct AsscEntry *assc_entry;
6967 Lisp_Object text_encoding_info_alist, text_encoding_info;
6968 struct gcpro gcpro1;
6970 GetPort (&port); /* save the current font number used */
6971 old_fontnum = port->txFont;
6973 text_encoding_info_alist = create_text_encoding_info_alist ();
6975 GCPRO1 (text_encoding_info_alist);
6977 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
6979 font_handle = GetIndResource ('FOND', i);
6980 if (!font_handle)
6981 continue;
6983 GetResInfo (font_handle, &id, &type, name);
6984 GetFNum (name, &fontnum);
6985 p2cstr (name);
6986 if (fontnum == 0)
6987 continue;
6989 TextFont (fontnum);
6990 scriptcode = FontToScript (fontnum);
6991 text_encoding_info = assq_no_quit (make_number (scriptcode),
6992 text_encoding_info_alist);
6993 if (NILP (text_encoding_info))
6994 text_encoding_info = assq_no_quit (make_number (smRoman),
6995 text_encoding_info_alist);
6996 decode_mac_font_name (name, sizeof (name),
6997 XCAR (XCDR (text_encoding_info)));
6998 fm_font_family_alist = Fcons (Fcons (build_string (name),
6999 make_number (fontnum)),
7000 fm_font_family_alist);
7003 HLock (font_handle);
7005 if (GetResourceSizeOnDisk (font_handle)
7006 >= sizeof (struct FamRec))
7008 fat = (struct FontAssoc *) (*font_handle
7009 + sizeof (struct FamRec));
7010 assc_entry
7011 = (struct AsscEntry *) (*font_handle
7012 + sizeof (struct FamRec)
7013 + sizeof (struct FontAssoc));
7015 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
7017 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
7019 for (; !NILP (rest); rest = XCDR (rest))
7021 char *cs = SDATA (XCAR (rest));
7023 add_font_name_table_entry (mac_to_x_fontname (name,
7024 assc_entry->fontSize,
7025 assc_entry->fontStyle,
7026 cs));
7031 HUnlock (font_handle);
7032 font_handle_2 = GetNextFOND (font_handle);
7033 ReleaseResource (font_handle);
7034 font_handle = font_handle_2;
7036 while (ResError () == noErr && font_handle);
7039 UNGCPRO;
7041 TextFont (old_fontnum);
7042 #endif /* !TARGET_API_MAC_CARBON */
7046 void
7047 mac_clear_font_name_table ()
7049 int i;
7051 for (i = 0; i < font_name_count; i++)
7052 xfree (font_name_table[i]);
7053 xfree (font_name_table);
7054 font_name_table = NULL;
7055 font_name_table_size = font_name_count = 0;
7056 fm_font_family_alist = Qnil;
7060 enum xlfd_scalable_field_index
7062 XLFD_SCL_PIXEL_SIZE,
7063 XLFD_SCL_POINT_SIZE,
7064 XLFD_SCL_AVGWIDTH,
7065 XLFD_SCL_LAST
7068 static int xlfd_scalable_fields[] =
7070 6, /* PIXEL_SIZE */
7071 7, /* POINT_SIZE */
7072 11, /* AVGWIDTH */
7076 static Lisp_Object
7077 mac_do_list_fonts (pattern, maxnames)
7078 char *pattern;
7079 int maxnames;
7081 int i, n_fonts = 0;
7082 Lisp_Object font_list = Qnil;
7083 struct xlfdpat *pat;
7084 char *scaled, *ptr;
7085 int scl_val[XLFD_SCL_LAST], *field, *val;
7086 int exact;
7088 if (font_name_table == NULL) /* Initialize when first used. */
7089 init_font_name_table ();
7091 for (i = 0; i < XLFD_SCL_LAST; i++)
7092 scl_val[i] = -1;
7094 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
7095 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
7096 fonts are scaled according to the specified size. */
7097 ptr = pattern;
7098 i = 0;
7099 field = xlfd_scalable_fields;
7100 val = scl_val;
7101 if (*ptr == '-')
7104 ptr++;
7105 if (i == *field)
7107 if ('0' <= *ptr && *ptr <= '9')
7109 *val = *ptr++ - '0';
7110 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
7111 *val = *val * 10 + *ptr++ - '0';
7112 if (*ptr != '-')
7113 *val = -1;
7115 field++;
7116 val++;
7118 ptr = strchr (ptr, '-');
7119 i++;
7121 while (ptr && i < 14);
7123 if (i == 14 && ptr == NULL)
7125 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
7126 scl_val[XLFD_SCL_PIXEL_SIZE] =
7127 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
7128 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
7129 : -1));
7130 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
7131 scl_val[XLFD_SCL_POINT_SIZE] =
7132 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
7133 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
7134 : -1));
7135 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
7136 scl_val[XLFD_SCL_AVGWIDTH] =
7137 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
7138 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
7139 : -1));
7141 else
7142 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
7144 pat = xlfdpat_create (pattern);
7145 if (pat == NULL)
7146 return Qnil;
7148 exact = xlfdpat_exact_p (pat);
7150 for (i = 0; i < font_name_count; i++)
7152 if (xlfdpat_match (pat, font_name_table[i]))
7154 font_list = Fcons (build_string (font_name_table[i]), font_list);
7155 if (exact || maxnames > 0 && ++n_fonts >= maxnames)
7156 break;
7158 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
7159 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
7161 int former_len = ptr - font_name_table[i];
7163 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
7164 if (scaled == NULL)
7165 continue;
7166 memcpy (scaled, font_name_table[i], former_len);
7167 sprintf (scaled + former_len,
7168 "-%d-%d-72-72-m-%d-%s",
7169 scl_val[XLFD_SCL_PIXEL_SIZE],
7170 scl_val[XLFD_SCL_POINT_SIZE],
7171 scl_val[XLFD_SCL_AVGWIDTH],
7172 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
7174 if (xlfdpat_match (pat, scaled))
7176 font_list = Fcons (build_string (scaled), font_list);
7177 xfree (scaled);
7178 if (exact || maxnames > 0 && ++n_fonts >= maxnames)
7179 break;
7181 else
7182 xfree (scaled);
7186 xlfdpat_destroy (pat);
7188 return font_list;
7191 /* Return a list of names of available fonts matching PATTERN on frame F.
7193 Frame F null means we have not yet created any frame on Mac, and
7194 consult the first display in x_display_list. MAXNAMES sets a limit
7195 on how many fonts to match. */
7197 Lisp_Object
7198 x_list_fonts (f, pattern, size, maxnames)
7199 struct frame *f;
7200 Lisp_Object pattern;
7201 int size, maxnames;
7203 Lisp_Object list = Qnil, patterns, tem, key;
7204 struct mac_display_info *dpyinfo
7205 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
7207 xassert (size <= 0);
7209 patterns = Fassoc (pattern, Valternate_fontname_alist);
7210 if (NILP (patterns))
7211 patterns = Fcons (pattern, Qnil);
7213 for (; CONSP (patterns); patterns = XCDR (patterns))
7215 pattern = XCAR (patterns);
7217 if (!STRINGP (pattern))
7218 continue;
7220 tem = XCAR (XCDR (dpyinfo->name_list_element));
7221 key = Fcons (pattern, make_number (maxnames));
7223 list = Fassoc (key, tem);
7224 if (!NILP (list))
7226 list = Fcdr_safe (list);
7227 /* We have a cashed list. Don't have to get the list again. */
7228 goto label_cached;
7231 BLOCK_INPUT;
7232 list = mac_do_list_fonts (SDATA (pattern), maxnames);
7233 UNBLOCK_INPUT;
7235 /* MAC_TODO: add code for matching outline fonts here */
7237 /* Now store the result in the cache. */
7238 XSETCAR (XCDR (dpyinfo->name_list_element),
7239 Fcons (Fcons (key, list),
7240 XCAR (XCDR (dpyinfo->name_list_element))));
7242 label_cached:
7243 if (NILP (list)) continue; /* Try the remaining alternatives. */
7246 return list;
7250 #if GLYPH_DEBUG
7252 /* Check that FONT is valid on frame F. It is if it can be found in F's
7253 font table. */
7255 static void
7256 x_check_font (f, font)
7257 struct frame *f;
7258 XFontStruct *font;
7260 int i;
7261 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7263 xassert (font != NULL);
7265 for (i = 0; i < dpyinfo->n_fonts; i++)
7266 if (dpyinfo->font_table[i].name
7267 && font == dpyinfo->font_table[i].font)
7268 break;
7270 xassert (i < dpyinfo->n_fonts);
7273 #endif /* GLYPH_DEBUG != 0 */
7275 /* Set *W to the minimum width, *H to the minimum font height of FONT.
7276 Note: There are (broken) X fonts out there with invalid XFontStruct
7277 min_bounds contents. For example, handa@etl.go.jp reports that
7278 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
7279 have font->min_bounds.width == 0. */
7281 static INLINE void
7282 x_font_min_bounds (font, w, h)
7283 MacFontStruct *font;
7284 int *w, *h;
7286 *h = FONT_HEIGHT (font);
7287 *w = font->min_bounds.width;
7291 /* Compute the smallest character width and smallest font height over
7292 all fonts available on frame F. Set the members smallest_char_width
7293 and smallest_font_height in F's x_display_info structure to
7294 the values computed. Value is non-zero if smallest_font_height or
7295 smallest_char_width become smaller than they were before. */
7297 static int
7298 x_compute_min_glyph_bounds (f)
7299 struct frame *f;
7301 int i;
7302 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7303 MacFontStruct *font;
7304 int old_width = dpyinfo->smallest_char_width;
7305 int old_height = dpyinfo->smallest_font_height;
7307 dpyinfo->smallest_font_height = 100000;
7308 dpyinfo->smallest_char_width = 100000;
7310 for (i = 0; i < dpyinfo->n_fonts; ++i)
7311 if (dpyinfo->font_table[i].name)
7313 struct font_info *fontp = dpyinfo->font_table + i;
7314 int w, h;
7316 font = (MacFontStruct *) fontp->font;
7317 xassert (font != (MacFontStruct *) ~0);
7318 x_font_min_bounds (font, &w, &h);
7320 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
7321 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
7324 xassert (dpyinfo->smallest_char_width > 0
7325 && dpyinfo->smallest_font_height > 0);
7327 return (dpyinfo->n_fonts == 1
7328 || dpyinfo->smallest_char_width < old_width
7329 || dpyinfo->smallest_font_height < old_height);
7333 /* Determine whether given string is a fully-specified XLFD: all 14
7334 fields are present, none is '*'. */
7336 static int
7337 is_fully_specified_xlfd (char *p)
7339 int i;
7340 char *q;
7342 if (*p != '-')
7343 return 0;
7345 for (i = 0; i < 13; i++)
7347 q = strchr (p + 1, '-');
7348 if (q == NULL)
7349 return 0;
7350 if (q - p == 2 && *(p + 1) == '*')
7351 return 0;
7352 p = q;
7355 if (strchr (p + 1, '-') != NULL)
7356 return 0;
7358 if (*(p + 1) == '*' && *(p + 2) == '\0')
7359 return 0;
7361 return 1;
7365 /* XLoadQueryFont creates and returns an internal representation for a
7366 font in a MacFontStruct struct. There is really no concept
7367 corresponding to "loading" a font on the Mac. But we check its
7368 existence and find the font number and all other information for it
7369 and store them in the returned MacFontStruct. */
7371 static MacFontStruct *
7372 XLoadQueryFont (Display *dpy, char *fontname)
7374 int i, size, char_width;
7375 char *name;
7376 Str255 family;
7377 Str31 charset;
7378 SInt16 fontnum;
7379 #if USE_ATSUI
7380 static ATSUFontID font_id;
7381 ATSUStyle mac_style = NULL;
7382 #endif
7383 Style fontface;
7384 #if TARGET_API_MAC_CARBON
7385 TextEncoding encoding;
7386 int scriptcode;
7387 #else
7388 short scriptcode;
7389 #endif
7390 MacFontStruct *font;
7392 if (is_fully_specified_xlfd (fontname))
7393 name = fontname;
7394 else
7396 Lisp_Object matched_fonts;
7398 matched_fonts = mac_do_list_fonts (fontname, 1);
7399 if (NILP (matched_fonts))
7400 return NULL;
7401 name = SDATA (XCAR (matched_fonts));
7404 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
7405 return NULL;
7407 #if USE_ATSUI
7408 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
7410 OSErr err;
7411 ATSUAttributeTag tags[] = {kATSUFontTag, kATSUSizeTag,
7412 kATSUQDBoldfaceTag, kATSUQDItalicTag};
7413 ByteCount sizes[] = {sizeof (ATSUFontID), sizeof (Fixed),
7414 sizeof (Boolean), sizeof (Boolean)};
7415 static Fixed size_fixed;
7416 static Boolean bold_p, italic_p;
7417 ATSUAttributeValuePtr values[] = {&font_id, &size_fixed,
7418 &bold_p, &italic_p};
7419 ATSUFontFeatureType types[] = {kAllTypographicFeaturesType};
7420 ATSUFontFeatureSelector selectors[] = {kAllTypeFeaturesOffSelector};
7421 Lisp_Object font_id_cons;
7423 font_id_cons = Fgethash (make_unibyte_string (family, strlen (family)),
7424 atsu_font_id_hash, Qnil);
7425 if (NILP (font_id_cons))
7426 return NULL;
7427 font_id = cons_to_long (font_id_cons);
7428 size_fixed = Long2Fix (size);
7429 bold_p = (fontface & bold) != 0;
7430 italic_p = (fontface & italic) != 0;
7431 err = ATSUCreateStyle (&mac_style);
7432 if (err != noErr)
7433 return NULL;
7434 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
7435 types, selectors);
7436 if (err != noErr)
7437 return NULL;
7438 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
7439 tags, sizes, values);
7440 fontnum = -1;
7441 scriptcode = kTextEncodingMacUnicode;
7443 else
7444 #endif
7446 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
7448 if (NILP (tmp))
7449 return NULL;
7450 fontnum = XINT (XCDR (tmp));
7451 #if TARGET_API_MAC_CARBON
7452 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
7453 return NULL;
7454 scriptcode = GetTextEncodingBase (encoding);
7455 #else
7456 scriptcode = FontToScript (fontnum);
7457 #endif
7460 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
7462 font->mac_fontnum = fontnum;
7463 font->mac_fontsize = size;
7464 font->mac_fontface = fontface;
7465 font->mac_scriptcode = scriptcode;
7466 #if USE_ATSUI
7467 font->mac_style = mac_style;
7468 #if USE_CG_TEXT_DRAWING
7469 font->cg_font = NULL;
7470 font->cg_glyphs = NULL;
7471 #endif
7472 #endif
7474 /* Apple Japanese (SJIS) font is listed as both
7475 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
7476 (Roman script) in init_font_name_table (). The latter should be
7477 treated as a one-byte font. */
7478 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
7479 font->mac_scriptcode = smRoman;
7481 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
7483 #if USE_ATSUI
7484 if (font->mac_style)
7486 OSErr err;
7487 ATSUTextLayout text_layout;
7488 UniChar c = 0x20;
7489 Rect char_bounds, min_bounds, max_bounds;
7490 int min_width, max_width;
7491 ATSTrapezoid glyph_bounds;
7493 font->per_char = xmalloc (sizeof (XCharStruct) * 0x10000);
7494 if (font->per_char == NULL)
7496 mac_unload_font (&one_mac_display_info, font);
7497 return NULL;
7499 bzero (font->per_char, sizeof (XCharStruct) * 0x10000);
7501 #if USE_CG_TEXT_DRAWING
7503 FMFontFamily font_family;
7504 FMFontStyle style;
7505 ATSFontRef ats_font;
7507 err = FMGetFontFamilyInstanceFromFont (font_id, &font_family, &style);
7508 if (err == noErr)
7509 err = FMGetFontFromFontFamilyInstance (font_family, fontface,
7510 &font_id, &style);
7511 /* Use CG text drawing if italic/bold is not synthesized. */
7512 if (err == noErr && style == fontface)
7514 ats_font = FMGetATSFontRefFromFont (font_id);
7515 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
7519 if (font->cg_font)
7520 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
7521 if (font->cg_glyphs)
7522 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
7523 #endif
7525 err = atsu_get_text_layout_with_text_ptr (&c, 1,
7526 font->mac_style,
7527 &text_layout);
7528 if (err != noErr)
7530 mac_unload_font (&one_mac_display_info, font);
7531 return NULL;
7534 for (c = 0x20; c <= 0xff; c++)
7536 if (c == 0xad)
7537 /* Soft hyphen is not supported in ATSUI. */
7538 continue;
7539 else if (c == 0x7f)
7541 STORE_XCHARSTRUCT (font->min_bounds, min_width, min_bounds);
7542 STORE_XCHARSTRUCT (font->max_bounds, max_width, max_bounds);
7543 c = 0x9f;
7544 continue;
7547 err = ATSUClearLayoutCache (text_layout, kATSUFromTextBeginning);
7548 if (err == noErr)
7549 err = ATSUMeasureTextImage (text_layout,
7550 kATSUFromTextBeginning, kATSUToTextEnd,
7551 0, 0, &char_bounds);
7552 if (err == noErr)
7553 err = ATSUGetGlyphBounds (text_layout, 0, 0,
7554 kATSUFromTextBeginning, kATSUToTextEnd,
7555 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
7556 kATSUseFractionalOrigins,
7557 #else
7558 kATSUseDeviceOrigins,
7559 #endif
7560 1, &glyph_bounds, NULL);
7561 if (err == noErr)
7563 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
7564 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
7566 char_width = Fix2Long (glyph_bounds.upperRight.x
7567 - glyph_bounds.upperLeft.x);
7568 STORE_XCHARSTRUCT (font->per_char[c],
7569 char_width, char_bounds);
7570 if (c == 0x20)
7572 min_width = max_width = char_width;
7573 min_bounds = max_bounds = char_bounds;
7574 font->ascent = -Fix2Long (glyph_bounds.upperLeft.y);
7575 font->descent = Fix2Long (glyph_bounds.lowerLeft.y);
7577 else
7579 if (char_width > 0)
7581 min_width = min (min_width, char_width);
7582 max_width = max (max_width, char_width);
7584 if (!EmptyRect (&char_bounds))
7586 SetRect (&min_bounds,
7587 max (min_bounds.left, char_bounds.left),
7588 max (min_bounds.top, char_bounds.top),
7589 min (min_bounds.right, char_bounds.right),
7590 min (min_bounds.bottom, char_bounds.bottom));
7591 UnionRect (&max_bounds, &char_bounds, &max_bounds);
7595 #if USE_CG_TEXT_DRAWING
7596 if (err == noErr && char_width > 0 && font->cg_font)
7598 ATSUGlyphInfoArray glyph_info_array;
7599 ByteCount count = sizeof (ATSUGlyphInfoArray);
7601 err = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
7602 kATSUToTextEnd, NULL, NULL, NULL);
7603 if (err == noErr)
7604 err = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
7605 kATSUToTextEnd, &count,
7606 &glyph_info_array);
7607 if (err == noErr)
7608 font->cg_glyphs[c] = glyph_info_array.glyphs[0].glyphID;
7609 else
7611 /* Don't use CG text drawing if font substitution
7612 occurs in ASCII or Latin-1 characters. */
7613 CGFontRelease (font->cg_font);
7614 font->cg_font = NULL;
7615 xfree (font->cg_glyphs);
7616 font->cg_glyphs = NULL;
7619 #endif
7622 font->min_byte1 = 0;
7623 font->max_byte1 = 0xff;
7624 font->min_char_or_byte2 = 0;
7625 font->max_char_or_byte2 = 0xff;
7627 else
7628 #endif
7630 GrafPtr port;
7631 SInt16 old_fontnum, old_fontsize;
7632 Style old_fontface;
7633 FontInfo the_fontinfo;
7634 int is_two_byte_font;
7636 /* Save the current font number used. */
7637 GetPort (&port);
7638 #if TARGET_API_MAC_CARBON
7639 old_fontnum = GetPortTextFont (port);
7640 old_fontsize = GetPortTextSize (port);
7641 old_fontface = GetPortTextFace (port);
7642 #else
7643 old_fontnum = port->txFont;
7644 old_fontsize = port->txSize;
7645 old_fontface = port->txFace;
7646 #endif
7648 TextFont (fontnum);
7649 TextSize (size);
7650 TextFace (fontface);
7652 GetFontInfo (&the_fontinfo);
7654 font->ascent = the_fontinfo.ascent;
7655 font->descent = the_fontinfo.descent;
7657 is_two_byte_font = (font->mac_scriptcode == smJapanese
7658 || font->mac_scriptcode == smTradChinese
7659 || font->mac_scriptcode == smSimpChinese
7660 || font->mac_scriptcode == smKorean);
7662 if (is_two_byte_font)
7664 font->min_byte1 = 0xa1;
7665 font->max_byte1 = 0xfe;
7666 font->min_char_or_byte2 = 0xa1;
7667 font->max_char_or_byte2 = 0xfe;
7669 /* Use the width of an "ideographic space" of that font
7670 because the_fontinfo.widMax returns the wrong width for
7671 some fonts. */
7672 switch (font->mac_scriptcode)
7674 case smJapanese:
7675 font->min_byte1 = 0x81;
7676 font->max_byte1 = 0xfc;
7677 font->min_char_or_byte2 = 0x40;
7678 font->max_char_or_byte2 = 0xfc;
7679 char_width = StringWidth("\p\x81\x40");
7680 break;
7681 case smTradChinese:
7682 font->min_char_or_byte2 = 0x40;
7683 char_width = StringWidth("\p\xa1\x40");
7684 break;
7685 case smSimpChinese:
7686 char_width = StringWidth("\p\xa1\xa1");
7687 break;
7688 case smKorean:
7689 char_width = StringWidth("\p\xa1\xa1");
7690 break;
7693 else
7695 font->min_byte1 = font->max_byte1 = 0;
7696 font->min_char_or_byte2 = 0x20;
7697 font->max_char_or_byte2 = 0xff;
7699 /* Do this instead of use the_fontinfo.widMax, which
7700 incorrectly returns 15 for 12-point Monaco! */
7701 char_width = CharWidth ('m');
7704 if (is_two_byte_font)
7706 font->per_char = NULL;
7708 if (fontface & italic)
7709 font->max_bounds.rbearing = char_width + 1;
7710 else
7711 font->max_bounds.rbearing = char_width;
7712 font->max_bounds.lbearing = 0;
7713 font->max_bounds.width = char_width;
7714 font->max_bounds.ascent = the_fontinfo.ascent;
7715 font->max_bounds.descent = the_fontinfo.descent;
7717 font->min_bounds = font->max_bounds;
7719 else
7721 int c, min_width, max_width;
7722 Rect char_bounds, min_bounds, max_bounds;
7723 char ch;
7725 font->per_char = xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
7726 bzero (font->per_char, sizeof (XCharStruct) * (0xff - 0x20 + 1));
7728 min_width = max_width = char_width;
7729 SetRect (&min_bounds, -32767, -32767, 32767, 32767);
7730 SetRect (&max_bounds, 0, 0, 0, 0);
7731 for (c = 0x20; c <= 0xff; c++)
7733 if (c == 0x7f)
7735 STORE_XCHARSTRUCT (font->min_bounds, min_width, min_bounds);
7736 STORE_XCHARSTRUCT (font->max_bounds, max_width, max_bounds);
7737 continue;
7740 ch = c;
7741 char_width = CharWidth (ch);
7742 QDTextBounds (1, &ch, &char_bounds);
7743 STORE_XCHARSTRUCT (font->per_char[c - 0x20],
7744 char_width, char_bounds);
7745 /* Some Japanese fonts (in SJIS encoding) return 0 as
7746 the character width of 0x7f. */
7747 if (char_width > 0)
7749 min_width = min (min_width, char_width);
7750 max_width = max (max_width, char_width);
7752 if (!EmptyRect (&char_bounds))
7754 SetRect (&min_bounds,
7755 max (min_bounds.left, char_bounds.left),
7756 max (min_bounds.top, char_bounds.top),
7757 min (min_bounds.right, char_bounds.right),
7758 min (min_bounds.bottom, char_bounds.bottom));
7759 UnionRect (&max_bounds, &char_bounds, &max_bounds);
7762 if (min_width == max_width
7763 && max_bounds.left >= 0 && max_bounds.right <= max_width)
7765 /* Fixed width and no overhangs. */
7766 xfree (font->per_char);
7767 font->per_char = NULL;
7771 /* Restore previous font number, size and face. */
7772 TextFont (old_fontnum);
7773 TextSize (old_fontsize);
7774 TextFace (old_fontface);
7777 #if !defined (MAC_OS8) || USE_ATSUI
7778 /* AppKit and WebKit do some adjustment to the heights of Courier,
7779 Helvetica, and Times. This only works on the environments where
7780 the XDrawImageString counterpart is never used. */
7781 if (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
7782 || strcmp (family, "times") == 0)
7783 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
7784 #endif
7786 return font;
7790 void
7791 mac_unload_font (dpyinfo, font)
7792 struct mac_display_info *dpyinfo;
7793 XFontStruct *font;
7795 xfree (font->full_name);
7796 if (font->per_char)
7797 xfree (font->per_char);
7798 #if USE_ATSUI
7799 if (font->mac_style)
7800 ATSUDisposeStyle (font->mac_style);
7801 #if USE_CG_TEXT_DRAWING
7802 if (font->cg_font)
7803 CGFontRelease (font->cg_font);
7804 if (font->cg_glyphs)
7805 xfree (font->cg_glyphs);
7806 #endif
7807 #endif
7808 xfree (font);
7812 /* Load font named FONTNAME of the size SIZE for frame F, and return a
7813 pointer to the structure font_info while allocating it dynamically.
7814 If SIZE is 0, load any size of font.
7815 If loading is failed, return NULL. */
7817 struct font_info *
7818 x_load_font (f, fontname, size)
7819 struct frame *f;
7820 register char *fontname;
7821 int size;
7823 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7824 Lisp_Object font_names;
7826 /* Get a list of all the fonts that match this name. Once we
7827 have a list of matching fonts, we compare them against the fonts
7828 we already have by comparing names. */
7829 font_names = x_list_fonts (f, build_string (fontname), size, 1);
7831 if (!NILP (font_names))
7833 Lisp_Object tail;
7834 int i;
7836 for (i = 0; i < dpyinfo->n_fonts; i++)
7837 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
7838 if (dpyinfo->font_table[i].name
7839 && (!strcmp (dpyinfo->font_table[i].name,
7840 SDATA (XCAR (tail)))
7841 || !strcmp (dpyinfo->font_table[i].full_name,
7842 SDATA (XCAR (tail)))))
7843 return (dpyinfo->font_table + i);
7845 else
7846 return NULL;
7848 /* Load the font and add it to the table. */
7850 char *full_name;
7851 struct MacFontStruct *font;
7852 struct font_info *fontp;
7853 unsigned long value;
7854 int i;
7856 fontname = (char *) SDATA (XCAR (font_names));
7858 BLOCK_INPUT;
7859 font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname);
7860 UNBLOCK_INPUT;
7861 if (!font)
7862 return NULL;
7864 /* Find a free slot in the font table. */
7865 for (i = 0; i < dpyinfo->n_fonts; ++i)
7866 if (dpyinfo->font_table[i].name == NULL)
7867 break;
7869 /* If no free slot found, maybe enlarge the font table. */
7870 if (i == dpyinfo->n_fonts
7871 && dpyinfo->n_fonts == dpyinfo->font_table_size)
7873 int sz;
7874 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
7875 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
7876 dpyinfo->font_table
7877 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
7880 fontp = dpyinfo->font_table + i;
7881 if (i == dpyinfo->n_fonts)
7882 ++dpyinfo->n_fonts;
7884 /* Now fill in the slots of *FONTP. */
7885 BLOCK_INPUT;
7886 bzero (fontp, sizeof (*fontp));
7887 fontp->font = font;
7888 fontp->font_idx = i;
7889 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
7890 bcopy (fontname, fontp->name, strlen (fontname) + 1);
7892 if (font->min_bounds.width == font->max_bounds.width)
7894 /* Fixed width font. */
7895 fontp->average_width = fontp->space_width = font->min_bounds.width;
7897 else
7899 XChar2b char2b;
7900 XCharStruct *pcm;
7902 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
7903 pcm = mac_per_char_metric (font, &char2b, 0);
7904 if (pcm)
7905 fontp->space_width = pcm->width;
7906 else
7907 fontp->space_width = FONT_WIDTH (font);
7909 if (pcm)
7911 int width = pcm->width;
7912 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
7913 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
7914 width += pcm->width;
7915 fontp->average_width = width / 95;
7917 else
7918 fontp->average_width = FONT_WIDTH (font);
7921 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
7922 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
7924 fontp->size = font->max_bounds.width;
7925 fontp->height = FONT_HEIGHT (font);
7927 /* For some font, ascent and descent in max_bounds field is
7928 larger than the above value. */
7929 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
7930 if (max_height > fontp->height)
7931 fontp->height = max_height;
7934 /* The slot `encoding' specifies how to map a character
7935 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
7936 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
7937 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
7938 2:0xA020..0xFF7F). For the moment, we don't know which charset
7939 uses this font. So, we set information in fontp->encoding[1]
7940 which is never used by any charset. If mapping can't be
7941 decided, set FONT_ENCODING_NOT_DECIDED. */
7942 if (font->mac_scriptcode == smJapanese)
7943 fontp->encoding[1] = 4;
7944 else
7946 fontp->encoding[1]
7947 = (font->max_byte1 == 0
7948 /* 1-byte font */
7949 ? (font->min_char_or_byte2 < 0x80
7950 ? (font->max_char_or_byte2 < 0x80
7951 ? 0 /* 0x20..0x7F */
7952 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
7953 : 1) /* 0xA0..0xFF */
7954 /* 2-byte font */
7955 : (font->min_byte1 < 0x80
7956 ? (font->max_byte1 < 0x80
7957 ? (font->min_char_or_byte2 < 0x80
7958 ? (font->max_char_or_byte2 < 0x80
7959 ? 0 /* 0x2020..0x7F7F */
7960 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
7961 : 3) /* 0x20A0..0x7FFF */
7962 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
7963 : (font->min_char_or_byte2 < 0x80
7964 ? (font->max_char_or_byte2 < 0x80
7965 ? 2 /* 0xA020..0xFF7F */
7966 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
7967 : 1))); /* 0xA0A0..0xFFFF */
7970 #if 0 /* MAC_TODO: fill these out with more reasonably values */
7971 fontp->baseline_offset
7972 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
7973 ? (long) value : 0);
7974 fontp->relative_compose
7975 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
7976 ? (long) value : 0);
7977 fontp->default_ascent
7978 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
7979 ? (long) value : 0);
7980 #else
7981 fontp->baseline_offset = 0;
7982 fontp->relative_compose = 0;
7983 fontp->default_ascent = 0;
7984 #endif
7986 /* Set global flag fonts_changed_p to non-zero if the font loaded
7987 has a character with a smaller width than any other character
7988 before, or if the font loaded has a smaller height than any
7989 other font loaded before. If this happens, it will make a
7990 glyph matrix reallocation necessary. */
7991 fonts_changed_p |= x_compute_min_glyph_bounds (f);
7992 UNBLOCK_INPUT;
7993 return fontp;
7998 /* Return a pointer to struct font_info of a font named FONTNAME for
7999 frame F. If no such font is loaded, return NULL. */
8001 struct font_info *
8002 x_query_font (f, fontname)
8003 struct frame *f;
8004 register char *fontname;
8006 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8007 int i;
8009 for (i = 0; i < dpyinfo->n_fonts; i++)
8010 if (dpyinfo->font_table[i].name
8011 && (!strcmp (dpyinfo->font_table[i].name, fontname)
8012 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
8013 return (dpyinfo->font_table + i);
8014 return NULL;
8018 /* Find a CCL program for a font specified by FONTP, and set the member
8019 `encoder' of the structure. */
8021 void
8022 x_find_ccl_program (fontp)
8023 struct font_info *fontp;
8025 Lisp_Object list, elt;
8027 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
8029 elt = XCAR (list);
8030 if (CONSP (elt)
8031 && STRINGP (XCAR (elt))
8032 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
8033 >= 0))
8034 break;
8036 if (! NILP (list))
8038 struct ccl_program *ccl
8039 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
8041 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
8042 xfree (ccl);
8043 else
8044 fontp->font_encoder = ccl;
8050 /* The Mac Event loop code */
8052 #if !TARGET_API_MAC_CARBON
8053 #include <Events.h>
8054 #include <Quickdraw.h>
8055 #include <Balloons.h>
8056 #include <Devices.h>
8057 #include <Fonts.h>
8058 #include <Gestalt.h>
8059 #include <Menus.h>
8060 #include <Processes.h>
8061 #include <Sound.h>
8062 #include <ToolUtils.h>
8063 #include <TextUtils.h>
8064 #include <Dialogs.h>
8065 #include <Script.h>
8066 #include <Types.h>
8067 #include <Resources.h>
8069 #if __MWERKS__
8070 #include <unix.h>
8071 #endif
8072 #endif /* ! TARGET_API_MAC_CARBON */
8074 #define M_APPLE 128
8075 #define I_ABOUT 1
8077 #define WINDOW_RESOURCE 128
8078 #define TERM_WINDOW_RESOURCE 129
8080 #define DEFAULT_NUM_COLS 80
8082 #define MIN_DOC_SIZE 64
8083 #define MAX_DOC_SIZE 32767
8085 #define EXTRA_STACK_ALLOC (256 * 1024)
8087 #define ARGV_STRING_LIST_ID 129
8088 #define ABOUT_ALERT_ID 128
8089 #define RAM_TOO_LARGE_ALERT_ID 129
8091 /* Contains the string "reverse", which is a constant for mouse button emu.*/
8092 Lisp_Object Qreverse;
8095 /* Modifier associated with the control key, or nil to ignore. */
8096 Lisp_Object Vmac_control_modifier;
8098 /* Modifier associated with the option key, or nil to ignore. */
8099 Lisp_Object Vmac_option_modifier;
8101 /* Modifier associated with the command key, or nil to ignore. */
8102 Lisp_Object Vmac_command_modifier;
8104 /* Modifier associated with the function key, or nil to ignore. */
8105 Lisp_Object Vmac_function_modifier;
8107 /* True if the option and command modifiers should be used to emulate
8108 a three button mouse */
8109 Lisp_Object Vmac_emulate_three_button_mouse;
8111 #if USE_CARBON_EVENTS
8112 /* True if the mouse wheel button (i.e. button 4) should map to
8113 mouse-2, instead of mouse-3. */
8114 Lisp_Object Vmac_wheel_button_is_mouse_2;
8116 /* If Non-nil, the Mac "Command" key is passed on to the Mac Toolbox
8117 for processing before Emacs sees it. */
8118 Lisp_Object Vmac_pass_command_to_system;
8120 /* If Non-nil, the Mac "Control" key is passed on to the Mac Toolbox
8121 for processing before Emacs sees it. */
8122 Lisp_Object Vmac_pass_control_to_system;
8123 #endif
8125 /* Points to the variable `inev' in the function XTread_socket. It is
8126 used for passing an input event to the function back from
8127 Carbon/Apple event handlers. */
8128 static struct input_event *read_socket_inev = NULL;
8130 /* Set in term/mac-win.el to indicate that event loop can now generate
8131 drag and drop events. */
8132 Lisp_Object Qmac_ready_for_drag_n_drop;
8134 Point saved_menu_event_location;
8136 /* Apple Events */
8137 static void init_required_apple_events (void);
8138 static pascal OSErr
8139 do_ae_open_application (const AppleEvent *, AppleEvent *, long);
8140 static pascal OSErr
8141 do_ae_print_documents (const AppleEvent *, AppleEvent *, long);
8142 static pascal OSErr do_ae_open_documents (AppleEvent *, AppleEvent *, long);
8143 static pascal OSErr do_ae_quit_application (AppleEvent *, AppleEvent *, long);
8145 #if TARGET_API_MAC_CARBON
8146 /* Drag and Drop */
8147 static pascal OSErr mac_do_track_drag (DragTrackingMessage, WindowPtr, void*, DragReference);
8148 static pascal OSErr mac_do_receive_drag (WindowPtr, void*, DragReference);
8149 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
8150 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
8151 #endif
8153 static Lisp_Object Qapplication, Qabout;
8154 #if USE_CARBON_EVENTS
8155 #ifdef MAC_OSX
8156 extern void init_service_handler ();
8157 static Lisp_Object Qpreferences, Qservices, Qpaste, Qperform;
8158 #endif
8159 /* Window Event Handler */
8160 static pascal OSStatus mac_handle_window_event (EventHandlerCallRef,
8161 EventRef, void *);
8162 #endif
8163 OSErr install_window_handler (WindowPtr);
8165 extern void init_emacs_passwd_dir ();
8166 extern int emacs_main (int, char **, char **);
8168 extern void initialize_applescript();
8169 extern void terminate_applescript();
8171 static unsigned int
8172 #if USE_CARBON_EVENTS
8173 mac_to_emacs_modifiers (UInt32 mods)
8174 #else
8175 mac_to_emacs_modifiers (EventModifiers mods)
8176 #endif
8178 unsigned int result = 0;
8179 if (mods & shiftKey)
8180 result |= shift_modifier;
8184 /* Deactivated to simplify configuration:
8185 if Vmac_option_modifier is non-NIL, we fully process the Option
8186 key. Otherwise, we only process it if an additional Ctrl or Command
8187 is pressed. That way the system may convert the character to a
8188 composed one.
8189 if ((mods & optionKey) &&
8190 (( !NILP(Vmac_option_modifier) ||
8191 ((mods & cmdKey) || (mods & controlKey))))) */
8193 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
8194 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
8195 if (INTEGERP(val))
8196 result |= XUINT(val);
8198 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
8199 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
8200 if (INTEGERP(val))
8201 result |= XUINT(val);
8203 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
8204 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
8205 if (INTEGERP(val))
8206 result |= XUINT(val);
8209 #ifdef MAC_OSX
8210 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
8211 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
8212 if (INTEGERP(val))
8213 result |= XUINT(val);
8215 #endif
8217 return result;
8220 static int
8221 mac_get_emulated_btn ( UInt32 modifiers )
8223 int result = 0;
8224 if (!NILP (Vmac_emulate_three_button_mouse)) {
8225 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
8226 if (modifiers & cmdKey)
8227 result = cmdIs3 ? 2 : 1;
8228 else if (modifiers & optionKey)
8229 result = cmdIs3 ? 1 : 2;
8231 return result;
8234 #if USE_CARBON_EVENTS
8235 /* Obtains the event modifiers from the event ref and then calls
8236 mac_to_emacs_modifiers. */
8237 static UInt32
8238 mac_event_to_emacs_modifiers (EventRef eventRef)
8240 UInt32 mods = 0;
8241 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
8242 sizeof (UInt32), NULL, &mods);
8243 if (!NILP (Vmac_emulate_three_button_mouse) &&
8244 GetEventClass(eventRef) == kEventClassMouse)
8246 mods &= ~(optionKey | cmdKey);
8248 return mac_to_emacs_modifiers (mods);
8251 /* Given an event ref, return the code to use for the mouse button
8252 code in the emacs input_event. */
8253 static int
8254 mac_get_mouse_btn (EventRef ref)
8256 EventMouseButton result = kEventMouseButtonPrimary;
8257 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
8258 sizeof (EventMouseButton), NULL, &result);
8259 switch (result)
8261 case kEventMouseButtonPrimary:
8262 if (NILP (Vmac_emulate_three_button_mouse))
8263 return 0;
8264 else {
8265 UInt32 mods = 0;
8266 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
8267 sizeof (UInt32), NULL, &mods);
8268 return mac_get_emulated_btn(mods);
8270 case kEventMouseButtonSecondary:
8271 return NILP (Vmac_wheel_button_is_mouse_2) ? 1 : 2;
8272 case kEventMouseButtonTertiary:
8273 case 4: /* 4 is the number for the mouse wheel button */
8274 return NILP (Vmac_wheel_button_is_mouse_2) ? 2 : 1;
8275 default:
8276 return 0;
8280 /* Normally, ConvertEventRefToEventRecord will correctly handle all
8281 events. However the click of the mouse wheel is not converted to a
8282 mouseDown or mouseUp event. Likewise for dead key down events.
8283 This calls ConvertEventRef, but then checks to see if it is a mouse
8284 up/down, or a dead key down carbon event that has not been
8285 converted, and if so, converts it by hand (to be picked up in the
8286 XTread_socket loop). */
8287 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
8289 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
8291 if (result)
8292 return result;
8294 switch (GetEventClass (eventRef))
8296 case kEventClassMouse:
8297 switch (GetEventKind (eventRef))
8299 case kEventMouseDown:
8300 eventRec->what = mouseDown;
8301 result = 1;
8302 break;
8304 case kEventMouseUp:
8305 eventRec->what = mouseUp;
8306 result = 1;
8307 break;
8309 default:
8310 break;
8312 break;
8314 case kEventClassKeyboard:
8315 switch (GetEventKind (eventRef))
8317 case kEventRawKeyDown:
8319 unsigned char char_codes;
8320 UInt32 key_code;
8322 eventRec->what = keyDown;
8323 GetEventParameter (eventRef, kEventParamKeyMacCharCodes, typeChar,
8324 NULL, sizeof (char), NULL, &char_codes);
8325 GetEventParameter (eventRef, kEventParamKeyCode, typeUInt32,
8326 NULL, sizeof (UInt32), NULL, &key_code);
8327 eventRec->message = char_codes | ((key_code & 0xff) << 8);
8328 result = 1;
8330 break;
8332 default:
8333 break;
8335 break;
8337 default:
8338 break;
8341 if (result)
8343 /* Need where and when. */
8344 UInt32 mods;
8346 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
8347 NULL, sizeof (Point), NULL, &eventRec->where);
8348 /* Use two step process because new event modifiers are 32-bit
8349 and old are 16-bit. Currently, only loss is NumLock & Fn. */
8350 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
8351 NULL, sizeof (UInt32), NULL, &mods);
8352 eventRec->modifiers = mods;
8354 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
8357 return result;
8360 #endif
8362 static void
8363 do_get_menus (void)
8365 Handle menubar_handle;
8366 MenuHandle menu_handle;
8368 menubar_handle = GetNewMBar (128);
8369 if(menubar_handle == NULL)
8370 abort ();
8371 SetMenuBar (menubar_handle);
8372 DrawMenuBar ();
8374 #if !TARGET_API_MAC_CARBON
8375 menu_handle = GetMenuHandle (M_APPLE);
8376 if(menu_handle != NULL)
8377 AppendResMenu (menu_handle,'DRVR');
8378 else
8379 abort ();
8380 #endif
8384 static void
8385 do_init_managers (void)
8387 #if !TARGET_API_MAC_CARBON
8388 InitGraf (&qd.thePort);
8389 InitFonts ();
8390 FlushEvents (everyEvent, 0);
8391 InitWindows ();
8392 InitMenus ();
8393 TEInit ();
8394 InitDialogs (NULL);
8395 #endif /* !TARGET_API_MAC_CARBON */
8396 InitCursor ();
8398 #if !TARGET_API_MAC_CARBON
8399 /* set up some extra stack space for use by emacs */
8400 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
8402 /* MaxApplZone must be called for AppleScript to execute more
8403 complicated scripts */
8404 MaxApplZone ();
8405 MoreMasters ();
8406 #endif /* !TARGET_API_MAC_CARBON */
8409 static void
8410 do_check_ram_size (void)
8412 SInt32 physical_ram_size, logical_ram_size;
8414 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
8415 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
8416 || physical_ram_size > (1 << VALBITS)
8417 || logical_ram_size > (1 << VALBITS))
8419 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
8420 exit (1);
8424 static void
8425 do_window_update (WindowPtr win)
8427 struct frame *f = mac_window_to_frame (win);
8429 BeginUpdate (win);
8431 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
8432 below. */
8433 if (win != tip_window)
8435 if (f->async_visible == 0)
8437 /* Update events may occur when a frame gets iconified. */
8438 #if 0
8439 f->async_visible = 1;
8440 f->async_iconified = 0;
8441 SET_FRAME_GARBAGED (f);
8442 #endif
8444 else
8446 Rect r;
8447 #if TARGET_API_MAC_CARBON
8448 RgnHandle region = NewRgn ();
8450 GetPortVisibleRegion (GetWindowPort (win), region);
8451 GetRegionBounds (region, &r);
8452 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
8453 UpdateControls (win, region);
8454 DisposeRgn (region);
8455 #else
8456 r = (*win->visRgn)->rgnBBox;
8457 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
8458 UpdateControls (win, win->visRgn);
8459 #endif
8463 EndUpdate (win);
8466 static int
8467 is_emacs_window (WindowPtr win)
8469 Lisp_Object tail, frame;
8471 if (!win)
8472 return 0;
8474 FOR_EACH_FRAME (tail, frame)
8475 if (FRAME_MAC_P (XFRAME (frame)))
8476 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
8477 return 1;
8479 return 0;
8482 static void
8483 do_app_resume ()
8485 /* Window-activate events will do the job. */
8488 static void
8489 do_app_suspend ()
8491 /* Window-deactivate events will do the job. */
8495 static void
8496 do_apple_menu (SInt16 menu_item)
8498 #if !TARGET_API_MAC_CARBON
8499 Str255 item_name;
8500 SInt16 da_driver_refnum;
8502 if (menu_item == I_ABOUT)
8503 NoteAlert (ABOUT_ALERT_ID, NULL);
8504 else
8506 GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name);
8507 da_driver_refnum = OpenDeskAcc (item_name);
8509 #endif /* !TARGET_API_MAC_CARBON */
8512 void
8513 do_menu_choice (SInt32 menu_choice)
8515 SInt16 menu_id, menu_item;
8517 menu_id = HiWord (menu_choice);
8518 menu_item = LoWord (menu_choice);
8520 switch (menu_id)
8522 case 0:
8523 break;
8525 case M_APPLE:
8526 do_apple_menu (menu_item);
8527 break;
8529 default:
8531 struct frame *f = mac_focus_frame (&one_mac_display_info);
8532 MenuHandle menu = GetMenuHandle (menu_id);
8533 if (menu)
8535 UInt32 refcon;
8537 GetMenuItemRefCon (menu, menu_item, &refcon);
8538 menubar_selection_callback (f, refcon);
8543 HiliteMenu (0);
8547 /* Handle drags in size box. Based on code contributed by Ben
8548 Mesander and IM - Window Manager A. */
8550 static void
8551 do_grow_window (WindowPtr w, EventRecord *e)
8553 Rect limit_rect;
8554 int rows, columns, width, height;
8555 struct frame *f = mac_window_to_frame (w);
8556 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
8557 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
8558 #if TARGET_API_MAC_CARBON
8559 Rect new_rect;
8560 #else
8561 long grow_size;
8562 #endif
8564 if (size_hints->flags & PMinSize)
8566 min_width = size_hints->min_width;
8567 min_height = size_hints->min_height;
8569 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
8571 #if TARGET_API_MAC_CARBON
8572 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
8573 return;
8574 height = new_rect.bottom - new_rect.top;
8575 width = new_rect.right - new_rect.left;
8576 #else
8577 grow_size = GrowWindow (w, e->where, &limit_rect);
8578 /* see if it really changed size */
8579 if (grow_size == 0)
8580 return;
8581 height = HiWord (grow_size);
8582 width = LoWord (grow_size);
8583 #endif
8585 if (width != FRAME_PIXEL_WIDTH (f)
8586 || height != FRAME_PIXEL_HEIGHT (f))
8588 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
8589 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
8591 x_set_window_size (f, 0, columns, rows);
8596 /* Handle clicks in zoom box. Calculation of "standard state" based
8597 on code in IM - Window Manager A and code contributed by Ben
8598 Mesander. The standard state of an Emacs window is 80-characters
8599 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
8601 static void
8602 do_zoom_window (WindowPtr w, int zoom_in_or_out)
8604 GrafPtr save_port;
8605 Rect zoom_rect, port_rect;
8606 Point top_left;
8607 int w_title_height, columns, rows, width, height;
8608 struct frame *f = mac_window_to_frame (w);
8609 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8611 #if TARGET_API_MAC_CARBON
8613 Point standard_size;
8615 standard_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
8616 standard_size.v = dpyinfo->height;
8618 if (IsWindowInStandardState (w, &standard_size, &zoom_rect))
8619 zoom_in_or_out = inZoomIn;
8620 else
8622 /* Adjust the standard size according to character boundaries. */
8624 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, zoom_rect.right - zoom_rect.left);
8625 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
8626 standard_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
8627 standard_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
8628 GetWindowBounds (w, kWindowContentRgn, &port_rect);
8629 if (IsWindowInStandardState (w, &standard_size, &zoom_rect)
8630 && port_rect.left == zoom_rect.left
8631 && port_rect.top == zoom_rect.top)
8632 zoom_in_or_out = inZoomIn;
8633 else
8634 zoom_in_or_out = inZoomOut;
8637 ZoomWindowIdeal (w, zoom_in_or_out, &standard_size);
8639 #else /* not TARGET_API_MAC_CARBON */
8640 GetPort (&save_port);
8642 SetPortWindowPort (w);
8644 /* Clear window to avoid flicker. */
8645 EraseRect (&(w->portRect));
8646 if (zoom_in_or_out == inZoomOut)
8648 SetPt (&top_left, w->portRect.left, w->portRect.top);
8649 LocalToGlobal (&top_left);
8651 /* calculate height of window's title bar */
8652 w_title_height = top_left.v - 1
8653 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
8655 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
8656 zoom_rect = qd.screenBits.bounds;
8657 zoom_rect.top += w_title_height;
8658 InsetRect (&zoom_rect, 8, 4); /* not too tight */
8660 zoom_rect.right = zoom_rect.left
8661 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
8663 /* Adjust the standard size according to character boundaries. */
8664 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
8665 zoom_rect.bottom =
8666 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
8668 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
8669 = zoom_rect;
8672 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
8674 SetPort (save_port);
8675 #endif /* not TARGET_API_MAC_CARBON */
8677 /* retrieve window size and update application values */
8678 #if TARGET_API_MAC_CARBON
8679 GetWindowPortBounds (w, &port_rect);
8680 #else
8681 port_rect = w->portRect;
8682 #endif
8683 height = port_rect.bottom - port_rect.top;
8684 width = port_rect.right - port_rect.left;
8686 if (width != FRAME_PIXEL_WIDTH (f)
8687 || height != FRAME_PIXEL_HEIGHT (f))
8689 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
8690 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
8692 change_frame_size (f, rows, columns, 0, 1, 0);
8693 SET_FRAME_GARBAGED (f);
8694 cancel_mouse_face (f);
8696 FRAME_PIXEL_WIDTH (f) = width;
8697 FRAME_PIXEL_HEIGHT (f) = height;
8699 x_real_positions (f, &f->left_pos, &f->top_pos);
8702 /* Intialize AppleEvent dispatcher table for the required events. */
8703 void
8704 init_required_apple_events ()
8706 OSErr err;
8707 long result;
8709 /* Make sure we have apple events before starting. */
8710 err = Gestalt (gestaltAppleEventsAttr, &result);
8711 if (err != noErr)
8712 abort ();
8714 if (!(result & (1 << gestaltAppleEventsPresent)))
8715 abort ();
8717 #if TARGET_API_MAC_CARBON
8718 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
8719 NewAEEventHandlerUPP
8720 ((AEEventHandlerProcPtr) do_ae_open_application),
8721 0L, false);
8722 #else
8723 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
8724 NewAEEventHandlerProc
8725 ((AEEventHandlerProcPtr) do_ae_open_application),
8726 0L, false);
8727 #endif
8728 if (err != noErr)
8729 abort ();
8731 #if TARGET_API_MAC_CARBON
8732 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
8733 NewAEEventHandlerUPP
8734 ((AEEventHandlerProcPtr) do_ae_open_documents),
8735 0L, false);
8736 #else
8737 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
8738 NewAEEventHandlerProc
8739 ((AEEventHandlerProcPtr) do_ae_open_documents),
8740 0L, false);
8741 #endif
8742 if (err != noErr)
8743 abort ();
8745 #if TARGET_API_MAC_CARBON
8746 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
8747 NewAEEventHandlerUPP
8748 ((AEEventHandlerProcPtr) do_ae_print_documents),
8749 0L, false);
8750 #else
8751 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
8752 NewAEEventHandlerProc
8753 ((AEEventHandlerProcPtr) do_ae_print_documents),
8754 0L, false);
8755 #endif
8756 if (err != noErr)
8757 abort ();
8759 #if TARGET_API_MAC_CARBON
8760 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
8761 NewAEEventHandlerUPP
8762 ((AEEventHandlerProcPtr) do_ae_quit_application),
8763 0L, false);
8764 #else
8765 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
8766 NewAEEventHandlerProc
8767 ((AEEventHandlerProcPtr) do_ae_quit_application),
8768 0L, false);
8769 #endif
8770 if (err != noErr)
8771 abort ();
8774 void
8775 mac_store_application_menu_event (event)
8776 #if USE_CARBON_EVENTS
8777 EventRef event;
8778 #else
8779 UInt32 event;
8780 #endif
8782 struct input_event buf;
8783 Lisp_Object frame, entry;
8785 EVENT_INIT (buf);
8787 XSETFRAME (frame, mac_focus_frame (&one_mac_display_info));
8788 buf.kind = MENU_BAR_EVENT;
8789 buf.frame_or_window = frame;
8790 buf.arg = frame;
8791 kbd_buffer_store_event (&buf);
8793 buf.arg = Qapplication;
8794 kbd_buffer_store_event (&buf);
8796 #if USE_CARBON_EVENTS
8797 switch (GetEventClass (event))
8799 #ifdef MAC_OSX
8800 case kEventClassService:
8801 buf.arg = Qservices;
8802 kbd_buffer_store_event (&buf);
8803 switch (GetEventKind (event))
8805 case kEventServicePaste:
8806 entry = Qpaste;
8807 break;
8809 case kEventServicePerform:
8811 OSErr err;
8812 CFStringRef message;
8814 err = GetEventParameter (event, kEventParamServiceMessageName,
8815 typeCFStringRef, NULL,
8816 sizeof (CFStringRef), NULL, &message);
8817 buf.arg = Qperform;
8818 kbd_buffer_store_event (&buf);
8819 if (err == noErr && message)
8820 entry = intern (SDATA (cfstring_to_lisp (message)));
8821 else
8822 entry = Qnil;
8824 break;
8826 default:
8827 abort ();
8829 break;
8830 #endif /* MAC_OSX */
8831 case kEventClassCommand:
8833 HICommand command;
8835 GetEventParameter(event, kEventParamDirectObject, typeHICommand,
8836 NULL, sizeof (HICommand), NULL, &command);
8837 switch (command.commandID)
8839 case kHICommandAbout:
8840 entry = Qabout;
8841 break;
8842 #ifdef MAC_OSX
8843 case kHICommandPreferences:
8844 entry = Qpreferences;
8845 break;
8846 #endif /* MAC_OSX */
8847 case kHICommandQuit:
8848 entry = Qquit;
8849 break;
8850 default:
8851 abort ();
8854 break;
8856 default:
8857 abort ();
8859 #else /* USE_CARBON_EVENTS */
8860 switch (event)
8862 case kHICommandAbout:
8863 entry = Qabout;
8864 break;
8865 case kHICommandQuit:
8866 entry = Qquit;
8867 break;
8868 default:
8869 abort ();
8871 #endif
8873 buf.arg = entry;
8874 kbd_buffer_store_event (&buf);
8877 #if USE_CARBON_EVENTS
8878 static pascal OSStatus
8879 mac_handle_command_event (next_handler, event, data)
8880 EventHandlerCallRef next_handler;
8881 EventRef event;
8882 void *data;
8884 HICommand command;
8885 OSErr result;
8887 GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL,
8888 sizeof (HICommand), NULL, &command);
8890 switch (command.commandID)
8892 case kHICommandAbout:
8893 #ifdef MAC_OSX
8894 case kHICommandPreferences:
8895 #endif /* MAC_OSX */
8896 result = CallNextEventHandler (next_handler, event);
8897 if (result != eventNotHandledErr)
8898 return result;
8900 mac_store_application_menu_event (event);
8901 return noErr;
8903 default:
8904 break;
8907 return eventNotHandledErr;
8910 static OSErr
8911 init_command_handler ()
8913 OSErr err = noErr;
8914 EventTypeSpec specs[] = {{kEventClassCommand, kEventCommandProcess}};
8915 static EventHandlerUPP handle_command_eventUPP = NULL;
8917 if (handle_command_eventUPP == NULL)
8918 handle_command_eventUPP = NewEventHandlerUPP (mac_handle_command_event);
8919 return InstallApplicationEventHandler (handle_command_eventUPP,
8920 GetEventTypeCount (specs), specs,
8921 NULL, NULL);
8924 static pascal OSStatus
8925 mac_handle_window_event (next_handler, event, data)
8926 EventHandlerCallRef next_handler;
8927 EventRef event;
8928 void *data;
8930 WindowPtr wp;
8931 OSStatus result;
8932 UInt32 attributes;
8933 XSizeHints *size_hints;
8935 GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
8936 NULL, sizeof (WindowPtr), NULL, &wp);
8938 switch (GetEventKind (event))
8940 case kEventWindowUpdate:
8941 result = CallNextEventHandler (next_handler, event);
8942 if (result != eventNotHandledErr)
8943 return result;
8945 do_window_update (wp);
8946 return noErr;
8948 case kEventWindowBoundsChanging:
8949 result = CallNextEventHandler (next_handler, event);
8950 if (result != eventNotHandledErr)
8951 return result;
8953 GetEventParameter (event, kEventParamAttributes, typeUInt32,
8954 NULL, sizeof (UInt32), NULL, &attributes);
8955 size_hints = FRAME_SIZE_HINTS (mac_window_to_frame (wp));
8956 if ((attributes & kWindowBoundsChangeUserResize)
8957 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
8958 == (PResizeInc | PBaseSize | PMinSize)))
8960 Rect bounds;
8961 int width, height;
8963 GetEventParameter (event, kEventParamCurrentBounds,
8964 typeQDRectangle,
8965 NULL, sizeof (Rect), NULL, &bounds);
8966 width = bounds.right - bounds.left;
8967 height = bounds.bottom - bounds.top;
8969 if (width < size_hints->min_width)
8970 width = size_hints->min_width;
8971 else
8972 width = size_hints->base_width
8973 + (int) ((width - size_hints->base_width)
8974 / (float) size_hints->width_inc + .5)
8975 * size_hints->width_inc;
8977 if (height < size_hints->min_height)
8978 height = size_hints->min_height;
8979 else
8980 height = size_hints->base_height
8981 + (int) ((height - size_hints->base_height)
8982 / (float) size_hints->height_inc + .5)
8983 * size_hints->height_inc;
8985 bounds.right = bounds.left + width;
8986 bounds.bottom = bounds.top + height;
8987 SetEventParameter (event, kEventParamCurrentBounds,
8988 typeQDRectangle, sizeof (Rect), &bounds);
8989 return noErr;
8991 break;
8993 case kEventWindowShown:
8994 case kEventWindowHidden:
8995 case kEventWindowExpanded:
8996 case kEventWindowCollapsed:
8997 result = CallNextEventHandler (next_handler, event);
8999 mac_handle_visibility_change (mac_window_to_frame (wp));
9000 return noErr;
9002 break;
9005 return eventNotHandledErr;
9008 static pascal OSStatus
9009 mac_handle_mouse_event (next_handler, event, data)
9010 EventHandlerCallRef next_handler;
9011 EventRef event;
9012 void *data;
9014 OSStatus result;
9016 switch (GetEventKind (event))
9018 case kEventMouseWheelMoved:
9020 WindowPtr wp;
9021 struct frame *f;
9022 EventMouseWheelAxis axis;
9023 SInt32 delta;
9024 Point point;
9026 result = CallNextEventHandler (next_handler, event);
9027 if (result != eventNotHandledErr || read_socket_inev == NULL)
9028 return result;
9030 GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
9031 NULL, sizeof (WindowRef), NULL, &wp);
9032 f = mac_window_to_frame (wp);
9033 if (f != mac_focus_frame (&one_mac_display_info))
9034 break;
9036 GetEventParameter (event, kEventParamMouseWheelAxis,
9037 typeMouseWheelAxis, NULL,
9038 sizeof (EventMouseWheelAxis), NULL, &axis);
9039 if (axis != kEventMouseWheelAxisY)
9040 break;
9042 GetEventParameter (event, kEventParamMouseWheelDelta, typeSInt32,
9043 NULL, sizeof (SInt32), NULL, &delta);
9044 GetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
9045 NULL, sizeof (Point), NULL, &point);
9046 read_socket_inev->kind = WHEEL_EVENT;
9047 read_socket_inev->code = 0;
9048 read_socket_inev->modifiers =
9049 (mac_event_to_emacs_modifiers (event)
9050 | ((delta < 0) ? down_modifier : up_modifier));
9051 SetPortWindowPort (wp);
9052 GlobalToLocal (&point);
9053 XSETINT (read_socket_inev->x, point.h);
9054 XSETINT (read_socket_inev->y, point.v);
9055 XSETFRAME (read_socket_inev->frame_or_window, f);
9057 return noErr;
9059 break;
9061 default:
9062 break;
9065 return eventNotHandledErr;
9067 #endif /* USE_CARBON_EVENTS */
9070 OSErr
9071 install_window_handler (window)
9072 WindowPtr window;
9074 OSErr err = noErr;
9075 #if USE_CARBON_EVENTS
9076 EventTypeSpec specs_window[] =
9077 {{kEventClassWindow, kEventWindowUpdate},
9078 {kEventClassWindow, kEventWindowBoundsChanging},
9079 {kEventClassWindow, kEventWindowShown},
9080 {kEventClassWindow, kEventWindowHidden},
9081 {kEventClassWindow, kEventWindowExpanded},
9082 {kEventClassWindow, kEventWindowCollapsed}};
9083 EventTypeSpec specs_mouse[] = {{kEventClassMouse, kEventMouseWheelMoved}};
9084 static EventHandlerUPP handle_window_eventUPP = NULL;
9085 static EventHandlerUPP handle_mouse_eventUPP = NULL;
9087 if (handle_window_eventUPP == NULL)
9088 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
9089 if (handle_mouse_eventUPP == NULL)
9090 handle_mouse_eventUPP = NewEventHandlerUPP (mac_handle_mouse_event);
9091 err = InstallWindowEventHandler (window, handle_window_eventUPP,
9092 GetEventTypeCount (specs_window),
9093 specs_window, NULL, NULL);
9094 if (err == noErr)
9095 err = InstallWindowEventHandler (window, handle_mouse_eventUPP,
9096 GetEventTypeCount (specs_mouse),
9097 specs_mouse, NULL, NULL);
9098 #endif
9099 #if TARGET_API_MAC_CARBON
9100 if (mac_do_track_dragUPP == NULL)
9101 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
9102 if (mac_do_receive_dragUPP == NULL)
9103 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
9105 if (err == noErr)
9106 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
9107 if (err == noErr)
9108 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
9109 #endif
9110 return err;
9113 void
9114 remove_window_handler (window)
9115 WindowPtr window;
9117 #if TARGET_API_MAC_CARBON
9118 if (mac_do_track_dragUPP)
9119 RemoveTrackingHandler (mac_do_track_dragUPP, window);
9120 if (mac_do_receive_dragUPP)
9121 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
9122 #endif
9125 /* Open Application Apple Event */
9126 static pascal OSErr
9127 do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon)
9129 return noErr;
9133 /* Called when we receive an AppleEvent with an ID of
9134 "kAEOpenDocuments". This routine gets the direct parameter,
9135 extracts the FSSpecs in it, and puts their names on a list. */
9136 #pragma options align=mac68k
9137 typedef struct SelectionRange {
9138 short unused1; // 0 (not used)
9139 short lineNum; // line to select (<0 to specify range)
9140 long startRange; // start of selection range (if line < 0)
9141 long endRange; // end of selection range (if line < 0)
9142 long unused2; // 0 (not used)
9143 long theDate; // modification date/time
9144 } SelectionRange;
9145 #pragma options align=reset
9147 static pascal OSErr
9148 do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
9150 OSErr err, err2;
9151 AEDesc the_desc;
9152 AEKeyword keyword;
9153 DescType actual_type;
9154 Size actual_size;
9155 SelectionRange position;
9156 Lisp_Object file_list = Qnil;
9158 xassert (read_socket_inev);
9160 err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc);
9161 if (err != noErr)
9162 goto descriptor_error_exit;
9164 err = AEGetParamPtr (message, keyAEPosition, typeChar, &actual_type, &position, sizeof(SelectionRange), &actual_size);
9165 if (err == noErr)
9166 file_list = Fcons (list3 (make_number (position.lineNum + 1),
9167 make_number (position.startRange + 1),
9168 make_number (position.endRange + 1)),
9169 file_list);
9171 /* Check to see that we got all of the required parameters from the
9172 event descriptor. For an 'odoc' event this should just be the
9173 file list. */
9174 err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
9175 &actual_type, (Ptr) &keyword,
9176 sizeof (keyword), &actual_size);
9177 /* No error means that we found some unused parameters.
9178 errAEDescNotFound means that there are no more parameters. If we
9179 get an error code other than that, flag it. */
9180 if ((err == noErr) || (err != errAEDescNotFound))
9182 err = errAEEventNotHandled;
9183 goto error_exit;
9185 err = noErr;
9187 /* Got all the parameters we need. Now, go through the direct
9188 object list and parse it up. */
9190 long num_files_to_open;
9192 err = AECountItems (&the_desc, &num_files_to_open);
9193 if (err == noErr)
9195 int i;
9197 /* AE file list is one based so just use that for indexing here. */
9198 for (i = 1; i <= num_files_to_open; i++)
9200 char unix_path_name[MAXPATHLEN];
9201 #ifdef MAC_OSX
9202 FSRef fref;
9204 err = AEGetNthPtr (&the_desc, i, typeFSRef, &keyword,
9205 &actual_type, &fref, sizeof (FSRef),
9206 &actual_size);
9207 if (err != noErr || actual_type != typeFSRef)
9208 continue;
9210 if (FSRefMakePath (&fref, unix_path_name, sizeof (unix_path_name))
9211 == noErr)
9212 #else
9213 FSSpec fs;
9215 err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type,
9216 (Ptr) &fs, sizeof (fs), &actual_size);
9217 if (err != noErr) continue;
9219 if (fsspec_to_posix_pathname (&fs, unix_path_name,
9220 sizeof (unix_path_name) - 1) == noErr)
9221 #endif
9222 /* x-dnd functions expect undecoded filenames. */
9223 file_list = Fcons (make_unibyte_string (unix_path_name,
9224 strlen (unix_path_name)),
9225 file_list);
9229 /* Build a DRAG_N_DROP_EVENT type event as is done in
9230 constuct_drag_n_drop in w32term.c. */
9231 if (!NILP (file_list))
9233 struct frame *f = mac_focus_frame (&one_mac_display_info);
9234 WindowPtr wp;
9235 Lisp_Object frame;
9237 read_socket_inev->kind = DRAG_N_DROP_EVENT;
9238 read_socket_inev->code = 0;
9239 read_socket_inev->modifiers = 0;
9241 XSETINT (read_socket_inev->x, 0);
9242 XSETINT (read_socket_inev->y, 0);
9244 XSETFRAME (frame, f);
9245 read_socket_inev->frame_or_window = Fcons (frame, file_list);
9247 #if 0
9248 /* Regardless of whether Emacs was suspended or in the
9249 foreground, ask it to redraw its entire screen. Otherwise
9250 parts of the screen can be left in an inconsistent
9251 state. */
9252 wp = FRAME_MAC_WINDOW (f);
9253 if (wp)
9254 #if TARGET_API_MAC_CARBON
9256 Rect r;
9258 GetWindowPortBounds (wp, &r);
9259 InvalWindowRect (wp, &r);
9261 #else /* not TARGET_API_MAC_CARBON */
9262 InvalRect (&(wp->portRect));
9263 #endif /* not TARGET_API_MAC_CARBON */
9264 #endif
9268 error_exit:
9269 /* Nuke the coerced file list in any case */
9270 err2 = AEDisposeDesc(&the_desc);
9272 descriptor_error_exit:
9273 /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */
9274 return err;
9278 #if TARGET_API_MAC_CARBON
9279 static pascal OSErr
9280 mac_do_track_drag (DragTrackingMessage message, WindowPtr window,
9281 void *handlerRefCon, DragReference theDrag)
9283 static int can_accept;
9284 short items;
9285 short index;
9286 ItemReference theItem;
9287 FlavorFlags theFlags;
9288 OSErr result;
9290 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
9291 return dragNotAcceptedErr;
9293 switch (message)
9295 case kDragTrackingEnterHandler:
9296 CountDragItems (theDrag, &items);
9297 can_accept = 0;
9298 for (index = 1; index <= items; index++)
9300 GetDragItemReferenceNumber (theDrag, index, &theItem);
9301 result = GetFlavorFlags (theDrag, theItem, flavorTypeHFS, &theFlags);
9302 if (result == noErr)
9304 can_accept = 1;
9305 break;
9308 break;
9310 case kDragTrackingEnterWindow:
9311 if (can_accept)
9313 RgnHandle hilite_rgn = NewRgn ();
9314 Rect r;
9315 struct frame *f = mac_window_to_frame (window);
9317 GetWindowPortBounds (window, &r);
9318 OffsetRect (&r, -r.left, -r.top);
9319 RectRgn (hilite_rgn, &r);
9320 ShowDragHilite (theDrag, hilite_rgn, true);
9321 DisposeRgn (hilite_rgn);
9322 SetThemeCursor (kThemeCopyArrowCursor);
9324 break;
9326 case kDragTrackingInWindow:
9327 break;
9329 case kDragTrackingLeaveWindow:
9330 if (can_accept)
9332 struct frame *f = mac_window_to_frame (window);
9334 HideDragHilite (theDrag);
9335 SetThemeCursor (kThemeArrowCursor);
9337 break;
9339 case kDragTrackingLeaveHandler:
9340 break;
9343 return noErr;
9346 static pascal OSErr
9347 mac_do_receive_drag (WindowPtr window, void *handlerRefCon,
9348 DragReference theDrag)
9350 short items;
9351 short index;
9352 FlavorFlags theFlags;
9353 Point mouse;
9354 OSErr result;
9355 ItemReference theItem;
9356 HFSFlavor data;
9357 Size size = sizeof (HFSFlavor);
9358 Lisp_Object file_list;
9360 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
9361 return dragNotAcceptedErr;
9363 file_list = Qnil;
9364 GetDragMouse (theDrag, &mouse, 0L);
9365 CountDragItems (theDrag, &items);
9366 for (index = 1; index <= items; index++)
9368 /* Only handle file references. */
9369 GetDragItemReferenceNumber (theDrag, index, &theItem);
9370 result = GetFlavorFlags (theDrag, theItem, flavorTypeHFS, &theFlags);
9371 if (result == noErr)
9373 #ifdef MAC_OSX
9374 FSRef fref;
9375 #endif
9376 char unix_path_name[MAXPATHLEN];
9378 GetFlavorData (theDrag, theItem, flavorTypeHFS, &data, &size, 0L);
9379 #ifdef MAC_OSX
9380 /* Use Carbon routines, otherwise it converts the file name
9381 to /Macintosh HD/..., which is not correct. */
9382 FSpMakeFSRef (&data.fileSpec, &fref);
9383 if (! FSRefMakePath (&fref, unix_path_name, sizeof (unix_path_name)));
9384 #else
9385 if (fsspec_to_posix_pathname (&data.fileSpec, unix_path_name,
9386 sizeof (unix_path_name) - 1) == noErr)
9387 #endif
9388 /* x-dnd functions expect undecoded filenames. */
9389 file_list = Fcons (make_unibyte_string (unix_path_name,
9390 strlen (unix_path_name)),
9391 file_list);
9394 /* If there are items in the list, construct an event and post it to
9395 the queue like an interrupt using kbd_buffer_store_event. */
9396 if (!NILP (file_list))
9398 struct input_event event;
9399 Lisp_Object frame;
9400 struct frame *f = mac_window_to_frame (window);
9401 SInt16 modifiers;
9403 GlobalToLocal (&mouse);
9404 GetDragModifiers (theDrag, NULL, NULL, &modifiers);
9406 event.kind = DRAG_N_DROP_EVENT;
9407 event.code = 0;
9408 event.modifiers = mac_to_emacs_modifiers (modifiers);
9409 event.timestamp = TickCount () * (1000 / 60);
9410 XSETINT (event.x, mouse.h);
9411 XSETINT (event.y, mouse.v);
9412 XSETFRAME (frame, f);
9413 event.frame_or_window = Fcons (frame, file_list);
9414 event.arg = Qnil;
9415 /* Post to the interrupt queue */
9416 kbd_buffer_store_event (&event);
9417 /* MAC_TODO: Mimic behavior of windows by switching contexts to Emacs */
9419 ProcessSerialNumber psn;
9420 GetCurrentProcess (&psn);
9421 SetFrontProcess (&psn);
9424 return noErr;
9426 else
9427 return dragNotAcceptedErr;
9429 #endif
9432 /* Print Document Apple Event */
9433 static pascal OSErr
9434 do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon)
9436 return errAEEventNotHandled;
9440 static pascal OSErr
9441 do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon)
9443 #if USE_CARBON_EVENTS
9444 OSErr err;
9445 EventRef event = NULL;
9446 static const HICommand quit_command = {kEventAttributeNone, kHICommandQuit};
9448 err = CreateEvent (NULL, kEventClassCommand, kEventCommandProcess, 0,
9449 kEventAttributeUserEvent, &event);
9450 if (err == noErr)
9451 err = SetEventParameter (event, kEventParamDirectObject, typeHICommand,
9452 sizeof (HICommand), &quit_command);
9453 if (err == noErr)
9454 mac_store_application_menu_event (event);
9455 if (event)
9456 ReleaseEvent (event);
9458 if (err == noErr)
9459 return noErr;
9460 else
9461 return errAEEventNotHandled;
9462 #else
9463 mac_store_application_menu_event (kHICommandQuit);
9465 return noErr;
9466 #endif
9470 #if __profile__
9471 void
9472 profiler_exit_proc ()
9474 ProfilerDump ("\pEmacs.prof");
9475 ProfilerTerm ();
9477 #endif
9479 /* These few functions implement Emacs as a normal Mac application
9480 (almost): set up the heap and the Toolbox, handle necessary system
9481 events plus a few simple menu events. They also set up Emacs's
9482 access to functions defined in the rest of this file. Emacs uses
9483 function hooks to perform all its terminal I/O. A complete list of
9484 these functions appear in termhooks.h. For what they do, read the
9485 comments there and see also w32term.c and xterm.c. What's
9486 noticeably missing here is the event loop, which is normally
9487 present in most Mac application. After performing the necessary
9488 Mac initializations, main passes off control to emacs_main
9489 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
9490 (defined further below) to read input. This is where
9491 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
9493 #ifdef MAC_OS8
9494 #undef main
9496 main (void)
9498 #if __profile__ /* is the profiler on? */
9499 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
9500 exit(1);
9501 #endif
9503 #if __MWERKS__
9504 /* set creator and type for files created by MSL */
9505 _fcreator = 'EMAx';
9506 _ftype = 'TEXT';
9507 #endif
9509 do_init_managers ();
9511 do_get_menus ();
9513 #ifndef USE_LSB_TAG
9514 do_check_ram_size ();
9515 #endif
9517 init_emacs_passwd_dir ();
9519 init_environ ();
9521 initialize_applescript ();
9523 init_required_apple_events ();
9526 char **argv;
9527 int argc = 0;
9529 /* set up argv array from STR# resource */
9530 get_string_list (&argv, ARGV_STRING_LIST_ID);
9531 while (argv[argc])
9532 argc++;
9534 /* free up AppleScript resources on exit */
9535 atexit (terminate_applescript);
9537 #if __profile__ /* is the profiler on? */
9538 atexit (profiler_exit_proc);
9539 #endif
9541 /* 3rd param "envp" never used in emacs_main */
9542 (void) emacs_main (argc, argv, 0);
9545 /* Never reached - real exit in Fkill_emacs */
9546 return 0;
9548 #endif
9550 /* Table for translating Mac keycode to X keysym values. Contributed
9551 by Sudhir Shenoy.
9552 Mapping for special keys is now identical to that in Apple X11
9553 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9554 on the right of the Cmd key on laptops, and fn + `enter' (->
9555 <linefeed>). */
9556 static unsigned char keycode_to_xkeysym_table[] = {
9557 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9558 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9559 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9561 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9562 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9563 /*0x38*/ 0, 0, 0, 0,
9564 /*0x3C*/ 0, 0, 0, 0,
9566 /*0x40*/ 0, 0xae /*kp-.*/, 0, 0xaa /*kp-**/,
9567 /*0x44*/ 0, 0xab /*kp-+*/, 0, 0x0b /*clear*/,
9568 /*0x48*/ 0, 0, 0, 0xaf /*kp-/*/,
9569 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp--*/, 0,
9571 /*0x50*/ 0, 0xbd /*kp-=*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9572 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9573 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9574 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9576 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9577 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9578 /*0x68*/ 0, 0xca /*f13*/, 0, 0xcb /*f14*/,
9579 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9581 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9582 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9583 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9584 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9588 static int
9589 keycode_to_xkeysym (int keyCode, int *xKeySym)
9591 *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f];
9592 return *xKeySym != 0;
9595 static unsigned char fn_keycode_to_xkeysym_table[] = {
9596 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9597 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9598 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9600 /*0x30*/ 0, 0, 0, 0,
9601 /*0x34*/ 0, 0, 0, 0,
9602 /*0x38*/ 0, 0, 0, 0,
9603 /*0x3C*/ 0, 0, 0, 0,
9605 /*0x40*/ 0, 0x2e /*kp-. = .*/, 0, 0x50 /*kp-* = 'p'*/,
9606 /*0x44*/ 0, '/' /*kp-+*/, 0, 0,
9607 /*0x48*/ 0, 0, 0, 0x30 /*kp-/ = '0'*/,
9608 /*0x4C*/ 0, 0, 0x3b /*kp-- = ';'*/, 0,
9610 /*0x50*/ 0, 0x2d /*kp-= = '-'*/, 0x6d /*kp-0 = 'm'*/, 0x6a /*kp-1 = 'j'*/,
9611 /*0x54*/ 0x6b /*kp-2 = 'k'*/, 0x6c /*kp-3 = 'l'*/, 'u' /*kp-4*/, 'i' /*kp-5*/,
9612 /*0x58*/ 'o' /*kp-6*/, '7' /*kp-7*/, 0, '8' /*kp-8*/,
9613 /*0x5C*/ '9' /*kp-9*/, 0, 0, 0,
9615 /*0x60*/ 0, 0, 0, 0,
9616 /*0x64*/ 0, 0, 0, 0,
9617 /*0x68*/ 0, 0, 0, 0,
9618 /*0x6C*/ 0, 0, 0, 0,
9620 /*0x70*/ 0, 0, 0, 0,
9621 /*0x74*/ 0, 0, 0, 0,
9622 /*0x78*/ 0, 0, 0, 0,
9623 /*0x7C*/ 0, 0, 0, 0
9625 static int
9626 convert_fn_keycode (EventRef eventRef, int keyCode, int *newCode)
9628 #ifdef MAC_OSX
9629 /* Use the special map to translate keys when function modifier is
9630 to be caught. KeyTranslate can't be used in that case.
9631 We can't detect the function key using the input_event.modifiers,
9632 because this uses the high word of an UInt32. Therefore,
9633 we'll just read it out of the original eventRef.
9637 /* TODO / known issues
9639 - Fn-Shift-j is regonized as Fn-j and not Fn-J.
9640 The above table always translates to lower characters. We need to use
9641 the KCHR keyboard resource (KeyTranslate() ) to map k->K and 8->*.
9643 - The table is meant for English language keyboards, and it will work
9644 for many others with the exception of key combinations like Fn-ö on
9645 a German keyboard, which is currently mapped to Fn-;.
9646 How to solve this without keeping separate tables for all keyboards
9647 around? KeyTranslate isn't of much help here, as it only takes a 16-bit
9648 value for keycode with the modifiers in he high byte, i.e. no room for the
9649 Fn modifier. That's why we need the table.
9653 UInt32 mods = 0;
9654 if (!NILP(Vmac_function_modifier))
9656 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
9657 sizeof (UInt32), NULL, &mods);
9658 if (mods & kEventKeyModifierFnMask)
9659 { *newCode = fn_keycode_to_xkeysym_table [keyCode & 0x7f];
9661 return (*newCode != 0);
9664 #endif
9665 return false;
9668 static int
9669 backtranslate_modified_keycode(int mods, int keycode, int def)
9671 if (mods &
9672 (controlKey |
9673 (NILP (Vmac_option_modifier) ? 0 : optionKey) |
9674 cmdKey))
9676 /* This code comes from Keyboard Resource,
9677 Appendix C of IM - Text. This is necessary
9678 since shift is ignored in KCHR table
9679 translation when option or command is pressed.
9680 It also does not translate correctly
9681 control-shift chars like C-% so mask off shift
9682 here also.
9684 Not done for combinations with the option key (alt)
9685 unless it is to be caught by Emacs: this is
9686 to preserve key combinations translated by the OS
9687 such as Alt-3.
9689 /* mask off option and command */
9690 int new_modifiers = mods & 0xe600;
9691 /* set high byte of keycode to modifier high byte*/
9692 int new_keycode = keycode | new_modifiers;
9693 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
9694 unsigned long some_state = 0;
9695 return (int) KeyTranslate (kchr_ptr, new_keycode,
9696 &some_state) & 0xff;
9697 /* TO DO: Recognize two separate resulting characters, "for
9698 example, when the user presses Option-E followed by N, you
9699 can map this through the KeyTranslate function using the
9700 U.S. 'KCHR' resource to produce ´n, which KeyTranslate
9701 returns as two characters in the bytes labeled Character code
9702 1 and Character code 2." (from Carbon API doc) */
9705 else
9706 return def;
9710 #if !USE_CARBON_EVENTS
9711 static RgnHandle mouse_region = NULL;
9713 Boolean
9714 mac_wait_next_event (er, sleep_time, dequeue)
9715 EventRecord *er;
9716 UInt32 sleep_time;
9717 Boolean dequeue;
9719 static EventRecord er_buf = {nullEvent};
9720 UInt32 target_tick, current_tick;
9721 EventMask event_mask;
9723 if (mouse_region == NULL)
9724 mouse_region = NewRgn ();
9726 event_mask = everyEvent;
9727 if (NILP (Fboundp (Qmac_ready_for_drag_n_drop)))
9728 event_mask -= highLevelEventMask;
9730 current_tick = TickCount ();
9731 target_tick = current_tick + sleep_time;
9733 if (er_buf.what == nullEvent)
9734 while (!WaitNextEvent (event_mask, &er_buf,
9735 target_tick - current_tick, mouse_region))
9737 current_tick = TickCount ();
9738 if (target_tick <= current_tick)
9739 return false;
9742 *er = er_buf;
9743 if (dequeue)
9744 er_buf.what = nullEvent;
9745 return true;
9747 #endif /* not USE_CARBON_EVENTS */
9749 /* Emacs calls this whenever it wants to read an input event from the
9750 user. */
9752 XTread_socket (sd, expected, hold_quit)
9753 int sd, expected;
9754 struct input_event *hold_quit;
9756 struct input_event inev;
9757 int count = 0;
9758 #if USE_CARBON_EVENTS
9759 EventRef eventRef;
9760 EventTargetRef toolbox_dispatcher;
9761 #endif
9762 EventRecord er;
9763 struct mac_display_info *dpyinfo = &one_mac_display_info;
9765 if (interrupt_input_blocked)
9767 interrupt_input_pending = 1;
9768 return -1;
9771 interrupt_input_pending = 0;
9772 BLOCK_INPUT;
9774 /* So people can tell when we have read the available input. */
9775 input_signal_count++;
9777 #if USE_CARBON_EVENTS
9778 toolbox_dispatcher = GetEventDispatcherTarget ();
9780 while (!ReceiveNextEvent (0, NULL, kEventDurationNoWait,
9781 kEventRemoveFromQueue, &eventRef))
9782 #else /* !USE_CARBON_EVENTS */
9783 while (mac_wait_next_event (&er, 0, true))
9784 #endif /* !USE_CARBON_EVENTS */
9786 int do_help = 0;
9787 struct frame *f;
9788 unsigned long timestamp;
9790 /* It is necessary to set this (additional) argument slot of an
9791 event to nil because keyboard.c protects incompletely
9792 processed event from being garbage collected by placing them
9793 in the kbd_buffer_gcpro vector. */
9794 EVENT_INIT (inev);
9795 inev.kind = NO_EVENT;
9796 inev.arg = Qnil;
9798 #if USE_CARBON_EVENTS
9799 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
9800 #else
9801 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
9802 #endif
9804 #if USE_CARBON_EVENTS
9805 /* Handle new events */
9806 if (!mac_convert_event_ref (eventRef, &er))
9808 /* There used to be a handler for the kEventMouseWheelMoved
9809 event here. But as of Mac OS X 10.4, this kind of event
9810 is not directly posted to the main event queue by
9811 two-finger scrolling on the trackpad. Instead, some
9812 private event is posted and it is converted to a wheel
9813 event by the default handler for the application target.
9814 The converted one can be received by a Carbon event
9815 handler installed on a window target. */
9816 read_socket_inev = &inev;
9817 SendEventToEventTarget (eventRef, toolbox_dispatcher);
9818 read_socket_inev = NULL;
9820 else
9821 #endif /* USE_CARBON_EVENTS */
9822 switch (er.what)
9824 case mouseDown:
9825 case mouseUp:
9827 WindowPtr window_ptr;
9828 ControlPartCode part_code;
9829 int tool_bar_p = 0;
9831 #if USE_CARBON_EVENTS
9832 /* This is needed to send mouse events like aqua window
9833 buttons to the correct handler. */
9834 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
9835 != eventNotHandledErr)
9836 break;
9837 #endif
9838 last_mouse_glyph_frame = 0;
9840 if (dpyinfo->grabbed && last_mouse_frame
9841 && FRAME_LIVE_P (last_mouse_frame))
9843 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
9844 part_code = inContent;
9846 else
9848 part_code = FindWindow (er.where, &window_ptr);
9849 if (tip_window && window_ptr == tip_window)
9851 HideWindow (tip_window);
9852 part_code = FindWindow (er.where, &window_ptr);
9856 if (er.what != mouseDown &&
9857 (part_code != inContent || dpyinfo->grabbed == 0))
9858 break;
9860 switch (part_code)
9862 case inMenuBar:
9863 f = mac_focus_frame (dpyinfo);
9864 saved_menu_event_location = er.where;
9865 inev.kind = MENU_BAR_ACTIVATE_EVENT;
9866 XSETFRAME (inev.frame_or_window, f);
9867 break;
9869 case inContent:
9870 if (window_ptr != FRAME_MAC_WINDOW (mac_focus_frame (dpyinfo)))
9871 SelectWindow (window_ptr);
9872 else
9874 ControlPartCode control_part_code;
9875 ControlHandle ch;
9876 Point mouse_loc = er.where;
9877 #ifdef MAC_OSX
9878 ControlKind control_kind;
9879 #endif
9881 f = mac_window_to_frame (window_ptr);
9882 /* convert to local coordinates of new window */
9883 SetPortWindowPort (window_ptr);
9885 GlobalToLocal (&mouse_loc);
9886 #if TARGET_API_MAC_CARBON
9887 ch = FindControlUnderMouse (mouse_loc, window_ptr,
9888 &control_part_code);
9889 #ifdef MAC_OSX
9890 if (ch)
9891 GetControlKind (ch, &control_kind);
9892 #endif
9893 #else
9894 control_part_code = FindControl (mouse_loc, window_ptr,
9895 &ch);
9896 #endif
9898 #if USE_CARBON_EVENTS
9899 inev.code = mac_get_mouse_btn (eventRef);
9900 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
9901 #else
9902 inev.code = mac_get_emulated_btn (er.modifiers);
9903 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
9904 #endif
9905 XSETINT (inev.x, mouse_loc.h);
9906 XSETINT (inev.y, mouse_loc.v);
9908 if (dpyinfo->grabbed && tracked_scroll_bar
9909 || ch != 0
9910 #ifndef USE_TOOLKIT_SCROLL_BARS
9911 /* control_part_code becomes kControlNoPart if
9912 a progress indicator is clicked. */
9913 && control_part_code != kControlNoPart
9914 #else /* USE_TOOLKIT_SCROLL_BARS */
9915 #ifdef MAC_OSX
9916 && control_kind.kind == kControlKindScrollBar
9917 #endif /* MAC_OSX */
9918 #endif /* USE_TOOLKIT_SCROLL_BARS */
9921 struct scroll_bar *bar;
9923 if (dpyinfo->grabbed && tracked_scroll_bar)
9925 bar = tracked_scroll_bar;
9926 #ifndef USE_TOOLKIT_SCROLL_BARS
9927 control_part_code = kControlIndicatorPart;
9928 #endif
9930 else
9931 bar = (struct scroll_bar *) GetControlReference (ch);
9932 #ifdef USE_TOOLKIT_SCROLL_BARS
9933 /* Make the "Ctrl-Mouse-2 splits window" work
9934 for toolkit scroll bars. */
9935 if (er.modifiers & controlKey)
9936 x_scroll_bar_handle_click (bar, control_part_code,
9937 &er, &inev);
9938 else if (er.what == mouseDown)
9939 x_scroll_bar_handle_press (bar, control_part_code,
9940 &inev);
9941 else
9942 x_scroll_bar_handle_release (bar, &inev);
9943 #else /* not USE_TOOLKIT_SCROLL_BARS */
9944 x_scroll_bar_handle_click (bar, control_part_code,
9945 &er, &inev);
9946 if (er.what == mouseDown
9947 && control_part_code == kControlIndicatorPart)
9948 tracked_scroll_bar = bar;
9949 else
9950 tracked_scroll_bar = NULL;
9951 #endif /* not USE_TOOLKIT_SCROLL_BARS */
9953 else
9955 Lisp_Object window;
9956 int x = mouse_loc.h;
9957 int y = mouse_loc.v;
9959 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
9960 if (EQ (window, f->tool_bar_window))
9962 if (er.what == mouseDown)
9963 handle_tool_bar_click (f, x, y, 1, 0);
9964 else
9965 handle_tool_bar_click (f, x, y, 0,
9966 inev.modifiers);
9967 tool_bar_p = 1;
9969 else
9971 XSETFRAME (inev.frame_or_window, f);
9972 inev.kind = MOUSE_CLICK_EVENT;
9976 if (er.what == mouseDown)
9978 dpyinfo->grabbed |= (1 << inev.code);
9979 last_mouse_frame = f;
9981 if (!tool_bar_p)
9982 last_tool_bar_item = -1;
9984 else
9986 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
9987 /* If a button is released though it was not
9988 previously pressed, that would be because
9989 of multi-button emulation. */
9990 dpyinfo->grabbed = 0;
9991 else
9992 dpyinfo->grabbed &= ~(1 << inev.code);
9995 /* Ignore any mouse motion that happened before
9996 this event; any subsequent mouse-movement Emacs
9997 events should reflect only motion after the
9998 ButtonPress. */
9999 if (f != 0)
10000 f->mouse_moved = 0;
10002 #ifdef USE_TOOLKIT_SCROLL_BARS
10003 if (inev.kind == MOUSE_CLICK_EVENT)
10004 #endif
10005 switch (er.what)
10007 case mouseDown:
10008 inev.modifiers |= down_modifier;
10009 break;
10010 case mouseUp:
10011 inev.modifiers |= up_modifier;
10012 break;
10015 break;
10017 case inDrag:
10018 #if TARGET_API_MAC_CARBON
10019 DragWindow (window_ptr, er.where, NULL);
10020 #else /* not TARGET_API_MAC_CARBON */
10021 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
10022 #endif /* not TARGET_API_MAC_CARBON */
10023 /* Update the frame parameters. */
10025 struct frame *f = mac_window_to_frame (window_ptr);
10027 if (f && !f->async_iconified)
10028 x_real_positions (f, &f->left_pos, &f->top_pos);
10030 break;
10032 case inGoAway:
10033 if (TrackGoAway (window_ptr, er.where))
10035 inev.kind = DELETE_WINDOW_EVENT;
10036 XSETFRAME (inev.frame_or_window,
10037 mac_window_to_frame (window_ptr));
10039 break;
10041 /* window resize handling added --ben */
10042 case inGrow:
10043 do_grow_window (window_ptr, &er);
10044 break;
10046 /* window zoom handling added --ben */
10047 case inZoomIn:
10048 case inZoomOut:
10049 if (TrackBox (window_ptr, er.where, part_code))
10050 do_zoom_window (window_ptr, part_code);
10051 break;
10053 default:
10054 break;
10057 break;
10059 case updateEvt:
10060 #if USE_CARBON_EVENTS
10061 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
10062 != eventNotHandledErr)
10063 break;
10064 #else
10065 do_window_update ((WindowPtr) er.message);
10066 #endif
10067 break;
10069 case osEvt:
10070 #if USE_CARBON_EVENTS
10071 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
10072 != eventNotHandledErr)
10073 break;
10074 #endif
10075 switch ((er.message >> 24) & 0x000000FF)
10077 case suspendResumeMessage:
10078 if ((er.message & resumeFlag) == 1)
10079 do_app_resume ();
10080 else
10081 do_app_suspend ();
10082 break;
10084 case mouseMovedMessage:
10085 #if !USE_CARBON_EVENTS
10086 SetRectRgn (mouse_region, er.where.h, er.where.v,
10087 er.where.h + 1, er.where.v + 1);
10088 #endif
10089 previous_help_echo_string = help_echo_string;
10090 help_echo_string = Qnil;
10092 if (dpyinfo->grabbed && last_mouse_frame
10093 && FRAME_LIVE_P (last_mouse_frame))
10094 f = last_mouse_frame;
10095 else
10096 f = dpyinfo->x_focus_frame;
10098 if (dpyinfo->mouse_face_hidden)
10100 dpyinfo->mouse_face_hidden = 0;
10101 clear_mouse_face (dpyinfo);
10104 if (f)
10106 WindowPtr wp = FRAME_MAC_WINDOW (f);
10107 Point mouse_pos = er.where;
10109 SetPortWindowPort (wp);
10111 GlobalToLocal (&mouse_pos);
10113 if (dpyinfo->grabbed && tracked_scroll_bar)
10114 #ifdef USE_TOOLKIT_SCROLL_BARS
10115 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
10116 mouse_pos, &inev);
10117 #else /* not USE_TOOLKIT_SCROLL_BARS */
10118 x_scroll_bar_note_movement (tracked_scroll_bar,
10119 mouse_pos.v
10120 - XINT (tracked_scroll_bar->top),
10121 er.when * (1000 / 60));
10122 #endif /* not USE_TOOLKIT_SCROLL_BARS */
10123 else
10125 /* Generate SELECT_WINDOW_EVENTs when needed. */
10126 if (mouse_autoselect_window)
10128 Lisp_Object window;
10130 window = window_from_coordinates (f,
10131 mouse_pos.h,
10132 mouse_pos.v,
10133 0, 0, 0, 0);
10135 /* Window will be selected only when it is
10136 not selected now and last mouse movement
10137 event was not in it. Minibuffer window
10138 will be selected iff it is active. */
10139 if (WINDOWP (window)
10140 && !EQ (window, last_window)
10141 && !EQ (window, selected_window))
10143 inev.kind = SELECT_WINDOW_EVENT;
10144 inev.frame_or_window = window;
10147 last_window=window;
10149 if (!note_mouse_movement (f, &mouse_pos))
10150 help_echo_string = previous_help_echo_string;
10154 /* If the contents of the global variable
10155 help_echo_string has changed, generate a
10156 HELP_EVENT. */
10157 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
10158 do_help = 1;
10159 break;
10161 break;
10163 case activateEvt:
10165 WindowPtr window_ptr = (WindowPtr) er.message;
10167 #if USE_CARBON_EVENTS
10168 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
10169 != eventNotHandledErr)
10170 break;
10171 #endif
10172 if (window_ptr == tip_window)
10174 HideWindow (tip_window);
10175 break;
10178 if (!is_emacs_window (window_ptr))
10179 break;
10181 if ((er.modifiers & activeFlag) != 0)
10183 /* A window has been activated */
10184 Point mouse_loc = er.where;
10186 x_detect_focus_change (dpyinfo, &er, &inev);
10188 SetPortWindowPort (window_ptr);
10189 GlobalToLocal (&mouse_loc);
10190 /* Window-activated event counts as mouse movement,
10191 so update things that depend on mouse position. */
10192 note_mouse_movement (mac_window_to_frame (window_ptr),
10193 &mouse_loc);
10195 else
10197 /* A window has been deactivated */
10198 #if USE_TOOLKIT_SCROLL_BARS
10199 if (dpyinfo->grabbed && tracked_scroll_bar)
10201 struct input_event event;
10203 EVENT_INIT (event);
10204 event.kind = NO_EVENT;
10205 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
10206 if (event.kind != NO_EVENT)
10208 event.timestamp = timestamp;
10209 kbd_buffer_store_event_hold (&event, hold_quit);
10210 count++;
10213 #endif
10214 dpyinfo->grabbed = 0;
10216 x_detect_focus_change (dpyinfo, &er, &inev);
10218 f = mac_window_to_frame (window_ptr);
10219 if (f == dpyinfo->mouse_face_mouse_frame)
10221 /* If we move outside the frame, then we're
10222 certainly no longer on any text in the
10223 frame. */
10224 clear_mouse_face (dpyinfo);
10225 dpyinfo->mouse_face_mouse_frame = 0;
10228 /* Generate a nil HELP_EVENT to cancel a help-echo.
10229 Do it only if there's something to cancel.
10230 Otherwise, the startup message is cleared when the
10231 mouse leaves the frame. */
10232 if (any_help_event_p)
10233 do_help = -1;
10236 break;
10238 case keyDown:
10239 case autoKey:
10241 int keycode = (er.message & keyCodeMask) >> 8;
10242 int xkeysym;
10244 #if USE_CARBON_EVENTS && defined (MAC_OSX)
10245 /* When using Carbon Events, we need to pass raw keyboard
10246 events to the TSM ourselves. If TSM handles it, it
10247 will pass back noErr, otherwise it will pass back
10248 "eventNotHandledErr" and we can process it
10249 normally. */
10250 if ((!NILP (Vmac_pass_command_to_system)
10251 || !(er.modifiers & cmdKey))
10252 && (!NILP (Vmac_pass_control_to_system)
10253 || !(er.modifiers & controlKey))
10254 && (NILP (Vmac_option_modifier)
10255 || !(er.modifiers & optionKey)))
10256 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
10257 != eventNotHandledErr)
10258 break;
10259 #endif
10261 #if 0
10262 if (dpyinfo->x_focus_frame == NULL)
10264 /* Beep if keyboard input occurs when all the frames
10265 are invisible. */
10266 SysBeep (1);
10267 break;
10269 #endif
10272 static SInt16 last_key_script = -1;
10273 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10275 if (last_key_script != current_key_script)
10277 struct input_event event;
10279 EVENT_INIT (event);
10280 event.kind = LANGUAGE_CHANGE_EVENT;
10281 event.arg = Qnil;
10282 event.code = current_key_script;
10283 event.timestamp = timestamp;
10284 kbd_buffer_store_event (&event);
10285 count++;
10287 last_key_script = current_key_script;
10290 ObscureCursor ();
10292 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
10294 clear_mouse_face (dpyinfo);
10295 dpyinfo->mouse_face_hidden = 1;
10298 /* translate the keycode back to determine the original key */
10299 /* Convert key code if function key is pressed.
10300 Otherwise, if non-ASCII-event, take care of that
10301 without re-translating the key code. */
10302 #if USE_CARBON_EVENTS
10303 if (convert_fn_keycode (eventRef, keycode, &xkeysym))
10305 inev.code = xkeysym;
10306 /* this doesn't work - tried to add shift modifiers */
10307 inev.code =
10308 backtranslate_modified_keycode(er.modifiers & (~0x2200),
10309 xkeysym | 0x80, xkeysym);
10310 inev.kind = ASCII_KEYSTROKE_EVENT;
10312 else
10313 #endif
10314 if (keycode_to_xkeysym (keycode, &xkeysym))
10316 inev.code = 0xff00 | xkeysym;
10317 inev.kind = NON_ASCII_KEYSTROKE_EVENT;
10319 else
10322 inev.code =
10323 backtranslate_modified_keycode(er.modifiers, keycode,
10324 er.message & charCodeMask);
10325 inev.kind = ASCII_KEYSTROKE_EVENT;
10330 #if USE_CARBON_EVENTS
10331 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
10332 #else
10333 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
10334 #endif
10335 inev.modifiers |= (extra_keyboard_modifiers
10336 & (meta_modifier | alt_modifier
10337 | hyper_modifier | super_modifier));
10338 XSETFRAME (inev.frame_or_window, mac_focus_frame (dpyinfo));
10339 break;
10341 case kHighLevelEvent:
10342 read_socket_inev = &inev;
10343 AEProcessAppleEvent (&er);
10344 read_socket_inev = NULL;
10345 break;
10347 default:
10348 break;
10350 #if USE_CARBON_EVENTS
10351 ReleaseEvent (eventRef);
10352 #endif
10354 if (inev.kind != NO_EVENT)
10356 inev.timestamp = timestamp;
10357 kbd_buffer_store_event_hold (&inev, hold_quit);
10358 count++;
10361 if (do_help
10362 && !(hold_quit && hold_quit->kind != NO_EVENT))
10364 Lisp_Object frame;
10366 if (f)
10367 XSETFRAME (frame, f);
10368 else
10369 frame = Qnil;
10371 if (do_help > 0)
10373 any_help_event_p = 1;
10374 gen_help_event (help_echo_string, frame, help_echo_window,
10375 help_echo_object, help_echo_pos);
10377 else
10379 help_echo_string = Qnil;
10380 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
10382 count++;
10387 /* If the focus was just given to an autoraising frame,
10388 raise it now. */
10389 /* ??? This ought to be able to handle more than one such frame. */
10390 if (pending_autoraise_frame)
10392 x_raise_frame (pending_autoraise_frame);
10393 pending_autoraise_frame = 0;
10396 #if !USE_CARBON_EVENTS
10397 /* Check which frames are still visible. We do this here because
10398 there doesn't seem to be any direct notification from the Window
10399 Manager that the visibility of a window has changed (at least,
10400 not in all cases). */
10402 Lisp_Object tail, frame;
10404 FOR_EACH_FRAME (tail, frame)
10406 struct frame *f = XFRAME (frame);
10408 /* The tooltip has been drawn already. Avoid the
10409 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
10410 if (EQ (frame, tip_frame))
10411 continue;
10413 if (FRAME_MAC_P (f))
10414 mac_handle_visibility_change (f);
10417 #endif
10419 UNBLOCK_INPUT;
10420 return count;
10424 /* Need to override CodeWarrior's input function so no conversion is
10425 done on newlines Otherwise compiled functions in .elc files will be
10426 read incorrectly. Defined in ...:MSL C:MSL
10427 Common:Source:buffer_io.c. */
10428 #ifdef __MWERKS__
10429 void
10430 __convert_to_newlines (unsigned char * p, size_t * n)
10432 #pragma unused(p,n)
10435 void
10436 __convert_from_newlines (unsigned char * p, size_t * n)
10438 #pragma unused(p,n)
10440 #endif
10442 #ifdef MAC_OS8
10443 void
10444 make_mac_terminal_frame (struct frame *f)
10446 Lisp_Object frame;
10447 Rect r;
10449 XSETFRAME (frame, f);
10451 f->output_method = output_mac;
10452 f->output_data.mac = (struct mac_output *)
10453 xmalloc (sizeof (struct mac_output));
10454 bzero (f->output_data.mac, sizeof (struct mac_output));
10456 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
10458 FRAME_COLS (f) = 96;
10459 FRAME_LINES (f) = 4;
10461 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
10462 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
10464 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
10466 f->output_data.mac->cursor_pixel = 0;
10467 f->output_data.mac->border_pixel = 0x00ff00;
10468 f->output_data.mac->mouse_pixel = 0xff00ff;
10469 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
10471 f->output_data.mac->text_cursor = kThemeIBeamCursor;
10472 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
10473 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
10474 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
10475 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
10476 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
10478 FRAME_FONTSET (f) = -1;
10479 f->output_data.mac->explicit_parent = 0;
10480 f->left_pos = 8;
10481 f->top_pos = 32;
10482 f->border_width = 0;
10484 f->internal_border_width = 0;
10486 f->auto_raise = 1;
10487 f->auto_lower = 1;
10489 f->new_text_cols = 0;
10490 f->new_text_lines = 0;
10492 SetRect (&r, f->left_pos, f->top_pos,
10493 f->left_pos + FRAME_PIXEL_WIDTH (f),
10494 f->top_pos + FRAME_PIXEL_HEIGHT (f));
10496 BLOCK_INPUT;
10498 if (!(FRAME_MAC_WINDOW (f) =
10499 NewCWindow (NULL, &r, "\p", true, dBoxProc,
10500 (WindowPtr) -1, 1, (long) f->output_data.mac)))
10501 abort ();
10502 /* so that update events can find this mac_output struct */
10503 f->output_data.mac->mFP = f; /* point back to emacs frame */
10505 UNBLOCK_INPUT;
10507 x_make_gc (f);
10509 /* Need to be initialized for unshow_buffer in window.c. */
10510 selected_window = f->selected_window;
10512 Fmodify_frame_parameters (frame,
10513 Fcons (Fcons (Qfont,
10514 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
10515 Fmodify_frame_parameters (frame,
10516 Fcons (Fcons (Qforeground_color,
10517 build_string ("black")), Qnil));
10518 Fmodify_frame_parameters (frame,
10519 Fcons (Fcons (Qbackground_color,
10520 build_string ("white")), Qnil));
10522 #endif
10525 /***********************************************************************
10526 Initialization
10527 ***********************************************************************/
10529 int mac_initialized = 0;
10531 void
10532 mac_initialize_display_info ()
10534 struct mac_display_info *dpyinfo = &one_mac_display_info;
10535 GDHandle main_device_handle;
10537 bzero (dpyinfo, sizeof (*dpyinfo));
10539 #ifdef MAC_OSX
10540 dpyinfo->mac_id_name
10541 = (char *) xmalloc (SCHARS (Vinvocation_name)
10542 + SCHARS (Vsystem_name)
10543 + 2);
10544 sprintf (dpyinfo->mac_id_name, "%s@%s",
10545 SDATA (Vinvocation_name), SDATA (Vsystem_name));
10546 #else
10547 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
10548 strcpy (dpyinfo->mac_id_name, "Mac Display");
10549 #endif
10551 main_device_handle = LMGetMainDevice();
10553 dpyinfo->reference_count = 0;
10554 dpyinfo->resx = 72.0;
10555 dpyinfo->resy = 72.0;
10556 dpyinfo->color_p = TestDeviceAttribute (main_device_handle, gdDevType);
10557 #ifdef MAC_OSX
10558 /* HasDepth returns true if it is possible to have a 32 bit display,
10559 but this may not be what is actually used. Mac OSX can do better.
10560 CGMainDisplayID is only available on OSX 10.2 and higher, but the
10561 header for CGGetActiveDisplayList says that the first display returned
10562 is the active one, so we use that. */
10564 CGDirectDisplayID disp_id[1];
10565 CGDisplayCount disp_count;
10566 CGDisplayErr error_code;
10568 error_code = CGGetActiveDisplayList (1, disp_id, &disp_count);
10569 if (error_code != 0)
10570 error ("No display found, CGGetActiveDisplayList error %d", error_code);
10572 dpyinfo->n_planes = CGDisplayBitsPerPixel (disp_id[0]);
10574 #else
10575 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
10576 if (HasDepth (main_device_handle, dpyinfo->n_planes,
10577 gdDevType, dpyinfo->color_p))
10578 break;
10579 #endif
10580 dpyinfo->height = (**main_device_handle).gdRect.bottom;
10581 dpyinfo->width = (**main_device_handle).gdRect.right;
10582 dpyinfo->grabbed = 0;
10583 dpyinfo->root_window = NULL;
10584 dpyinfo->image_cache = make_image_cache ();
10586 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
10587 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
10588 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
10589 dpyinfo->mouse_face_window = Qnil;
10590 dpyinfo->mouse_face_overlay = Qnil;
10591 dpyinfo->mouse_face_hidden = 0;
10595 static XrmDatabase
10596 mac_make_rdb (xrm_option)
10597 char *xrm_option;
10599 XrmDatabase database;
10601 database = xrm_get_preference_database (NULL);
10602 if (xrm_option)
10603 xrm_merge_string_database (database, xrm_option);
10605 return database;
10608 struct mac_display_info *
10609 mac_term_init (display_name, xrm_option, resource_name)
10610 Lisp_Object display_name;
10611 char *xrm_option;
10612 char *resource_name;
10614 struct mac_display_info *dpyinfo;
10616 BLOCK_INPUT;
10618 if (!mac_initialized)
10620 mac_initialize ();
10621 mac_initialized = 1;
10624 if (x_display_list)
10625 error ("Sorry, this version can only handle one display");
10627 mac_initialize_display_info ();
10629 dpyinfo = &one_mac_display_info;
10631 dpyinfo->xrdb = mac_make_rdb (xrm_option);
10633 /* Put this display on the chain. */
10634 dpyinfo->next = x_display_list;
10635 x_display_list = dpyinfo;
10637 /* Put it on x_display_name_list. */
10638 x_display_name_list = Fcons (Fcons (display_name,
10639 Fcons (Qnil, dpyinfo->xrdb)),
10640 x_display_name_list);
10641 dpyinfo->name_list_element = XCAR (x_display_name_list);
10643 UNBLOCK_INPUT;
10645 return dpyinfo;
10647 /* Get rid of display DPYINFO, assuming all frames are already gone. */
10649 void
10650 x_delete_display (dpyinfo)
10651 struct mac_display_info *dpyinfo;
10653 int i;
10655 /* Discard this display from x_display_name_list and x_display_list.
10656 We can't use Fdelq because that can quit. */
10657 if (! NILP (x_display_name_list)
10658 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
10659 x_display_name_list = XCDR (x_display_name_list);
10660 else
10662 Lisp_Object tail;
10664 tail = x_display_name_list;
10665 while (CONSP (tail) && CONSP (XCDR (tail)))
10667 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
10669 XSETCDR (tail, XCDR (XCDR (tail)));
10670 break;
10672 tail = XCDR (tail);
10676 if (x_display_list == dpyinfo)
10677 x_display_list = dpyinfo->next;
10678 else
10680 struct x_display_info *tail;
10682 for (tail = x_display_list; tail; tail = tail->next)
10683 if (tail->next == dpyinfo)
10684 tail->next = tail->next->next;
10687 /* Free the font names in the font table. */
10688 for (i = 0; i < dpyinfo->n_fonts; i++)
10689 if (dpyinfo->font_table[i].name)
10691 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
10692 xfree (dpyinfo->font_table[i].full_name);
10693 xfree (dpyinfo->font_table[i].name);
10696 if (dpyinfo->font_table->font_encoder)
10697 xfree (dpyinfo->font_table->font_encoder);
10699 xfree (dpyinfo->font_table);
10700 xfree (dpyinfo->mac_id_name);
10702 if (x_display_list == 0)
10704 mac_clear_font_name_table ();
10705 bzero (dpyinfo, sizeof (*dpyinfo));
10710 #ifdef MAC_OSX
10711 void
10712 mac_check_bundle()
10714 extern int inhibit_window_system;
10715 extern int noninteractive;
10716 CFBundleRef appsBundle;
10717 pid_t child;
10719 /* No need to test if already -nw*/
10720 if (inhibit_window_system || noninteractive)
10721 return;
10723 appsBundle = CFBundleGetMainBundle();
10724 if (appsBundle != NULL)
10726 CFStringRef cfBI = CFSTR("CFBundleIdentifier");
10727 CFTypeRef res = CFBundleGetValueForInfoDictionaryKey(appsBundle, cfBI);
10728 /* We found the bundle identifier, now we know we are valid. */
10729 if (res != NULL)
10731 CFRelease(res);
10732 return;
10735 /* MAC_TODO: Have this start the bundled executable */
10737 /* For now, prevent the fatal error by bringing it up in the terminal */
10738 inhibit_window_system = 1;
10741 void
10742 MakeMeTheFrontProcess ()
10744 ProcessSerialNumber psn;
10745 OSErr err;
10747 err = GetCurrentProcess (&psn);
10748 if (err == noErr)
10749 (void) SetFrontProcess (&psn);
10752 /***** Code to handle C-g testing *****/
10754 /* Contains the Mac modifier formed from quit_char */
10755 int mac_quit_char_modifiers = 0;
10756 int mac_quit_char_keycode;
10757 extern int quit_char;
10759 static void
10760 mac_determine_quit_char_modifiers()
10762 /* Todo: Determine modifiers from quit_char. */
10763 UInt32 qc_modifiers = ctrl_modifier;
10765 /* Map modifiers */
10766 mac_quit_char_modifiers = 0;
10767 if (qc_modifiers & ctrl_modifier) mac_quit_char_modifiers |= controlKey;
10768 if (qc_modifiers & shift_modifier) mac_quit_char_modifiers |= shiftKey;
10769 if (qc_modifiers & alt_modifier) mac_quit_char_modifiers |= optionKey;
10772 static void
10773 init_quit_char_handler ()
10775 /* TODO: Let this support keys other the 'g' */
10776 mac_quit_char_keycode = 5;
10777 /* Look at <architecture/adb_kb_map.h> for details */
10778 /* http://gemma.apple.com/techpubs/mac/Toolbox/Toolbox-40.html#MARKER-9-184*/
10780 mac_determine_quit_char_modifiers();
10782 #endif /* MAC_OSX */
10784 static void
10785 init_menu_bar ()
10787 #ifdef MAC_OSX
10788 OSErr err;
10789 MenuRef menu;
10790 MenuItemIndex menu_index;
10792 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
10793 &menu, &menu_index);
10794 if (err == noErr)
10795 SetMenuItemCommandKey (menu, menu_index, false, 0);
10796 #if USE_CARBON_EVENTS
10797 EnableMenuCommand (NULL, kHICommandPreferences);
10798 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
10799 &menu, &menu_index);
10800 if (err == noErr)
10802 SetMenuItemCommandKey (menu, menu_index, false, 0);
10803 InsertMenuItemTextWithCFString (menu, NULL,
10804 0, kMenuItemAttrSeparator, 0);
10805 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
10806 0, 0, kHICommandAbout);
10808 #endif /* USE_CARBON_EVENTS */
10809 #else /* !MAC_OSX */
10810 #if USE_CARBON_EVENTS
10811 SetMenuItemCommandID (GetMenuHandle (M_APPLE), I_ABOUT, kHICommandAbout);
10812 #endif
10813 #endif
10817 /* Set up use of X before we make the first connection. */
10819 extern frame_parm_handler mac_frame_parm_handlers[];
10821 static struct redisplay_interface x_redisplay_interface =
10823 mac_frame_parm_handlers,
10824 x_produce_glyphs,
10825 x_write_glyphs,
10826 x_insert_glyphs,
10827 x_clear_end_of_line,
10828 x_scroll_run,
10829 x_after_update_window_line,
10830 x_update_window_begin,
10831 x_update_window_end,
10832 x_cursor_to,
10833 x_flush,
10834 0, /* flush_display_optional */
10835 x_clear_window_mouse_face,
10836 x_get_glyph_overhangs,
10837 x_fix_overlapping_area,
10838 x_draw_fringe_bitmap,
10839 0, /* define_fringe_bitmap */
10840 0, /* destroy_fringe_bitmap */
10841 mac_per_char_metric,
10842 mac_encode_char,
10843 mac_compute_glyph_string_overhangs,
10844 x_draw_glyph_string,
10845 mac_define_frame_cursor,
10846 mac_clear_frame_area,
10847 mac_draw_window_cursor,
10848 mac_draw_vertical_window_border,
10849 mac_shift_glyphs_for_insert
10852 void
10853 mac_initialize ()
10855 rif = &x_redisplay_interface;
10857 clear_frame_hook = x_clear_frame;
10858 ins_del_lines_hook = x_ins_del_lines;
10859 delete_glyphs_hook = x_delete_glyphs;
10860 ring_bell_hook = XTring_bell;
10861 reset_terminal_modes_hook = XTreset_terminal_modes;
10862 set_terminal_modes_hook = XTset_terminal_modes;
10863 update_begin_hook = x_update_begin;
10864 update_end_hook = x_update_end;
10865 set_terminal_window_hook = XTset_terminal_window;
10866 read_socket_hook = XTread_socket;
10867 frame_up_to_date_hook = XTframe_up_to_date;
10868 mouse_position_hook = XTmouse_position;
10869 frame_rehighlight_hook = XTframe_rehighlight;
10870 frame_raise_lower_hook = XTframe_raise_lower;
10872 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
10873 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
10874 redeem_scroll_bar_hook = XTredeem_scroll_bar;
10875 judge_scroll_bars_hook = XTjudge_scroll_bars;
10877 scroll_region_ok = 1; /* we'll scroll partial frames */
10878 char_ins_del_ok = 1;
10879 line_ins_del_ok = 1; /* we'll just blt 'em */
10880 fast_clear_end_of_line = 1; /* X does this well */
10881 memory_below_frame = 0; /* we don't remember what scrolls
10882 off the bottom */
10883 baud_rate = 19200;
10885 last_tool_bar_item = -1;
10886 any_help_event_p = 0;
10888 /* Try to use interrupt input; if we can't, then start polling. */
10889 Fset_input_mode (Qt, Qnil, Qt, Qnil);
10891 BLOCK_INPUT;
10893 #if TARGET_API_MAC_CARBON
10894 init_required_apple_events ();
10896 #if USE_CARBON_EVENTS
10897 #ifdef MAC_OSX
10898 init_service_handler ();
10900 init_quit_char_handler ();
10901 #endif /* MAC_OSX */
10903 init_command_handler ();
10905 init_menu_bar ();
10906 #endif /* USE_CARBON_EVENTS */
10908 #ifdef MAC_OSX
10909 if (!inhibit_window_system)
10910 MakeMeTheFrontProcess ();
10911 #endif
10912 #endif
10913 UNBLOCK_INPUT;
10917 void
10918 syms_of_macterm ()
10920 #if 0
10921 staticpro (&x_error_message_string);
10922 x_error_message_string = Qnil;
10923 #endif
10925 Qcontrol = intern ("control"); staticpro (&Qcontrol);
10926 Qmeta = intern ("meta"); staticpro (&Qmeta);
10927 Qalt = intern ("alt"); staticpro (&Qalt);
10928 Qhyper = intern ("hyper"); staticpro (&Qhyper);
10929 Qsuper = intern ("super"); staticpro (&Qsuper);
10930 Qmodifier_value = intern ("modifier-value");
10931 staticpro (&Qmodifier_value);
10933 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
10934 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
10935 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
10936 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
10937 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
10939 Qapplication = intern ("application"); staticpro (&Qapplication);
10940 Qabout = intern ("about"); staticpro (&Qabout);
10942 #if USE_CARBON_EVENTS && defined (MAC_OSX)
10943 Qpreferences = intern ("preferences"); staticpro (&Qpreferences);
10944 Qservices = intern ("services"); staticpro (&Qservices);
10945 Qpaste = intern ("paste"); staticpro (&Qpaste);
10946 Qperform = intern ("perform"); staticpro (&Qperform);
10947 #endif
10949 #ifdef MAC_OSX
10950 Fprovide (intern ("mac-carbon"), Qnil);
10951 #endif
10953 staticpro (&Qreverse);
10954 Qreverse = intern ("reverse");
10956 staticpro (&Qmac_ready_for_drag_n_drop);
10957 Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop");
10959 staticpro (&x_display_name_list);
10960 x_display_name_list = Qnil;
10962 staticpro (&last_mouse_scroll_bar);
10963 last_mouse_scroll_bar = Qnil;
10965 staticpro (&fm_font_family_alist);
10966 fm_font_family_alist = Qnil;
10968 #if USE_ATSUI
10969 staticpro (&atsu_font_id_hash);
10970 atsu_font_id_hash = Qnil;
10971 #endif
10973 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
10974 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
10975 #ifdef USE_TOOLKIT_SCROLL_BARS
10976 Vx_toolkit_scroll_bars = Qt;
10977 #else
10978 Vx_toolkit_scroll_bars = Qnil;
10979 #endif
10981 staticpro (&last_mouse_motion_frame);
10982 last_mouse_motion_frame = Qnil;
10984 /* Variables to configure modifier key assignment. */
10986 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
10987 doc: /* Modifier key assumed when the Mac control key is pressed.
10988 The value can be `alt', `control', `hyper', or `super' for the
10989 respective modifier. The default is `control'. */);
10990 Vmac_control_modifier = Qcontrol;
10992 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
10993 doc: /* Modifier key assumed when the Mac alt/option key is pressed.
10994 The value can be `alt', `control', `hyper', or `super' for the
10995 respective modifier. If the value is nil then the key will act as the
10996 normal Mac control modifier, and the option key can be used to compose
10997 characters depending on the chosen Mac keyboard setting. */);
10998 Vmac_option_modifier = Qnil;
11000 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
11001 doc: /* Modifier key assumed when the Mac command key is pressed.
11002 The value can be `alt', `control', `hyper', or `super' for the
11003 respective modifier. The default is `meta'. */);
11004 Vmac_command_modifier = Qmeta;
11006 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
11007 doc: /* Modifier key assumed when the Mac function key is pressed.
11008 The value can be `alt', `control', `hyper', or `super' for the
11009 respective modifier. Note that remapping the function key may lead to
11010 unexpected results for some keys on non-US/GB keyboards. */);
11011 Vmac_function_modifier = Qnil;
11013 DEFVAR_LISP ("mac-emulate-three-button-mouse",
11014 &Vmac_emulate_three_button_mouse,
11015 doc: /* Specify a way of three button mouse emulation.
11016 The value can be nil, t, or the symbol `reverse'.
11017 nil means that no emulation should be done and the modifiers should be
11018 placed on the mouse-1 event.
11019 t means that when the option-key is held down while pressing the mouse
11020 button, the click will register as mouse-2 and while the command-key
11021 is held down, the click will register as mouse-3.
11022 The symbol `reverse' means that the option-key will register for
11023 mouse-3 and the command-key will register for mouse-2. */);
11024 Vmac_emulate_three_button_mouse = Qnil;
11026 #if USE_CARBON_EVENTS
11027 DEFVAR_LISP ("mac-wheel-button-is-mouse-2", &Vmac_wheel_button_is_mouse_2,
11028 doc: /* Non-nil if the wheel button is mouse-2 and the right click mouse-3.
11029 Otherwise, the right click will be treated as mouse-2 and the wheel
11030 button will be mouse-3. */);
11031 Vmac_wheel_button_is_mouse_2 = Qt;
11033 DEFVAR_LISP ("mac-pass-command-to-system", &Vmac_pass_command_to_system,
11034 doc: /* Non-nil if command key presses are passed on to the Mac Toolbox. */);
11035 Vmac_pass_command_to_system = Qt;
11037 DEFVAR_LISP ("mac-pass-control-to-system", &Vmac_pass_control_to_system,
11038 doc: /* Non-nil if control key presses are passed on to the Mac Toolbox. */);
11039 Vmac_pass_control_to_system = Qt;
11041 #endif
11043 DEFVAR_LISP ("mac-allow-anti-aliasing", &Vmac_use_core_graphics,
11044 doc: /* If non-nil, allow anti-aliasing.
11045 The text will be rendered using Core Graphics text rendering which
11046 may anti-alias the text. */);
11047 Vmac_use_core_graphics = Qnil;
11049 /* Register an entry for `mac-roman' so that it can be used when
11050 creating the terminal frame on Mac OS 9 before loading
11051 term/mac-win.elc. */
11052 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
11053 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
11054 Each entry should be of the form:
11056 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
11058 where CHARSET-NAME is a string used in font names to identify the
11059 charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
11060 CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
11061 Vmac_charset_info_alist =
11062 Fcons (list3 (build_string ("mac-roman"),
11063 make_number (smRoman), Qnil), Qnil);
11066 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
11067 (do not change this comment) */