Make "xfree (NULL)" a no-op; remove useless if-before-xfree.
[bpt/emacs.git] / src / macterm.c
CommitLineData
1a578e9b 1/* Implementation of GUI terminal on the Mac OS.
9ec0b715
GM
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
1a578e9b
AC
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
1a578e9b 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
1a578e9b
AC
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1a578e9b 19
e0f712ba 20/* Contributed by Andrew Choi (akochoi@mac.com). */
1a578e9b
AC
21
22#include <config.h>
1a578e9b 23#include <signal.h>
95dfb192 24
1a578e9b 25#include <stdio.h>
95dfb192 26
1a578e9b
AC
27#include "lisp.h"
28#include "blockinput.h"
29
1a578e9b
AC
30#include "macterm.h"
31
e0f712ba 32#ifndef MAC_OSX
1a578e9b 33#include <alloca.h>
e0f712ba 34#endif
1a578e9b 35
3354caee 36#if !TARGET_API_MAC_CARBON
1a578e9b
AC
37#include <Quickdraw.h>
38#include <ToolUtils.h>
39#include <Sound.h>
40#include <Events.h>
41#include <Script.h>
42#include <Resources.h>
43#include <Fonts.h>
44#include <TextUtils.h>
45#include <LowMem.h>
46#include <Controls.h>
bf06c82f 47#include <Windows.h>
19ee09cc 48#include <Displays.h>
e0f712ba 49#if defined (__MRC__) || (__MSL__ >= 0x6000)
1a578e9b
AC
50#include <ControlDefinitions.h>
51#endif
52
53#if __profile__
54#include <profiler.h>
55#endif
25c9622b 56#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
57
58#include "systty.h"
59#include "systime.h"
60
1a578e9b
AC
61#include <ctype.h>
62#include <errno.h>
63#include <setjmp.h>
64#include <sys/stat.h>
65
95dfb192
YM
66#include "charset.h"
67#include "coding.h"
1a578e9b
AC
68#include "frame.h"
69#include "dispextern.h"
70#include "fontset.h"
71#include "termhooks.h"
72#include "termopts.h"
73#include "termchar.h"
1a578e9b
AC
74#include "disptab.h"
75#include "buffer.h"
76#include "window.h"
95dfb192 77#include "keyboard.h"
1a578e9b 78#include "intervals.h"
95dfb192
YM
79#include "atimer.h"
80#include "keymap.h"
cc02ceee 81#include "character.h"
cc02ceee 82#include "ccl.h"
1a578e9b 83
1a578e9b 84\f
1a578e9b 85
e0f712ba 86/* Non-nil means Emacs uses toolkit scroll bars. */
1a578e9b 87
e0f712ba 88Lisp_Object Vx_toolkit_scroll_bars;
1a578e9b 89
70ed951a
YM
90/* If non-zero, the text will be rendered using Core Graphics text
91 rendering which may anti-alias the text. */
92int mac_use_core_graphics;
743d0696
ST
93
94
1a578e9b
AC
95/* Non-zero means that a HELP_EVENT has been generated since Emacs
96 start. */
97
98static int any_help_event_p;
99
7ca7ccd5
YM
100/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
101static Lisp_Object last_window;
e0f712ba 102
70ed951a
YM
103/* Non-zero means make use of UNDERLINE_POSITION font properties.
104 (Not yet supported.) */
105int x_use_underline_position_properties;
106
cf2c6835
YM
107/* Non-zero means to draw the underline at the same place as the descent line. */
108
109int x_underline_at_descent_line;
110
1a578e9b
AC
111/* This is a chain of structures for all the X displays currently in
112 use. */
113
114struct x_display_info *x_display_list;
115
116/* This is a list of cons cells, each of the form (NAME
b298e813
YM
117 FONT-LIST-CACHE . RESOURCE-DATABASE), one for each element of
118 x_display_list and in the same order. NAME is the name of the
119 frame. FONT-LIST-CACHE records previous values returned by
120 x-list-fonts. RESOURCE-DATABASE preserves the X Resource Database
121 equivalent, which is implemented with a Lisp object, for the
122 display. */
1a578e9b
AC
123
124Lisp_Object x_display_name_list;
125
126/* This is display since Mac does not support multiple ones. */
127struct mac_display_info one_mac_display_info;
128
129/* Frame being updated by update_frame. This is declared in term.c.
130 This is set by update_begin and looked at by all the XT functions.
131 It is zero while not inside an update. In that case, the XT
132 functions assume that `selected_frame' is the frame to apply to. */
133
134extern struct frame *updating_frame;
135
1a578e9b
AC
136/* This is a frame waiting to be auto-raised, within XTread_socket. */
137
138struct frame *pending_autoraise_frame;
139
1a578e9b
AC
140/* Mouse movement.
141
142 Formerly, we used PointerMotionHintMask (in standard_event_mask)
143 so that we would have to call XQueryPointer after each MotionNotify
144 event to ask for another such event. However, this made mouse tracking
145 slow, and there was a bug that made it eventually stop.
146
147 Simply asking for MotionNotify all the time seems to work better.
148
149 In order to avoid asking for motion events and then throwing most
150 of them away or busy-polling the server for mouse positions, we ask
151 the server for pointer motion hints. This means that we get only
152 one event per group of mouse movements. "Groups" are delimited by
153 other kinds of events (focus changes and button clicks, for
154 example), or by XQueryPointer calls; when one of these happens, we
155 get another MotionNotify event the next time the mouse moves. This
156 is at least as efficient as getting motion events when mouse
157 tracking is on, and I suspect only negligibly worse when tracking
158 is off. */
159
160/* Where the mouse was last time we reported a mouse event. */
161
1a578e9b 162static Rect last_mouse_glyph;
05f7d868 163static FRAME_PTR last_mouse_glyph_frame;
1a578e9b
AC
164
165/* The scroll bar in which the last X motion event occurred.
166
167 If the last X motion event occurred in a scroll bar, we set this so
168 XTmouse_position can know whether to report a scroll bar motion or
169 an ordinary motion.
170
171 If the last X motion event didn't occur in a scroll bar, we set
172 this to Qnil, to tell XTmouse_position to return an ordinary motion
173 event. */
174
175static Lisp_Object last_mouse_scroll_bar;
176
177/* This is a hack. We would really prefer that XTmouse_position would
178 return the time associated with the position it returns, but there
179 doesn't seem to be any way to wrest the time-stamp from the server
180 along with the position query. So, we just keep track of the time
181 of the last movement we received, and return that in hopes that
182 it's somewhat accurate. */
183
184static Time last_mouse_movement_time;
185
1a578e9b
AC
186struct scroll_bar *tracked_scroll_bar = NULL;
187
188/* Incremented by XTread_socket whenever it really tries to read
189 events. */
190
191#ifdef __STDC__
192static int volatile input_signal_count;
193#else
194static int input_signal_count;
195#endif
196
95dfb192 197extern Lisp_Object Vsystem_name;
1a578e9b 198
92289429
YM
199extern Lisp_Object Qeql;
200
1a578e9b
AC
201/* A mask of extra modifier bits to put into every keyboard char. */
202
95dfb192 203extern EMACS_INT extra_keyboard_modifiers;
1a578e9b 204
a36f1680
JW
205/* The keysyms to use for the various modifiers. */
206
70ed951a 207static Lisp_Object Qalt, Qhyper, Qsuper, Qcontrol, Qmeta, Qmodifier_value;
a36f1680 208
8030369c 209extern int inhibit_window_system;
1a578e9b 210
25c9622b 211#if __MRC__ && !TARGET_API_MAC_CARBON
1a578e9b
AC
212QDGlobals qd; /* QuickDraw global information structure. */
213#endif
214
95dfb192 215#define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
1a578e9b 216
1a578e9b
AC
217struct mac_display_info *mac_display_info_for_display (Display *);
218static void x_update_window_end P_ ((struct window *, int, int));
1a578e9b
AC
219int x_catch_errors P_ ((Display *));
220void x_uncatch_errors P_ ((Display *, int));
221void x_lower_frame P_ ((struct frame *));
222void x_scroll_bar_clear P_ ((struct frame *));
223int x_had_errors_p P_ ((Display *));
224void x_wm_set_size_hint P_ ((struct frame *, long, int));
225void x_raise_frame P_ ((struct frame *));
226void x_set_window_size P_ ((struct frame *, int, int, int));
227void x_wm_set_window_state P_ ((struct frame *, int));
228void x_wm_set_icon_pixmap P_ ((struct frame *, int));
80ca7302 229static void mac_initialize P_ ((void));
1a578e9b
AC
230static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
231static int x_compute_min_glyph_bounds P_ ((struct frame *));
1a578e9b
AC
232static void x_update_end P_ ((struct frame *));
233static void XTframe_up_to_date P_ ((struct frame *));
80ca7302
DN
234static void XTset_terminal_modes P_ ((struct terminal *));
235static void XTreset_terminal_modes P_ ((struct terminal *));
236static void x_clear_frame P_ ((struct frame *));
1a578e9b
AC
237static void frame_highlight P_ ((struct frame *));
238static void frame_unhighlight P_ ((struct frame *));
239static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
7ca7ccd5
YM
240static void mac_focus_changed P_ ((int, struct mac_display_info *,
241 struct frame *, struct input_event *));
242static void x_detect_focus_change P_ ((struct mac_display_info *,
369a7a37
YM
243 const EventRecord *,
244 struct input_event *));
1a578e9b
AC
245static void XTframe_rehighlight P_ ((struct frame *));
246static void x_frame_rehighlight P_ ((struct x_display_info *));
247static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
6b61353c
KH
248static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
249 enum text_cursor_kinds));
250
08f66682 251static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
1a578e9b
AC
252static void x_flush P_ ((struct frame *f));
253static void x_update_begin P_ ((struct frame *));
254static void x_update_window_begin P_ ((struct window *));
1a578e9b 255static void x_after_update_window_line P_ ((struct glyph_row *));
95dfb192
YM
256static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
257 enum scroll_bar_part *,
258 Lisp_Object *, Lisp_Object *,
259 unsigned long *));
1a578e9b 260
3354caee 261static int is_emacs_window P_ ((WindowRef));
b73e4d84 262static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int));
e4f5e019 263static void XSetFont P_ ((Display *, GC, XFontStruct *));
80ca7302
DN
264static struct terminal *mac_create_terminal P_ ((struct mac_display_info *dpyinfo));
265
1a578e9b 266
e4f5e019
YM
267#define GC_FORE_COLOR(gc) (&(gc)->fore_color)
268#define GC_BACK_COLOR(gc) (&(gc)->back_color)
269#define GC_FONT(gc) ((gc)->xgcv.font)
236072ae 270#define FRAME_NORMAL_GC(f) ((f)->output_data.mac->normal_gc)
e2d3b7e1
YM
271
272#define CG_SET_FILL_COLOR(context, color) \
4ea08bbf
YM
273 CGContextSetRGBFillColor (context, \
274 RED_FROM_ULONG (color) / 255.0f, \
275 GREEN_FROM_ULONG (color) / 255.0f, \
276 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
e2d3b7e1
YM
277#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
278#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
279#define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
280 do { \
281 if (CGColorGetTypeID != NULL) \
282 CGContextSetFillColorWithColor (context, cg_color); \
283 else \
284 CG_SET_FILL_COLOR (context, color); \
285 } while (0)
286#else
287#define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
288 CGContextSetFillColorWithColor (context, cg_color)
289#endif
290#else
291#define CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
292 CG_SET_FILL_COLOR (context, color)
293#endif
294#define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, gc) \
295 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
296 (gc)->cg_fore_color)
297#define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, gc) \
298 CG_SET_FILL_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.background, \
299 (gc)->cg_back_color)
300
301
302#define CG_SET_STROKE_COLOR(context, color) \
4ea08bbf
YM
303 CGContextSetRGBStrokeColor (context, \
304 RED_FROM_ULONG (color) / 255.0f, \
305 GREEN_FROM_ULONG (color) / 255.0f, \
306 BLUE_FROM_ULONG (color) / 255.0f, 1.0f)
e2d3b7e1
YM
307#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
308#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
309#define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
310 do { \
311 if (CGColorGetTypeID != NULL) \
312 CGContextSetStrokeColorWithColor (context, cg_color); \
313 else \
314 CG_SET_STROKE_COLOR (context, color); \
315 } while (0)
316#else
317#define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
318 CGContextSetStrokeColorWithColor (context, cg_color)
319#endif
320#else
321#define CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR(context, color, cg_color) \
322 CG_SET_STROKE_COLOR (context, color)
323#endif
324#define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, gc) \
325 CG_SET_STROKE_COLOR_MAYBE_WITH_CGCOLOR (context, (gc)->xgcv.foreground, \
326 (gc)->cg_fore_color)
327
4ea08bbf
YM
328#if USE_CG_DRAWING
329#define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
330
ad21830e
YM
331/* Fringe bitmaps. */
332
333static int max_fringe_bmp = 0;
334static CGImageRef *fringe_bmp = 0;
335
b03daa51 336CGColorSpaceRef mac_cg_color_space_rgb;
e2d3b7e1
YM
337#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
338static CGColorRef mac_cg_color_black;
339#endif
340
341static void
342init_cg_color ()
343{
344 mac_cg_color_space_rgb = CGColorSpaceCreateDeviceRGB ();
345#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
346#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
347 /* Don't check the availability of CGColorCreate; this symbol is
348 defined even in Mac OS X 10.1. */
349 if (CGColorGetTypeID != NULL)
350#endif
351 {
834263b6 352 CGFloat rgba[] = {0.0f, 0.0f, 0.0f, 1.0f};
e2d3b7e1
YM
353
354 mac_cg_color_black = CGColorCreate (mac_cg_color_space_rgb, rgba);
355 }
356#endif
357}
358
4ea08bbf
YM
359static CGContextRef
360mac_begin_cg_clip (f, gc)
361 struct frame *f;
362 GC gc;
363{
364 CGContextRef context = FRAME_CG_CONTEXT (f);
365
366 if (!context)
367 {
368 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
369 FRAME_CG_CONTEXT (f) = context;
370 }
371
372 CGContextSaveGState (context);
373 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
374 CGContextScaleCTM (context, 1, -1);
375 if (gc && gc->n_clip_rects)
376 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
377
378 return context;
379}
380
381static void
382mac_end_cg_clip (f)
383 struct frame *f;
384{
385 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
386}
387
388void
389mac_prepare_for_quickdraw (f)
390 struct frame *f;
391{
392 if (f == NULL)
393 {
394 Lisp_Object rest, frame;
395 FOR_EACH_FRAME (rest, frame)
396 if (FRAME_MAC_P (XFRAME (frame)))
397 mac_prepare_for_quickdraw (XFRAME (frame));
398 }
399 else
400 {
401 CGContextRef context = FRAME_CG_CONTEXT (f);
402
403 if (context)
404 {
405 CGContextSynchronize (context);
406 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
407 &FRAME_CG_CONTEXT (f));
408 }
409 }
410}
411#endif
e4f5e019 412
1c4ac540
YM
413static RgnHandle saved_port_clip_region = NULL;
414
415static void
7adf3143
YM
416mac_begin_clip (f, gc)
417 struct frame *f;
b6e3efe0 418 GC gc;
1c4ac540
YM
419{
420 static RgnHandle new_region = NULL;
421
422 if (saved_port_clip_region == NULL)
423 saved_port_clip_region = NewRgn ();
424 if (new_region == NULL)
425 new_region = NewRgn ();
426
7adf3143
YM
427#if USE_CG_DRAWING
428 mac_prepare_for_quickdraw (f);
429#endif
430 SetPortWindowPort (FRAME_MAC_WINDOW (f));
431
b6e3efe0 432 if (gc->n_clip_rects)
1c4ac540
YM
433 {
434 GetClip (saved_port_clip_region);
b6e3efe0 435 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
1c4ac540
YM
436 SetClip (new_region);
437 }
438}
439
440static void
b6e3efe0
YM
441mac_end_clip (gc)
442 GC gc;
1c4ac540 443{
b6e3efe0 444 if (gc->n_clip_rects)
1c4ac540
YM
445 SetClip (saved_port_clip_region);
446}
447
e4f5e019 448
1a578e9b
AC
449/* X display function emulation */
450
1a578e9b
AC
451/* Mac version of XDrawLine. */
452
453static void
236072ae
YM
454mac_draw_line (f, gc, x1, y1, x2, y2)
455 struct frame *f;
1a578e9b
AC
456 GC gc;
457 int x1, y1, x2, y2;
458{
4ea08bbf
YM
459#if USE_CG_DRAWING
460 CGContextRef context;
834263b6 461 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
458dbb8c
YM
462
463 if (y1 != y2)
464 gx1 += 0.5f, gx2 += 0.5f;
465 if (x1 != x2)
466 gy1 += 0.5f, gy2 += 0.5f;
4ea08bbf
YM
467
468 context = mac_begin_cg_clip (f, gc);
e2d3b7e1 469 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
4ea08bbf 470 CGContextBeginPath (context);
458dbb8c
YM
471 CGContextMoveToPoint (context, gx1, gy1);
472 CGContextAddLineToPoint (context, gx2, gy2);
4ea08bbf
YM
473 CGContextClosePath (context);
474 CGContextStrokePath (context);
475 mac_end_cg_clip (f);
476#else
458dbb8c
YM
477 if (x1 == x2)
478 {
479 if (y1 > y2)
480 y1--;
481 else if (y2 > y1)
482 y2--;
483 }
484 else if (y1 == y2)
485 {
486 if (x1 > x2)
487 x1--;
488 else
489 x2--;
490 }
491
7adf3143 492 mac_begin_clip (f, gc);
e4f5e019 493 RGBForeColor (GC_FORE_COLOR (gc));
1a578e9b
AC
494 MoveTo (x1, y1);
495 LineTo (x2, y2);
b6e3efe0 496 mac_end_clip (gc);
4ea08bbf 497#endif
1a578e9b
AC
498}
499
a84cad70
YM
500/* Mac version of XDrawLine (to Pixmap). */
501
6b61353c 502void
a84cad70 503XDrawLine (display, p, gc, x1, y1, x2, y2)
6b61353c
KH
504 Display *display;
505 Pixmap p;
506 GC gc;
507 int x1, y1, x2, y2;
508{
b03daa51
YM
509#if USE_MAC_IMAGE_IO
510 CGContextRef context;
511 XImagePtr ximg = p;
512 CGColorSpaceRef color_space;
513 CGImageAlphaInfo alpha_info;
514 CGFloat gx1 = x1, gy1 = y1, gx2 = x2, gy2 = y2;
515
516 if (y1 != y2)
517 gx1 += 0.5f, gx2 += 0.5f;
518 if (x1 != x2)
519 gy1 += 0.5f, gy2 += 0.5f;
520
521 if (ximg->bits_per_pixel == 32)
522 {
523 color_space = mac_cg_color_space_rgb;
0e9378b3
YM
524 alpha_info = (kCGImageAlphaNoneSkipFirst
525#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
526 | kCGBitmapByteOrder32Host
527#endif
528 );
b03daa51
YM
529 }
530 else
531 {
532 color_space = NULL;
533 alpha_info = kCGImageAlphaOnly;
534 }
535 if (color_space == NULL)
536 return;
537 context = CGBitmapContextCreate (ximg->data, ximg->width,
538 ximg->height, 8,
539 ximg->bytes_per_line, color_space,
540 alpha_info);
541 if (ximg->bits_per_pixel == 32)
542 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
543 else
544 CGContextSetGrayStrokeColor (context, gc->xgcv.foreground / 255.0f, 1.0);
545 CGContextMoveToPoint (context, gx1, gy1);
546 CGContextAddLineToPoint (context, gx2, gy2);
547 CGContextClosePath (context);
548 CGContextStrokePath (context);
549 CGContextRelease (context);
550#else
2a316a84
ST
551 CGrafPtr old_port;
552 GDHandle old_gdh;
553
458dbb8c
YM
554 if (x1 == x2)
555 {
556 if (y1 > y2)
557 y1--;
558 else if (y2 > y1)
559 y2--;
560 }
561 else if (y1 == y2)
562 {
563 if (x1 > x2)
564 x1--;
565 else
566 x2--;
567 }
568
2a316a84 569 GetGWorld (&old_port, &old_gdh);
6b61353c
KH
570 SetGWorld (p, NULL);
571
e4f5e019 572 RGBForeColor (GC_FORE_COLOR (gc));
6b61353c
KH
573
574 LockPixels (GetGWorldPixMap (p));
575 MoveTo (x1, y1);
576 LineTo (x2, y2);
577 UnlockPixels (GetGWorldPixMap (p));
2a316a84
ST
578
579 SetGWorld (old_port, old_gdh);
b03daa51 580#endif
6b61353c
KH
581}
582
1a578e9b 583
e4f5e019 584static void
236072ae
YM
585mac_erase_rectangle (f, gc, x, y, width, height)
586 struct frame *f;
e4f5e019 587 GC gc;
1a578e9b
AC
588 int x, y;
589 unsigned int width, height;
1a578e9b 590{
4ea08bbf 591#if USE_CG_DRAWING
7adf3143
YM
592 {
593 CGContextRef context;
4ea08bbf 594
7adf3143
YM
595 context = mac_begin_cg_clip (f, gc);
596 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
834263b6 597 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
7adf3143
YM
598 mac_end_cg_clip (f);
599 }
4ea08bbf 600#else
7adf3143
YM
601 {
602 Rect r;
b69efa23 603
7adf3143
YM
604 mac_begin_clip (f, gc);
605 RGBBackColor (GC_BACK_COLOR (gc));
606 SetRect (&r, x, y, x + width, y + height);
607 EraseRect (&r);
608 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
609 mac_end_clip (gc);
610 }
4ea08bbf 611#endif
e4f5e019
YM
612}
613
614
615/* Mac version of XClearArea. */
616
617void
236072ae
YM
618mac_clear_area (f, x, y, width, height)
619 struct frame *f;
e4f5e019
YM
620 int x, y;
621 unsigned int width, height;
e4f5e019 622{
236072ae 623 mac_erase_rectangle (f, FRAME_NORMAL_GC (f), x, y, width, height);
1a578e9b
AC
624}
625
626/* Mac version of XClearWindow. */
627
628static void
236072ae
YM
629mac_clear_window (f)
630 struct frame *f;
1a578e9b 631{
4ea08bbf 632#if USE_CG_DRAWING
7adf3143
YM
633 {
634 CGContextRef context;
635 GC gc = FRAME_NORMAL_GC (f);
636
637 context = mac_begin_cg_clip (f, NULL);
638 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
639 CGContextFillRect (context, CGRectMake (0, 0, FRAME_PIXEL_WIDTH (f),
640 FRAME_PIXEL_HEIGHT (f)));
641 mac_end_cg_clip (f);
642 }
643#else /* !USE_CG_DRAWING */
236072ae 644 SetPortWindowPort (FRAME_MAC_WINDOW (f));
e0f712ba 645
236072ae 646 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1a578e9b 647
e0f712ba
AC
648#if TARGET_API_MAC_CARBON
649 {
650 Rect r;
177c0ea7 651
236072ae 652 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
e0f712ba
AC
653 EraseRect (&r);
654 }
655#else /* not TARGET_API_MAC_CARBON */
236072ae 656 EraseRect (&(FRAME_MAC_WINDOW (f)->portRect));
e0f712ba 657#endif /* not TARGET_API_MAC_CARBON */
4ea08bbf 658#endif
1a578e9b
AC
659}
660
661
662/* Mac replacement for XCopyArea. */
663
ad21830e
YM
664#if USE_CG_DRAWING
665static void
666mac_draw_cg_image (image, f, gc, src_x, src_y, width, height,
667 dest_x, dest_y, overlay_p)
668 CGImageRef image;
669 struct frame *f;
670 GC gc;
671 int src_x, src_y;
672 unsigned int width, height;
673 int dest_x, dest_y, overlay_p;
674{
675 CGContextRef context;
834263b6
YM
676 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
677 CGRect dest_rect = mac_rect_make (f, dest_x, dest_y, width, height);
ad21830e
YM
678
679 context = mac_begin_cg_clip (f, gc);
680 if (!overlay_p)
681 {
e2d3b7e1 682 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
ad21830e
YM
683 CGContextFillRect (context, dest_rect);
684 }
685 CGContextClipToRect (context, dest_rect);
686 CGContextScaleCTM (context, 1, -1);
687 CGContextTranslateCTM (context, 0, -port_height);
688 if (CGImageIsMask (image))
e2d3b7e1 689 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
ad21830e 690 CGContextDrawImage (context,
834263b6
YM
691 mac_rect_make (f, dest_x - src_x,
692 port_height - (dest_y - src_y
693 + CGImageGetHeight (image)),
694 CGImageGetWidth (image),
695 CGImageGetHeight (image)),
ad21830e
YM
696 image);
697 mac_end_cg_clip (f);
698}
699
700#else /* !USE_CG_DRAWING */
701
1a578e9b 702static void
236072ae
YM
703mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p)
704 struct frame *f;
1a578e9b 705 GC gc;
6b61353c
KH
706 int x, y, width, height;
707 unsigned short *bits;
708 int overlay_p;
1a578e9b 709{
6b61353c 710 BitMap bitmap;
1a578e9b
AC
711 Rect r;
712
6b61353c
KH
713 bitmap.rowBytes = sizeof(unsigned short);
714 bitmap.baseAddr = (char *)bits;
715 SetRect (&(bitmap.bounds), 0, 0, width, height);
716
7adf3143 717 mac_begin_clip (f, gc);
e4f5e019
YM
718 RGBForeColor (GC_FORE_COLOR (gc));
719 RGBBackColor (GC_BACK_COLOR (gc));
6b61353c 720 SetRect (&r, x, y, x + width, y + height);
e0f712ba 721#if TARGET_API_MAC_CARBON
236072ae
YM
722 {
723 CGrafPtr port;
724
725 GetPort (&port);
726 LockPortBits (port);
727 CopyBits (&bitmap, GetPortBitMapForCopyBits (port),
728 &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0);
729 UnlockPortBits (port);
730 }
e0f712ba 731#else /* not TARGET_API_MAC_CARBON */
236072ae 732 CopyBits (&bitmap, &(FRAME_MAC_WINDOW (f)->portBits), &(bitmap.bounds), &r,
6b61353c 733 overlay_p ? srcOr : srcCopy, 0);
e0f712ba 734#endif /* not TARGET_API_MAC_CARBON */
236072ae 735 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143 736 mac_end_clip (gc);
1a578e9b 737}
ad21830e 738#endif /* !USE_CG_DRAWING */
1a578e9b
AC
739
740
1a578e9b
AC
741/* Mac replacement for XCreateBitmapFromBitmapData. */
742
743static void
744mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
745 BitMap *bitmap;
746 char *bits;
747 int w, h;
748{
369a7a37 749 static const unsigned char swap_nibble[16]
30c92fab
ST
750 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
751 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
752 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
753 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
6b61353c
KH
754 int i, j, w1;
755 char *p;
1a578e9b 756
6b61353c
KH
757 w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */
758 bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */
1a578e9b 759 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
1a578e9b
AC
760 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
761 for (i = 0; i < h; i++)
6b61353c
KH
762 {
763 p = bitmap->baseAddr + i * bitmap->rowBytes;
764 for (j = 0; j < w1; j++)
30c92fab
ST
765 {
766 /* Bitswap XBM bytes to match how Mac does things. */
767 unsigned char c = *bits++;
768 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
3b8c0c70 769 | (swap_nibble[(c>>4) & 0xf]));
30c92fab 770 }
6b61353c 771 }
1a578e9b
AC
772
773 SetRect (&(bitmap->bounds), 0, 0, w, h);
774}
775
776
777static void
778mac_free_bitmap (bitmap)
779 BitMap *bitmap;
780{
781 xfree (bitmap->baseAddr);
782}
783
6b61353c
KH
784
785Pixmap
786XCreatePixmap (display, w, width, height, depth)
7adf3143 787 Display *display;
834263b6 788 Window w;
6b61353c 789 unsigned int width, height;
fc7a70cc 790 unsigned int depth;
6b61353c 791{
b03daa51
YM
792#if USE_MAC_IMAGE_IO
793 XImagePtr ximg;
794
795 ximg = xmalloc (sizeof (*ximg));
796 ximg->width = width;
797 ximg->height = height;
798 ximg->bits_per_pixel = depth == 1 ? 8 : 32;
799 ximg->bytes_per_line = width * (ximg->bits_per_pixel / 8);
800 ximg->data = xmalloc (ximg->bytes_per_line * height);
801 return ximg;
802#else
6b61353c
KH
803 Pixmap pixmap;
804 Rect r;
805 QDErr err;
806
834263b6 807#ifdef MAC_OS8
50bf7673 808 SetPortWindowPort (w);
834263b6 809#endif
6b61353c 810 SetRect (&r, 0, 0, width, height);
e09ce637
YM
811#if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
812 if (depth == 1)
813#endif
814 err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0);
815#if !defined (WORDS_BIG_ENDIAN) && USE_CG_DRAWING
816 else
817 /* CreateCGImageFromPixMaps requires ARGB format. */
818 err = QTNewGWorld (&pixmap, k32ARGBPixelFormat, &r, NULL, NULL, 0);
819#endif
6b61353c
KH
820 if (err != noErr)
821 return NULL;
822 return pixmap;
b03daa51 823#endif
6b61353c
KH
824}
825
826
827Pixmap
828XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth)
7adf3143 829 Display *display;
834263b6 830 Window w;
6b61353c
KH
831 char *data;
832 unsigned int width, height;
833 unsigned long fg, bg;
e4f5e019 834 unsigned int depth;
6b61353c
KH
835{
836 Pixmap pixmap;
837 BitMap bitmap;
b03daa51
YM
838#if USE_MAC_IMAGE_IO
839 CGDataProviderRef provider;
840 CGImageRef image_mask;
841 CGContextRef context;
842
843 pixmap = XCreatePixmap (display, w, width, height, depth);
844 if (pixmap == NULL)
845 return NULL;
846
847 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
848 provider = CGDataProviderCreateWithData (NULL, bitmap.baseAddr,
849 bitmap.rowBytes * height, NULL);
850 image_mask = CGImageMaskCreate (width, height, 1, 1, bitmap.rowBytes,
851 provider, NULL, 0);
852 CGDataProviderRelease (provider);
853
854 context = CGBitmapContextCreate (pixmap->data, width, height, 8,
855 pixmap->bytes_per_line,
856 mac_cg_color_space_rgb,
0e9378b3
YM
857 kCGImageAlphaNoneSkipFirst
858#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
859 | kCGBitmapByteOrder32Host
860#endif
861 );
b03daa51
YM
862
863 CG_SET_FILL_COLOR (context, fg);
864 CGContextFillRect (context, CGRectMake (0, 0, width, height));
865 CG_SET_FILL_COLOR (context, bg);
866 CGContextDrawImage (context, CGRectMake (0, 0, width, height), image_mask);
867 CGContextRelease (context);
868 CGImageRelease (image_mask);
869#else
2a316a84
ST
870 CGrafPtr old_port;
871 GDHandle old_gdh;
7adf3143 872 static GC gc = NULL;
e4f5e019
YM
873
874 if (gc == NULL)
875 gc = XCreateGC (display, w, 0, NULL);
6b61353c
KH
876
877 pixmap = XCreatePixmap (display, w, width, height, depth);
878 if (pixmap == NULL)
879 return NULL;
880
2a316a84 881 GetGWorld (&old_port, &old_gdh);
6b61353c
KH
882 SetGWorld (pixmap, NULL);
883 mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height);
e4f5e019
YM
884 XSetForeground (display, gc, fg);
885 XSetBackground (display, gc, bg);
886 RGBForeColor (GC_FORE_COLOR (gc));
887 RGBBackColor (GC_BACK_COLOR (gc));
6b61353c
KH
888 LockPixels (GetGWorldPixMap (pixmap));
889#if TARGET_API_MAC_CARBON
890 CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap),
891 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
892#else /* not TARGET_API_MAC_CARBON */
893 CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits),
894 &bitmap.bounds, &bitmap.bounds, srcCopy, 0);
895#endif /* not TARGET_API_MAC_CARBON */
896 UnlockPixels (GetGWorldPixMap (pixmap));
2a316a84 897 SetGWorld (old_port, old_gdh);
b03daa51 898#endif
6b61353c
KH
899 mac_free_bitmap (&bitmap);
900
901 return pixmap;
902}
903
904
7adf3143
YM
905void
906XFreePixmap (display, pixmap)
907 Display *display;
908 Pixmap pixmap;
909{
b03daa51
YM
910#if USE_MAC_IMAGE_IO
911 if (pixmap)
912 {
70fdbb46 913 xfree (pixmap->data);
b03daa51
YM
914 xfree (pixmap);
915 }
916#else
7adf3143 917 DisposeGWorld (pixmap);
b03daa51 918#endif
7adf3143
YM
919}
920
921
1a578e9b
AC
922/* Mac replacement for XFillRectangle. */
923
924static void
236072ae
YM
925mac_fill_rectangle (f, gc, x, y, width, height)
926 struct frame *f;
1a578e9b
AC
927 GC gc;
928 int x, y;
929 unsigned int width, height;
930{
4ea08bbf
YM
931#if USE_CG_DRAWING
932 CGContextRef context;
933
934 context = mac_begin_cg_clip (f, gc);
e2d3b7e1 935 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
834263b6 936 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
4ea08bbf
YM
937 mac_end_cg_clip (f);
938#else
1a578e9b
AC
939 Rect r;
940
7adf3143 941 mac_begin_clip (f, gc);
e4f5e019 942 RGBForeColor (GC_FORE_COLOR (gc));
1a578e9b 943 SetRect (&r, x, y, x + width, y + height);
1a578e9b 944 PaintRect (&r); /* using foreground color of gc */
b6e3efe0 945 mac_end_clip (gc);
4ea08bbf 946#endif
1a578e9b
AC
947}
948
949
950/* Mac replacement for XDrawRectangle: dest is a window. */
951
952static void
236072ae
YM
953mac_draw_rectangle (f, gc, x, y, width, height)
954 struct frame *f;
1a578e9b
AC
955 GC gc;
956 int x, y;
957 unsigned int width, height;
958{
4ea08bbf
YM
959#if USE_CG_DRAWING
960 CGContextRef context;
961
962 context = mac_begin_cg_clip (f, gc);
e2d3b7e1 963 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
4ea08bbf
YM
964 CGContextStrokeRect (context,
965 CGRectMake (x + 0.5f, y + 0.5f, width, height));
966 mac_end_cg_clip (f);
967#else
1a578e9b
AC
968 Rect r;
969
7adf3143 970 mac_begin_clip (f, gc);
e4f5e019 971 RGBForeColor (GC_FORE_COLOR (gc));
1a578e9b 972 SetRect (&r, x, y, x + width + 1, y + height + 1);
1a578e9b 973 FrameRect (&r); /* using foreground color of gc */
b6e3efe0 974 mac_end_clip (gc);
4ea08bbf 975#endif
1a578e9b
AC
976}
977
978
7adf3143
YM
979static void
980mac_invert_rectangle (f, x, y, width, height)
981 struct frame *f;
982 int x, y;
983 unsigned int width, height;
984{
834263b6
YM
985#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
986#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
987 if (CGContextSetBlendMode != NULL)
988#endif
989 {
990 CGContextRef context;
660425fa 991
834263b6
YM
992 context = mac_begin_cg_clip (f, NULL);
993 CGContextSetRGBFillColor (context, 1.0f, 1.0f, 1.0f, 1.0f);
994 CGContextSetBlendMode (context, kCGBlendModeDifference);
995 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
996 mac_end_cg_clip (f);
997 }
998#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
999 else /* CGContextSetBlendMode == NULL */
1000#endif
1001#endif /* USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 */
1002#if !USE_CG_DRAWING || MAC_OS_X_VERSION_MAX_ALLOWED < 1040 || (MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020)
1003 {
1004 Rect r;
7adf3143
YM
1005
1006#if USE_CG_DRAWING
1007 mac_prepare_for_quickdraw (f);
1008#endif
1009 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1010
1011 SetRect (&r, x, y, x + width, y + height);
1012
1013 InvertRect (&r);
1014}
1015
1016
c3bd8190
YM
1017#if USE_ATSUI
1018static OSStatus
1019atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
1020 ConstUniCharArrayPtr text;
1021 UniCharCount text_length;
1022 ATSUStyle style;
1023 ATSUTextLayout *text_layout;
1024{
1025 OSStatus err;
7adf3143 1026 static ATSUTextLayout saved_text_layout = NULL;
c3bd8190
YM
1027
1028 if (saved_text_layout == NULL)
1029 {
369a7a37
YM
1030 static const UniCharCount lengths[] = {kATSUToTextEnd};
1031 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
1032 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
c3bd8190
YM
1033 static ATSLineLayoutOptions line_layout =
1034#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
6a0b5d37 1035 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
3e16e799 1036 | kATSLineUseQDRendering
c3bd8190 1037#else
1c4ac540 1038 kATSLineIsDisplayOnly | kATSLineFractDisable
c3bd8190
YM
1039#endif
1040 ;
369a7a37 1041 static const ATSUAttributeValuePtr values[] = {&line_layout};
c3bd8190
YM
1042
1043 err = ATSUCreateTextLayoutWithTextPtr (text,
1044 kATSUFromTextBeginning,
1045 kATSUToTextEnd,
1046 text_length,
1047 1, lengths, &style,
1048 &saved_text_layout);
1049 if (err == noErr)
1050 err = ATSUSetLayoutControls (saved_text_layout,
1051 sizeof (tags) / sizeof (tags[0]),
1052 tags, sizes, values);
c3bd8190
YM
1053 if (err == noErr)
1054 err = ATSUSetTransientFontMatching (saved_text_layout, true);
1055 }
1056 else
1057 {
1058 err = ATSUSetRunStyle (saved_text_layout, style,
1059 kATSUFromTextBeginning, kATSUToTextEnd);
1060 if (err == noErr)
1061 err = ATSUSetTextPointerLocation (saved_text_layout, text,
1062 kATSUFromTextBeginning,
1063 kATSUToTextEnd,
1064 text_length);
1065 }
1066
1067 if (err == noErr)
1068 *text_layout = saved_text_layout;
1069 return err;
1070}
d4a8455b
YM
1071
1072
1a578e9b 1073static void
7adf3143
YM
1074mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1075 overstrike_p, bytes_per_char)
236072ae 1076 struct frame *f;
1a578e9b
AC
1077 GC gc;
1078 int x, y;
1079 char *buf;
bb420759 1080 int nchars, bg_width, overstrike_p, bytes_per_char;
1a578e9b 1081{
7adf3143
YM
1082 OSStatus err;
1083 ATSUTextLayout text_layout;
c3bd8190 1084
7adf3143 1085 xassert (bytes_per_char == 2);
c3bd8190
YM
1086
1087#ifndef WORDS_BIG_ENDIAN
7adf3143
YM
1088 {
1089 int i;
1090 UniChar *text = (UniChar *)buf;
c3bd8190 1091
7adf3143
YM
1092 for (i = 0; i < nchars; i++)
1093 text[i] = EndianU16_BtoN (text[i]);
1094 }
c3bd8190 1095#endif
7adf3143
YM
1096 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
1097 nchars,
1098 GC_FONT (gc)->mac_style,
1099 &text_layout);
1100 if (err != noErr)
1101 return;
c3bd8190 1102#ifdef MAC_OSX
7adf3143
YM
1103 if (!mac_use_core_graphics)
1104 {
c3bd8190 1105#endif
7adf3143
YM
1106 mac_begin_clip (f, gc);
1107 RGBForeColor (GC_FORE_COLOR (gc));
1108 if (bg_width)
1109 {
1110 Rect r;
9fb446e3 1111
7adf3143
YM
1112 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1113 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1114 RGBBackColor (GC_BACK_COLOR (gc));
1115 EraseRect (&r);
1116 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1117 }
1118 MoveTo (x, y);
1119 ATSUDrawText (text_layout,
1120 kATSUFromTextBeginning, kATSUToTextEnd,
1121 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1122 if (overstrike_p)
1123 {
1124 MoveTo (x + 1, y);
9fb446e3
YM
1125 ATSUDrawText (text_layout,
1126 kATSUFromTextBeginning, kATSUToTextEnd,
1127 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
9fb446e3 1128 }
7adf3143
YM
1129 mac_end_clip (gc);
1130#ifdef MAC_OSX
1131 }
1132 else
1133 {
1134 static CGContextRef context;
834263b6 1135 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
7adf3143
YM
1136 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1137 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1138 static const ATSUAttributeValuePtr values[] = {&context};
9fb446e3 1139
4ea08bbf 1140#if USE_CG_DRAWING
7adf3143 1141 context = mac_begin_cg_clip (f, gc);
4ea08bbf 1142#else
7adf3143
YM
1143 CGrafPtr port;
1144
1145 GetPort (&port);
1146 QDBeginCGContext (port, &context);
1147 if (gc->n_clip_rects || bg_width)
1148 {
1149 CGContextTranslateCTM (context, 0, port_height);
1150 CGContextScaleCTM (context, 1, -1);
1151 if (gc->n_clip_rects)
1152 CGContextClipToRects (context, gc->clip_rects,
1153 gc->n_clip_rects);
4ea08bbf 1154#endif
7adf3143 1155 if (bg_width)
bb420759 1156 {
7adf3143
YM
1157 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1158 CGContextFillRect (context,
834263b6
YM
1159 mac_rect_make (f,
1160 x, y - FONT_BASE (GC_FONT (gc)),
1161 bg_width,
1162 FONT_HEIGHT (GC_FONT (gc))));
bb420759 1163 }
7adf3143
YM
1164 CGContextScaleCTM (context, 1, -1);
1165 CGContextTranslateCTM (context, 0, -port_height);
1166#if !USE_CG_DRAWING
1167 }
1168#endif
1169 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1170 err = ATSUSetLayoutControls (text_layout,
1171 sizeof (tags) / sizeof (tags[0]),
1172 tags, sizes, values);
1173 if (err == noErr)
1174 {
1175 ATSUDrawText (text_layout,
1176 kATSUFromTextBeginning, kATSUToTextEnd,
1177 Long2Fix (x), Long2Fix (port_height - y));
1178 if (overstrike_p)
1179 ATSUDrawText (text_layout,
1180 kATSUFromTextBeginning, kATSUToTextEnd,
1181 Long2Fix (x + 1), Long2Fix (port_height - y));
1182 }
4ea08bbf 1183#if USE_CG_DRAWING
7adf3143
YM
1184 mac_end_cg_clip (f);
1185 context = NULL;
4ea08bbf 1186#else
7adf3143
YM
1187 CGContextSynchronize (context);
1188 QDEndCGContext (port, &context);
4ea08bbf 1189#endif
9fb446e3 1190#if 0
7adf3143
YM
1191 /* This doesn't work on Mac OS X 10.1. */
1192 ATSUClearLayoutControls (text_layout,
1193 sizeof (tags) / sizeof (tags[0]), tags);
05f7d868 1194#else
7adf3143
YM
1195 ATSUSetLayoutControls (text_layout,
1196 sizeof (tags) / sizeof (tags[0]),
1197 tags, sizes, values);
c3bd8190 1198#endif
c3bd8190 1199 }
7adf3143
YM
1200#endif /* MAC_OSX */
1201}
9fb446e3 1202#endif /* USE_ATSUI */
9fb446e3 1203
7adf3143
YM
1204
1205static void
1206mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1207 overstrike_p, bytes_per_char)
1208 struct frame *f;
1209 GC gc;
1210 int x, y;
1211 char *buf;
1212 int nchars, bg_width, overstrike_p, bytes_per_char;
1213{
1214#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1215 UInt32 savedFlags;
4ea08bbf 1216#endif
7adf3143
YM
1217
1218 mac_begin_clip (f, gc);
1219#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1220 if (mac_use_core_graphics)
1221 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
c3bd8190 1222#endif
7adf3143 1223 RGBForeColor (GC_FORE_COLOR (gc));
9fb446e3 1224#ifdef MAC_OS8
7adf3143
YM
1225 if (bg_width)
1226 {
1227 RGBBackColor (GC_BACK_COLOR (gc));
1228 TextMode (srcCopy);
1229 }
1230 else
1231 TextMode (srcOr);
9fb446e3 1232#else
7adf3143
YM
1233 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1234 because:
1235 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1236 into an offscreen graphics world first. So performance gain
1237 cannot be expected.)
1238 - It lowers rendering quality.
1239 - Some fonts leave garbage on cursor movement. */
1240 if (bg_width)
1241 {
1242 Rect r;
1a578e9b 1243
7adf3143
YM
1244 RGBBackColor (GC_BACK_COLOR (gc));
1245 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1246 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1247 EraseRect (&r);
1248 }
1249 TextMode (srcOr);
c3bd8190 1250#endif
7adf3143
YM
1251 TextFont (GC_FONT (gc)->mac_fontnum);
1252 TextSize (GC_FONT (gc)->mac_fontsize);
1253 TextFace (GC_FONT (gc)->mac_fontface);
1254 MoveTo (x, y);
1255 DrawText (buf, 0, nchars * bytes_per_char);
1256 if (overstrike_p)
1257 {
1258 TextMode (srcOr);
1259 MoveTo (x + 1, y);
9fb446e3 1260 DrawText (buf, 0, nchars * bytes_per_char);
7adf3143
YM
1261 }
1262 if (bg_width)
1263 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1264 mac_end_clip (gc);
b69efa23 1265
e9859e26 1266#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
7adf3143
YM
1267 if (mac_use_core_graphics)
1268 SwapQDTextFlags(savedFlags);
743d0696 1269#endif
7adf3143
YM
1270}
1271
1272
1273static INLINE void
1274mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1275 overstrike_p, bytes_per_char)
1276 struct frame *f;
1277 GC gc;
1278 int x, y;
1279 char *buf;
1280 int nchars, bg_width, overstrike_p, bytes_per_char;
1281{
1282#if USE_ATSUI
1283 if (GC_FONT (gc)->mac_style)
1284 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1285 overstrike_p, bytes_per_char);
1286 else
1287#endif /* USE_ATSUI */
1288 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1289 overstrike_p, bytes_per_char);
1a578e9b
AC
1290}
1291
1292
1a578e9b
AC
1293/* Mac replacement for XDrawImageString. */
1294
1295static void
bb420759 1296mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
236072ae 1297 struct frame *f;
1a578e9b
AC
1298 GC gc;
1299 int x, y;
1300 char *buf;
bb420759 1301 int nchars, bg_width, overstrike_p;
1a578e9b 1302{
bb420759
YM
1303 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1304 overstrike_p, 1);
1a578e9b
AC
1305}
1306
1307
bb420759 1308/* Mac replacement for XDrawImageString16. */
1a578e9b
AC
1309
1310static void
bb420759 1311mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
236072ae 1312 struct frame *f;
1a578e9b
AC
1313 GC gc;
1314 int x, y;
1315 XChar2b *buf;
bb420759 1316 int nchars, bg_width, overstrike_p;
1a578e9b 1317{
bb420759
YM
1318 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1319 overstrike_p, 2);
1a578e9b
AC
1320}
1321
1322
b73e4d84
YM
1323/* Mac replacement for XQueryTextExtents, but takes a character. If
1324 STYLE is NULL, measurement is done by QuickDraw Text routines for
1325 the font of the current graphics port. If CG_GLYPH is not NULL,
1326 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1327
3e7424f7 1328static OSStatus
b73e4d84
YM
1329mac_query_char_extents (style, c,
1330 font_ascent_return, font_descent_return,
1331 overall_return, cg_glyph)
1332#if USE_ATSUI
1333 ATSUStyle style;
1334#else
1335 void *style;
1336#endif
1337 int c;
1338 int *font_ascent_return, *font_descent_return;
1339 XCharStruct *overall_return;
16805b2e 1340#if USE_CG_TEXT_DRAWING
b73e4d84
YM
1341 CGGlyph *cg_glyph;
1342#else
1343 void *cg_glyph;
1344#endif
1345{
3e7424f7 1346 OSStatus err = noErr;
b73e4d84
YM
1347 int width;
1348 Rect char_bounds;
1349
1350#if USE_ATSUI
1351 if (style)
1352 {
1353 ATSUTextLayout text_layout;
1354 UniChar ch = c;
1355
1356 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
0d36bf23
YM
1357 if (err == noErr
1358 && (font_ascent_return || font_descent_return || overall_return))
b73e4d84
YM
1359 {
1360 ATSTrapezoid glyph_bounds;
16805b2e 1361
b73e4d84
YM
1362 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1363 kATSUFromTextBeginning, kATSUToTextEnd,
1364#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1365 kATSUseFractionalOrigins,
1366#else
1367 kATSUseDeviceOrigins,
1368#endif
1369 1, &glyph_bounds, NULL);
1370 if (err == noErr)
1371 {
1372 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1373 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1374
1375 width = Fix2Long (glyph_bounds.upperRight.x
1376 - glyph_bounds.upperLeft.x);
1377 if (font_ascent_return)
1378 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1379 if (font_descent_return)
1380 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1381 }
1382 }
1383 if (err == noErr && overall_return)
1384 {
1385 err = ATSUMeasureTextImage (text_layout,
1386 kATSUFromTextBeginning, kATSUToTextEnd,
1387 0, 0, &char_bounds);
1388 if (err == noErr)
1389 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1390#if USE_CG_TEXT_DRAWING
1391 if (err == noErr && cg_glyph)
1392 {
3e7424f7 1393 OSStatus err1;
b73e4d84
YM
1394 ATSUGlyphInfoArray glyph_info_array;
1395 ByteCount count = sizeof (ATSUGlyphInfoArray);
1396
1397 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1398 kATSUToTextEnd, NULL, NULL, NULL);
1399 if (err1 == noErr)
1400 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1401 kATSUToTextEnd, &count,
1402 &glyph_info_array);
7c682cf1
YM
1403 if (err1 == noErr
1404 /* Make sure that we don't have to make layout
1405 adjustments. */
1406 && glyph_info_array.glyphs[0].deltaY == 0.0f
1407 && glyph_info_array.glyphs[0].idealX == 0.0f
1408 && glyph_info_array.glyphs[0].screenX == 0)
b73e4d84
YM
1409 {
1410 xassert (glyph_info_array.glyphs[0].glyphID);
1411 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1412 }
1413 else
1414 *cg_glyph = 0;
1415 }
1416#endif
1417 }
1418 }
1419 else
1420#endif
1421 {
1422 if (font_ascent_return || font_descent_return)
1423 {
1424 FontInfo font_info;
1425
1426 GetFontInfo (&font_info);
1427 if (font_ascent_return)
1428 *font_ascent_return = font_info.ascent;
1429 if (font_descent_return)
1430 *font_descent_return = font_info.descent;
1431 }
1432 if (overall_return)
1433 {
1434 char ch = c;
1435
1436 width = CharWidth (ch);
1437 QDTextBounds (1, &ch, &char_bounds);
1438 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1439 }
1440 }
1441
1442 return err;
1443}
1444
1445
1446/* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1447
1448static int
1449mac_text_extents_16 (font_struct, string, nchars, overall_return)
1450 XFontStruct *font_struct;
1451 XChar2b *string;
1452 int nchars;
1453 XCharStruct *overall_return;
1454{
1455 int i;
1456 short width = 0, lbearing = 0, rbearing = 0;
1457 XCharStruct *pcm;
1458
1459 for (i = 0; i < nchars; i++)
1460 {
1461 pcm = mac_per_char_metric (font_struct, string, 0);
1462 if (pcm == NULL)
1463 width += FONT_WIDTH (font_struct);
1464 else
1465 {
1466 lbearing = min (lbearing, width + pcm->lbearing);
1467 rbearing = max (rbearing, width + pcm->rbearing);
1468 width += pcm->width;
1469 }
1470 string++;
1471 }
1472
1473 overall_return->lbearing = lbearing;
1474 overall_return->rbearing = rbearing;
1475 overall_return->width = width;
1476
1477 /* What's the meaning of the return value of XTextExtents16? */
1478}
1479
1480
1481#if USE_CG_TEXT_DRAWING
6b9ad469
YM
1482static int cg_text_anti_aliasing_threshold = 8;
1483
1484static void
1485init_cg_text_anti_aliasing_threshold ()
1486{
b465419f
YM
1487 int threshold;
1488 Boolean valid_p;
6b9ad469 1489
b465419f
YM
1490 threshold =
1491 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1492 kCFPreferencesCurrentApplication,
1493 &valid_p);
1494 if (valid_p)
1495 cg_text_anti_aliasing_threshold = threshold;
6b9ad469
YM
1496}
1497
16805b2e 1498static int
bb420759 1499mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
16805b2e
YM
1500 struct frame *f;
1501 GC gc;
1502 int x, y;
1503 XChar2b *buf;
bb420759 1504 int nchars, bg_width, overstrike_p;
16805b2e 1505{
834263b6 1506 CGFloat port_height, gx, gy;
16805b2e
YM
1507 int i;
1508 CGContextRef context;
1509 CGGlyph *glyphs;
1510 CGSize *advances;
1511
70ed951a 1512 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
16805b2e
YM
1513 return 0;
1514
16805b2e
YM
1515 port_height = FRAME_PIXEL_HEIGHT (f);
1516 gx = x;
1517 gy = port_height - y;
1518 glyphs = (CGGlyph *)buf;
9fb446e3
YM
1519 advances = alloca (sizeof (CGSize) * nchars);
1520 if (advances == NULL)
1521 return 0;
16805b2e
YM
1522 for (i = 0; i < nchars; i++)
1523 {
b73e4d84
YM
1524 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1525
1526 advances[i].width = pcm->width;
16805b2e
YM
1527 advances[i].height = 0;
1528 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1529 buf++;
1530 }
1531
4ea08bbf
YM
1532#if USE_CG_DRAWING
1533 context = mac_begin_cg_clip (f, gc);
1534#else
7adf3143 1535 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
9fb446e3 1536 if (gc->n_clip_rects || bg_width)
16805b2e
YM
1537 {
1538 CGContextTranslateCTM (context, 0, port_height);
1539 CGContextScaleCTM (context, 1, -1);
9fb446e3
YM
1540 if (gc->n_clip_rects)
1541 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
4ea08bbf 1542#endif
9fb446e3
YM
1543 if (bg_width)
1544 {
e2d3b7e1 1545 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
9fb446e3
YM
1546 CGContextFillRect
1547 (context,
834263b6
YM
1548 mac_rect_make (f, gx, y - FONT_BASE (GC_FONT (gc)),
1549 bg_width, FONT_HEIGHT (GC_FONT (gc))));
9fb446e3 1550 }
16805b2e
YM
1551 CGContextScaleCTM (context, 1, -1);
1552 CGContextTranslateCTM (context, 0, -port_height);
4ea08bbf 1553#if !USE_CG_DRAWING
16805b2e 1554 }
4ea08bbf 1555#endif
e2d3b7e1 1556 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
16805b2e
YM
1557 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1558 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
6b9ad469
YM
1559 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1560 CGContextSetShouldAntialias (context, false);
16805b2e 1561#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1d4412cd
YM
1562#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1563 if (CGContextShowGlyphsWithAdvances != NULL)
1564#endif
bb420759 1565 {
1d4412cd 1566 CGContextSetTextPosition (context, gx, gy);
bb420759 1567 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1d4412cd
YM
1568 if (overstrike_p)
1569 {
1570 CGContextSetTextPosition (context, gx + 1.0f, gy);
1571 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1572 }
bb420759 1573 }
1d4412cd 1574#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
7adf3143 1575 else /* CGContextShowGlyphsWithAdvances == NULL */
1d4412cd
YM
1576#endif
1577#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1578#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
16805b2e 1579 {
1d4412cd
YM
1580 for (i = 0; i < nchars; i++)
1581 {
1582 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1583 if (overstrike_p)
1584 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1585 gx += advances[i].width;
1586 }
16805b2e
YM
1587 }
1588#endif
4ea08bbf
YM
1589#if USE_CG_DRAWING
1590 mac_end_cg_clip (f);
1591#else
16805b2e 1592 CGContextSynchronize (context);
7adf3143 1593 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
4ea08bbf 1594#endif
16805b2e 1595
16805b2e
YM
1596 return 1;
1597}
1598#endif
1599
1600
e09ce637 1601#if !USE_CG_DRAWING
1a578e9b
AC
1602/* Mac replacement for XCopyArea: dest must be window. */
1603
1604static void
236072ae 1605mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1a578e9b 1606 Pixmap src;
236072ae 1607 struct frame *f;
1a578e9b
AC
1608 GC gc;
1609 int src_x, src_y;
1610 unsigned int width, height;
1611 int dest_x, dest_y;
1612{
1613 Rect src_r, dest_r;
1614
7adf3143 1615 mac_begin_clip (f, gc);
e0f712ba 1616
1a578e9b
AC
1617 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1618 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1619
6b61353c
KH
1620 ForeColor (blackColor);
1621 BackColor (whiteColor);
1622
1623 LockPixels (GetGWorldPixMap (src));
e0f712ba 1624#if TARGET_API_MAC_CARBON
236072ae
YM
1625 {
1626 CGrafPtr port;
1627
1628 GetPort (&port);
1629 LockPortBits (port);
1630 CopyBits (GetPortBitMapForCopyBits (src),
1631 GetPortBitMapForCopyBits (port),
1632 &src_r, &dest_r, srcCopy, 0);
1633 UnlockPortBits (port);
1634 }
6b61353c 1635#else /* not TARGET_API_MAC_CARBON */
236072ae 1636 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
6b61353c
KH
1637 &src_r, &dest_r, srcCopy, 0);
1638#endif /* not TARGET_API_MAC_CARBON */
1639 UnlockPixels (GetGWorldPixMap (src));
1f98fbb4 1640
236072ae 1641 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143
YM
1642
1643 mac_end_clip (gc);
6b61353c 1644}
e0f712ba 1645
6b61353c
KH
1646
1647static void
236072ae 1648mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
6b61353c 1649 width, height, dest_x, dest_y)
6b61353c 1650 Pixmap src, mask;
236072ae 1651 struct frame *f;
6b61353c
KH
1652 GC gc;
1653 int src_x, src_y;
1654 unsigned int width, height;
1655 int dest_x, dest_y;
1656{
1657 Rect src_r, dest_r;
1658
7adf3143 1659 mac_begin_clip (f, gc);
6b61353c
KH
1660
1661 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1662 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1663
1664 ForeColor (blackColor);
1665 BackColor (whiteColor);
1666
1667 LockPixels (GetGWorldPixMap (src));
1668 LockPixels (GetGWorldPixMap (mask));
1669#if TARGET_API_MAC_CARBON
236072ae
YM
1670 {
1671 CGrafPtr port;
1672
1673 GetPort (&port);
1674 LockPortBits (port);
1675 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1676 GetPortBitMapForCopyBits (port),
1677 &src_r, &src_r, &dest_r);
1678 UnlockPortBits (port);
1679 }
e0f712ba 1680#else /* not TARGET_API_MAC_CARBON */
6b61353c 1681 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
236072ae 1682 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
e0f712ba 1683#endif /* not TARGET_API_MAC_CARBON */
6b61353c
KH
1684 UnlockPixels (GetGWorldPixMap (mask));
1685 UnlockPixels (GetGWorldPixMap (src));
1f98fbb4 1686
236072ae 1687 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143
YM
1688
1689 mac_end_clip (gc);
1a578e9b 1690}
e09ce637 1691#endif /* !USE_CG_DRAWING */
1a578e9b
AC
1692
1693
1a578e9b
AC
1694/* Mac replacement for XCopyArea: used only for scrolling. */
1695
1696static void
236072ae
YM
1697mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1698 struct frame *f;
1a578e9b
AC
1699 GC gc;
1700 int src_x, src_y;
1701 unsigned int width, height;
1702 int dest_x, dest_y;
1703{
e0f712ba 1704#if TARGET_API_MAC_CARBON
fc7a70cc
ST
1705 Rect src_r;
1706 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
e0f712ba
AC
1707
1708 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
4ea08bbf
YM
1709#if USE_CG_DRAWING
1710 mac_prepare_for_quickdraw (f);
1711#endif
236072ae
YM
1712 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1713 &src_r, dest_x - src_x, dest_y - src_y,
fc7a70cc
ST
1714 kScrollWindowNoOptions, dummy);
1715 DisposeRgn (dummy);
e0f712ba 1716#else /* not TARGET_API_MAC_CARBON */
1a578e9b 1717 Rect src_r, dest_r;
3354caee 1718 WindowRef w = FRAME_MAC_WINDOW (f);
1a578e9b 1719
7adf3143 1720 mac_begin_clip (f, gc);
1a578e9b
AC
1721
1722 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1723 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1724
f9e25d0c
AC
1725 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1726 color mapping in CopyBits. Otherwise, it will be slow. */
1727 ForeColor (blackColor);
1728 BackColor (whiteColor);
1729 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
177c0ea7 1730
236072ae 1731 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143
YM
1732
1733 mac_end_clip (gc);
e0f712ba 1734#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
1735}
1736
1737
1a578e9b
AC
1738/* Mac replacement for XChangeGC. */
1739
1740static void
e4f5e019
YM
1741XChangeGC (display, gc, mask, xgcv)
1742 Display *display;
1743 GC gc;
1744 unsigned long mask;
1745 XGCValues *xgcv;
1a578e9b
AC
1746{
1747 if (mask & GCForeground)
e4f5e019 1748 XSetForeground (display, gc, xgcv->foreground);
1a578e9b 1749 if (mask & GCBackground)
e4f5e019 1750 XSetBackground (display, gc, xgcv->background);
1a578e9b 1751 if (mask & GCFont)
e4f5e019 1752 XSetFont (display, gc, xgcv->font);
1a578e9b
AC
1753}
1754
1755
1756/* Mac replacement for XCreateGC. */
1757
e4f5e019 1758GC
a84cad70 1759XCreateGC (display, d, mask, xgcv)
e4f5e019 1760 Display *display;
a84cad70 1761 void *d;
e4f5e019
YM
1762 unsigned long mask;
1763 XGCValues *xgcv;
1a578e9b 1764{
e4f5e019 1765 GC gc = xmalloc (sizeof (*gc));
1a578e9b 1766
b96fe6ea 1767 bzero (gc, sizeof (*gc));
e2d3b7e1
YM
1768#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1769#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1770 if (CGColorGetTypeID != NULL)
1771#endif
1772 {
1773 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1774 CGColorRetain (gc->cg_fore_color);
1775 CGColorRetain (gc->cg_back_color);
1776 }
1777#endif
b96fe6ea 1778 XChangeGC (display, gc, mask, xgcv);
1a578e9b
AC
1779
1780 return gc;
1781}
1782
1783
1784/* Used in xfaces.c. */
1785
1786void
1787XFreeGC (display, gc)
1788 Display *display;
1789 GC gc;
1790{
1c4ac540
YM
1791 if (gc->clip_region)
1792 DisposeRgn (gc->clip_region);
e2d3b7e1 1793#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
a84cad70
YM
1794#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1795 if (CGColorGetTypeID != NULL)
1796#endif
1797 {
1798 CGColorRelease (gc->cg_fore_color);
1799 CGColorRelease (gc->cg_back_color);
1800 }
e2d3b7e1 1801#endif
1a578e9b
AC
1802 xfree (gc);
1803}
1804
1805
1806/* Mac replacement for XGetGCValues. */
1807
1808static void
e4f5e019
YM
1809XGetGCValues (display, gc, mask, xgcv)
1810 Display *display;
1811 GC gc;
1812 unsigned long mask;
1813 XGCValues *xgcv;
1a578e9b 1814{
e4f5e019
YM
1815 if (mask & GCForeground)
1816 xgcv->foreground = gc->xgcv.foreground;
1817 if (mask & GCBackground)
1818 xgcv->background = gc->xgcv.background;
1819 if (mask & GCFont)
1820 xgcv->font = gc->xgcv.font;
1a578e9b
AC
1821}
1822
1823
1824/* Mac replacement for XSetForeground. */
1825
6b61353c 1826void
1a578e9b
AC
1827XSetForeground (display, gc, color)
1828 Display *display;
1829 GC gc;
1830 unsigned long color;
1831{
e4f5e019
YM
1832 if (gc->xgcv.foreground != color)
1833 {
1834 gc->xgcv.foreground = color;
1835 gc->fore_color.red = RED16_FROM_ULONG (color);
1836 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1837 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
e2d3b7e1
YM
1838#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1839#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1840 if (CGColorGetTypeID != NULL)
1841#endif
1842 {
1843 CGColorRelease (gc->cg_fore_color);
1844 if (color == 0)
1845 {
1846 gc->cg_fore_color = mac_cg_color_black;
1847 CGColorRetain (gc->cg_fore_color);
1848 }
1849 else
1850 {
834263b6 1851 CGFloat rgba[4];
e2d3b7e1
YM
1852
1853 rgba[0] = gc->fore_color.red / 65535.0f;
1854 rgba[1] = gc->fore_color.green / 65535.0f;
1855 rgba[2] = gc->fore_color.blue / 65535.0f;
1856 rgba[3] = 1.0f;
1857 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1858 }
1859 }
1860#endif
e4f5e019 1861 }
1a578e9b
AC
1862}
1863
1864
9cdd4884
ST
1865/* Mac replacement for XSetBackground. */
1866
1867void
1868XSetBackground (display, gc, color)
1869 Display *display;
1870 GC gc;
1871 unsigned long color;
1872{
e4f5e019
YM
1873 if (gc->xgcv.background != color)
1874 {
1875 gc->xgcv.background = color;
1876 gc->back_color.red = RED16_FROM_ULONG (color);
1877 gc->back_color.green = GREEN16_FROM_ULONG (color);
1878 gc->back_color.blue = BLUE16_FROM_ULONG (color);
e2d3b7e1
YM
1879#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1880#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1881 if (CGColorGetTypeID != NULL)
1882#endif
1883 {
1884 CGColorRelease (gc->cg_back_color);
1885 if (color == 0)
1886 {
1887 gc->cg_back_color = mac_cg_color_black;
1888 CGColorRetain (gc->cg_back_color);
1889 }
1890 else
1891 {
834263b6 1892 CGFloat rgba[4];
e2d3b7e1
YM
1893
1894 rgba[0] = gc->back_color.red / 65535.0f;
1895 rgba[1] = gc->back_color.green / 65535.0f;
1896 rgba[2] = gc->back_color.blue / 65535.0f;
1897 rgba[3] = 1.0f;
1898 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1899 }
1900 }
1901#endif
e4f5e019
YM
1902 }
1903}
1904
1905
1906/* Mac replacement for XSetFont. */
1907
1908static void
1909XSetFont (display, gc, font)
1910 Display *display;
1911 GC gc;
1912 XFontStruct *font;
1913{
1914 gc->xgcv.font = font;
9cdd4884
ST
1915}
1916
1917
1c4ac540
YM
1918/* Mac replacement for XSetClipRectangles. */
1919
1920static void
834263b6
YM
1921mac_set_clip_rectangles (f, gc, rectangles, n)
1922 struct frame *f;
1c4ac540
YM
1923 GC gc;
1924 Rect *rectangles;
1925 int n;
1926{
1927 int i;
1928
b6e3efe0
YM
1929 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1930
1931 gc->n_clip_rects = n;
1932 if (n > 0)
1c4ac540
YM
1933 {
1934 if (gc->clip_region == NULL)
1935 gc->clip_region = NewRgn ();
1936 RectRgn (gc->clip_region, rectangles);
1937 if (n > 1)
1938 {
1939 RgnHandle region = NewRgn ();
1940
1941 for (i = 1; i < n; i++)
1942 {
1943 RectRgn (region, rectangles + i);
1944 UnionRgn (gc->clip_region, region, gc->clip_region);
1945 }
1946 DisposeRgn (region);
1947 }
1948 }
458dbb8c 1949#if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1c4ac540
YM
1950 for (i = 0; i < n; i++)
1951 {
1952 Rect *rect = rectangles + i;
1953
834263b6
YM
1954 gc->clip_rects[i] = mac_rect_make (f, rect->left, rect->top,
1955 rect->right - rect->left,
1956 rect->bottom - rect->top);
1c4ac540
YM
1957 }
1958#endif
1959}
1960
1961
1962/* Mac replacement for XSetClipMask. */
1963
1964static INLINE void
834263b6
YM
1965mac_reset_clip_rectangles (f, gc)
1966 struct frame *f;
1c4ac540
YM
1967 GC gc;
1968{
b6e3efe0 1969 gc->n_clip_rects = 0;
1c4ac540
YM
1970}
1971
1972
9cdd4884
ST
1973/* Mac replacement for XSetWindowBackground. */
1974
1975void
1976XSetWindowBackground (display, w, color)
1977 Display *display;
3354caee 1978 WindowRef w;
9cdd4884
ST
1979 unsigned long color;
1980{
1981#if !TARGET_API_MAC_CARBON
1982 AuxWinHandle aw_handle;
1983 CTabHandle ctab_handle;
1984 ColorSpecPtr ct_table;
1985 short ct_size;
1986#endif
1987 RGBColor bg_color;
1988
1989 bg_color.red = RED16_FROM_ULONG (color);
1990 bg_color.green = GREEN16_FROM_ULONG (color);
1991 bg_color.blue = BLUE16_FROM_ULONG (color);
1992
1993#if TARGET_API_MAC_CARBON
1994 SetWindowContentColor (w, &bg_color);
1995#else
1996 if (GetAuxWin (w, &aw_handle))
1997 {
1998 ctab_handle = (*aw_handle)->awCTable;
1999 HandToHand ((Handle *) &ctab_handle);
2000 ct_table = (*ctab_handle)->ctTable;
2001 ct_size = (*ctab_handle)->ctSize;
2002 while (ct_size > -1)
2003 {
2004 if (ct_table->value == 0)
2005 {
2006 ct_table->rgb = bg_color;
2007 CTabChanged (ctab_handle);
2008 SetWinColor (w, (WCTabHandle) ctab_handle);
2009 }
2010 ct_size--;
2011 }
2012 }
2013#endif
2014}
2015
1a578e9b
AC
2016/* Flush display of frame F, or of all frames if F is null. */
2017
fc7a70cc 2018static void
1a578e9b
AC
2019x_flush (f)
2020 struct frame *f;
2021{
e0f712ba 2022#if TARGET_API_MAC_CARBON
1a578e9b 2023 BLOCK_INPUT;
4ea08bbf
YM
2024#if USE_CG_DRAWING
2025 mac_prepare_for_quickdraw (f);
2026#endif
fc7a70cc
ST
2027 if (f)
2028 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
2029 else
2030 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1a578e9b 2031 UNBLOCK_INPUT;
fc7a70cc 2032#endif
1a578e9b
AC
2033}
2034
2035
fc7a70cc
ST
2036/* Remove calls to XFlush by defining XFlush to an empty replacement.
2037 Calls to XFlush should be unnecessary because the X output buffer
2038 is flushed automatically as needed by calls to XPending,
2039 XNextEvent, or XWindowEvent according to the XFlush man page.
2040 XTread_socket calls XPending. Removing XFlush improves
2041 performance. */
2042
2043#define XFlush(DISPLAY) (void) 0
2044
e6509087
YM
2045#if USE_CG_DRAWING
2046static void
2047mac_flush_display_optional (f)
2048 struct frame *f;
1a578e9b 2049{
e6509087
YM
2050 BLOCK_INPUT;
2051 mac_prepare_for_quickdraw (f);
2052 UNBLOCK_INPUT;
1a578e9b 2053}
e6509087 2054#endif
1a578e9b
AC
2055\f
2056/***********************************************************************
2057 Starting and ending an update
2058 ***********************************************************************/
177c0ea7 2059
1a578e9b
AC
2060/* Start an update of frame F. This function is installed as a hook
2061 for update_begin, i.e. it is called when update_begin is called.
2062 This function is called prior to calls to x_update_window_begin for
e0f712ba 2063 each window being updated. */
1a578e9b 2064
e0f712ba 2065static void
1a578e9b
AC
2066x_update_begin (f)
2067 struct frame *f;
2068{
b15325b2
ST
2069#if TARGET_API_MAC_CARBON
2070 /* During update of a frame, availability of input events is
2071 periodically checked with ReceiveNextEvent if
2072 redisplay-dont-pause is nil. That normally flushes window buffer
2073 changes for every check, and thus screen update looks waving even
2074 if no input is available. So we disable screen updates during
2075 update of a frame. */
2076 BLOCK_INPUT;
2077 DisableScreenUpdates ();
2078 UNBLOCK_INPUT;
2079#endif
1a578e9b
AC
2080}
2081
2082
2083/* Start update of window W. Set the global variable updated_window
2084 to the window being updated and set output_cursor to the cursor
2085 position of W. */
2086
e0f712ba 2087static void
1a578e9b
AC
2088x_update_window_begin (w)
2089 struct window *w;
2090{
2091 struct frame *f = XFRAME (WINDOW_FRAME (w));
2092 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
177c0ea7 2093
1a578e9b
AC
2094 updated_window = w;
2095 set_output_cursor (&w->cursor);
2096
2097 BLOCK_INPUT;
2098
2099 if (f == display_info->mouse_face_mouse_frame)
2100 {
2101 /* Don't do highlighting for mouse motion during the update. */
2102 display_info->mouse_face_defer = 1;
2103
2104 /* If F needs to be redrawn, simply forget about any prior mouse
2105 highlighting. */
2106 if (FRAME_GARBAGED_P (f))
2107 display_info->mouse_face_window = Qnil;
2108
2109#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
2110 their mouse_face_p flag set, which means that they are always
2111 unequal to rows in a desired matrix which never have that
2112 flag set. So, rows containing mouse-face glyphs are never
2113 scrolled, and we don't have to switch the mouse highlight off
2114 here to prevent it from being scrolled. */
177c0ea7 2115
1a578e9b
AC
2116 /* Can we tell that this update does not affect the window
2117 where the mouse highlight is? If so, no need to turn off.
2118 Likewise, don't do anything if the frame is garbaged;
2119 in that case, the frame's current matrix that we would use
2120 is all wrong, and we will redisplay that line anyway. */
2121 if (!NILP (display_info->mouse_face_window)
2122 && w == XWINDOW (display_info->mouse_face_window))
2123 {
2124 int i;
2125
50bf7673 2126 for (i = 0; i < w->desired_matrix->nrows; ++i)
1a578e9b
AC
2127 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2128 break;
2129
2130 if (i < w->desired_matrix->nrows)
2131 clear_mouse_face (display_info);
2132 }
2133#endif /* 0 */
2134 }
2135
2136 UNBLOCK_INPUT;
2137}
2138
2139
f9e65eb3 2140/* Draw a vertical window border from (x,y0) to (x,y1) */
1a578e9b
AC
2141
2142static void
f9e65eb3 2143mac_draw_vertical_window_border (w, x, y0, y1)
1a578e9b 2144 struct window *w;
f9e65eb3 2145 int x, y0, y1;
1a578e9b
AC
2146{
2147 struct frame *f = XFRAME (WINDOW_FRAME (w));
dd15724d
YM
2148 struct face *face;
2149
2150 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2151 if (face)
2152 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2153 face->foreground);
ffe8b3f4 2154
236072ae 2155 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
1a578e9b 2156}
e0f712ba 2157
1a578e9b
AC
2158/* End update of window W (which is equal to updated_window).
2159
2160 Draw vertical borders between horizontally adjacent windows, and
2161 display W's cursor if CURSOR_ON_P is non-zero.
2162
2163 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2164 glyphs in mouse-face were overwritten. In that case we have to
2165 make sure that the mouse-highlight is properly redrawn.
2166
2167 W may be a menu bar pseudo-window in case we don't have X toolkit
b15325b2 2168 support. Such windows don't have a cursor, so don't display it
95dfb192 2169 here. */
1a578e9b 2170
e0f712ba 2171static void
1a578e9b
AC
2172x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2173 struct window *w;
2174 int cursor_on_p, mouse_face_overwritten_p;
2175{
f9e65eb3 2176 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
e0f712ba 2177
1a578e9b
AC
2178 if (!w->pseudo_window_p)
2179 {
1a578e9b
AC
2180 BLOCK_INPUT;
2181
1a578e9b 2182 if (cursor_on_p)
f9e65eb3
KS
2183 display_and_set_cursor (w, 1, output_cursor.hpos,
2184 output_cursor.vpos,
2185 output_cursor.x, output_cursor.y);
177c0ea7 2186
f94a2622
KS
2187 if (draw_window_fringes (w, 1))
2188 x_draw_vertical_border (w);
6b61353c 2189
1a578e9b
AC
2190 UNBLOCK_INPUT;
2191 }
e0f712ba
AC
2192
2193 /* If a row with mouse-face was overwritten, arrange for
2194 XTframe_up_to_date to redisplay the mouse highlight. */
2195 if (mouse_face_overwritten_p)
2196 {
2197 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2198 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2199 dpyinfo->mouse_face_window = Qnil;
2200 }
2201
1a578e9b
AC
2202 updated_window = NULL;
2203}
2204
2205
2206/* End update of frame F. This function is installed as a hook in
2207 update_end. */
2208
e0f712ba 2209static void
1a578e9b
AC
2210x_update_end (f)
2211 struct frame *f;
2212{
404e4b84
ST
2213 /* Mouse highlight may be displayed again. */
2214 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2215
2216 BLOCK_INPUT;
b15325b2
ST
2217#if TARGET_API_MAC_CARBON
2218 EnableScreenUpdates ();
2219#endif
1a578e9b
AC
2220 XFlush (FRAME_MAC_DISPLAY (f));
2221 UNBLOCK_INPUT;
2222}
2223
2224
2225/* This function is called from various places in xdisp.c whenever a
2226 complete update has been performed. The global variable
2227 updated_window is not available here. */
2228
e0f712ba 2229static void
1a578e9b
AC
2230XTframe_up_to_date (f)
2231 struct frame *f;
2232{
fe97e8df 2233 if (FRAME_MAC_P (f))
1a578e9b
AC
2234 {
2235 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2236
2237 if (dpyinfo->mouse_face_deferred_gc
2238 || f == dpyinfo->mouse_face_mouse_frame)
2239 {
2240 BLOCK_INPUT;
2241 if (dpyinfo->mouse_face_mouse_frame)
2242 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2243 dpyinfo->mouse_face_mouse_x,
2244 dpyinfo->mouse_face_mouse_y);
2245 dpyinfo->mouse_face_deferred_gc = 0;
2246 UNBLOCK_INPUT;
2247 }
2248 }
2249}
2250
2251
2252/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 2253 arrow bitmaps, or clear the fringes if no bitmaps are required
1a578e9b 2254 before DESIRED_ROW is made current. The window being updated is
e0f712ba 2255 found in updated_window. This function is called from
1a578e9b
AC
2256 update_window_line only if it is known that there are differences
2257 between bitmaps to be drawn between current row and DESIRED_ROW. */
2258
e0f712ba 2259static void
1a578e9b
AC
2260x_after_update_window_line (desired_row)
2261 struct glyph_row *desired_row;
2262{
2263 struct window *w = updated_window;
e0f712ba
AC
2264 struct frame *f;
2265 int width, height;
2266
1a578e9b 2267 xassert (w);
177c0ea7 2268
1a578e9b 2269 if (!desired_row->mode_line_p && !w->pseudo_window_p)
6b61353c 2270 desired_row->redraw_fringe_bitmaps_p = 1;
1a578e9b 2271
e0f712ba
AC
2272 /* When a window has disappeared, make sure that no rest of
2273 full-width rows stays visible in the internal border. Could
2274 check here if updated_window is the leftmost/rightmost window,
2275 but I guess it's not worth doing since vertically split windows
2276 are almost never used, internal border is rarely set, and the
2277 overhead is very small. */
2278 if (windows_or_buffers_changed
2279 && desired_row->full_width_p
2280 && (f = XFRAME (w->frame),
2281 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2282 width != 0)
2283 && (height = desired_row->visible_height,
2284 height > 0))
2285 {
2286 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
95dfb192 2287
e0f712ba
AC
2288 /* Internal border is drawn below the tool bar. */
2289 if (WINDOWP (f->tool_bar_window)
2290 && w == XWINDOW (f->tool_bar_window))
2291 y -= width;
1a578e9b 2292
e0f712ba 2293 BLOCK_INPUT;
236072ae
YM
2294 mac_clear_area (f, 0, y, width, height);
2295 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1a578e9b
AC
2296 UNBLOCK_INPUT;
2297 }
2298}
2299
2300
3f332ef3 2301/* Draw the bitmap WHICH in one of the left or right fringes of
1a578e9b
AC
2302 window W. ROW is the glyph row for which to display the bitmap; it
2303 determines the vertical position at which the bitmap has to be
2304 drawn. */
2305
2306static void
5958f265 2307x_draw_fringe_bitmap (w, row, p)
1a578e9b
AC
2308 struct window *w;
2309 struct glyph_row *row;
5958f265 2310 struct draw_fringe_bitmap_params *p;
1a578e9b
AC
2311{
2312 struct frame *f = XFRAME (WINDOW_FRAME (w));
2313 Display *display = FRAME_MAC_DISPLAY (f);
5958f265 2314 struct face *face = p->face;
6b61353c 2315 int rowY;
e855c5d8 2316 int overlay_p = p->overlay_p;
1a578e9b 2317
c6829f81 2318#ifdef MAC_OSX
e855c5d8 2319 if (!overlay_p)
c6829f81 2320 {
e855c5d8 2321 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
c6829f81
YM
2322
2323#if 0 /* MAC_TODO: stipple */
2324 /* In case the same realized face is used for fringes and
2325 for something displayed in the text (e.g. face `region' on
2326 mono-displays, the fill style may have been changed to
2327 FillSolid in x_draw_glyph_string_background. */
2328 if (face->stipple)
2329 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2330 else
2331 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2332#endif
2333
2334 /* If the fringe is adjacent to the left (right) scroll bar of a
2335 leftmost (rightmost, respectively) window, then extend its
2336 background to the gap between the fringe and the bar. */
2337 if ((WINDOW_LEFTMOST_P (w)
2338 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2339 || (WINDOW_RIGHTMOST_P (w)
2340 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2341 {
2342 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2343
2344 if (sb_width > 0)
2345 {
2346 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2347 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2348 * FRAME_COLUMN_WIDTH (f));
2349
e855c5d8
YM
2350 if (bx < 0
2351 && (left + width == p->x
2352 || p->x + p->wd == left))
2353 {
2354 /* Bitmap fills the fringe and we need background
2355 extension. */
2356 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2357
2358 bx = p->x;
2359 nx = p->wd;
2360 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2361 row->y));
2362 ny = row->visible_height;
2363 }
2364
511a18d9 2365 if (bx >= 0)
c6829f81 2366 {
511a18d9
YM
2367 if (left + width == bx)
2368 {
2369 bx = left + sb_width;
2370 nx += width - sb_width;
2371 }
2372 else if (bx + nx == left)
2373 nx += width - sb_width;
c6829f81 2374 }
c6829f81
YM
2375 }
2376 }
2377
e855c5d8
YM
2378 if (bx >= 0)
2379 {
2380 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2381 /* The fringe background has already been filled. */
2382 overlay_p = 1;
2383 }
c6829f81
YM
2384
2385#if 0 /* MAC_TODO: stipple */
2386 if (!face->stipple)
2387 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2388#endif
2389 }
2390#endif /* MAC_OSX */
2391
1a578e9b 2392 /* Must clip because of partially visible lines. */
6b61353c
KH
2393 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2394 if (p->y < rowY)
2395 {
2396 /* Adjust position of "bottom aligned" bitmap on partially
2397 visible last row. */
2398 int oldY = row->y;
2399 int oldVH = row->visible_height;
2400 row->visible_height = p->h;
2401 row->y -= rowY - p->y;
236072ae 2402 x_clip_to_row (w, row, -1, face->gc);
6b61353c
KH
2403 row->y = oldY;
2404 row->visible_height = oldVH;
2405 }
2406 else
236072ae 2407 x_clip_to_row (w, row, -1, face->gc);
1a578e9b 2408
c6829f81 2409#ifndef MAC_OSX
6b61353c 2410 if (p->bx >= 0 && !p->overlay_p)
d33c49e8 2411 {
d33c49e8
KS
2412#if 0 /* MAC_TODO: stipple */
2413 /* In case the same realized face is used for fringes and
2414 for something displayed in the text (e.g. face `region' on
2415 mono-displays, the fill style may have been changed to
2416 FillSolid in x_draw_glyph_string_background. */
2417 if (face->stipple)
2418 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2419 else
2420 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2421#endif
2422
236072ae 2423 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
d33c49e8
KS
2424
2425#if 0 /* MAC_TODO: stipple */
2426 if (!face->stipple)
2427 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2428#endif
2429 }
c6829f81 2430#endif /* !MAC_OSX */
d33c49e8 2431
ad21830e
YM
2432 if (p->which
2433#if USE_CG_DRAWING
2434 && p->which < max_fringe_bmp
2435#endif
2436 )
e0f712ba 2437 {
e4f5e019 2438 XGCValues gcv;
1a578e9b 2439
e4f5e019
YM
2440 XGetGCValues (display, face->gc, GCForeground, &gcv);
2441 XSetForeground (display, face->gc,
2442 (p->cursor_p
2443 ? (p->overlay_p ? face->background
2444 : f->output_data.mac->cursor_pixel)
2445 : face->foreground));
ad21830e
YM
2446#if USE_CG_DRAWING
2447 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
e855c5d8 2448 p->wd, p->h, p->x, p->y, overlay_p);
ad21830e 2449#else
236072ae 2450 mac_draw_bitmap (f, face->gc, p->x, p->y,
e855c5d8 2451 p->wd, p->h, p->bits + p->dh, overlay_p);
ad21830e 2452#endif
e4f5e019 2453 XSetForeground (display, face->gc, gcv.foreground);
d33c49e8 2454 }
1a578e9b 2455
834263b6 2456 mac_reset_clip_rectangles (f, face->gc);
1a578e9b
AC
2457}
2458
ad21830e
YM
2459#if USE_CG_DRAWING
2460static void
2461mac_define_fringe_bitmap (which, bits, h, wd)
2462 int which;
2463 unsigned short *bits;
2464 int h, wd;
2465{
ad21830e
YM
2466 int i;
2467 CGDataProviderRef provider;
2468
2469 if (which >= max_fringe_bmp)
2470 {
2471 i = max_fringe_bmp;
2472 max_fringe_bmp = which + 20;
2473 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2474 while (i < max_fringe_bmp)
2475 fringe_bmp[i++] = 0;
2476 }
2477
2478 for (i = 0; i < h; i++)
2479 bits[i] = ~bits[i];
cb91e86a
YM
2480
2481 BLOCK_INPUT;
2482
ad21830e
YM
2483 provider = CGDataProviderCreateWithData (NULL, bits,
2484 sizeof (unsigned short) * h, NULL);
2485 if (provider)
2486 {
2487 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2488 sizeof (unsigned short),
2489 provider, NULL, 0);
2490 CGDataProviderRelease (provider);
2491 }
cb91e86a
YM
2492
2493 UNBLOCK_INPUT;
ad21830e
YM
2494}
2495
2496static void
2497mac_destroy_fringe_bitmap (which)
2498 int which;
2499{
2500 if (which >= max_fringe_bmp)
2501 return;
2502
2503 if (fringe_bmp[which])
cb91e86a
YM
2504 {
2505 BLOCK_INPUT;
2506 CGImageRelease (fringe_bmp[which]);
2507 UNBLOCK_INPUT;
2508 }
ad21830e
YM
2509 fringe_bmp[which] = 0;
2510}
2511#endif
1a578e9b 2512\f
95dfb192 2513
1a578e9b 2514/* This is called when starting Emacs and when restarting after
e0f712ba 2515 suspend. When starting Emacs, no window is mapped. And nothing
1a578e9b
AC
2516 must be done to Emacs's own window if it is suspended (though that
2517 rarely happens). */
2518
e0f712ba 2519static void
80ca7302 2520XTset_terminal_modes (struct terminal *t)
1a578e9b
AC
2521{
2522}
2523
2524/* This is called when exiting or suspending Emacs. Exiting will make
e0f712ba 2525 the windows go away, and suspending requires no action. */
1a578e9b 2526
e0f712ba 2527static void
80ca7302 2528XTreset_terminal_modes (struct terminal *t)
1a578e9b
AC
2529{
2530}
2531
95dfb192 2532
1a578e9b
AC
2533\f
2534/***********************************************************************
2535 Display Iterator
2536 ***********************************************************************/
2537
2538/* Function prototypes of this page. */
2539
1a578e9b 2540static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
cc02ceee
ST
2541static int mac_encode_char P_ ((int, XChar2b *, struct font_info *,
2542 struct charset *, int *));
1a578e9b
AC
2543
2544
458dbb8c
YM
2545static void
2546pcm_init (pcm, count)
2547 XCharStruct *pcm;
2548 int count;
2549{
2550 bzero (pcm, sizeof (XCharStruct) * count);
2551 while (--count >= 0)
2552 {
2553 pcm->descent = PCM_INVALID;
2554 pcm++;
2555 }
2556}
2557
2558static enum pcm_status
2559pcm_get_status (pcm)
369a7a37 2560 const XCharStruct *pcm;
458dbb8c
YM
2561{
2562 int height = pcm->ascent + pcm->descent;
2563
2564 /* Negative height means some special status. */
2565 return height >= 0 ? PCM_VALID : height;
2566}
2567
1a578e9b
AC
2568/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2569 is not contained in the font. */
2570
2571static INLINE XCharStruct *
2572x_per_char_metric (font, char2b)
2573 XFontStruct *font;
2574 XChar2b *char2b;
2575{
2576 /* The result metric information. */
2577 XCharStruct *pcm = NULL;
2578
2579 xassert (font && char2b);
2580
c3bd8190
YM
2581#if USE_ATSUI
2582 if (font->mac_style)
2583 {
458dbb8c 2584 XCharStruct **row = font->bounds.rows + char2b->byte1;
b73e4d84
YM
2585
2586 if (*row == NULL)
c3bd8190 2587 {
458dbb8c
YM
2588 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2589 pcm_init (*row, 0x100);
c3bd8190 2590 }
458dbb8c
YM
2591 pcm = *row + char2b->byte2;
2592 if (pcm_get_status (pcm) != PCM_VALID)
c3bd8190 2593 {
b96fe6ea
YM
2594 BLOCK_INPUT;
2595 mac_query_char_extents (font->mac_style,
2596 (char2b->byte1 << 8) + char2b->byte2,
2597 NULL, NULL, pcm, NULL);
2598 UNBLOCK_INPUT;
c3bd8190
YM
2599 }
2600 }
2601 else
2602 {
2603#endif
b73e4d84 2604 if (font->bounds.per_char != NULL)
1a578e9b
AC
2605 {
2606 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2607 {
2608 /* min_char_or_byte2 specifies the linear character index
2609 corresponding to the first element of the per_char array,
2610 max_char_or_byte2 is the index of the last character. A
2611 character with non-zero CHAR2B->byte1 is not in the font.
2612 A character with byte2 less than min_char_or_byte2 or
2613 greater max_char_or_byte2 is not in the font. */
2614 if (char2b->byte1 == 0
2615 && char2b->byte2 >= font->min_char_or_byte2
2616 && char2b->byte2 <= font->max_char_or_byte2)
b73e4d84
YM
2617 pcm = font->bounds.per_char
2618 + (char2b->byte2 - font->min_char_or_byte2);
1a578e9b
AC
2619 }
2620 else
2621 {
2622 /* If either min_byte1 or max_byte1 are nonzero, both
2623 min_char_or_byte2 and max_char_or_byte2 are less than
2624 256, and the 2-byte character index values corresponding
2625 to the per_char array element N (counting from 0) are:
2626
2627 byte1 = N/D + min_byte1
2628 byte2 = N\D + min_char_or_byte2
2629
2630 where:
2631
2632 D = max_char_or_byte2 - min_char_or_byte2 + 1
2633 / = integer division
2634 \ = integer modulus */
2635 if (char2b->byte1 >= font->min_byte1
2636 && char2b->byte1 <= font->max_byte1
2637 && char2b->byte2 >= font->min_char_or_byte2
2638 && char2b->byte2 <= font->max_char_or_byte2)
2639 {
b73e4d84 2640 pcm = (font->bounds.per_char
1a578e9b
AC
2641 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2642 * (char2b->byte1 - font->min_byte1))
2643 + (char2b->byte2 - font->min_char_or_byte2));
2644 }
2645 }
2646 }
2647 else
2648 {
2649 /* If the per_char pointer is null, all glyphs between the first
2650 and last character indexes inclusive have the same
2651 information, as given by both min_bounds and max_bounds. */
2652 if (char2b->byte2 >= font->min_char_or_byte2
2653 && char2b->byte2 <= font->max_char_or_byte2)
2654 pcm = &font->max_bounds;
2655 }
c3bd8190
YM
2656#if USE_ATSUI
2657 }
2658#endif
1a578e9b
AC
2659
2660 return ((pcm == NULL
a0c62ca2
YM
2661 || (pcm->width == 0
2662#if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2663 && (pcm->rbearing - pcm->lbearing) == 0
2664#endif
2665 ))
1a578e9b
AC
2666 ? NULL : pcm);
2667}
2668
750fc673
KS
2669/* RIF:
2670 */
2671
2672static XCharStruct *
2673mac_per_char_metric (font, char2b, font_type)
2674 XFontStruct *font;
2675 XChar2b *char2b;
2676 int font_type;
2677{
2678 return x_per_char_metric (font, char2b);
2679}
1a578e9b 2680
750fc673
KS
2681/* RIF:
2682 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1a578e9b
AC
2683 the two-byte form of C. Encoding is returned in *CHAR2B. */
2684
750fc673 2685static int
cc02ceee 2686mac_encode_char (c, char2b, font_info, charset, two_byte_p)
1a578e9b
AC
2687 int c;
2688 XChar2b *char2b;
2689 struct font_info *font_info;
cc02ceee 2690 struct charset *charset;
750fc673 2691 int *two_byte_p;
1a578e9b 2692{
1a578e9b
AC
2693 XFontStruct *font = font_info->font;
2694
2695 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2696 This may be either a program in a special encoder language or a
2697 fixed encoding. */
2698 if (font_info->font_encoder)
2699 {
2700 /* It's a program. */
2701 struct ccl_program *ccl = font_info->font_encoder;
2702
dd15724d 2703 check_ccl_update (ccl);
1a578e9b
AC
2704 if (CHARSET_DIMENSION (charset) == 1)
2705 {
cc02ceee
ST
2706 ccl->reg[0] = CHARSET_ID (charset);
2707 ccl->reg[1] = XCHAR2B_BYTE2 (char2b);
2708 ccl->reg[2] = -1;
1a578e9b
AC
2709 }
2710 else
2711 {
cc02ceee
ST
2712 ccl->reg[0] = CHARSET_ID (charset);
2713 ccl->reg[1] = XCHAR2B_BYTE1 (char2b);
2714 ccl->reg[2] = XCHAR2B_BYTE2 (char2b);
1a578e9b 2715 }
177c0ea7 2716
6abfb022 2717 ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
177c0ea7 2718
1a578e9b
AC
2719 /* We assume that MSBs are appropriately set/reset by CCL
2720 program. */
2721 if (font->max_byte1 == 0) /* 1-byte font */
cc02ceee 2722 STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
1a578e9b 2723 else
cc02ceee 2724 STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
1a578e9b 2725 }
cc02ceee 2726 else if (font_info->encoding_type)
1a578e9b
AC
2727 {
2728 /* Fixed encoding scheme. See fontset.h for the meaning of the
2729 encoding numbers. */
cc02ceee 2730 unsigned char enc = font_info->encoding_type;
177c0ea7 2731
1a578e9b
AC
2732 if ((enc == 1 || enc == 2)
2733 && CHARSET_DIMENSION (charset) == 2)
2734 char2b->byte1 |= 0x80;
177c0ea7 2735
1a578e9b
AC
2736 if (enc == 1 || enc == 3)
2737 char2b->byte2 |= 0x80;
2738
2739 if (enc == 4)
6abfb022
YM
2740 {
2741 int code = (char2b->byte1 << 8) | char2b->byte2;
1a578e9b 2742
6abfb022
YM
2743 JIS_TO_SJIS (code);
2744 STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
2745 }
1a578e9b 2746 }
1a578e9b
AC
2747
2748 if (two_byte_p)
750fc673 2749 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
1a578e9b 2750
750fc673 2751 return FONT_TYPE_UNKNOWN;
1a578e9b
AC
2752}
2753
2754
1a578e9b
AC
2755\f
2756/***********************************************************************
2757 Glyph display
2758 ***********************************************************************/
2759
1a578e9b 2760
95dfb192 2761
1a578e9b
AC
2762static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2763static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2764static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2765 int));
2766static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2767static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2768static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2769static void x_draw_glyph_string P_ ((struct glyph_string *));
95dfb192 2770static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
1a578e9b
AC
2771static void x_set_cursor_gc P_ ((struct glyph_string *));
2772static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2773static void x_set_mouse_face_gc P_ ((struct glyph_string *));
e0f712ba
AC
2774/*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2775 unsigned long *, double, int));*/
1a578e9b
AC
2776static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2777 double, int, unsigned long));
2778static void x_setup_relief_colors P_ ((struct glyph_string *));
2779static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2780static void x_draw_image_relief P_ ((struct glyph_string *));
2781static void x_draw_image_foreground P_ ((struct glyph_string *));
1a578e9b
AC
2782static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2783 int, int, int));
2784static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
ffe8b3f4
KS
2785 int, int, int, int, int, int,
2786 Rect *));
1a578e9b 2787static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
e0f712ba 2788 int, int, int, Rect *));
1a578e9b
AC
2789
2790#if GLYPH_DEBUG
2791static void x_check_font P_ ((struct frame *, XFontStruct *));
2792#endif
2793
177c0ea7 2794
1a578e9b
AC
2795/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2796 face. */
2797
2798static void
2799x_set_cursor_gc (s)
2800 struct glyph_string *s;
2801{
2802 if (s->font == FRAME_FONT (s->f)
2803 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2804 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2805 && !s->cmp)
2806 s->gc = s->f->output_data.mac->cursor_gc;
2807 else
2808 {
2809 /* Cursor on non-default face: must merge. */
2810 XGCValues xgcv;
2811 unsigned long mask;
2812
2813 xgcv.background = s->f->output_data.mac->cursor_pixel;
2814 xgcv.foreground = s->face->background;
2815
2816 /* If the glyph would be invisible, try a different foreground. */
2817 if (xgcv.foreground == xgcv.background)
2818 xgcv.foreground = s->face->foreground;
2819 if (xgcv.foreground == xgcv.background)
2820 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2821 if (xgcv.foreground == xgcv.background)
2822 xgcv.foreground = s->face->foreground;
2823
2824 /* Make sure the cursor is distinct from text in this face. */
2825 if (xgcv.background == s->face->background
2826 && xgcv.foreground == s->face->foreground)
2827 {
2828 xgcv.background = s->face->foreground;
2829 xgcv.foreground = s->face->background;
2830 }
2831
2832 IF_DEBUG (x_check_font (s->f, s->font));
2833 xgcv.font = s->font;
2834 mask = GCForeground | GCBackground | GCFont;
2835
2836 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2837 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2838 mask, &xgcv);
2839 else
2840 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2841 = XCreateGC (s->display, s->window, mask, &xgcv);
2842
2843 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2844 }
2845}
2846
2847
2848/* Set up S->gc of glyph string S for drawing text in mouse face. */
177c0ea7 2849
1a578e9b
AC
2850static void
2851x_set_mouse_face_gc (s)
2852 struct glyph_string *s;
177c0ea7 2853{
1a578e9b
AC
2854 int face_id;
2855 struct face *face;
2856
e0f712ba 2857 /* What face has to be used last for the mouse face? */
1a578e9b
AC
2858 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2859 face = FACE_FROM_ID (s->f, face_id);
e0f712ba
AC
2860 if (face == NULL)
2861 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
177c0ea7 2862
1a578e9b 2863 if (s->first_glyph->type == CHAR_GLYPH)
fda2f91b 2864 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1a578e9b 2865 else
fda2f91b 2866 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1a578e9b
AC
2867 s->face = FACE_FROM_ID (s->f, face_id);
2868 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2869
2870 /* If font in this face is same as S->font, use it. */
2871 if (s->font == s->face->font)
2872 s->gc = s->face->gc;
2873 else
2874 {
2875 /* Otherwise construct scratch_cursor_gc with values from FACE
2876 but font FONT. */
2877 XGCValues xgcv;
2878 unsigned long mask;
177c0ea7 2879
1a578e9b
AC
2880 xgcv.background = s->face->background;
2881 xgcv.foreground = s->face->foreground;
2882 IF_DEBUG (x_check_font (s->f, s->font));
2883 xgcv.font = s->font;
2884 mask = GCForeground | GCBackground | GCFont;
177c0ea7 2885
1a578e9b
AC
2886 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2887 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2888 mask, &xgcv);
2889 else
2890 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2891 = XCreateGC (s->display, s->window, mask, &xgcv);
177c0ea7 2892
1a578e9b
AC
2893 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2894 }
2895
2896 xassert (s->gc != 0);
2897}
2898
2899
2900/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2901 Faces to use in the mode line have already been computed when the
2902 matrix was built, so there isn't much to do, here. */
2903
2904static INLINE void
2905x_set_mode_line_face_gc (s)
2906 struct glyph_string *s;
177c0ea7 2907{
1a578e9b
AC
2908 s->gc = s->face->gc;
2909}
2910
2911
2912/* Set S->gc of glyph string S for drawing that glyph string. Set
2913 S->stippled_p to a non-zero value if the face of S has a stipple
2914 pattern. */
2915
2916static INLINE void
2917x_set_glyph_string_gc (s)
2918 struct glyph_string *s;
2919{
2920 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
177c0ea7 2921
1a578e9b
AC
2922 if (s->hl == DRAW_NORMAL_TEXT)
2923 {
2924 s->gc = s->face->gc;
2925 s->stippled_p = s->face->stipple != 0;
2926 }
2927 else if (s->hl == DRAW_INVERSE_VIDEO)
2928 {
2929 x_set_mode_line_face_gc (s);
2930 s->stippled_p = s->face->stipple != 0;
2931 }
2932 else if (s->hl == DRAW_CURSOR)
2933 {
2934 x_set_cursor_gc (s);
2935 s->stippled_p = 0;
2936 }
2937 else if (s->hl == DRAW_MOUSE_FACE)
2938 {
2939 x_set_mouse_face_gc (s);
2940 s->stippled_p = s->face->stipple != 0;
2941 }
2942 else if (s->hl == DRAW_IMAGE_RAISED
2943 || s->hl == DRAW_IMAGE_SUNKEN)
2944 {
2945 s->gc = s->face->gc;
2946 s->stippled_p = s->face->stipple != 0;
2947 }
2948 else
2949 {
2950 s->gc = s->face->gc;
2951 s->stippled_p = s->face->stipple != 0;
2952 }
2953
2954 /* GC must have been set. */
2955 xassert (s->gc != 0);
2956}
2957
2958
1a578e9b
AC
2959/* Set clipping for output of glyph string S. S may be part of a mode
2960 line or menu if we don't have X toolkit support. */
2961
2962static INLINE void
2963x_set_glyph_string_clipping (s)
2964 struct glyph_string *s;
2965{
1c4ac540
YM
2966 Rect rects[MAX_CLIP_RECTS];
2967 int n;
2968
2969 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
834263b6 2970 mac_set_clip_rectangles (s->f, s->gc, rects, n);
1a578e9b
AC
2971}
2972
2973
750fc673
KS
2974/* RIF:
2975 Compute left and right overhang of glyph string S. If S is a glyph
1a578e9b
AC
2976 string for a composition, assume overhangs don't exist. */
2977
750fc673
KS
2978static void
2979mac_compute_glyph_string_overhangs (s)
1a578e9b
AC
2980 struct glyph_string *s;
2981{
f93e4d4f
YM
2982 if (!(s->cmp == NULL
2983 && s->first_glyph->type == CHAR_GLYPH))
2984 return;
2985
2986 if (!s->two_byte_p
c3bd8190 2987#if USE_ATSUI
f93e4d4f 2988 || s->font->mac_style
b73e4d84 2989#endif
f93e4d4f
YM
2990 )
2991 {
2992 XCharStruct cs;
c3bd8190 2993
f93e4d4f
YM
2994 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2995 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2996 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2997 }
2998 else
2999 {
3000 Rect r;
3001 MacFontStruct *font = s->font;
c3bd8190 3002
444a42fd
YM
3003#if USE_CG_DRAWING
3004 mac_prepare_for_quickdraw (s->f);
3005#endif
3006 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
3007
f93e4d4f
YM
3008 TextFont (font->mac_fontnum);
3009 TextSize (font->mac_fontsize);
3010 TextFace (font->mac_fontface);
95085023 3011
f93e4d4f 3012 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
8c2da0fa 3013
f93e4d4f
YM
3014 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
3015 s->left_overhang = r.left < 0 ? -r.left : 0;
3016 }
1a578e9b
AC
3017}
3018
3019
3020/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3021
3022static INLINE void
3023x_clear_glyph_string_rect (s, x, y, w, h)
3024 struct glyph_string *s;
3025 int x, y, w, h;
3026{
236072ae 3027 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
1a578e9b
AC
3028}
3029
3030
3031/* Draw the background of glyph_string S. If S->background_filled_p
3032 is non-zero don't draw it. FORCE_P non-zero means draw the
3033 background even if it wouldn't be drawn normally. This is used
3034 when a string preceding S draws into the background of S, or S
3035 contains the first component of a composition. */
3036
3037static void
3038x_draw_glyph_string_background (s, force_p)
3039 struct glyph_string *s;
3040 int force_p;
3041{
3042 /* Nothing to do if background has already been drawn or if it
3043 shouldn't be drawn in the first place. */
3044 if (!s->background_filled_p)
3045 {
e0f712ba
AC
3046 int box_line_width = max (s->face->box_line_width, 0);
3047
1a578e9b
AC
3048#if 0 /* MAC_TODO: stipple */
3049 if (s->stippled_p)
3050 {
3051 /* Fill background with a stipple pattern. */
3052 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3053 XFillRectangle (s->display, s->window, s->gc, s->x,
e0f712ba 3054 s->y + box_line_width,
1a578e9b 3055 s->background_width,
e0f712ba 3056 s->height - 2 * box_line_width);
1a578e9b
AC
3057 XSetFillStyle (s->display, s->gc, FillSolid);
3058 s->background_filled_p = 1;
3059 }
3060 else
3061#endif
e0f712ba 3062 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1a578e9b
AC
3063 || s->font_not_found_p
3064 || s->extends_to_end_of_line_p
3065 || force_p)
3066 {
e0f712ba 3067 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1a578e9b 3068 s->background_width,
e0f712ba 3069 s->height - 2 * box_line_width);
1a578e9b
AC
3070 s->background_filled_p = 1;
3071 }
3072 }
3073}
3074
3075
3076/* Draw the foreground of glyph string S. */
3077
3078static void
3079x_draw_glyph_string_foreground (s)
3080 struct glyph_string *s;
3081{
9fb446e3 3082 int i, x, bg_width;
1a578e9b
AC
3083
3084 /* If first glyph of S has a left box line, start drawing the text
3085 of S to the right of that box line. */
3086 if (s->face->box != FACE_NO_BOX
3087 && s->first_glyph->left_box_line_p)
1ea40aa2 3088 x = s->x + eabs (s->face->box_line_width);
1a578e9b
AC
3089 else
3090 x = s->x;
3091
3092 /* Draw characters of S as rectangles if S's font could not be
3093 loaded. */
3094 if (s->font_not_found_p)
3095 {
3096 for (i = 0; i < s->nchars; ++i)
3097 {
3098 struct glyph *g = s->first_glyph + i;
236072ae
YM
3099 mac_draw_rectangle (s->f, s->gc, x, s->y,
3100 g->pixel_width - 1, s->height - 1);
1a578e9b
AC
3101 x += g->pixel_width;
3102 }
3103 }
3104 else
3105 {
3106 char *char1b = (char *) s->char2b;
3107 int boff = s->font_info->baseline_offset;
3108
3109 if (s->font_info->vertical_centering)
3110 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3111
3112 /* If we can use 8-bit functions, condense S->char2b. */
c3bd8190
YM
3113 if (!s->two_byte_p
3114#if USE_ATSUI
3115 && GC_FONT (s->gc)->mac_style == NULL
3116#endif
3117 )
1a578e9b
AC
3118 for (i = 0; i < s->nchars; ++i)
3119 char1b[i] = s->char2b[i].byte2;
3120
3121 /* Draw text with XDrawString if background has already been
3122 filled. Otherwise, use XDrawImageString. (Note that
3123 XDrawImageString is usually faster than XDrawString.) Always
3124 use XDrawImageString when drawing the cursor so that there is
3125 no chance that characters under a box cursor are invisible. */
c2ded1b7 3126 if (s->for_overlaps
1a578e9b 3127 || (s->background_filled_p && s->hl != DRAW_CURSOR))
9fb446e3
YM
3128 bg_width = 0; /* Corresponds to XDrawString. */
3129 else
3130 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3131
3132 if (s->two_byte_p
c3bd8190 3133#if USE_ATSUI
9fb446e3 3134 || GC_FONT (s->gc)->mac_style
c3bd8190 3135#endif
9fb446e3 3136 )
16805b2e 3137#if USE_CG_TEXT_DRAWING
9fb446e3
YM
3138 if (!s->two_byte_p
3139 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
bb420759
YM
3140 s->char2b, s->nchars, bg_width,
3141 s->face->overstrike))
9fb446e3
YM
3142 ;
3143 else
16805b2e 3144#endif
9fb446e3 3145 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
bb420759
YM
3146 s->char2b, s->nchars, bg_width,
3147 s->face->overstrike);
1a578e9b 3148 else
9fb446e3 3149 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
bb420759
YM
3150 char1b, s->nchars, bg_width,
3151 s->face->overstrike);
1a578e9b
AC
3152 }
3153}
3154
3155/* Draw the foreground of composite glyph string S. */
3156
3157static void
3158x_draw_composite_glyph_string_foreground (s)
3159 struct glyph_string *s;
3160{
3161 int i, x;
3162
3163 /* If first glyph of S has a left box line, start drawing the text
3164 of S to the right of that box line. */
3165 if (s->face->box != FACE_NO_BOX
3166 && s->first_glyph->left_box_line_p)
1ea40aa2 3167 x = s->x + eabs (s->face->box_line_width);
1a578e9b
AC
3168 else
3169 x = s->x;
3170
3171 /* S is a glyph string for a composition. S->gidx is the index of
3172 the first character drawn for glyphs of this composition.
3173 S->gidx == 0 means we are drawing the very first character of
3174 this composition. */
3175
3176 /* Draw a rectangle for the composition if the font for the very
3177 first character of the composition could not be loaded. */
3178 if (s->font_not_found_p)
3179 {
3180 if (s->gidx == 0)
236072ae
YM
3181 mac_draw_rectangle (s->f, s->gc, x, s->y,
3182 s->width - 1, s->height - 1);
1a578e9b
AC
3183 }
3184 else
3185 {
3186 for (i = 0; i < s->nchars; i++, ++s->gidx)
83cc8d35
YM
3187 if (mac_per_char_metric (GC_FONT (s->gc), s->char2b + i, 0) == NULL)
3188 /* This is a nonexistent or zero-width glyph such as a
3189 combining diacritic. Draw a rectangle. */
3190 mac_draw_rectangle (s->f, s->gc,
3191 x + s->cmp->offsets[s->gidx * 2], s->y,
3192 FONT_WIDTH (GC_FONT (s->gc)) - 1, s->height - 1);
3193 else
3194 mac_draw_image_string_16 (s->f, s->gc,
3195 x + s->cmp->offsets[s->gidx * 2],
3196 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3197 s->char2b + i, 1, 0, s->face->overstrike);
1a578e9b
AC
3198 }
3199}
3200
3201
3202#ifdef USE_X_TOOLKIT
3203
3204static struct frame *x_frame_of_widget P_ ((Widget));
3205
3206
3207/* Return the frame on which widget WIDGET is used.. Abort if frame
3208 cannot be determined. */
3209
3210static struct frame *
3211x_frame_of_widget (widget)
3212 Widget widget;
3213{
3214 struct x_display_info *dpyinfo;
3215 Lisp_Object tail;
3216 struct frame *f;
177c0ea7 3217
1a578e9b 3218 dpyinfo = x_display_info_for_display (XtDisplay (widget));
177c0ea7 3219
1a578e9b
AC
3220 /* Find the top-level shell of the widget. Note that this function
3221 can be called when the widget is not yet realized, so XtWindow
3222 (widget) == 0. That's the reason we can't simply use
3223 x_any_window_to_frame. */
3224 while (!XtIsTopLevelShell (widget))
3225 widget = XtParent (widget);
3226
3227 /* Look for a frame with that top-level widget. Allocate the color
3228 on that frame to get the right gamma correction value. */
8e50cc2d
SM
3229 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
3230 if (FRAMEP (XCAR (tail))
1a578e9b
AC
3231 && (f = XFRAME (XCAR (tail)),
3232 (f->output_data.nothing != 1
3233 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3234 && f->output_data.x->widget == widget)
3235 return f;
3236
3237 abort ();
3238}
3239
3240
3241/* Allocate the color COLOR->pixel on the screen and display of
3242 widget WIDGET in colormap CMAP. If an exact match cannot be
3243 allocated, try the nearest color available. Value is non-zero
3244 if successful. This is called from lwlib. */
3245
3246int
3247x_alloc_nearest_color_for_widget (widget, cmap, color)
3248 Widget widget;
3249 Colormap cmap;
3250 XColor *color;
3251{
3252 struct frame *f = x_frame_of_widget (widget);
3253 return x_alloc_nearest_color (f, cmap, color);
3254}
3255
3256
3257#endif /* USE_X_TOOLKIT */
3258
e0f712ba 3259#if 0 /* MAC_TODO */
1a578e9b
AC
3260
3261/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3262 CMAP. If an exact match can't be allocated, try the nearest color
3263 available. Value is non-zero if successful. Set *COLOR to the
3264 color allocated. */
3265
3266int
3267x_alloc_nearest_color (f, cmap, color)
3268 struct frame *f;
3269 Colormap cmap;
3270 XColor *color;
3271{
3272 Display *display = FRAME_X_DISPLAY (f);
3273 Screen *screen = FRAME_X_SCREEN (f);
3274 int rc;
3275
3276 gamma_correct (f, color);
3277 rc = XAllocColor (display, cmap, color);
3278 if (rc == 0)
3279 {
3280 /* If we got to this point, the colormap is full, so we're going
3281 to try to get the next closest color. The algorithm used is
3282 a least-squares matching, which is what X uses for closest
3283 color matching with StaticColor visuals. */
3284 int nearest, i;
3285 unsigned long nearest_delta = ~0;
3286 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3287 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3288
3289 for (i = 0; i < ncells; ++i)
3290 cells[i].pixel = i;
3291 XQueryColors (display, cmap, cells, ncells);
3292
3293 for (nearest = i = 0; i < ncells; ++i)
3294 {
3295 long dred = (color->red >> 8) - (cells[i].red >> 8);
3296 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3297 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3298 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3299
3300 if (delta < nearest_delta)
3301 {
3302 nearest = i;
3303 nearest_delta = delta;
3304 }
3305 }
177c0ea7 3306
1a578e9b
AC
3307 color->red = cells[nearest].red;
3308 color->green = cells[nearest].green;
3309 color->blue = cells[nearest].blue;
3310 rc = XAllocColor (display, cmap, color);
3311 }
3312
3313#ifdef DEBUG_X_COLORS
3314 if (rc)
3315 register_color (color->pixel);
3316#endif /* DEBUG_X_COLORS */
177c0ea7 3317
1a578e9b
AC
3318 return rc;
3319}
3320
3321
3322/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3323 It's necessary to do this instead of just using PIXEL directly to
3324 get color reference counts right. */
3325
3326unsigned long
3327x_copy_color (f, pixel)
3328 struct frame *f;
3329 unsigned long pixel;
3330{
3331 XColor color;
3332
3333 color.pixel = pixel;
3334 BLOCK_INPUT;
3335 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3336 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3337 UNBLOCK_INPUT;
3338#ifdef DEBUG_X_COLORS
3339 register_color (pixel);
3340#endif
3341 return color.pixel;
3342}
3343
3344
3345/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3346 It's necessary to do this instead of just using PIXEL directly to
3347 get color reference counts right. */
3348
3349unsigned long
3350x_copy_dpy_color (dpy, cmap, pixel)
3351 Display *dpy;
3352 Colormap cmap;
3353 unsigned long pixel;
3354{
3355 XColor color;
3356
3357 color.pixel = pixel;
3358 BLOCK_INPUT;
3359 XQueryColor (dpy, cmap, &color);
3360 XAllocColor (dpy, cmap, &color);
3361 UNBLOCK_INPUT;
3362#ifdef DEBUG_X_COLORS
3363 register_color (pixel);
3364#endif
3365 return color.pixel;
3366}
3367
e0f712ba 3368#endif /* MAC_TODO */
1a578e9b 3369
6b61353c
KH
3370
3371/* Brightness beyond which a color won't have its highlight brightness
3372 boosted.
3373
3374 Nominally, highlight colors for `3d' faces are calculated by
3375 brightening an object's color by a constant scale factor, but this
3376 doesn't yield good results for dark colors, so for colors who's
3377 brightness is less than this value (on a scale of 0-255) have to
3378 use an additional additive factor.
3379
3380 The value here is set so that the default menu-bar/mode-line color
3381 (grey75) will not have its highlights changed at all. */
3382#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3383
3384
1a578e9b
AC
3385/* Allocate a color which is lighter or darker than *COLOR by FACTOR
3386 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3387 If this produces the same color as COLOR, try a color where all RGB
3388 values have DELTA added. Return the allocated color in *COLOR.
3389 DISPLAY is the X display, CMAP is the colormap to operate on.
3390 Value is non-zero if successful. */
3391
3392static int
3393mac_alloc_lighter_color (f, color, factor, delta)
3394 struct frame *f;
3395 unsigned long *color;
3396 double factor;
3397 int delta;
3398{
3399 unsigned long new;
6b61353c
KH
3400 long bright;
3401
3402 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3403 delta /= 256;
1a578e9b
AC
3404
3405 /* Change RGB values by specified FACTOR. Avoid overflow! */
3406 xassert (factor >= 0);
3407 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3408 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3409 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
6b61353c
KH
3410
3411 /* Calculate brightness of COLOR. */
3412 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3413 + BLUE_FROM_ULONG (*color)) / 6;
3414
3415 /* We only boost colors that are darker than
3416 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3417 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3418 /* Make an additive adjustment to NEW, because it's dark enough so
3419 that scaling by FACTOR alone isn't enough. */
3420 {
3421 /* How far below the limit this color is (0 - 1, 1 being darker). */
3422 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3423 /* The additive adjustment. */
3424 int min_delta = delta * dimness * factor / 2;
3425
3426 if (factor < 1)
3427 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3428 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3429 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3430 else
3431 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3432 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3433 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3434 }
3435
1a578e9b
AC
3436 if (new == *color)
3437 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3438 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3439 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3440
3441 /* MAC_TODO: Map to palette and retry with delta if same? */
3442 /* MAC_TODO: Free colors (if using palette)? */
3443
3444 if (new == *color)
3445 return 0;
3446
3447 *color = new;
3448
3449 return 1;
3450}
3451
3452
3453/* Set up the foreground color for drawing relief lines of glyph
3454 string S. RELIEF is a pointer to a struct relief containing the GC
3455 with which lines will be drawn. Use a color that is FACTOR or
3456 DELTA lighter or darker than the relief's background which is found
3457 in S->f->output_data.x->relief_background. If such a color cannot
3458 be allocated, use DEFAULT_PIXEL, instead. */
177c0ea7 3459
1a578e9b
AC
3460static void
3461x_setup_relief_color (f, relief, factor, delta, default_pixel)
3462 struct frame *f;
3463 struct relief *relief;
3464 double factor;
3465 int delta;
3466 unsigned long default_pixel;
3467{
3468 XGCValues xgcv;
3469 struct mac_output *di = f->output_data.mac;
3470 unsigned long mask = GCForeground;
3471 unsigned long pixel;
3472 unsigned long background = di->relief_background;
3473 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3474
3475 /* MAC_TODO: Free colors (if using palette)? */
3476
3477 /* Allocate new color. */
3478 xgcv.foreground = default_pixel;
3479 pixel = background;
6b61353c
KH
3480 if (dpyinfo->n_planes != 1
3481 && mac_alloc_lighter_color (f, &pixel, factor, delta))
1a578e9b
AC
3482 {
3483 relief->allocated_p = 1;
3484 xgcv.foreground = relief->pixel = pixel;
3485 }
177c0ea7 3486
1a578e9b
AC
3487 if (relief->gc == 0)
3488 {
3489#if 0 /* MAC_TODO: stipple */
3490 xgcv.stipple = dpyinfo->gray;
3491 mask |= GCStipple;
3492#endif
3493 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3494 }
3495 else
3496 XChangeGC (NULL, relief->gc, mask, &xgcv);
3497}
3498
3499
3500/* Set up colors for the relief lines around glyph string S. */
3501
3502static void
3503x_setup_relief_colors (s)
3504 struct glyph_string *s;
3505{
3506 struct mac_output *di = s->f->output_data.mac;
3507 unsigned long color;
3508
3509 if (s->face->use_box_color_for_shadows_p)
3510 color = s->face->box_color;
6b61353c
KH
3511 else if (s->first_glyph->type == IMAGE_GLYPH
3512 && s->img->pixmap
3513 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3514 color = IMAGE_BACKGROUND (s->img, s->f, 0);
1a578e9b
AC
3515 else
3516 {
3517 XGCValues xgcv;
177c0ea7 3518
1a578e9b
AC
3519 /* Get the background color of the face. */
3520 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3521 color = xgcv.background;
3522 }
3523
3524 if (di->white_relief.gc == 0
3525 || color != di->relief_background)
3526 {
3527 di->relief_background = color;
3528 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3529 WHITE_PIX_DEFAULT (s->f));
3530 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3531 BLACK_PIX_DEFAULT (s->f));
3532 }
3533}
3534
3535
3536/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3537 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3538 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3539 relief. LEFT_P non-zero means draw a relief on the left side of
3540 the rectangle. RIGHT_P non-zero means draw a relief on the right
3541 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3542 when drawing. */
3543
3544static void
3545x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
ffe8b3f4 3546 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
1a578e9b 3547 struct frame *f;
ffe8b3f4
KS
3548 int left_x, top_y, right_x, bottom_y, width;
3549 int top_p, bot_p, left_p, right_p, raised_p;
1a578e9b
AC
3550 Rect *clip_rect;
3551{
3552 int i;
3553 GC gc;
177c0ea7 3554
1a578e9b
AC
3555 if (raised_p)
3556 gc = f->output_data.mac->white_relief.gc;
3557 else
3558 gc = f->output_data.mac->black_relief.gc;
834263b6 3559 mac_set_clip_rectangles (f, gc, clip_rect, 1);
1a578e9b
AC
3560
3561 /* Top. */
ffe8b3f4
KS
3562 if (top_p)
3563 for (i = 0; i < width; ++i)
236072ae
YM
3564 mac_draw_line (f, gc,
3565 left_x + i * left_p, top_y + i,
458dbb8c 3566 right_x + 1 - i * right_p, top_y + i);
1a578e9b
AC
3567
3568 /* Left. */
3569 if (left_p)
3570 for (i = 0; i < width; ++i)
236072ae 3571 mac_draw_line (f, gc,
458dbb8c 3572 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
1a578e9b 3573
834263b6 3574 mac_reset_clip_rectangles (f, gc);
1a578e9b
AC
3575 if (raised_p)
3576 gc = f->output_data.mac->black_relief.gc;
3577 else
3578 gc = f->output_data.mac->white_relief.gc;
834263b6 3579 mac_set_clip_rectangles (f, gc, clip_rect, 1);
177c0ea7 3580
1a578e9b 3581 /* Bottom. */
ffe8b3f4
KS
3582 if (bot_p)
3583 for (i = 0; i < width; ++i)
236072ae
YM
3584 mac_draw_line (f, gc,
3585 left_x + i * left_p, bottom_y - i,
458dbb8c 3586 right_x + 1 - i * right_p, bottom_y - i);
177c0ea7 3587
1a578e9b
AC
3588 /* Right. */
3589 if (right_p)
3590 for (i = 0; i < width; ++i)
236072ae 3591 mac_draw_line (f, gc,
458dbb8c 3592 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
1a578e9b 3593
834263b6 3594 mac_reset_clip_rectangles (f, gc);
1a578e9b
AC
3595}
3596
3597
3598/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3599 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3600 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3601 left side of the rectangle. RIGHT_P non-zero means draw a line
3602 on the right side of the rectangle. CLIP_RECT is the clipping
3603 rectangle to use when drawing. */
3604
3605static void
3606x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3607 left_p, right_p, clip_rect)
3608 struct glyph_string *s;
6b61353c 3609 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
1a578e9b
AC
3610 Rect *clip_rect;
3611{
3612 XGCValues xgcv;
177c0ea7 3613
e4f5e019
YM
3614 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3615 XSetForeground (s->display, s->gc, s->face->box_color);
834263b6 3616 mac_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
177c0ea7 3617
1a578e9b 3618 /* Top. */
236072ae
YM
3619 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3620 right_x - left_x + 1, width);
1a578e9b
AC
3621
3622 /* Left. */
3623 if (left_p)
236072ae
YM
3624 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3625 width, bottom_y - top_y + 1);
1a578e9b
AC
3626
3627 /* Bottom. */
236072ae
YM
3628 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3629 right_x - left_x + 1, width);
177c0ea7 3630
1a578e9b
AC
3631 /* Right. */
3632 if (right_p)
236072ae
YM
3633 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3634 top_y, width, bottom_y - top_y + 1);
1a578e9b 3635
e4f5e019 3636 XSetForeground (s->display, s->gc, xgcv.foreground);
834263b6 3637 mac_reset_clip_rectangles (s->f, s->gc);
1a578e9b
AC
3638}
3639
3640
3641/* Draw a box around glyph string S. */
3642
3643static void
3644x_draw_glyph_string_box (s)
3645 struct glyph_string *s;
3646{
3647 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3648 int left_p, right_p;
3649 struct glyph *last_glyph;
3650 Rect clip_rect;
3651
82ead4b1
KS
3652 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3653 ? WINDOW_RIGHT_EDGE_X (s->w)
3654 : window_box_right (s->w, s->area));
177c0ea7 3655
1a578e9b
AC
3656 /* The glyph that may have a right box line. */
3657 last_glyph = (s->cmp || s->img
3658 ? s->first_glyph
3659 : s->first_glyph + s->nchars - 1);
3660
1ea40aa2 3661 width = eabs (s->face->box_line_width);
1a578e9b
AC
3662 raised_p = s->face->box == FACE_RAISED_BOX;
3663 left_x = s->x;
6b61353c
KH
3664 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3665 ? last_x - 1
3666 : min (last_x, s->x + s->background_width) - 1);
1a578e9b
AC
3667 top_y = s->y;
3668 bottom_y = top_y + s->height - 1;
3669
3670 left_p = (s->first_glyph->left_box_line_p
3671 || (s->hl == DRAW_MOUSE_FACE
3672 && (s->prev == NULL
3673 || s->prev->hl != s->hl)));
3674 right_p = (last_glyph->right_box_line_p
3675 || (s->hl == DRAW_MOUSE_FACE
3676 && (s->next == NULL
3677 || s->next->hl != s->hl)));
177c0ea7 3678
f9e65eb3 3679 get_glyph_string_clip_rect (s, &clip_rect);
1a578e9b
AC
3680
3681 if (s->face->box == FACE_SIMPLE_BOX)
3682 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3683 left_p, right_p, &clip_rect);
3684 else
3685 {
3686 x_setup_relief_colors (s);
3687 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
ffe8b3f4 3688 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
1a578e9b
AC
3689 }
3690}
3691
3692
3693/* Draw foreground of image glyph string S. */
3694
3695static void
3696x_draw_image_foreground (s)
3697 struct glyph_string *s;
3698{
ffe8b3f4
KS
3699 int x = s->x;
3700 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
1a578e9b
AC
3701
3702 /* If first glyph of S has a left box line, start drawing it to the
3703 right of that line. */
3704 if (s->face->box != FACE_NO_BOX
ffe8b3f4
KS
3705 && s->first_glyph->left_box_line_p
3706 && s->slice.x == 0)
1ea40aa2 3707 x += eabs (s->face->box_line_width);
1a578e9b
AC
3708
3709 /* If there is a margin around the image, adjust x- and y-position
3710 by that margin. */
ffe8b3f4
KS
3711 if (s->slice.x == 0)
3712 x += s->img->hmargin;
3713 if (s->slice.y == 0)
3714 y += s->img->vmargin;
1a578e9b
AC
3715
3716 if (s->img->pixmap)
3717 {
fc7a70cc
ST
3718 x_set_glyph_string_clipping (s);
3719
e09ce637
YM
3720#if USE_CG_DRAWING
3721 mac_draw_cg_image (s->img->data.ptr_val,
3722 s->f, s->gc, s->slice.x, s->slice.y,
3723 s->slice.width, s->slice.height, x, y, 1);
3724#endif
1a578e9b 3725 if (s->img->mask)
e09ce637 3726#if !USE_CG_DRAWING
236072ae
YM
3727 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3728 s->f, s->gc, s->slice.x, s->slice.y,
fc7a70cc 3729 s->slice.width, s->slice.height, x, y);
e09ce637
YM
3730#else
3731 ;
3732#endif
1a578e9b 3733 else
1a578e9b 3734 {
e09ce637 3735#if !USE_CG_DRAWING
236072ae
YM
3736 mac_copy_area (s->img->pixmap,
3737 s->f, s->gc, s->slice.x, s->slice.y,
fc7a70cc 3738 s->slice.width, s->slice.height, x, y);
e09ce637 3739#endif
177c0ea7 3740
1a578e9b
AC
3741 /* When the image has a mask, we can expect that at
3742 least part of a mouse highlight or a block cursor will
3743 be visible. If the image doesn't have a mask, make
3744 a block cursor visible by drawing a rectangle around
3745 the image. I believe it's looking better if we do
3746 nothing here for mouse-face. */
3747 if (s->hl == DRAW_CURSOR)
534c20b2
KS
3748 {
3749 int r = s->img->relief;
3750 if (r < 0) r = -r;
236072ae 3751 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
ffe8b3f4
KS
3752 s->slice.width + r*2 - 1,
3753 s->slice.height + r*2 - 1);
534c20b2 3754 }
1a578e9b
AC
3755 }
3756 }
3757 else
3758 /* Draw a rectangle if image could not be loaded. */
236072ae 3759 mac_draw_rectangle (s->f, s->gc, x, y,
ffe8b3f4 3760 s->slice.width - 1, s->slice.height - 1);
1a578e9b
AC
3761}
3762
3763
3764/* Draw a relief around the image glyph string S. */
3765
3766static void
3767x_draw_image_relief (s)
3768 struct glyph_string *s;
3769{
3770 int x0, y0, x1, y1, thick, raised_p;
3771 Rect r;
ffe8b3f4
KS
3772 int x = s->x;
3773 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
177c0ea7 3774
1a578e9b
AC
3775 /* If first glyph of S has a left box line, start drawing it to the
3776 right of that line. */
3777 if (s->face->box != FACE_NO_BOX
ffe8b3f4
KS
3778 && s->first_glyph->left_box_line_p
3779 && s->slice.x == 0)
1ea40aa2 3780 x += eabs (s->face->box_line_width);
177c0ea7 3781
1a578e9b
AC
3782 /* If there is a margin around the image, adjust x- and y-position
3783 by that margin. */
ffe8b3f4
KS
3784 if (s->slice.x == 0)
3785 x += s->img->hmargin;
3786 if (s->slice.y == 0)
3787 y += s->img->vmargin;
177c0ea7 3788
1a578e9b
AC
3789 if (s->hl == DRAW_IMAGE_SUNKEN
3790 || s->hl == DRAW_IMAGE_RAISED)
3791 {
e0f712ba 3792 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
1a578e9b
AC
3793 raised_p = s->hl == DRAW_IMAGE_RAISED;
3794 }
3795 else
3796 {
1ea40aa2 3797 thick = eabs (s->img->relief);
1a578e9b
AC
3798 raised_p = s->img->relief > 0;
3799 }
177c0ea7 3800
1a578e9b
AC
3801 x0 = x - thick;
3802 y0 = y - thick;
ffe8b3f4
KS
3803 x1 = x + s->slice.width + thick - 1;
3804 y1 = y + s->slice.height + thick - 1;
177c0ea7 3805
1a578e9b 3806 x_setup_relief_colors (s);
f9e65eb3 3807 get_glyph_string_clip_rect (s, &r);
ffe8b3f4
KS
3808 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3809 s->slice.y == 0,
3810 s->slice.y + s->slice.height == s->img->height,
3811 s->slice.x == 0,
3812 s->slice.x + s->slice.width == s->img->width,
3813 &r);
1a578e9b
AC
3814}
3815
3816
1a578e9b
AC
3817/* Draw part of the background of glyph string S. X, Y, W, and H
3818 give the rectangle to draw. */
3819
3820static void
3821x_draw_glyph_string_bg_rect (s, x, y, w, h)
3822 struct glyph_string *s;
3823 int x, y, w, h;
3824{
3825#if 0 /* MAC_TODO: stipple */
3826 if (s->stippled_p)
3827 {
3828 /* Fill background with a stipple pattern. */
3829 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3830 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3831 XSetFillStyle (s->display, s->gc, FillSolid);
3832 }
3833 else
e0f712ba 3834#endif /* MAC_TODO */
1a578e9b
AC
3835 x_clear_glyph_string_rect (s, x, y, w, h);
3836}
3837
3838
177c0ea7 3839/* Draw image glyph string S.
1a578e9b
AC
3840
3841 s->y
3842 s->x +-------------------------
3843 | s->face->box
3844 |
3845 | +-------------------------
6b61353c 3846 | | s->img->margin
1a578e9b
AC
3847 | |
3848 | | +-------------------
3849 | | | the image
3850
3851 */
3852
3853static void
3854x_draw_image_glyph_string (s)
3855 struct glyph_string *s;
3856{
3857 int x, y;
1ea40aa2 3858 int box_line_hwidth = eabs (s->face->box_line_width);
e0f712ba 3859 int box_line_vwidth = max (s->face->box_line_width, 0);
1a578e9b 3860 int height;
1a578e9b 3861
e0f712ba 3862 height = s->height - 2 * box_line_vwidth;
1a578e9b 3863
6b61353c 3864
1a578e9b
AC
3865 /* Fill background with face under the image. Do it only if row is
3866 taller than image or if image has a clip mask to reduce
3867 flickering. */
3868 s->stippled_p = s->face->stipple != 0;
ffe8b3f4 3869 if (height > s->slice.height
83a96b4d 3870 || s->img->hmargin
e0f712ba 3871 || s->img->vmargin
1a578e9b 3872 || s->img->mask
1a578e9b
AC
3873 || s->img->pixmap == 0
3874 || s->width != s->background_width)
3875 {
ffe8b3f4
KS
3876 x = s->x;
3877 if (s->first_glyph->left_box_line_p
3878 && s->slice.x == 0)
3879 x += box_line_hwidth;
177c0ea7 3880
ffe8b3f4
KS
3881 y = s->y;
3882 if (s->slice.y == 0)
3883 y += box_line_vwidth;
6b61353c 3884
236072ae 3885 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
177c0ea7 3886
1a578e9b
AC
3887 s->background_filled_p = 1;
3888 }
3889
3890 /* Draw the foreground. */
236072ae 3891 x_draw_image_foreground (s);
1a578e9b
AC
3892
3893 /* If we must draw a relief around the image, do it. */
3894 if (s->img->relief
3895 || s->hl == DRAW_IMAGE_RAISED
3896 || s->hl == DRAW_IMAGE_SUNKEN)
3897 x_draw_image_relief (s);
3898}
3899
3900
3901/* Draw stretch glyph string S. */
3902
3903static void
3904x_draw_stretch_glyph_string (s)
3905 struct glyph_string *s;
3906{
3907 xassert (s->first_glyph->type == STRETCH_GLYPH);
1a578e9b
AC
3908
3909 if (s->hl == DRAW_CURSOR
3910 && !x_stretch_cursor_p)
3911 {
3912 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3913 as wide as the stretch glyph. */
e8f6b0db
KS
3914 int width, background_width = s->background_width;
3915 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3916
3917 if (x < left_x)
3918 {
3919 background_width -= left_x - x;
3920 x = left_x;
3921 }
3922 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
1a578e9b
AC
3923
3924 /* Draw cursor. */
e8f6b0db 3925 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
1a578e9b
AC
3926
3927 /* Clear rest using the GC of the original non-cursor face. */
e8f6b0db 3928 if (width < background_width)
1a578e9b 3929 {
e8f6b0db
KS
3930 int y = s->y;
3931 int w = background_width - width, h = s->height;
1a578e9b 3932 Rect r;
6b61353c 3933 GC gc;
1a578e9b 3934
e8f6b0db 3935 x += width;
e0f712ba
AC
3936 if (s->row->mouse_face_p
3937 && cursor_in_mouse_face_p (s->w))
3938 {
3939 x_set_mouse_face_gc (s);
3940 gc = s->gc;
3941 }
3942 else
3943 gc = s->face->gc;
177c0ea7 3944
f9e65eb3 3945 get_glyph_string_clip_rect (s, &r);
834263b6 3946 mac_set_clip_rectangles (s->f, gc, &r, 1);
1a578e9b
AC
3947
3948#if 0 /* MAC_TODO: stipple */
3949 if (s->face->stipple)
3950 {
3951 /* Fill background with a stipple pattern. */
3952 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3953 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3954 XSetFillStyle (s->display, gc, FillSolid);
3955 }
3956 else
e0f712ba 3957#endif /* MAC_TODO */
236072ae 3958 mac_erase_rectangle (s->f, gc, x, y, w, h);
1a578e9b
AC
3959 }
3960 }
e0f712ba 3961 else if (!s->background_filled_p)
e8f6b0db
KS
3962 {
3963 int background_width = s->background_width;
3964 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3965
6c693929
KS
3966 /* Don't draw into left margin, fringe or scrollbar area
3967 except for header line and mode line. */
3968 if (x < left_x && !s->row->mode_line_p)
e8f6b0db
KS
3969 {
3970 background_width -= left_x - x;
3971 x = left_x;
3972 }
3973 if (background_width > 0)
3974 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3975 }
177c0ea7 3976
1a578e9b
AC
3977 s->background_filled_p = 1;
3978}
3979
3980
3981/* Draw glyph string S. */
3982
3983static void
3984x_draw_glyph_string (s)
3985 struct glyph_string *s;
3986{
e0f712ba
AC
3987 int relief_drawn_p = 0;
3988
8c2da0fa
ST
3989 /* If S draws into the background of its successor that does not
3990 draw a cursor, draw the background of the successor first so that
3991 S can draw into it. This makes S->next use XDrawString instead
3992 of XDrawImageString. */
c2ded1b7 3993 if (s->next && s->right_overhang && !s->for_overlaps
8c2da0fa 3994 && s->next->hl != DRAW_CURSOR)
1a578e9b
AC
3995 {
3996 xassert (s->next->img == NULL);
3997 x_set_glyph_string_gc (s->next);
3998 x_set_glyph_string_clipping (s->next);
3999 x_draw_glyph_string_background (s->next, 1);
4000 }
4001
4002 /* Set up S->gc, set clipping and draw S. */
4003 x_set_glyph_string_gc (s);
e0f712ba
AC
4004
4005 /* Draw relief (if any) in advance for char/composition so that the
4006 glyph string can be drawn over it. */
c2ded1b7 4007 if (!s->for_overlaps
e0f712ba
AC
4008 && s->face->box != FACE_NO_BOX
4009 && (s->first_glyph->type == CHAR_GLYPH
4010 || s->first_glyph->type == COMPOSITE_GLYPH))
4011
4012 {
4013 x_set_glyph_string_clipping (s);
4014 x_draw_glyph_string_background (s, 1);
4015 x_draw_glyph_string_box (s);
4016 x_set_glyph_string_clipping (s);
4017 relief_drawn_p = 1;
4018 }
4019 else
4020 x_set_glyph_string_clipping (s);
1a578e9b
AC
4021
4022 switch (s->first_glyph->type)
4023 {
4024 case IMAGE_GLYPH:
4025 x_draw_image_glyph_string (s);
4026 break;
4027
4028 case STRETCH_GLYPH:
4029 x_draw_stretch_glyph_string (s);
4030 break;
4031
4032 case CHAR_GLYPH:
c2ded1b7 4033 if (s->for_overlaps)
1a578e9b
AC
4034 s->background_filled_p = 1;
4035 else
6b61353c 4036 x_draw_glyph_string_background (s, 0);
1a578e9b
AC
4037 x_draw_glyph_string_foreground (s);
4038 break;
4039
4040 case COMPOSITE_GLYPH:
c2ded1b7 4041 if (s->for_overlaps || s->gidx > 0)
1a578e9b
AC
4042 s->background_filled_p = 1;
4043 else
4044 x_draw_glyph_string_background (s, 1);
4045 x_draw_composite_glyph_string_foreground (s);
4046 break;
4047
4048 default:
4049 abort ();
4050 }
4051
c2ded1b7 4052 if (!s->for_overlaps)
1a578e9b
AC
4053 {
4054 /* Draw underline. */
4055 if (s->face->underline_p)
4056 {
cf2c6835
YM
4057 unsigned long tem, h;
4058 int y;
4059
4060#if 0
4061 /* Get the underline thickness. Default is 1 pixel. */
4062 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4063#endif
4064 h = 1;
4065
4066 y = s->y + s->height - h;
4067 if (!x_underline_at_descent_line)
4068 {
4069 /* Get the underline position. This is the recommended
4070 vertical offset in pixels from the baseline to the top of
4071 the underline. This is a signed value according to the
4072 specs, and its default is
4073
4074 ROUND ((maximum descent) / 2), with
4075 ROUND(x) = floor (x + 0.5) */
4076
4077#if 0
4078 if (x_use_underline_position_properties
4079 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4080 y = s->ybase + (long) tem;
4081 else
4082#endif
4083 if (s->face->font)
4084 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4085 }
177c0ea7 4086
1a578e9b 4087 if (s->face->underline_defaulted_p)
cf2c6835 4088 mac_fill_rectangle (s->f, s->gc, s->x, y,
30f27523 4089 s->background_width, h);
1a578e9b
AC
4090 else
4091 {
4092 XGCValues xgcv;
4093 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4094 XSetForeground (s->display, s->gc, s->face->underline_color);
cf2c6835 4095 mac_fill_rectangle (s->f, s->gc, s->x, y,
30f27523 4096 s->background_width, h);
1a578e9b
AC
4097 XSetForeground (s->display, s->gc, xgcv.foreground);
4098 }
4099 }
4100
4101 /* Draw overline. */
4102 if (s->face->overline_p)
4103 {
4104 unsigned long dy = 0, h = 1;
4105
4106 if (s->face->overline_color_defaulted_p)
236072ae 4107 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
30f27523 4108 s->background_width, h);
1a578e9b
AC
4109 else
4110 {
4111 XGCValues xgcv;
4112 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4113 XSetForeground (s->display, s->gc, s->face->overline_color);
236072ae 4114 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
30f27523 4115 s->background_width, h);
1a578e9b
AC
4116 XSetForeground (s->display, s->gc, xgcv.foreground);
4117 }
4118 }
177c0ea7 4119
1a578e9b
AC
4120 /* Draw strike-through. */
4121 if (s->face->strike_through_p)
4122 {
4123 unsigned long h = 1;
4124 unsigned long dy = (s->height - h) / 2;
4125
4126 if (s->face->strike_through_color_defaulted_p)
236072ae
YM
4127 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4128 s->width, h);
1a578e9b
AC
4129 else
4130 {
4131 XGCValues xgcv;
4132 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4133 XSetForeground (s->display, s->gc, s->face->strike_through_color);
236072ae
YM
4134 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4135 s->width, h);
1a578e9b
AC
4136 XSetForeground (s->display, s->gc, xgcv.foreground);
4137 }
4138 }
177c0ea7 4139
6b61353c 4140 /* Draw relief if not yet drawn. */
e0f712ba 4141 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
6b61353c 4142 x_draw_glyph_string_box (s);
1a578e9b 4143 }
e0f712ba 4144
1a578e9b 4145 /* Reset clipping. */
834263b6 4146 mac_reset_clip_rectangles (s->f, s->gc);
1a578e9b
AC
4147}
4148
f9e65eb3 4149/* Shift display to make room for inserted glyphs. */
1a578e9b 4150
f9e65eb3
KS
4151void
4152mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4153 struct frame *f;
4154 int x, y, width, height, shift_by;
1a578e9b 4155{
236072ae 4156 mac_scroll_area (f, f->output_data.mac->normal_gc,
f9e65eb3
KS
4157 x, y, width, height,
4158 x + shift_by, y);
1a578e9b
AC
4159}
4160
1a578e9b
AC
4161/* Delete N glyphs at the nominal cursor position. Not implemented
4162 for X frames. */
4163
e0f712ba 4164static void
1a578e9b
AC
4165x_delete_glyphs (n)
4166 register int n;
4167{
4168 abort ();
4169}
4170
4171
1a578e9b
AC
4172/* Clear entire frame. If updating_frame is non-null, clear that
4173 frame. Otherwise clear the selected frame. */
4174
e0f712ba 4175static void
80ca7302 4176x_clear_frame (struct frame *f)
1a578e9b 4177{
1a578e9b
AC
4178 /* Clearing the frame will erase any cursor, so mark them all as no
4179 longer visible. */
4180 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4181 output_cursor.hpos = output_cursor.vpos = 0;
4182 output_cursor.x = -1;
4183
4184 /* We don't set the output cursor here because there will always
4185 follow an explicit cursor_to. */
4186 BLOCK_INPUT;
236072ae 4187 mac_clear_window (f);
1a578e9b 4188
1a578e9b
AC
4189 /* We have to clear the scroll bars, too. If we have changed
4190 colors or something like that, then they should be notified. */
4191 x_scroll_bar_clear (f);
1a578e9b
AC
4192
4193 XFlush (FRAME_MAC_DISPLAY (f));
4194 UNBLOCK_INPUT;
4195}
4196
4197
4198\f
4199/* Invert the middle quarter of the frame for .15 sec. */
4200
4201/* We use the select system call to do the waiting, so we have to make
4202 sure it's available. If it isn't, we just won't do visual bells. */
4203
4204#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4205
6b61353c 4206
1a578e9b
AC
4207/* Subtract the `struct timeval' values X and Y, storing the result in
4208 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4209
4210static int
4211timeval_subtract (result, x, y)
4212 struct timeval *result, x, y;
4213{
4214 /* Perform the carry for the later subtraction by updating y. This
4215 is safer because on some systems the tv_sec member is unsigned. */
4216 if (x.tv_usec < y.tv_usec)
4217 {
4218 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4219 y.tv_usec -= 1000000 * nsec;
4220 y.tv_sec += nsec;
4221 }
177c0ea7 4222
1a578e9b
AC
4223 if (x.tv_usec - y.tv_usec > 1000000)
4224 {
4225 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4226 y.tv_usec += 1000000 * nsec;
4227 y.tv_sec -= nsec;
4228 }
4229
4230 /* Compute the time remaining to wait. tv_usec is certainly
4231 positive. */
4232 result->tv_sec = x.tv_sec - y.tv_sec;
4233 result->tv_usec = x.tv_usec - y.tv_usec;
4234
4235 /* Return indication of whether the result should be considered
4236 negative. */
4237 return x.tv_sec < y.tv_sec;
4238}
4239
4240void
4241XTflash (f)
4242 struct frame *f;
4243{
d4a8455b
YM
4244 /* Get the height not including a menu bar widget. */
4245 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4246 /* Height of each line to flash. */
4247 int flash_height = FRAME_LINE_HEIGHT (f);
4248 /* These will be the left and right margins of the rectangles. */
4249 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4250 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4251
4252 int width;
4253
4254 /* Don't flash the area between a scroll bar and the frame
4255 edge it is next to. */
4256 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4257 {
4258 case vertical_scroll_bar_left:
4259 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4260 break;
4261
4262 case vertical_scroll_bar_right:
4263 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4264 break;
4265
4266 default:
4267 break;
4268 }
4269
4270 width = flash_right - flash_left;
4271
1a578e9b
AC
4272 BLOCK_INPUT;
4273
d4a8455b
YM
4274 /* If window is tall, flash top and bottom line. */
4275 if (height > 3 * FRAME_LINE_HEIGHT (f))
4276 {
236072ae 4277 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4278 (FRAME_INTERNAL_BORDER_WIDTH (f)
4279 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4280 width, flash_height);
236072ae 4281 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4282 (height - flash_height
4283 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4284 width, flash_height);
4285 }
4286 else
4287 /* If it is short, flash it all. */
236072ae 4288 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
d4a8455b
YM
4289 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4290
4291 x_flush (f);
1a578e9b
AC
4292
4293 {
4294 struct timeval wakeup;
4295
4296 EMACS_GET_TIME (wakeup);
4297
4298 /* Compute time to wait until, propagating carry from usecs. */
4299 wakeup.tv_usec += 150000;
4300 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4301 wakeup.tv_usec %= 1000000;
4302
d4a8455b
YM
4303 /* Keep waiting until past the time wakeup or any input gets
4304 available. */
4305 while (! detect_input_pending ())
1a578e9b 4306 {
d4a8455b
YM
4307 struct timeval current;
4308 struct timeval timeout;
1a578e9b 4309
d4a8455b 4310 EMACS_GET_TIME (current);
1a578e9b 4311
d4a8455b
YM
4312 /* Break if result would be negative. */
4313 if (timeval_subtract (&current, wakeup, current))
4314 break;
1a578e9b 4315
d4a8455b
YM
4316 /* How long `select' should wait. */
4317 timeout.tv_sec = 0;
4318 timeout.tv_usec = 10000;
1a578e9b 4319
d4a8455b
YM
4320 /* Try to wait that long--but we might wake up sooner. */
4321 select (0, NULL, NULL, NULL, &timeout);
1a578e9b
AC
4322 }
4323 }
177c0ea7 4324
d4a8455b
YM
4325 /* If window is tall, flash top and bottom line. */
4326 if (height > 3 * FRAME_LINE_HEIGHT (f))
4327 {
236072ae 4328 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4329 (FRAME_INTERNAL_BORDER_WIDTH (f)
4330 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4331 width, flash_height);
236072ae 4332 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4333 (height - flash_height
4334 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4335 width, flash_height);
4336 }
4337 else
4338 /* If it is short, flash it all. */
236072ae 4339 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
d4a8455b
YM
4340 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4341
4342 x_flush (f);
1a578e9b
AC
4343
4344 UNBLOCK_INPUT;
4345}
4346
4347#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4348
4349
4350/* Make audible bell. */
4351
4352void
4353XTring_bell ()
4354{
4355 struct frame *f = SELECTED_FRAME ();
177c0ea7 4356
1a578e9b
AC
4357#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4358 if (visible_bell)
4359 XTflash (f);
4360 else
4361#endif
4362 {
4363 BLOCK_INPUT;
4364 SysBeep (1);
4365 XFlush (FRAME_MAC_DISPLAY (f));
4366 UNBLOCK_INPUT;
4367 }
4368}
4369
1a578e9b
AC
4370\f
4371/* Specify how many text lines, from the top of the window,
4372 should be affected by insert-lines and delete-lines operations.
4373 This, and those operations, are used only within an update
4374 that is bounded by calls to x_update_begin and x_update_end. */
4375
6b61353c 4376static void
1a578e9b
AC
4377XTset_terminal_window (n)
4378 register int n;
4379{
4380 /* This function intentionally left blank. */
4381}
4382
4383
4384\f
4385/***********************************************************************
4386 Line Dance
4387 ***********************************************************************/
4388
4389/* Perform an insert-lines or delete-lines operation, inserting N
4390 lines or deleting -N lines at vertical position VPOS. */
4391
e0f712ba 4392static void
1a578e9b
AC
4393x_ins_del_lines (vpos, n)
4394 int vpos, n;
4395{
4396 abort ();
4397}
4398
4399
4400/* Scroll part of the display as described by RUN. */
4401
e0f712ba 4402static void
1a578e9b
AC
4403x_scroll_run (w, run)
4404 struct window *w;
4405 struct run *run;
4406{
4407 struct frame *f = XFRAME (w->frame);
4408 int x, y, width, height, from_y, to_y, bottom_y;
4409
4410 /* Get frame-relative bounding box of the text display area of W,
3f332ef3 4411 without mode lines. Include in this box the left and right
6b61353c 4412 fringe of W. */
1a578e9b 4413 window_box (w, -1, &x, &y, &width, &height);
1a578e9b
AC
4414
4415 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4416 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4417 bottom_y = y + height;
4418
4419 if (to_y < from_y)
4420 {
4421 /* Scrolling up. Make sure we don't copy part of the mode
4422 line at the bottom. */
4423 if (from_y + run->height > bottom_y)
4424 height = bottom_y - from_y;
4425 else
4426 height = run->height;
4427 }
4428 else
4429 {
4430 /* Scolling down. Make sure we don't copy over the mode line.
4431 at the bottom. */
4432 if (to_y + run->height > bottom_y)
4433 height = bottom_y - to_y;
4434 else
4435 height = run->height;
4436 }
4437
4438 BLOCK_INPUT;
177c0ea7 4439
1a578e9b
AC
4440 /* Cursor off. Will be switched on again in x_update_window_end. */
4441 updated_window = w;
4442 x_clear_cursor (w);
4443
236072ae
YM
4444 mac_scroll_area (f, f->output_data.mac->normal_gc,
4445 x, from_y,
4446 width, height,
4447 x, to_y);
177c0ea7 4448
1a578e9b
AC
4449 UNBLOCK_INPUT;
4450}
4451
4452
4453\f
4454/***********************************************************************
4455 Exposure Events
4456 ***********************************************************************/
177c0ea7 4457
f9e65eb3
KS
4458\f
4459static void
4460frame_highlight (f)
4461 struct frame *f;
4462{
4463 x_update_cursor (f, 1);
4464}
1a578e9b
AC
4465
4466static void
f9e65eb3 4467frame_unhighlight (f)
1a578e9b 4468 struct frame *f;
1a578e9b 4469{
f9e65eb3
KS
4470 x_update_cursor (f, 1);
4471}
4472
4473/* The focus has changed. Update the frames as necessary to reflect
4474 the new situation. Note that we can't change the selected frame
4475 here, because the Lisp code we are interrupting might become confused.
4476 Each event gets marked with the frame in which it occurred, so the
4477 Lisp code can tell when the switch took place by examining the events. */
1a578e9b 4478
f9e65eb3
KS
4479static void
4480x_new_focus_frame (dpyinfo, frame)
4481 struct x_display_info *dpyinfo;
4482 struct frame *frame;
4483{
4484 struct frame *old_focus = dpyinfo->x_focus_frame;
1a578e9b 4485
f9e65eb3 4486 if (frame != dpyinfo->x_focus_frame)
1a578e9b 4487 {
f9e65eb3
KS
4488 /* Set this before calling other routines, so that they see
4489 the correct value of x_focus_frame. */
4490 dpyinfo->x_focus_frame = frame;
1a578e9b 4491
f9e65eb3
KS
4492 if (old_focus && old_focus->auto_lower)
4493 x_lower_frame (old_focus);
1a578e9b 4494
f9e65eb3
KS
4495#if 0
4496 selected_frame = frame;
4497 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4498 selected_frame);
f1321dc3 4499 Fselect_window (selected_frame->selected_window, Qnil);
f9e65eb3
KS
4500 choose_minibuf_frame ();
4501#endif /* ! 0 */
1a578e9b 4502
f9e65eb3
KS
4503 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4504 pending_autoraise_frame = dpyinfo->x_focus_frame;
4505 else
4506 pending_autoraise_frame = 0;
68c767a3
YM
4507
4508#if USE_MAC_FONT_PANEL
4509 if (frame)
4cb62a90 4510 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
68c767a3 4511#endif
1a578e9b 4512 }
1a578e9b 4513
f9e65eb3
KS
4514 x_frame_rehighlight (dpyinfo);
4515}
1a578e9b 4516
7ca7ccd5
YM
4517/* Handle FocusIn and FocusOut state changes for FRAME.
4518 If FRAME has focus and there exists more than one frame, puts
4519 a FOCUS_IN_EVENT into *BUFP. */
4520
4521static void
4522mac_focus_changed (type, dpyinfo, frame, bufp)
4523 int type;
4524 struct mac_display_info *dpyinfo;
4525 struct frame *frame;
4526 struct input_event *bufp;
4527{
4528 if (type == activeFlag)
4529 {
4530 if (dpyinfo->x_focus_event_frame != frame)
4531 {
4532 x_new_focus_frame (dpyinfo, frame);
4533 dpyinfo->x_focus_event_frame = frame;
4534
4535 /* Don't stop displaying the initial startup message
4536 for a switch-frame event we don't need. */
8e50cc2d
SM
4537 if (NILP (Vterminal_frame)
4538 && CONSP (Vframe_list)
4539 && !NILP (XCDR (Vframe_list)))
7ca7ccd5
YM
4540 {
4541 bufp->kind = FOCUS_IN_EVENT;
4542 XSETFRAME (bufp->frame_or_window, frame);
4543 }
4544 }
4545 }
4546 else
4547 {
4548 if (dpyinfo->x_focus_event_frame == frame)
4549 {
4550 dpyinfo->x_focus_event_frame = 0;
4551 x_new_focus_frame (dpyinfo, 0);
4552 }
4553 }
4554}
4555
4556/* The focus may have changed. Figure out if it is a real focus change,
4557 by checking both FocusIn/Out and Enter/LeaveNotify events.
4558
4559 Returns FOCUS_IN_EVENT event in *BUFP. */
4560
4561static void
4562x_detect_focus_change (dpyinfo, event, bufp)
4563 struct mac_display_info *dpyinfo;
369a7a37 4564 const EventRecord *event;
7ca7ccd5
YM
4565 struct input_event *bufp;
4566{
4567 struct frame *frame;
4568
3354caee 4569 frame = mac_window_to_frame ((WindowRef) event->message);
7ca7ccd5
YM
4570 if (! frame)
4571 return;
4572
4573 /* On Mac, this is only called from focus events, so no switch needed. */
4574 mac_focus_changed ((event->modifiers & activeFlag),
4575 dpyinfo, frame, bufp);
4576}
4577
4578
f9e65eb3 4579/* Handle an event saying the mouse has moved out of an Emacs frame. */
1a578e9b 4580
f9e65eb3
KS
4581void
4582x_mouse_leave (dpyinfo)
4583 struct x_display_info *dpyinfo;
1a578e9b 4584{
f9e65eb3 4585 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
1a578e9b
AC
4586}
4587
f9e65eb3
KS
4588/* The focus has changed, or we have redirected a frame's focus to
4589 another frame (this happens when a frame uses a surrogate
4590 mini-buffer frame). Shift the highlight as appropriate.
1a578e9b 4591
f9e65eb3
KS
4592 The FRAME argument doesn't necessarily have anything to do with which
4593 frame is being highlighted or un-highlighted; we only use it to find
4594 the appropriate X display info. */
1a578e9b
AC
4595
4596static void
f9e65eb3 4597XTframe_rehighlight (frame)
1a578e9b
AC
4598 struct frame *frame;
4599{
1a578e9b
AC
4600 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4601}
4602
4603static void
4604x_frame_rehighlight (dpyinfo)
4605 struct x_display_info *dpyinfo;
4606{
4607 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4608
4609 if (dpyinfo->x_focus_frame)
4610 {
4611 dpyinfo->x_highlight_frame
8e50cc2d 4612 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
1a578e9b
AC
4613 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4614 : dpyinfo->x_focus_frame);
4615 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4616 {
4617 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4618 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4619 }
4620 }
4621 else
4622 dpyinfo->x_highlight_frame = 0;
4623
4624 if (dpyinfo->x_highlight_frame != old_highlight)
4625 {
4626 if (old_highlight)
4627 frame_unhighlight (old_highlight);
4628 if (dpyinfo->x_highlight_frame)
4629 frame_highlight (dpyinfo->x_highlight_frame);
4630 }
4631}
4632
4633
4634\f
1a578e9b
AC
4635/* Convert a keysym to its name. */
4636
4637char *
4638x_get_keysym_name (keysym)
4639 int keysym;
4640{
4641 char *value;
4642
4643 BLOCK_INPUT;
4644#if 0
4645 value = XKeysymToString (keysym);
4646#else
4647 value = 0;
4648#endif
4649 UNBLOCK_INPUT;
4650
4651 return value;
4652}
4653
4654
4655\f
f9e65eb3
KS
4656/* Function to report a mouse movement to the mainstream Emacs code.
4657 The input handler calls this.
4658
4659 We have received a mouse movement event, which is given in *event.
4660 If the mouse is over a different glyph than it was last time, tell
4661 the mainstream emacs code by setting mouse_moved. If not, ask for
4662 another motion event, so we can check again the next time it moves. */
1a578e9b 4663
f9e65eb3
KS
4664static Point last_mouse_motion_position;
4665static Lisp_Object last_mouse_motion_frame;
1a578e9b 4666
af1229d9 4667static int
f9e65eb3
KS
4668note_mouse_movement (frame, pos)
4669 FRAME_PTR frame;
4670 Point *pos;
1a578e9b 4671{
50bf7673 4672 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
f9e65eb3
KS
4673#if TARGET_API_MAC_CARBON
4674 Rect r;
4675#endif
1a578e9b 4676
f9e65eb3
KS
4677 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4678 last_mouse_motion_position = *pos;
4679 XSETFRAME (last_mouse_motion_frame, frame);
4680
6a0ace5b 4681 if (frame == dpyinfo->mouse_face_mouse_frame
f9e65eb3 4682#if TARGET_API_MAC_CARBON
6a0ace5b 4683 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
f9e65eb3 4684#else
6a0ace5b 4685 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
f9e65eb3 4686#endif
6a0ace5b 4687 )
f9e65eb3 4688 {
6a0ace5b
YM
4689 /* This case corresponds to LeaveNotify in X11. If we move
4690 outside the frame, then we're certainly no longer on any text
4691 in the frame. */
4692 clear_mouse_face (dpyinfo);
4693 dpyinfo->mouse_face_mouse_frame = 0;
4694 if (!dpyinfo->grabbed)
80ca7302 4695 FRAME_RIF (frame)->define_frame_cursor (frame,
6a0ace5b 4696 frame->output_data.mac->nontext_cursor);
f9e65eb3 4697 }
6a0ace5b 4698
f9e65eb3 4699 /* Has the mouse moved off the glyph it was on at the last sighting? */
05f7d868
YM
4700 if (frame != last_mouse_glyph_frame
4701 || !PtInRect (*pos, &last_mouse_glyph))
f9e65eb3
KS
4702 {
4703 frame->mouse_moved = 1;
4704 last_mouse_scroll_bar = Qnil;
4705 note_mouse_highlight (frame, pos->h, pos->v);
e2570d37
KS
4706 /* Remember which glyph we're now on. */
4707 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
05f7d868 4708 last_mouse_glyph_frame = frame;
af1229d9 4709 return 1;
f9e65eb3 4710 }
af1229d9
YM
4711
4712 return 0;
1a578e9b
AC
4713}
4714
1a578e9b 4715\f
f9e65eb3
KS
4716/************************************************************************
4717 Mouse Face
4718 ************************************************************************/
4719
f9e65eb3
KS
4720/* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4721
4722static void
4723redo_mouse_highlight ()
4724{
4725 if (!NILP (last_mouse_motion_frame)
4726 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4727 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4728 last_mouse_motion_position.h,
4729 last_mouse_motion_position.v);
4730}
4731
4732
7ca7ccd5
YM
4733static struct frame *
4734mac_focus_frame (dpyinfo)
4735 struct mac_display_info *dpyinfo;
50bf7673 4736{
7ca7ccd5
YM
4737 if (dpyinfo->x_focus_frame)
4738 return dpyinfo->x_focus_frame;
4739 else
4740 /* Mac version may get events, such as a menu bar click, even when
4741 all the frames are invisible. In this case, we regard the
4742 event came to the selected frame. */
4743 return SELECTED_FRAME ();
50bf7673
ST
4744}
4745
50bf7673 4746
1a578e9b 4747/* Return the current position of the mouse.
e2570d37 4748 *FP should be a frame which indicates which display to ask about.
1a578e9b 4749
e2570d37
KS
4750 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4751 and *PART to the frame, window, and scroll bar part that the mouse
4752 is over. Set *X and *Y to the portion and whole of the mouse's
1a578e9b
AC
4753 position on the scroll bar.
4754
e2570d37
KS
4755 If the mouse movement started elsewhere, set *FP to the frame the
4756 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
1a578e9b
AC
4757 the mouse is over.
4758
e2570d37 4759 Set *TIME to the server time-stamp for the time at which the mouse
1a578e9b
AC
4760 was at this position.
4761
4762 Don't store anything if we don't have a valid set of values to report.
4763
4764 This clears the mouse_moved flag, so we can wait for the next mouse
4765 movement. */
4766
e0f712ba 4767static void
1a578e9b
AC
4768XTmouse_position (fp, insist, bar_window, part, x, y, time)
4769 FRAME_PTR *fp;
4770 int insist;
4771 Lisp_Object *bar_window;
4772 enum scroll_bar_part *part;
4773 Lisp_Object *x, *y;
4774 unsigned long *time;
4775{
e2570d37 4776 FRAME_PTR f1;
1a578e9b
AC
4777
4778 BLOCK_INPUT;
4779
4780 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4781 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4782 else
4783 {
e2570d37
KS
4784 Lisp_Object frame, tail;
4785
1a578e9b
AC
4786 /* Clear the mouse-moved flag for every frame on this display. */
4787 FOR_EACH_FRAME (tail, frame)
e2570d37 4788 XFRAME (frame)->mouse_moved = 0;
1a578e9b
AC
4789
4790 last_mouse_scroll_bar = Qnil;
4791
e2570d37
KS
4792 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4793 && FRAME_LIVE_P (last_mouse_frame))
4794 f1 = last_mouse_frame;
4795 else
4796 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
1a578e9b 4797
e2570d37
KS
4798 if (f1)
4799 {
4800 /* Ok, we found a frame. Store all the values.
4801 last_mouse_glyph is a rectangle used to reduce the
4802 generation of mouse events. To not miss any motion
4803 events, we must divide the frame into rectangles of the
4804 size of the smallest character that could be displayed
4805 on it, i.e. into the same rectangles that matrices on
4806 the frame are divided into. */
4807 Point mouse_pos;
4808
7adf3143
YM
4809#if TARGET_API_MAC_CARBON
4810 GetGlobalMouse (&mouse_pos);
4811 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4812 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4813#else
e2570d37
KS
4814 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4815 GetMouse (&mouse_pos);
7adf3143 4816#endif
e2570d37
KS
4817 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4818 &last_mouse_glyph);
05f7d868 4819 last_mouse_glyph_frame = f1;
e2570d37
KS
4820
4821 *bar_window = Qnil;
4822 *part = 0;
4823 *fp = f1;
4824 XSETINT (*x, mouse_pos.h);
4825 XSETINT (*y, mouse_pos.v);
4826 *time = last_mouse_movement_time;
4827 }
1a578e9b 4828 }
177c0ea7 4829
1a578e9b
AC
4830 UNBLOCK_INPUT;
4831}
4832
4833\f
5b8b73ff
YM
4834/************************************************************************
4835 Toolkit scroll bars
4836 ************************************************************************/
4837
4838#ifdef USE_TOOLKIT_SCROLL_BARS
4839
4840static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4841static OSStatus install_scroll_bar_timer P_ ((void));
4842static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
e6bdfa32 4843static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
5b8b73ff 4844static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
5b8b73ff 4845 struct input_event *));
3354caee 4846static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
a3510ffa 4847 Rect *));
5b8b73ff 4848static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
e6509087 4849 ControlPartCode, Point,
5b8b73ff
YM
4850 struct input_event *));
4851static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
5b8b73ff 4852 struct input_event *));
3354caee 4853static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
95dfb192 4854 Point, struct input_event *));
5b8b73ff
YM
4855static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4856 int, int, int));
4857
4858/* Last scroll bar part sent in x_scroll_bar_handle_*. */
4859
4860static int last_scroll_bar_part;
4861
4862static EventLoopTimerRef scroll_bar_timer;
4863
4864static int scroll_bar_timer_event_posted_p;
4865
4866#define SCROLL_BAR_FIRST_DELAY 0.5
4867#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4868
4869static pascal void
4870scroll_bar_timer_callback (timer, data)
4871 EventLoopTimerRef timer;
4872 void *data;
4873{
a733ef16 4874 OSStatus err;
5b8b73ff 4875
a733ef16 4876 err = mac_post_mouse_moved_event ();
5b8b73ff
YM
4877 if (err == noErr)
4878 scroll_bar_timer_event_posted_p = 1;
5b8b73ff
YM
4879}
4880
4881static OSStatus
4882install_scroll_bar_timer ()
4883{
4884 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4885
4886 if (scroll_bar_timer_callbackUPP == NULL)
4887 scroll_bar_timer_callbackUPP =
4888 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4889
4890 if (scroll_bar_timer == NULL)
4891 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4892 kEventDurationForever as delays. */
4893 return
4894 InstallEventLoopTimer (GetCurrentEventLoop (),
4895 kEventDurationForever, kEventDurationForever,
4896 scroll_bar_timer_callbackUPP, NULL,
4897 &scroll_bar_timer);
4898}
4899
4900static OSStatus
4901set_scroll_bar_timer (delay)
4902 EventTimerInterval delay;
4903{
4904 if (scroll_bar_timer == NULL)
4905 install_scroll_bar_timer ();
4906
4907 scroll_bar_timer_event_posted_p = 0;
4908
4909 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4910}
4911
4912static int
4913control_part_code_to_scroll_bar_part (part_code)
4914 ControlPartCode part_code;
4915{
4916 switch (part_code)
4917 {
4918 case kControlUpButtonPart: return scroll_bar_up_arrow;
4919 case kControlDownButtonPart: return scroll_bar_down_arrow;
4920 case kControlPageUpPart: return scroll_bar_above_handle;
4921 case kControlPageDownPart: return scroll_bar_below_handle;
4922 case kControlIndicatorPart: return scroll_bar_handle;
4923 }
4924
4925 return -1;
4926}
f9e65eb3
KS
4927
4928static void
95dfb192 4929construct_scroll_bar_click (bar, part, bufp)
5b8b73ff
YM
4930 struct scroll_bar *bar;
4931 int part;
5b8b73ff
YM
4932 struct input_event *bufp;
4933{
4934 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4935 bufp->frame_or_window = bar->window;
4936 bufp->arg = Qnil;
4937 bufp->part = part;
4938 bufp->code = 0;
5b8b73ff
YM
4939 XSETINT (bufp->x, 0);
4940 XSETINT (bufp->y, 0);
4941 bufp->modifiers = 0;
4942}
4943
a3510ffa 4944static OSStatus
e6bdfa32 4945get_control_part_bounds (ch, part_code, rect)
3354caee 4946 ControlRef ch;
5b8b73ff
YM
4947 ControlPartCode part_code;
4948 Rect *rect;
4949{
4950 RgnHandle region = NewRgn ();
4951 OSStatus err;
4952
4953 err = GetControlRegion (ch, part_code, region);
4954 if (err == noErr)
4955 GetRegionBounds (region, rect);
4956 DisposeRgn (region);
4957
4958 return err;
4959}
4960
4961static void
e6509087 4962x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
5b8b73ff
YM
4963 struct scroll_bar *bar;
4964 ControlPartCode part_code;
e6509087 4965 Point mouse_pos;
5b8b73ff
YM
4966 struct input_event *bufp;
4967{
4968 int part = control_part_code_to_scroll_bar_part (part_code);
4969
4970 if (part < 0)
4971 return;
4972
4973 if (part != scroll_bar_handle)
4974 {
95dfb192 4975 construct_scroll_bar_click (bar, part, bufp);
3354caee 4976 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5b8b73ff 4977 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
e6509087
YM
4978 bar->dragging = Qnil;
4979 }
4980 else
4981 {
4982 Rect r;
4983
3354caee 4984 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
e6509087
YM
4985 kControlIndicatorPart, &r);
4986 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
5b8b73ff
YM
4987 }
4988
4989 last_scroll_bar_part = part;
5b8b73ff
YM
4990 tracked_scroll_bar = bar;
4991}
4992
4993static void
95dfb192 4994x_scroll_bar_handle_release (bar, bufp)
5b8b73ff 4995 struct scroll_bar *bar;
5b8b73ff
YM
4996 struct input_event *bufp;
4997{
4998 if (last_scroll_bar_part != scroll_bar_handle
e6509087 4999 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
95dfb192 5000 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
5b8b73ff 5001
3354caee 5002 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5b8b73ff
YM
5003 set_scroll_bar_timer (kEventDurationForever);
5004
5005 last_scroll_bar_part = -1;
5006 bar->dragging = Qnil;
5007 tracked_scroll_bar = NULL;
5008}
5009
5010static void
95dfb192 5011x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
3354caee 5012 WindowRef win;
5b8b73ff
YM
5013 struct scroll_bar *bar;
5014 Point mouse_pos;
5b8b73ff
YM
5015 struct input_event *bufp;
5016{
3354caee 5017 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5b8b73ff
YM
5018
5019 if (last_scroll_bar_part == scroll_bar_handle)
5020 {
5021 int top, top_range;
5022 Rect r;
5023
3354caee 5024 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
e6bdfa32 5025 kControlIndicatorPart, &r);
5b8b73ff 5026
e6509087
YM
5027 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
5028 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
5b8b73ff
YM
5029
5030 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
4d5724e5 5031 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
95dfb192 5032
5b8b73ff
YM
5033 if (top < 0)
5034 top = 0;
5035 if (top > top_range)
5036 top = top_range;
5037
95dfb192 5038 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
5b8b73ff
YM
5039 XSETINT (bufp->x, top);
5040 XSETINT (bufp->y, top_range);
5041 }
5042 else
5043 {
5044 ControlPartCode part_code;
5045 int unhilite_p = 0, part;
5046
5047 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
5048 unhilite_p = 1;
5049 else
5050 {
5051 part = control_part_code_to_scroll_bar_part (part_code);
5052
5053 switch (last_scroll_bar_part)
5054 {
5055 case scroll_bar_above_handle:
5056 case scroll_bar_below_handle:
5057 if (part != scroll_bar_above_handle
5058 && part != scroll_bar_below_handle)
5059 unhilite_p = 1;
5060 break;
5061
5062 case scroll_bar_up_arrow:
5063 case scroll_bar_down_arrow:
5064 if (part != scroll_bar_up_arrow
5065 && part != scroll_bar_down_arrow)
5066 unhilite_p = 1;
5067 break;
5068 }
5069 }
5070
5071 if (unhilite_p)
3354caee 5072 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5b8b73ff
YM
5073 else if (part != last_scroll_bar_part
5074 || scroll_bar_timer_event_posted_p)
5075 {
95dfb192 5076 construct_scroll_bar_click (bar, part, bufp);
5b8b73ff 5077 last_scroll_bar_part = part;
3354caee 5078 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5b8b73ff
YM
5079 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
5080 }
5081 }
5082}
5083
5084/* Set the thumb size and position of scroll bar BAR. We are currently
5085 displaying PORTION out of a whole WHOLE, and our position POSITION. */
5086
5087static void
5088x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
5089 struct scroll_bar *bar;
5090 int portion, position, whole;
f9e65eb3 5091{
3354caee 5092 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5b8b73ff
YM
5093 int value, viewsize, maximum;
5094
a3510ffa
YM
5095 if (XINT (bar->track_height) == 0)
5096 return;
5097
4d5724e5 5098 if (whole <= portion)
5b8b73ff 5099 value = 0, viewsize = 1, maximum = 0;
f9e65eb3 5100 else
5b8b73ff 5101 {
4d5724e5
YM
5102 float scale;
5103
5104 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
5105 scale = (float) maximum / (whole - portion);
5106 value = position * scale + 0.5f;
5107 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
5b8b73ff
YM
5108 }
5109
5110 BLOCK_INPUT;
5111
a3510ffa
YM
5112 if (GetControlViewSize (ch) != viewsize
5113 || GetControl32BitValue (ch) != value
5114 || GetControl32BitMaximum (ch) != maximum)
5b574e69
YM
5115 {
5116 /* Temporarily hide the scroll bar to avoid multiple redraws. */
5117 SetControlVisibility (ch, false, false);
b6e3efe0 5118
5b574e69
YM
5119 SetControl32BitMaximum (ch, maximum);
5120 SetControl32BitValue (ch, value);
5121 SetControlViewSize (ch, viewsize);
5b8b73ff 5122
5b574e69
YM
5123 SetControlVisibility (ch, true, true);
5124 }
5b8b73ff
YM
5125
5126 UNBLOCK_INPUT;
f9e65eb3
KS
5127}
5128
5b8b73ff
YM
5129#endif /* USE_TOOLKIT_SCROLL_BARS */
5130
5131
f9e65eb3 5132\f
1a578e9b
AC
5133/************************************************************************
5134 Scroll bars, general
5135 ************************************************************************/
177c0ea7 5136
1a578e9b
AC
5137/* Create a scroll bar and return the scroll bar vector for it. W is
5138 the Emacs window on which to create the scroll bar. TOP, LEFT,
e0f712ba 5139 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
1a578e9b
AC
5140 scroll bar. */
5141
5142static struct scroll_bar *
5143x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5144 struct window *w;
5145 int top, left, width, height, disp_top, disp_height;
5146{
5147 struct frame *f = XFRAME (w->frame);
5148 struct scroll_bar *bar
5149 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5150 Rect r;
3354caee 5151 ControlRef ch;
1a578e9b
AC
5152
5153 BLOCK_INPUT;
5154
5155 r.left = left;
5156 r.top = disp_top;
5157 r.right = left + width;
5158 r.bottom = disp_top + disp_height;
177c0ea7 5159
4ea08bbf
YM
5160#if USE_CG_DRAWING
5161 mac_prepare_for_quickdraw (f);
5162#endif
b15325b2 5163#if TARGET_API_MAC_CARBON
a3510ffa 5164 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
70385fe6 5165#ifdef USE_TOOLKIT_SCROLL_BARS
a3510ffa
YM
5166 false,
5167#else
5168 width < disp_height,
5169#endif
95dfb192 5170 0, 0, 0, kControlScrollBarProc, (long) bar);
e0f712ba 5171#else
95dfb192
YM
5172 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5173 0, 0, 0, scrollBarProc, (long) bar);
e0f712ba 5174#endif
3354caee 5175 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
1a578e9b
AC
5176
5177 XSETWINDOW (bar->window, w);
5178 XSETINT (bar->top, top);
5179 XSETINT (bar->left, left);
5180 XSETINT (bar->width, width);
5181 XSETINT (bar->height, height);
5182 XSETINT (bar->start, 0);
5183 XSETINT (bar->end, 0);
5184 bar->dragging = Qnil;
c6829f81
YM
5185#ifdef MAC_OSX
5186 bar->fringe_extended_p = Qnil;
5187#endif
1ec6ded9 5188 bar->redraw_needed_p = Qnil;
5b8b73ff
YM
5189#ifdef USE_TOOLKIT_SCROLL_BARS
5190 bar->track_top = Qnil;
5191 bar->track_height = Qnil;
4d5724e5 5192 bar->min_handle = Qnil;
5b8b73ff 5193#endif
1a578e9b
AC
5194
5195 /* Add bar to its frame's list of scroll bars. */
5196 bar->next = FRAME_SCROLL_BARS (f);
5197 bar->prev = Qnil;
5198 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5199 if (!NILP (bar->next))
5200 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5201
5202 UNBLOCK_INPUT;
5203 return bar;
5204}
5205
5206
5207/* Draw BAR's handle in the proper position.
177c0ea7 5208
1a578e9b
AC
5209 If the handle is already drawn from START to END, don't bother
5210 redrawing it, unless REBUILD is non-zero; in that case, always
5211 redraw it. (REBUILD is handy for drawing the handle after expose
5212 events.)
5213
5214 Normally, we want to constrain the start and end of the handle to
5215 fit inside its rectangle, but if the user is dragging the scroll
5216 bar handle, we want to let them drag it down all the way, so that
5217 the bar's top is as far down as it goes; otherwise, there's no way
5218 to move to the very end of the buffer. */
5219
5b8b73ff
YM
5220#ifndef USE_TOOLKIT_SCROLL_BARS
5221
1a578e9b
AC
5222static void
5223x_scroll_bar_set_handle (bar, start, end, rebuild)
5224 struct scroll_bar *bar;
5225 int start, end;
5226 int rebuild;
5227{
5228 int dragging = ! NILP (bar->dragging);
3354caee 5229 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
1a578e9b 5230 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
e0f712ba
AC
5231 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5232 int length = end - start;
1a578e9b
AC
5233
5234 /* If the display is already accurate, do nothing. */
5235 if (! rebuild
5236 && start == XINT (bar->start)
5237 && end == XINT (bar->end))
5238 return;
5239
5240 BLOCK_INPUT;
5241
e0f712ba
AC
5242 /* Make sure the values are reasonable, and try to preserve the
5243 distance between start and end. */
5244 if (start < 0)
5245 start = 0;
5246 else if (start > top_range)
5247 start = top_range;
5248 end = start + length;
177c0ea7 5249
e0f712ba
AC
5250 if (end < start)
5251 end = start;
5252 else if (end > top_range && ! dragging)
5253 end = top_range;
5254
5255 /* Store the adjusted setting in the scroll bar. */
5256 XSETINT (bar->start, start);
5257 XSETINT (bar->end, end);
5258
5259 /* Clip the end position, just for display. */
5260 if (end > top_range)
5261 end = top_range;
5262
5263 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5264 top positions, to make sure the handle is always at least that
5265 many pixels tall. */
5266 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5267
5268 SetControlMinimum (ch, 0);
5269 /* Don't inadvertently activate deactivated scroll bars */
5270 if (GetControlMaximum (ch) != -1)
5271 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5272 - (end - start));
5273 SetControlValue (ch, start);
5274#if TARGET_API_MAC_CARBON
5275 SetControlViewSize (ch, end - start);
1a578e9b 5276#endif
1a578e9b
AC
5277
5278 UNBLOCK_INPUT;
5279}
5280
5b8b73ff 5281#endif /* !USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5282
5283/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5284 nil. */
5285
5286static void
5287x_scroll_bar_remove (bar)
5288 struct scroll_bar *bar;
5289{
5290 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
e0f712ba 5291
1a578e9b
AC
5292 BLOCK_INPUT;
5293
4ea08bbf
YM
5294#if USE_CG_DRAWING
5295 mac_prepare_for_quickdraw (f);
5296#endif
1a578e9b 5297 /* Destroy the Mac scroll bar control */
3354caee 5298 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
1a578e9b
AC
5299
5300 /* Disassociate this scroll bar from its window. */
5301 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5302
5303 UNBLOCK_INPUT;
5304}
5305
95dfb192 5306
1a578e9b
AC
5307/* Set the handle of the vertical scroll bar for WINDOW to indicate
5308 that we are displaying PORTION characters out of a total of WHOLE
5309 characters, starting at POSITION. If WINDOW has no scroll bar,
5310 create one. */
95dfb192 5311
1a578e9b
AC
5312static void
5313XTset_vertical_scroll_bar (w, portion, whole, position)
5314 struct window *w;
5315 int portion, whole, position;
5316{
5317 struct frame *f = XFRAME (w->frame);
5318 struct scroll_bar *bar;
5319 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
f1a83aab 5320 int window_y, window_height;
c6829f81
YM
5321#ifdef MAC_OSX
5322 int fringe_extended_p;
5323#endif
1a578e9b
AC
5324
5325 /* Get window dimensions. */
f1a83aab 5326 window_box (w, -1, 0, &window_y, 0, &window_height);
1a578e9b 5327 top = window_y;
f1a83aab 5328 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
1a578e9b
AC
5329 height = window_height;
5330
5331 /* Compute the left edge of the scroll bar area. */
f1a83aab 5332 left = WINDOW_SCROLL_BAR_AREA_X (w);
1a578e9b
AC
5333
5334 /* Compute the width of the scroll bar which might be less than
5335 the width of the area reserved for the scroll bar. */
f1a83aab
KS
5336 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5337 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
1a578e9b
AC
5338 else
5339 sb_width = width;
5340
5341 /* Compute the left edge of the scroll bar. */
f1a83aab 5342 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
c6829f81 5343 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
1a578e9b 5344 else
c6829f81 5345 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
177c0ea7 5346
1a578e9b
AC
5347 /* Adjustments according to Inside Macintosh to make it look nice */
5348 disp_top = top;
5349 disp_height = height;
a3510ffa 5350#ifdef MAC_OS8
1a578e9b
AC
5351 if (disp_top == 0)
5352 {
5353 disp_top = -1;
5354 disp_height++;
5355 }
f1a83aab 5356 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
1a578e9b
AC
5357 {
5358 disp_top++;
5359 disp_height--;
5360 }
177c0ea7 5361
f1a83aab 5362 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
1a578e9b 5363 sb_left++;
a3510ffa 5364#endif
177c0ea7 5365
c6829f81
YM
5366#ifdef MAC_OSX
5367 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5368 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5369 && WINDOW_LEFT_FRINGE_WIDTH (w)
5370 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5371 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5372 else
5373 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5374 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5375 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5376 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5377#endif
5378
1a578e9b
AC
5379 /* Does the scroll bar exist yet? */
5380 if (NILP (w->vertical_scroll_bar))
5381 {
5382 BLOCK_INPUT;
c6829f81
YM
5383#ifdef MAC_OSX
5384 if (fringe_extended_p)
5385 mac_clear_area (f, sb_left, top, sb_width, height);
5386 else
5387#endif
5388 mac_clear_area (f, left, top, width, height);
1a578e9b
AC
5389 UNBLOCK_INPUT;
5390 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5391 disp_height);
5392 XSETVECTOR (w->vertical_scroll_bar, bar);
5393 }
5394 else
5395 {
5396 /* It may just need to be moved and resized. */
3354caee 5397 ControlRef ch;
177c0ea7 5398
1a578e9b 5399 bar = XSCROLL_BAR (w->vertical_scroll_bar);
3354caee 5400 ch = SCROLL_BAR_CONTROL_REF (bar);
1a578e9b
AC
5401
5402 BLOCK_INPUT;
5403
5404 /* If already correctly positioned, do nothing. */
1ec6ded9
YM
5405 if (XINT (bar->left) == sb_left
5406 && XINT (bar->top) == top
5407 && XINT (bar->width) == sb_width
1bad168e 5408 && XINT (bar->height) == height
c6829f81 5409#ifdef MAC_OSX
1bad168e 5410 && !NILP (bar->fringe_extended_p) == fringe_extended_p
c6829f81 5411#endif
1bad168e 5412 )
1ec6ded9
YM
5413 {
5414 if (!NILP (bar->redraw_needed_p))
5415 {
5416#if USE_CG_DRAWING
5417 mac_prepare_for_quickdraw (f);
5418#endif
8b329dba 5419 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
1ec6ded9
YM
5420 }
5421 }
5422 else
e6bdfa32 5423 {
e4f5e019
YM
5424 /* Since toolkit scroll bars are smaller than the space reserved
5425 for them on the frame, we have to clear "under" them. */
c6829f81
YM
5426#ifdef MAC_OSX
5427 if (fringe_extended_p)
5428 mac_clear_area (f, sb_left, top, sb_width, height);
5429 else
5430#endif
5431 mac_clear_area (f, left, top, width, height);
1a578e9b 5432
4ea08bbf
YM
5433#if USE_CG_DRAWING
5434 mac_prepare_for_quickdraw (f);
5435#endif
1a578e9b
AC
5436 HideControl (ch);
5437 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5438 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5439 disp_height);
a3510ffa 5440#ifndef USE_TOOLKIT_SCROLL_BARS
95dfb192
YM
5441 if (sb_width < disp_height)
5442 ShowControl (ch);
a3510ffa 5443#endif
177c0ea7 5444
1a578e9b
AC
5445 /* Remember new settings. */
5446 XSETINT (bar->left, sb_left);
5447 XSETINT (bar->top, top);
5448 XSETINT (bar->width, sb_width);
5449 XSETINT (bar->height, height);
5b8b73ff
YM
5450#ifdef USE_TOOLKIT_SCROLL_BARS
5451 bar->track_top = Qnil;
5452 bar->track_height = Qnil;
4d5724e5 5453 bar->min_handle = Qnil;
5b8b73ff 5454#endif
1a578e9b
AC
5455 }
5456
5457 UNBLOCK_INPUT;
5458 }
5459
c6829f81
YM
5460#ifdef MAC_OSX
5461 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5462#endif
5463
1ec6ded9
YM
5464 bar->redraw_needed_p = Qnil;
5465
5b8b73ff
YM
5466#ifdef USE_TOOLKIT_SCROLL_BARS
5467 if (NILP (bar->track_top))
f93e4d4f 5468 {
7a844a76
YM
5469 if (sb_width >= disp_height
5470#ifdef MAC_OSX
5471 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5472#endif
5473 )
f93e4d4f
YM
5474 {
5475 XSETINT (bar->track_top, 0);
5476 XSETINT (bar->track_height, 0);
4d5724e5 5477 XSETINT (bar->min_handle, 0);
f93e4d4f
YM
5478 }
5479 else
5480 {
3354caee 5481 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
f93e4d4f 5482 Rect r0, r1;
5b8b73ff 5483
f93e4d4f 5484 BLOCK_INPUT;
5b8b73ff 5485
f93e4d4f 5486 SetControl32BitMinimum (ch, 0);
4d5724e5 5487 SetControl32BitMaximum (ch, 1 << 30);
f93e4d4f 5488 SetControlViewSize (ch, 1);
5b8b73ff 5489
f93e4d4f
YM
5490 /* Move the scroll bar thumb to the top. */
5491 SetControl32BitValue (ch, 0);
5492 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5b8b73ff 5493
f93e4d4f 5494 /* Move the scroll bar thumb to the bottom. */
4d5724e5 5495 SetControl32BitValue (ch, 1 << 30);
f93e4d4f 5496 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5b8b73ff 5497
f93e4d4f
YM
5498 UnionRect (&r0, &r1, &r0);
5499 XSETINT (bar->track_top, r0.top);
5500 XSETINT (bar->track_height, r0.bottom - r0.top);
4d5724e5 5501 XSETINT (bar->min_handle, r1.bottom - r1.top);
5b8b73ff 5502
f93e4d4f
YM
5503 /* Don't show the scroll bar if its height is not enough to
5504 display the scroll bar thumb. */
5505 if (r0.bottom - r0.top > 0)
5506 ShowControl (ch);
a3510ffa 5507
f93e4d4f
YM
5508 UNBLOCK_INPUT;
5509 }
5510 }
5b8b73ff
YM
5511
5512 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5513#else /* not USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5514 /* Set the scroll bar's current state, unless we're currently being
5515 dragged. */
5516 if (NILP (bar->dragging))
5517 {
5518 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5519
5520 if (whole == 0)
5521 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5522 else
5523 {
5524 int start = ((double) position * top_range) / whole;
5525 int end = ((double) (position + portion) * top_range) / whole;
5526 x_scroll_bar_set_handle (bar, start, end, 0);
5527 }
5528 }
5b8b73ff 5529#endif /* not USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5530}
5531
5532
5533/* The following three hooks are used when we're doing a thorough
5534 redisplay of the frame. We don't explicitly know which scroll bars
5535 are going to be deleted, because keeping track of when windows go
5536 away is a real pain - "Can you say set-window-configuration, boys
5537 and girls?" Instead, we just assert at the beginning of redisplay
5538 that *all* scroll bars are to be removed, and then save a scroll bar
5539 from the fiery pit when we actually redisplay its window. */
5540
5541/* Arrange for all scroll bars on FRAME to be removed at the next call
5542 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5543 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5544
5545static void
5546XTcondemn_scroll_bars (frame)
5547 FRAME_PTR frame;
5548{
5549 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5550 while (! NILP (FRAME_SCROLL_BARS (frame)))
5551 {
5552 Lisp_Object bar;
5553 bar = FRAME_SCROLL_BARS (frame);
5554 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5555 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5556 XSCROLL_BAR (bar)->prev = Qnil;
5557 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5558 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5559 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5560 }
5561}
5562
e0f712ba 5563
1a578e9b
AC
5564/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5565 Note that WINDOW isn't necessarily condemned at all. */
e0f712ba 5566
1a578e9b
AC
5567static void
5568XTredeem_scroll_bar (window)
5569 struct window *window;
5570{
5571 struct scroll_bar *bar;
95dfb192 5572 struct frame *f;
1a578e9b
AC
5573
5574 /* We can't redeem this window's scroll bar if it doesn't have one. */
5575 if (NILP (window->vertical_scroll_bar))
5576 abort ();
5577
5578 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5579
5580 /* Unlink it from the condemned list. */
95dfb192
YM
5581 f = XFRAME (WINDOW_FRAME (window));
5582 if (NILP (bar->prev))
5583 {
5584 /* If the prev pointer is nil, it must be the first in one of
5585 the lists. */
5586 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5587 /* It's not condemned. Everything's fine. */
5588 return;
5589 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5590 window->vertical_scroll_bar))
5591 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5592 else
5593 /* If its prev pointer is nil, it must be at the front of
5594 one or the other! */
5595 abort ();
5596 }
5597 else
5598 XSCROLL_BAR (bar->prev)->next = bar->next;
1a578e9b 5599
95dfb192
YM
5600 if (! NILP (bar->next))
5601 XSCROLL_BAR (bar->next)->prev = bar->prev;
1a578e9b 5602
95dfb192
YM
5603 bar->next = FRAME_SCROLL_BARS (f);
5604 bar->prev = Qnil;
5605 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5606 if (! NILP (bar->next))
5607 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
1a578e9b
AC
5608}
5609
5610/* Remove all scroll bars on FRAME that haven't been saved since the
5611 last call to `*condemn_scroll_bars_hook'. */
5612
5613static void
5614XTjudge_scroll_bars (f)
5615 FRAME_PTR f;
5616{
5617 Lisp_Object bar, next;
5618
5619 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5620
5621 /* Clear out the condemned list now so we won't try to process any
5622 more events on the hapless scroll bars. */
5623 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5624
5625 for (; ! NILP (bar); bar = next)
5626 {
5627 struct scroll_bar *b = XSCROLL_BAR (bar);
5628
5629 x_scroll_bar_remove (b);
5630
5631 next = b->next;
5632 b->next = b->prev = Qnil;
5633 }
5634
5635 /* Now there should be no references to the condemned scroll bars,
5636 and they should get garbage-collected. */
5637}
5638
5639
1a578e9b 5640/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3b8f9651 5641 is set to something other than NO_EVENT, it is enqueued.
1a578e9b
AC
5642
5643 This may be called from a signal handler, so we have to ignore GC
5644 mark bits. */
5645
5646static void
5647x_scroll_bar_handle_click (bar, part_code, er, bufp)
5648 struct scroll_bar *bar;
e6bdfa32 5649 ControlPartCode part_code;
369a7a37 5650 const EventRecord *er;
1a578e9b
AC
5651 struct input_event *bufp;
5652{
50bf7673
ST
5653 int win_y, top_range;
5654
8e50cc2d 5655 if (! WINDOWP (bar->window))
1a578e9b
AC
5656 abort ();
5657
3b8f9651 5658 bufp->kind = SCROLL_BAR_CLICK_EVENT;
1a578e9b
AC
5659 bufp->frame_or_window = bar->window;
5660 bufp->arg = Qnil;
5661
5662 bar->dragging = Qnil;
177c0ea7 5663
1a578e9b
AC
5664 switch (part_code)
5665 {
5666 case kControlUpButtonPart:
5667 bufp->part = scroll_bar_up_arrow;
5668 break;
5669 case kControlDownButtonPart:
5670 bufp->part = scroll_bar_down_arrow;
5671 break;
5672 case kControlPageUpPart:
5673 bufp->part = scroll_bar_above_handle;
5674 break;
5675 case kControlPageDownPart:
5676 bufp->part = scroll_bar_below_handle;
5677 break;
b15325b2 5678#if TARGET_API_MAC_CARBON
e0f712ba
AC
5679 default:
5680#else
1a578e9b 5681 case kControlIndicatorPart:
e0f712ba 5682#endif
1a578e9b
AC
5683 if (er->what == mouseDown)
5684 bar->dragging = make_number (0);
5685 XSETVECTOR (last_mouse_scroll_bar, bar);
5686 bufp->part = scroll_bar_handle;
5687 break;
5688 }
50bf7673
ST
5689
5690 win_y = XINT (bufp->y) - XINT (bar->top);
5691 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5692
5693 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5694
5695 win_y -= 24;
5696
5697 if (! NILP (bar->dragging))
5698 win_y -= XINT (bar->dragging);
5699
5700 if (win_y < 0)
5701 win_y = 0;
5702 if (win_y > top_range)
5703 win_y = top_range;
5704
5705 XSETINT (bufp->x, win_y);
5706 XSETINT (bufp->y, top_range);
1a578e9b
AC
5707}
5708
5b8b73ff 5709#ifndef USE_TOOLKIT_SCROLL_BARS
1a578e9b
AC
5710
5711/* Handle some mouse motion while someone is dragging the scroll bar.
5712
5713 This may be called from a signal handler, so we have to ignore GC
5714 mark bits. */
5715
5716static void
5717x_scroll_bar_note_movement (bar, y_pos, t)
5718 struct scroll_bar *bar;
5719 int y_pos;
5720 Time t;
5721{
5722 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5723
5724 last_mouse_movement_time = t;
5725
5726 f->mouse_moved = 1;
5727 XSETVECTOR (last_mouse_scroll_bar, bar);
5728
5729 /* If we're dragging the bar, display it. */
8e50cc2d 5730 if (! NILP (bar->dragging))
1a578e9b
AC
5731 {
5732 /* Where should the handle be now? */
5733 int new_start = y_pos - 24;
5734
5735 if (new_start != XINT (bar->start))
5736 {
5737 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5738
5739 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5740 }
5741 }
5742}
5743
5b8b73ff 5744#endif /* !USE_TOOLKIT_SCROLL_BARS */
1a578e9b 5745
95dfb192
YM
5746/* Return information to the user about the current position of the mouse
5747 on the scroll bar. */
1a578e9b
AC
5748
5749static void
5750x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5751 FRAME_PTR *fp;
5752 Lisp_Object *bar_window;
5753 enum scroll_bar_part *part;
5754 Lisp_Object *x, *y;
5755 unsigned long *time;
5756{
5757 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
3354caee 5758 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
7ca7ccd5 5759#if TARGET_API_MAC_CARBON
3354caee 5760 WindowRef wp = GetControlOwner (ch);
7ca7ccd5 5761#else
3354caee 5762 WindowRef wp = (*ch)->contrlOwner;
7ca7ccd5 5763#endif
1a578e9b 5764 Point mouse_pos;
50bf7673 5765 struct frame *f = mac_window_to_frame (wp);
1a578e9b
AC
5766 int win_y, top_range;
5767
7adf3143
YM
5768#if TARGET_API_MAC_CARBON
5769 GetGlobalMouse (&mouse_pos);
5770 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5771 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5772#else
50bf7673 5773 SetPortWindowPort (wp);
1a578e9b 5774 GetMouse (&mouse_pos);
7adf3143 5775#endif
1a578e9b
AC
5776
5777 win_y = mouse_pos.v - XINT (bar->top);
5778 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5779
5780 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5781
5782 win_y -= 24;
5783
5784 if (! NILP (bar->dragging))
5785 win_y -= XINT (bar->dragging);
5786
5787 if (win_y < 0)
5788 win_y = 0;
5789 if (win_y > top_range)
5790 win_y = top_range;
5791
5792 *fp = f;
5793 *bar_window = bar->window;
5794
5795 if (! NILP (bar->dragging))
5796 *part = scroll_bar_handle;
5797 else if (win_y < XINT (bar->start))
5798 *part = scroll_bar_above_handle;
5799 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5800 *part = scroll_bar_handle;
5801 else
5802 *part = scroll_bar_below_handle;
5803
5804 XSETINT (*x, win_y);
5805 XSETINT (*y, top_range);
5806
5807 f->mouse_moved = 0;
5808 last_mouse_scroll_bar = Qnil;
5809
5810 *time = last_mouse_movement_time;
5811}
e6bdfa32
YM
5812
5813
5814/* The screen has been cleared so we may have changed foreground or
5815 background colors, and the scroll bars may need to be redrawn.
5816 Clear out the scroll bars, and ask for expose events, so we can
5817 redraw them. */
5818
5819void
5820x_scroll_bar_clear (f)
5821 FRAME_PTR f;
5822{
1ec6ded9
YM
5823 Lisp_Object bar;
5824
5825 /* We can have scroll bars even if this is 0,
5826 if we just turned off scroll bar mode.
5827 But in that case we should not clear them. */
5828 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5829 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5830 bar = XSCROLL_BAR (bar)->next)
5831 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
e6bdfa32
YM
5832}
5833
1a578e9b 5834\f
c6829f81
YM
5835/***********************************************************************
5836 Tool-bars
5837 ***********************************************************************/
5838#if USE_MAC_TOOLBAR
5839
5840/* In identifiers such as function/variable names, Emacs tool bar is
5841 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5842
5843#define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5844#define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5845
5846#define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5847#define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5848 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5849#define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5850 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5851#define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5852 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5853
5854static int mac_event_to_emacs_modifiers P_ ((EventRef));
5855static void mac_handle_origin_change P_ ((struct frame *));
5856static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5857 EventRef, void *));
5858
5859static void
5860mac_move_window_with_gravity (f, win_gravity, left, top)
5861 struct frame *f;
5862 int win_gravity;
5863 short left, top;
5864{
5865 Rect inner, outer;
5866
5867 mac_get_window_bounds (f, &inner, &outer);
5868
5869 switch (win_gravity)
5870 {
5871 case NorthWestGravity:
5872 case WestGravity:
5873 case SouthWestGravity:
5874 left += inner.left - outer.left;
5875 break;
5876
5877 case NorthGravity:
5878 case CenterGravity:
5879 case SouthGravity:
5880 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5881 break;
5882
5883 case NorthEastGravity:
5884 case EastGravity:
5885 case SouthEastGravity:
5886 left += inner.right - outer.right;
5887 break;
5888 }
5889
5890 switch (win_gravity)
5891 {
5892 case NorthWestGravity:
5893 case NorthGravity:
5894 case NorthEastGravity:
5895 top += inner.top - outer.top;
5896 break;
5897
5898 case WestGravity:
5899 case CenterGravity:
5900 case EastGravity:
5901 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5902 break;
5903
5904 case SouthWestGravity:
5905 case SouthGravity:
5906 case SouthEastGravity:
5907 top += inner.bottom - outer.bottom;
5908 break;
5909 }
5910
5911 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5912}
5913
5914static void
5915mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5916 struct frame *f;
5917 int win_gravity;
5918 short *left, *top;
5919{
5920 Rect inner, outer;
5921
5922 mac_get_window_bounds (f, &inner, &outer);
5923
5924 switch (win_gravity)
5925 {
5926 case NorthWestGravity:
5927 case WestGravity:
5928 case SouthWestGravity:
5929 *left = outer.left;
5930 break;
5931
5932 case NorthGravity:
5933 case CenterGravity:
5934 case SouthGravity:
5935 *left = outer.left + ((outer.right - outer.left)
5936 - (inner.right - inner.left)) / 2;
5937 break;
5938
5939 case NorthEastGravity:
5940 case EastGravity:
5941 case SouthEastGravity:
5942 *left = outer.right - (inner.right - inner.left);
5943 break;
5944 }
5945
5946 switch (win_gravity)
5947 {
5948 case NorthWestGravity:
5949 case NorthGravity:
5950 case NorthEastGravity:
5951 *top = outer.top;
5952 break;
5953
5954 case WestGravity:
5955 case CenterGravity:
5956 case EastGravity:
5957 *top = outer.top + ((outer.bottom - outer.top)
5958 - (inner.bottom - inner.top)) / 2;
5959 break;
5960
5961 case SouthWestGravity:
5962 case SouthGravity:
5963 case SouthEastGravity:
5964 *top = outer.bottom - (inner.bottom - inner.top);
5965 break;
5966 }
5967}
5968
5969static OSStatus
5970mac_handle_toolbar_event (next_handler, event, data)
5971 EventHandlerCallRef next_handler;
5972 EventRef event;
5973 void *data;
5974{
5975 OSStatus err, result = eventNotHandledErr;
5976
5977 switch (GetEventKind (event))
5978 {
5979 case kEventToolbarGetDefaultIdentifiers:
5980 result = noErr;
5981 break;
5982
5983 case kEventToolbarGetAllowedIdentifiers:
5984 {
5985 CFMutableArrayRef array;
5986
5987 GetEventParameter (event, kEventParamMutableArray,
5988 typeCFMutableArrayRef, NULL,
5989 sizeof (CFMutableArrayRef), NULL, &array);
5990 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5991 result = noErr;
5992 }
5993 break;
5994
5995 case kEventToolbarCreateItemWithIdentifier:
5996 {
5997 CFStringRef identifier;
5998 HIToolbarItemRef item = NULL;
5999
6000 GetEventParameter (event, kEventParamToolbarItemIdentifier,
6001 typeCFStringRef, NULL,
6002 sizeof (CFStringRef), NULL, &identifier);
6003
6004 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
6005 == kCFCompareEqualTo)
6006 HIToolbarItemCreate (identifier,
6007 kHIToolbarItemAllowDuplicates
6008 | kHIToolbarItemCantBeRemoved, &item);
6009
6010 if (item)
6011 {
6012 SetEventParameter (event, kEventParamToolbarItem,
6013 typeHIToolbarItemRef,
6014 sizeof (HIToolbarItemRef), &item);
6015 result = noErr;
6016 }
6017 }
6018 break;
6019
6020 default:
6021 abort ();
6022 }
6023
6024 return result;
6025}
6026
6027static CGImageRef
6028mac_image_spec_to_cg_image (f, image)
6029 struct frame *f;
6030 Lisp_Object image;
6031{
6032 if (!valid_image_p (image))
6033 return NULL;
6034 else
6035 {
6036 int img_id = lookup_image (f, image);
6037 struct image *img = IMAGE_FROM_ID (f, img_id);
6038
6039 prepare_image_for_display (f, img);
6040
6041 return img->data.ptr_val;
6042 }
6043}
6044
6045/* Create a tool bar for frame F. */
6046
6047static OSStatus
6048mac_create_frame_tool_bar (f)
6049 FRAME_PTR f;
6050{
6051 OSStatus err;
6052 HIToolbarRef toolbar;
6053
6054 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
6055 &toolbar);
6056 if (err == noErr)
6057 {
6058 static const EventTypeSpec specs[] =
6059 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
6060 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
6061 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
6062
6063 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
6064 mac_handle_toolbar_event,
6065 GetEventTypeCount (specs), specs,
6066 f, NULL);
6067 }
6068
6069 if (err == noErr)
6070 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
6071 if (err == noErr)
6072 {
6073 static const EventTypeSpec specs[] =
6074 {{kEventClassCommand, kEventCommandProcess}};
6075
6076 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
6077 mac_handle_toolbar_command_event,
6078 GetEventTypeCount (specs),
6079 specs, f, NULL);
6080 }
6081 if (err == noErr)
6082 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
6083
6084 if (toolbar)
6085 CFRelease (toolbar);
6086
6087 return err;
6088}
6089
6090/* Update the tool bar for frame F. Add new buttons and remove old. */
6091
6092void
6093update_frame_tool_bar (f)
6094 FRAME_PTR f;
6095{
6096 HIToolbarRef toolbar = NULL;
6097 short left, top;
6098 CFArrayRef old_items = NULL;
6099 CFIndex old_count;
6100 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
6101 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6102
6103 BLOCK_INPUT;
6104
6105 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6106 if (toolbar == NULL)
6107 {
6108 mac_create_frame_tool_bar (f);
6109 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6110 if (toolbar == NULL)
6111 goto out;
6112 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6113 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6114 }
6115
6116 HIToolbarCopyItems (toolbar, &old_items);
6117 if (old_items == NULL)
6118 goto out;
6119
6120 old_count = CFArrayGetCount (old_items);
6121 pos = 0;
6122 for (i = 0; i < f->n_tool_bar_items; ++i)
6123 {
6124#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6125
6126 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6127 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6128 int idx;
6129 Lisp_Object image;
6130 CGImageRef cg_image;
6131 CFStringRef label;
6132 HIToolbarItemRef item;
6133
6134 /* If image is a vector, choose the image according to the
6135 button state. */
6136 image = PROP (TOOL_BAR_ITEM_IMAGES);
6137 if (VECTORP (image))
6138 {
6139 if (enabled_p)
6140 idx = (selected_p
6141 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6142 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6143 else
6144 idx = (selected_p
6145 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6146 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6147
6148 xassert (ASIZE (image) >= idx);
6149 image = AREF (image, idx);
6150 }
6151 else
6152 idx = -1;
6153
6154 cg_image = mac_image_spec_to_cg_image (f, image);
6155 /* Ignore invalid image specifications. */
6156 if (cg_image == NULL)
6157 continue;
6158
6159 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6160 if (label == NULL)
6161 label = CFSTR ("");
6162
6163 if (pos < old_count)
6164 {
6165 CGImageRef old_cg_image = NULL;
6166 CFStringRef old_label = NULL;
6167 Boolean old_enabled_p;
6168
6169 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6170
6171 HIToolbarItemCopyImage (item, &old_cg_image);
6172 if (cg_image != old_cg_image)
6173 HIToolbarItemSetImage (item, cg_image);
6174 CGImageRelease (old_cg_image);
6175
6176 HIToolbarItemCopyLabel (item, &old_label);
6177 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6178 HIToolbarItemSetLabel (item, label);
6179 CFRelease (old_label);
6180
6181 old_enabled_p = HIToolbarItemIsEnabled (item);
6182 if ((enabled_p || idx >= 0) != old_enabled_p)
6183 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6184 }
6185 else
6186 {
6187 item = NULL;
6188 HIToolbarCreateItemWithIdentifier (toolbar,
6189 TOOLBAR_ICON_ITEM_IDENTIFIER,
6190 NULL, &item);
6191 if (item)
6192 {
6193 HIToolbarItemSetImage (item, cg_image);
6194 HIToolbarItemSetLabel (item, label);
6195 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6196 HIToolbarAppendItem (toolbar, item);
6197 CFRelease (item);
6198 }
6199 }
6200
6201 CFRelease (label);
6202 if (item)
6203 {
6204 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6205 pos++;
6206 }
6207 }
6208
6209 CFRelease (old_items);
6210
6211 while (pos < old_count)
6212 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6213
6214 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6215 !win_gravity && f == mac_focus_frame (dpyinfo));
6216 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6217 toolbar visibility change. */
6218 mac_handle_origin_change (f);
6219 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6220 {
6221 mac_move_window_with_gravity (f, win_gravity, left, top);
6222 /* If the title bar is completely outside the screen, adjust the
6223 position. */
6224 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6225 kWindowConstrainMoveRegardlessOfFit
6226 | kWindowConstrainAllowPartial, NULL, NULL);
6227 f->output_data.mac->toolbar_win_gravity = 0;
6228 }
6229
6230 out:
6231 UNBLOCK_INPUT;
6232}
6233
6234/* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6235 doesn't deallocate the resources. */
6236
6237void
6238free_frame_tool_bar (f)
6239 FRAME_PTR f;
6240{
6241 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6242 {
6243 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6244
6245 BLOCK_INPUT;
6246 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
7b7d07bb
YM
6247 (NILP (Fsymbol_value
6248 (intern ("frame-notice-user-settings")))
6249 && f == mac_focus_frame (dpyinfo)));
c6829f81
YM
6250 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6251 on toolbar visibility change. */
6252 mac_handle_origin_change (f);
6253 UNBLOCK_INPUT;
6254 }
6255}
6256
6257static void
6258mac_tool_bar_note_mouse_movement (f, event)
6259 struct frame *f;
6260 EventRef event;
6261{
6262 OSStatus err;
6263 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6264 int mouse_down_p;
6265 HIViewRef item_view;
6266 UInt32 command_id;
6267
6268 mouse_down_p = (dpyinfo->grabbed
6269 && f == last_mouse_frame
6270 && FRAME_LIVE_P (f));
6271 if (mouse_down_p)
6272 return;
6273
6274 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6275 event, &item_view);
6276 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6277 toolbar item view seems to have the same command ID with that of
6278 the toolbar item. */
6279 if (err == noErr)
6280 err = GetControlCommandID (item_view, &command_id);
6281 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6282 {
6283 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6284
6285 if (i < f->n_tool_bar_items)
6286 {
6287 HIRect bounds;
6288 HIViewRef content_view;
6289
6290 err = HIViewGetBounds (item_view, &bounds);
6291 if (err == noErr)
6292 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6293 kHIViewWindowContentID, &content_view);
6294 if (err == noErr)
6295 err = HIViewConvertRect (&bounds, item_view, content_view);
6296 if (err == noErr)
6297 SetRect (&last_mouse_glyph,
6298 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6299 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6300
6301 help_echo_object = help_echo_window = Qnil;
6302 help_echo_pos = -1;
6303 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6304 if (NILP (help_echo_string))
6305 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6306 }
6307 }
6308}
6309
6310static OSStatus
6311mac_handle_toolbar_command_event (next_handler, event, data)
6312 EventHandlerCallRef next_handler;
6313 EventRef event;
6314 void *data;
6315{
6316 OSStatus err, result = eventNotHandledErr;
6317 struct frame *f = (struct frame *) data;
6318 HICommand command;
6319
6320 err = GetEventParameter (event, kEventParamDirectObject,
6321 typeHICommand, NULL,
6322 sizeof (HICommand), NULL, &command);
6323 if (err != noErr)
6324 return result;
6325
6326 switch (GetEventKind (event))
6327 {
6328 case kEventCommandProcess:
6329 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6330 result = CallNextEventHandler (next_handler, event);
6331 else
6332 {
6333 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6334
6335 if (i < f->n_tool_bar_items
6336 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6337 {
6338 Lisp_Object frame;
6339 struct input_event buf;
6340
6341 EVENT_INIT (buf);
6342
6343 XSETFRAME (frame, f);
6344 buf.kind = TOOL_BAR_EVENT;
6345 buf.frame_or_window = frame;
6346 buf.arg = frame;
6347 kbd_buffer_store_event (&buf);
6348
6349 buf.kind = TOOL_BAR_EVENT;
6350 buf.frame_or_window = frame;
6351 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6352 buf.modifiers = mac_event_to_emacs_modifiers (event);
6353 kbd_buffer_store_event (&buf);
6354
6355 result = noErr;
6356 }
6357 }
6358 break;
6359
6360 default:
6361 abort ();
6362 }
6363#undef PROP
6364
6365 return result;
6366}
6367#endif /* USE_MAC_TOOLBAR */
6368
6369\f
1a578e9b
AC
6370/***********************************************************************
6371 Text Cursor
6372 ***********************************************************************/
6373
1a578e9b
AC
6374/* Set clipping for output in glyph row ROW. W is the window in which
6375 we operate. GC is the graphics context to set clipping in.
1a578e9b
AC
6376
6377 ROW may be a text row or, e.g., a mode line. Text rows must be
6378 clipped to the interior of the window dedicated to text display,
6379 mode lines must be clipped to the whole window. */
6380
6381static void
08f66682 6382x_clip_to_row (w, row, area, gc)
1a578e9b
AC
6383 struct window *w;
6384 struct glyph_row *row;
08f66682 6385 int area;
1a578e9b 6386 GC gc;
1a578e9b
AC
6387{
6388 struct frame *f = XFRAME (WINDOW_FRAME (w));
6389 Rect clip_rect;
08f66682 6390 int window_x, window_y, window_width;
1a578e9b 6391
08f66682 6392 window_box (w, area, &window_x, &window_y, &window_width, 0);
1a578e9b 6393
08f66682 6394 clip_rect.left = window_x;
1a578e9b
AC
6395 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6396 clip_rect.top = max (clip_rect.top, window_y);
6397 clip_rect.right = clip_rect.left + window_width;
6398 clip_rect.bottom = clip_rect.top + row->visible_height;
6399
1c4ac540 6400 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
1a578e9b
AC
6401}
6402
6403
6404/* Draw a hollow box cursor on window W in glyph row ROW. */
6405
6406static void
6407x_draw_hollow_cursor (w, row)
6408 struct window *w;
6409 struct glyph_row *row;
6410{
6411 struct frame *f = XFRAME (WINDOW_FRAME (w));
6412 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6413 Display *dpy = FRAME_MAC_DISPLAY (f);
6414 int x, y, wd, h;
6415 XGCValues xgcv;
6416 struct glyph *cursor_glyph;
6417 GC gc;
6418
1a578e9b
AC
6419 /* Get the glyph the cursor is on. If we can't tell because
6420 the current matrix is invalid or such, give up. */
6421 cursor_glyph = get_phys_cursor_glyph (w);
6422 if (cursor_glyph == NULL)
6423 return;
6424
4d91ce74 6425 /* Compute frame-relative coordinates for phys cursor. */
e8f6b0db 6426 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
4d91ce74 6427 wd = w->phys_cursor_width;
177c0ea7 6428
1a578e9b
AC
6429 /* The foreground of cursor_gc is typically the same as the normal
6430 background color, which can cause the cursor box to be invisible. */
6431 xgcv.foreground = f->output_data.mac->cursor_pixel;
6432 if (dpyinfo->scratch_cursor_gc)
6433 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6434 else
6435 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6436 GCForeground, &xgcv);
6437 gc = dpyinfo->scratch_cursor_gc;
6438
6439 /* Set clipping, draw the rectangle, and reset clipping again. */
08f66682 6440 x_clip_to_row (w, row, TEXT_AREA, gc);
4ea08bbf 6441 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
1c4ac540 6442 mac_reset_clip_rectangles (dpy, gc);
1a578e9b
AC
6443}
6444
6445
6446/* Draw a bar cursor on window W in glyph row ROW.
6447
6448 Implementation note: One would like to draw a bar cursor with an
6449 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6450 Unfortunately, I didn't find a font yet that has this property set.
6451 --gerd. */
6452
6453static void
6b61353c 6454x_draw_bar_cursor (w, row, width, kind)
1a578e9b
AC
6455 struct window *w;
6456 struct glyph_row *row;
6457 int width;
6b61353c 6458 enum text_cursor_kinds kind;
1a578e9b 6459{
6b61353c
KH
6460 struct frame *f = XFRAME (w->frame);
6461 struct glyph *cursor_glyph;
6462
6463 /* If cursor is out of bounds, don't draw garbage. This can happen
6464 in mini-buffer windows when switching between echo area glyphs
6465 and mini-buffer. */
6466 cursor_glyph = get_phys_cursor_glyph (w);
6467 if (cursor_glyph == NULL)
6468 return;
6469
6470 /* If on an image, draw like a normal cursor. That's usually better
6471 visible than drawing a bar, esp. if the image is large so that
6472 the bar might not be in the window. */
6473 if (cursor_glyph->type == IMAGE_GLYPH)
1a578e9b 6474 {
6b61353c
KH
6475 struct glyph_row *row;
6476 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6477 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6478 }
6479 else
6480 {
6481 Display *dpy = FRAME_MAC_DISPLAY (f);
6482 Window window = FRAME_MAC_WINDOW (f);
6483 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6484 unsigned long mask = GCForeground | GCBackground;
6485 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
1a578e9b 6486 XGCValues xgcv;
177c0ea7 6487
6b61353c
KH
6488 /* If the glyph's background equals the color we normally draw
6489 the bar cursor in, the bar cursor in its normal color is
6490 invisible. Use the glyph's foreground color instead in this
6491 case, on the assumption that the glyph's colors are chosen so
6492 that the glyph is legible. */
6493 if (face->background == f->output_data.mac->cursor_pixel)
6494 xgcv.background = xgcv.foreground = face->foreground;
6495 else
6496 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
177c0ea7 6497
1a578e9b
AC
6498 if (gc)
6499 XChangeGC (dpy, gc, mask, &xgcv);
6500 else
6501 {
6502 gc = XCreateGC (dpy, window, mask, &xgcv);
6503 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6504 }
6505
6506 if (width < 0)
668e2d32 6507 width = FRAME_CURSOR_WIDTH (f);
6b61353c 6508 width = min (cursor_glyph->pixel_width, width);
1a578e9b 6509
6b61353c 6510 w->phys_cursor_width = width;
08f66682 6511 x_clip_to_row (w, row, TEXT_AREA, gc);
6b61353c
KH
6512
6513 if (kind == BAR_CURSOR)
236072ae
YM
6514 mac_fill_rectangle (f, gc,
6515 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6516 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6517 width, row->height);
6b61353c 6518 else
236072ae
YM
6519 mac_fill_rectangle (f, gc,
6520 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6521 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6522 row->height - width),
6523 cursor_glyph->pixel_width,
6524 width);
6b61353c 6525
834263b6 6526 mac_reset_clip_rectangles (f, gc);
1a578e9b
AC
6527 }
6528}
6529
6530
f9e65eb3 6531/* RIF: Define cursor CURSOR on frame F. */
1a578e9b
AC
6532
6533static void
f9e65eb3
KS
6534mac_define_frame_cursor (f, cursor)
6535 struct frame *f;
6536 Cursor cursor;
1a578e9b 6537{
b465419f
YM
6538 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6539
6540 if (dpyinfo->x_focus_frame == f)
6541 SetThemeCursor (cursor);
1a578e9b
AC
6542}
6543
6544
f9e65eb3 6545/* RIF: Clear area on frame F. */
1a578e9b
AC
6546
6547static void
f9e65eb3
KS
6548mac_clear_frame_area (f, x, y, width, height)
6549 struct frame *f;
6550 int x, y, width, height;
1a578e9b 6551{
236072ae 6552 mac_clear_area (f, x, y, width, height);
1a578e9b
AC
6553}
6554
6555
f9e65eb3 6556/* RIF: Draw cursor on window W. */
1a578e9b
AC
6557
6558static void
e5a3b7d9 6559mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
1a578e9b 6560 struct window *w;
f9e65eb3 6561 struct glyph_row *glyph_row;
e5a3b7d9
KS
6562 int x, y;
6563 int cursor_type, cursor_width;
6564 int on_p, active_p;
1a578e9b 6565{
e5a3b7d9 6566 if (on_p)
1a578e9b 6567 {
e5a3b7d9 6568 w->phys_cursor_type = cursor_type;
1a578e9b
AC
6569 w->phys_cursor_on_p = 1;
6570
6b61353c
KH
6571 if (glyph_row->exact_window_width_line_p
6572 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6573 {
6574 glyph_row->cursor_in_fringe_p = 1;
6575 draw_fringe_bitmap (w, glyph_row, 0);
6576 }
6577 else
e5a3b7d9 6578 switch (cursor_type)
1a578e9b
AC
6579 {
6580 case HOLLOW_BOX_CURSOR:
6581 x_draw_hollow_cursor (w, glyph_row);
6582 break;
6583
6584 case FILLED_BOX_CURSOR:
f9e65eb3 6585 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
1a578e9b
AC
6586 break;
6587
6588 case BAR_CURSOR:
6b61353c
KH
6589 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6590 break;
6591
6592 case HBAR_CURSOR:
6593 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
1a578e9b
AC
6594 break;
6595
6596 case NO_CURSOR:
6b61353c 6597 w->phys_cursor_width = 0;
1a578e9b
AC
6598 break;
6599
6600 default:
6601 abort ();
6602 }
1a578e9b 6603 }
1a578e9b
AC
6604}
6605
e0f712ba
AC
6606\f
6607/* Icons. */
1a578e9b 6608
e0f712ba 6609#if 0 /* MAC_TODO: no icon support yet. */
1a578e9b 6610int
e0f712ba 6611x_bitmap_icon (f, icon)
1a578e9b 6612 struct frame *f;
e0f712ba 6613 Lisp_Object icon;
1a578e9b 6614{
e0f712ba 6615 HANDLE hicon;
1a578e9b 6616
e0f712ba 6617 if (FRAME_W32_WINDOW (f) == 0)
1a578e9b
AC
6618 return 1;
6619
e0f712ba
AC
6620 if (NILP (icon))
6621 hicon = LoadIcon (hinst, EMACS_CLASS);
6622 else if (STRINGP (icon))
d5db4077 6623 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
e0f712ba
AC
6624 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6625 else if (SYMBOLP (icon))
6626 {
6627 LPCTSTR name;
6628
6629 if (EQ (icon, intern ("application")))
6630 name = (LPCTSTR) IDI_APPLICATION;
6631 else if (EQ (icon, intern ("hand")))
6632 name = (LPCTSTR) IDI_HAND;
6633 else if (EQ (icon, intern ("question")))
6634 name = (LPCTSTR) IDI_QUESTION;
6635 else if (EQ (icon, intern ("exclamation")))
6636 name = (LPCTSTR) IDI_EXCLAMATION;
6637 else if (EQ (icon, intern ("asterisk")))
6638 name = (LPCTSTR) IDI_ASTERISK;
6639 else if (EQ (icon, intern ("winlogo")))
6640 name = (LPCTSTR) IDI_WINLOGO;
6641 else
6642 return 1;
1a578e9b 6643
e0f712ba 6644 hicon = LoadIcon (NULL, name);
1a578e9b 6645 }
e0f712ba 6646 else
1a578e9b
AC
6647 return 1;
6648
e0f712ba
AC
6649 if (hicon == NULL)
6650 return 1;
1a578e9b 6651
e0f712ba
AC
6652 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6653 (LPARAM) hicon);
1a578e9b
AC
6654
6655 return 0;
6656}
e0f712ba 6657#endif /* MAC_TODO */
1a578e9b 6658\f
e0f712ba
AC
6659/************************************************************************
6660 Handling X errors
6661 ************************************************************************/
1a578e9b 6662
e0f712ba
AC
6663/* Display Error Handling functions not used on W32. Listing them here
6664 helps diff stay in step when comparing w32term.c with xterm.c.
1a578e9b 6665
1a578e9b 6666x_error_catcher (display, error)
1a578e9b 6667x_catch_errors (dpy)
1a578e9b 6668x_catch_errors_unwind (old_val)
1a578e9b 6669x_check_errors (dpy, format)
1a578e9b 6670x_had_errors_p (dpy)
1a578e9b 6671x_clear_errors (dpy)
1a578e9b 6672x_uncatch_errors (dpy, count)
1a578e9b 6673x_trace_wire ()
e0f712ba
AC
6674x_connection_signal (signalnum)
6675x_connection_closed (dpy, error_message)
1a578e9b 6676x_error_quitter (display, error)
1a578e9b 6677x_error_handler (display, error)
1a578e9b 6678x_io_error_quitter (display)
1a578e9b 6679
e0f712ba
AC
6680 */
6681
1a578e9b
AC
6682\f
6683/* Changing the font of the frame. */
6684
6685/* Give frame F the font named FONTNAME as its default font, and
6686 return the full name of that font. FONTNAME may be a wildcard
6687 pattern; in that case, we choose some font that fits the pattern.
6688 The return value shows which font we chose. */
6689
6690Lisp_Object
6691x_new_font (f, fontname)
6692 struct frame *f;
6693 register char *fontname;
6694{
6695 struct font_info *fontp
cc02ceee 6696 = FS_LOAD_FONT (f, fontname);
1a578e9b
AC
6697
6698 if (!fontp)
6699 return Qnil;
6700
cc02ceee
ST
6701 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
6702 /* This font is already set in frame F. There's nothing more to
6703 do. */
6704 return build_string (fontp->full_name);
6705
e0f712ba
AC
6706 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6707 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6708 FRAME_FONTSET (f) = -1;
6709
e169f939
ST
6710 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6711 FRAME_SPACE_WIDTH (f) = fontp->space_width;
f1a83aab
KS
6712 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6713
6714 compute_fringe_widths (f, 1);
6715
1a578e9b 6716 /* Compute the scroll bar width in character columns. */
f1a83aab 6717 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
1a578e9b 6718 {
f1a83aab 6719 int wid = FRAME_COLUMN_WIDTH (f);
ffe8b3f4 6720 FRAME_CONFIG_SCROLL_BAR_COLS (f)
f1a83aab 6721 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
1a578e9b
AC
6722 }
6723 else
6724 {
f1a83aab
KS
6725 int wid = FRAME_COLUMN_WIDTH (f);
6726 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
1a578e9b
AC
6727 }
6728
6729 /* Now make the frame display the given font. */
6730 if (FRAME_MAC_WINDOW (f) != 0)
6731 {
f00691a3 6732 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
f1a83aab 6733 FRAME_FONT (f));
f00691a3 6734 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
f1a83aab 6735 FRAME_FONT (f));
f00691a3 6736 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
f1a83aab 6737 FRAME_FONT (f));
f00691a3 6738
b15325b2
ST
6739 /* Don't change the size of a tip frame; there's no point in
6740 doing it because it's done in Fx_show_tip, and it leads to
6741 problems because the tip frame has no widget. */
e0f712ba 6742 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
f1a83aab 6743 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1a578e9b 6744 }
1a578e9b
AC
6745
6746 return build_string (fontp->full_name);
6747}
6abfb022
YM
6748\f
6749/* Give frame F the fontset named FONTSETNAME as its default fontset,
6750 and return the full name of that fontset. FONTSETNAME may be a
6751 wildcard pattern; in that case, we choose some fontset that fits
6752 the pattern. FONTSETNAME may be a font name for ASCII characters;
6753 in that case, we create a fontset from that font name.
b15325b2 6754
6abfb022
YM
6755 The return value shows which fontset we chose.
6756 If FONTSETNAME specifies the default fontset, return Qt.
6757 If an ASCII font in the specified fontset can't be loaded, return
6758 Qnil. */
1a578e9b
AC
6759
6760Lisp_Object
6761x_new_fontset (f, fontsetname)
6762 struct frame *f;
cc02ceee 6763 Lisp_Object fontsetname;
1a578e9b 6764{
cc02ceee 6765 int fontset = fs_query_fontset (fontsetname, 0);
1a578e9b
AC
6766 Lisp_Object result;
6767
cc02ceee 6768 if (fontset > 0 && FRAME_FONTSET(f) == fontset)
1a578e9b
AC
6769 /* This fontset is already set in frame F. There's nothing more
6770 to do. */
6771 return fontset_name (fontset);
cc02ceee
ST
6772 else if (fontset == 0)
6773 /* The default fontset can't be the default font. */
6774 return Qt;
1a578e9b 6775
cc02ceee
ST
6776 if (fontset > 0)
6777 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6778 else
6779 result = x_new_font (f, SDATA (fontsetname));
1a578e9b
AC
6780
6781 if (!STRINGP (result))
6782 /* Can't load ASCII font. */
6783 return Qnil;
6784
cc02ceee
ST
6785 if (fontset < 0)
6786 fontset = new_fontset_from_font_name (result);
6787
e0f712ba 6788 /* Since x_new_font doesn't update any fontset information, do it now. */
7ca7ccd5 6789 FRAME_FONTSET (f) = fontset;
1a578e9b 6790
cc02ceee 6791 return fontset_name (fontset);
1a578e9b
AC
6792}
6793
1a578e9b
AC
6794\f
6795/***********************************************************************
e0f712ba 6796 TODO: W32 Input Methods
1a578e9b 6797 ***********************************************************************/
e0f712ba 6798/* Listing missing functions from xterm.c helps diff stay in step.
1a578e9b 6799
1a578e9b 6800xim_destroy_callback (xim, client_data, call_data)
1a578e9b 6801xim_open_dpy (dpyinfo, resource_name)
1a578e9b 6802struct xim_inst_t
1a578e9b 6803xim_instantiate_callback (display, client_data, call_data)
1a578e9b 6804xim_initialize (dpyinfo, resource_name)
1a578e9b 6805xim_close_dpy (dpyinfo)
1a578e9b 6806
e0f712ba 6807 */
1a578e9b 6808
1a578e9b 6809\f
bf06c82f
ST
6810void
6811mac_get_window_bounds (f, inner, outer)
6812 struct frame *f;
6813 Rect *inner, *outer;
6814{
6815#if TARGET_API_MAC_CARBON
6816 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6817 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6818#else /* not TARGET_API_MAC_CARBON */
6819 RgnHandle region = NewRgn ();
f94a2622 6820
bf06c82f
ST
6821 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6822 *inner = (*region)->rgnBBox;
6823 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6824 *outer = (*region)->rgnBBox;
6825 DisposeRgn (region);
6826#endif /* not TARGET_API_MAC_CARBON */
6827}
6828
bed0bf95
YM
6829static void
6830mac_handle_origin_change (f)
6831 struct frame *f;
6832{
6833 x_real_positions (f, &f->left_pos, &f->top_pos);
6834}
6835
6836static void
6837mac_handle_size_change (f, pixelwidth, pixelheight)
6838 struct frame *f;
6839 int pixelwidth, pixelheight;
6840{
6841 int cols, rows;
6842
6843 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6844 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6845
6846 if (cols != FRAME_COLS (f)
6847 || rows != FRAME_LINES (f)
6848 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6849 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6850 {
6851 /* We pass 1 for DELAY since we can't run Lisp code inside of
6852 a BLOCK_INPUT. */
6853 change_frame_size (f, rows, cols, 0, 1, 0);
6854 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6855 FRAME_PIXEL_HEIGHT (f) = pixelheight;
bed0bf95
YM
6856
6857 /* If cursor was outside the new size, mark it as off. */
6858 mark_window_cursors_off (XWINDOW (f->root_window));
6859
6860 /* Clear out any recollection of where the mouse highlighting
6861 was, since it might be in a place that's outside the new
6862 frame size. Actually checking whether it is outside is a
6863 pain in the neck, so don't try--just let the highlighting be
6864 done afresh with new size. */
6865 cancel_mouse_face (f);
6866
6867#if TARGET_API_MAC_CARBON
6868 if (f->output_data.mac->hourglass_control)
6869 {
6870#if USE_CG_DRAWING
6871 mac_prepare_for_quickdraw (f);
6872#endif
6873 MoveControl (f->output_data.mac->hourglass_control,
6874 pixelwidth - HOURGLASS_WIDTH, 0);
6875 }
6876#endif
6877 }
6878}
bf06c82f 6879
95dfb192 6880\f
1a578e9b
AC
6881/* Calculate the absolute position in frame F
6882 from its current recorded position values and gravity. */
6883
e0f712ba 6884void
1a578e9b
AC
6885x_calc_absolute_position (f)
6886 struct frame *f;
6887{
f1a83aab 6888 int flags = f->size_hint_flags;
bf06c82f 6889 Rect inner, outer;
1a578e9b 6890
bf06c82f
ST
6891 /* We have nothing to do if the current position
6892 is already for the top-left corner. */
6893 if (! ((flags & XNegative) || (flags & YNegative)))
6894 return;
1a578e9b 6895
bf06c82f 6896 /* Find the offsets of the outside upper-left corner of
1a578e9b 6897 the inner window, with respect to the outer window. */
1d5bcd55 6898 BLOCK_INPUT;
bf06c82f 6899 mac_get_window_bounds (f, &inner, &outer);
1d5bcd55 6900 UNBLOCK_INPUT;
e0f712ba 6901
1a578e9b
AC
6902 /* Treat negative positions as relative to the leftmost bottommost
6903 position that fits on the screen. */
6904 if (flags & XNegative)
834263b6
YM
6905 f->left_pos += (FRAME_MAC_DISPLAY_INFO (f)->width
6906 - (outer.right - outer.left));
bf06c82f 6907
1a578e9b 6908 if (flags & YNegative)
834263b6
YM
6909 f->top_pos += (FRAME_MAC_DISPLAY_INFO (f)->height
6910 - (outer.bottom - outer.top));
bf06c82f 6911
1a578e9b
AC
6912 /* The left_pos and top_pos
6913 are now relative to the top and left screen edges,
6914 so the flags should correspond. */
f1a83aab 6915 f->size_hint_flags &= ~ (XNegative | YNegative);
1a578e9b
AC
6916}
6917
6918/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6919 to really change the position, and 0 when calling from
6920 x_make_frame_visible (in that case, XOFF and YOFF are the current
6921 position values). It is -1 when calling from x_set_frame_parameters,
6922 which means, do adjust for borders but don't change the gravity. */
6923
6924void
6925x_set_offset (f, xoff, yoff, change_gravity)
6926 struct frame *f;
6927 register int xoff, yoff;
6928 int change_gravity;
6929{
6930 if (change_gravity > 0)
6931 {
f1a83aab
KS
6932 f->top_pos = yoff;
6933 f->left_pos = xoff;
6934 f->size_hint_flags &= ~ (XNegative | YNegative);
1a578e9b 6935 if (xoff < 0)
f1a83aab 6936 f->size_hint_flags |= XNegative;
1a578e9b 6937 if (yoff < 0)
f1a83aab
KS
6938 f->size_hint_flags |= YNegative;
6939 f->win_gravity = NorthWestGravity;
1a578e9b
AC
6940 }
6941 x_calc_absolute_position (f);
6942
6943 BLOCK_INPUT;
6944 x_wm_set_size_hint (f, (long) 0, 0);
6945
bf06c82f
ST
6946#if TARGET_API_MAC_CARBON
6947 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6948 /* If the title bar is completely outside the screen, adjust the
6949 position. */
6950 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6951 kWindowConstrainMoveRegardlessOfFit
6952 | kWindowConstrainAllowPartial, NULL, NULL);
bed0bf95 6953 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
bed0bf95 6954 mac_handle_origin_change (f);
bf06c82f
ST
6955#else
6956 {
6957 Rect inner, outer, screen_rect, dummy;
6958 RgnHandle region = NewRgn ();
f94a2622 6959
bf06c82f
ST
6960 mac_get_window_bounds (f, &inner, &outer);
6961 f->x_pixels_diff = inner.left - outer.left;
6962 f->y_pixels_diff = inner.top - outer.top;
6963 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6964 f->top_pos + f->y_pixels_diff, false);
6965
6966 /* If the title bar is completely outside the screen, adjust the
6967 position. The variable `outer' holds the title bar rectangle.
6968 The variable `inner' holds slightly smaller one than `outer',
6969 so that the calculation of overlapping may not become too
6970 strict. */
6971 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6972 outer = (*region)->rgnBBox;
6973 DisposeRgn (region);
6974 inner = outer;
6975 InsetRect (&inner, 8, 8);
6976 screen_rect = qd.screenBits.bounds;
6977 screen_rect.top += GetMBarHeight ();
6978
6979 if (!SectRect (&inner, &screen_rect, &dummy))
6980 {
6981 if (inner.right <= screen_rect.left)
6982 f->left_pos = screen_rect.left;
6983 else if (inner.left >= screen_rect.right)
6984 f->left_pos = screen_rect.right - (outer.right - outer.left);
6985
6986 if (inner.bottom <= screen_rect.top)
6987 f->top_pos = screen_rect.top;
6988 else if (inner.top >= screen_rect.bottom)
6989 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6990
6991 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6992 f->top_pos + f->y_pixels_diff, false);
6993 }
6994 }
6995#endif
1a578e9b
AC
6996
6997 UNBLOCK_INPUT;
6998}
6999
7000/* Call this to change the size of frame F's x-window.
7001 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
7002 for this size change and subsequent size changes.
7003 Otherwise we leave the window gravity unchanged. */
7004
7005void
7006x_set_window_size (f, change_gravity, cols, rows)
7007 struct frame *f;
7008 int change_gravity;
7009 int cols, rows;
7010{
7011 int pixelwidth, pixelheight;
177c0ea7 7012
e0f712ba 7013 BLOCK_INPUT;
177c0ea7 7014
1a578e9b 7015 check_frame_size (f, &rows, &cols);
f1a83aab
KS
7016 f->scroll_bar_actual_width
7017 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
d33c49e8 7018
5958f265 7019 compute_fringe_widths (f, 0);
d33c49e8 7020
f1a83aab
KS
7021 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
7022 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1a578e9b 7023
f1a83aab 7024 f->win_gravity = NorthWestGravity;
1a578e9b
AC
7025 x_wm_set_size_hint (f, (long) 0, 0);
7026
7027 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
1a578e9b 7028
3354caee 7029#if TARGET_API_MAC_CARBON
bed0bf95
YM
7030 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
7031#endif
7032 mac_handle_size_change (f, pixelwidth, pixelheight);
e0f712ba 7033
70385fe6
YM
7034 if (f->output_data.mac->internal_border_width
7035 != FRAME_INTERNAL_BORDER_WIDTH (f))
7036 {
7037 mac_clear_window (f);
7038 f->output_data.mac->internal_border_width
7039 = FRAME_INTERNAL_BORDER_WIDTH (f);
7040 }
7041
7042 SET_FRAME_GARBAGED (f);
7043
e0f712ba 7044 UNBLOCK_INPUT;
1a578e9b
AC
7045}
7046\f
7047/* Mouse warping. */
7048
7049void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
7050
7051void
7052x_set_mouse_position (f, x, y)
7053 struct frame *f;
7054 int x, y;
7055{
7056 int pix_x, pix_y;
7057
f1a83aab
KS
7058 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
7059 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
1a578e9b
AC
7060
7061 if (pix_x < 0) pix_x = 0;
f1a83aab 7062 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1a578e9b
AC
7063
7064 if (pix_y < 0) pix_y = 0;
f1a83aab 7065 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1a578e9b
AC
7066
7067 x_set_mouse_pixel_position (f, pix_x, pix_y);
7068}
7069
1a578e9b
AC
7070void
7071x_set_mouse_pixel_position (f, pix_x, pix_y)
7072 struct frame *f;
7073 int pix_x, pix_y;
7074{
92289429 7075#ifdef MAC_OSX
7adf3143
YM
7076 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
7077 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
92289429
YM
7078
7079 BLOCK_INPUT;
7adf3143 7080 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
92289429
YM
7081 UNBLOCK_INPUT;
7082#else
7083#if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
1a578e9b
AC
7084 BLOCK_INPUT;
7085
7086 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
7087 0, 0, 0, 0, pix_x, pix_y);
7088 UNBLOCK_INPUT;
7089#endif
92289429 7090#endif
1a578e9b
AC
7091}
7092\f
7093/* focus shifting, raising and lowering. */
7094
e0f712ba 7095void
1a578e9b
AC
7096x_focus_on_frame (f)
7097 struct frame *f;
7098{
7099#if 0 /* This proves to be unpleasant. */
7100 x_raise_frame (f);
7101#endif
7102#if 0
7103 /* I don't think that the ICCCM allows programs to do things like this
7104 without the interaction of the window manager. Whatever you end up
7105 doing with this code, do it to x_unfocus_frame too. */
7106 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7107 RevertToPointerRoot, CurrentTime);
7108#endif /* ! 0 */
7109}
7110
e0f712ba 7111void
1a578e9b
AC
7112x_unfocus_frame (f)
7113 struct frame *f;
7114{
1a578e9b
AC
7115}
7116
7117/* Raise frame F. */
95dfb192 7118
1a578e9b
AC
7119void
7120x_raise_frame (f)
7121 struct frame *f;
7122{
7123 if (f->async_visible)
c3f4c690
ST
7124 {
7125 BLOCK_INPUT;
b465419f 7126 BringToFront (FRAME_MAC_WINDOW (f));
c3f4c690
ST
7127 UNBLOCK_INPUT;
7128 }
1a578e9b
AC
7129}
7130
7131/* Lower frame F. */
95dfb192 7132
1a578e9b
AC
7133void
7134x_lower_frame (f)
7135 struct frame *f;
7136{
7137 if (f->async_visible)
c3f4c690
ST
7138 {
7139 BLOCK_INPUT;
b465419f 7140 SendBehind (FRAME_MAC_WINDOW (f), NULL);
c3f4c690
ST
7141 UNBLOCK_INPUT;
7142 }
1a578e9b
AC
7143}
7144
e0f712ba 7145static void
1a578e9b
AC
7146XTframe_raise_lower (f, raise_flag)
7147 FRAME_PTR f;
7148 int raise_flag;
7149{
7150 if (raise_flag)
7151 x_raise_frame (f);
7152 else
7153 x_lower_frame (f);
7154}
7155\f
7156/* Change of visibility. */
7157
1f98fbb4
YM
7158static void
7159mac_handle_visibility_change (f)
7160 struct frame *f;
7161{
3354caee 7162 WindowRef wp = FRAME_MAC_WINDOW (f);
1f98fbb4
YM
7163 int visible = 0, iconified = 0;
7164 struct input_event buf;
7165
7166 if (IsWindowVisible (wp))
f93e4d4f
YM
7167 {
7168 if (IsWindowCollapsed (wp))
7169 iconified = 1;
7170 else
7171 visible = 1;
7172 }
1f98fbb4
YM
7173
7174 if (!f->async_visible && visible)
7175 {
7176 if (f->iconified)
7177 {
7178 /* wait_reading_process_output will notice this and update
7179 the frame's display structures. If we were made
7180 invisible, we should not set garbaged, because that stops
7181 redrawing on Update events. */
7182 SET_FRAME_GARBAGED (f);
7183
7184 EVENT_INIT (buf);
7185 buf.kind = DEICONIFY_EVENT;
7186 XSETFRAME (buf.frame_or_window, f);
36f0107c 7187 buf.arg = Qnil;
1f98fbb4
YM
7188 kbd_buffer_store_event (&buf);
7189 }
7190 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7191 /* Force a redisplay sooner or later to update the
7192 frame titles in case this is the second frame. */
7193 record_asynch_buffer_change ();
7194 }
7195 else if (f->async_visible && !visible)
7196 if (iconified)
7197 {
7198 EVENT_INIT (buf);
7199 buf.kind = ICONIFY_EVENT;
7200 XSETFRAME (buf.frame_or_window, f);
36f0107c 7201 buf.arg = Qnil;
1f98fbb4
YM
7202 kbd_buffer_store_event (&buf);
7203 }
7204
7205 f->async_visible = visible;
7206 f->async_iconified = iconified;
7207}
7208
1a578e9b
AC
7209/* This tries to wait until the frame is really visible.
7210 However, if the window manager asks the user where to position
7211 the frame, this will return before the user finishes doing that.
7212 The frame will not actually be visible at that time,
7213 but it will become visible later when the window manager
7214 finishes with it. */
7215
7216void
7217x_make_frame_visible (f)
7218 struct frame *f;
7219{
1a578e9b
AC
7220 BLOCK_INPUT;
7221
7222 if (! FRAME_VISIBLE_P (f))
7223 {
7224 /* We test FRAME_GARBAGED_P here to make sure we don't
7225 call x_set_offset a second time
7226 if we get to x_make_frame_visible a second time
7227 before the window gets really visible. */
7228 if (! FRAME_ICONIFIED_P (f)
7229 && ! f->output_data.mac->asked_for_visible)
7adf3143 7230 x_set_offset (f, f->left_pos, f->top_pos, 0);
1f98fbb4
YM
7231
7232 f->output_data.mac->asked_for_visible = 1;
7233
1f98fbb4 7234 CollapseWindow (FRAME_MAC_WINDOW (f), false);
1a578e9b
AC
7235 ShowWindow (FRAME_MAC_WINDOW (f));
7236 }
7237
7238 XFlush (FRAME_MAC_DISPLAY (f));
7239
7240 /* Synchronize to ensure Emacs knows the frame is visible
7241 before we do anything else. We do this loop with input not blocked
7242 so that incoming events are handled. */
7243 {
7244 Lisp_Object frame;
7245 int count;
7246
7247 /* This must come after we set COUNT. */
7248 UNBLOCK_INPUT;
7249
7250 XSETFRAME (frame, f);
7251
7252 /* Wait until the frame is visible. Process X events until a
7253 MapNotify event has been seen, or until we think we won't get a
7254 MapNotify at all.. */
7255 for (count = input_signal_count + 10;
7256 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7257 {
7258 /* Force processing of queued events. */
7259 x_sync (f);
7260
7261 /* Machines that do polling rather than SIGIO have been
7262 observed to go into a busy-wait here. So we'll fake an
7263 alarm signal to let the handler know that there's something
7264 to be read. We used to raise a real alarm, but it seems
7265 that the handler isn't always enabled here. This is
7266 probably a bug. */
7267 if (input_polling_used ())
7268 {
7269 /* It could be confusing if a real alarm arrives while
7270 processing the fake one. Turn it off and let the
7271 handler reset it. */
7272 extern void poll_for_input_1 P_ ((void));
7273 int old_poll_suppress_count = poll_suppress_count;
7274 poll_suppress_count = 1;
7275 poll_for_input_1 ();
7276 poll_suppress_count = old_poll_suppress_count;
7277 }
7278
7279 /* See if a MapNotify event has been processed. */
7280 FRAME_SAMPLE_VISIBILITY (f);
7281 }
7282 }
7283}
7284
7285/* Change from mapped state to withdrawn state. */
7286
7287/* Make the frame visible (mapped and not iconified). */
7288
7289void
7290x_make_frame_invisible (f)
7291 struct frame *f;
7292{
1f98fbb4
YM
7293 /* A deactivate event does not occur when the last visible frame is
7294 made invisible. So if we clear the highlight here, it will not
7295 be rehighlighted when it is made visible. */
7296#if 0
1a578e9b
AC
7297 /* Don't keep the highlight on an invisible frame. */
7298 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7299 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
1f98fbb4 7300#endif
177c0ea7 7301
1a578e9b 7302 BLOCK_INPUT;
177c0ea7 7303
7adf3143 7304#if !TARGET_API_MAC_CARBON
7ca7ccd5
YM
7305 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7306 that the current position of the window is user-specified, rather than
7307 program-specified, so that when the window is mapped again, it will be
7308 placed at the same location, without forcing the user to position it
7309 by hand again (they have already done that once for this window.) */
7310 x_wm_set_size_hint (f, (long) 0, 1);
7adf3143 7311#endif
7ca7ccd5 7312
1a578e9b 7313 HideWindow (FRAME_MAC_WINDOW (f));
177c0ea7 7314
1a578e9b 7315 UNBLOCK_INPUT;
1f98fbb4 7316
3354caee 7317#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
7318 mac_handle_visibility_change (f);
7319#endif
1a578e9b
AC
7320}
7321
7322/* Change window state from mapped to iconified. */
7323
7324void
7325x_iconify_frame (f)
7326 struct frame *f;
7327{
3e7424f7 7328 OSStatus err;
1f98fbb4
YM
7329
7330 /* A deactivate event does not occur when the last visible frame is
7331 iconified. So if we clear the highlight here, it will not be
7332 rehighlighted when it is deiconified. */
7333#if 0
1a578e9b 7334 /* Don't keep the highlight on an invisible frame. */
742fbed7
AC
7335 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7336 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
1f98fbb4 7337#endif
1a578e9b
AC
7338
7339 if (f->async_iconified)
7340 return;
7341
7342 BLOCK_INPUT;
7343
1f98fbb4
YM
7344 FRAME_SAMPLE_VISIBILITY (f);
7345
7346 if (! FRAME_VISIBLE_P (f))
7347 ShowWindow (FRAME_MAC_WINDOW (f));
7348
7349 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
177c0ea7 7350
1a578e9b 7351 UNBLOCK_INPUT;
1f98fbb4
YM
7352
7353 if (err != noErr)
7354 error ("Can't notify window manager of iconification");
7355
3354caee 7356#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
7357 mac_handle_visibility_change (f);
7358#endif
1a578e9b 7359}
e0f712ba 7360
1a578e9b 7361\f
6b61353c 7362/* Free X resources of frame F. */
1a578e9b
AC
7363
7364void
6b61353c 7365x_free_frame_resources (f)
1a578e9b
AC
7366 struct frame *f;
7367{
7368 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3354caee 7369 WindowRef wp = FRAME_MAC_WINDOW (f);
1a578e9b
AC
7370
7371 BLOCK_INPUT;
7372
25c9622b
YM
7373 if (wp != tip_window)
7374 remove_window_handler (wp);
7375
c857519f
YM
7376#if USE_CG_DRAWING
7377 mac_prepare_for_quickdraw (f);
7378#endif
50bf7673
ST
7379 DisposeWindow (wp);
7380 if (wp == tip_window)
7381 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7382 closed' event. So we reset tip_window here. */
7383 tip_window = NULL;
1a578e9b
AC
7384
7385 free_frame_menubar (f);
6b61353c
KH
7386
7387 if (FRAME_FACE_CACHE (f))
7388 free_frame_faces (f);
7389
7390 x_free_gcs (f);
1a578e9b 7391
70fdbb46 7392 xfree (FRAME_SIZE_HINTS (f));
b15325b2 7393
1a578e9b 7394 xfree (f->output_data.mac);
6b61353c
KH
7395 f->output_data.mac = NULL;
7396
1a578e9b 7397 if (f == dpyinfo->x_focus_frame)
4cb62a90
YM
7398 {
7399 dpyinfo->x_focus_frame = 0;
7400#if USE_MAC_FONT_PANEL
7401 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7402#endif
7403 }
1a578e9b
AC
7404 if (f == dpyinfo->x_focus_event_frame)
7405 dpyinfo->x_focus_event_frame = 0;
7406 if (f == dpyinfo->x_highlight_frame)
7407 dpyinfo->x_highlight_frame = 0;
7408
1a578e9b
AC
7409 if (f == dpyinfo->mouse_face_mouse_frame)
7410 {
7411 dpyinfo->mouse_face_beg_row
7412 = dpyinfo->mouse_face_beg_col = -1;
7413 dpyinfo->mouse_face_end_row
7414 = dpyinfo->mouse_face_end_col = -1;
7415 dpyinfo->mouse_face_window = Qnil;
7416 dpyinfo->mouse_face_deferred_gc = 0;
7417 dpyinfo->mouse_face_mouse_frame = 0;
7418 }
7419
7420 UNBLOCK_INPUT;
7421}
6b61353c
KH
7422
7423
7424/* Destroy the X window of frame F. */
7425
7426void
7427x_destroy_window (f)
7428 struct frame *f;
7429{
7430 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7431
7432 x_free_frame_resources (f);
7433
7434 dpyinfo->reference_count--;
7435}
7436
1a578e9b
AC
7437\f
7438/* Setting window manager hints. */
7439
7440/* Set the normal size hints for the window manager, for frame F.
7441 FLAGS is the flags word to use--or 0 meaning preserve the flags
7442 that the window now has.
7443 If USER_POSITION is nonzero, we set the USPosition
7444 flag (this is useful when FLAGS is 0). */
1a578e9b
AC
7445void
7446x_wm_set_size_hint (f, flags, user_position)
7447 struct frame *f;
7448 long flags;
7449 int user_position;
7450{
b15325b2
ST
7451 int base_width, base_height, width_inc, height_inc;
7452 int min_rows = 0, min_cols = 0;
7453 XSizeHints *size_hints;
1a578e9b 7454
b15325b2
ST
7455 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7456 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7457 width_inc = FRAME_COLUMN_WIDTH (f);
7458 height_inc = FRAME_LINE_HEIGHT (f);
1a578e9b 7459
b15325b2 7460 check_frame_size (f, &min_rows, &min_cols);
1a578e9b 7461
b15325b2
ST
7462 size_hints = FRAME_SIZE_HINTS (f);
7463 if (size_hints == NULL)
1a578e9b 7464 {
b15325b2
ST
7465 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7466 bzero (size_hints, sizeof (XSizeHints));
1a578e9b 7467 }
1a578e9b 7468
b15325b2
ST
7469 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7470 size_hints->width_inc = width_inc;
7471 size_hints->height_inc = height_inc;
7472 size_hints->min_width = base_width + min_cols * width_inc;
7473 size_hints->min_height = base_height + min_rows * height_inc;
7474 size_hints->base_width = base_width;
7475 size_hints->base_height = base_height;
1a578e9b 7476
b15325b2
ST
7477 if (flags)
7478 size_hints->flags = flags;
7479 else if (user_position)
1a578e9b 7480 {
b15325b2
ST
7481 size_hints->flags &= ~ PPosition;
7482 size_hints->flags |= USPosition;
1a578e9b 7483 }
1a578e9b
AC
7484}
7485
e0f712ba 7486#if 0 /* MAC_TODO: hide application instead of iconify? */
1a578e9b
AC
7487/* Used for IconicState or NormalState */
7488
7489void
7490x_wm_set_window_state (f, state)
7491 struct frame *f;
7492 int state;
7493{
7494#ifdef USE_X_TOOLKIT
7495 Arg al[1];
7496
7497 XtSetArg (al[0], XtNinitialState, state);
7498 XtSetValues (f->output_data.x->widget, al, 1);
7499#else /* not USE_X_TOOLKIT */
7500 Window window = FRAME_X_WINDOW (f);
7501
7502 f->output_data.x->wm_hints.flags |= StateHint;
7503 f->output_data.x->wm_hints.initial_state = state;
7504
7505 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7506#endif /* not USE_X_TOOLKIT */
7507}
7508
7509void
7510x_wm_set_icon_pixmap (f, pixmap_id)
7511 struct frame *f;
7512 int pixmap_id;
7513{
7514 Pixmap icon_pixmap;
7515
7516#ifndef USE_X_TOOLKIT
7517 Window window = FRAME_X_WINDOW (f);
7518#endif
7519
7520 if (pixmap_id > 0)
7521 {
7522 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7523 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7524 }
7525 else
7526 {
7527 /* It seems there is no way to turn off use of an icon pixmap.
7528 The following line does it, only if no icon has yet been created,
7529 for some window managers. But with mwm it crashes.
7530 Some people say it should clear the IconPixmapHint bit in this case,
7531 but that doesn't work, and the X consortium said it isn't the
7532 right thing at all. Since there is no way to win,
7533 best to explicitly give up. */
7534#if 0
7535 f->output_data.x->wm_hints.icon_pixmap = None;
7536#else
7537 return;
7538#endif
7539 }
7540
7541#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7542
7543 {
7544 Arg al[1];
7545 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7546 XtSetValues (f->output_data.x->widget, al, 1);
7547 }
7548
7549#else /* not USE_X_TOOLKIT */
177c0ea7 7550
1a578e9b
AC
7551 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7552 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7553
7554#endif /* not USE_X_TOOLKIT */
7555}
7556
e0f712ba 7557#endif /* MAC_TODO */
1a578e9b
AC
7558
7559void
7560x_wm_set_icon_position (f, icon_x, icon_y)
7561 struct frame *f;
7562 int icon_x, icon_y;
7563{
7564#if 0 /* MAC_TODO: no icons on Mac */
7565#ifdef USE_X_TOOLKIT
7566 Window window = XtWindow (f->output_data.x->widget);
7567#else
7568 Window window = FRAME_X_WINDOW (f);
7569#endif
7570
7571 f->output_data.x->wm_hints.flags |= IconPositionHint;
7572 f->output_data.x->wm_hints.icon_x = icon_x;
7573 f->output_data.x->wm_hints.icon_y = icon_y;
7574
7575 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
e0f712ba 7576#endif /* MAC_TODO */
1a578e9b
AC
7577}
7578
7579\f
468213f1
YM
7580/***********************************************************************
7581 XLFD Pattern Match
7582 ***********************************************************************/
7583
7584/* An XLFD pattern is divided into blocks delimited by '*'. This
7585 structure holds information for each block. */
7586struct xlfdpat_block
7587{
7588 /* Length of the pattern string in this block. Non-zero except for
7589 the first and the last blocks. */
7590 int len;
7591
7592 /* Pattern string except the last character in this block. The last
7593 character is replaced with NUL in order to use it as a
7594 sentinel. */
7595 unsigned char *pattern;
7596
7597 /* Last character of the pattern string. Must not be '?'. */
7598 unsigned char last_char;
7599
7600 /* One of the tables for the Boyer-Moore string search. It
7601 specifies the number of positions to proceed for each character
7602 with which the match fails. */
7603 int skip[256];
7604
7605 /* The skip value for the last character in the above `skip' is
7606 assigned to `infinity' in order to simplify a loop condition.
7607 The original value is saved here. */
7608 int last_char_skip;
7609};
7610
7611struct xlfdpat
7612{
7613 /* Normalized pattern string. "Normalized" means that capital
7614 letters are lowered, blocks are not empty except the first and
7615 the last ones, and trailing '?'s in a block that is not the last
7616 one are moved to the next one. The last character in each block
7617 is replaced with NUL. */
7618 unsigned char *buf;
7619
7620 /* Number of characters except '*'s and trailing '?'s in the
7621 normalized pattern string. */
7622 int nchars;
7623
7624 /* Number of trailing '?'s in the normalized pattern string. */
7625 int trailing_anychars;
7626
7627 /* Number of blocks and information for each block. The latter is
7628 NULL if the pattern is exact (no '*' or '?' in it). */
7629 int nblocks;
7630 struct xlfdpat_block *blocks;
7631};
7632
7633static void
7634xlfdpat_destroy (pat)
7635 struct xlfdpat *pat;
7636{
7637 if (pat)
7638 {
7639 if (pat->buf)
7640 {
70fdbb46 7641 xfree (pat->blocks);
468213f1
YM
7642 xfree (pat->buf);
7643 }
7644 xfree (pat);
7645 }
7646}
7647
7648static struct xlfdpat *
7649xlfdpat_create (pattern)
369a7a37 7650 const char *pattern;
468213f1
YM
7651{
7652 struct xlfdpat *pat;
7653 int nblocks, i, skip;
7654 unsigned char last_char, *p, *q, *anychar_head;
369a7a37 7655 const unsigned char *ptr;
468213f1
YM
7656 struct xlfdpat_block *blk;
7657
7658 pat = xmalloc (sizeof (struct xlfdpat));
468213f1 7659 pat->buf = xmalloc (strlen (pattern) + 1);
468213f1
YM
7660
7661 /* Normalize the pattern string and store it to `pat->buf'. */
7662 nblocks = 0;
7663 anychar_head = NULL;
7664 q = pat->buf;
7665 last_char = '\0';
369a7a37 7666 for (ptr = pattern; *ptr; ptr++)
468213f1 7667 {
369a7a37 7668 unsigned char c = *ptr;
468213f1
YM
7669
7670 if (c == '*')
7671 if (last_char == '*')
7672 /* ...a** -> ...a* */
7673 continue;
7674 else
7675 {
7676 if (last_char == '?')
f93e4d4f
YM
7677 {
7678 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7679 /* ...*??* -> ...*?? */
7680 continue;
7681 else
7682 /* ...a??* -> ...a*?? */
7683 {
7684 *anychar_head++ = '*';
7685 c = '?';
7686 }
7687 }
468213f1
YM
7688 nblocks++;
7689 }
7690 else if (c == '?')
7691 {
7692 if (last_char != '?')
7693 anychar_head = q;
7694 }
7695 else
7696 /* On Mac OS X 10.3, tolower also converts non-ASCII
7697 characters for some locales. */
7698 if (isascii (c))
7699 c = tolower (c);
7700
7701 *q++ = last_char = c;
7702 }
7703 *q = '\0';
7704 nblocks++;
7705 pat->nblocks = nblocks;
7706 if (last_char != '?')
7707 pat->trailing_anychars = 0;
7708 else
7709 {
7710 pat->trailing_anychars = q - anychar_head;
7711 q = anychar_head;
7712 }
7713 pat->nchars = q - pat->buf - (nblocks - 1);
7714
7715 if (anychar_head == NULL && nblocks == 1)
7716 {
7717 /* The pattern is exact. */
7718 pat->blocks = NULL;
7719 return pat;
7720 }
7721
7722 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
468213f1
YM
7723
7724 /* Divide the normalized pattern into blocks. */
7725 p = pat->buf;
7726 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7727 {
7728 blk->pattern = p;
7729 while (*p != '*')
7730 p++;
7731 blk->len = p - blk->pattern;
7732 p++;
7733 }
7734 blk->pattern = p;
7735 blk->len = q - blk->pattern;
7736
7737 /* Setup a table for the Boyer-Moore string search. */
7738 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7739 if (blk->len != 0)
7740 {
7741 blk->last_char = blk->pattern[blk->len - 1];
7742 blk->pattern[blk->len - 1] = '\0';
7743
7744 for (skip = 1; skip < blk->len; skip++)
7745 if (blk->pattern[blk->len - skip - 1] == '?')
7746 break;
7747
7748 for (i = 0; i < 256; i++)
7749 blk->skip[i] = skip;
7750
7751 p = blk->pattern + (blk->len - skip);
7752 while (--skip > 0)
7753 blk->skip[*p++] = skip;
7754
7755 blk->last_char_skip = blk->skip[blk->last_char];
7756 }
7757
7758 return pat;
468213f1
YM
7759}
7760
7761static INLINE int
7762xlfdpat_exact_p (pat)
7763 struct xlfdpat *pat;
7764{
7c3d233d 7765 return pat->blocks == NULL;
468213f1
YM
7766}
7767
7768/* Return the first string in STRING + 0, ..., STRING + START_MAX such
7769 that the pattern in *BLK matches with its prefix. Return NULL
7770 there is no such strings. STRING must be lowered in advance. */
7771
369a7a37 7772static const char *
468213f1
YM
7773xlfdpat_block_match_1 (blk, string, start_max)
7774 struct xlfdpat_block *blk;
369a7a37 7775 const unsigned char *string;
468213f1
YM
7776 int start_max;
7777{
7778 int start, infinity;
369a7a37
YM
7779 unsigned char *p;
7780 const unsigned char *s;
468213f1
YM
7781
7782 xassert (blk->len > 0);
7783 xassert (start_max + blk->len <= strlen (string));
7c3d233d 7784 xassert (blk->last_char != '?');
468213f1
YM
7785
7786 /* See the comments in the function `boyer_moore' (search.c) for the
7787 use of `infinity'. */
7788 infinity = start_max + blk->len + 1;
7789 blk->skip[blk->last_char] = infinity;
7790
7791 start = 0;
7792 do
7793 {
7794 /* Check the last character of the pattern. */
7795 s = string + blk->len - 1;
7796 do
7797 {
7798 start += blk->skip[*(s + start)];
7799 }
7800 while (start <= start_max);
7801
7802 if (start < infinity)
7803 /* Couldn't find the last character. */
7804 return NULL;
7805
7806 /* No less than `infinity' means we could find the last
7807 character at `s[start - infinity]'. */
7808 start -= infinity;
7809
7810 /* Check the remaining characters. We prefer making no-'?'
7811 cases faster because the use of '?' is really rare. */
7812 p = blk->pattern;
7813 s = string + start;
7814 do
7815 {
7816 while (*p++ == *s++)
7817 ;
7818 }
7819 while (*(p - 1) == '?');
7820
7821 if (*(p - 1) == '\0')
7822 /* Matched. */
7823 return string + start;
7824
7825 /* Didn't match. */
7826 start += blk->last_char_skip;
7827 }
7828 while (start <= start_max);
7829
7830 return NULL;
7831}
7832
7833#define xlfdpat_block_match(b, s, m) \
7834 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7835 : xlfdpat_block_match_1 (b, s, m))
7836
369a7a37 7837/* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
468213f1
YM
7838 matches with STRING. STRING must be lowered in advance. */
7839
7840static int
7841xlfdpat_match (pat, string)
7842 struct xlfdpat *pat;
369a7a37 7843 const unsigned char *string;
468213f1
YM
7844{
7845 int str_len, nblocks, i, start_max;
7846 struct xlfdpat_block *blk;
369a7a37 7847 const unsigned char *s;
468213f1
YM
7848
7849 xassert (pat->nblocks > 0);
7850
7851 if (xlfdpat_exact_p (pat))
7852 return strcmp (pat->buf, string) == 0;
7853
7854 /* The number of the characters in the string must not be smaller
7855 than that in the pattern. */
7856 str_len = strlen (string);
7857 if (str_len < pat->nchars + pat->trailing_anychars)
7858 return 0;
7859
7860 /* Chop off the trailing '?'s. */
7861 str_len -= pat->trailing_anychars;
7862
7863 /* The last block. When it is non-empty, it must match at the end
7864 of the string. */
7865 nblocks = pat->nblocks;
7866 blk = pat->blocks + (nblocks - 1);
7867 if (nblocks == 1)
7868 /* The last block is also the first one. */
7869 return (str_len == blk->len
7870 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7871 else if (blk->len != 0)
7872 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7873 return 0;
7874
7875 /* The first block. When it is non-empty, it must match at the
7876 beginning of the string. */
7877 blk = pat->blocks;
7878 if (blk->len != 0)
7879 {
7880 s = xlfdpat_block_match (blk, string, 0);
7881 if (s == NULL)
7882 return 0;
7883 string = s + blk->len;
7884 }
7885
7886 /* The rest of the blocks. */
7887 start_max = str_len - pat->nchars;
7888 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7889 {
7890 s = xlfdpat_block_match (blk, string, start_max);
7891 if (s == NULL)
7892 return 0;
7893 start_max -= s - string;
7894 string = s + blk->len;
7895 }
7896
7897 return 1;
7898}
7899
7900\f
1a578e9b
AC
7901/***********************************************************************
7902 Fonts
7903 ***********************************************************************/
7904
7905/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7906
7907struct font_info *
7908x_get_font_info (f, font_idx)
7909 FRAME_PTR f;
7910 int font_idx;
7911{
7912 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7913}
7914
7915/* the global font name table */
95dfb192
YM
7916static char **font_name_table = NULL;
7917static int font_name_table_size = 0;
7918static int font_name_count = 0;
1a578e9b 7919
71b7a47f
YM
7920/* Alist linking font family names to Font Manager font family
7921 references (which can also be used as QuickDraw font IDs). We use
7922 an alist because hash tables are not ready when the terminal frame
7923 for Mac OS Classic is created. */
7924static Lisp_Object fm_font_family_alist;
c3bd8190 7925#if USE_ATSUI
71b7a47f 7926/* Hash table linking font family names to ATSU font IDs. */
c3bd8190 7927static Lisp_Object atsu_font_id_hash;
92289429
YM
7928/* Alist linking Font Manager style to face attributes. */
7929static Lisp_Object fm_style_face_attributes_alist;
68c767a3 7930extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
c3bd8190
YM
7931#endif
7932
94d0e806
YM
7933/* Alist linking character set strings to Mac text encoding and Emacs
7934 coding system. */
7935static Lisp_Object Vmac_charset_info_alist;
1a578e9b 7936
94d0e806
YM
7937static Lisp_Object
7938create_text_encoding_info_alist ()
1a578e9b 7939{
94d0e806 7940 Lisp_Object result = Qnil, rest;
1a578e9b 7941
94d0e806
YM
7942 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7943 {
7944 Lisp_Object charset_info = XCAR (rest);
7945 Lisp_Object charset, coding_system, text_encoding;
7946 Lisp_Object existing_info;
1a578e9b 7947
94d0e806 7948 if (!(CONSP (charset_info)
b51065cf
YM
7949 && (charset = XCAR (charset_info),
7950 STRINGP (charset))
94d0e806 7951 && CONSP (XCDR (charset_info))
b51065cf
YM
7952 && (text_encoding = XCAR (XCDR (charset_info)),
7953 INTEGERP (text_encoding))
94d0e806 7954 && CONSP (XCDR (XCDR (charset_info)))
b51065cf
YM
7955 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7956 SYMBOLP (coding_system))))
94d0e806 7957 continue;
1a578e9b 7958
94d0e806
YM
7959 existing_info = assq_no_quit (text_encoding, result);
7960 if (NILP (existing_info))
7961 result = Fcons (list3 (text_encoding, coding_system, charset),
7962 result);
1a578e9b 7963 else
94d0e806
YM
7964 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7965 XSETCDR (XCDR (existing_info),
7966 Fcons (charset, XCDR (XCDR (existing_info))));
1a578e9b 7967 }
1a578e9b 7968
94d0e806 7969 return result;
1a578e9b 7970}
6b61353c 7971
6b61353c
KH
7972
7973static void
94d0e806 7974decode_mac_font_name (name, size, coding_system)
fc7a70cc
ST
7975 char *name;
7976 int size;
94d0e806 7977 Lisp_Object coding_system;
6b61353c 7978{
6b61353c 7979 struct coding_system coding;
94d0e806 7980 char *buf, *p;
6b61353c 7981
71b7a47f
YM
7982 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7983 {
7984 for (p = name; *p; p++)
7985 if (!isascii (*p) || iscntrl (*p))
7986 break;
94d0e806 7987
71b7a47f
YM
7988 if (*p)
7989 {
7990 setup_coding_system (coding_system, &coding);
7991 coding.src_multibyte = 0;
7992 coding.dst_multibyte = 1;
7993 coding.mode |= CODING_MODE_LAST_BLOCK;
6abfb022
YM
7994 coding.dst_bytes = size;
7995 coding.destination = (unsigned char *) alloca (coding.dst_bytes);
71b7a47f 7996
6abfb022
YM
7997 decode_coding_c_string (&coding, name, strlen (name), Qnil);
7998 bcopy (coding.destination, name, min (coding.produced, size));
7999 name[min (coding.produced, size)] = '\0';
71b7a47f
YM
8000 }
8001 }
6b61353c 8002
71b7a47f
YM
8003 /* If there's just one occurrence of '-' in the family name, it is
8004 replaced with '_'. (More than one occurrence of '-' means a
8005 "FOUNDRY-FAMILY-CHARSET"-style name.) */
8006 p = strchr (name, '-');
8007 if (p && strchr (p + 1, '-') == NULL)
8008 *p = '_';
6b61353c 8009
71b7a47f
YM
8010 for (p = name; *p; p++)
8011 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8012 for some locales. */
8013 if (isascii (*p))
8014 *p = tolower (*p);
6b61353c 8015}
1a578e9b
AC
8016
8017
8018static char *
94d0e806 8019mac_to_x_fontname (name, size, style, charset)
369a7a37 8020 const char *name;
fc7a70cc
ST
8021 int size;
8022 Style style;
94d0e806 8023 char *charset;
1a578e9b 8024{
dd15724d
YM
8025 Str31 foundry, cs;
8026 Str255 family;
468213f1
YM
8027 char xf[256], *result;
8028 unsigned char *p;
1a578e9b 8029
dd15724d 8030 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
94d0e806
YM
8031 charset = cs;
8032 else
1a578e9b
AC
8033 {
8034 strcpy(foundry, "Apple");
8035 strcpy(family, name);
1a578e9b
AC
8036 }
8037
dd15724d
YM
8038 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
8039 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
05f7d868 8040 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
177c0ea7 8041
dd15724d
YM
8042 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
8043 sprintf (result, "-%s-%s-%s", foundry, family, xf);
1a578e9b 8044 for (p = result; *p; p++)
468213f1
YM
8045 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8046 for some locales. */
8047 if (isascii (*p))
8048 *p = tolower (*p);
1a578e9b
AC
8049 return result;
8050}
177c0ea7 8051
1a578e9b 8052
71b7a47f
YM
8053/* Parse fully-specified and instantiated X11 font spec XF, and store
8054 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
8055 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
8056 caller must allocate at least 256 and 32 bytes respectively. For
8057 ordinary Mac fonts, the value stored to FAMILY should just be their
8058 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
8059 intlfonts collection contain their charset designation in their
8060 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
8061 types of font names are handled accordingly. */
8062
8063const int kDefaultFontSize = 12;
8064
8065static int
8066parse_x_font_name (xf, family, size, style, charset)
369a7a37
YM
8067 const char *xf;
8068 char *family;
71b7a47f 8069 int *size;
94d0e806 8070 Style *style;
71b7a47f 8071 char *charset;
1a578e9b 8072{
71b7a47f
YM
8073 Str31 foundry, weight;
8074 int point_size, avgwidth;
8075 char slant[2], *p;
1a578e9b 8076
71b7a47f
YM
8077 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8078 foundry, family, weight, slant, size,
8079 &point_size, &avgwidth, charset) != 8
8080 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8081 foundry, family, weight, slant, size,
8082 &point_size, &avgwidth, charset) != 8)
8083 return 0;
1a578e9b 8084
71b7a47f
YM
8085 if (*size == 0)
8086 {
8087 if (point_size > 0)
8088 *size = point_size / 10;
8089 else if (avgwidth > 0)
8090 *size = avgwidth / 10;
8091 }
8092 if (*size == 0)
8093 *size = kDefaultFontSize;
1a578e9b 8094
94d0e806
YM
8095 *style = normal;
8096 if (strcmp (weight, "bold") == 0)
8097 *style |= bold;
8098 if (*slant == 'i')
8099 *style |= italic;
8100
71b7a47f 8101 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
94d0e806 8102 {
71b7a47f
YM
8103 int foundry_len = strlen (foundry), family_len = strlen (family);
8104
8105 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
8106 {
8107 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
8108 but take overlap into account. */
8109 memmove (family + foundry_len + 1, family, family_len);
8110 memcpy (family, foundry, foundry_len);
8111 family[foundry_len] = '-';
8112 family[foundry_len + 1 + family_len] = '-';
8113 strcpy (family + foundry_len + 1 + family_len + 1, charset);
8114 }
8115 else
8116 return 0;
94d0e806 8117 }
6b61353c 8118
71b7a47f
YM
8119 for (p = family; *p; p++)
8120 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8121 for some locales. */
8122 if (isascii (*p))
8123 *p = tolower (*p);
40b9c9c2 8124
71b7a47f 8125 return 1;
1a578e9b
AC
8126}
8127
8128
f00691a3
AC
8129static void
8130add_font_name_table_entry (char *font_name)
8131{
8132 if (font_name_table_size == 0)
8133 {
468213f1 8134 font_name_table_size = 256;
f00691a3
AC
8135 font_name_table = (char **)
8136 xmalloc (font_name_table_size * sizeof (char *));
8137 }
8138 else if (font_name_count + 1 >= font_name_table_size)
8139 {
468213f1 8140 font_name_table_size *= 2;
f00691a3
AC
8141 font_name_table = (char **)
8142 xrealloc (font_name_table,
8143 font_name_table_size * sizeof (char *));
8144 }
8145
8146 font_name_table[font_name_count++] = font_name;
8147}
8148
a0c62ca2
YM
8149static void
8150add_mac_font_name (name, size, style, charset)
369a7a37 8151 const char *name;
a0c62ca2
YM
8152 int size;
8153 Style style;
369a7a37 8154 const char *charset;
a0c62ca2
YM
8155{
8156 if (size > 0)
8157 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8158 else
8159 {
8160 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8161 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8162 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8163 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8164 charset));
8165 }
8166}
8167
92289429 8168#if USE_ATSUI
0d36bf23
YM
8169static FMFontStyle
8170fm_get_style_from_font (font)
8171 FMFont font;
8172{
8173 OSStatus err;
8174 FMFontStyle style = normal;
8175 ByteCount len;
8176 UInt16 mac_style;
8177 FMFontFamily font_family;
8178#define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8179
8180 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8181 some font (e.g., Optima) even if it is `bold'. */
8182 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8183 sizeof (mac_style), &mac_style, &len);
8184 if (err == noErr
8185 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8186 style = EndianU16_BtoN (mac_style);
8187 else
8188 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8189
8190 return style;
8191}
8192
8193static ATSUFontID
8194atsu_find_font_from_family_name (family)
8195 const char *family;
8196{
8197 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8198 unsigned hash_code;
8199 int i;
8200 Lisp_Object rest, best;
8201 FMFontStyle min_style, style;
8202
8203 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8204 &hash_code);
8205 if (i < 0)
8206 return kATSUInvalidFontID;
8207
8208 rest = HASH_VALUE (h, i);
8209 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8210 return cons_to_long (rest);
8211
8212 rest = Fnreverse (rest);
8213 best = XCAR (rest);
8214 rest = XCDR (rest);
8215 if (!NILP (rest)
8216 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8217 do
8218 {
8219 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8220 if (style < min_style)
8221 {
8222 best = XCAR (rest);
8223 if (style == normal)
8224 break;
8225 else
8226 min_style = style;
8227 }
8228 rest = XCDR (rest);
8229 }
8230 while (!NILP (rest));
8231
8232 HASH_VALUE (h, i) = best;
8233 return cons_to_long (best);
8234}
8235
92289429
YM
8236static Lisp_Object
8237fm_style_to_face_attributes (fm_style)
8238 FMFontStyle fm_style;
8239{
8240 Lisp_Object tem;
8241
8242 fm_style &= (bold | italic);
8243 tem = assq_no_quit (make_number (fm_style),
8244 fm_style_face_attributes_alist);
8245 if (!NILP (tem))
8246 return XCDR (tem);
8247
8248 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8249 QCslant, fm_style & italic ? Qitalic : Qnormal);
8250 fm_style_face_attributes_alist =
8251 Fcons (Fcons (make_number (fm_style), tem),
8252 fm_style_face_attributes_alist);
8253
8254 return tem;
8255}
0d36bf23
YM
8256
8257static Lisp_Object
8258atsu_find_font_family_name (font_id)
8259 ATSUFontID font_id;
8260{
8261 OSStatus err;
8262 ByteCount len;
8263 Lisp_Object family = Qnil;
8264
8265 err = ATSUFindFontName (font_id, kFontFamilyName,
8266 kFontMacintoshPlatform, kFontNoScript,
8267 kFontNoLanguage, 0, NULL, &len, NULL);
8268 if (err == noErr)
8269 {
8270 family = make_uninit_string (len);
8271 err = ATSUFindFontName (font_id, kFontFamilyName,
8272 kFontMacintoshPlatform, kFontNoScript,
8273 kFontNoLanguage, len, SDATA (family),
8274 NULL, NULL);
8275 }
8276 if (err == noErr)
8277 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8278
8279 return family;
8280}
8281
8282Lisp_Object
8283mac_atsu_font_face_attributes (font_id)
8284 ATSUFontID font_id;
8285{
8286 Lisp_Object family, style_attrs;
8287
8288 family = atsu_find_font_family_name (font_id);
8289 if (NILP (family))
8290 return Qnil;
8291 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8292 return Fcons (QCfamily, Fcons (family, style_attrs));
8293}
92289429
YM
8294#endif
8295
f00691a3
AC
8296/* Sets up the table font_name_table to contain the list of all fonts
8297 in the system the first time the table is used so that the Resource
8298 Manager need not be accessed every time this information is
8299 needed. */
1a578e9b
AC
8300
8301static void
8302init_font_name_table ()
8303{
e0f712ba 8304#if TARGET_API_MAC_CARBON
94d0e806
YM
8305 FMFontFamilyIterator ffi;
8306 FMFontFamilyInstanceIterator ffii;
8307 FMFontFamily ff;
8308 Lisp_Object text_encoding_info_alist;
8309 struct gcpro gcpro1;
8310
c3bd8190
YM
8311 text_encoding_info_alist = create_text_encoding_info_alist ();
8312
8313#if USE_ATSUI
6b9ad469
YM
8314#if USE_CG_TEXT_DRAWING
8315 init_cg_text_anti_aliasing_threshold ();
8316#endif
c3bd8190
YM
8317 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8318 text_encoding_info_alist)))
8319 {
3e7424f7 8320 OSStatus err;
a0c62ca2
YM
8321 struct Lisp_Hash_Table *h;
8322 unsigned hash_code;
c3bd8190
YM
8323 ItemCount nfonts, i;
8324 ATSUFontID *font_ids = NULL;
0d36bf23
YM
8325 Lisp_Object prev_family = Qnil;
8326 int j;
c3bd8190
YM
8327
8328 atsu_font_id_hash =
8329 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8330 make_float (DEFAULT_REHASH_SIZE),
8331 make_float (DEFAULT_REHASH_THRESHOLD),
3b8c0c70 8332 Qnil, Qnil, Qnil);
a0c62ca2
YM
8333 h = XHASH_TABLE (atsu_font_id_hash);
8334
c3bd8190
YM
8335 err = ATSUFontCount (&nfonts);
8336 if (err == noErr)
b96fe6ea
YM
8337 {
8338 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8339 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8340 }
c3bd8190
YM
8341 if (err == noErr)
8342 for (i = 0; i < nfonts; i++)
8343 {
0d36bf23
YM
8344 Lisp_Object family;
8345
8346 family = atsu_find_font_family_name (font_ids[i]);
8347 if (NILP (family) || SREF (family, 0) == '.')
c3bd8190 8348 continue;
0d36bf23
YM
8349 if (!NILP (Fequal (prev_family, family)))
8350 family = prev_family;
8351 else
8352 j = hash_lookup (h, family, &hash_code);
8353 if (j < 0)
c3bd8190 8354 {
0d36bf23
YM
8355 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8356 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8357 Qnil), hash_code);
c3bd8190 8358 }
0d36bf23
YM
8359 else if (EQ (prev_family, family))
8360 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8361 HASH_VALUE (h, j));
8362 prev_family = family;
c3bd8190 8363 }
70fdbb46 8364 xfree (font_ids);
c3bd8190
YM
8365 }
8366#endif
8367
94d0e806
YM
8368 /* Create a dummy instance iterator here to avoid creating and
8369 destroying it in the loop. */
8370 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8371 return;
8372 /* Create an iterator to enumerate the font families. */
8373 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8374 != noErr)
8375 {
8376 FMDisposeFontFamilyInstanceIterator (&ffii);
8377 return;
8378 }
177c0ea7 8379
94d0e806
YM
8380 GCPRO1 (text_encoding_info_alist);
8381
8382 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
e0f712ba 8383 {
94d0e806
YM
8384 Str255 name;
8385 FMFont font;
8386 FMFontStyle style;
8387 FMFontSize size;
8388 TextEncoding encoding;
8389 TextEncodingBase sc;
a0c62ca2 8390 Lisp_Object text_encoding_info, family;
1a578e9b 8391
94d0e806 8392 if (FMGetFontFamilyName (ff, name) != noErr)
a0c62ca2 8393 continue;
94d0e806
YM
8394 p2cstr (name);
8395 if (*name == '.')
8396 continue;
1a578e9b 8397
94d0e806 8398 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
a0c62ca2 8399 continue;
94d0e806
YM
8400 sc = GetTextEncodingBase (encoding);
8401 text_encoding_info = assq_no_quit (make_number (sc),
8402 text_encoding_info_alist);
71b7a47f 8403 if (NILP (text_encoding_info))
94d0e806
YM
8404 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8405 text_encoding_info_alist);
71b7a47f
YM
8406 decode_mac_font_name (name, sizeof (name),
8407 XCAR (XCDR (text_encoding_info)));
a0c62ca2
YM
8408 family = build_string (name);
8409 if (!NILP (Fassoc (family, fm_font_family_alist)))
8410 continue;
8411 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
71b7a47f 8412 fm_font_family_alist);
177c0ea7 8413
94d0e806
YM
8414 /* Point the instance iterator at the current font family. */
8415 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
a0c62ca2 8416 continue;
b15325b2 8417
94d0e806
YM
8418 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8419 == noErr)
8420 {
8421 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
177c0ea7 8422
7c3d233d 8423 if (size > 0 || style == normal)
9beb8baa 8424 for (; CONSP (rest); rest = XCDR (rest))
a0c62ca2 8425 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
e0f712ba 8426 }
e0f712ba 8427 }
94d0e806
YM
8428
8429 UNGCPRO;
8430
8431 /* Dispose of the iterators. */
8432 FMDisposeFontFamilyIterator (&ffi);
8433 FMDisposeFontFamilyInstanceIterator (&ffii);
8434#else /* !TARGET_API_MAC_CARBON */
8435 GrafPtr port;
8436 SInt16 fontnum, old_fontnum;
8437 int num_mac_fonts = CountResources('FOND');
8438 int i, j;
8439 Handle font_handle, font_handle_2;
8440 short id, scriptcode;
8441 ResType type;
dd15724d 8442 Str255 name;
94d0e806
YM
8443 struct FontAssoc *fat;
8444 struct AsscEntry *assc_entry;
a0c62ca2 8445 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
94d0e806
YM
8446 struct gcpro gcpro1;
8447
8448 GetPort (&port); /* save the current font number used */
8449 old_fontnum = port->txFont;
8450
8451 text_encoding_info_alist = create_text_encoding_info_alist ();
8452
8453 GCPRO1 (text_encoding_info_alist);
8454
8455 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
1a578e9b 8456 {
94d0e806
YM
8457 font_handle = GetIndResource ('FOND', i);
8458 if (!font_handle)
8459 continue;
e0f712ba 8460
94d0e806
YM
8461 GetResInfo (font_handle, &id, &type, name);
8462 GetFNum (name, &fontnum);
8463 p2cstr (name);
a0c62ca2 8464 if (fontnum == 0 || *name == '.')
94d0e806 8465 continue;
177c0ea7 8466
94d0e806
YM
8467 TextFont (fontnum);
8468 scriptcode = FontToScript (fontnum);
8469 text_encoding_info = assq_no_quit (make_number (scriptcode),
8470 text_encoding_info_alist);
71b7a47f 8471 if (NILP (text_encoding_info))
94d0e806
YM
8472 text_encoding_info = assq_no_quit (make_number (smRoman),
8473 text_encoding_info_alist);
71b7a47f
YM
8474 decode_mac_font_name (name, sizeof (name),
8475 XCAR (XCDR (text_encoding_info)));
a0c62ca2
YM
8476 family = build_string (name);
8477 if (!NILP (Fassoc (family, fm_font_family_alist)))
8478 continue;
8479 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
71b7a47f 8480 fm_font_family_alist);
94d0e806
YM
8481 do
8482 {
8483 HLock (font_handle);
177c0ea7 8484
94d0e806
YM
8485 if (GetResourceSizeOnDisk (font_handle)
8486 >= sizeof (struct FamRec))
e0f712ba 8487 {
94d0e806
YM
8488 fat = (struct FontAssoc *) (*font_handle
8489 + sizeof (struct FamRec));
8490 assc_entry
8491 = (struct AsscEntry *) (*font_handle
8492 + sizeof (struct FamRec)
8493 + sizeof (struct FontAssoc));
8494
8495 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
e0f712ba 8496 {
94d0e806
YM
8497 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8498
9beb8baa 8499 for (; CONSP (rest); rest = XCDR (rest))
a0c62ca2
YM
8500 add_mac_font_name (name, assc_entry->fontSize,
8501 assc_entry->fontStyle,
8502 SDATA (XCAR (rest)));
e0f712ba 8503 }
e0f712ba 8504 }
177c0ea7 8505
94d0e806
YM
8506 HUnlock (font_handle);
8507 font_handle_2 = GetNextFOND (font_handle);
8508 ReleaseResource (font_handle);
8509 font_handle = font_handle_2;
8510 }
8511 while (ResError () == noErr && font_handle);
1a578e9b 8512 }
94d0e806
YM
8513
8514 UNGCPRO;
8515
8516 TextFont (old_fontnum);
8517#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
8518}
8519
8520
b15325b2
ST
8521void
8522mac_clear_font_name_table ()
8523{
8524 int i;
8525
8526 for (i = 0; i < font_name_count; i++)
8527 xfree (font_name_table[i]);
8528 xfree (font_name_table);
8529 font_name_table = NULL;
8530 font_name_table_size = font_name_count = 0;
71b7a47f 8531 fm_font_family_alist = Qnil;
b15325b2
ST
8532}
8533
8534
6b61353c
KH
8535enum xlfd_scalable_field_index
8536 {
8537 XLFD_SCL_PIXEL_SIZE,
8538 XLFD_SCL_POINT_SIZE,
8539 XLFD_SCL_AVGWIDTH,
8540 XLFD_SCL_LAST
8541 };
8542
369a7a37 8543static const int xlfd_scalable_fields[] =
6b61353c
KH
8544 {
8545 6, /* PIXEL_SIZE */
8546 7, /* POINT_SIZE */
8547 11, /* AVGWIDTH */
8548 -1
8549 };
8550
8551static Lisp_Object
8552mac_do_list_fonts (pattern, maxnames)
369a7a37 8553 const char *pattern;
6b61353c
KH
8554 int maxnames;
8555{
8556 int i, n_fonts = 0;
468213f1
YM
8557 Lisp_Object font_list = Qnil;
8558 struct xlfdpat *pat;
369a7a37
YM
8559 char *scaled;
8560 const char *ptr;
8561 int scl_val[XLFD_SCL_LAST], *val;
8562 const int *field;
468213f1 8563 int exact;
e3564461 8564
b15325b2
ST
8565 if (font_name_table == NULL) /* Initialize when first used. */
8566 init_font_name_table ();
6b61353c
KH
8567
8568 for (i = 0; i < XLFD_SCL_LAST; i++)
8569 scl_val[i] = -1;
8570
8571 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8572 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8573 fonts are scaled according to the specified size. */
8574 ptr = pattern;
8575 i = 0;
8576 field = xlfd_scalable_fields;
8577 val = scl_val;
8578 if (*ptr == '-')
8579 do
8580 {
8581 ptr++;
8582 if (i == *field)
8583 {
94d0e806 8584 if ('0' <= *ptr && *ptr <= '9')
6b61353c
KH
8585 {
8586 *val = *ptr++ - '0';
8587 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8588 *val = *val * 10 + *ptr++ - '0';
8589 if (*ptr != '-')
8590 *val = -1;
8591 }
8592 field++;
8593 val++;
8594 }
8595 ptr = strchr (ptr, '-');
8596 i++;
8597 }
8598 while (ptr && i < 14);
8599
8600 if (i == 14 && ptr == NULL)
8601 {
94d0e806
YM
8602 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8603 scl_val[XLFD_SCL_PIXEL_SIZE] =
8604 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8605 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8606 : -1));
8607 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8608 scl_val[XLFD_SCL_POINT_SIZE] =
8609 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8610 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8611 : -1));
8612 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8613 scl_val[XLFD_SCL_AVGWIDTH] =
8614 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8615 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8616 : -1));
6b61353c
KH
8617 }
8618 else
8619 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8620
468213f1
YM
8621 pat = xlfdpat_create (pattern);
8622 if (pat == NULL)
8623 return Qnil;
fbe6152f 8624
468213f1 8625 exact = xlfdpat_exact_p (pat);
6b61353c
KH
8626
8627 for (i = 0; i < font_name_count; i++)
8628 {
468213f1 8629 if (xlfdpat_match (pat, font_name_table[i]))
6b61353c 8630 {
468213f1 8631 font_list = Fcons (build_string (font_name_table[i]), font_list);
f93e4d4f 8632 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
68c69027 8633 break;
6b61353c
KH
8634 }
8635 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
b0241f69 8636 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
6b61353c
KH
8637 {
8638 int former_len = ptr - font_name_table[i];
8639
dd15724d 8640 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
6b61353c
KH
8641 memcpy (scaled, font_name_table[i], former_len);
8642 sprintf (scaled + former_len,
05f7d868 8643 "-%d-%d-72-72-m-%d-%s",
6b61353c
KH
8644 scl_val[XLFD_SCL_PIXEL_SIZE],
8645 scl_val[XLFD_SCL_POINT_SIZE],
8646 scl_val[XLFD_SCL_AVGWIDTH],
b0241f69 8647 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
468213f1
YM
8648
8649 if (xlfdpat_match (pat, scaled))
6b61353c 8650 {
468213f1
YM
8651 font_list = Fcons (build_string (scaled), font_list);
8652 xfree (scaled);
f93e4d4f 8653 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
468213f1 8654 break;
6b61353c 8655 }
468213f1
YM
8656 else
8657 xfree (scaled);
6b61353c
KH
8658 }
8659 }
fbe6152f 8660
468213f1 8661 xlfdpat_destroy (pat);
fbe6152f 8662
6b61353c
KH
8663 return font_list;
8664}
8665
94d0e806
YM
8666/* Return a list of names of available fonts matching PATTERN on frame F.
8667
8668 Frame F null means we have not yet created any frame on Mac, and
8669 consult the first display in x_display_list. MAXNAMES sets a limit
8670 on how many fonts to match. */
1a578e9b
AC
8671
8672Lisp_Object
94d0e806
YM
8673x_list_fonts (f, pattern, size, maxnames)
8674 struct frame *f;
8675 Lisp_Object pattern;
8676 int size, maxnames;
1a578e9b 8677{
94d0e806
YM
8678 Lisp_Object list = Qnil, patterns, tem, key;
8679 struct mac_display_info *dpyinfo
8680 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
1a578e9b 8681
94d0e806
YM
8682 xassert (size <= 0);
8683
8684 patterns = Fassoc (pattern, Valternate_fontname_alist);
8685 if (NILP (patterns))
8686 patterns = Fcons (pattern, Qnil);
1a578e9b 8687
94d0e806 8688 for (; CONSP (patterns); patterns = XCDR (patterns))
10ba2aec 8689 {
94d0e806
YM
8690 pattern = XCAR (patterns);
8691
8692 if (!STRINGP (pattern))
8693 continue;
8694
b298e813 8695 tem = XCAR (XCDR (dpyinfo->name_list_element));
10ba2aec
AC
8696 key = Fcons (pattern, make_number (maxnames));
8697
94d0e806
YM
8698 list = Fassoc (key, tem);
8699 if (!NILP (list))
10ba2aec 8700 {
94d0e806
YM
8701 list = Fcdr_safe (list);
8702 /* We have a cashed list. Don't have to get the list again. */
10ba2aec
AC
8703 goto label_cached;
8704 }
10ba2aec 8705
94d0e806
YM
8706 BLOCK_INPUT;
8707 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8708 UNBLOCK_INPUT;
177c0ea7 8709
94d0e806 8710 /* MAC_TODO: add code for matching outline fonts here */
1a578e9b 8711
94d0e806 8712 /* Now store the result in the cache. */
b298e813 8713 XSETCAR (XCDR (dpyinfo->name_list_element),
94d0e806 8714 Fcons (Fcons (key, list),
b298e813 8715 XCAR (XCDR (dpyinfo->name_list_element))));
94d0e806
YM
8716
8717 label_cached:
8718 if (NILP (list)) continue; /* Try the remaining alternatives. */
10ba2aec 8719 }
177c0ea7 8720
94d0e806 8721 return list;
1a578e9b
AC
8722}
8723
8724
8725#if GLYPH_DEBUG
8726
e0f712ba
AC
8727/* Check that FONT is valid on frame F. It is if it can be found in F's
8728 font table. */
1a578e9b
AC
8729
8730static void
8731x_check_font (f, font)
8732 struct frame *f;
8733 XFontStruct *font;
8734{
8735 int i;
8736 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8737
8738 xassert (font != NULL);
8739
8740 for (i = 0; i < dpyinfo->n_fonts; i++)
177c0ea7 8741 if (dpyinfo->font_table[i].name
1a578e9b
AC
8742 && font == dpyinfo->font_table[i].font)
8743 break;
8744
8745 xassert (i < dpyinfo->n_fonts);
8746}
8747
8748#endif /* GLYPH_DEBUG != 0 */
8749
1a578e9b
AC
8750/* Set *W to the minimum width, *H to the minimum font height of FONT.
8751 Note: There are (broken) X fonts out there with invalid XFontStruct
8752 min_bounds contents. For example, handa@etl.go.jp reports that
8753 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8754 have font->min_bounds.width == 0. */
8755
8756static INLINE void
8757x_font_min_bounds (font, w, h)
8758 MacFontStruct *font;
8759 int *w, *h;
8760{
8761 *h = FONT_HEIGHT (font);
e169f939 8762 *w = font->min_bounds.width;
1a578e9b
AC
8763}
8764
8765
8766/* Compute the smallest character width and smallest font height over
8767 all fonts available on frame F. Set the members smallest_char_width
8768 and smallest_font_height in F's x_display_info structure to
8769 the values computed. Value is non-zero if smallest_font_height or
8770 smallest_char_width become smaller than they were before. */
8771
dd15724d 8772static int
1a578e9b
AC
8773x_compute_min_glyph_bounds (f)
8774 struct frame *f;
8775{
8776 int i;
8777 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8778 MacFontStruct *font;
8779 int old_width = dpyinfo->smallest_char_width;
8780 int old_height = dpyinfo->smallest_font_height;
177c0ea7 8781
1a578e9b
AC
8782 dpyinfo->smallest_font_height = 100000;
8783 dpyinfo->smallest_char_width = 100000;
177c0ea7 8784
1a578e9b
AC
8785 for (i = 0; i < dpyinfo->n_fonts; ++i)
8786 if (dpyinfo->font_table[i].name)
8787 {
8788 struct font_info *fontp = dpyinfo->font_table + i;
8789 int w, h;
177c0ea7 8790
1a578e9b
AC
8791 font = (MacFontStruct *) fontp->font;
8792 xassert (font != (MacFontStruct *) ~0);
8793 x_font_min_bounds (font, &w, &h);
177c0ea7 8794
1a578e9b
AC
8795 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8796 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8797 }
8798
8799 xassert (dpyinfo->smallest_char_width > 0
8800 && dpyinfo->smallest_font_height > 0);
8801
8802 return (dpyinfo->n_fonts == 1
8803 || dpyinfo->smallest_char_width < old_width
8804 || dpyinfo->smallest_font_height < old_height);
8805}
8806
8807
8808/* Determine whether given string is a fully-specified XLFD: all 14
8809 fields are present, none is '*'. */
8810
8811static int
369a7a37
YM
8812is_fully_specified_xlfd (p)
8813 const char *p;
1a578e9b
AC
8814{
8815 int i;
8816 char *q;
8817
8818 if (*p != '-')
8819 return 0;
177c0ea7 8820
1a578e9b
AC
8821 for (i = 0; i < 13; i++)
8822 {
8823 q = strchr (p + 1, '-');
8824 if (q == NULL)
8825 return 0;
8826 if (q - p == 2 && *(p + 1) == '*')
8827 return 0;
8828 p = q;
8829 }
8830
8831 if (strchr (p + 1, '-') != NULL)
8832 return 0;
177c0ea7 8833
1a578e9b
AC
8834 if (*(p + 1) == '*' && *(p + 2) == '\0')
8835 return 0;
8836
8837 return 1;
8838}
8839
8840
bb420759
YM
8841/* mac_load_query_font creates and returns an internal representation
8842 for a font in a MacFontStruct struct. There is really no concept
e0f712ba
AC
8843 corresponding to "loading" a font on the Mac. But we check its
8844 existence and find the font number and all other information for it
8845 and store them in the returned MacFontStruct. */
1a578e9b
AC
8846
8847static MacFontStruct *
bb420759
YM
8848mac_load_query_font (f, fontname)
8849 struct frame *f;
8850 char *fontname;
1a578e9b 8851{
b73e4d84 8852 int size;
1a578e9b 8853 char *name;
71b7a47f 8854 Str255 family;
dd15724d 8855 Str31 charset;
1a578e9b 8856 SInt16 fontnum;
c3bd8190 8857#if USE_ATSUI
16805b2e 8858 static ATSUFontID font_id;
c3bd8190
YM
8859 ATSUStyle mac_style = NULL;
8860#endif
94d0e806
YM
8861 Style fontface;
8862#if TARGET_API_MAC_CARBON
8863 TextEncoding encoding;
8864 int scriptcode;
8865#else
8866 short scriptcode;
8867#endif
1a578e9b 8868 MacFontStruct *font;
b73e4d84 8869 XCharStruct *space_bounds = NULL, *pcm;
1a578e9b
AC
8870
8871 if (is_fully_specified_xlfd (fontname))
8872 name = fontname;
8873 else
8874 {
6b61353c 8875 Lisp_Object matched_fonts;
1a578e9b 8876
6b61353c
KH
8877 matched_fonts = mac_do_list_fonts (fontname, 1);
8878 if (NILP (matched_fonts))
8879 return NULL;
8880 name = SDATA (XCAR (matched_fonts));
1a578e9b
AC
8881 }
8882
71b7a47f
YM
8883 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8884 return NULL;
1a578e9b 8885
c3bd8190
YM
8886#if USE_ATSUI
8887 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8888 {
3e7424f7 8889 OSStatus err;
369a7a37
YM
8890 static const ATSUAttributeTag tags[] =
8891 {kATSUFontTag, kATSUSizeTag,
8892 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8893 static const ByteCount sizes[] =
8894 {sizeof (ATSUFontID), sizeof (Fixed),
8895 sizeof (Boolean), sizeof (Boolean)};
c3bd8190
YM
8896 static Fixed size_fixed;
8897 static Boolean bold_p, italic_p;
369a7a37
YM
8898 static const ATSUAttributeValuePtr values[] =
8899 {&font_id, &size_fixed,
8900 &bold_p, &italic_p};
8901 static const ATSUFontFeatureType types[] =
8902 {kAllTypographicFeaturesType, kDiacriticsType};
8903 static const ATSUFontFeatureSelector selectors[] =
8904 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
68c767a3 8905 FMFontStyle style;
1c4ac540 8906
0d36bf23
YM
8907 font_id = atsu_find_font_from_family_name (family);
8908 if (font_id == kATSUInvalidFontID)
cb91e86a 8909 return NULL;
c3bd8190
YM
8910 size_fixed = Long2Fix (size);
8911 bold_p = (fontface & bold) != 0;
8912 italic_p = (fontface & italic) != 0;
8913 err = ATSUCreateStyle (&mac_style);
8914 if (err != noErr)
8915 return NULL;
8916 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8917 types, selectors);
8918 if (err != noErr)
8919 return NULL;
8920 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8921 tags, sizes, values);
68c767a3
YM
8922 if (err != noErr)
8923 return NULL;
8924 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8925 if (err != noErr)
8926 fontnum = -1;
c3bd8190
YM
8927 scriptcode = kTextEncodingMacUnicode;
8928 }
8929 else
c3bd8190 8930#endif
71b7a47f
YM
8931 {
8932 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8933
8934 if (NILP (tmp))
8935 return NULL;
8936 fontnum = XINT (XCDR (tmp));
94d0e806 8937#if TARGET_API_MAC_CARBON
71b7a47f
YM
8938 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8939 return NULL;
8940 scriptcode = GetTextEncodingBase (encoding);
94d0e806 8941#else
71b7a47f 8942 scriptcode = FontToScript (fontnum);
94d0e806 8943#endif
c3bd8190 8944 }
177c0ea7 8945
1a578e9b 8946 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
177c0ea7 8947
1a578e9b
AC
8948 font->mac_fontnum = fontnum;
8949 font->mac_fontsize = size;
8950 font->mac_fontface = fontface;
94d0e806 8951 font->mac_scriptcode = scriptcode;
c3bd8190
YM
8952#if USE_ATSUI
8953 font->mac_style = mac_style;
16805b2e
YM
8954#if USE_CG_TEXT_DRAWING
8955 font->cg_font = NULL;
8956 font->cg_glyphs = NULL;
8957#endif
c3bd8190 8958#endif
1a578e9b 8959
199f9270 8960 /* Apple Japanese (SJIS) font is listed as both
2f64cf3a 8961 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
e0f712ba 8962 (Roman script) in init_font_name_table (). The latter should be
2f64cf3a 8963 treated as a one-byte font. */
94d0e806
YM
8964 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8965 font->mac_scriptcode = smRoman;
199f9270 8966
71b7a47f 8967 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
177c0ea7 8968
c3bd8190
YM
8969#if USE_ATSUI
8970 if (font->mac_style)
8971 {
3e7424f7 8972 OSStatus err;
b73e4d84 8973 UniChar c;
c3bd8190 8974
b73e4d84
YM
8975 font->min_byte1 = 0;
8976 font->max_byte1 = 0xff;
8977 font->min_char_or_byte2 = 0;
8978 font->max_char_or_byte2 = 0xff;
c3bd8190 8979
458dbb8c
YM
8980 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8981 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8982 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8983 pcm_init (font->bounds.rows[0], 0x100);
c3bd8190 8984
16805b2e 8985#if USE_CG_TEXT_DRAWING
68c767a3
YM
8986 if (fontnum != -1)
8987 {
8988 FMFontStyle style;
8989 ATSFontRef ats_font;
16805b2e 8990
68c767a3 8991 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
16805b2e 8992 &font_id, &style);
68c767a3
YM
8993 /* Use CG text drawing if italic/bold is not synthesized. */
8994 if (err == noErr && style == fontface)
8995 {
8996 ats_font = FMGetATSFontRefFromFont (font_id);
8997 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
8998 }
8999 }
16805b2e
YM
9000
9001 if (font->cg_font)
b96fe6ea
YM
9002 {
9003 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
9004 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
9005 }
16805b2e 9006#endif
458dbb8c 9007 space_bounds = font->bounds.rows[0] + 0x20;
b73e4d84
YM
9008 err = mac_query_char_extents (font->mac_style, 0x20,
9009 &font->ascent, &font->descent,
9010 space_bounds,
9011#if USE_CG_TEXT_DRAWING
9012 (font->cg_glyphs ? font->cg_glyphs + 0x20
9013 : NULL)
9014#else
9015 NULL
9016#endif
9017 );
7c682cf1
YM
9018 if (err != noErr
9019 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
c3bd8190
YM
9020 {
9021 mac_unload_font (&one_mac_display_info, font);
9022 return NULL;
9023 }
9024
458dbb8c 9025 pcm = font->bounds.rows[0];
b73e4d84 9026 for (c = 0x21; c <= 0xff; c++)
c3bd8190 9027 {
16805b2e
YM
9028 if (c == 0xad)
9029 /* Soft hyphen is not supported in ATSUI. */
9030 continue;
9031 else if (c == 0x7f)
c3bd8190 9032 {
0d36bf23
YM
9033#if USE_CG_TEXT_DRAWING
9034 if (font->cg_glyphs)
9035 {
9036 c = 0x9f;
9037 pcm = NULL;
9038 continue;
9039 }
9040#endif
9041 break;
16805b2e 9042 }
c3bd8190 9043
0d36bf23
YM
9044 mac_query_char_extents (font->mac_style, c, NULL, NULL,
9045 pcm ? pcm + c : NULL,
b73e4d84
YM
9046#if USE_CG_TEXT_DRAWING
9047 (font->cg_glyphs ? font->cg_glyphs + c
9048 : NULL)
05f7d868 9049#else
b73e4d84 9050 NULL
05f7d868 9051#endif
b73e4d84 9052 );
c3bd8190 9053
16805b2e 9054#if USE_CG_TEXT_DRAWING
b73e4d84 9055 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
16805b2e 9056 {
b73e4d84
YM
9057 /* Don't use CG text drawing if font substitution occurs in
9058 ASCII or Latin-1 characters. */
9059 CGFontRelease (font->cg_font);
9060 font->cg_font = NULL;
9061 xfree (font->cg_glyphs);
9062 font->cg_glyphs = NULL;
0d36bf23
YM
9063 if (pcm == NULL)
9064 break;
c3bd8190 9065 }
16805b2e 9066#endif
c3bd8190 9067 }
c3bd8190
YM
9068 }
9069 else
71b7a47f 9070#endif
c3bd8190 9071 {
0d36bf23 9072 OSStatus err;
71b7a47f
YM
9073 FontInfo the_fontinfo;
9074 int is_two_byte_font;
9075
444a42fd 9076#if USE_CG_DRAWING
bb420759 9077 mac_prepare_for_quickdraw (f);
c3bd8190 9078#endif
bb420759 9079 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1a578e9b 9080
71b7a47f
YM
9081 TextFont (fontnum);
9082 TextSize (size);
9083 TextFace (fontface);
177c0ea7 9084
71b7a47f 9085 GetFontInfo (&the_fontinfo);
1a578e9b 9086
71b7a47f
YM
9087 font->ascent = the_fontinfo.ascent;
9088 font->descent = the_fontinfo.descent;
1a578e9b 9089
71b7a47f
YM
9090 is_two_byte_font = (font->mac_scriptcode == smJapanese
9091 || font->mac_scriptcode == smTradChinese
9092 || font->mac_scriptcode == smSimpChinese
9093 || font->mac_scriptcode == smKorean);
c3bd8190 9094
71b7a47f
YM
9095 if (is_two_byte_font)
9096 {
b73e4d84
YM
9097 int char_width;
9098
71b7a47f
YM
9099 font->min_byte1 = 0xa1;
9100 font->max_byte1 = 0xfe;
9101 font->min_char_or_byte2 = 0xa1;
9102 font->max_char_or_byte2 = 0xfe;
9103
9104 /* Use the width of an "ideographic space" of that font
9105 because the_fontinfo.widMax returns the wrong width for
9106 some fonts. */
9107 switch (font->mac_scriptcode)
9108 {
9109 case smJapanese:
9110 font->min_byte1 = 0x81;
9111 font->max_byte1 = 0xfc;
9112 font->min_char_or_byte2 = 0x40;
9113 font->max_char_or_byte2 = 0xfc;
9114 char_width = StringWidth("\p\x81\x40");
9115 break;
9116 case smTradChinese:
9117 font->min_char_or_byte2 = 0x40;
9118 char_width = StringWidth("\p\xa1\x40");
9119 break;
9120 case smSimpChinese:
9121 char_width = StringWidth("\p\xa1\xa1");
9122 break;
9123 case smKorean:
9124 char_width = StringWidth("\p\xa1\xa1");
9125 break;
9126 }
1a578e9b 9127
b73e4d84 9128 font->bounds.per_char = NULL;
1a578e9b 9129
71b7a47f
YM
9130 if (fontface & italic)
9131 font->max_bounds.rbearing = char_width + 1;
9132 else
9133 font->max_bounds.rbearing = char_width;
9134 font->max_bounds.lbearing = 0;
9135 font->max_bounds.width = char_width;
9136 font->max_bounds.ascent = the_fontinfo.ascent;
9137 font->max_bounds.descent = the_fontinfo.descent;
1a578e9b 9138
71b7a47f
YM
9139 font->min_bounds = font->max_bounds;
9140 }
9141 else
9142 {
b73e4d84 9143 int c;
c3bd8190 9144
b73e4d84
YM
9145 font->min_byte1 = font->max_byte1 = 0;
9146 font->min_char_or_byte2 = 0x20;
9147 font->max_char_or_byte2 = 0xff;
c3bd8190 9148
b73e4d84
YM
9149 font->bounds.per_char =
9150 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
b73e4d84
YM
9151 bzero (font->bounds.per_char,
9152 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9153
9154 space_bounds = font->bounds.per_char;
0d36bf23
YM
9155 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9156 &font->descent, space_bounds, NULL);
9157 if (err != noErr || space_bounds->width <= 0)
9158 {
9159 mac_unload_font (&one_mac_display_info, font);
9160 return NULL;
9161 }
b73e4d84
YM
9162
9163 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9164 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
c3bd8190 9165 }
71b7a47f 9166 }
177c0ea7 9167
b73e4d84
YM
9168 if (space_bounds)
9169 {
9170 int c;
9171
9172 font->min_bounds = font->max_bounds = *space_bounds;
9173 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9174 if (pcm->width > 0)
9175 {
9176 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9177 pcm->lbearing);
9178 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9179 pcm->rbearing);
9180 font->min_bounds.width = min (font->min_bounds.width,
9181 pcm->width);
9182 font->min_bounds.ascent = min (font->min_bounds.ascent,
9183 pcm->ascent);
cf2c6835
YM
9184 font->min_bounds.descent = min (font->min_bounds.descent,
9185 pcm->descent);
b73e4d84
YM
9186
9187 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9188 pcm->lbearing);
9189 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9190 pcm->rbearing);
9191 font->max_bounds.width = max (font->max_bounds.width,
9192 pcm->width);
9193 font->max_bounds.ascent = max (font->max_bounds.ascent,
9194 pcm->ascent);
cf2c6835
YM
9195 font->max_bounds.descent = max (font->max_bounds.descent,
9196 pcm->descent);
b73e4d84
YM
9197 }
9198 if (
9199#if USE_ATSUI
9200 font->mac_style == NULL &&
9201#endif
9202 font->max_bounds.width == font->min_bounds.width
9203 && font->min_bounds.lbearing >= 0
9204 && font->max_bounds.rbearing <= font->max_bounds.width)
9205 {
9206 /* Fixed width and no overhangs. */
9207 xfree (font->bounds.per_char);
9208 font->bounds.per_char = NULL;
9209 }
9210 }
9211
16805b2e
YM
9212#if !defined (MAC_OS8) || USE_ATSUI
9213 /* AppKit and WebKit do some adjustment to the heights of Courier,
9214 Helvetica, and Times. This only works on the environments where
9fb446e3
YM
9215 srcCopy text transfer mode is never used. */
9216 if (
9217#ifdef MAC_OS8 /* implies USE_ATSUI */
9218 font->mac_style &&
9219#endif
9220 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9221 || strcmp (family, "times") == 0))
16805b2e
YM
9222 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9223#endif
9224
1a578e9b
AC
9225 return font;
9226}
9227
9228
b15325b2
ST
9229void
9230mac_unload_font (dpyinfo, font)
9231 struct mac_display_info *dpyinfo;
9232 XFontStruct *font;
9233{
94d0e806 9234 xfree (font->full_name);
c3bd8190
YM
9235#if USE_ATSUI
9236 if (font->mac_style)
b73e4d84
YM
9237 {
9238 int i;
9239
9240 for (i = font->min_byte1; i <= font->max_byte1; i++)
70fdbb46 9241 xfree (font->bounds.rows[i]);
b73e4d84
YM
9242 xfree (font->bounds.rows);
9243 ATSUDisposeStyle (font->mac_style);
9244 }
9245 else
9246#endif
70fdbb46 9247 xfree (font->bounds.per_char);
16805b2e
YM
9248#if USE_CG_TEXT_DRAWING
9249 if (font->cg_font)
9250 CGFontRelease (font->cg_font);
70fdbb46 9251 xfree (font->cg_glyphs);
c3bd8190 9252#endif
b15325b2
ST
9253 xfree (font);
9254}
9255
9256
1a578e9b
AC
9257/* Load font named FONTNAME of the size SIZE for frame F, and return a
9258 pointer to the structure font_info while allocating it dynamically.
9259 If SIZE is 0, load any size of font.
9260 If loading is failed, return NULL. */
9261
9262struct font_info *
9263x_load_font (f, fontname, size)
9264 struct frame *f;
9265 register char *fontname;
9266 int size;
9267{
9268 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9269 Lisp_Object font_names;
9270
9271 /* Get a list of all the fonts that match this name. Once we
9272 have a list of matching fonts, we compare them against the fonts
9273 we already have by comparing names. */
9274 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9275
9276 if (!NILP (font_names))
9277 {
9278 Lisp_Object tail;
9279 int i;
9280
9281 for (i = 0; i < dpyinfo->n_fonts; i++)
9282 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9283 if (dpyinfo->font_table[i].name
9284 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 9285 SDATA (XCAR (tail)))
1a578e9b 9286 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 9287 SDATA (XCAR (tail)))))
1a578e9b
AC
9288 return (dpyinfo->font_table + i);
9289 }
94d0e806
YM
9290 else
9291 return NULL;
1a578e9b
AC
9292
9293 /* Load the font and add it to the table. */
9294 {
1a578e9b
AC
9295 struct MacFontStruct *font;
9296 struct font_info *fontp;
1a578e9b
AC
9297 int i;
9298
94d0e806 9299 fontname = (char *) SDATA (XCAR (font_names));
1a578e9b 9300
b15325b2 9301 BLOCK_INPUT;
bb420759 9302 font = mac_load_query_font (f, fontname);
b15325b2 9303 UNBLOCK_INPUT;
1a578e9b
AC
9304 if (!font)
9305 return NULL;
9306
9307 /* Find a free slot in the font table. */
9308 for (i = 0; i < dpyinfo->n_fonts; ++i)
9309 if (dpyinfo->font_table[i].name == NULL)
9310 break;
9311
9312 /* If no free slot found, maybe enlarge the font table. */
9313 if (i == dpyinfo->n_fonts
9314 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9315 {
9316 int sz;
9317 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9318 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9319 dpyinfo->font_table
9320 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9321 }
9322
9323 fontp = dpyinfo->font_table + i;
9324 if (i == dpyinfo->n_fonts)
9325 ++dpyinfo->n_fonts;
9326
9327 /* Now fill in the slots of *FONTP. */
9328 BLOCK_INPUT;
6b61353c 9329 bzero (fontp, sizeof (*fontp));
1a578e9b
AC
9330 fontp->font = font;
9331 fontp->font_idx = i;
6abfb022 9332 fontp->charset = -1; /* fs_load_font sets it. */
94d0e806
YM
9333 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9334 bcopy (fontname, fontp->name, strlen (fontname) + 1);
1a578e9b 9335
e169f939
ST
9336 if (font->min_bounds.width == font->max_bounds.width)
9337 {
9338 /* Fixed width font. */
9339 fontp->average_width = fontp->space_width = font->min_bounds.width;
9340 }
9341 else
9342 {
9343 XChar2b char2b;
9344 XCharStruct *pcm;
9345
9346 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9347 pcm = mac_per_char_metric (font, &char2b, 0);
9348 if (pcm)
9349 fontp->space_width = pcm->width;
9350 else
9351 fontp->space_width = FONT_WIDTH (font);
9352
9353 if (pcm)
9354 {
9355 int width = pcm->width;
9356 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9357 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9358 width += pcm->width;
9359 fontp->average_width = width / 95;
9360 }
9361 else
9362 fontp->average_width = FONT_WIDTH (font);
9363 }
9364
94d0e806
YM
9365 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9366 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
1a578e9b
AC
9367
9368 fontp->size = font->max_bounds.width;
9369 fontp->height = FONT_HEIGHT (font);
9370 {
9371 /* For some font, ascent and descent in max_bounds field is
9372 larger than the above value. */
9373 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9374 if (max_height > fontp->height)
9375 fontp->height = max_height;
9376 }
9377
cc02ceee 9378 /* MAC_TODO: The script encoding is irrelevant in unicode? */
1a578e9b
AC
9379 /* The slot `encoding' specifies how to map a character
9380 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9381 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9382 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9383 2:0xA020..0xFF7F). For the moment, we don't know which charset
6abfb022 9384 uses this font. So, we set information in fontp->encoding_type
1a578e9b
AC
9385 which is never used by any charset. If mapping can't be
9386 decided, set FONT_ENCODING_NOT_DECIDED. */
9387 if (font->mac_scriptcode == smJapanese)
6abfb022 9388 fontp->encoding_type = 4;
1a578e9b
AC
9389 else
9390 {
6abfb022 9391 fontp->encoding_type
1a578e9b
AC
9392 = (font->max_byte1 == 0
9393 /* 1-byte font */
9394 ? (font->min_char_or_byte2 < 0x80
9395 ? (font->max_char_or_byte2 < 0x80
9396 ? 0 /* 0x20..0x7F */
9397 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9398 : 1) /* 0xA0..0xFF */
9399 /* 2-byte font */
9400 : (font->min_byte1 < 0x80
9401 ? (font->max_byte1 < 0x80
9402 ? (font->min_char_or_byte2 < 0x80
9403 ? (font->max_char_or_byte2 < 0x80
9404 ? 0 /* 0x2020..0x7F7F */
9405 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9406 : 3) /* 0x20A0..0x7FFF */
9407 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9408 : (font->min_char_or_byte2 < 0x80
9409 ? (font->max_char_or_byte2 < 0x80
9410 ? 2 /* 0xA020..0xFF7F */
9411 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9412 : 1))); /* 0xA0A0..0xFFFF */
9413 }
9414
6abfb022 9415#if 0 /* MAC_TODO: fill these out with more reasonably values */
1a578e9b
AC
9416 fontp->baseline_offset
9417 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9418 ? (long) value : 0);
9419 fontp->relative_compose
9420 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9421 ? (long) value : 0);
9422 fontp->default_ascent
9423 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9424 ? (long) value : 0);
9425#else
9426 fontp->baseline_offset = 0;
9427 fontp->relative_compose = 0;
9428 fontp->default_ascent = 0;
9429#endif
9430
9431 /* Set global flag fonts_changed_p to non-zero if the font loaded
9432 has a character with a smaller width than any other character
1f98fbb4 9433 before, or if the font loaded has a smaller height than any
1a578e9b
AC
9434 other font loaded before. If this happens, it will make a
9435 glyph matrix reallocation necessary. */
dd15724d 9436 fonts_changed_p |= x_compute_min_glyph_bounds (f);
1a578e9b
AC
9437 UNBLOCK_INPUT;
9438 return fontp;
9439 }
9440}
9441
9442
9443/* Return a pointer to struct font_info of a font named FONTNAME for
9444 frame F. If no such font is loaded, return NULL. */
9445
9446struct font_info *
9447x_query_font (f, fontname)
9448 struct frame *f;
9449 register char *fontname;
9450{
9451 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9452 int i;
9453
9454 for (i = 0; i < dpyinfo->n_fonts; i++)
9455 if (dpyinfo->font_table[i].name
05131107
JR
9456 && (!xstrcasecmp (dpyinfo->font_table[i].name, fontname)
9457 || !xstrcasecmp (dpyinfo->font_table[i].full_name, fontname)))
1a578e9b
AC
9458 return (dpyinfo->font_table + i);
9459 return NULL;
9460}
9461
9462
9463/* Find a CCL program for a font specified by FONTP, and set the member
9464 `encoder' of the structure. */
9465
9466void
9467x_find_ccl_program (fontp)
9468 struct font_info *fontp;
9469{
9470 Lisp_Object list, elt;
9471
9472 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9473 {
9474 elt = XCAR (list);
9475 if (CONSP (elt)
9476 && STRINGP (XCAR (elt))
9477 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9478 >= 0))
9479 break;
9480 }
9481 if (! NILP (list))
9482 {
9483 struct ccl_program *ccl
9484 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9485
9486 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9487 xfree (ccl);
9488 else
9489 fontp->font_encoder = ccl;
9490 }
9491}
9492
68c767a3 9493#if USE_MAC_FONT_PANEL
36f0107c
YM
9494/* Whether Font Panel has been shown before. The first call to font
9495 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9496 slow. This variable is used for deferring such a call as much as
9497 possible. */
b71c381c
YM
9498static int font_panel_shown_p = 0;
9499
7adf3143
YM
9500extern Lisp_Object Qfont;
9501static Lisp_Object Qpanel_closed, Qselection;
9502
9503static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9504 Lisp_Object,
9505 Lisp_Object,
9506 EventRef, UInt32,
9507 const EventParamName *,
9508 const EventParamType *));
9509
b71c381c
YM
9510int
9511mac_font_panel_visible_p ()
9512{
9513 return font_panel_shown_p && FPIsFontPanelVisible ();
9514}
9515
7adf3143
YM
9516static pascal OSStatus
9517mac_handle_font_event (next_handler, event, data)
9518 EventHandlerCallRef next_handler;
9519 EventRef event;
9520 void *data;
9521{
9522 OSStatus result, err;
9523 Lisp_Object id_key;
9524 int num_params;
9525 const EventParamName *names;
9526 const EventParamType *types;
9527 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9528 kEventParamATSUFontSize,
9529 kEventParamFMFontFamily,
7b7d07bb 9530 kEventParamFMFontStyle,
7adf3143
YM
9531 kEventParamFMFontSize,
9532 kEventParamFontColor};
9533 static const EventParamType types_sel[] = {typeATSUFontID,
9534 typeATSUSize,
9535 typeFMFontFamily,
7b7d07bb 9536 typeFMFontStyle,
7adf3143
YM
9537 typeFMFontSize,
9538 typeFontColor};
9539
9540 result = CallNextEventHandler (next_handler, event);
9541 if (result != eventNotHandledErr)
9542 return result;
9543
9544 switch (GetEventKind (event))
9545 {
9546 case kEventFontPanelClosed:
9547 id_key = Qpanel_closed;
9548 num_params = 0;
9549 names = NULL;
9550 types = NULL;
9551 break;
9552
9553 case kEventFontSelection:
9554 id_key = Qselection;
9555 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9556 names = names_sel;
9557 types = types_sel;
9558 break;
9559 }
9560
9561 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9562 event, num_params,
9563 names, types);
9564 if (err == noErr)
9565 result = noErr;
9566
9567 return result;
9568}
9569
b71c381c
YM
9570OSStatus
9571mac_show_hide_font_panel ()
9572{
7adf3143
YM
9573 if (!font_panel_shown_p)
9574 {
9575 OSStatus err;
9576
9577 static const EventTypeSpec specs[] =
9578 {{kEventClassFont, kEventFontPanelClosed},
9579 {kEventClassFont, kEventFontSelection}};
9580
9581 err = InstallApplicationEventHandler (mac_handle_font_event,
9582 GetEventTypeCount (specs),
9583 specs, NULL, NULL);
9584 if (err != noErr)
9585 return err;
9586
9587 font_panel_shown_p = 1;
9588 }
b71c381c
YM
9589
9590 return FPShowHideFontPanel ();
9591}
9592
68c767a3 9593OSStatus
4cb62a90 9594mac_set_font_info_for_selection (f, face_id, c)
68c767a3 9595 struct frame *f;
4cb62a90 9596 int face_id, c;
68c767a3
YM
9597{
9598 OSStatus err;
4cb62a90
YM
9599 EventTargetRef target = NULL;
9600 XFontStruct *font = NULL;
68c767a3 9601
b71c381c
YM
9602 if (!mac_font_panel_visible_p ())
9603 return noErr;
9604
4cb62a90 9605 if (f)
68c767a3 9606 {
4cb62a90 9607 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
68c767a3 9608
4cb62a90
YM
9609 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9610 {
9611 struct face *face;
9612
9613 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9614 face = FACE_FROM_ID (f, face_id);
9615 font = face->font;
9616 }
9617 }
9618
9619 if (font == NULL)
9620 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9621 else
9622 {
9623 if (font->mac_fontnum != -1)
68c767a3
YM
9624 {
9625 FontSelectionQDStyle qd_style;
9626
9627 qd_style.version = kFontSelectionQDStyleVersionZero;
4cb62a90
YM
9628 qd_style.instance.fontFamily = font->mac_fontnum;
9629 qd_style.instance.fontStyle = font->mac_fontface;
9630 qd_style.size = font->mac_fontsize;
68c767a3
YM
9631 qd_style.hasColor = false;
9632
9633 err = SetFontInfoForSelection (kFontSelectionQDType,
9634 1, &qd_style, target);
9635 }
9636 else
9637 err = SetFontInfoForSelection (kFontSelectionATSUIType,
4cb62a90 9638 1, &font->mac_style, target);
68c767a3
YM
9639 }
9640
9641 return err;
9642}
9643#endif
1a578e9b
AC
9644
9645\f
1a578e9b
AC
9646/* The Mac Event loop code */
9647
25c9622b 9648#if !TARGET_API_MAC_CARBON
1a578e9b
AC
9649#include <Events.h>
9650#include <Quickdraw.h>
9651#include <Balloons.h>
9652#include <Devices.h>
9653#include <Fonts.h>
9654#include <Gestalt.h>
9655#include <Menus.h>
9656#include <Processes.h>
9657#include <Sound.h>
9658#include <ToolUtils.h>
9659#include <TextUtils.h>
9660#include <Dialogs.h>
9661#include <Script.h>
1a578e9b 9662#include <Types.h>
1a578e9b
AC
9663#include <Resources.h>
9664
9665#if __MWERKS__
9666#include <unix.h>
9667#endif
25c9622b 9668#endif /* ! TARGET_API_MAC_CARBON */
1a578e9b 9669
20a1fc8b 9670#define M_APPLE 234
1a578e9b
AC
9671#define I_ABOUT 1
9672
1a578e9b
AC
9673#define DEFAULT_NUM_COLS 80
9674
9675#define MIN_DOC_SIZE 64
9676#define MAX_DOC_SIZE 32767
9677
1a578e9b
AC
9678#define EXTRA_STACK_ALLOC (256 * 1024)
9679
9680#define ARGV_STRING_LIST_ID 129
9681#define ABOUT_ALERT_ID 128
2e875e36 9682#define RAM_TOO_LARGE_ALERT_ID 129
1a578e9b 9683
6b61353c
KH
9684/* Contains the string "reverse", which is a constant for mouse button emu.*/
9685Lisp_Object Qreverse;
9686
1a578e9b 9687
b02e3f7b
ST
9688/* Modifier associated with the control key, or nil to ignore. */
9689Lisp_Object Vmac_control_modifier;
9690
9691/* Modifier associated with the option key, or nil to ignore. */
a36f1680
JW
9692Lisp_Object Vmac_option_modifier;
9693
b02e3f7b
ST
9694/* Modifier associated with the command key, or nil to ignore. */
9695Lisp_Object Vmac_command_modifier;
9696
9697/* Modifier associated with the function key, or nil to ignore. */
9698Lisp_Object Vmac_function_modifier;
742fbed7 9699
6b61353c
KH
9700/* True if the option and command modifiers should be used to emulate
9701 a three button mouse */
9702Lisp_Object Vmac_emulate_three_button_mouse;
9703
3354caee 9704#if TARGET_API_MAC_CARBON
70ed951a 9705/* Non-zero if the mouse wheel button (i.e. button 4) should map to
742fbed7 9706 mouse-2, instead of mouse-3. */
70ed951a 9707int mac_wheel_button_is_mouse_2;
5883787c 9708
70ed951a 9709/* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
5883787c 9710 for processing before Emacs sees it. */
70ed951a 9711int mac_pass_command_to_system;
5883787c 9712
70ed951a 9713/* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
5883787c 9714 for processing before Emacs sees it. */
70ed951a 9715int mac_pass_control_to_system;
1f98fbb4 9716#endif
95085023
YM
9717
9718/* Points to the variable `inev' in the function XTread_socket. It is
95dfb192
YM
9719 used for passing an input event to the function back from
9720 Carbon/Apple event handlers. */
95085023 9721static struct input_event *read_socket_inev = NULL;
742fbed7 9722
19ee09cc
YM
9723/* Whether or not the screen configuration has changed. */
9724static int mac_screen_config_changed = 0;
9725
1a578e9b
AC
9726Point saved_menu_event_location;
9727
9728/* Apple Events */
3354caee 9729#if TARGET_API_MAC_CARBON
3e7424f7 9730static Lisp_Object Qhi_command;
68c767a3
YM
9731#ifdef MAC_OSX
9732extern Lisp_Object Qwindow;
9733static Lisp_Object Qtoolbar_switch_mode;
9734#endif
02236cbc
YM
9735#if USE_MAC_TSM
9736static TSMDocumentID tsm_document_id;
f2ec385e
YM
9737Lisp_Object Qtext_input;
9738Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
e1adb139 9739Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
02236cbc 9740extern Lisp_Object Qbefore_string;
b4c51596 9741static Lisp_Object Vmac_ts_script_language_on_focus;
92289429 9742static Lisp_Object saved_ts_script_language_on_focus;
b4c51596
YM
9743static ScriptLanguageRecord saved_ts_language;
9744static Component saved_ts_component;
02236cbc 9745#endif
7adf3143 9746#endif /* TARGET_API_MAC_CARBON */
6a0b5d37
YM
9747extern int mac_ready_for_apple_events;
9748extern Lisp_Object Qundefined;
9749extern void init_apple_event_handler P_ ((void));
9750extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9751 Lisp_Object *, Lisp_Object *,
9752 Lisp_Object *));
0e0a1663 9753extern OSErr init_coercion_handler P_ ((void));
742fbed7
AC
9754
9755/* Drag and Drop */
e2d3b7e1
YM
9756extern OSErr install_drag_handler P_ ((WindowRef));
9757extern void remove_drag_handler P_ ((WindowRef));
9758
7adf3143 9759#if TARGET_API_MAC_CARBON
e2d3b7e1 9760/* Showing help echo string during menu tracking */
7adf3143 9761extern OSStatus install_menu_target_item_handler P_ ((void));
742fbed7 9762
25c9622b 9763#ifdef MAC_OSX
7adf3143 9764extern OSStatus install_service_handler ();
08861c5c
MB
9765Lisp_Object Qservice, Qpaste, Qperform;
9766Lisp_Object Qmouse_drag_overlay;
25c9622b 9767#endif
742fbed7 9768#endif
1a578e9b
AC
9769
9770extern void init_emacs_passwd_dir ();
9771extern int emacs_main (int, char **, char **);
1a578e9b
AC
9772
9773extern void initialize_applescript();
9774extern void terminate_applescript();
9775
1e53bd0e
YM
9776/* Table for translating Mac keycode to X keysym values. Contributed
9777 by Sudhir Shenoy.
9778 Mapping for special keys is now identical to that in Apple X11
9779 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9780 on the right of the Cmd key on laptops, and fn + `enter' (->
9781 <linefeed>). */
369a7a37 9782static const unsigned char keycode_to_xkeysym_table[] = {
1e53bd0e
YM
9783 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9784 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9785 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9786
9787 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9788 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9789 /*0x38*/ 0, 0, 0, 0,
9790 /*0x3C*/ 0, 0, 0, 0,
9791
9792 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9793 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9794 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9795 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9796
9797 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9798 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9799 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9800 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9801
9802 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9803 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9804 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9805 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9806
9807 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9808 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9809 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9810 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9811};
9812
9813#ifdef MAC_OSX
9814/* Table for translating Mac keycode with the laptop `fn' key to that
9815 without it. Destination symbols in comments are keys on US
9816 keyboard, and they may not be the same on other types of keyboards.
9817 If the destination is identical to the source (f1 ... f12), it
9818 doesn't map `fn' key to a modifier. */
369a7a37 9819static const unsigned char fn_keycode_to_keycode_table[] = {
1e53bd0e
YM
9820 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9821 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9822 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9823
9824 /*0x30*/ 0, 0, 0, 0,
9825 /*0x34*/ 0, 0, 0, 0,
9826 /*0x38*/ 0, 0, 0, 0,
9827 /*0x3C*/ 0, 0, 0, 0,
9828
9829 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9830 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9831 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9832 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9833
9834 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9835 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9836 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9837 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9838
9839 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9840 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9841 /*0x68*/ 0, 0, 0, 0,
9842 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9843
9844 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9845 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9846 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9847 /*0x7C*/ 0, 0, 0, 0
9848};
9849#endif /* MAC_OSX */
9850
a84cad70 9851static int
3354caee 9852#if TARGET_API_MAC_CARBON
742fbed7
AC
9853mac_to_emacs_modifiers (UInt32 mods)
9854#else
9855mac_to_emacs_modifiers (EventModifiers mods)
9856#endif
9857{
9858 unsigned int result = 0;
b02e3f7b 9859 if (mods & shiftKey)
742fbed7 9860 result |= shift_modifier;
16805b2e 9861
b02e3f7b
ST
9862 /* Deactivated to simplify configuration:
9863 if Vmac_option_modifier is non-NIL, we fully process the Option
9864 key. Otherwise, we only process it if an additional Ctrl or Command
16805b2e 9865 is pressed. That way the system may convert the character to a
b02e3f7b
ST
9866 composed one.
9867 if ((mods & optionKey) &&
16805b2e 9868 (( !NILP(Vmac_option_modifier) ||
b02e3f7b
ST
9869 ((mods & cmdKey) || (mods & controlKey))))) */
9870
a36f1680 9871 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
b02e3f7b
ST
9872 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9873 if (INTEGERP(val))
9874 result |= XUINT(val);
a36f1680 9875 }
b02e3f7b
ST
9876 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9877 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9878 if (INTEGERP(val))
9879 result |= XUINT(val);
a36f1680 9880 }
b02e3f7b
ST
9881 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9882 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9883 if (INTEGERP(val))
9884 result |= XUINT(val);
16805b2e 9885 }
a36f1680 9886
b02e3f7b
ST
9887#ifdef MAC_OSX
9888 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9889 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9890 if (INTEGERP(val))
9891 result |= XUINT(val);
16805b2e 9892 }
b02e3f7b 9893#endif
a36f1680 9894
742fbed7
AC
9895 return result;
9896}
9897
a84cad70
YM
9898static UInt32
9899mac_mapped_modifiers (modifiers)
9900 UInt32 modifiers;
9901{
9902 UInt32 mapped_modifiers_all =
9903 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9904 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9905 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9906
9907#ifdef MAC_OSX
9908 mapped_modifiers_all |=
9909 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9910#endif
9911
9912 return mapped_modifiers_all & modifiers;
9913}
9914
6b61353c
KH
9915static int
9916mac_get_emulated_btn ( UInt32 modifiers )
9917{
9918 int result = 0;
a433994a
ST
9919 if (!NILP (Vmac_emulate_three_button_mouse)) {
9920 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
c61278bb 9921 if (modifiers & cmdKey)
6b61353c
KH
9922 result = cmdIs3 ? 2 : 1;
9923 else if (modifiers & optionKey)
ffe8b3f4 9924 result = cmdIs3 ? 1 : 2;
6b61353c
KH
9925 }
9926 return result;
9927}
9928
e1adb139
YM
9929#ifdef MAC_OSX
9930void
9931mac_get_selected_range (w, range)
9932 struct window *w;
9933 CFRange *range;
9934{
9935 Lisp_Object overlay = find_symbol_value (Qmouse_drag_overlay);
9936 struct buffer *b = XBUFFER (w->buffer);
9937 int begv = BUF_BEGV (b), zv = BUF_ZV (b);
9938 int start, end;
9939
9940 if (OVERLAYP (overlay)
9941 && EQ (Foverlay_buffer (overlay), w->buffer)
9942 && (start = XINT (Foverlay_start (overlay)),
9943 end = XINT (Foverlay_end (overlay)),
9944 start != end))
9945 ;
9946 else
9947 {
9948 if (w == XWINDOW (selected_window) && b == current_buffer)
9949 start = PT;
9950 else
9951 start = marker_position (w->pointm);
9952
9953 if (NILP (Vtransient_mark_mode) || NILP (b->mark_active))
9954 end = start;
9955 else
9956 {
9957 int mark_pos = marker_position (b->mark);
9958
9959 if (start <= mark_pos)
9960 end = mark_pos;
9961 else
9962 {
9963 end = start;
9964 start = mark_pos;
9965 }
9966 }
9967 }
9968
9969 if (start != end)
9970 {
9971 if (start < begv)
9972 start = begv;
9973 else if (start > zv)
9974 start = zv;
9975
9976 if (end < begv)
9977 end = begv;
9978 else if (end > zv)
9979 end = zv;
9980 }
9981
9982 range->location = start - begv;
9983 range->length = end - start;
9984}
9985
9986/* Store the text of the buffer BUF from START to END as Unicode
9987 characters in CHARACTERS. Return non-zero if successful. */
9988
9989int
9990mac_store_buffer_text_to_unicode_chars (buf, start, end, characters)
9991 struct buffer *buf;
9992 int start, end;
9993 UniChar *characters;
9994{
9995 int start_byte, end_byte, char_count, byte_count;
9996 struct coding_system coding;
9997 unsigned char *dst = (unsigned char *) characters;
9998
9999 start_byte = buf_charpos_to_bytepos (buf, start);
10000 end_byte = buf_charpos_to_bytepos (buf, end);
10001 char_count = end - start;
10002 byte_count = end_byte - start_byte;
10003
10004 if (setup_coding_system (
10005#ifdef WORDS_BIG_ENDIAN
10006 intern ("utf-16be")
10007#else
10008 intern ("utf-16le")
10009#endif
10010 , &coding) < 0)
10011 return 0;
10012
10013 coding.src_multibyte = !NILP (buf->enable_multibyte_characters);
10014 coding.dst_multibyte = 0;
10015 coding.mode |= CODING_MODE_LAST_BLOCK;
10016 coding.composing = COMPOSITION_DISABLED;
10017
10018 if (BUF_GPT_BYTE (buf) <= start_byte || end_byte <= BUF_GPT_BYTE (buf))
10019 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10020 byte_count, char_count * sizeof (UniChar));
10021 else
10022 {
10023 int first_byte_count = BUF_GPT_BYTE (buf) - start_byte;
10024
10025 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10026 first_byte_count, char_count * sizeof (UniChar));
10027 if (coding.result == CODING_FINISH_NORMAL)
10028 encode_coding (&coding,
10029 BUF_BYTE_ADDRESS (buf, start_byte + first_byte_count),
10030 dst + coding.produced,
10031 byte_count - first_byte_count,
10032 char_count * sizeof (UniChar) - coding.produced);
10033 }
10034
10035 if (coding.result != CODING_FINISH_NORMAL)
10036 return 0;
10037
10038 return 1;
10039}
10040
10041void
10042mac_ax_selected_text_range (f, range)
10043 struct frame *f;
10044 CFRange *range;
10045{
10046 mac_get_selected_range (XWINDOW (f->selected_window), range);
10047}
10048
10049#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
10050unsigned int
10051mac_ax_number_of_characters (f)
10052 struct frame *f;
10053{
10054 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
10055
10056 return BUF_ZV (b) - BUF_BEGV (b);
10057}
10058#endif
10059#endif
10060
f2ec385e
YM
10061#if USE_MAC_TSM
10062OSStatus
10063mac_restore_keyboard_input_source ()
10064{
10065 OSStatus err = noErr;
10066 ScriptLanguageRecord slrec, *slptr = NULL;
10067
10068 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10069 && EQ (saved_ts_script_language_on_focus, Qt))
10070 slptr = &saved_ts_language;
10071 else if (CONSP (Vmac_ts_script_language_on_focus)
10072 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10073 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10074 && CONSP (saved_ts_script_language_on_focus)
10075 && EQ (XCAR (saved_ts_script_language_on_focus),
10076 XCAR (Vmac_ts_script_language_on_focus))
10077 && EQ (XCDR (saved_ts_script_language_on_focus),
10078 XCDR (Vmac_ts_script_language_on_focus)))
10079 {
10080 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10081 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10082 slptr = &slrec;
10083 }
10084
10085 if (slptr)
10086 {
10087#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10088 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10089 kKeyboardInputMethodClass);
10090#else
10091 err = SetDefaultInputMethod (saved_ts_component, slptr);
10092#endif
10093 if (err == noErr)
10094 err = SetTextServiceLanguage (slptr);
10095
10096 /* Seems to be needed on Mac OS X 10.2. */
10097 if (err == noErr)
10098 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10099 }
10100
10101 return err;
10102}
10103
10104void
10105mac_save_keyboard_input_source ()
10106{
10107 OSStatus err;
10108 ScriptLanguageRecord slrec, *slptr = NULL;
10109
10110 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10111
10112 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10113 {
10114 err = GetTextServiceLanguage (&saved_ts_language);
10115 if (err == noErr)
10116 slptr = &saved_ts_language;
10117 }
10118 else if (CONSP (Vmac_ts_script_language_on_focus)
10119 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10120 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10121 {
10122 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10123 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10124 slptr = &slrec;
10125 }
10126
10127 if (slptr)
10128 {
10129#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10130 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10131 kKeyboardInputMethodClass);
10132#else
10133 GetDefaultInputMethod (&saved_ts_component, slptr);
10134#endif
10135 }
10136}
10137#endif
10138
c857519f
YM
10139#if TARGET_API_MAC_CARBON
10140/***** Code to handle C-g testing *****/
10141extern int quit_char;
10142extern int make_ctrl_char P_ ((int));
10143
10144int
10145mac_quit_char_key_p (modifiers, key_code)
10146 UInt32 modifiers, key_code;
10147{
10148 UInt32 char_code;
10149 unsigned long some_state = 0;
10150 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10151 int c, emacs_modifiers;
10152
10153 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
10154 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
10155 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
10156 if (char_code & ~0xff)
10157 return 0;
10158
10159 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
10160 if (emacs_modifiers & ctrl_modifier)
10161 c = make_ctrl_char (char_code);
10162
10163 c |= (emacs_modifiers
10164 & (meta_modifier | alt_modifier
10165 | hyper_modifier | super_modifier));
10166
10167 return c == quit_char;
10168}
10169#endif
10170
3354caee 10171#if TARGET_API_MAC_CARBON
742fbed7
AC
10172/* Obtains the event modifiers from the event ref and then calls
10173 mac_to_emacs_modifiers. */
a84cad70 10174static int
177c0ea7 10175mac_event_to_emacs_modifiers (EventRef eventRef)
742fbed7 10176{
7adf3143
YM
10177 UInt32 mods = 0, class;
10178
742fbed7
AC
10179 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
10180 sizeof (UInt32), NULL, &mods);
7adf3143 10181 class = GetEventClass (eventRef);
a433994a 10182 if (!NILP (Vmac_emulate_three_button_mouse) &&
7adf3143 10183 (class == kEventClassMouse || class == kEventClassCommand))
6b61353c 10184 {
c61278bb 10185 mods &= ~(optionKey | cmdKey);
6b61353c 10186 }
742fbed7
AC
10187 return mac_to_emacs_modifiers (mods);
10188}
10189
10190/* Given an event ref, return the code to use for the mouse button
10191 code in the emacs input_event. */
10192static int
177c0ea7 10193mac_get_mouse_btn (EventRef ref)
742fbed7
AC
10194{
10195 EventMouseButton result = kEventMouseButtonPrimary;
10196 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
10197 sizeof (EventMouseButton), NULL, &result);
177c0ea7 10198 switch (result)
742fbed7
AC
10199 {
10200 case kEventMouseButtonPrimary:
a433994a 10201 if (NILP (Vmac_emulate_three_button_mouse))
6b61353c
KH
10202 return 0;
10203 else {
10204 UInt32 mods = 0;
10205 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
10206 sizeof (UInt32), NULL, &mods);
10207 return mac_get_emulated_btn(mods);
10208 }
742fbed7 10209 case kEventMouseButtonSecondary:
70ed951a 10210 return mac_wheel_button_is_mouse_2 ? 2 : 1;
742fbed7
AC
10211 case kEventMouseButtonTertiary:
10212 case 4: /* 4 is the number for the mouse wheel button */
70ed951a 10213 return mac_wheel_button_is_mouse_2 ? 1 : 2;
742fbed7
AC
10214 default:
10215 return 0;
10216 }
10217}
10218
10219/* Normally, ConvertEventRefToEventRecord will correctly handle all
10220 events. However the click of the mouse wheel is not converted to a
e4f5123f
YM
10221 mouseDown or mouseUp event. Likewise for dead key events. This
10222 calls ConvertEventRefToEventRecord, but then checks to see if it is
10223 a mouse up/down, or a dead key Carbon event that has not been
95085023
YM
10224 converted, and if so, converts it by hand (to be picked up in the
10225 XTread_socket loop). */
177c0ea7 10226static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
742fbed7 10227{
a3510ffa 10228 OSStatus err;
742fbed7 10229 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
e4f5123f 10230 EventKind action;
95085023
YM
10231
10232 if (result)
10233 return result;
10234
10235 switch (GetEventClass (eventRef))
177c0ea7 10236 {
95085023
YM
10237 case kEventClassMouse:
10238 switch (GetEventKind (eventRef))
742fbed7 10239 {
95085023 10240 case kEventMouseDown:
742fbed7 10241 eventRec->what = mouseDown;
95085023
YM
10242 result = 1;
10243 break;
10244
10245 case kEventMouseUp:
742fbed7 10246 eventRec->what = mouseUp;
95085023
YM
10247 result = 1;
10248 break;
10249
10250 default:
10251 break;
742fbed7 10252 }
92de1e01 10253 break;
95085023
YM
10254
10255 case kEventClassKeyboard:
10256 switch (GetEventKind (eventRef))
742fbed7 10257 {
95085023 10258 case kEventRawKeyDown:
e4f5123f
YM
10259 action = keyDown;
10260 goto keystroke_common;
10261 case kEventRawKeyRepeat:
10262 action = autoKey;
10263 goto keystroke_common;
10264 case kEventRawKeyUp:
10265 action = keyUp;
10266 keystroke_common:
95085023
YM
10267 {
10268 unsigned char char_codes;
10269 UInt32 key_code;
10270
a3510ffa
YM
10271 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
10272 typeChar, NULL, sizeof (char),
10273 NULL, &char_codes);
10274 if (err == noErr)
10275 err = GetEventParameter (eventRef, kEventParamKeyCode,
10276 typeUInt32, NULL, sizeof (UInt32),
10277 NULL, &key_code);
10278 if (err == noErr)
10279 {
e4f5123f 10280 eventRec->what = action;
a3510ffa
YM
10281 eventRec->message = char_codes | ((key_code & 0xff) << 8);
10282 result = 1;
10283 }
95085023
YM
10284 }
10285 break;
10286
10287 default:
10288 break;
742fbed7 10289 }
92de1e01 10290 break;
95085023
YM
10291
10292 default:
10293 break;
742fbed7 10294 }
95085023
YM
10295
10296 if (result)
10297 {
10298 /* Need where and when. */
a3510ffa 10299 UInt32 mods = 0;
95085023
YM
10300
10301 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
10302 NULL, sizeof (Point), NULL, &eventRec->where);
10303 /* Use two step process because new event modifiers are 32-bit
10304 and old are 16-bit. Currently, only loss is NumLock & Fn. */
10305 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
10306 NULL, sizeof (UInt32), NULL, &mods);
10307 eventRec->modifiers = mods;
10308
10309 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
10310 }
10311
742fbed7
AC
10312 return result;
10313}
10314
10315#endif
1a578e9b 10316
f93e4d4f 10317#ifdef MAC_OS8
1a578e9b
AC
10318static void
10319do_get_menus (void)
10320{
10321 Handle menubar_handle;
3354caee 10322 MenuRef menu;
177c0ea7 10323
1a578e9b
AC
10324 menubar_handle = GetNewMBar (128);
10325 if(menubar_handle == NULL)
10326 abort ();
10327 SetMenuBar (menubar_handle);
10328 DrawMenuBar ();
10329
1c05c15b 10330#if !TARGET_API_MAC_CARBON
3354caee
YM
10331 menu = GetMenuRef (M_APPLE);
10332 if (menu != NULL)
10333 AppendResMenu (menu, 'DRVR');
1a578e9b
AC
10334 else
10335 abort ();
1c05c15b 10336#endif
1a578e9b
AC
10337}
10338
10339
10340static void
10341do_init_managers (void)
10342{
e0f712ba 10343#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10344 InitGraf (&qd.thePort);
10345 InitFonts ();
10346 FlushEvents (everyEvent, 0);
10347 InitWindows ();
10348 InitMenus ();
10349 TEInit ();
10350 InitDialogs (NULL);
e0f712ba
AC
10351#endif /* !TARGET_API_MAC_CARBON */
10352 InitCursor ();
177c0ea7 10353
e0f712ba 10354#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10355 /* set up some extra stack space for use by emacs */
10356 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10357
10358 /* MaxApplZone must be called for AppleScript to execute more
10359 complicated scripts */
10360 MaxApplZone ();
10361 MoreMasters ();
e0f712ba 10362#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
10363}
10364
2e875e36
AC
10365static void
10366do_check_ram_size (void)
10367{
10368 SInt32 physical_ram_size, logical_ram_size;
177c0ea7 10369
2e875e36
AC
10370 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10371 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
6b61353c
KH
10372 || physical_ram_size > (1 << VALBITS)
10373 || logical_ram_size > (1 << VALBITS))
2e875e36
AC
10374 {
10375 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10376 exit (1);
10377 }
10378}
f93e4d4f 10379#endif /* MAC_OS8 */
2e875e36 10380
1a578e9b 10381static void
3354caee 10382do_window_update (WindowRef win)
1a578e9b 10383{
50bf7673
ST
10384 struct frame *f = mac_window_to_frame (win);
10385
b15325b2 10386 BeginUpdate (win);
1a578e9b 10387
b15325b2
ST
10388 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10389 below. */
10390 if (win != tip_window)
1a578e9b
AC
10391 {
10392 if (f->async_visible == 0)
10393 {
1f98fbb4
YM
10394 /* Update events may occur when a frame gets iconified. */
10395#if 0
1a578e9b
AC
10396 f->async_visible = 1;
10397 f->async_iconified = 0;
10398 SET_FRAME_GARBAGED (f);
1f98fbb4 10399#endif
1a578e9b
AC
10400 }
10401 else
1f98fbb4 10402 {
b15325b2 10403 Rect r;
b15325b2 10404#if TARGET_API_MAC_CARBON
1f98fbb4 10405 RgnHandle region = NewRgn ();
2d97ff8c 10406
1f98fbb4
YM
10407 GetPortVisibleRegion (GetWindowPort (win), region);
10408 GetRegionBounds (region, &r);
10409 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
a84cad70
YM
10410#if USE_CG_DRAWING
10411 mac_prepare_for_quickdraw (f);
10412#endif
1f98fbb4
YM
10413 UpdateControls (win, region);
10414 DisposeRgn (region);
b15325b2 10415#else
b15325b2 10416 r = (*win->visRgn)->rgnBBox;
b15325b2 10417 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
b69efa23
YM
10418 UpdateControls (win, win->visRgn);
10419#endif
1f98fbb4 10420 }
1a578e9b 10421 }
b15325b2
ST
10422
10423 EndUpdate (win);
1a578e9b
AC
10424}
10425
e0f712ba 10426static int
3354caee 10427is_emacs_window (WindowRef win)
e0f712ba
AC
10428{
10429 Lisp_Object tail, frame;
10430
10431 if (!win)
10432 return 0;
10433
10434 FOR_EACH_FRAME (tail, frame)
10435 if (FRAME_MAC_P (XFRAME (frame)))
10436 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10437 return 1;
10438
10439 return 0;
10440}
10441
02236cbc 10442#if USE_MAC_TSM
b4c51596
YM
10443static OSStatus
10444mac_tsm_resume ()
10445{
10446 OSStatus err;
10447 ScriptLanguageRecord slrec, *slptr = NULL;
10448
10449 err = ActivateTSMDocument (tsm_document_id);
10450
10451 if (err == noErr)
10452 {
92289429
YM
10453 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10454 && EQ (saved_ts_script_language_on_focus, Qt))
b4c51596
YM
10455 slptr = &saved_ts_language;
10456 else if (CONSP (Vmac_ts_script_language_on_focus)
10457 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
92289429
YM
10458 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10459 && CONSP (saved_ts_script_language_on_focus)
10460 && EQ (XCAR (saved_ts_script_language_on_focus),
10461 XCAR (Vmac_ts_script_language_on_focus))
10462 && EQ (XCDR (saved_ts_script_language_on_focus),
10463 XCDR (Vmac_ts_script_language_on_focus)))
b4c51596
YM
10464 {
10465 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10466 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10467 slptr = &slrec;
10468 }
10469 }
10470
10471 if (slptr)
10472 {
10473#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10474 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10475 kKeyboardInputMethodClass);
10476#else
10477 err = SetDefaultInputMethod (saved_ts_component, slptr);
02236cbc 10478#endif
b4c51596
YM
10479 if (err == noErr)
10480 err = SetTextServiceLanguage (slptr);
10481
10482 /* Seems to be needed on Mac OS X 10.2. */
10483 if (err == noErr)
10484 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10485 }
10486
10487 return err;
1a578e9b
AC
10488}
10489
b4c51596
YM
10490static OSStatus
10491mac_tsm_suspend ()
1a578e9b 10492{
b4c51596
YM
10493 OSStatus err;
10494 ScriptLanguageRecord slrec, *slptr = NULL;
10495
92289429
YM
10496 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10497
b4c51596
YM
10498 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10499 {
10500 err = GetTextServiceLanguage (&saved_ts_language);
10501 if (err == noErr)
10502 slptr = &saved_ts_language;
10503 }
10504 else if (CONSP (Vmac_ts_script_language_on_focus)
10505 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10506 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10507 {
10508 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10509 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10510 slptr = &slrec;
10511 }
10512
10513 if (slptr)
10514 {
10515#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10516 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10517 kKeyboardInputMethodClass);
10518#else
10519 GetDefaultInputMethod (&saved_ts_component, slptr);
02236cbc 10520#endif
b4c51596 10521 }
1a578e9b 10522
b4c51596
YM
10523 err = DeactivateTSMDocument (tsm_document_id);
10524
10525 return err;
10526}
10527#endif
1a578e9b 10528
20a1fc8b
YM
10529#if !TARGET_API_MAC_CARBON
10530void
1a578e9b
AC
10531do_apple_menu (SInt16 menu_item)
10532{
10533 Str255 item_name;
10534 SInt16 da_driver_refnum;
177c0ea7 10535
1a578e9b
AC
10536 if (menu_item == I_ABOUT)
10537 NoteAlert (ABOUT_ALERT_ID, NULL);
10538 else
10539 {
3354caee 10540 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
1a578e9b
AC
10541 da_driver_refnum = OpenDeskAcc (item_name);
10542 }
1a578e9b 10543}
20a1fc8b 10544#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
10545
10546/* Handle drags in size box. Based on code contributed by Ben
10547 Mesander and IM - Window Manager A. */
10548
10549static void
369a7a37 10550do_grow_window (w, e)
3354caee 10551 WindowRef w;
369a7a37 10552 const EventRecord *e;
1a578e9b 10553{
1a578e9b 10554 Rect limit_rect;
b15325b2 10555 int rows, columns, width, height;
50bf7673 10556 struct frame *f = mac_window_to_frame (w);
b15325b2
ST
10557 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10558 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10559#if TARGET_API_MAC_CARBON
10560 Rect new_rect;
10561#else
10562 long grow_size;
10563#endif
177c0ea7 10564
b15325b2
ST
10565 if (size_hints->flags & PMinSize)
10566 {
10567 min_width = size_hints->min_width;
10568 min_height = size_hints->min_height;
10569 }
10570 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
177c0ea7 10571
b15325b2
ST
10572#if TARGET_API_MAC_CARBON
10573 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10574 return;
10575 height = new_rect.bottom - new_rect.top;
10576 width = new_rect.right - new_rect.left;
10577#else
1a578e9b 10578 grow_size = GrowWindow (w, e->where, &limit_rect);
1a578e9b 10579 /* see if it really changed size */
b15325b2
ST
10580 if (grow_size == 0)
10581 return;
10582 height = HiWord (grow_size);
10583 width = LoWord (grow_size);
10584#endif
10585
10586 if (width != FRAME_PIXEL_WIDTH (f)
10587 || height != FRAME_PIXEL_HEIGHT (f))
1a578e9b 10588 {
b15325b2
ST
10589 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10590 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
177c0ea7 10591
1a578e9b
AC
10592 x_set_window_size (f, 0, columns, rows);
10593 }
10594}
10595
10596
bed0bf95
YM
10597#if TARGET_API_MAC_CARBON
10598static Point
10599mac_get_ideal_size (f)
10600 struct frame *f;
10601{
10602 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3354caee 10603 WindowRef w = FRAME_MAC_WINDOW (f);
bed0bf95
YM
10604 Point ideal_size;
10605 Rect standard_rect;
10606 int height, width, columns, rows;
10607
10608 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10609 ideal_size.v = dpyinfo->height;
10610 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10611 /* Adjust the standard size according to character boundaries. */
10612 width = standard_rect.right - standard_rect.left;
10613 height = standard_rect.bottom - standard_rect.top;
10614 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10615 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10616 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10617 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10618
10619 return ideal_size;
10620}
10621#endif
10622
1a578e9b
AC
10623/* Handle clicks in zoom box. Calculation of "standard state" based
10624 on code in IM - Window Manager A and code contributed by Ben
10625 Mesander. The standard state of an Emacs window is 80-characters
10626 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10627
10628static void
3354caee 10629do_zoom_window (WindowRef w, int zoom_in_or_out)
1a578e9b 10630{
1a578e9b 10631 Rect zoom_rect, port_rect;
bed0bf95 10632 int width, height;
50bf7673 10633 struct frame *f = mac_window_to_frame (w);
e0f712ba 10634#if TARGET_API_MAC_CARBON
bed0bf95 10635 Point ideal_size = mac_get_ideal_size (f);
e0f712ba 10636
bed0bf95
YM
10637 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10638 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10639 && port_rect.left == zoom_rect.left
10640 && port_rect.top == zoom_rect.top)
f93e4d4f
YM
10641 zoom_in_or_out = inZoomIn;
10642 else
bed0bf95 10643 zoom_in_or_out = inZoomOut;
f93e4d4f 10644
bed0bf95
YM
10645#ifdef MAC_OS8
10646 mac_clear_window (f);
10647#endif
10648 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
e0f712ba 10649#else /* not TARGET_API_MAC_CARBON */
f93e4d4f
YM
10650 GrafPtr save_port;
10651 Point top_left;
bed0bf95
YM
10652 int w_title_height, rows;
10653 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
f93e4d4f 10654
bf06c82f
ST
10655 GetPort (&save_port);
10656
10657 SetPortWindowPort (w);
10658
10659 /* Clear window to avoid flicker. */
e0f712ba 10660 EraseRect (&(w->portRect));
1a578e9b
AC
10661 if (zoom_in_or_out == inZoomOut)
10662 {
e0f712ba 10663 SetPt (&top_left, w->portRect.left, w->portRect.top);
1a578e9b
AC
10664 LocalToGlobal (&top_left);
10665
10666 /* calculate height of window's title bar */
10667 w_title_height = top_left.v - 1
e0f712ba 10668 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1a578e9b
AC
10669
10670 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10671 zoom_rect = qd.screenBits.bounds;
10672 zoom_rect.top += w_title_height;
10673 InsetRect (&zoom_rect, 8, 4); /* not too tight */
177c0ea7 10674
1a578e9b 10675 zoom_rect.right = zoom_rect.left
f1a83aab 10676 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1a578e9b 10677
bf06c82f
ST
10678 /* Adjust the standard size according to character boundaries. */
10679 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10680 zoom_rect.bottom =
10681 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10682
e0f712ba
AC
10683 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10684 = zoom_rect;
1a578e9b
AC
10685 }
10686
7ca7ccd5 10687 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
bf06c82f
ST
10688
10689 SetPort (save_port);
10690#endif /* not TARGET_API_MAC_CARBON */
1a578e9b 10691
3354caee 10692#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10693 /* retrieve window size and update application values */
10694 port_rect = w->portRect;
b15325b2
ST
10695 height = port_rect.bottom - port_rect.top;
10696 width = port_rect.right - port_rect.left;
1a578e9b 10697
bed0bf95
YM
10698 mac_handle_size_change (f, width, height);
10699 mac_handle_origin_change (f);
10700#endif
742fbed7 10701}
1a578e9b 10702
7adf3143
YM
10703static void
10704mac_set_unicode_keystroke_event (code, buf)
10705 UniChar code;
10706 struct input_event *buf;
10707{
10708 int charset_id, c1, c2;
10709
10710 if (code < 0x80)
10711 {
10712 buf->kind = ASCII_KEYSTROKE_EVENT;
10713 buf->code = code;
10714 }
10715 else if (code < 0x100)
10716 {
10717 if (code < 0xA0)
10718 charset_id = CHARSET_8_BIT_CONTROL;
10719 else
10720 charset_id = charset_latin_iso8859_1;
10721 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10722 buf->code = MAKE_CHAR (charset_id, code, 0);
10723 }
10724 else
10725 {
10726 if (code < 0x2500)
10727 charset_id = charset_mule_unicode_0100_24ff,
10728 code -= 0x100;
10729 else if (code < 0x33FF)
10730 charset_id = charset_mule_unicode_2500_33ff,
10731 code -= 0x2500;
10732 else if (code >= 0xE000)
10733 charset_id = charset_mule_unicode_e000_ffff,
10734 code -= 0xE000;
10735 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10736 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10737 buf->code = MAKE_CHAR (charset_id, c1, c2);
10738 }
10739}
10740
10741static void
10742do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10743 EventKind action;
10744 unsigned char char_code;
10745 UInt32 key_code, modifiers;
10746 unsigned long timestamp;
10747 struct input_event *buf;
10748{
10749 static SInt16 last_key_script = -1;
10750 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10751 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10752
10753#ifdef MAC_OSX
10754 if (mapped_modifiers & kEventKeyModifierFnMask
10755 && key_code <= 0x7f
10756 && fn_keycode_to_keycode_table[key_code])
10757 key_code = fn_keycode_to_keycode_table[key_code];
10758#endif
10759
10760 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10761 {
10762 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10763 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10764#ifdef MAC_OSX
10765 if (modifiers & kEventKeyModifierFnMask
10766 && key_code <= 0x7f
10767 && fn_keycode_to_keycode_table[key_code] == key_code)
10768 modifiers &= ~kEventKeyModifierFnMask;
10769#endif
10770 }
10771 else if (mapped_modifiers)
10772 {
10773 /* translate the keycode back to determine the original key */
10774#ifdef MAC_OSX
10775 UCKeyboardLayout *uchr_ptr = NULL;
10776#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10777 OSStatus err;
10778 KeyboardLayoutRef layout;
10779
10780 err = KLGetCurrentKeyboardLayout (&layout);
10781 if (err == noErr)
10782 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10783 (const void **) &uchr_ptr);
10784#else
10785 static SInt16 last_key_layout_id = 0;
10786 static Handle uchr_handle = (Handle)-1;
10787 SInt16 current_key_layout_id =
10788 GetScriptVariable (current_key_script, smScriptKeys);
10789
10790 if (uchr_handle == (Handle)-1
10791 || last_key_layout_id != current_key_layout_id)
10792 {
10793 uchr_handle = GetResource ('uchr', current_key_layout_id);
10794 last_key_layout_id = current_key_layout_id;
10795 }
10796 if (uchr_handle)
10797 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10798#endif
10799
10800 if (uchr_ptr)
10801 {
10802 OSStatus status;
10803 UInt16 key_action = action - keyDown;
10804 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10805 UInt32 keyboard_type = LMGetKbdType ();
10806 SInt32 dead_key_state = 0;
10807 UniChar code;
10808 UniCharCount actual_length;
10809
10810 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10811 modifier_key_state, keyboard_type,
10812 kUCKeyTranslateNoDeadKeysMask,
10813 &dead_key_state,
10814 1, &actual_length, &code);
10815 if (status == noErr && actual_length == 1)
10816 mac_set_unicode_keystroke_event (code, buf);
10817 }
10818#endif /* MAC_OSX */
10819
10820 if (buf->kind == NO_EVENT)
10821 {
10822 /* This code comes from Keyboard Resource, Appendix C of IM
10823 - Text. This is necessary since shift is ignored in KCHR
10824 table translation when option or command is pressed. It
10825 also does not translate correctly control-shift chars
10826 like C-% so mask off shift here also. */
10827 /* Mask off modifier keys that are mapped to some Emacs
10828 modifiers. */
10829 int new_modifiers = modifiers & ~mapped_modifiers;
10830 /* set high byte of keycode to modifier high byte*/
10831 int new_key_code = key_code | new_modifiers;
10832 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10833 unsigned long some_state = 0;
10834 UInt32 new_char_code;
10835
10836 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10837 if (new_char_code == 0)
10838 /* Seems like a dead key. Append up-stroke. */
10839 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10840 &some_state);
10841 if (new_char_code)
10842 {
10843 buf->kind = ASCII_KEYSTROKE_EVENT;
10844 buf->code = new_char_code & 0xff;
10845 }
10846 }
10847 }
10848
10849 if (buf->kind == NO_EVENT)
10850 {
10851 buf->kind = ASCII_KEYSTROKE_EVENT;
10852 buf->code = char_code;
10853 }
10854
10855 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10856 buf->modifiers |= (extra_keyboard_modifiers
10857 & (meta_modifier | alt_modifier
10858 | hyper_modifier | super_modifier));
10859
10860#if TARGET_API_MAC_CARBON
10861 if (buf->kind == ASCII_KEYSTROKE_EVENT
10862 && buf->code >= 0x80 && buf->modifiers)
10863 {
10864 OSStatus err;
10865 TextEncoding encoding = kTextEncodingMacRoman;
10866 TextToUnicodeInfo ttu_info;
10867
10868 UpgradeScriptInfoToTextEncoding (current_key_script,
10869 kTextLanguageDontCare,
10870 kTextRegionDontCare,
10871 NULL, &encoding);
10872 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10873 if (err == noErr)
10874 {
10875 UniChar code;
10876 Str255 pstr;
10877 ByteCount unicode_len;
10878
10879 pstr[0] = 1;
10880 pstr[1] = buf->code;
10881 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10882 sizeof (UniChar),
10883 &unicode_len, &code);
10884 if (err == noErr && unicode_len == sizeof (UniChar))
10885 mac_set_unicode_keystroke_event (code, buf);
10886 DisposeTextToUnicodeInfo (&ttu_info);
10887 }
10888 }
10889#endif
10890
10891 if (buf->kind == ASCII_KEYSTROKE_EVENT
10892 && buf->code >= 0x80
10893 && last_key_script != current_key_script)
10894 {
10895 struct input_event event;
10896
10897 EVENT_INIT (event);
10898 event.kind = LANGUAGE_CHANGE_EVENT;
10899 event.arg = Qnil;
10900 event.code = current_key_script;
10901 event.timestamp = timestamp;
10902 kbd_buffer_store_event (&event);
10903 last_key_script = current_key_script;
10904 }
10905}
10906
a733ef16 10907void
6a0b5d37
YM
10908mac_store_apple_event (class, id, desc)
10909 Lisp_Object class, id;
10910 const AEDesc *desc;
742fbed7 10911{
1c05c15b 10912 struct input_event buf;
742fbed7 10913
a733ef16 10914 EVENT_INIT (buf);
1c05c15b 10915
a733ef16
YM
10916 buf.kind = MAC_APPLE_EVENT;
10917 buf.x = class;
10918 buf.y = id;
10919 XSETFRAME (buf.frame_or_window,
10920 mac_focus_frame (&one_mac_display_info));
10921 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10922 is safe to use them during read_socket_hook. */
10923 buf.arg = mac_aedesc_to_lisp (desc);
10924 kbd_buffer_store_event (&buf);
6a0b5d37 10925}
1c05c15b 10926
a733ef16 10927#if TARGET_API_MAC_CARBON
68c767a3
YM
10928static OSStatus
10929mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10930 event, num_params, names, types)
10931 AEEventClass class;
10932 AEEventID id;
10933 Lisp_Object class_key, id_key;
10934 EventRef event;
10935 UInt32 num_params;
369a7a37
YM
10936 const EventParamName *names;
10937 const EventParamType *types;
68c767a3
YM
10938{
10939 OSStatus err = eventNotHandledErr;
10940 Lisp_Object binding;
10941
10942 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10943 if (!NILP (binding) && !EQ (binding, Qundefined))
10944 {
10945 if (INTEGERP (binding))
10946 err = XINT (binding);
10947 else
10948 {
10949 AppleEvent apple_event;
10950 err = create_apple_event_from_event_ref (event, num_params,
10951 names, types,
10952 &apple_event);
10953 if (err == noErr)
10954 {
10955 mac_store_apple_event (class_key, id_key, &apple_event);
10956 AEDisposeDesc (&apple_event);
0d36bf23 10957 mac_wakeup_from_rne ();
68c767a3
YM
10958 }
10959 }
6a0b5d37 10960 }
1c05c15b 10961
6a0b5d37
YM
10962 return err;
10963}
1c05c15b 10964
a733ef16
YM
10965void
10966mac_store_drag_event (window, mouse_pos, modifiers, desc)
10967 WindowRef window;
10968 Point mouse_pos;
10969 SInt16 modifiers;
10970 const AEDesc *desc;
6a0b5d37 10971{
a733ef16 10972 struct input_event buf;
1c05c15b 10973
a733ef16 10974 EVENT_INIT (buf);
b15325b2 10975
a733ef16
YM
10976 buf.kind = DRAG_N_DROP_EVENT;
10977 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10978 buf.timestamp = TickCount () * (1000 / 60);
10979 XSETINT (buf.x, mouse_pos.h);
10980 XSETINT (buf.y, mouse_pos.v);
10981 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10982 buf.arg = mac_aedesc_to_lisp (desc);
10983 kbd_buffer_store_event (&buf);
1c05c15b
YM
10984}
10985
7adf3143
YM
10986#ifdef MAC_OSX
10987OSStatus
10988mac_store_service_event (event)
1c05c15b 10989 EventRef event;
1c05c15b 10990{
7adf3143
YM
10991 OSStatus err;
10992 Lisp_Object id_key;
10993 int num_params;
10994 const EventParamName *names;
10995 const EventParamType *types;
10996 static const EventParamName names_pfm[] =
10997 {kEventParamServiceMessageName, kEventParamServiceUserData};
10998 static const EventParamType types_pfm[] =
10999 {typeCFStringRef, typeCFStringRef};
1c05c15b 11000
7adf3143
YM
11001 switch (GetEventKind (event))
11002 {
11003 case kEventServicePaste:
11004 id_key = Qpaste;
11005 num_params = 0;
11006 names = NULL;
11007 types = NULL;
11008 break;
1c05c15b 11009
7adf3143
YM
11010 case kEventServicePerform:
11011 id_key = Qperform;
11012 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
11013 names = names_pfm;
11014 types = types_pfm;
11015 break;
1c05c15b 11016
7adf3143
YM
11017 default:
11018 abort ();
11019 }
1c05c15b 11020
7adf3143
YM
11021 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
11022 event, num_params,
11023 names, types);
1c05c15b 11024
7adf3143 11025 return err;
1c05c15b 11026}
7adf3143 11027#endif /* MAC_OSX */
1c05c15b 11028
b15325b2
ST
11029static pascal OSStatus
11030mac_handle_window_event (next_handler, event, data)
11031 EventHandlerCallRef next_handler;
11032 EventRef event;
11033 void *data;
11034{
3354caee 11035 WindowRef wp;
7adf3143 11036 OSStatus err, result = eventNotHandledErr;
bed0bf95 11037 struct frame *f;
b15325b2
ST
11038 UInt32 attributes;
11039 XSizeHints *size_hints;
11040
a3510ffa 11041 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
3354caee 11042 NULL, sizeof (WindowRef), NULL, &wp);
a3510ffa
YM
11043 if (err != noErr)
11044 return eventNotHandledErr;
b15325b2 11045
bed0bf95 11046 f = mac_window_to_frame (wp);
b15325b2
ST
11047 switch (GetEventKind (event))
11048 {
7adf3143
YM
11049 /* -- window refresh events -- */
11050
e0e76ab9
ST
11051 case kEventWindowUpdate:
11052 result = CallNextEventHandler (next_handler, event);
11053 if (result != eventNotHandledErr)
7adf3143 11054 break;
e0e76ab9
ST
11055
11056 do_window_update (wp);
7adf3143
YM
11057 result = noErr;
11058 break;
e0e76ab9 11059
7adf3143 11060 /* -- window state change events -- */
bed0bf95 11061
7adf3143
YM
11062 case kEventWindowShowing:
11063 size_hints = FRAME_SIZE_HINTS (f);
11064 if (!(size_hints->flags & (USPosition | PPosition)))
11065 {
11066 struct frame *sf = SELECTED_FRAME ();
bed0bf95 11067
ad3b3e02 11068 if (!(FRAME_MAC_P (sf) && sf->async_visible))
7adf3143
YM
11069 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
11070 else
11071 {
11072 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
11073#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
11074 kWindowCascadeStartAtParentWindowScreen
11075#else
11076 kWindowCascadeOnParentWindowScreen
11077#endif
11078 );
c6829f81
YM
11079#if USE_MAC_TOOLBAR
11080 /* This is a workaround. RepositionWindow fails to put
11081 a window at the cascading position when its parent
11082 window has a Carbon HIToolbar. */
f9426479
YM
11083 if ((f->left_pos == sf->left_pos
11084 && f->top_pos == sf->top_pos)
11085 || (f->left_pos == sf->left_pos + 10 * 2
11086 && f->top_pos == sf->top_pos + 32 * 2))
ad3b3e02 11087 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
c6829f81 11088#endif
7adf3143
YM
11089 }
11090 result = noErr;
11091 }
11092 break;
11093
11094 case kEventWindowHiding:
11095 /* Before unmapping the window, update the WM_SIZE_HINTS
11096 property to claim that the current position of the window is
11097 user-specified, rather than program-specified, so that when
11098 the window is mapped again, it will be placed at the same
11099 location, without forcing the user to position it by hand
11100 again (they have already done that once for this window.) */
11101 x_wm_set_size_hint (f, (long) 0, 1);
11102 result = noErr;
11103 break;
11104
11105 case kEventWindowShown:
11106 case kEventWindowHidden:
11107 case kEventWindowCollapsed:
11108 case kEventWindowExpanded:
11109 mac_handle_visibility_change (f);
11110 result = noErr;
bed0bf95
YM
11111 break;
11112
b15325b2
ST
11113 case kEventWindowBoundsChanging:
11114 result = CallNextEventHandler (next_handler, event);
11115 if (result != eventNotHandledErr)
7adf3143 11116 break;
b15325b2 11117
a3510ffa
YM
11118 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11119 NULL, sizeof (UInt32), NULL, &attributes);
11120 if (err != noErr)
11121 break;
11122
bed0bf95 11123 size_hints = FRAME_SIZE_HINTS (f);
b15325b2
ST
11124 if ((attributes & kWindowBoundsChangeUserResize)
11125 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
11126 == (PResizeInc | PBaseSize | PMinSize)))
11127 {
11128 Rect bounds;
11129 int width, height;
11130
a3510ffa
YM
11131 err = GetEventParameter (event, kEventParamCurrentBounds,
11132 typeQDRectangle, NULL, sizeof (Rect),
11133 NULL, &bounds);
11134 if (err != noErr)
11135 break;
11136
b15325b2
ST
11137 width = bounds.right - bounds.left;
11138 height = bounds.bottom - bounds.top;
11139
11140 if (width < size_hints->min_width)
11141 width = size_hints->min_width;
11142 else
11143 width = size_hints->base_width
11144 + (int) ((width - size_hints->base_width)
11145 / (float) size_hints->width_inc + .5)
11146 * size_hints->width_inc;
11147
11148 if (height < size_hints->min_height)
11149 height = size_hints->min_height;
11150 else
11151 height = size_hints->base_height
11152 + (int) ((height - size_hints->base_height)
11153 / (float) size_hints->height_inc + .5)
11154 * size_hints->height_inc;
11155
11156 bounds.right = bounds.left + width;
11157 bounds.bottom = bounds.top + height;
11158 SetEventParameter (event, kEventParamCurrentBounds,
11159 typeQDRectangle, sizeof (Rect), &bounds);
7adf3143 11160 result = noErr;
b15325b2
ST
11161 }
11162 break;
1f98fbb4 11163
bed0bf95
YM
11164 case kEventWindowBoundsChanged:
11165 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11166 NULL, sizeof (UInt32), NULL, &attributes);
11167 if (err != noErr)
11168 break;
11169
11170 if (attributes & kWindowBoundsChangeSizeChanged)
11171 {
11172 Rect bounds;
11173
11174 err = GetEventParameter (event, kEventParamCurrentBounds,
11175 typeQDRectangle, NULL, sizeof (Rect),
11176 NULL, &bounds);
11177 if (err == noErr)
11178 {
11179 int width, height;
11180
11181 width = bounds.right - bounds.left;
11182 height = bounds.bottom - bounds.top;
11183 mac_handle_size_change (f, width, height);
262be72a 11184 mac_wakeup_from_rne ();
bed0bf95
YM
11185 }
11186 }
11187
11188 if (attributes & kWindowBoundsChangeOriginChanged)
11189 mac_handle_origin_change (f);
11190
7adf3143 11191 result = noErr;
1f98fbb4 11192 break;
68c767a3 11193
7adf3143
YM
11194 /* -- window action events -- */
11195
750a6cf4
YM
11196 case kEventWindowClose:
11197 {
11198 struct input_event buf;
11199
11200 EVENT_INIT (buf);
11201 buf.kind = DELETE_WINDOW_EVENT;
bed0bf95 11202 XSETFRAME (buf.frame_or_window, f);
750a6cf4
YM
11203 buf.arg = Qnil;
11204 kbd_buffer_store_event (&buf);
11205 }
7adf3143
YM
11206 result = noErr;
11207 break;
11208
11209 case kEventWindowGetIdealSize:
11210 result = CallNextEventHandler (next_handler, event);
11211 if (result != eventNotHandledErr)
11212 break;
11213
11214 {
11215 Point ideal_size = mac_get_ideal_size (f);
11216
11217 err = SetEventParameter (event, kEventParamDimensions,
11218 typeQDPoint, sizeof (Point), &ideal_size);
11219 if (err == noErr)
11220 result = noErr;
11221 }
11222 break;
750a6cf4 11223
68c767a3
YM
11224#ifdef MAC_OSX
11225 case kEventWindowToolbarSwitchMode:
68c767a3 11226 {
369a7a37
YM
11227 static const EventParamName names[] = {kEventParamDirectObject,
11228 kEventParamWindowMouseLocation,
11229 kEventParamKeyModifiers,
11230 kEventParamMouseButton,
11231 kEventParamClickCount,
11232 kEventParamMouseChord};
11233 static const EventParamType types[] = {typeWindowRef,
11234 typeQDPoint,
11235 typeUInt32,
11236 typeMouseButton,
11237 typeUInt32,
11238 typeUInt32};
68c767a3
YM
11239 int num_params = sizeof (names) / sizeof (names[0]);
11240
11241 err = mac_store_event_ref_as_apple_event (0, 0,
11242 Qwindow,
11243 Qtoolbar_switch_mode,
11244 event, num_params,
11245 names, types);
11246 }
7adf3143
YM
11247 if (err == noErr)
11248 result = noErr;
11249 break;
68c767a3 11250#endif
02236cbc
YM
11251
11252#if USE_MAC_TSM
7adf3143
YM
11253 /* -- window focus events -- */
11254
02236cbc 11255 case kEventWindowFocusAcquired:
b4c51596 11256 err = mac_tsm_resume ();
7adf3143
YM
11257 if (err == noErr)
11258 result = noErr;
11259 break;
02236cbc
YM
11260
11261 case kEventWindowFocusRelinquish:
b4c51596 11262 err = mac_tsm_suspend ();
7adf3143
YM
11263 if (err == noErr)
11264 result = noErr;
11265 break;
11266#endif
11267
11268 default:
11269 abort ();
11270 }
11271
11272 return result;
11273}
11274
11275static pascal OSStatus
11276mac_handle_application_event (next_handler, event, data)
11277 EventHandlerCallRef next_handler;
11278 EventRef event;
11279 void *data;
11280{
11281 OSStatus err, result = eventNotHandledErr;
11282
11283 switch (GetEventKind (event))
11284 {
11285#if USE_MAC_TSM
11286 case kEventAppActivated:
11287 err = mac_tsm_resume ();
11288 break;
11289
11290 case kEventAppDeactivated:
11291 err = mac_tsm_suspend ();
11292 break;
11293#endif
11294
11295 default:
11296 abort ();
11297 }
11298
11299 if (err == noErr)
11300 result = noErr;
11301
11302 return result;
11303}
11304
11305static pascal OSStatus
11306mac_handle_keyboard_event (next_handler, event, data)
11307 EventHandlerCallRef next_handler;
11308 EventRef event;
11309 void *data;
11310{
11311 OSStatus err, result = eventNotHandledErr;
7b7d07bb 11312 UInt32 event_kind, key_code, modifiers;
7adf3143
YM
11313 unsigned char char_code;
11314
11315 event_kind = GetEventKind (event);
11316 switch (event_kind)
11317 {
11318 case kEventRawKeyDown:
11319 case kEventRawKeyRepeat:
11320 case kEventRawKeyUp:
7adf3143
YM
11321 /* When using Carbon Events, we need to pass raw keyboard events
11322 to the TSM ourselves. If TSM handles it, it will pass back
11323 noErr, otherwise it will pass back "eventNotHandledErr" and
11324 we can process it normally. */
7b7d07bb
YM
11325 result = CallNextEventHandler (next_handler, event);
11326 if (result != eventNotHandledErr)
11327 break;
11328
11329 if (read_socket_inev == NULL)
11330 break;
7adf3143
YM
11331
11332#if USE_MAC_TSM
11333 if (read_socket_inev->kind != NO_EVENT)
11334 {
11335 result = noErr;
11336 break;
11337 }
02236cbc 11338#endif
7adf3143
YM
11339
11340 if (event_kind == kEventRawKeyUp)
11341 break;
11342
11343 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11344 typeChar, NULL,
11345 sizeof (char), NULL, &char_code);
11346 if (err != noErr)
11347 break;
11348
11349 err = GetEventParameter (event, kEventParamKeyCode,
11350 typeUInt32, NULL,
11351 sizeof (UInt32), NULL, &key_code);
11352 if (err != noErr)
11353 break;
11354
7b7d07bb
YM
11355 err = GetEventParameter (event, kEventParamKeyModifiers,
11356 typeUInt32, NULL,
11357 sizeof (UInt32), NULL, &modifiers);
11358 if (err != noErr)
11359 break;
11360
c6829f81 11361 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
7adf3143
YM
11362 char_code, key_code, modifiers,
11363 ((unsigned long)
11364 (GetEventTime (event) / kEventDurationMillisecond)),
11365 read_socket_inev);
11366 result = noErr;
11367 break;
11368
11369 default:
11370 abort ();
11371 }
11372
11373 return result;
11374}
11375
11376static pascal OSStatus
11377mac_handle_command_event (next_handler, event, data)
11378 EventHandlerCallRef next_handler;
11379 EventRef event;
11380 void *data;
11381{
11382 OSStatus err, result = eventNotHandledErr;
11383 HICommand command;
11384 static const EventParamName names[] =
11385 {kEventParamDirectObject, kEventParamKeyModifiers};
11386 static const EventParamType types[] =
11387 {typeHICommand, typeUInt32};
11388 int num_params = sizeof (names) / sizeof (names[0]);
11389
11390 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11391 NULL, sizeof (HICommand), NULL, &command);
11392 if (err != noErr)
11393 return eventNotHandledErr;
11394
11395 switch (GetEventKind (event))
11396 {
11397 case kEventCommandProcess:
11398 result = CallNextEventHandler (next_handler, event);
11399 if (result != eventNotHandledErr)
11400 break;
11401
11402 err = GetEventParameter (event, kEventParamDirectObject,
11403 typeHICommand, NULL,
11404 sizeof (HICommand), NULL, &command);
11405
11406 if (err != noErr || command.commandID == 0)
11407 break;
11408
11409 /* A HI command event is mapped to an Apple event whose event
11410 class symbol is `hi-command' and event ID is its command
11411 ID. */
11412 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11413 Qhi_command, Qnil,
11414 event, num_params,
11415 names, types);
11416 if (err == noErr)
11417 result = noErr;
11418 break;
11419
11420 default:
11421 abort ();
b15325b2
ST
11422 }
11423
7adf3143 11424 return result;
b15325b2 11425}
95085023
YM
11426
11427static pascal OSStatus
11428mac_handle_mouse_event (next_handler, event, data)
11429 EventHandlerCallRef next_handler;
11430 EventRef event;
11431 void *data;
11432{
7adf3143 11433 OSStatus err, result = eventNotHandledErr;
95085023
YM
11434
11435 switch (GetEventKind (event))
11436 {
11437 case kEventMouseWheelMoved:
11438 {
3354caee 11439 WindowRef wp;
95085023
YM
11440 struct frame *f;
11441 EventMouseWheelAxis axis;
11442 SInt32 delta;
11443 Point point;
11444
11445 result = CallNextEventHandler (next_handler, event);
11446 if (result != eventNotHandledErr || read_socket_inev == NULL)
7adf3143
YM
11447 break;
11448
11449 f = mac_focus_frame (&one_mac_display_info);
95085023 11450
a3510ffa
YM
11451 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11452 NULL, sizeof (WindowRef), NULL, &wp);
7adf3143
YM
11453 if (err != noErr
11454 || wp != FRAME_MAC_WINDOW (f))
95085023
YM
11455 break;
11456
a3510ffa
YM
11457 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11458 typeMouseWheelAxis, NULL,
11459 sizeof (EventMouseWheelAxis), NULL, &axis);
11460 if (err != noErr || axis != kEventMouseWheelAxisY)
95085023
YM
11461 break;
11462
a3510ffa
YM
11463 err = GetEventParameter (event, kEventParamMouseLocation,
11464 typeQDPoint, NULL, sizeof (Point),
11465 NULL, &point);
11466 if (err != noErr)
11467 break;
5bc21f35 11468
7adf3143
YM
11469 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11470 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5bc21f35
YM
11471 if (point.h < 0 || point.v < 0
11472 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11473 f->tool_bar_window))
11474 break;
11475
11476 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11477 typeSInt32, NULL, sizeof (SInt32),
11478 NULL, &delta);
11479 if (err != noErr)
11480 break;
11481
95085023
YM
11482 read_socket_inev->kind = WHEEL_EVENT;
11483 read_socket_inev->code = 0;
11484 read_socket_inev->modifiers =
11485 (mac_event_to_emacs_modifiers (event)
11486 | ((delta < 0) ? down_modifier : up_modifier));
95085023
YM
11487 XSETINT (read_socket_inev->x, point.h);
11488 XSETINT (read_socket_inev->y, point.v);
11489 XSETFRAME (read_socket_inev->frame_or_window, f);
95085023 11490
7adf3143 11491 result = noErr;
95085023
YM
11492 }
11493 break;
11494
11495 default:
7adf3143 11496 abort ();
68c767a3
YM
11497 }
11498
7adf3143 11499 return result;
68c767a3 11500}
68c767a3 11501
02236cbc
YM
11502#if USE_MAC_TSM
11503static pascal OSStatus
11504mac_handle_text_input_event (next_handler, event, data)
11505 EventHandlerCallRef next_handler;
11506 EventRef event;
11507 void *data;
11508{
a56dd283 11509 OSStatus err, result;
02236cbc
YM
11510 Lisp_Object id_key = Qnil;
11511 int num_params;
369a7a37
YM
11512 const EventParamName *names;
11513 const EventParamType *types;
02236cbc 11514 static UInt32 seqno_uaia = 0;
369a7a37 11515 static const EventParamName names_uaia[] =
02236cbc
YM
11516 {kEventParamTextInputSendComponentInstance,
11517 kEventParamTextInputSendRefCon,
11518 kEventParamTextInputSendSLRec,
11519 kEventParamTextInputSendFixLen,
11520 kEventParamTextInputSendText,
11521 kEventParamTextInputSendUpdateRng,
11522 kEventParamTextInputSendHiliteRng,
11523 kEventParamTextInputSendClauseRng,
11524 kEventParamTextInputSendPinRng,
11525 kEventParamTextInputSendTextServiceEncoding,
11526 kEventParamTextInputSendTextServiceMacEncoding,
11527 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
369a7a37 11528 static const EventParamType types_uaia[] =
02236cbc
YM
11529 {typeComponentInstance,
11530 typeLongInteger,
11531 typeIntlWritingCode,
11532 typeLongInteger,
92289429 11533#ifdef MAC_OSX
02236cbc 11534 typeUnicodeText,
92289429
YM
11535#else
11536 typeChar,
11537#endif
02236cbc
YM
11538 typeTextRangeArray,
11539 typeTextRangeArray,
11540 typeOffsetArray,
11541 typeTextRange,
11542 typeUInt32,
11543 typeUInt32,
11544 typeUInt32};
369a7a37 11545 static const EventParamName names_ufke[] =
02236cbc
YM
11546 {kEventParamTextInputSendComponentInstance,
11547 kEventParamTextInputSendRefCon,
11548 kEventParamTextInputSendSLRec,
11549 kEventParamTextInputSendText};
369a7a37 11550 static const EventParamType types_ufke[] =
02236cbc
YM
11551 {typeComponentInstance,
11552 typeLongInteger,
11553 typeIntlWritingCode,
11554 typeUnicodeText};
11555
11556 result = CallNextEventHandler (next_handler, event);
7adf3143
YM
11557 if (result != eventNotHandledErr)
11558 return result;
02236cbc
YM
11559
11560 switch (GetEventKind (event))
11561 {
11562 case kEventTextInputUpdateActiveInputArea:
11563 id_key = Qupdate_active_input_area;
11564 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11565 names = names_uaia;
11566 types = types_uaia;
11567 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11568 typeUInt32, sizeof (UInt32), &seqno_uaia);
11569 seqno_uaia++;
a56dd283 11570 result = noErr;
02236cbc
YM
11571 break;
11572
11573 case kEventTextInputUnicodeForKeyEvent:
11574 {
11575 EventRef kbd_event;
d8506697 11576 UInt32 actual_size, modifiers;
02236cbc
YM
11577
11578 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11579 typeEventRef, NULL, sizeof (EventRef), NULL,
11580 &kbd_event);
11581 if (err == noErr)
11582 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11583 typeUInt32, NULL,
11584 sizeof (UInt32), NULL, &modifiers);
a84cad70
YM
11585 if (err == noErr && mac_mapped_modifiers (modifiers))
11586 /* There're mapped modifier keys. Process it in
7adf3143 11587 do_keystroke. */
a56dd283 11588 break;
02236cbc
YM
11589 if (err == noErr)
11590 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11591 typeUnicodeText, NULL, 0, &actual_size,
11592 NULL);
1e53bd0e 11593 if (err == noErr && actual_size == sizeof (UniChar))
02236cbc 11594 {
1e53bd0e
YM
11595 UniChar code;
11596
11597 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11598 typeUnicodeText, NULL,
11599 sizeof (UniChar), NULL, &code);
02236cbc
YM
11600 if (err == noErr && code < 0x80)
11601 {
7adf3143 11602 /* ASCII character. Process it in do_keystroke. */
67b5f809 11603 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
02236cbc 11604 {
1e53bd0e
YM
11605 UInt32 key_code;
11606
11607 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11608 typeUInt32, NULL, sizeof (UInt32),
11609 NULL, &key_code);
11610 if (!(err == noErr && key_code <= 0x7f
11611 && keycode_to_xkeysym_table [key_code]))
11612 {
11613 struct frame *f =
11614 mac_focus_frame (&one_mac_display_info);
11615
11616 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11617 read_socket_inev->code = code;
11618 read_socket_inev->modifiers =
750a6cf4
YM
11619 mac_to_emacs_modifiers (modifiers);
11620 read_socket_inev->modifiers |=
1e53bd0e
YM
11621 (extra_keyboard_modifiers
11622 & (meta_modifier | alt_modifier
11623 | hyper_modifier | super_modifier));
11624 XSETFRAME (read_socket_inev->frame_or_window, f);
11625 }
02236cbc 11626 }
a56dd283 11627 break;
02236cbc
YM
11628 }
11629 }
a56dd283
YM
11630 if (err == noErr)
11631 {
11632 /* Non-ASCII keystrokes without mapped modifiers are
11633 processed at the Lisp level. */
11634 id_key = Qunicode_for_key_event;
11635 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11636 names = names_ufke;
11637 types = types_ufke;
11638 result = noErr;
11639 }
02236cbc 11640 }
02236cbc
YM
11641 break;
11642
11643 case kEventTextInputOffsetToPos:
11644 {
11645 struct frame *f;
11646 struct window *w;
11647 Point p;
11648
11649 if (!OVERLAYP (Vmac_ts_active_input_overlay))
a56dd283 11650 break;
02236cbc
YM
11651
11652 /* Strictly speaking, this is not always correct because
11653 previous events may change some states about display. */
a56dd283
YM
11654 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11655 {
11656 /* Active input area is displayed around the current point. */
11657 f = SELECTED_FRAME ();
11658 w = XWINDOW (f->selected_window);
11659 }
11660 else if (WINDOWP (echo_area_window))
02236cbc
YM
11661 {
11662 /* Active input area is displayed in the echo area. */
11663 w = XWINDOW (echo_area_window);
11664 f = WINDOW_XFRAME (w);
11665 }
11666 else
a56dd283 11667 break;
02236cbc
YM
11668
11669 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
7adf3143
YM
11670 + WINDOW_LEFT_FRINGE_WIDTH (w)
11671 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
02236cbc 11672 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
7adf3143
YM
11673 + FONT_BASE (FRAME_FONT (f))
11674 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
02236cbc
YM
11675 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11676 typeQDPoint, sizeof (typeQDPoint), &p);
a56dd283
YM
11677 if (err == noErr)
11678 result = noErr;
02236cbc
YM
11679 }
11680 break;
11681
11682 default:
11683 abort ();
11684 }
11685
11686 if (!NILP (id_key))
11687 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11688 event, num_params,
11689 names, types);
7adf3143 11690 return result;
02236cbc
YM
11691}
11692#endif
3354caee 11693#endif /* TARGET_API_MAC_CARBON */
b15325b2 11694
02236cbc 11695
68c767a3 11696OSStatus
b15325b2 11697install_window_handler (window)
3354caee 11698 WindowRef window;
6a0b5d37 11699{
3e7424f7 11700 OSStatus err = noErr;
6a0b5d37 11701
3354caee 11702#if TARGET_API_MAC_CARBON
7adf3143 11703 if (err == noErr)
6a0b5d37 11704 {
7adf3143
YM
11705 static const EventTypeSpec specs[] =
11706 {
11707 /* -- window refresh events -- */
11708 {kEventClassWindow, kEventWindowUpdate},
11709 /* -- window state change events -- */
11710 {kEventClassWindow, kEventWindowShowing},
11711 {kEventClassWindow, kEventWindowHiding},
11712 {kEventClassWindow, kEventWindowShown},
11713 {kEventClassWindow, kEventWindowHidden},
11714 {kEventClassWindow, kEventWindowCollapsed},
11715 {kEventClassWindow, kEventWindowExpanded},
11716 {kEventClassWindow, kEventWindowBoundsChanging},
11717 {kEventClassWindow, kEventWindowBoundsChanged},
11718 /* -- window action events -- */
11719 {kEventClassWindow, kEventWindowClose},
11720 {kEventClassWindow, kEventWindowGetIdealSize},
68c767a3 11721#ifdef MAC_OSX
7adf3143 11722 {kEventClassWindow, kEventWindowToolbarSwitchMode},
68c767a3 11723#endif
02236cbc 11724#if USE_MAC_TSM
7adf3143
YM
11725 /* -- window focus events -- */
11726 {kEventClassWindow, kEventWindowFocusAcquired},
11727 {kEventClassWindow, kEventWindowFocusRelinquish},
02236cbc 11728#endif
7adf3143
YM
11729 };
11730 static EventHandlerUPP handle_window_eventUPP = NULL;
6a0b5d37 11731
7adf3143
YM
11732 if (handle_window_eventUPP == NULL)
11733 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
6a0b5d37 11734
7adf3143
YM
11735 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11736 GetEventTypeCount (specs),
11737 specs, NULL, NULL);
6a0b5d37 11738 }
30c92fab 11739#endif
6a0b5d37 11740
30c92fab 11741 if (err == noErr)
a733ef16 11742 err = install_drag_handler (window);
6a0b5d37
YM
11743
11744 return err;
11745}
b15325b2 11746
25c9622b
YM
11747void
11748remove_window_handler (window)
3354caee 11749 WindowRef window;
25c9622b 11750{
a733ef16 11751 remove_drag_handler (window);
742fbed7 11752}
b15325b2 11753
7adf3143
YM
11754#if TARGET_API_MAC_CARBON
11755static OSStatus
11756install_application_handler ()
b15325b2 11757{
3e7424f7 11758 OSStatus err = noErr;
95085023 11759
7adf3143
YM
11760 if (err == noErr)
11761 {
11762 static const EventTypeSpec specs[] = {
02236cbc 11763#if USE_MAC_TSM
7adf3143
YM
11764 {kEventClassApplication, kEventAppActivated},
11765 {kEventClassApplication, kEventAppDeactivated},
68c767a3 11766#endif
7adf3143
YM
11767 };
11768
11769 err = InstallApplicationEventHandler (NewEventHandlerUPP
11770 (mac_handle_application_event),
11771 GetEventTypeCount (specs),
11772 specs, NULL, NULL);
11773 }
11774
95085023 11775 if (err == noErr)
7adf3143
YM
11776 {
11777 static const EventTypeSpec specs[] =
11778 {{kEventClassKeyboard, kEventRawKeyDown},
11779 {kEventClassKeyboard, kEventRawKeyRepeat},
11780 {kEventClassKeyboard, kEventRawKeyUp}};
11781
11782 err = InstallApplicationEventHandler (NewEventHandlerUPP
11783 (mac_handle_keyboard_event),
11784 GetEventTypeCount (specs),
11785 specs, NULL, NULL);
11786 }
11787
30c92fab 11788 if (err == noErr)
7adf3143
YM
11789 {
11790 static const EventTypeSpec specs[] =
11791 {{kEventClassCommand, kEventCommandProcess}};
11792
11793 err = InstallApplicationEventHandler (NewEventHandlerUPP
11794 (mac_handle_command_event),
11795 GetEventTypeCount (specs),
11796 specs, NULL, NULL);
11797 }
11798
11799 if (err == noErr)
11800 {
11801 static const EventTypeSpec specs[] =
11802 {{kEventClassMouse, kEventMouseWheelMoved}};
11803
11804 err = InstallApplicationEventHandler (NewEventHandlerUPP
11805 (mac_handle_mouse_event),
11806 GetEventTypeCount (specs),
11807 specs, NULL, NULL);
11808 }
11809
02236cbc
YM
11810#if USE_MAC_TSM
11811 if (err == noErr)
7adf3143
YM
11812 {
11813 static const EventTypeSpec spec[] =
11814 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11815 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11816 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11817
11818 err = InstallApplicationEventHandler (NewEventHandlerUPP
11819 (mac_handle_text_input_event),
11820 GetEventTypeCount (spec),
11821 spec, NULL, NULL);
11822 }
742fbed7 11823#endif
7adf3143 11824
30c92fab 11825 if (err == noErr)
7adf3143
YM
11826 err = install_menu_target_item_handler ();
11827
11828#ifdef MAC_OSX
e2d3b7e1 11829 if (err == noErr)
7adf3143
YM
11830 err = install_service_handler ();
11831#endif
a733ef16 11832
30c92fab 11833 return err;
b15325b2 11834}
7adf3143 11835#endif
742fbed7 11836
19ee09cc
YM
11837static pascal void
11838mac_handle_dm_notification (event)
11839 AppleEvent *event;
11840{
11841 mac_screen_config_changed = 1;
11842}
11843
7adf3143
YM
11844#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11845static void
11846mac_handle_cg_display_reconfig (display, flags, user_info)
11847 CGDirectDisplayID display;
11848 CGDisplayChangeSummaryFlags flags;
11849 void *user_info;
11850{
11851 mac_screen_config_changed = 1;
11852}
11853#endif
11854
19ee09cc
YM
11855static OSErr
11856init_dm_notification_handler ()
11857{
7adf3143
YM
11858 OSErr err = noErr;
11859
11860#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11861#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11862 if (CGDisplayRegisterReconfigurationCallback != NULL)
11863#endif
11864 {
11865 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11866 NULL);
11867 }
11868#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11869 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11870#endif
11871#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11872#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11873 {
11874 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11875 ProcessSerialNumber psn;
19ee09cc 11876
7adf3143
YM
11877 if (handle_dm_notificationUPP == NULL)
11878 handle_dm_notificationUPP =
11879 NewDMNotificationUPP (mac_handle_dm_notification);
19ee09cc 11880
7adf3143
YM
11881 err = GetCurrentProcess (&psn);
11882 if (err == noErr)
11883 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11884 }
11885#endif
19ee09cc
YM
11886
11887 return err;
11888}
11889
11890static void
11891mac_get_screen_info (dpyinfo)
11892 struct mac_display_info *dpyinfo;
11893{
11894#ifdef MAC_OSX
11895 /* HasDepth returns true if it is possible to have a 32 bit display,
11896 but this may not be what is actually used. Mac OSX can do better. */
11897 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11898 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11899 {
11900 CGDisplayErr err;
11901 CGDisplayCount ndisps;
11902 CGDirectDisplayID *displays;
11903
11904 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11905 if (err == noErr)
11906 {
11907 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11908 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11909 }
11910 if (err == noErr)
11911 {
11912 CGRect bounds = CGRectZero;
11913
11914 while (ndisps-- > 0)
11915 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11916 dpyinfo->height = CGRectGetHeight (bounds);
11917 dpyinfo->width = CGRectGetWidth (bounds);
11918 }
11919 else
11920 {
11921 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11922 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11923 }
11924 }
11925#else /* !MAC_OSX */
11926 {
11927 GDHandle gdh = GetMainDevice ();
11928 Rect rect = (**gdh).gdRect;
11929
11930 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11931 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11932 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11933 break;
11934
11935 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11936 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11937 UnionRect (&rect, &(**gdh).gdRect, &rect);
11938
11939 dpyinfo->height = rect.bottom - rect.top;
11940 dpyinfo->width = rect.right - rect.left;
11941 }
11942#endif /* !MAC_OSX */
11943}
11944
11945
1a578e9b
AC
11946#if __profile__
11947void
11948profiler_exit_proc ()
11949{
11950 ProfilerDump ("\pEmacs.prof");
11951 ProfilerTerm ();
11952}
11953#endif
11954
11955/* These few functions implement Emacs as a normal Mac application
e6bdfa32
YM
11956 (almost): set up the heap and the Toolbox, handle necessary system
11957 events plus a few simple menu events. They also set up Emacs's
11958 access to functions defined in the rest of this file. Emacs uses
11959 function hooks to perform all its terminal I/O. A complete list of
11960 these functions appear in termhooks.h. For what they do, read the
11961 comments there and see also w32term.c and xterm.c. What's
11962 noticeably missing here is the event loop, which is normally
11963 present in most Mac application. After performing the necessary
11964 Mac initializations, main passes off control to emacs_main
11965 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11966 (defined further below) to read input. This is where
11967 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
1a578e9b 11968
25c9622b 11969#ifdef MAC_OS8
1a578e9b 11970#undef main
177c0ea7 11971int
1a578e9b
AC
11972main (void)
11973{
11974#if __profile__ /* is the profiler on? */
11975 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11976 exit(1);
11977#endif
11978
11979#if __MWERKS__
11980 /* set creator and type for files created by MSL */
e2d3b7e1 11981 _fcreator = MAC_EMACS_CREATOR_CODE;
1a578e9b
AC
11982 _ftype = 'TEXT';
11983#endif
11984
11985 do_init_managers ();
177c0ea7 11986
1a578e9b 11987 do_get_menus ();
177c0ea7 11988
6b61353c 11989#ifndef USE_LSB_TAG
2e875e36 11990 do_check_ram_size ();
6b61353c 11991#endif
2e875e36 11992
1a578e9b
AC
11993 init_emacs_passwd_dir ();
11994
11995 init_environ ();
11996
0e0a1663
YM
11997 init_coercion_handler ();
11998
1a578e9b
AC
11999 initialize_applescript ();
12000
6a0b5d37 12001 init_apple_event_handler ();
177c0ea7 12002
19ee09cc
YM
12003 init_dm_notification_handler ();
12004
1a578e9b
AC
12005 {
12006 char **argv;
12007 int argc = 0;
12008
12009 /* set up argv array from STR# resource */
12010 get_string_list (&argv, ARGV_STRING_LIST_ID);
12011 while (argv[argc])
12012 argc++;
12013
12014 /* free up AppleScript resources on exit */
12015 atexit (terminate_applescript);
12016
12017#if __profile__ /* is the profiler on? */
12018 atexit (profiler_exit_proc);
12019#endif
12020
12021 /* 3rd param "envp" never used in emacs_main */
12022 (void) emacs_main (argc, argv, 0);
12023 }
12024
12025 /* Never reached - real exit in Fkill_emacs */
12026 return 0;
12027}
e0f712ba 12028#endif
1a578e9b 12029
3354caee 12030#if !TARGET_API_MAC_CARBON
b15325b2
ST
12031static RgnHandle mouse_region = NULL;
12032
12033Boolean
12034mac_wait_next_event (er, sleep_time, dequeue)
12035 EventRecord *er;
12036 UInt32 sleep_time;
12037 Boolean dequeue;
12038{
12039 static EventRecord er_buf = {nullEvent};
12040 UInt32 target_tick, current_tick;
12041 EventMask event_mask;
12042
12043 if (mouse_region == NULL)
12044 mouse_region = NewRgn ();
12045
12046 event_mask = everyEvent;
6a0b5d37 12047 if (!mac_ready_for_apple_events)
b15325b2
ST
12048 event_mask -= highLevelEventMask;
12049
12050 current_tick = TickCount ();
12051 target_tick = current_tick + sleep_time;
12052
12053 if (er_buf.what == nullEvent)
12054 while (!WaitNextEvent (event_mask, &er_buf,
12055 target_tick - current_tick, mouse_region))
12056 {
12057 current_tick = TickCount ();
12058 if (target_tick <= current_tick)
12059 return false;
12060 }
12061
12062 *er = er_buf;
12063 if (dequeue)
12064 er_buf.what = nullEvent;
12065 return true;
12066}
3354caee 12067#endif /* not TARGET_API_MAC_CARBON */
b15325b2 12068
a733ef16
YM
12069#if TARGET_API_MAC_CARBON
12070OSStatus
12071mac_post_mouse_moved_event ()
12072{
12073 EventRef event = NULL;
12074 OSStatus err;
12075
12076 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
12077 kEventAttributeNone, &event);
12078 if (err == noErr)
12079 {
12080 Point mouse_pos;
12081
2a953eae 12082 GetGlobalMouse (&mouse_pos);
a733ef16
YM
12083 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
12084 sizeof (Point), &mouse_pos);
12085 }
12086 if (err == noErr)
12087 {
12088 UInt32 modifiers = GetCurrentKeyModifiers ();
12089
12090 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
12091 sizeof (UInt32), &modifiers);
12092 }
12093 if (err == noErr)
12094 err = PostEventToQueue (GetCurrentEventQueue (), event,
12095 kEventPriorityStandard);
12096 if (event)
12097 ReleaseEvent (event);
12098
12099 return err;
12100}
12101#endif
12102
1a578e9b
AC
12103/* Emacs calls this whenever it wants to read an input event from the
12104 user. */
12105int
50bf7673
ST
12106XTread_socket (sd, expected, hold_quit)
12107 int sd, expected;
12108 struct input_event *hold_quit;
1a578e9b 12109{
6b61353c 12110 struct input_event inev;
177c0ea7 12111 int count = 0;
3354caee 12112#if TARGET_API_MAC_CARBON
742fbed7 12113 EventRef eventRef;
b15325b2 12114 EventTargetRef toolbox_dispatcher;
742fbed7 12115#endif
1a578e9b 12116 EventRecord er;
50bf7673 12117 struct mac_display_info *dpyinfo = &one_mac_display_info;
1a578e9b
AC
12118
12119 if (interrupt_input_blocked)
12120 {
12121 interrupt_input_pending = 1;
12122 return -1;
12123 }
12124
12125 interrupt_input_pending = 0;
12126 BLOCK_INPUT;
12127
12128 /* So people can tell when we have read the available input. */
12129 input_signal_count++;
12130
b465419f
YM
12131 ++handling_signal;
12132
3354caee 12133#if TARGET_API_MAC_CARBON
b15325b2 12134 toolbox_dispatcher = GetEventDispatcherTarget ();
1a578e9b 12135
4ea08bbf
YM
12136 while (
12137#if USE_CG_DRAWING
12138 mac_prepare_for_quickdraw (NULL),
12139#endif
12140 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
50bf7673 12141 kEventRemoveFromQueue, &eventRef))
3354caee 12142#else /* !TARGET_API_MAC_CARBON */
b15325b2 12143 while (mac_wait_next_event (&er, 0, true))
3354caee 12144#endif /* !TARGET_API_MAC_CARBON */
742fbed7 12145 {
50bf7673
ST
12146 int do_help = 0;
12147 struct frame *f;
95dfb192 12148 unsigned long timestamp;
50bf7673 12149
50bf7673
ST
12150 EVENT_INIT (inev);
12151 inev.kind = NO_EVENT;
12152 inev.arg = Qnil;
12153
3354caee 12154#if TARGET_API_MAC_CARBON
95dfb192 12155 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
95dfb192 12156
177c0ea7 12157 if (!mac_convert_event_ref (eventRef, &er))
7adf3143
YM
12158 goto OTHER;
12159#else /* !TARGET_API_MAC_CARBON */
12160 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12161#endif /* !TARGET_API_MAC_CARBON */
12162
50bf7673 12163 switch (er.what)
1a578e9b 12164 {
50bf7673
ST
12165 case mouseDown:
12166 case mouseUp:
12167 {
3354caee 12168 WindowRef window_ptr;
e6bdfa32 12169 ControlPartCode part_code;
50bf7673
ST
12170 int tool_bar_p = 0;
12171
3354caee 12172#if TARGET_API_MAC_CARBON
7adf3143
YM
12173 OSStatus err;
12174
59feca74
ST
12175 /* This is needed to send mouse events like aqua window
12176 buttons to the correct handler. */
7adf3143
YM
12177 read_socket_inev = &inev;
12178 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12179 read_socket_inev = NULL;
12180 if (err != eventNotHandledErr)
59feca74
ST
12181 break;
12182#endif
05f7d868 12183 last_mouse_glyph_frame = 0;
59feca74 12184
50bf7673
ST
12185 if (dpyinfo->grabbed && last_mouse_frame
12186 && FRAME_LIVE_P (last_mouse_frame))
12187 {
12188 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
12189 part_code = inContent;
12190 }
12191 else
12192 {
bf06c82f 12193 part_code = FindWindow (er.where, &window_ptr);
50bf7673
ST
12194 if (tip_window && window_ptr == tip_window)
12195 {
12196 HideWindow (tip_window);
bf06c82f 12197 part_code = FindWindow (er.where, &window_ptr);
50bf7673 12198 }
50bf7673
ST
12199 }
12200
0e41b66d
YM
12201 if (er.what != mouseDown &&
12202 (part_code != inContent || dpyinfo->grabbed == 0))
bf06c82f
ST
12203 break;
12204
50bf7673
ST
12205 switch (part_code)
12206 {
12207 case inMenuBar:
7ca7ccd5 12208 f = mac_focus_frame (dpyinfo);
bf06c82f
ST
12209 saved_menu_event_location = er.where;
12210 inev.kind = MENU_BAR_ACTIVATE_EVENT;
12211 XSETFRAME (inev.frame_or_window, f);
50bf7673 12212 break;
742fbed7 12213
50bf7673 12214 case inContent:
4cb62a90
YM
12215 if (
12216#if TARGET_API_MAC_CARBON
12217 FrontNonFloatingWindow ()
12218#else
12219 FrontWindow ()
12220#endif
0d36bf23
YM
12221 != window_ptr
12222 || (mac_window_to_frame (window_ptr)
12223 != dpyinfo->x_focus_frame))
50bf7673
ST
12224 SelectWindow (window_ptr);
12225 else
12226 {
e6bdfa32 12227 ControlPartCode control_part_code;
3354caee 12228 ControlRef ch;
7adf3143 12229 Point mouse_loc;
5b8b73ff
YM
12230#ifdef MAC_OSX
12231 ControlKind control_kind;
12232#endif
177c0ea7 12233
50bf7673
ST
12234 f = mac_window_to_frame (window_ptr);
12235 /* convert to local coordinates of new window */
7adf3143
YM
12236 mouse_loc.h = (er.where.h
12237 - (f->left_pos
12238 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12239 mouse_loc.v = (er.where.v
12240 - (f->top_pos
12241 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
e0f712ba 12242#if TARGET_API_MAC_CARBON
50bf7673
ST
12243 ch = FindControlUnderMouse (mouse_loc, window_ptr,
12244 &control_part_code);
5b8b73ff
YM
12245#ifdef MAC_OSX
12246 if (ch)
12247 GetControlKind (ch, &control_kind);
12248#endif
e0f712ba 12249#else
50bf7673
ST
12250 control_part_code = FindControl (mouse_loc, window_ptr,
12251 &ch);
e0f712ba
AC
12252#endif
12253
3354caee 12254#if TARGET_API_MAC_CARBON
50bf7673
ST
12255 inev.code = mac_get_mouse_btn (eventRef);
12256 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
742fbed7 12257#else
50bf7673
ST
12258 inev.code = mac_get_emulated_btn (er.modifiers);
12259 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
742fbed7 12260#endif
50bf7673
ST
12261 XSETINT (inev.x, mouse_loc.h);
12262 XSETINT (inev.y, mouse_loc.v);
50bf7673 12263
f93e4d4f
YM
12264 if ((dpyinfo->grabbed && tracked_scroll_bar)
12265 || (ch != 0
5b8b73ff 12266#ifndef USE_TOOLKIT_SCROLL_BARS
f93e4d4f
YM
12267 /* control_part_code becomes kControlNoPart if
12268 a progress indicator is clicked. */
12269 && control_part_code != kControlNoPart
5b8b73ff
YM
12270#else /* USE_TOOLKIT_SCROLL_BARS */
12271#ifdef MAC_OSX
f93e4d4f 12272 && control_kind.kind == kControlKindScrollBar
5b8b73ff
YM
12273#endif /* MAC_OSX */
12274#endif /* USE_TOOLKIT_SCROLL_BARS */
f93e4d4f 12275 ))
50bf7673
ST
12276 {
12277 struct scroll_bar *bar;
12278
12279 if (dpyinfo->grabbed && tracked_scroll_bar)
12280 {
12281 bar = tracked_scroll_bar;
5b8b73ff 12282#ifndef USE_TOOLKIT_SCROLL_BARS
50bf7673 12283 control_part_code = kControlIndicatorPart;
5b8b73ff 12284#endif
50bf7673
ST
12285 }
12286 else
12287 bar = (struct scroll_bar *) GetControlReference (ch);
5b8b73ff
YM
12288#ifdef USE_TOOLKIT_SCROLL_BARS
12289 /* Make the "Ctrl-Mouse-2 splits window" work
12290 for toolkit scroll bars. */
e6509087 12291 if (inev.modifiers & ctrl_modifier)
5b8b73ff
YM
12292 x_scroll_bar_handle_click (bar, control_part_code,
12293 &er, &inev);
12294 else if (er.what == mouseDown)
12295 x_scroll_bar_handle_press (bar, control_part_code,
e6509087 12296 mouse_loc, &inev);
5b8b73ff 12297 else
95dfb192 12298 x_scroll_bar_handle_release (bar, &inev);
5b8b73ff 12299#else /* not USE_TOOLKIT_SCROLL_BARS */
50bf7673
ST
12300 x_scroll_bar_handle_click (bar, control_part_code,
12301 &er, &inev);
12302 if (er.what == mouseDown
12303 && control_part_code == kControlIndicatorPart)
12304 tracked_scroll_bar = bar;
12305 else
12306 tracked_scroll_bar = NULL;
5b8b73ff 12307#endif /* not USE_TOOLKIT_SCROLL_BARS */
50bf7673
ST
12308 }
12309 else
12310 {
12311 Lisp_Object window;
12312 int x = mouse_loc.h;
12313 int y = mouse_loc.v;
12314
12315 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
12316 if (EQ (window, f->tool_bar_window))
12317 {
12318 if (er.what == mouseDown)
12319 handle_tool_bar_click (f, x, y, 1, 0);
12320 else
12321 handle_tool_bar_click (f, x, y, 0,
12322 inev.modifiers);
12323 tool_bar_p = 1;
12324 }
12325 else
12326 {
12327 XSETFRAME (inev.frame_or_window, f);
12328 inev.kind = MOUSE_CLICK_EVENT;
12329 }
12330 }
12331
12332 if (er.what == mouseDown)
12333 {
12334 dpyinfo->grabbed |= (1 << inev.code);
12335 last_mouse_frame = f;
50bf7673
ST
12336
12337 if (!tool_bar_p)
12338 last_tool_bar_item = -1;
12339 }
12340 else
12341 {
bf06c82f 12342 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
50bf7673
ST
12343 /* If a button is released though it was not
12344 previously pressed, that would be because
12345 of multi-button emulation. */
12346 dpyinfo->grabbed = 0;
12347 else
12348 dpyinfo->grabbed &= ~(1 << inev.code);
12349 }
12350
0e41b66d
YM
12351 /* Ignore any mouse motion that happened before
12352 this event; any subsequent mouse-movement Emacs
12353 events should reflect only motion after the
12354 ButtonPress. */
12355 if (f != 0)
12356 f->mouse_moved = 0;
12357
5b8b73ff 12358#ifdef USE_TOOLKIT_SCROLL_BARS
e6509087
YM
12359 if (inev.kind == MOUSE_CLICK_EVENT
12360 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12361 && (inev.modifiers & ctrl_modifier)))
5b8b73ff
YM
12362#endif
12363 switch (er.what)
12364 {
12365 case mouseDown:
12366 inev.modifiers |= down_modifier;
12367 break;
12368 case mouseUp:
12369 inev.modifiers |= up_modifier;
12370 break;
12371 }
50bf7673
ST
12372 }
12373 break;
1a578e9b 12374
50bf7673
ST
12375 case inDrag:
12376#if TARGET_API_MAC_CARBON
a733ef16 12377 case inProxyIcon:
458dbb8c
YM
12378 if (IsWindowPathSelectClick (window_ptr, &er))
12379 {
12380 WindowPathSelect (window_ptr, NULL, NULL);
12381 break;
12382 }
a733ef16
YM
12383 if (part_code == inProxyIcon
12384 && (TrackWindowProxyDrag (window_ptr, er.where)
12385 != errUserWantsToDragWindow))
12386 break;
bf06c82f 12387 DragWindow (window_ptr, er.where, NULL);
50bf7673
ST
12388#else /* not TARGET_API_MAC_CARBON */
12389 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
e439b925
ST
12390 /* Update the frame parameters. */
12391 {
12392 struct frame *f = mac_window_to_frame (window_ptr);
bf06c82f 12393
e439b925 12394 if (f && !f->async_iconified)
bed0bf95 12395 mac_handle_origin_change (f);
e439b925 12396 }
3354caee 12397#endif /* not TARGET_API_MAC_CARBON */
50bf7673 12398 break;
177c0ea7 12399
50bf7673
ST
12400 case inGoAway:
12401 if (TrackGoAway (window_ptr, er.where))
12402 {
12403 inev.kind = DELETE_WINDOW_EVENT;
12404 XSETFRAME (inev.frame_or_window,
12405 mac_window_to_frame (window_ptr));
12406 }
12407 break;
1a578e9b 12408
50bf7673
ST
12409 /* window resize handling added --ben */
12410 case inGrow:
bf06c82f
ST
12411 do_grow_window (window_ptr, &er);
12412 break;
e0f712ba 12413
50bf7673
ST
12414 /* window zoom handling added --ben */
12415 case inZoomIn:
12416 case inZoomOut:
12417 if (TrackBox (window_ptr, er.where, part_code))
12418 do_zoom_window (window_ptr, part_code);
12419 break;
742fbed7 12420
c6829f81
YM
12421#if USE_MAC_TOOLBAR
12422 case inStructure:
12423 {
12424 OSStatus err;
12425 HIViewRef ch;
12426
12427 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12428 eventRef, &ch);
12429 /* This doesn't work on Mac OS X 10.2. */
12430 if (err == noErr)
12431 HIViewClick (ch, eventRef);
12432 }
12433 break;
12434#endif /* USE_MAC_TOOLBAR */
12435
50bf7673
ST
12436 default:
12437 break;
12438 }
12439 }
12440 break;
e0f712ba 12441
7adf3143 12442#if !TARGET_API_MAC_CARBON
50bf7673 12443 case updateEvt:
3354caee 12444 do_window_update ((WindowRef) er.message);
50bf7673 12445 break;
7adf3143 12446#endif
177c0ea7 12447
50bf7673 12448 case osEvt:
50bf7673
ST
12449 switch ((er.message >> 24) & 0x000000FF)
12450 {
50bf7673 12451 case mouseMovedMessage:
3354caee 12452#if !TARGET_API_MAC_CARBON
b15325b2
ST
12453 SetRectRgn (mouse_region, er.where.h, er.where.v,
12454 er.where.h + 1, er.where.v + 1);
12455#endif
50bf7673 12456 previous_help_echo_string = help_echo_string;
af1229d9 12457 help_echo_string = Qnil;
1a578e9b 12458
7ca7ccd5
YM
12459 if (dpyinfo->grabbed && last_mouse_frame
12460 && FRAME_LIVE_P (last_mouse_frame))
12461 f = last_mouse_frame;
12462 else
12463 f = dpyinfo->x_focus_frame;
12464
12465 if (dpyinfo->mouse_face_hidden)
12466 {
12467 dpyinfo->mouse_face_hidden = 0;
12468 clear_mouse_face (dpyinfo);
12469 }
12470
12471 if (f)
12472 {
3354caee 12473 WindowRef wp = FRAME_MAC_WINDOW (f);
7adf3143
YM
12474 Point mouse_pos;
12475
12476 mouse_pos.h = (er.where.h
12477 - (f->left_pos
12478 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12479 mouse_pos.v = (er.where.v
12480 - (f->top_pos
12481 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
7ca7ccd5 12482 if (dpyinfo->grabbed && tracked_scroll_bar)
5b8b73ff
YM
12483#ifdef USE_TOOLKIT_SCROLL_BARS
12484 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
95dfb192 12485 mouse_pos, &inev);
5b8b73ff 12486#else /* not USE_TOOLKIT_SCROLL_BARS */
7ca7ccd5
YM
12487 x_scroll_bar_note_movement (tracked_scroll_bar,
12488 mouse_pos.v
12489 - XINT (tracked_scroll_bar->top),
5b8b73ff
YM
12490 er.when * (1000 / 60));
12491#endif /* not USE_TOOLKIT_SCROLL_BARS */
7ca7ccd5
YM
12492 else
12493 {
12494 /* Generate SELECT_WINDOW_EVENTs when needed. */
92b23323 12495 if (!NILP (Vmouse_autoselect_window))
7ca7ccd5
YM
12496 {
12497 Lisp_Object window;
12498
12499 window = window_from_coordinates (f,
12500 mouse_pos.h,
12501 mouse_pos.v,
12502 0, 0, 0, 0);
12503
12504 /* Window will be selected only when it is
12505 not selected now and last mouse movement
12506 event was not in it. Minibuffer window
e0f24100 12507 will be selected only when it is active. */
7ca7ccd5
YM
12508 if (WINDOWP (window)
12509 && !EQ (window, last_window)
b0c6cec4
MR
12510 && !EQ (window, selected_window)
12511 /* For click-to-focus window managers
12512 create event iff we don't leave the
12513 selected frame. */
12514 && (focus_follows_mouse
12515 || (EQ (XWINDOW (window)->frame,
12516 XWINDOW (selected_window)->frame))))
7ca7ccd5
YM
12517 {
12518 inev.kind = SELECT_WINDOW_EVENT;
12519 inev.frame_or_window = window;
12520 }
12521
12522 last_window=window;
12523 }
af1229d9
YM
12524 if (!note_mouse_movement (f, &mouse_pos))
12525 help_echo_string = previous_help_echo_string;
c6829f81
YM
12526#if USE_MAC_TOOLBAR
12527 else
12528 mac_tool_bar_note_mouse_movement (f, eventRef);
12529#endif
7ca7ccd5
YM
12530 }
12531 }
1a578e9b 12532
50bf7673
ST
12533 /* If the contents of the global variable
12534 help_echo_string has changed, generate a
12535 HELP_EVENT. */
12536 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12537 do_help = 1;
1a578e9b 12538 break;
7adf3143
YM
12539
12540 default:
12541 goto OTHER;
1a578e9b 12542 }
50bf7673
ST
12543 break;
12544
12545 case activateEvt:
12546 {
3354caee 12547 WindowRef window_ptr = (WindowRef) er.message;
7b7d07bb
YM
12548 OSErr err;
12549 ControlRef root_control;
177c0ea7 12550
50bf7673
ST
12551 if (window_ptr == tip_window)
12552 {
12553 HideWindow (tip_window);
12554 break;
12555 }
177c0ea7 12556
59feca74 12557 if (!is_emacs_window (window_ptr))
7adf3143
YM
12558 goto OTHER;
12559
12560 f = mac_window_to_frame (window_ptr);
f94a2622 12561
50bf7673
ST
12562 if ((er.modifiers & activeFlag) != 0)
12563 {
59feca74 12564 /* A window has been activated */
7adf3143 12565 Point mouse_loc;
177c0ea7 12566
7b7d07bb
YM
12567 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12568 if (err == noErr)
12569 ActivateControl (root_control);
12570
7ca7ccd5 12571 x_detect_focus_change (dpyinfo, &er, &inev);
177c0ea7 12572
7adf3143
YM
12573 mouse_loc.h = (er.where.h
12574 - (f->left_pos
12575 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12576 mouse_loc.v = (er.where.v
12577 - (f->top_pos
12578 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
59feca74 12579 /* Window-activated event counts as mouse movement,
50bf7673 12580 so update things that depend on mouse position. */
7adf3143 12581 note_mouse_movement (f, &mouse_loc);
50bf7673
ST
12582 }
12583 else
12584 {
59feca74 12585 /* A window has been deactivated */
7b7d07bb
YM
12586 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12587 if (err == noErr)
12588 DeactivateControl (root_control);
12589
70385fe6 12590#ifdef USE_TOOLKIT_SCROLL_BARS
5b8b73ff
YM
12591 if (dpyinfo->grabbed && tracked_scroll_bar)
12592 {
12593 struct input_event event;
12594
12595 EVENT_INIT (event);
12596 event.kind = NO_EVENT;
95dfb192 12597 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
5b8b73ff
YM
12598 if (event.kind != NO_EVENT)
12599 {
95dfb192 12600 event.timestamp = timestamp;
5b8b73ff
YM
12601 kbd_buffer_store_event_hold (&event, hold_quit);
12602 count++;
12603 }
12604 }
12605#endif
59feca74
ST
12606 dpyinfo->grabbed = 0;
12607
7ca7ccd5 12608 x_detect_focus_change (dpyinfo, &er, &inev);
177c0ea7 12609
50bf7673
ST
12610 if (f == dpyinfo->mouse_face_mouse_frame)
12611 {
12612 /* If we move outside the frame, then we're
12613 certainly no longer on any text in the
12614 frame. */
12615 clear_mouse_face (dpyinfo);
12616 dpyinfo->mouse_face_mouse_frame = 0;
12617 }
177c0ea7 12618
50bf7673
ST
12619 /* Generate a nil HELP_EVENT to cancel a help-echo.
12620 Do it only if there's something to cancel.
12621 Otherwise, the startup message is cleared when the
12622 mouse leaves the frame. */
12623 if (any_help_event_p)
12624 do_help = -1;
12625 }
12626 }
12627 break;
177c0ea7 12628
50bf7673 12629 case keyDown:
2abb0fde 12630 case keyUp:
50bf7673 12631 case autoKey:
7adf3143 12632 ObscureCursor ();
b8c6940e 12633
7adf3143
YM
12634 f = mac_focus_frame (dpyinfo);
12635 XSETFRAME (inev.frame_or_window, f);
b8c6940e 12636
7adf3143
YM
12637 /* If mouse-highlight is an integer, input clears out mouse
12638 highlighting. */
12639 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12640 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12641 {
12642 clear_mouse_face (dpyinfo);
12643 dpyinfo->mouse_face_hidden = 1;
12644 }
7b7d07bb
YM
12645
12646 {
12647 UInt32 modifiers = er.modifiers, mapped_modifiers;
12648
12649#ifdef MAC_OSX
12650 GetEventParameter (eventRef, kEventParamKeyModifiers,
12651 typeUInt32, NULL,
12652 sizeof (UInt32), NULL, &modifiers);
12653#endif
12654 mapped_modifiers = mac_mapped_modifiers (modifiers);
12655
b8c6940e 12656#if TARGET_API_MAC_CARBON
7b7d07bb
YM
12657 if (!(mapped_modifiers
12658 & ~(mac_pass_command_to_system ? cmdKey : 0)
12659 & ~(mac_pass_control_to_system ? controlKey : 0)))
12660 goto OTHER;
12661 else
742fbed7 12662#endif
7b7d07bb
YM
12663 if (er.what != keyUp)
12664 do_keystroke (er.what, er.message & charCodeMask,
12665 (er.message & keyCodeMask) >> 8,
12666 modifiers, timestamp, &inev);
12667 }
50bf7673 12668 break;
177c0ea7 12669
50bf7673 12670 case kHighLevelEvent:
95dfb192 12671 AEProcessAppleEvent (&er);
95dfb192 12672 break;
177c0ea7 12673
50bf7673 12674 default:
7adf3143
YM
12675 OTHER:
12676#if TARGET_API_MAC_CARBON
12677 {
12678 OSStatus err;
12679
12680 read_socket_inev = &inev;
12681 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12682 read_socket_inev = NULL;
12683 }
12684#endif
50bf7673
ST
12685 break;
12686 }
3354caee 12687#if TARGET_API_MAC_CARBON
742fbed7 12688 ReleaseEvent (eventRef);
742fbed7 12689#endif
1a578e9b 12690
50bf7673
ST
12691 if (inev.kind != NO_EVENT)
12692 {
95dfb192 12693 inev.timestamp = timestamp;
50bf7673
ST
12694 kbd_buffer_store_event_hold (&inev, hold_quit);
12695 count++;
12696 }
12697
12698 if (do_help
12699 && !(hold_quit && hold_quit->kind != NO_EVENT))
12700 {
12701 Lisp_Object frame;
12702
12703 if (f)
12704 XSETFRAME (frame, f);
12705 else
12706 frame = Qnil;
12707
12708 if (do_help > 0)
12709 {
12710 any_help_event_p = 1;
12711 gen_help_event (help_echo_string, frame, help_echo_window,
12712 help_echo_object, help_echo_pos);
12713 }
12714 else
12715 {
12716 help_echo_string = Qnil;
12717 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12718 }
12719 count++;
12720 }
50bf7673
ST
12721 }
12722
1a578e9b
AC
12723 /* If the focus was just given to an autoraising frame,
12724 raise it now. */
12725 /* ??? This ought to be able to handle more than one such frame. */
12726 if (pending_autoraise_frame)
12727 {
12728 x_raise_frame (pending_autoraise_frame);
12729 pending_autoraise_frame = 0;
12730 }
12731
19ee09cc
YM
12732 if (mac_screen_config_changed)
12733 {
12734 mac_get_screen_info (dpyinfo);
12735 mac_screen_config_changed = 0;
12736 }
12737
3354caee 12738#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
12739 /* Check which frames are still visible. We do this here because
12740 there doesn't seem to be any direct notification from the Window
12741 Manager that the visibility of a window has changed (at least,
12742 not in all cases). */
12743 {
12744 Lisp_Object tail, frame;
12745
12746 FOR_EACH_FRAME (tail, frame)
12747 {
12748 struct frame *f = XFRAME (frame);
12749
12750 /* The tooltip has been drawn already. Avoid the
12751 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12752 if (EQ (frame, tip_frame))
12753 continue;
12754
12755 if (FRAME_MAC_P (f))
12756 mac_handle_visibility_change (f);
12757 }
12758 }
12759#endif
12760
b465419f 12761 --handling_signal;
6b61353c 12762 UNBLOCK_INPUT;
1a578e9b
AC
12763 return count;
12764}
12765
12766
12767/* Need to override CodeWarrior's input function so no conversion is
12768 done on newlines Otherwise compiled functions in .elc files will be
12769 read incorrectly. Defined in ...:MSL C:MSL
12770 Common:Source:buffer_io.c. */
12771#ifdef __MWERKS__
12772void
12773__convert_to_newlines (unsigned char * p, size_t * n)
12774{
12775#pragma unused(p,n)
12776}
12777
12778void
12779__convert_from_newlines (unsigned char * p, size_t * n)
12780{
12781#pragma unused(p,n)
12782}
12783#endif
12784
b15325b2 12785#ifdef MAC_OS8
770136ad 12786void
50bf7673 12787make_mac_terminal_frame (struct frame *f)
1a578e9b 12788{
50bf7673 12789 Lisp_Object frame;
b15325b2 12790 Rect r;
177c0ea7 12791
50bf7673
ST
12792 XSETFRAME (frame, f);
12793
12794 f->output_method = output_mac;
12795 f->output_data.mac = (struct mac_output *)
12796 xmalloc (sizeof (struct mac_output));
12797 bzero (f->output_data.mac, sizeof (struct mac_output));
12798
12799 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
177c0ea7 12800
50bf7673
ST
12801 FRAME_COLS (f) = 96;
12802 FRAME_LINES (f) = 4;
12803
12804 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12805 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12806
12807 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
1a578e9b
AC
12808
12809 f->output_data.mac->cursor_pixel = 0;
12810 f->output_data.mac->border_pixel = 0x00ff00;
12811 f->output_data.mac->mouse_pixel = 0xff00ff;
12812 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12813
25c9622b
YM
12814 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12815 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12816 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12817 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12818 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12819 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
b15325b2 12820
f1a83aab 12821 FRAME_FONTSET (f) = -1;
1a578e9b 12822 f->output_data.mac->explicit_parent = 0;
b15325b2
ST
12823 f->left_pos = 8;
12824 f->top_pos = 32;
f1a83aab 12825 f->border_width = 0;
177c0ea7 12826
f1a83aab 12827 f->internal_border_width = 0;
1a578e9b 12828
1a578e9b
AC
12829 f->auto_raise = 1;
12830 f->auto_lower = 1;
177c0ea7 12831
f1a83aab
KS
12832 f->new_text_cols = 0;
12833 f->new_text_lines = 0;
6b61353c 12834
b15325b2
ST
12835 SetRect (&r, f->left_pos, f->top_pos,
12836 f->left_pos + FRAME_PIXEL_WIDTH (f),
12837 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12838
12839 BLOCK_INPUT;
12840
12841 if (!(FRAME_MAC_WINDOW (f) =
12842 NewCWindow (NULL, &r, "\p", true, dBoxProc,
3354caee 12843 (WindowRef) -1, 1, (long) f->output_data.mac)))
b15325b2
ST
12844 abort ();
12845 /* so that update events can find this mac_output struct */
12846 f->output_data.mac->mFP = f; /* point back to emacs frame */
12847
12848 UNBLOCK_INPUT;
e0f712ba
AC
12849
12850 x_make_gc (f);
177c0ea7 12851
e0f712ba
AC
12852 /* Need to be initialized for unshow_buffer in window.c. */
12853 selected_window = f->selected_window;
12854
1a578e9b
AC
12855 Fmodify_frame_parameters (frame,
12856 Fcons (Fcons (Qfont,
12857 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12858 Fmodify_frame_parameters (frame,
12859 Fcons (Fcons (Qforeground_color,
12860 build_string ("black")), Qnil));
12861 Fmodify_frame_parameters (frame,
12862 Fcons (Fcons (Qbackground_color,
12863 build_string ("white")), Qnil));
12864}
b15325b2 12865#endif
1a578e9b 12866
e0f712ba
AC
12867\f
12868/***********************************************************************
12869 Initialization
12870 ***********************************************************************/
12871
19ee09cc 12872static int mac_initialized = 0;
b15325b2 12873
b298e813 12874static XrmDatabase
b15325b2 12875mac_make_rdb (xrm_option)
369a7a37 12876 const char *xrm_option;
b15325b2 12877{
b298e813 12878 XrmDatabase database;
b15325b2 12879
b298e813
YM
12880 database = xrm_get_preference_database (NULL);
12881 if (xrm_option)
12882 xrm_merge_string_database (database, xrm_option);
b15325b2 12883
b298e813 12884 return database;
b15325b2
ST
12885}
12886
e0f712ba
AC
12887struct mac_display_info *
12888mac_term_init (display_name, xrm_option, resource_name)
12889 Lisp_Object display_name;
12890 char *xrm_option;
12891 char *resource_name;
12892{
12893 struct mac_display_info *dpyinfo;
80ca7302 12894 struct terminal *terminal;
b15325b2
ST
12895
12896 BLOCK_INPUT;
e0f712ba
AC
12897
12898 if (!mac_initialized)
12899 {
12900 mac_initialize ();
12901 mac_initialized = 1;
12902 }
12903
b15325b2
ST
12904 if (x_display_list)
12905 error ("Sorry, this version can only handle one display");
12906
e0f712ba 12907 dpyinfo = &one_mac_display_info;
19ee09cc
YM
12908 bzero (dpyinfo, sizeof (*dpyinfo));
12909
80ca7302
DN
12910 terminal = mac_create_terminal (dpyinfo);
12911
12912 /* Set the name of the terminal. */
12913 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12914 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12915 terminal->name[SBYTES (display_name)] = 0;
12916
19ee09cc
YM
12917#ifdef MAC_OSX
12918 dpyinfo->mac_id_name
12919 = (char *) xmalloc (SCHARS (Vinvocation_name)
12920 + SCHARS (Vsystem_name)
12921 + 2);
12922 sprintf (dpyinfo->mac_id_name, "%s@%s",
12923 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12924#else
12925 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12926 strcpy (dpyinfo->mac_id_name, "Mac Display");
12927#endif
12928
12929 dpyinfo->reference_count = 0;
12930 dpyinfo->resx = 72.0;
12931 dpyinfo->resy = 72.0;
12932
12933 mac_get_screen_info (dpyinfo);
12934
12935 dpyinfo->grabbed = 0;
12936 dpyinfo->root_window = NULL;
354884c4 12937 dpyinfo->terminal->image_cache = make_image_cache ();
19ee09cc
YM
12938
12939 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12940 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12941 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12942 dpyinfo->mouse_face_window = Qnil;
12943 dpyinfo->mouse_face_overlay = Qnil;
12944 dpyinfo->mouse_face_hidden = 0;
e0f712ba 12945
b298e813 12946 dpyinfo->xrdb = mac_make_rdb (xrm_option);
e0f712ba 12947
b15325b2
ST
12948 /* Put this display on the chain. */
12949 dpyinfo->next = x_display_list;
12950 x_display_list = dpyinfo;
12951
12952 /* Put it on x_display_name_list. */
b298e813
YM
12953 x_display_name_list = Fcons (Fcons (display_name,
12954 Fcons (Qnil, dpyinfo->xrdb)),
b15325b2
ST
12955 x_display_name_list);
12956 dpyinfo->name_list_element = XCAR (x_display_name_list);
12957
b951420f
DN
12958 /* FIXME: Untested.
12959 Add the default keyboard. */
12960 add_keyboard_wait_descriptor (0);
12961
9c7c716d
JR
12962#if USE_CG_DRAWING
12963 mac_init_fringe (terminal->rif);
12964#endif
12965
b15325b2 12966 UNBLOCK_INPUT;
1a578e9b 12967
e0f712ba 12968 return dpyinfo;
1a578e9b 12969}
19ee09cc 12970\f
b15325b2
ST
12971/* Get rid of display DPYINFO, assuming all frames are already gone. */
12972
12973void
12974x_delete_display (dpyinfo)
12975 struct mac_display_info *dpyinfo;
12976{
12977 int i;
12978
12979 /* Discard this display from x_display_name_list and x_display_list.
12980 We can't use Fdelq because that can quit. */
12981 if (! NILP (x_display_name_list)
12982 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12983 x_display_name_list = XCDR (x_display_name_list);
12984 else
12985 {
12986 Lisp_Object tail;
12987
12988 tail = x_display_name_list;
12989 while (CONSP (tail) && CONSP (XCDR (tail)))
12990 {
12991 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
12992 {
12993 XSETCDR (tail, XCDR (XCDR (tail)));
12994 break;
12995 }
12996 tail = XCDR (tail);
12997 }
12998 }
12999
13000 if (x_display_list == dpyinfo)
13001 x_display_list = dpyinfo->next;
13002 else
13003 {
13004 struct x_display_info *tail;
13005
13006 for (tail = x_display_list; tail; tail = tail->next)
13007 if (tail->next == dpyinfo)
13008 tail->next = tail->next->next;
13009 }
13010
13011 /* Free the font names in the font table. */
13012 for (i = 0; i < dpyinfo->n_fonts; i++)
13013 if (dpyinfo->font_table[i].name)
13014 {
13015 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
13016 xfree (dpyinfo->font_table[i].full_name);
13017 xfree (dpyinfo->font_table[i].name);
13018 }
13019
1e53bd0e
YM
13020 if (dpyinfo->font_table)
13021 {
70fdbb46 13022 xfree (dpyinfo->font_table->font_encoder);
1e53bd0e
YM
13023 xfree (dpyinfo->font_table);
13024 }
70fdbb46 13025 xfree (dpyinfo->mac_id_name);
b15325b2
ST
13026
13027 if (x_display_list == 0)
13028 {
13029 mac_clear_font_name_table ();
13030 bzero (dpyinfo, sizeof (*dpyinfo));
13031 }
13032}
13033
e0f712ba 13034\f
1c05c15b
YM
13035static void
13036init_menu_bar ()
13037{
13038#ifdef MAC_OSX
3e7424f7 13039 OSStatus err;
1c05c15b
YM
13040 MenuRef menu;
13041 MenuItemIndex menu_index;
13042
13043 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
13044 &menu, &menu_index);
13045 if (err == noErr)
13046 SetMenuItemCommandKey (menu, menu_index, false, 0);
1c05c15b
YM
13047 EnableMenuCommand (NULL, kHICommandPreferences);
13048 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
13049 &menu, &menu_index);
13050 if (err == noErr)
13051 {
13052 SetMenuItemCommandKey (menu, menu_index, false, 0);
13053 InsertMenuItemTextWithCFString (menu, NULL,
13054 0, kMenuItemAttrSeparator, 0);
13055 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
13056 0, 0, kHICommandAbout);
13057 }
1c05c15b 13058#else /* !MAC_OSX */
3354caee
YM
13059#if TARGET_API_MAC_CARBON
13060 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
1c05c15b
YM
13061#endif
13062#endif
13063}
13064
02236cbc
YM
13065#if USE_MAC_TSM
13066static void
13067init_tsm ()
13068{
92289429 13069#ifdef MAC_OSX
02236cbc 13070 static InterfaceTypeList types = {kUnicodeDocument};
92289429
YM
13071#else
13072 static InterfaceTypeList types = {kTextService};
13073#endif
02236cbc
YM
13074
13075 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
13076 &tsm_document_id, 0);
13077}
13078#endif
1c05c15b 13079
e0f712ba
AC
13080/* Set up use of X before we make the first connection. */
13081
88cd462d
KS
13082extern frame_parm_handler mac_frame_parm_handlers[];
13083
e0f712ba
AC
13084static struct redisplay_interface x_redisplay_interface =
13085{
88cd462d 13086 mac_frame_parm_handlers,
e0f712ba
AC
13087 x_produce_glyphs,
13088 x_write_glyphs,
13089 x_insert_glyphs,
13090 x_clear_end_of_line,
13091 x_scroll_run,
13092 x_after_update_window_line,
13093 x_update_window_begin,
13094 x_update_window_end,
f9e65eb3
KS
13095 x_cursor_to,
13096 x_flush,
e6509087
YM
13097#if USE_CG_DRAWING
13098 mac_flush_display_optional,
13099#else
fc7a70cc 13100 0, /* flush_display_optional */
e6509087 13101#endif
f9e65eb3 13102 x_clear_window_mouse_face,
e0f712ba 13103 x_get_glyph_overhangs,
5958f265 13104 x_fix_overlapping_area,
750fc673 13105 x_draw_fringe_bitmap,
ad21830e
YM
13106#if USE_CG_DRAWING
13107 mac_define_fringe_bitmap,
13108 mac_destroy_fringe_bitmap,
13109#else
6b61353c
KH
13110 0, /* define_fringe_bitmap */
13111 0, /* destroy_fringe_bitmap */
ad21830e 13112#endif
750fc673
KS
13113 mac_per_char_metric,
13114 mac_encode_char,
8c2da0fa 13115 mac_compute_glyph_string_overhangs,
f9e65eb3
KS
13116 x_draw_glyph_string,
13117 mac_define_frame_cursor,
13118 mac_clear_frame_area,
13119 mac_draw_window_cursor,
efcf4234 13120 mac_draw_vertical_window_border,
f9e65eb3 13121 mac_shift_glyphs_for_insert
e0f712ba 13122};
1a578e9b 13123
80ca7302
DN
13124static struct terminal *
13125mac_create_terminal (struct mac_display_info *dpyinfo)
13126{
13127 struct terminal *terminal;
13128
13129 terminal = create_terminal ();
13130
13131 terminal->type = output_mac;
13132 terminal->display_info.mac = dpyinfo;
13133 dpyinfo->terminal = terminal;
13134
80ca7302
DN
13135 terminal->clear_frame_hook = x_clear_frame;
13136 terminal->ins_del_lines_hook = x_ins_del_lines;
13137 terminal->delete_glyphs_hook = x_delete_glyphs;
13138 terminal->ring_bell_hook = XTring_bell;
13139 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
13140 terminal->set_terminal_modes_hook = XTset_terminal_modes;
13141 terminal->update_begin_hook = x_update_begin;
13142 terminal->update_end_hook = x_update_end;
13143 terminal->set_terminal_window_hook = XTset_terminal_window;
13144 terminal->read_socket_hook = XTread_socket;
13145 terminal->frame_up_to_date_hook = XTframe_up_to_date;
13146 terminal->mouse_position_hook = XTmouse_position;
13147 terminal->frame_rehighlight_hook = XTframe_rehighlight;
13148 terminal->frame_raise_lower_hook = XTframe_raise_lower;
88acaaf2
DN
13149 /* terminal->fullscreen_hook = XTfullscreen_hook; */
13150 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13151 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13152 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
13153 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
13154 terminal->delete_frame_hook = x_destroy_window;
13155 /* terminal->delete_terminal_hook = x_delete_terminal; */
80ca7302 13156
88acaaf2 13157 terminal->rif = &x_redisplay_interface;
80ca7302 13158#if 0
28d440ab
KL
13159 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
13160 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
13161 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
13162 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
13163 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
8a56675d
KL
13164 scrolls off the
13165 bottom */
80ca7302
DN
13166#else
13167 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
13168 terminal->char_ins_del_ok = 1;
13169 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
13170 terminal->fast_clear_end_of_line = 1; /* X does this well. */
13171 terminal->memory_below_frame = 0; /* We don't remember what scrolls
13172 off the bottom. */
13173
70b8d0a4
SM
13174#endif
13175
13176 /* FIXME: This keyboard setup is 100% untested, just copied from
13177 w32_create_terminal in order to set window-system now that it's
13178 a keyboard object. */
70b8d0a4
SM
13179 /* We don't yet support separate terminals on Mac, so don't try to share
13180 keyboards between virtual terminals that are on the same physical
13181 terminal like X does. */
13182 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13183 init_kboard (terminal->kboard);
13184 terminal->kboard->Vwindow_system = intern ("mac");
13185 terminal->kboard->next_kboard = all_kboards;
13186 all_kboards = terminal->kboard;
13187 /* Don't let the initial kboard remain current longer than necessary.
13188 That would cause problems if a file loaded on startup tries to
13189 prompt in the mini-buffer. */
13190 if (current_kboard == initial_kboard)
13191 current_kboard = terminal->kboard;
13192 terminal->kboard->reference_count++;
9c7c716d 13193
80ca7302
DN
13194 return terminal;
13195}
13196
13197static void
e0f712ba 13198mac_initialize ()
1a578e9b 13199{
80ca7302 13200
1a578e9b
AC
13201 baud_rate = 19200;
13202
1a578e9b
AC
13203 last_tool_bar_item = -1;
13204 any_help_event_p = 0;
177c0ea7 13205
1a578e9b 13206 /* Try to use interrupt input; if we can't, then start polling. */
a712a8c3 13207 Fset_input_interrupt_mode (Qt);
1a578e9b 13208
c3f4c690 13209 BLOCK_INPUT;
bc21bf11
AC
13210
13211#if TARGET_API_MAC_CARBON
bc21bf11 13212
7adf3143 13213 install_application_handler ();
1c05c15b
YM
13214
13215 init_menu_bar ();
02236cbc
YM
13216
13217#if USE_MAC_TSM
13218 init_tsm ();
13219#endif
8030369c 13220
25c9622b 13221#ifdef MAC_OSX
0e0a1663
YM
13222 init_coercion_handler ();
13223
6a0b5d37
YM
13224 init_apple_event_handler ();
13225
19ee09cc
YM
13226 init_dm_notification_handler ();
13227
8030369c 13228 if (!inhibit_window_system)
5eafe967
YM
13229 {
13230 static const ProcessSerialNumber psn = {0, kCurrentProcess};
13231
13232 SetFrontProcess (&psn);
13233 }
25c9622b 13234#endif
bc21bf11 13235#endif
ad21830e
YM
13236
13237#if USE_CG_DRAWING
e2d3b7e1 13238 init_cg_color ();
ad21830e
YM
13239#endif
13240
c3f4c690 13241 UNBLOCK_INPUT;
80ca7302 13242
1a578e9b
AC
13243}
13244
13245
13246void
13247syms_of_macterm ()
13248{
13249#if 0
13250 staticpro (&x_error_message_string);
13251 x_error_message_string = Qnil;
13252#endif
13253
f2d8779b
YM
13254 Qcontrol = intern ("control"); staticpro (&Qcontrol);
13255 Qmeta = intern ("meta"); staticpro (&Qmeta);
13256 Qalt = intern ("alt"); staticpro (&Qalt);
13257 Qhyper = intern ("hyper"); staticpro (&Qhyper);
13258 Qsuper = intern ("super"); staticpro (&Qsuper);
a36f1680 13259 Qmodifier_value = intern ("modifier-value");
f2d8779b 13260 staticpro (&Qmodifier_value);
a36f1680 13261
f2d8779b
YM
13262 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
13263 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
13264 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
13265 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
13266 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
1c05c15b 13267
3354caee 13268#if TARGET_API_MAC_CARBON
3e7424f7 13269 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
6a0b5d37 13270#ifdef MAC_OSX
68c767a3
YM
13271 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
13272 staticpro (&Qtoolbar_switch_mode);
13273#if USE_MAC_FONT_PANEL
13274 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
13275 Qselection = intern ("selection"); staticpro (&Qselection);
13276#endif
13277
4cb62a90 13278 Qservice = intern ("service"); staticpro (&Qservice);
1c05c15b
YM
13279 Qpaste = intern ("paste"); staticpro (&Qpaste);
13280 Qperform = intern ("perform"); staticpro (&Qperform);
e1adb139
YM
13281
13282 Qmouse_drag_overlay = intern ("mouse-drag-overlay");
13283 staticpro (&Qmouse_drag_overlay);
1c05c15b 13284#endif
02236cbc
YM
13285#if USE_MAC_TSM
13286 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
13287 Qupdate_active_input_area = intern ("update-active-input-area");
13288 staticpro (&Qupdate_active_input_area);
13289 Qunicode_for_key_event = intern ("unicode-for-key-event");
13290 staticpro (&Qunicode_for_key_event);
13291#endif
6a0b5d37 13292#endif
1c05c15b 13293
b15325b2 13294#ifdef MAC_OSX
8c609cff 13295 Fprovide (intern ("mac-carbon"), Qnil);
b15325b2 13296#endif
8c609cff 13297
6b61353c
KH
13298 staticpro (&Qreverse);
13299 Qreverse = intern ("reverse");
13300
1a578e9b
AC
13301 staticpro (&x_display_name_list);
13302 x_display_name_list = Qnil;
13303
13304 staticpro (&last_mouse_scroll_bar);
13305 last_mouse_scroll_bar = Qnil;
13306
71b7a47f
YM
13307 staticpro (&fm_font_family_alist);
13308 fm_font_family_alist = Qnil;
8f47302e 13309
c3bd8190
YM
13310#if USE_ATSUI
13311 staticpro (&atsu_font_id_hash);
13312 atsu_font_id_hash = Qnil;
92289429
YM
13313
13314 staticpro (&fm_style_face_attributes_alist);
13315 fm_style_face_attributes_alist = Qnil;
13316#endif
13317
13318#if USE_MAC_TSM
13319 staticpro (&saved_ts_script_language_on_focus);
13320 saved_ts_script_language_on_focus = Qnil;
c3bd8190
YM
13321#endif
13322
70ed951a
YM
13323 /* We don't yet support this, but defining this here avoids whining
13324 from cus-start.el and other places, like "M-x set-variable". */
13325 DEFVAR_BOOL ("x-use-underline-position-properties",
13326 &x_use_underline_position_properties,
13327 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
17cf2c3e 13328A value of nil means ignore them. If you encounter fonts with bogus
70ed951a
YM
13329UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
13330to 4.1, set this to nil.
13331
13332NOTE: Not supported on Mac yet. */);
13333 x_use_underline_position_properties = 0;
13334
cf2c6835
YM
13335 DEFVAR_BOOL ("x-underline-at-descent-line",
13336 &x_underline_at_descent_line,
13337 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
17cf2c3e
JB
13338A value of nil means to draw the underline according to the value of the
13339variable `x-use-underline-position-properties', which is usually at the
13340baseline level. The default value is nil. */);
cf2c6835
YM
13341 x_underline_at_descent_line = 0;
13342
e0f712ba 13343 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
68c767a3 13344 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
5b8b73ff 13345#ifdef USE_TOOLKIT_SCROLL_BARS
e0f712ba 13346 Vx_toolkit_scroll_bars = Qt;
5b8b73ff
YM
13347#else
13348 Vx_toolkit_scroll_bars = Qnil;
13349#endif
e0f712ba 13350
1a578e9b
AC
13351 staticpro (&last_mouse_motion_frame);
13352 last_mouse_motion_frame = Qnil;
177c0ea7 13353
b02e3f7b 13354/* Variables to configure modifier key assignment. */
16805b2e 13355
b02e3f7b 13356 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
70ed951a
YM
13357 doc: /* *Modifier key assumed when the Mac control key is pressed.
13358The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13359respective modifier. The default is `control'. */);
13360 Vmac_control_modifier = Qcontrol;
1a578e9b 13361
a36f1680 13362 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
70ed951a
YM
13363 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13364The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13365respective modifier. If the value is nil then the key will act as the
13366normal Mac control modifier, and the option key can be used to compose
13367characters depending on the chosen Mac keyboard setting. */);
a36f1680
JW
13368 Vmac_option_modifier = Qnil;
13369
b02e3f7b 13370 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
70ed951a
YM
13371 doc: /* *Modifier key assumed when the Mac command key is pressed.
13372The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b 13373respective modifier. The default is `meta'. */);
b02e3f7b
ST
13374 Vmac_command_modifier = Qmeta;
13375
13376 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
70ed951a
YM
13377 doc: /* *Modifier key assumed when the Mac function key is pressed.
13378The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13379respective modifier. Note that remapping the function key may lead to
13380unexpected results for some keys on non-US/GB keyboards. */);
b02e3f7b 13381 Vmac_function_modifier = Qnil;
742fbed7 13382
ffe8b3f4 13383 DEFVAR_LISP ("mac-emulate-three-button-mouse",
6b61353c 13384 &Vmac_emulate_three_button_mouse,
70ed951a 13385 doc: /* *Specify a way of three button mouse emulation.
f2d8779b 13386The value can be nil, t, or the symbol `reverse'.
17cf2c3e
JB
13387A value of nil means that no emulation should be done and the modifiers
13388should be placed on the mouse-1 event.
f2d8779b
YM
13389t means that when the option-key is held down while pressing the mouse
13390button, the click will register as mouse-2 and while the command-key
13391is held down, the click will register as mouse-3.
13392The symbol `reverse' means that the option-key will register for
13393mouse-3 and the command-key will register for mouse-2. */);
6b61353c
KH
13394 Vmac_emulate_three_button_mouse = Qnil;
13395
3354caee 13396#if TARGET_API_MAC_CARBON
70ed951a 13397 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
68c767a3 13398 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
f2d8779b
YM
13399Otherwise, the right click will be treated as mouse-2 and the wheel
13400button will be mouse-3. */);
70ed951a 13401 mac_wheel_button_is_mouse_2 = 1;
5883787c 13402
70ed951a 13403 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
68c767a3 13404 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
70ed951a 13405 mac_pass_command_to_system = 1;
5883787c 13406
70ed951a 13407 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
68c767a3 13408 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
70ed951a 13409 mac_pass_control_to_system = 1;
743d0696 13410
742fbed7
AC
13411#endif
13412
70ed951a 13413 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
68c767a3 13414 doc: /* *If non-nil, allow anti-aliasing.
e24531b7
KS
13415The text will be rendered using Core Graphics text rendering which
13416may anti-alias the text. */);
458dbb8c
YM
13417#if USE_CG_DRAWING
13418 mac_use_core_graphics = 1;
13419#else
faef8681 13420 mac_use_core_graphics = 0;
458dbb8c 13421#endif
94d0e806
YM
13422
13423 /* Register an entry for `mac-roman' so that it can be used when
13424 creating the terminal frame on Mac OS 9 before loading
13425 term/mac-win.elc. */
13426 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
68c767a3 13427 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
94d0e806
YM
13428Each entry should be of the form:
13429
13430 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13431
13432where CHARSET-NAME is a string used in font names to identify the
f2d8779b
YM
13433charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13434CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
94d0e806
YM
13435 Vmac_charset_info_alist =
13436 Fcons (list3 (build_string ("mac-roman"),
13437 make_number (smRoman), Qnil), Qnil);
68c767a3 13438
02236cbc
YM
13439#if USE_MAC_TSM
13440 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13441 doc: /* Overlay used to display Mac TSM active input area. */);
13442 Vmac_ts_active_input_overlay = Qnil;
b4c51596 13443
e1adb139
YM
13444 DEFVAR_LISP ("mac-ts-active-input-buf", &Vmac_ts_active_input_buf,
13445 doc: /* Byte sequence of the current Mac TSM active input area. */);
13446 /* `empty_string' is not ready yet on Mac OS Classic. */
13447 Vmac_ts_active_input_buf = build_string ("");
13448
b4c51596
YM
13449 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13450 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13451If the value is t, the input script and language are restored to those
13452used in the last focus frame. If the value is a pair of integers, the
13453input script and language codes, which are defined in the Script
13454Manager, are set to its car and cdr parts, respectively. Otherwise,
13455Emacs doesn't set them and thus follows the system default behavior. */);
13456 Vmac_ts_script_language_on_focus = Qnil;
02236cbc 13457#endif
1a578e9b 13458}
6b61353c
KH
13459
13460/* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13461 (do not change this comment) */