(archive-add-new-member): Use `derived-mode-p'.
[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 {
913 if (pixmap->data)
914 xfree (pixmap->data);
915 xfree (pixmap);
916 }
917#else
7adf3143 918 DisposeGWorld (pixmap);
b03daa51 919#endif
7adf3143
YM
920}
921
922
1a578e9b
AC
923/* Mac replacement for XFillRectangle. */
924
925static void
236072ae
YM
926mac_fill_rectangle (f, gc, x, y, width, height)
927 struct frame *f;
1a578e9b
AC
928 GC gc;
929 int x, y;
930 unsigned int width, height;
931{
4ea08bbf
YM
932#if USE_CG_DRAWING
933 CGContextRef context;
934
935 context = mac_begin_cg_clip (f, gc);
e2d3b7e1 936 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
834263b6 937 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
4ea08bbf
YM
938 mac_end_cg_clip (f);
939#else
1a578e9b
AC
940 Rect r;
941
7adf3143 942 mac_begin_clip (f, gc);
e4f5e019 943 RGBForeColor (GC_FORE_COLOR (gc));
1a578e9b 944 SetRect (&r, x, y, x + width, y + height);
1a578e9b 945 PaintRect (&r); /* using foreground color of gc */
b6e3efe0 946 mac_end_clip (gc);
4ea08bbf 947#endif
1a578e9b
AC
948}
949
950
951/* Mac replacement for XDrawRectangle: dest is a window. */
952
953static void
236072ae
YM
954mac_draw_rectangle (f, gc, x, y, width, height)
955 struct frame *f;
1a578e9b
AC
956 GC gc;
957 int x, y;
958 unsigned int width, height;
959{
4ea08bbf
YM
960#if USE_CG_DRAWING
961 CGContextRef context;
962
963 context = mac_begin_cg_clip (f, gc);
e2d3b7e1 964 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, gc);
4ea08bbf
YM
965 CGContextStrokeRect (context,
966 CGRectMake (x + 0.5f, y + 0.5f, width, height));
967 mac_end_cg_clip (f);
968#else
1a578e9b
AC
969 Rect r;
970
7adf3143 971 mac_begin_clip (f, gc);
e4f5e019 972 RGBForeColor (GC_FORE_COLOR (gc));
1a578e9b 973 SetRect (&r, x, y, x + width + 1, y + height + 1);
1a578e9b 974 FrameRect (&r); /* using foreground color of gc */
b6e3efe0 975 mac_end_clip (gc);
4ea08bbf 976#endif
1a578e9b
AC
977}
978
979
7adf3143
YM
980static void
981mac_invert_rectangle (f, x, y, width, height)
982 struct frame *f;
983 int x, y;
984 unsigned int width, height;
985{
834263b6
YM
986#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
987#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
988 if (CGContextSetBlendMode != NULL)
989#endif
990 {
991 CGContextRef context;
660425fa 992
834263b6
YM
993 context = mac_begin_cg_clip (f, NULL);
994 CGContextSetRGBFillColor (context, 1.0f, 1.0f, 1.0f, 1.0f);
995 CGContextSetBlendMode (context, kCGBlendModeDifference);
996 CGContextFillRect (context, mac_rect_make (f, x, y, width, height));
997 mac_end_cg_clip (f);
998 }
999#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && MAC_OS_X_VERSION_MIN_REQUIRED >= 1020
1000 else /* CGContextSetBlendMode == NULL */
1001#endif
1002#endif /* USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 */
1003#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)
1004 {
1005 Rect r;
7adf3143
YM
1006
1007#if USE_CG_DRAWING
1008 mac_prepare_for_quickdraw (f);
1009#endif
1010 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1011
1012 SetRect (&r, x, y, x + width, y + height);
1013
1014 InvertRect (&r);
1015}
1016
1017
c3bd8190
YM
1018#if USE_ATSUI
1019static OSStatus
1020atsu_get_text_layout_with_text_ptr (text, text_length, style, text_layout)
1021 ConstUniCharArrayPtr text;
1022 UniCharCount text_length;
1023 ATSUStyle style;
1024 ATSUTextLayout *text_layout;
1025{
1026 OSStatus err;
7adf3143 1027 static ATSUTextLayout saved_text_layout = NULL;
c3bd8190
YM
1028
1029 if (saved_text_layout == NULL)
1030 {
369a7a37
YM
1031 static const UniCharCount lengths[] = {kATSUToTextEnd};
1032 static const ATSUAttributeTag tags[] = {kATSULineLayoutOptionsTag};
1033 static const ByteCount sizes[] = {sizeof (ATSLineLayoutOptions)};
c3bd8190
YM
1034 static ATSLineLayoutOptions line_layout =
1035#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
6a0b5d37 1036 kATSLineDisableAllLayoutOperations | kATSLineUseDeviceMetrics
3e16e799 1037 | kATSLineUseQDRendering
c3bd8190 1038#else
1c4ac540 1039 kATSLineIsDisplayOnly | kATSLineFractDisable
c3bd8190
YM
1040#endif
1041 ;
369a7a37 1042 static const ATSUAttributeValuePtr values[] = {&line_layout};
c3bd8190
YM
1043
1044 err = ATSUCreateTextLayoutWithTextPtr (text,
1045 kATSUFromTextBeginning,
1046 kATSUToTextEnd,
1047 text_length,
1048 1, lengths, &style,
1049 &saved_text_layout);
1050 if (err == noErr)
1051 err = ATSUSetLayoutControls (saved_text_layout,
1052 sizeof (tags) / sizeof (tags[0]),
1053 tags, sizes, values);
c3bd8190
YM
1054 if (err == noErr)
1055 err = ATSUSetTransientFontMatching (saved_text_layout, true);
1056 }
1057 else
1058 {
1059 err = ATSUSetRunStyle (saved_text_layout, style,
1060 kATSUFromTextBeginning, kATSUToTextEnd);
1061 if (err == noErr)
1062 err = ATSUSetTextPointerLocation (saved_text_layout, text,
1063 kATSUFromTextBeginning,
1064 kATSUToTextEnd,
1065 text_length);
1066 }
1067
1068 if (err == noErr)
1069 *text_layout = saved_text_layout;
1070 return err;
1071}
d4a8455b
YM
1072
1073
1a578e9b 1074static void
7adf3143
YM
1075mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1076 overstrike_p, bytes_per_char)
236072ae 1077 struct frame *f;
1a578e9b
AC
1078 GC gc;
1079 int x, y;
1080 char *buf;
bb420759 1081 int nchars, bg_width, overstrike_p, bytes_per_char;
1a578e9b 1082{
7adf3143
YM
1083 OSStatus err;
1084 ATSUTextLayout text_layout;
c3bd8190 1085
7adf3143 1086 xassert (bytes_per_char == 2);
c3bd8190
YM
1087
1088#ifndef WORDS_BIG_ENDIAN
7adf3143
YM
1089 {
1090 int i;
1091 UniChar *text = (UniChar *)buf;
c3bd8190 1092
7adf3143
YM
1093 for (i = 0; i < nchars; i++)
1094 text[i] = EndianU16_BtoN (text[i]);
1095 }
c3bd8190 1096#endif
7adf3143
YM
1097 err = atsu_get_text_layout_with_text_ptr ((ConstUniCharArrayPtr)buf,
1098 nchars,
1099 GC_FONT (gc)->mac_style,
1100 &text_layout);
1101 if (err != noErr)
1102 return;
c3bd8190 1103#ifdef MAC_OSX
7adf3143
YM
1104 if (!mac_use_core_graphics)
1105 {
c3bd8190 1106#endif
7adf3143
YM
1107 mac_begin_clip (f, gc);
1108 RGBForeColor (GC_FORE_COLOR (gc));
1109 if (bg_width)
1110 {
1111 Rect r;
9fb446e3 1112
7adf3143
YM
1113 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1114 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1115 RGBBackColor (GC_BACK_COLOR (gc));
1116 EraseRect (&r);
1117 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1118 }
1119 MoveTo (x, y);
1120 ATSUDrawText (text_layout,
1121 kATSUFromTextBeginning, kATSUToTextEnd,
1122 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
1123 if (overstrike_p)
1124 {
1125 MoveTo (x + 1, y);
9fb446e3
YM
1126 ATSUDrawText (text_layout,
1127 kATSUFromTextBeginning, kATSUToTextEnd,
1128 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
9fb446e3 1129 }
7adf3143
YM
1130 mac_end_clip (gc);
1131#ifdef MAC_OSX
1132 }
1133 else
1134 {
1135 static CGContextRef context;
834263b6 1136 CGFloat port_height = FRAME_PIXEL_HEIGHT (f);
7adf3143
YM
1137 static const ATSUAttributeTag tags[] = {kATSUCGContextTag};
1138 static const ByteCount sizes[] = {sizeof (CGContextRef)};
1139 static const ATSUAttributeValuePtr values[] = {&context};
9fb446e3 1140
4ea08bbf 1141#if USE_CG_DRAWING
7adf3143 1142 context = mac_begin_cg_clip (f, gc);
4ea08bbf 1143#else
7adf3143
YM
1144 CGrafPtr port;
1145
1146 GetPort (&port);
1147 QDBeginCGContext (port, &context);
1148 if (gc->n_clip_rects || bg_width)
1149 {
1150 CGContextTranslateCTM (context, 0, port_height);
1151 CGContextScaleCTM (context, 1, -1);
1152 if (gc->n_clip_rects)
1153 CGContextClipToRects (context, gc->clip_rects,
1154 gc->n_clip_rects);
4ea08bbf 1155#endif
7adf3143 1156 if (bg_width)
bb420759 1157 {
7adf3143
YM
1158 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
1159 CGContextFillRect (context,
834263b6
YM
1160 mac_rect_make (f,
1161 x, y - FONT_BASE (GC_FONT (gc)),
1162 bg_width,
1163 FONT_HEIGHT (GC_FONT (gc))));
bb420759 1164 }
7adf3143
YM
1165 CGContextScaleCTM (context, 1, -1);
1166 CGContextTranslateCTM (context, 0, -port_height);
1167#if !USE_CG_DRAWING
1168 }
1169#endif
1170 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
1171 err = ATSUSetLayoutControls (text_layout,
1172 sizeof (tags) / sizeof (tags[0]),
1173 tags, sizes, values);
1174 if (err == noErr)
1175 {
1176 ATSUDrawText (text_layout,
1177 kATSUFromTextBeginning, kATSUToTextEnd,
1178 Long2Fix (x), Long2Fix (port_height - y));
1179 if (overstrike_p)
1180 ATSUDrawText (text_layout,
1181 kATSUFromTextBeginning, kATSUToTextEnd,
1182 Long2Fix (x + 1), Long2Fix (port_height - y));
1183 }
4ea08bbf 1184#if USE_CG_DRAWING
7adf3143
YM
1185 mac_end_cg_clip (f);
1186 context = NULL;
4ea08bbf 1187#else
7adf3143
YM
1188 CGContextSynchronize (context);
1189 QDEndCGContext (port, &context);
4ea08bbf 1190#endif
9fb446e3 1191#if 0
7adf3143
YM
1192 /* This doesn't work on Mac OS X 10.1. */
1193 ATSUClearLayoutControls (text_layout,
1194 sizeof (tags) / sizeof (tags[0]), tags);
05f7d868 1195#else
7adf3143
YM
1196 ATSUSetLayoutControls (text_layout,
1197 sizeof (tags) / sizeof (tags[0]),
1198 tags, sizes, values);
c3bd8190 1199#endif
c3bd8190 1200 }
7adf3143
YM
1201#endif /* MAC_OSX */
1202}
9fb446e3 1203#endif /* USE_ATSUI */
9fb446e3 1204
7adf3143
YM
1205
1206static void
1207mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1208 overstrike_p, bytes_per_char)
1209 struct frame *f;
1210 GC gc;
1211 int x, y;
1212 char *buf;
1213 int nchars, bg_width, overstrike_p, bytes_per_char;
1214{
1215#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1216 UInt32 savedFlags;
4ea08bbf 1217#endif
7adf3143
YM
1218
1219 mac_begin_clip (f, gc);
1220#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1221 if (mac_use_core_graphics)
1222 savedFlags = SwapQDTextFlags (kQDUseCGTextRendering);
c3bd8190 1223#endif
7adf3143 1224 RGBForeColor (GC_FORE_COLOR (gc));
9fb446e3 1225#ifdef MAC_OS8
7adf3143
YM
1226 if (bg_width)
1227 {
1228 RGBBackColor (GC_BACK_COLOR (gc));
1229 TextMode (srcCopy);
1230 }
1231 else
1232 TextMode (srcOr);
9fb446e3 1233#else
7adf3143
YM
1234 /* We prefer not to use srcCopy text transfer mode on Mac OS X
1235 because:
1236 - Screen is double-buffered. (In srcCopy mode, a text is drawn
1237 into an offscreen graphics world first. So performance gain
1238 cannot be expected.)
1239 - It lowers rendering quality.
1240 - Some fonts leave garbage on cursor movement. */
1241 if (bg_width)
1242 {
1243 Rect r;
1a578e9b 1244
7adf3143
YM
1245 RGBBackColor (GC_BACK_COLOR (gc));
1246 SetRect (&r, x, y - FONT_BASE (GC_FONT (gc)),
1247 x + bg_width, y + FONT_DESCENT (GC_FONT (gc)));
1248 EraseRect (&r);
1249 }
1250 TextMode (srcOr);
c3bd8190 1251#endif
7adf3143
YM
1252 TextFont (GC_FONT (gc)->mac_fontnum);
1253 TextSize (GC_FONT (gc)->mac_fontsize);
1254 TextFace (GC_FONT (gc)->mac_fontface);
1255 MoveTo (x, y);
1256 DrawText (buf, 0, nchars * bytes_per_char);
1257 if (overstrike_p)
1258 {
1259 TextMode (srcOr);
1260 MoveTo (x + 1, y);
9fb446e3 1261 DrawText (buf, 0, nchars * bytes_per_char);
7adf3143
YM
1262 }
1263 if (bg_width)
1264 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
1265 mac_end_clip (gc);
b69efa23 1266
e9859e26 1267#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
7adf3143
YM
1268 if (mac_use_core_graphics)
1269 SwapQDTextFlags(savedFlags);
743d0696 1270#endif
7adf3143
YM
1271}
1272
1273
1274static INLINE void
1275mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1276 overstrike_p, bytes_per_char)
1277 struct frame *f;
1278 GC gc;
1279 int x, y;
1280 char *buf;
1281 int nchars, bg_width, overstrike_p, bytes_per_char;
1282{
1283#if USE_ATSUI
1284 if (GC_FONT (gc)->mac_style)
1285 mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width,
1286 overstrike_p, bytes_per_char);
1287 else
1288#endif /* USE_ATSUI */
1289 mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width,
1290 overstrike_p, bytes_per_char);
1a578e9b
AC
1291}
1292
1293
1a578e9b
AC
1294/* Mac replacement for XDrawImageString. */
1295
1296static void
bb420759 1297mac_draw_image_string (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
236072ae 1298 struct frame *f;
1a578e9b
AC
1299 GC gc;
1300 int x, y;
1301 char *buf;
bb420759 1302 int nchars, bg_width, overstrike_p;
1a578e9b 1303{
bb420759
YM
1304 mac_draw_string_common (f, gc, x, y, buf, nchars, bg_width,
1305 overstrike_p, 1);
1a578e9b
AC
1306}
1307
1308
bb420759 1309/* Mac replacement for XDrawImageString16. */
1a578e9b
AC
1310
1311static void
bb420759 1312mac_draw_image_string_16 (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
236072ae 1313 struct frame *f;
1a578e9b
AC
1314 GC gc;
1315 int x, y;
1316 XChar2b *buf;
bb420759 1317 int nchars, bg_width, overstrike_p;
1a578e9b 1318{
bb420759
YM
1319 mac_draw_string_common (f, gc, x, y, (char *) buf, nchars, bg_width,
1320 overstrike_p, 2);
1a578e9b
AC
1321}
1322
1323
b73e4d84
YM
1324/* Mac replacement for XQueryTextExtents, but takes a character. If
1325 STYLE is NULL, measurement is done by QuickDraw Text routines for
1326 the font of the current graphics port. If CG_GLYPH is not NULL,
1327 *CG_GLYPH is set to the glyph ID or 0 if it cannot be obtained. */
1328
3e7424f7 1329static OSStatus
b73e4d84
YM
1330mac_query_char_extents (style, c,
1331 font_ascent_return, font_descent_return,
1332 overall_return, cg_glyph)
1333#if USE_ATSUI
1334 ATSUStyle style;
1335#else
1336 void *style;
1337#endif
1338 int c;
1339 int *font_ascent_return, *font_descent_return;
1340 XCharStruct *overall_return;
16805b2e 1341#if USE_CG_TEXT_DRAWING
b73e4d84
YM
1342 CGGlyph *cg_glyph;
1343#else
1344 void *cg_glyph;
1345#endif
1346{
3e7424f7 1347 OSStatus err = noErr;
b73e4d84
YM
1348 int width;
1349 Rect char_bounds;
1350
1351#if USE_ATSUI
1352 if (style)
1353 {
1354 ATSUTextLayout text_layout;
1355 UniChar ch = c;
1356
1357 err = atsu_get_text_layout_with_text_ptr (&ch, 1, style, &text_layout);
0d36bf23
YM
1358 if (err == noErr
1359 && (font_ascent_return || font_descent_return || overall_return))
b73e4d84
YM
1360 {
1361 ATSTrapezoid glyph_bounds;
16805b2e 1362
b73e4d84
YM
1363 err = ATSUGetGlyphBounds (text_layout, 0, 0,
1364 kATSUFromTextBeginning, kATSUToTextEnd,
1365#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1366 kATSUseFractionalOrigins,
1367#else
1368 kATSUseDeviceOrigins,
1369#endif
1370 1, &glyph_bounds, NULL);
1371 if (err == noErr)
1372 {
1373 xassert (glyph_bounds.lowerRight.x - glyph_bounds.lowerLeft.x
1374 == glyph_bounds.upperRight.x - glyph_bounds.upperLeft.x);
1375
1376 width = Fix2Long (glyph_bounds.upperRight.x
1377 - glyph_bounds.upperLeft.x);
1378 if (font_ascent_return)
1379 *font_ascent_return = -Fix2Long (glyph_bounds.upperLeft.y);
1380 if (font_descent_return)
1381 *font_descent_return = Fix2Long (glyph_bounds.lowerLeft.y);
1382 }
1383 }
1384 if (err == noErr && overall_return)
1385 {
1386 err = ATSUMeasureTextImage (text_layout,
1387 kATSUFromTextBeginning, kATSUToTextEnd,
1388 0, 0, &char_bounds);
1389 if (err == noErr)
1390 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1391#if USE_CG_TEXT_DRAWING
1392 if (err == noErr && cg_glyph)
1393 {
3e7424f7 1394 OSStatus err1;
b73e4d84
YM
1395 ATSUGlyphInfoArray glyph_info_array;
1396 ByteCount count = sizeof (ATSUGlyphInfoArray);
1397
1398 err1 = ATSUMatchFontsToText (text_layout, kATSUFromTextBeginning,
1399 kATSUToTextEnd, NULL, NULL, NULL);
1400 if (err1 == noErr)
1401 err1 = ATSUGetGlyphInfo (text_layout, kATSUFromTextBeginning,
1402 kATSUToTextEnd, &count,
1403 &glyph_info_array);
7c682cf1
YM
1404 if (err1 == noErr
1405 /* Make sure that we don't have to make layout
1406 adjustments. */
1407 && glyph_info_array.glyphs[0].deltaY == 0.0f
1408 && glyph_info_array.glyphs[0].idealX == 0.0f
1409 && glyph_info_array.glyphs[0].screenX == 0)
b73e4d84
YM
1410 {
1411 xassert (glyph_info_array.glyphs[0].glyphID);
1412 *cg_glyph = glyph_info_array.glyphs[0].glyphID;
1413 }
1414 else
1415 *cg_glyph = 0;
1416 }
1417#endif
1418 }
1419 }
1420 else
1421#endif
1422 {
1423 if (font_ascent_return || font_descent_return)
1424 {
1425 FontInfo font_info;
1426
1427 GetFontInfo (&font_info);
1428 if (font_ascent_return)
1429 *font_ascent_return = font_info.ascent;
1430 if (font_descent_return)
1431 *font_descent_return = font_info.descent;
1432 }
1433 if (overall_return)
1434 {
1435 char ch = c;
1436
1437 width = CharWidth (ch);
1438 QDTextBounds (1, &ch, &char_bounds);
1439 STORE_XCHARSTRUCT (*overall_return, width, char_bounds);
1440 }
1441 }
1442
1443 return err;
1444}
1445
1446
1447/* Mac replacement for XTextExtents16. Only sets horizontal metrics. */
1448
1449static int
1450mac_text_extents_16 (font_struct, string, nchars, overall_return)
1451 XFontStruct *font_struct;
1452 XChar2b *string;
1453 int nchars;
1454 XCharStruct *overall_return;
1455{
1456 int i;
1457 short width = 0, lbearing = 0, rbearing = 0;
1458 XCharStruct *pcm;
1459
1460 for (i = 0; i < nchars; i++)
1461 {
1462 pcm = mac_per_char_metric (font_struct, string, 0);
1463 if (pcm == NULL)
1464 width += FONT_WIDTH (font_struct);
1465 else
1466 {
1467 lbearing = min (lbearing, width + pcm->lbearing);
1468 rbearing = max (rbearing, width + pcm->rbearing);
1469 width += pcm->width;
1470 }
1471 string++;
1472 }
1473
1474 overall_return->lbearing = lbearing;
1475 overall_return->rbearing = rbearing;
1476 overall_return->width = width;
1477
1478 /* What's the meaning of the return value of XTextExtents16? */
1479}
1480
1481
1482#if USE_CG_TEXT_DRAWING
6b9ad469
YM
1483static int cg_text_anti_aliasing_threshold = 8;
1484
1485static void
1486init_cg_text_anti_aliasing_threshold ()
1487{
b465419f
YM
1488 int threshold;
1489 Boolean valid_p;
6b9ad469 1490
b465419f
YM
1491 threshold =
1492 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
1493 kCFPreferencesCurrentApplication,
1494 &valid_p);
1495 if (valid_p)
1496 cg_text_anti_aliasing_threshold = threshold;
6b9ad469
YM
1497}
1498
16805b2e 1499static int
bb420759 1500mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p)
16805b2e
YM
1501 struct frame *f;
1502 GC gc;
1503 int x, y;
1504 XChar2b *buf;
bb420759 1505 int nchars, bg_width, overstrike_p;
16805b2e 1506{
834263b6 1507 CGFloat port_height, gx, gy;
16805b2e
YM
1508 int i;
1509 CGContextRef context;
1510 CGGlyph *glyphs;
1511 CGSize *advances;
1512
70ed951a 1513 if (!mac_use_core_graphics || GC_FONT (gc)->cg_font == NULL)
16805b2e
YM
1514 return 0;
1515
16805b2e
YM
1516 port_height = FRAME_PIXEL_HEIGHT (f);
1517 gx = x;
1518 gy = port_height - y;
1519 glyphs = (CGGlyph *)buf;
9fb446e3
YM
1520 advances = alloca (sizeof (CGSize) * nchars);
1521 if (advances == NULL)
1522 return 0;
16805b2e
YM
1523 for (i = 0; i < nchars; i++)
1524 {
b73e4d84
YM
1525 XCharStruct *pcm = mac_per_char_metric (GC_FONT (gc), buf, 0);
1526
1527 advances[i].width = pcm->width;
16805b2e
YM
1528 advances[i].height = 0;
1529 glyphs[i] = GC_FONT (gc)->cg_glyphs[buf->byte2];
1530 buf++;
1531 }
1532
4ea08bbf
YM
1533#if USE_CG_DRAWING
1534 context = mac_begin_cg_clip (f, gc);
1535#else
7adf3143 1536 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
9fb446e3 1537 if (gc->n_clip_rects || bg_width)
16805b2e
YM
1538 {
1539 CGContextTranslateCTM (context, 0, port_height);
1540 CGContextScaleCTM (context, 1, -1);
9fb446e3
YM
1541 if (gc->n_clip_rects)
1542 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
4ea08bbf 1543#endif
9fb446e3
YM
1544 if (bg_width)
1545 {
e2d3b7e1 1546 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, gc);
9fb446e3
YM
1547 CGContextFillRect
1548 (context,
834263b6
YM
1549 mac_rect_make (f, gx, y - FONT_BASE (GC_FONT (gc)),
1550 bg_width, FONT_HEIGHT (GC_FONT (gc))));
9fb446e3 1551 }
16805b2e
YM
1552 CGContextScaleCTM (context, 1, -1);
1553 CGContextTranslateCTM (context, 0, -port_height);
4ea08bbf 1554#if !USE_CG_DRAWING
16805b2e 1555 }
4ea08bbf 1556#endif
e2d3b7e1 1557 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc);
16805b2e
YM
1558 CGContextSetFont (context, GC_FONT (gc)->cg_font);
1559 CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize);
6b9ad469
YM
1560 if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold)
1561 CGContextSetShouldAntialias (context, false);
16805b2e 1562#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1d4412cd
YM
1563#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1564 if (CGContextShowGlyphsWithAdvances != NULL)
1565#endif
bb420759 1566 {
1d4412cd 1567 CGContextSetTextPosition (context, gx, gy);
bb420759 1568 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1d4412cd
YM
1569 if (overstrike_p)
1570 {
1571 CGContextSetTextPosition (context, gx + 1.0f, gy);
1572 CGContextShowGlyphsWithAdvances (context, glyphs, advances, nchars);
1573 }
bb420759 1574 }
1d4412cd 1575#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
7adf3143 1576 else /* CGContextShowGlyphsWithAdvances == NULL */
1d4412cd
YM
1577#endif
1578#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1579#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
16805b2e 1580 {
1d4412cd
YM
1581 for (i = 0; i < nchars; i++)
1582 {
1583 CGContextShowGlyphsAtPoint (context, gx, gy, glyphs + i, 1);
1584 if (overstrike_p)
1585 CGContextShowGlyphsAtPoint (context, gx + 1.0f, gy, glyphs + i, 1);
1586 gx += advances[i].width;
1587 }
16805b2e
YM
1588 }
1589#endif
4ea08bbf
YM
1590#if USE_CG_DRAWING
1591 mac_end_cg_clip (f);
1592#else
16805b2e 1593 CGContextSynchronize (context);
7adf3143 1594 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
4ea08bbf 1595#endif
16805b2e 1596
16805b2e
YM
1597 return 1;
1598}
1599#endif
1600
1601
e09ce637 1602#if !USE_CG_DRAWING
1a578e9b
AC
1603/* Mac replacement for XCopyArea: dest must be window. */
1604
1605static void
236072ae 1606mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y)
1a578e9b 1607 Pixmap src;
236072ae 1608 struct frame *f;
1a578e9b
AC
1609 GC gc;
1610 int src_x, src_y;
1611 unsigned int width, height;
1612 int dest_x, dest_y;
1613{
1614 Rect src_r, dest_r;
1615
7adf3143 1616 mac_begin_clip (f, gc);
e0f712ba 1617
1a578e9b
AC
1618 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1619 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1620
6b61353c
KH
1621 ForeColor (blackColor);
1622 BackColor (whiteColor);
1623
1624 LockPixels (GetGWorldPixMap (src));
e0f712ba 1625#if TARGET_API_MAC_CARBON
236072ae
YM
1626 {
1627 CGrafPtr port;
1628
1629 GetPort (&port);
1630 LockPortBits (port);
1631 CopyBits (GetPortBitMapForCopyBits (src),
1632 GetPortBitMapForCopyBits (port),
1633 &src_r, &dest_r, srcCopy, 0);
1634 UnlockPortBits (port);
1635 }
6b61353c 1636#else /* not TARGET_API_MAC_CARBON */
236072ae 1637 CopyBits (&(((GrafPtr)src)->portBits), &(FRAME_MAC_WINDOW (f)->portBits),
6b61353c
KH
1638 &src_r, &dest_r, srcCopy, 0);
1639#endif /* not TARGET_API_MAC_CARBON */
1640 UnlockPixels (GetGWorldPixMap (src));
1f98fbb4 1641
236072ae 1642 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143
YM
1643
1644 mac_end_clip (gc);
6b61353c 1645}
e0f712ba 1646
6b61353c
KH
1647
1648static void
236072ae 1649mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y,
6b61353c 1650 width, height, dest_x, dest_y)
6b61353c 1651 Pixmap src, mask;
236072ae 1652 struct frame *f;
6b61353c
KH
1653 GC gc;
1654 int src_x, src_y;
1655 unsigned int width, height;
1656 int dest_x, dest_y;
1657{
1658 Rect src_r, dest_r;
1659
7adf3143 1660 mac_begin_clip (f, gc);
6b61353c
KH
1661
1662 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1663 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1664
1665 ForeColor (blackColor);
1666 BackColor (whiteColor);
1667
1668 LockPixels (GetGWorldPixMap (src));
1669 LockPixels (GetGWorldPixMap (mask));
1670#if TARGET_API_MAC_CARBON
236072ae
YM
1671 {
1672 CGrafPtr port;
1673
1674 GetPort (&port);
1675 LockPortBits (port);
1676 CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask),
1677 GetPortBitMapForCopyBits (port),
1678 &src_r, &src_r, &dest_r);
1679 UnlockPortBits (port);
1680 }
e0f712ba 1681#else /* not TARGET_API_MAC_CARBON */
6b61353c 1682 CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits),
236072ae 1683 &(FRAME_MAC_WINDOW (f)->portBits), &src_r, &src_r, &dest_r);
e0f712ba 1684#endif /* not TARGET_API_MAC_CARBON */
6b61353c
KH
1685 UnlockPixels (GetGWorldPixMap (mask));
1686 UnlockPixels (GetGWorldPixMap (src));
1f98fbb4 1687
236072ae 1688 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143
YM
1689
1690 mac_end_clip (gc);
1a578e9b 1691}
e09ce637 1692#endif /* !USE_CG_DRAWING */
1a578e9b
AC
1693
1694
1a578e9b
AC
1695/* Mac replacement for XCopyArea: used only for scrolling. */
1696
1697static void
236072ae
YM
1698mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1699 struct frame *f;
1a578e9b
AC
1700 GC gc;
1701 int src_x, src_y;
1702 unsigned int width, height;
1703 int dest_x, dest_y;
1704{
e0f712ba 1705#if TARGET_API_MAC_CARBON
fc7a70cc
ST
1706 Rect src_r;
1707 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
e0f712ba
AC
1708
1709 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
4ea08bbf
YM
1710#if USE_CG_DRAWING
1711 mac_prepare_for_quickdraw (f);
1712#endif
236072ae
YM
1713 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1714 &src_r, dest_x - src_x, dest_y - src_y,
fc7a70cc
ST
1715 kScrollWindowNoOptions, dummy);
1716 DisposeRgn (dummy);
e0f712ba 1717#else /* not TARGET_API_MAC_CARBON */
1a578e9b 1718 Rect src_r, dest_r;
3354caee 1719 WindowRef w = FRAME_MAC_WINDOW (f);
1a578e9b 1720
7adf3143 1721 mac_begin_clip (f, gc);
1a578e9b
AC
1722
1723 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1724 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
1725
f9e25d0c
AC
1726 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
1727 color mapping in CopyBits. Otherwise, it will be slow. */
1728 ForeColor (blackColor);
1729 BackColor (whiteColor);
1730 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
177c0ea7 1731
236072ae 1732 RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f)));
7adf3143
YM
1733
1734 mac_end_clip (gc);
e0f712ba 1735#endif /* not TARGET_API_MAC_CARBON */
1a578e9b
AC
1736}
1737
1738
1a578e9b
AC
1739/* Mac replacement for XChangeGC. */
1740
1741static void
e4f5e019
YM
1742XChangeGC (display, gc, mask, xgcv)
1743 Display *display;
1744 GC gc;
1745 unsigned long mask;
1746 XGCValues *xgcv;
1a578e9b
AC
1747{
1748 if (mask & GCForeground)
e4f5e019 1749 XSetForeground (display, gc, xgcv->foreground);
1a578e9b 1750 if (mask & GCBackground)
e4f5e019 1751 XSetBackground (display, gc, xgcv->background);
1a578e9b 1752 if (mask & GCFont)
e4f5e019 1753 XSetFont (display, gc, xgcv->font);
1a578e9b
AC
1754}
1755
1756
1757/* Mac replacement for XCreateGC. */
1758
e4f5e019 1759GC
a84cad70 1760XCreateGC (display, d, mask, xgcv)
e4f5e019 1761 Display *display;
a84cad70 1762 void *d;
e4f5e019
YM
1763 unsigned long mask;
1764 XGCValues *xgcv;
1a578e9b 1765{
e4f5e019 1766 GC gc = xmalloc (sizeof (*gc));
1a578e9b 1767
b96fe6ea 1768 bzero (gc, sizeof (*gc));
e2d3b7e1
YM
1769#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1770#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1771 if (CGColorGetTypeID != NULL)
1772#endif
1773 {
1774 gc->cg_fore_color = gc->cg_back_color = mac_cg_color_black;
1775 CGColorRetain (gc->cg_fore_color);
1776 CGColorRetain (gc->cg_back_color);
1777 }
1778#endif
b96fe6ea 1779 XChangeGC (display, gc, mask, xgcv);
1a578e9b
AC
1780
1781 return gc;
1782}
1783
1784
1785/* Used in xfaces.c. */
1786
1787void
1788XFreeGC (display, gc)
1789 Display *display;
1790 GC gc;
1791{
1c4ac540
YM
1792 if (gc->clip_region)
1793 DisposeRgn (gc->clip_region);
e2d3b7e1 1794#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
a84cad70
YM
1795#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1796 if (CGColorGetTypeID != NULL)
1797#endif
1798 {
1799 CGColorRelease (gc->cg_fore_color);
1800 CGColorRelease (gc->cg_back_color);
1801 }
e2d3b7e1 1802#endif
1a578e9b
AC
1803 xfree (gc);
1804}
1805
1806
1807/* Mac replacement for XGetGCValues. */
1808
1809static void
e4f5e019
YM
1810XGetGCValues (display, gc, mask, xgcv)
1811 Display *display;
1812 GC gc;
1813 unsigned long mask;
1814 XGCValues *xgcv;
1a578e9b 1815{
e4f5e019
YM
1816 if (mask & GCForeground)
1817 xgcv->foreground = gc->xgcv.foreground;
1818 if (mask & GCBackground)
1819 xgcv->background = gc->xgcv.background;
1820 if (mask & GCFont)
1821 xgcv->font = gc->xgcv.font;
1a578e9b
AC
1822}
1823
1824
1825/* Mac replacement for XSetForeground. */
1826
6b61353c 1827void
1a578e9b
AC
1828XSetForeground (display, gc, color)
1829 Display *display;
1830 GC gc;
1831 unsigned long color;
1832{
e4f5e019
YM
1833 if (gc->xgcv.foreground != color)
1834 {
1835 gc->xgcv.foreground = color;
1836 gc->fore_color.red = RED16_FROM_ULONG (color);
1837 gc->fore_color.green = GREEN16_FROM_ULONG (color);
1838 gc->fore_color.blue = BLUE16_FROM_ULONG (color);
e2d3b7e1
YM
1839#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1840#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1841 if (CGColorGetTypeID != NULL)
1842#endif
1843 {
1844 CGColorRelease (gc->cg_fore_color);
1845 if (color == 0)
1846 {
1847 gc->cg_fore_color = mac_cg_color_black;
1848 CGColorRetain (gc->cg_fore_color);
1849 }
1850 else
1851 {
834263b6 1852 CGFloat rgba[4];
e2d3b7e1
YM
1853
1854 rgba[0] = gc->fore_color.red / 65535.0f;
1855 rgba[1] = gc->fore_color.green / 65535.0f;
1856 rgba[2] = gc->fore_color.blue / 65535.0f;
1857 rgba[3] = 1.0f;
1858 gc->cg_fore_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1859 }
1860 }
1861#endif
e4f5e019 1862 }
1a578e9b
AC
1863}
1864
1865
9cdd4884
ST
1866/* Mac replacement for XSetBackground. */
1867
1868void
1869XSetBackground (display, gc, color)
1870 Display *display;
1871 GC gc;
1872 unsigned long color;
1873{
e4f5e019
YM
1874 if (gc->xgcv.background != color)
1875 {
1876 gc->xgcv.background = color;
1877 gc->back_color.red = RED16_FROM_ULONG (color);
1878 gc->back_color.green = GREEN16_FROM_ULONG (color);
1879 gc->back_color.blue = BLUE16_FROM_ULONG (color);
e2d3b7e1
YM
1880#if USE_CG_DRAWING && MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1881#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1882 if (CGColorGetTypeID != NULL)
1883#endif
1884 {
1885 CGColorRelease (gc->cg_back_color);
1886 if (color == 0)
1887 {
1888 gc->cg_back_color = mac_cg_color_black;
1889 CGColorRetain (gc->cg_back_color);
1890 }
1891 else
1892 {
834263b6 1893 CGFloat rgba[4];
e2d3b7e1
YM
1894
1895 rgba[0] = gc->back_color.red / 65535.0f;
1896 rgba[1] = gc->back_color.green / 65535.0f;
1897 rgba[2] = gc->back_color.blue / 65535.0f;
1898 rgba[3] = 1.0f;
1899 gc->cg_back_color = CGColorCreate (mac_cg_color_space_rgb, rgba);
1900 }
1901 }
1902#endif
e4f5e019
YM
1903 }
1904}
1905
1906
1907/* Mac replacement for XSetFont. */
1908
1909static void
1910XSetFont (display, gc, font)
1911 Display *display;
1912 GC gc;
1913 XFontStruct *font;
1914{
1915 gc->xgcv.font = font;
9cdd4884
ST
1916}
1917
1918
1c4ac540
YM
1919/* Mac replacement for XSetClipRectangles. */
1920
1921static void
834263b6
YM
1922mac_set_clip_rectangles (f, gc, rectangles, n)
1923 struct frame *f;
1c4ac540
YM
1924 GC gc;
1925 Rect *rectangles;
1926 int n;
1927{
1928 int i;
1929
b6e3efe0
YM
1930 xassert (n >= 0 && n <= MAX_CLIP_RECTS);
1931
1932 gc->n_clip_rects = n;
1933 if (n > 0)
1c4ac540
YM
1934 {
1935 if (gc->clip_region == NULL)
1936 gc->clip_region = NewRgn ();
1937 RectRgn (gc->clip_region, rectangles);
1938 if (n > 1)
1939 {
1940 RgnHandle region = NewRgn ();
1941
1942 for (i = 1; i < n; i++)
1943 {
1944 RectRgn (region, rectangles + i);
1945 UnionRgn (gc->clip_region, region, gc->clip_region);
1946 }
1947 DisposeRgn (region);
1948 }
1949 }
458dbb8c 1950#if defined (MAC_OSX) && (USE_ATSUI || USE_CG_DRAWING)
1c4ac540
YM
1951 for (i = 0; i < n; i++)
1952 {
1953 Rect *rect = rectangles + i;
1954
834263b6
YM
1955 gc->clip_rects[i] = mac_rect_make (f, rect->left, rect->top,
1956 rect->right - rect->left,
1957 rect->bottom - rect->top);
1c4ac540
YM
1958 }
1959#endif
1960}
1961
1962
1963/* Mac replacement for XSetClipMask. */
1964
1965static INLINE void
834263b6
YM
1966mac_reset_clip_rectangles (f, gc)
1967 struct frame *f;
1c4ac540
YM
1968 GC gc;
1969{
b6e3efe0 1970 gc->n_clip_rects = 0;
1c4ac540
YM
1971}
1972
1973
9cdd4884
ST
1974/* Mac replacement for XSetWindowBackground. */
1975
1976void
1977XSetWindowBackground (display, w, color)
1978 Display *display;
3354caee 1979 WindowRef w;
9cdd4884
ST
1980 unsigned long color;
1981{
1982#if !TARGET_API_MAC_CARBON
1983 AuxWinHandle aw_handle;
1984 CTabHandle ctab_handle;
1985 ColorSpecPtr ct_table;
1986 short ct_size;
1987#endif
1988 RGBColor bg_color;
1989
1990 bg_color.red = RED16_FROM_ULONG (color);
1991 bg_color.green = GREEN16_FROM_ULONG (color);
1992 bg_color.blue = BLUE16_FROM_ULONG (color);
1993
1994#if TARGET_API_MAC_CARBON
1995 SetWindowContentColor (w, &bg_color);
1996#else
1997 if (GetAuxWin (w, &aw_handle))
1998 {
1999 ctab_handle = (*aw_handle)->awCTable;
2000 HandToHand ((Handle *) &ctab_handle);
2001 ct_table = (*ctab_handle)->ctTable;
2002 ct_size = (*ctab_handle)->ctSize;
2003 while (ct_size > -1)
2004 {
2005 if (ct_table->value == 0)
2006 {
2007 ct_table->rgb = bg_color;
2008 CTabChanged (ctab_handle);
2009 SetWinColor (w, (WCTabHandle) ctab_handle);
2010 }
2011 ct_size--;
2012 }
2013 }
2014#endif
2015}
2016
1a578e9b
AC
2017/* Flush display of frame F, or of all frames if F is null. */
2018
fc7a70cc 2019static void
1a578e9b
AC
2020x_flush (f)
2021 struct frame *f;
2022{
e0f712ba 2023#if TARGET_API_MAC_CARBON
1a578e9b 2024 BLOCK_INPUT;
4ea08bbf
YM
2025#if USE_CG_DRAWING
2026 mac_prepare_for_quickdraw (f);
2027#endif
fc7a70cc
ST
2028 if (f)
2029 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
2030 else
2031 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1a578e9b 2032 UNBLOCK_INPUT;
fc7a70cc 2033#endif
1a578e9b
AC
2034}
2035
2036
fc7a70cc
ST
2037/* Remove calls to XFlush by defining XFlush to an empty replacement.
2038 Calls to XFlush should be unnecessary because the X output buffer
2039 is flushed automatically as needed by calls to XPending,
2040 XNextEvent, or XWindowEvent according to the XFlush man page.
2041 XTread_socket calls XPending. Removing XFlush improves
2042 performance. */
2043
2044#define XFlush(DISPLAY) (void) 0
2045
e6509087
YM
2046#if USE_CG_DRAWING
2047static void
2048mac_flush_display_optional (f)
2049 struct frame *f;
1a578e9b 2050{
e6509087
YM
2051 BLOCK_INPUT;
2052 mac_prepare_for_quickdraw (f);
2053 UNBLOCK_INPUT;
1a578e9b 2054}
e6509087 2055#endif
1a578e9b
AC
2056\f
2057/***********************************************************************
2058 Starting and ending an update
2059 ***********************************************************************/
177c0ea7 2060
1a578e9b
AC
2061/* Start an update of frame F. This function is installed as a hook
2062 for update_begin, i.e. it is called when update_begin is called.
2063 This function is called prior to calls to x_update_window_begin for
e0f712ba 2064 each window being updated. */
1a578e9b 2065
e0f712ba 2066static void
1a578e9b
AC
2067x_update_begin (f)
2068 struct frame *f;
2069{
b15325b2
ST
2070#if TARGET_API_MAC_CARBON
2071 /* During update of a frame, availability of input events is
2072 periodically checked with ReceiveNextEvent if
2073 redisplay-dont-pause is nil. That normally flushes window buffer
2074 changes for every check, and thus screen update looks waving even
2075 if no input is available. So we disable screen updates during
2076 update of a frame. */
2077 BLOCK_INPUT;
2078 DisableScreenUpdates ();
2079 UNBLOCK_INPUT;
2080#endif
1a578e9b
AC
2081}
2082
2083
2084/* Start update of window W. Set the global variable updated_window
2085 to the window being updated and set output_cursor to the cursor
2086 position of W. */
2087
e0f712ba 2088static void
1a578e9b
AC
2089x_update_window_begin (w)
2090 struct window *w;
2091{
2092 struct frame *f = XFRAME (WINDOW_FRAME (w));
2093 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
177c0ea7 2094
1a578e9b
AC
2095 updated_window = w;
2096 set_output_cursor (&w->cursor);
2097
2098 BLOCK_INPUT;
2099
2100 if (f == display_info->mouse_face_mouse_frame)
2101 {
2102 /* Don't do highlighting for mouse motion during the update. */
2103 display_info->mouse_face_defer = 1;
2104
2105 /* If F needs to be redrawn, simply forget about any prior mouse
2106 highlighting. */
2107 if (FRAME_GARBAGED_P (f))
2108 display_info->mouse_face_window = Qnil;
2109
2110#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
2111 their mouse_face_p flag set, which means that they are always
2112 unequal to rows in a desired matrix which never have that
2113 flag set. So, rows containing mouse-face glyphs are never
2114 scrolled, and we don't have to switch the mouse highlight off
2115 here to prevent it from being scrolled. */
177c0ea7 2116
1a578e9b
AC
2117 /* Can we tell that this update does not affect the window
2118 where the mouse highlight is? If so, no need to turn off.
2119 Likewise, don't do anything if the frame is garbaged;
2120 in that case, the frame's current matrix that we would use
2121 is all wrong, and we will redisplay that line anyway. */
2122 if (!NILP (display_info->mouse_face_window)
2123 && w == XWINDOW (display_info->mouse_face_window))
2124 {
2125 int i;
2126
50bf7673 2127 for (i = 0; i < w->desired_matrix->nrows; ++i)
1a578e9b
AC
2128 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
2129 break;
2130
2131 if (i < w->desired_matrix->nrows)
2132 clear_mouse_face (display_info);
2133 }
2134#endif /* 0 */
2135 }
2136
2137 UNBLOCK_INPUT;
2138}
2139
2140
f9e65eb3 2141/* Draw a vertical window border from (x,y0) to (x,y1) */
1a578e9b
AC
2142
2143static void
f9e65eb3 2144mac_draw_vertical_window_border (w, x, y0, y1)
1a578e9b 2145 struct window *w;
f9e65eb3 2146 int x, y0, y1;
1a578e9b
AC
2147{
2148 struct frame *f = XFRAME (WINDOW_FRAME (w));
dd15724d
YM
2149 struct face *face;
2150
2151 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2152 if (face)
2153 XSetForeground (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
2154 face->foreground);
ffe8b3f4 2155
236072ae 2156 mac_draw_line (f, f->output_data.mac->normal_gc, x, y0, x, y1);
1a578e9b 2157}
e0f712ba 2158
1a578e9b
AC
2159/* End update of window W (which is equal to updated_window).
2160
2161 Draw vertical borders between horizontally adjacent windows, and
2162 display W's cursor if CURSOR_ON_P is non-zero.
2163
2164 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
2165 glyphs in mouse-face were overwritten. In that case we have to
2166 make sure that the mouse-highlight is properly redrawn.
2167
2168 W may be a menu bar pseudo-window in case we don't have X toolkit
b15325b2 2169 support. Such windows don't have a cursor, so don't display it
95dfb192 2170 here. */
1a578e9b 2171
e0f712ba 2172static void
1a578e9b
AC
2173x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
2174 struct window *w;
2175 int cursor_on_p, mouse_face_overwritten_p;
2176{
f9e65eb3 2177 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
e0f712ba 2178
1a578e9b
AC
2179 if (!w->pseudo_window_p)
2180 {
1a578e9b
AC
2181 BLOCK_INPUT;
2182
1a578e9b 2183 if (cursor_on_p)
f9e65eb3
KS
2184 display_and_set_cursor (w, 1, output_cursor.hpos,
2185 output_cursor.vpos,
2186 output_cursor.x, output_cursor.y);
177c0ea7 2187
f94a2622
KS
2188 if (draw_window_fringes (w, 1))
2189 x_draw_vertical_border (w);
6b61353c 2190
1a578e9b
AC
2191 UNBLOCK_INPUT;
2192 }
e0f712ba
AC
2193
2194 /* If a row with mouse-face was overwritten, arrange for
2195 XTframe_up_to_date to redisplay the mouse highlight. */
2196 if (mouse_face_overwritten_p)
2197 {
2198 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2199 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2200 dpyinfo->mouse_face_window = Qnil;
2201 }
2202
1a578e9b
AC
2203 updated_window = NULL;
2204}
2205
2206
2207/* End update of frame F. This function is installed as a hook in
2208 update_end. */
2209
e0f712ba 2210static void
1a578e9b
AC
2211x_update_end (f)
2212 struct frame *f;
2213{
404e4b84
ST
2214 /* Mouse highlight may be displayed again. */
2215 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
2216
2217 BLOCK_INPUT;
b15325b2
ST
2218#if TARGET_API_MAC_CARBON
2219 EnableScreenUpdates ();
2220#endif
1a578e9b
AC
2221 XFlush (FRAME_MAC_DISPLAY (f));
2222 UNBLOCK_INPUT;
2223}
2224
2225
2226/* This function is called from various places in xdisp.c whenever a
2227 complete update has been performed. The global variable
2228 updated_window is not available here. */
2229
e0f712ba 2230static void
1a578e9b
AC
2231XTframe_up_to_date (f)
2232 struct frame *f;
2233{
fe97e8df 2234 if (FRAME_MAC_P (f))
1a578e9b
AC
2235 {
2236 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2237
2238 if (dpyinfo->mouse_face_deferred_gc
2239 || f == dpyinfo->mouse_face_mouse_frame)
2240 {
2241 BLOCK_INPUT;
2242 if (dpyinfo->mouse_face_mouse_frame)
2243 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
2244 dpyinfo->mouse_face_mouse_x,
2245 dpyinfo->mouse_face_mouse_y);
2246 dpyinfo->mouse_face_deferred_gc = 0;
2247 UNBLOCK_INPUT;
2248 }
2249 }
2250}
2251
2252
2253/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 2254 arrow bitmaps, or clear the fringes if no bitmaps are required
1a578e9b 2255 before DESIRED_ROW is made current. The window being updated is
e0f712ba 2256 found in updated_window. This function is called from
1a578e9b
AC
2257 update_window_line only if it is known that there are differences
2258 between bitmaps to be drawn between current row and DESIRED_ROW. */
2259
e0f712ba 2260static void
1a578e9b
AC
2261x_after_update_window_line (desired_row)
2262 struct glyph_row *desired_row;
2263{
2264 struct window *w = updated_window;
e0f712ba
AC
2265 struct frame *f;
2266 int width, height;
2267
1a578e9b 2268 xassert (w);
177c0ea7 2269
1a578e9b 2270 if (!desired_row->mode_line_p && !w->pseudo_window_p)
6b61353c 2271 desired_row->redraw_fringe_bitmaps_p = 1;
1a578e9b 2272
e0f712ba
AC
2273 /* When a window has disappeared, make sure that no rest of
2274 full-width rows stays visible in the internal border. Could
2275 check here if updated_window is the leftmost/rightmost window,
2276 but I guess it's not worth doing since vertically split windows
2277 are almost never used, internal border is rarely set, and the
2278 overhead is very small. */
2279 if (windows_or_buffers_changed
2280 && desired_row->full_width_p
2281 && (f = XFRAME (w->frame),
2282 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2283 width != 0)
2284 && (height = desired_row->visible_height,
2285 height > 0))
2286 {
2287 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
95dfb192 2288
e0f712ba
AC
2289 /* Internal border is drawn below the tool bar. */
2290 if (WINDOWP (f->tool_bar_window)
2291 && w == XWINDOW (f->tool_bar_window))
2292 y -= width;
1a578e9b 2293
e0f712ba 2294 BLOCK_INPUT;
236072ae
YM
2295 mac_clear_area (f, 0, y, width, height);
2296 mac_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1a578e9b
AC
2297 UNBLOCK_INPUT;
2298 }
2299}
2300
2301
3f332ef3 2302/* Draw the bitmap WHICH in one of the left or right fringes of
1a578e9b
AC
2303 window W. ROW is the glyph row for which to display the bitmap; it
2304 determines the vertical position at which the bitmap has to be
2305 drawn. */
2306
2307static void
5958f265 2308x_draw_fringe_bitmap (w, row, p)
1a578e9b
AC
2309 struct window *w;
2310 struct glyph_row *row;
5958f265 2311 struct draw_fringe_bitmap_params *p;
1a578e9b
AC
2312{
2313 struct frame *f = XFRAME (WINDOW_FRAME (w));
2314 Display *display = FRAME_MAC_DISPLAY (f);
5958f265 2315 struct face *face = p->face;
6b61353c 2316 int rowY;
e855c5d8 2317 int overlay_p = p->overlay_p;
1a578e9b 2318
c6829f81 2319#ifdef MAC_OSX
e855c5d8 2320 if (!overlay_p)
c6829f81 2321 {
e855c5d8 2322 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
c6829f81
YM
2323
2324#if 0 /* MAC_TODO: stipple */
2325 /* In case the same realized face is used for fringes and
2326 for something displayed in the text (e.g. face `region' on
2327 mono-displays, the fill style may have been changed to
2328 FillSolid in x_draw_glyph_string_background. */
2329 if (face->stipple)
2330 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2331 else
2332 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2333#endif
2334
2335 /* If the fringe is adjacent to the left (right) scroll bar of a
2336 leftmost (rightmost, respectively) window, then extend its
2337 background to the gap between the fringe and the bar. */
2338 if ((WINDOW_LEFTMOST_P (w)
2339 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2340 || (WINDOW_RIGHTMOST_P (w)
2341 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2342 {
2343 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2344
2345 if (sb_width > 0)
2346 {
2347 int left = WINDOW_SCROLL_BAR_AREA_X (w);
2348 int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2349 * FRAME_COLUMN_WIDTH (f));
2350
e855c5d8
YM
2351 if (bx < 0
2352 && (left + width == p->x
2353 || p->x + p->wd == left))
2354 {
2355 /* Bitmap fills the fringe and we need background
2356 extension. */
2357 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2358
2359 bx = p->x;
2360 nx = p->wd;
2361 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2362 row->y));
2363 ny = row->visible_height;
2364 }
2365
511a18d9 2366 if (bx >= 0)
c6829f81 2367 {
511a18d9
YM
2368 if (left + width == bx)
2369 {
2370 bx = left + sb_width;
2371 nx += width - sb_width;
2372 }
2373 else if (bx + nx == left)
2374 nx += width - sb_width;
c6829f81 2375 }
c6829f81
YM
2376 }
2377 }
2378
e855c5d8
YM
2379 if (bx >= 0)
2380 {
2381 mac_erase_rectangle (f, face->gc, bx, by, nx, ny);
2382 /* The fringe background has already been filled. */
2383 overlay_p = 1;
2384 }
c6829f81
YM
2385
2386#if 0 /* MAC_TODO: stipple */
2387 if (!face->stipple)
2388 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2389#endif
2390 }
2391#endif /* MAC_OSX */
2392
1a578e9b 2393 /* Must clip because of partially visible lines. */
6b61353c
KH
2394 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2395 if (p->y < rowY)
2396 {
2397 /* Adjust position of "bottom aligned" bitmap on partially
2398 visible last row. */
2399 int oldY = row->y;
2400 int oldVH = row->visible_height;
2401 row->visible_height = p->h;
2402 row->y -= rowY - p->y;
236072ae 2403 x_clip_to_row (w, row, -1, face->gc);
6b61353c
KH
2404 row->y = oldY;
2405 row->visible_height = oldVH;
2406 }
2407 else
236072ae 2408 x_clip_to_row (w, row, -1, face->gc);
1a578e9b 2409
c6829f81 2410#ifndef MAC_OSX
6b61353c 2411 if (p->bx >= 0 && !p->overlay_p)
d33c49e8 2412 {
d33c49e8
KS
2413#if 0 /* MAC_TODO: stipple */
2414 /* In case the same realized face is used for fringes and
2415 for something displayed in the text (e.g. face `region' on
2416 mono-displays, the fill style may have been changed to
2417 FillSolid in x_draw_glyph_string_background. */
2418 if (face->stipple)
2419 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
2420 else
2421 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
2422#endif
2423
236072ae 2424 mac_erase_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
d33c49e8
KS
2425
2426#if 0 /* MAC_TODO: stipple */
2427 if (!face->stipple)
2428 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
2429#endif
2430 }
c6829f81 2431#endif /* !MAC_OSX */
d33c49e8 2432
ad21830e
YM
2433 if (p->which
2434#if USE_CG_DRAWING
2435 && p->which < max_fringe_bmp
2436#endif
2437 )
e0f712ba 2438 {
e4f5e019 2439 XGCValues gcv;
1a578e9b 2440
e4f5e019
YM
2441 XGetGCValues (display, face->gc, GCForeground, &gcv);
2442 XSetForeground (display, face->gc,
2443 (p->cursor_p
2444 ? (p->overlay_p ? face->background
2445 : f->output_data.mac->cursor_pixel)
2446 : face->foreground));
ad21830e
YM
2447#if USE_CG_DRAWING
2448 mac_draw_cg_image (fringe_bmp[p->which], f, face->gc, 0, p->dh,
e855c5d8 2449 p->wd, p->h, p->x, p->y, overlay_p);
ad21830e 2450#else
236072ae 2451 mac_draw_bitmap (f, face->gc, p->x, p->y,
e855c5d8 2452 p->wd, p->h, p->bits + p->dh, overlay_p);
ad21830e 2453#endif
e4f5e019 2454 XSetForeground (display, face->gc, gcv.foreground);
d33c49e8 2455 }
1a578e9b 2456
834263b6 2457 mac_reset_clip_rectangles (f, face->gc);
1a578e9b
AC
2458}
2459
ad21830e
YM
2460#if USE_CG_DRAWING
2461static void
2462mac_define_fringe_bitmap (which, bits, h, wd)
2463 int which;
2464 unsigned short *bits;
2465 int h, wd;
2466{
ad21830e
YM
2467 int i;
2468 CGDataProviderRef provider;
2469
2470 if (which >= max_fringe_bmp)
2471 {
2472 i = max_fringe_bmp;
2473 max_fringe_bmp = which + 20;
2474 fringe_bmp = (CGImageRef *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (CGImageRef));
2475 while (i < max_fringe_bmp)
2476 fringe_bmp[i++] = 0;
2477 }
2478
2479 for (i = 0; i < h; i++)
2480 bits[i] = ~bits[i];
cb91e86a
YM
2481
2482 BLOCK_INPUT;
2483
ad21830e
YM
2484 provider = CGDataProviderCreateWithData (NULL, bits,
2485 sizeof (unsigned short) * h, NULL);
2486 if (provider)
2487 {
2488 fringe_bmp[which] = CGImageMaskCreate (wd, h, 1, 1,
2489 sizeof (unsigned short),
2490 provider, NULL, 0);
2491 CGDataProviderRelease (provider);
2492 }
cb91e86a
YM
2493
2494 UNBLOCK_INPUT;
ad21830e
YM
2495}
2496
2497static void
2498mac_destroy_fringe_bitmap (which)
2499 int which;
2500{
2501 if (which >= max_fringe_bmp)
2502 return;
2503
2504 if (fringe_bmp[which])
cb91e86a
YM
2505 {
2506 BLOCK_INPUT;
2507 CGImageRelease (fringe_bmp[which]);
2508 UNBLOCK_INPUT;
2509 }
ad21830e
YM
2510 fringe_bmp[which] = 0;
2511}
2512#endif
1a578e9b 2513\f
95dfb192 2514
1a578e9b 2515/* This is called when starting Emacs and when restarting after
e0f712ba 2516 suspend. When starting Emacs, no window is mapped. And nothing
1a578e9b
AC
2517 must be done to Emacs's own window if it is suspended (though that
2518 rarely happens). */
2519
e0f712ba 2520static void
80ca7302 2521XTset_terminal_modes (struct terminal *t)
1a578e9b
AC
2522{
2523}
2524
2525/* This is called when exiting or suspending Emacs. Exiting will make
e0f712ba 2526 the windows go away, and suspending requires no action. */
1a578e9b 2527
e0f712ba 2528static void
80ca7302 2529XTreset_terminal_modes (struct terminal *t)
1a578e9b
AC
2530{
2531}
2532
95dfb192 2533
1a578e9b
AC
2534\f
2535/***********************************************************************
2536 Display Iterator
2537 ***********************************************************************/
2538
2539/* Function prototypes of this page. */
2540
1a578e9b 2541static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
cc02ceee
ST
2542static int mac_encode_char P_ ((int, XChar2b *, struct font_info *,
2543 struct charset *, int *));
1a578e9b
AC
2544
2545
458dbb8c
YM
2546static void
2547pcm_init (pcm, count)
2548 XCharStruct *pcm;
2549 int count;
2550{
2551 bzero (pcm, sizeof (XCharStruct) * count);
2552 while (--count >= 0)
2553 {
2554 pcm->descent = PCM_INVALID;
2555 pcm++;
2556 }
2557}
2558
2559static enum pcm_status
2560pcm_get_status (pcm)
369a7a37 2561 const XCharStruct *pcm;
458dbb8c
YM
2562{
2563 int height = pcm->ascent + pcm->descent;
2564
2565 /* Negative height means some special status. */
2566 return height >= 0 ? PCM_VALID : height;
2567}
2568
1a578e9b
AC
2569/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
2570 is not contained in the font. */
2571
2572static INLINE XCharStruct *
2573x_per_char_metric (font, char2b)
2574 XFontStruct *font;
2575 XChar2b *char2b;
2576{
2577 /* The result metric information. */
2578 XCharStruct *pcm = NULL;
2579
2580 xassert (font && char2b);
2581
c3bd8190
YM
2582#if USE_ATSUI
2583 if (font->mac_style)
2584 {
458dbb8c 2585 XCharStruct **row = font->bounds.rows + char2b->byte1;
b73e4d84
YM
2586
2587 if (*row == NULL)
c3bd8190 2588 {
458dbb8c
YM
2589 *row = xmalloc (sizeof (XCharStruct) * 0x100);
2590 pcm_init (*row, 0x100);
c3bd8190 2591 }
458dbb8c
YM
2592 pcm = *row + char2b->byte2;
2593 if (pcm_get_status (pcm) != PCM_VALID)
c3bd8190 2594 {
b96fe6ea
YM
2595 BLOCK_INPUT;
2596 mac_query_char_extents (font->mac_style,
2597 (char2b->byte1 << 8) + char2b->byte2,
2598 NULL, NULL, pcm, NULL);
2599 UNBLOCK_INPUT;
c3bd8190
YM
2600 }
2601 }
2602 else
2603 {
2604#endif
b73e4d84 2605 if (font->bounds.per_char != NULL)
1a578e9b
AC
2606 {
2607 if (font->min_byte1 == 0 && font->max_byte1 == 0)
2608 {
2609 /* min_char_or_byte2 specifies the linear character index
2610 corresponding to the first element of the per_char array,
2611 max_char_or_byte2 is the index of the last character. A
2612 character with non-zero CHAR2B->byte1 is not in the font.
2613 A character with byte2 less than min_char_or_byte2 or
2614 greater max_char_or_byte2 is not in the font. */
2615 if (char2b->byte1 == 0
2616 && char2b->byte2 >= font->min_char_or_byte2
2617 && char2b->byte2 <= font->max_char_or_byte2)
b73e4d84
YM
2618 pcm = font->bounds.per_char
2619 + (char2b->byte2 - font->min_char_or_byte2);
1a578e9b
AC
2620 }
2621 else
2622 {
2623 /* If either min_byte1 or max_byte1 are nonzero, both
2624 min_char_or_byte2 and max_char_or_byte2 are less than
2625 256, and the 2-byte character index values corresponding
2626 to the per_char array element N (counting from 0) are:
2627
2628 byte1 = N/D + min_byte1
2629 byte2 = N\D + min_char_or_byte2
2630
2631 where:
2632
2633 D = max_char_or_byte2 - min_char_or_byte2 + 1
2634 / = integer division
2635 \ = integer modulus */
2636 if (char2b->byte1 >= font->min_byte1
2637 && char2b->byte1 <= font->max_byte1
2638 && char2b->byte2 >= font->min_char_or_byte2
2639 && char2b->byte2 <= font->max_char_or_byte2)
2640 {
b73e4d84 2641 pcm = (font->bounds.per_char
1a578e9b
AC
2642 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
2643 * (char2b->byte1 - font->min_byte1))
2644 + (char2b->byte2 - font->min_char_or_byte2));
2645 }
2646 }
2647 }
2648 else
2649 {
2650 /* If the per_char pointer is null, all glyphs between the first
2651 and last character indexes inclusive have the same
2652 information, as given by both min_bounds and max_bounds. */
2653 if (char2b->byte2 >= font->min_char_or_byte2
2654 && char2b->byte2 <= font->max_char_or_byte2)
2655 pcm = &font->max_bounds;
2656 }
c3bd8190
YM
2657#if USE_ATSUI
2658 }
2659#endif
1a578e9b
AC
2660
2661 return ((pcm == NULL
a0c62ca2
YM
2662 || (pcm->width == 0
2663#if 0 /* Show hollow boxes for zero-width glyphs such as combining diacritics. */
2664 && (pcm->rbearing - pcm->lbearing) == 0
2665#endif
2666 ))
1a578e9b
AC
2667 ? NULL : pcm);
2668}
2669
750fc673
KS
2670/* RIF:
2671 */
2672
2673static XCharStruct *
2674mac_per_char_metric (font, char2b, font_type)
2675 XFontStruct *font;
2676 XChar2b *char2b;
2677 int font_type;
2678{
2679 return x_per_char_metric (font, char2b);
2680}
1a578e9b 2681
750fc673
KS
2682/* RIF:
2683 Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1a578e9b
AC
2684 the two-byte form of C. Encoding is returned in *CHAR2B. */
2685
750fc673 2686static int
cc02ceee 2687mac_encode_char (c, char2b, font_info, charset, two_byte_p)
1a578e9b
AC
2688 int c;
2689 XChar2b *char2b;
2690 struct font_info *font_info;
cc02ceee 2691 struct charset *charset;
750fc673 2692 int *two_byte_p;
1a578e9b 2693{
1a578e9b
AC
2694 XFontStruct *font = font_info->font;
2695
2696 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
2697 This may be either a program in a special encoder language or a
2698 fixed encoding. */
2699 if (font_info->font_encoder)
2700 {
2701 /* It's a program. */
2702 struct ccl_program *ccl = font_info->font_encoder;
2703
dd15724d 2704 check_ccl_update (ccl);
1a578e9b
AC
2705 if (CHARSET_DIMENSION (charset) == 1)
2706 {
cc02ceee
ST
2707 ccl->reg[0] = CHARSET_ID (charset);
2708 ccl->reg[1] = XCHAR2B_BYTE2 (char2b);
2709 ccl->reg[2] = -1;
1a578e9b
AC
2710 }
2711 else
2712 {
cc02ceee
ST
2713 ccl->reg[0] = CHARSET_ID (charset);
2714 ccl->reg[1] = XCHAR2B_BYTE1 (char2b);
2715 ccl->reg[2] = XCHAR2B_BYTE2 (char2b);
1a578e9b 2716 }
177c0ea7 2717
6abfb022 2718 ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
177c0ea7 2719
1a578e9b
AC
2720 /* We assume that MSBs are appropriately set/reset by CCL
2721 program. */
2722 if (font->max_byte1 == 0) /* 1-byte font */
cc02ceee 2723 STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
1a578e9b 2724 else
cc02ceee 2725 STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
1a578e9b 2726 }
cc02ceee 2727 else if (font_info->encoding_type)
1a578e9b
AC
2728 {
2729 /* Fixed encoding scheme. See fontset.h for the meaning of the
2730 encoding numbers. */
cc02ceee 2731 unsigned char enc = font_info->encoding_type;
177c0ea7 2732
1a578e9b
AC
2733 if ((enc == 1 || enc == 2)
2734 && CHARSET_DIMENSION (charset) == 2)
2735 char2b->byte1 |= 0x80;
177c0ea7 2736
1a578e9b
AC
2737 if (enc == 1 || enc == 3)
2738 char2b->byte2 |= 0x80;
2739
2740 if (enc == 4)
6abfb022
YM
2741 {
2742 int code = (char2b->byte1 << 8) | char2b->byte2;
1a578e9b 2743
6abfb022
YM
2744 JIS_TO_SJIS (code);
2745 STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
2746 }
1a578e9b 2747 }
1a578e9b
AC
2748
2749 if (two_byte_p)
750fc673 2750 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
1a578e9b 2751
750fc673 2752 return FONT_TYPE_UNKNOWN;
1a578e9b
AC
2753}
2754
2755
1a578e9b
AC
2756\f
2757/***********************************************************************
2758 Glyph display
2759 ***********************************************************************/
2760
1a578e9b 2761
95dfb192 2762
1a578e9b
AC
2763static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2764static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2765static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2766 int));
2767static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2768static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
2769static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2770static void x_draw_glyph_string P_ ((struct glyph_string *));
95dfb192 2771static void mac_compute_glyph_string_overhangs P_ ((struct glyph_string *));
1a578e9b
AC
2772static void x_set_cursor_gc P_ ((struct glyph_string *));
2773static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2774static void x_set_mouse_face_gc P_ ((struct glyph_string *));
e0f712ba
AC
2775/*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2776 unsigned long *, double, int));*/
1a578e9b
AC
2777static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2778 double, int, unsigned long));
2779static void x_setup_relief_colors P_ ((struct glyph_string *));
2780static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2781static void x_draw_image_relief P_ ((struct glyph_string *));
2782static void x_draw_image_foreground P_ ((struct glyph_string *));
1a578e9b
AC
2783static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2784 int, int, int));
2785static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
ffe8b3f4
KS
2786 int, int, int, int, int, int,
2787 Rect *));
1a578e9b 2788static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
e0f712ba 2789 int, int, int, Rect *));
1a578e9b
AC
2790
2791#if GLYPH_DEBUG
2792static void x_check_font P_ ((struct frame *, XFontStruct *));
2793#endif
2794
177c0ea7 2795
1a578e9b
AC
2796/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2797 face. */
2798
2799static void
2800x_set_cursor_gc (s)
2801 struct glyph_string *s;
2802{
2803 if (s->font == FRAME_FONT (s->f)
2804 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2805 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2806 && !s->cmp)
2807 s->gc = s->f->output_data.mac->cursor_gc;
2808 else
2809 {
2810 /* Cursor on non-default face: must merge. */
2811 XGCValues xgcv;
2812 unsigned long mask;
2813
2814 xgcv.background = s->f->output_data.mac->cursor_pixel;
2815 xgcv.foreground = s->face->background;
2816
2817 /* If the glyph would be invisible, try a different foreground. */
2818 if (xgcv.foreground == xgcv.background)
2819 xgcv.foreground = s->face->foreground;
2820 if (xgcv.foreground == xgcv.background)
2821 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
2822 if (xgcv.foreground == xgcv.background)
2823 xgcv.foreground = s->face->foreground;
2824
2825 /* Make sure the cursor is distinct from text in this face. */
2826 if (xgcv.background == s->face->background
2827 && xgcv.foreground == s->face->foreground)
2828 {
2829 xgcv.background = s->face->foreground;
2830 xgcv.foreground = s->face->background;
2831 }
2832
2833 IF_DEBUG (x_check_font (s->f, s->font));
2834 xgcv.font = s->font;
2835 mask = GCForeground | GCBackground | GCFont;
2836
2837 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2838 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2839 mask, &xgcv);
2840 else
2841 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2842 = XCreateGC (s->display, s->window, mask, &xgcv);
2843
2844 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2845 }
2846}
2847
2848
2849/* Set up S->gc of glyph string S for drawing text in mouse face. */
177c0ea7 2850
1a578e9b
AC
2851static void
2852x_set_mouse_face_gc (s)
2853 struct glyph_string *s;
177c0ea7 2854{
1a578e9b
AC
2855 int face_id;
2856 struct face *face;
2857
e0f712ba 2858 /* What face has to be used last for the mouse face? */
1a578e9b
AC
2859 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2860 face = FACE_FROM_ID (s->f, face_id);
e0f712ba
AC
2861 if (face == NULL)
2862 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
177c0ea7 2863
1a578e9b 2864 if (s->first_glyph->type == CHAR_GLYPH)
fda2f91b 2865 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1a578e9b 2866 else
fda2f91b 2867 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1a578e9b
AC
2868 s->face = FACE_FROM_ID (s->f, face_id);
2869 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2870
2871 /* If font in this face is same as S->font, use it. */
2872 if (s->font == s->face->font)
2873 s->gc = s->face->gc;
2874 else
2875 {
2876 /* Otherwise construct scratch_cursor_gc with values from FACE
2877 but font FONT. */
2878 XGCValues xgcv;
2879 unsigned long mask;
177c0ea7 2880
1a578e9b
AC
2881 xgcv.background = s->face->background;
2882 xgcv.foreground = s->face->foreground;
2883 IF_DEBUG (x_check_font (s->f, s->font));
2884 xgcv.font = s->font;
2885 mask = GCForeground | GCBackground | GCFont;
177c0ea7 2886
1a578e9b
AC
2887 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2888 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2889 mask, &xgcv);
2890 else
2891 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
2892 = XCreateGC (s->display, s->window, mask, &xgcv);
177c0ea7 2893
1a578e9b
AC
2894 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2895 }
2896
2897 xassert (s->gc != 0);
2898}
2899
2900
2901/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2902 Faces to use in the mode line have already been computed when the
2903 matrix was built, so there isn't much to do, here. */
2904
2905static INLINE void
2906x_set_mode_line_face_gc (s)
2907 struct glyph_string *s;
177c0ea7 2908{
1a578e9b
AC
2909 s->gc = s->face->gc;
2910}
2911
2912
2913/* Set S->gc of glyph string S for drawing that glyph string. Set
2914 S->stippled_p to a non-zero value if the face of S has a stipple
2915 pattern. */
2916
2917static INLINE void
2918x_set_glyph_string_gc (s)
2919 struct glyph_string *s;
2920{
2921 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
177c0ea7 2922
1a578e9b
AC
2923 if (s->hl == DRAW_NORMAL_TEXT)
2924 {
2925 s->gc = s->face->gc;
2926 s->stippled_p = s->face->stipple != 0;
2927 }
2928 else if (s->hl == DRAW_INVERSE_VIDEO)
2929 {
2930 x_set_mode_line_face_gc (s);
2931 s->stippled_p = s->face->stipple != 0;
2932 }
2933 else if (s->hl == DRAW_CURSOR)
2934 {
2935 x_set_cursor_gc (s);
2936 s->stippled_p = 0;
2937 }
2938 else if (s->hl == DRAW_MOUSE_FACE)
2939 {
2940 x_set_mouse_face_gc (s);
2941 s->stippled_p = s->face->stipple != 0;
2942 }
2943 else if (s->hl == DRAW_IMAGE_RAISED
2944 || s->hl == DRAW_IMAGE_SUNKEN)
2945 {
2946 s->gc = s->face->gc;
2947 s->stippled_p = s->face->stipple != 0;
2948 }
2949 else
2950 {
2951 s->gc = s->face->gc;
2952 s->stippled_p = s->face->stipple != 0;
2953 }
2954
2955 /* GC must have been set. */
2956 xassert (s->gc != 0);
2957}
2958
2959
1a578e9b
AC
2960/* Set clipping for output of glyph string S. S may be part of a mode
2961 line or menu if we don't have X toolkit support. */
2962
2963static INLINE void
2964x_set_glyph_string_clipping (s)
2965 struct glyph_string *s;
2966{
1c4ac540
YM
2967 Rect rects[MAX_CLIP_RECTS];
2968 int n;
2969
2970 n = get_glyph_string_clip_rects (s, rects, MAX_CLIP_RECTS);
834263b6 2971 mac_set_clip_rectangles (s->f, s->gc, rects, n);
1a578e9b
AC
2972}
2973
2974
750fc673
KS
2975/* RIF:
2976 Compute left and right overhang of glyph string S. If S is a glyph
1a578e9b
AC
2977 string for a composition, assume overhangs don't exist. */
2978
750fc673
KS
2979static void
2980mac_compute_glyph_string_overhangs (s)
1a578e9b
AC
2981 struct glyph_string *s;
2982{
f93e4d4f
YM
2983 if (!(s->cmp == NULL
2984 && s->first_glyph->type == CHAR_GLYPH))
2985 return;
2986
2987 if (!s->two_byte_p
c3bd8190 2988#if USE_ATSUI
f93e4d4f 2989 || s->font->mac_style
b73e4d84 2990#endif
f93e4d4f
YM
2991 )
2992 {
2993 XCharStruct cs;
c3bd8190 2994
f93e4d4f
YM
2995 mac_text_extents_16 (s->font, s->char2b, s->nchars, &cs);
2996 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2997 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2998 }
2999 else
3000 {
3001 Rect r;
3002 MacFontStruct *font = s->font;
c3bd8190 3003
444a42fd
YM
3004#if USE_CG_DRAWING
3005 mac_prepare_for_quickdraw (s->f);
3006#endif
3007 SetPortWindowPort (FRAME_MAC_WINDOW (s->f));
3008
f93e4d4f
YM
3009 TextFont (font->mac_fontnum);
3010 TextSize (font->mac_fontsize);
3011 TextFace (font->mac_fontface);
95085023 3012
f93e4d4f 3013 QDTextBounds (s->nchars * 2, (char *)s->char2b, &r);
8c2da0fa 3014
f93e4d4f
YM
3015 s->right_overhang = r.right > s->width ? r.right - s->width : 0;
3016 s->left_overhang = r.left < 0 ? -r.left : 0;
3017 }
1a578e9b
AC
3018}
3019
3020
3021/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3022
3023static INLINE void
3024x_clear_glyph_string_rect (s, x, y, w, h)
3025 struct glyph_string *s;
3026 int x, y, w, h;
3027{
236072ae 3028 mac_erase_rectangle (s->f, s->gc, x, y, w, h);
1a578e9b
AC
3029}
3030
3031
3032/* Draw the background of glyph_string S. If S->background_filled_p
3033 is non-zero don't draw it. FORCE_P non-zero means draw the
3034 background even if it wouldn't be drawn normally. This is used
3035 when a string preceding S draws into the background of S, or S
3036 contains the first component of a composition. */
3037
3038static void
3039x_draw_glyph_string_background (s, force_p)
3040 struct glyph_string *s;
3041 int force_p;
3042{
3043 /* Nothing to do if background has already been drawn or if it
3044 shouldn't be drawn in the first place. */
3045 if (!s->background_filled_p)
3046 {
e0f712ba
AC
3047 int box_line_width = max (s->face->box_line_width, 0);
3048
1a578e9b
AC
3049#if 0 /* MAC_TODO: stipple */
3050 if (s->stippled_p)
3051 {
3052 /* Fill background with a stipple pattern. */
3053 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3054 XFillRectangle (s->display, s->window, s->gc, s->x,
e0f712ba 3055 s->y + box_line_width,
1a578e9b 3056 s->background_width,
e0f712ba 3057 s->height - 2 * box_line_width);
1a578e9b
AC
3058 XSetFillStyle (s->display, s->gc, FillSolid);
3059 s->background_filled_p = 1;
3060 }
3061 else
3062#endif
e0f712ba 3063 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1a578e9b
AC
3064 || s->font_not_found_p
3065 || s->extends_to_end_of_line_p
3066 || force_p)
3067 {
e0f712ba 3068 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1a578e9b 3069 s->background_width,
e0f712ba 3070 s->height - 2 * box_line_width);
1a578e9b
AC
3071 s->background_filled_p = 1;
3072 }
3073 }
3074}
3075
3076
3077/* Draw the foreground of glyph string S. */
3078
3079static void
3080x_draw_glyph_string_foreground (s)
3081 struct glyph_string *s;
3082{
9fb446e3 3083 int i, x, bg_width;
1a578e9b
AC
3084
3085 /* If first glyph of S has a left box line, start drawing the text
3086 of S to the right of that box line. */
3087 if (s->face->box != FACE_NO_BOX
3088 && s->first_glyph->left_box_line_p)
1ea40aa2 3089 x = s->x + eabs (s->face->box_line_width);
1a578e9b
AC
3090 else
3091 x = s->x;
3092
3093 /* Draw characters of S as rectangles if S's font could not be
3094 loaded. */
3095 if (s->font_not_found_p)
3096 {
3097 for (i = 0; i < s->nchars; ++i)
3098 {
3099 struct glyph *g = s->first_glyph + i;
236072ae
YM
3100 mac_draw_rectangle (s->f, s->gc, x, s->y,
3101 g->pixel_width - 1, s->height - 1);
1a578e9b
AC
3102 x += g->pixel_width;
3103 }
3104 }
3105 else
3106 {
3107 char *char1b = (char *) s->char2b;
3108 int boff = s->font_info->baseline_offset;
3109
3110 if (s->font_info->vertical_centering)
3111 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3112
3113 /* If we can use 8-bit functions, condense S->char2b. */
c3bd8190
YM
3114 if (!s->two_byte_p
3115#if USE_ATSUI
3116 && GC_FONT (s->gc)->mac_style == NULL
3117#endif
3118 )
1a578e9b
AC
3119 for (i = 0; i < s->nchars; ++i)
3120 char1b[i] = s->char2b[i].byte2;
3121
3122 /* Draw text with XDrawString if background has already been
3123 filled. Otherwise, use XDrawImageString. (Note that
3124 XDrawImageString is usually faster than XDrawString.) Always
3125 use XDrawImageString when drawing the cursor so that there is
3126 no chance that characters under a box cursor are invisible. */
c2ded1b7 3127 if (s->for_overlaps
1a578e9b 3128 || (s->background_filled_p && s->hl != DRAW_CURSOR))
9fb446e3
YM
3129 bg_width = 0; /* Corresponds to XDrawString. */
3130 else
3131 bg_width = s->background_width; /* Corresponds to XDrawImageString. */
3132
3133 if (s->two_byte_p
c3bd8190 3134#if USE_ATSUI
9fb446e3 3135 || GC_FONT (s->gc)->mac_style
c3bd8190 3136#endif
9fb446e3 3137 )
16805b2e 3138#if USE_CG_TEXT_DRAWING
9fb446e3
YM
3139 if (!s->two_byte_p
3140 && mac_draw_image_string_cg (s->f, s->gc, x, s->ybase - boff,
bb420759
YM
3141 s->char2b, s->nchars, bg_width,
3142 s->face->overstrike))
9fb446e3
YM
3143 ;
3144 else
16805b2e 3145#endif
9fb446e3 3146 mac_draw_image_string_16 (s->f, s->gc, x, s->ybase - boff,
bb420759
YM
3147 s->char2b, s->nchars, bg_width,
3148 s->face->overstrike);
1a578e9b 3149 else
9fb446e3 3150 mac_draw_image_string (s->f, s->gc, x, s->ybase - boff,
bb420759
YM
3151 char1b, s->nchars, bg_width,
3152 s->face->overstrike);
1a578e9b
AC
3153 }
3154}
3155
3156/* Draw the foreground of composite glyph string S. */
3157
3158static void
3159x_draw_composite_glyph_string_foreground (s)
3160 struct glyph_string *s;
3161{
3162 int i, x;
3163
3164 /* If first glyph of S has a left box line, start drawing the text
3165 of S to the right of that box line. */
3166 if (s->face->box != FACE_NO_BOX
3167 && s->first_glyph->left_box_line_p)
1ea40aa2 3168 x = s->x + eabs (s->face->box_line_width);
1a578e9b
AC
3169 else
3170 x = s->x;
3171
3172 /* S is a glyph string for a composition. S->gidx is the index of
3173 the first character drawn for glyphs of this composition.
3174 S->gidx == 0 means we are drawing the very first character of
3175 this composition. */
3176
3177 /* Draw a rectangle for the composition if the font for the very
3178 first character of the composition could not be loaded. */
3179 if (s->font_not_found_p)
3180 {
3181 if (s->gidx == 0)
236072ae
YM
3182 mac_draw_rectangle (s->f, s->gc, x, s->y,
3183 s->width - 1, s->height - 1);
1a578e9b
AC
3184 }
3185 else
3186 {
3187 for (i = 0; i < s->nchars; i++, ++s->gidx)
83cc8d35
YM
3188 if (mac_per_char_metric (GC_FONT (s->gc), s->char2b + i, 0) == NULL)
3189 /* This is a nonexistent or zero-width glyph such as a
3190 combining diacritic. Draw a rectangle. */
3191 mac_draw_rectangle (s->f, s->gc,
3192 x + s->cmp->offsets[s->gidx * 2], s->y,
3193 FONT_WIDTH (GC_FONT (s->gc)) - 1, s->height - 1);
3194 else
3195 mac_draw_image_string_16 (s->f, s->gc,
3196 x + s->cmp->offsets[s->gidx * 2],
3197 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3198 s->char2b + i, 1, 0, s->face->overstrike);
1a578e9b
AC
3199 }
3200}
3201
3202
3203#ifdef USE_X_TOOLKIT
3204
3205static struct frame *x_frame_of_widget P_ ((Widget));
3206
3207
3208/* Return the frame on which widget WIDGET is used.. Abort if frame
3209 cannot be determined. */
3210
3211static struct frame *
3212x_frame_of_widget (widget)
3213 Widget widget;
3214{
3215 struct x_display_info *dpyinfo;
3216 Lisp_Object tail;
3217 struct frame *f;
177c0ea7 3218
1a578e9b 3219 dpyinfo = x_display_info_for_display (XtDisplay (widget));
177c0ea7 3220
1a578e9b
AC
3221 /* Find the top-level shell of the widget. Note that this function
3222 can be called when the widget is not yet realized, so XtWindow
3223 (widget) == 0. That's the reason we can't simply use
3224 x_any_window_to_frame. */
3225 while (!XtIsTopLevelShell (widget))
3226 widget = XtParent (widget);
3227
3228 /* Look for a frame with that top-level widget. Allocate the color
3229 on that frame to get the right gamma correction value. */
8e50cc2d
SM
3230 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
3231 if (FRAMEP (XCAR (tail))
1a578e9b
AC
3232 && (f = XFRAME (XCAR (tail)),
3233 (f->output_data.nothing != 1
3234 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3235 && f->output_data.x->widget == widget)
3236 return f;
3237
3238 abort ();
3239}
3240
3241
3242/* Allocate the color COLOR->pixel on the screen and display of
3243 widget WIDGET in colormap CMAP. If an exact match cannot be
3244 allocated, try the nearest color available. Value is non-zero
3245 if successful. This is called from lwlib. */
3246
3247int
3248x_alloc_nearest_color_for_widget (widget, cmap, color)
3249 Widget widget;
3250 Colormap cmap;
3251 XColor *color;
3252{
3253 struct frame *f = x_frame_of_widget (widget);
3254 return x_alloc_nearest_color (f, cmap, color);
3255}
3256
3257
3258#endif /* USE_X_TOOLKIT */
3259
e0f712ba 3260#if 0 /* MAC_TODO */
1a578e9b
AC
3261
3262/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3263 CMAP. If an exact match can't be allocated, try the nearest color
3264 available. Value is non-zero if successful. Set *COLOR to the
3265 color allocated. */
3266
3267int
3268x_alloc_nearest_color (f, cmap, color)
3269 struct frame *f;
3270 Colormap cmap;
3271 XColor *color;
3272{
3273 Display *display = FRAME_X_DISPLAY (f);
3274 Screen *screen = FRAME_X_SCREEN (f);
3275 int rc;
3276
3277 gamma_correct (f, color);
3278 rc = XAllocColor (display, cmap, color);
3279 if (rc == 0)
3280 {
3281 /* If we got to this point, the colormap is full, so we're going
3282 to try to get the next closest color. The algorithm used is
3283 a least-squares matching, which is what X uses for closest
3284 color matching with StaticColor visuals. */
3285 int nearest, i;
3286 unsigned long nearest_delta = ~0;
3287 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3288 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3289
3290 for (i = 0; i < ncells; ++i)
3291 cells[i].pixel = i;
3292 XQueryColors (display, cmap, cells, ncells);
3293
3294 for (nearest = i = 0; i < ncells; ++i)
3295 {
3296 long dred = (color->red >> 8) - (cells[i].red >> 8);
3297 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3298 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3299 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3300
3301 if (delta < nearest_delta)
3302 {
3303 nearest = i;
3304 nearest_delta = delta;
3305 }
3306 }
177c0ea7 3307
1a578e9b
AC
3308 color->red = cells[nearest].red;
3309 color->green = cells[nearest].green;
3310 color->blue = cells[nearest].blue;
3311 rc = XAllocColor (display, cmap, color);
3312 }
3313
3314#ifdef DEBUG_X_COLORS
3315 if (rc)
3316 register_color (color->pixel);
3317#endif /* DEBUG_X_COLORS */
177c0ea7 3318
1a578e9b
AC
3319 return rc;
3320}
3321
3322
3323/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3324 It's necessary to do this instead of just using PIXEL directly to
3325 get color reference counts right. */
3326
3327unsigned long
3328x_copy_color (f, pixel)
3329 struct frame *f;
3330 unsigned long pixel;
3331{
3332 XColor color;
3333
3334 color.pixel = pixel;
3335 BLOCK_INPUT;
3336 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3337 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3338 UNBLOCK_INPUT;
3339#ifdef DEBUG_X_COLORS
3340 register_color (pixel);
3341#endif
3342 return color.pixel;
3343}
3344
3345
3346/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3347 It's necessary to do this instead of just using PIXEL directly to
3348 get color reference counts right. */
3349
3350unsigned long
3351x_copy_dpy_color (dpy, cmap, pixel)
3352 Display *dpy;
3353 Colormap cmap;
3354 unsigned long pixel;
3355{
3356 XColor color;
3357
3358 color.pixel = pixel;
3359 BLOCK_INPUT;
3360 XQueryColor (dpy, cmap, &color);
3361 XAllocColor (dpy, cmap, &color);
3362 UNBLOCK_INPUT;
3363#ifdef DEBUG_X_COLORS
3364 register_color (pixel);
3365#endif
3366 return color.pixel;
3367}
3368
e0f712ba 3369#endif /* MAC_TODO */
1a578e9b 3370
6b61353c
KH
3371
3372/* Brightness beyond which a color won't have its highlight brightness
3373 boosted.
3374
3375 Nominally, highlight colors for `3d' faces are calculated by
3376 brightening an object's color by a constant scale factor, but this
3377 doesn't yield good results for dark colors, so for colors who's
3378 brightness is less than this value (on a scale of 0-255) have to
3379 use an additional additive factor.
3380
3381 The value here is set so that the default menu-bar/mode-line color
3382 (grey75) will not have its highlights changed at all. */
3383#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
3384
3385
1a578e9b
AC
3386/* Allocate a color which is lighter or darker than *COLOR by FACTOR
3387 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3388 If this produces the same color as COLOR, try a color where all RGB
3389 values have DELTA added. Return the allocated color in *COLOR.
3390 DISPLAY is the X display, CMAP is the colormap to operate on.
3391 Value is non-zero if successful. */
3392
3393static int
3394mac_alloc_lighter_color (f, color, factor, delta)
3395 struct frame *f;
3396 unsigned long *color;
3397 double factor;
3398 int delta;
3399{
3400 unsigned long new;
6b61353c
KH
3401 long bright;
3402
3403 /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */
3404 delta /= 256;
1a578e9b
AC
3405
3406 /* Change RGB values by specified FACTOR. Avoid overflow! */
3407 xassert (factor >= 0);
3408 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3409 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3410 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
6b61353c
KH
3411
3412 /* Calculate brightness of COLOR. */
3413 bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color)
3414 + BLUE_FROM_ULONG (*color)) / 6;
3415
3416 /* We only boost colors that are darker than
3417 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3418 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3419 /* Make an additive adjustment to NEW, because it's dark enough so
3420 that scaling by FACTOR alone isn't enough. */
3421 {
3422 /* How far below the limit this color is (0 - 1, 1 being darker). */
3423 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3424 /* The additive adjustment. */
3425 int min_delta = delta * dimness * factor / 2;
3426
3427 if (factor < 1)
3428 new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)),
3429 max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)),
3430 max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta)));
3431 else
3432 new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))),
3433 max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))),
3434 max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color)))));
3435 }
3436
1a578e9b
AC
3437 if (new == *color)
3438 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3439 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3440 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3441
3442 /* MAC_TODO: Map to palette and retry with delta if same? */
3443 /* MAC_TODO: Free colors (if using palette)? */
3444
3445 if (new == *color)
3446 return 0;
3447
3448 *color = new;
3449
3450 return 1;
3451}
3452
3453
3454/* Set up the foreground color for drawing relief lines of glyph
3455 string S. RELIEF is a pointer to a struct relief containing the GC
3456 with which lines will be drawn. Use a color that is FACTOR or
3457 DELTA lighter or darker than the relief's background which is found
3458 in S->f->output_data.x->relief_background. If such a color cannot
3459 be allocated, use DEFAULT_PIXEL, instead. */
177c0ea7 3460
1a578e9b
AC
3461static void
3462x_setup_relief_color (f, relief, factor, delta, default_pixel)
3463 struct frame *f;
3464 struct relief *relief;
3465 double factor;
3466 int delta;
3467 unsigned long default_pixel;
3468{
3469 XGCValues xgcv;
3470 struct mac_output *di = f->output_data.mac;
3471 unsigned long mask = GCForeground;
3472 unsigned long pixel;
3473 unsigned long background = di->relief_background;
3474 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3475
3476 /* MAC_TODO: Free colors (if using palette)? */
3477
3478 /* Allocate new color. */
3479 xgcv.foreground = default_pixel;
3480 pixel = background;
6b61353c
KH
3481 if (dpyinfo->n_planes != 1
3482 && mac_alloc_lighter_color (f, &pixel, factor, delta))
1a578e9b
AC
3483 {
3484 relief->allocated_p = 1;
3485 xgcv.foreground = relief->pixel = pixel;
3486 }
177c0ea7 3487
1a578e9b
AC
3488 if (relief->gc == 0)
3489 {
3490#if 0 /* MAC_TODO: stipple */
3491 xgcv.stipple = dpyinfo->gray;
3492 mask |= GCStipple;
3493#endif
3494 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3495 }
3496 else
3497 XChangeGC (NULL, relief->gc, mask, &xgcv);
3498}
3499
3500
3501/* Set up colors for the relief lines around glyph string S. */
3502
3503static void
3504x_setup_relief_colors (s)
3505 struct glyph_string *s;
3506{
3507 struct mac_output *di = s->f->output_data.mac;
3508 unsigned long color;
3509
3510 if (s->face->use_box_color_for_shadows_p)
3511 color = s->face->box_color;
6b61353c
KH
3512 else if (s->first_glyph->type == IMAGE_GLYPH
3513 && s->img->pixmap
3514 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3515 color = IMAGE_BACKGROUND (s->img, s->f, 0);
1a578e9b
AC
3516 else
3517 {
3518 XGCValues xgcv;
177c0ea7 3519
1a578e9b
AC
3520 /* Get the background color of the face. */
3521 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3522 color = xgcv.background;
3523 }
3524
3525 if (di->white_relief.gc == 0
3526 || color != di->relief_background)
3527 {
3528 di->relief_background = color;
3529 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3530 WHITE_PIX_DEFAULT (s->f));
3531 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3532 BLACK_PIX_DEFAULT (s->f));
3533 }
3534}
3535
3536
3537/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3538 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3539 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3540 relief. LEFT_P non-zero means draw a relief on the left side of
3541 the rectangle. RIGHT_P non-zero means draw a relief on the right
3542 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3543 when drawing. */
3544
3545static void
3546x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
ffe8b3f4 3547 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
1a578e9b 3548 struct frame *f;
ffe8b3f4
KS
3549 int left_x, top_y, right_x, bottom_y, width;
3550 int top_p, bot_p, left_p, right_p, raised_p;
1a578e9b
AC
3551 Rect *clip_rect;
3552{
6b61353c 3553 Display *dpy = FRAME_MAC_DISPLAY (f);
1a578e9b
AC
3554 int i;
3555 GC gc;
177c0ea7 3556
1a578e9b
AC
3557 if (raised_p)
3558 gc = f->output_data.mac->white_relief.gc;
3559 else
3560 gc = f->output_data.mac->black_relief.gc;
834263b6 3561 mac_set_clip_rectangles (f, gc, clip_rect, 1);
1a578e9b
AC
3562
3563 /* Top. */
ffe8b3f4
KS
3564 if (top_p)
3565 for (i = 0; i < width; ++i)
236072ae
YM
3566 mac_draw_line (f, gc,
3567 left_x + i * left_p, top_y + i,
458dbb8c 3568 right_x + 1 - i * right_p, top_y + i);
1a578e9b
AC
3569
3570 /* Left. */
3571 if (left_p)
3572 for (i = 0; i < width; ++i)
236072ae 3573 mac_draw_line (f, gc,
458dbb8c 3574 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
1a578e9b 3575
834263b6 3576 mac_reset_clip_rectangles (f, gc);
1a578e9b
AC
3577 if (raised_p)
3578 gc = f->output_data.mac->black_relief.gc;
3579 else
3580 gc = f->output_data.mac->white_relief.gc;
834263b6 3581 mac_set_clip_rectangles (f, gc, clip_rect, 1);
177c0ea7 3582
1a578e9b 3583 /* Bottom. */
ffe8b3f4
KS
3584 if (bot_p)
3585 for (i = 0; i < width; ++i)
236072ae
YM
3586 mac_draw_line (f, gc,
3587 left_x + i * left_p, bottom_y - i,
458dbb8c 3588 right_x + 1 - i * right_p, bottom_y - i);
177c0ea7 3589
1a578e9b
AC
3590 /* Right. */
3591 if (right_p)
3592 for (i = 0; i < width; ++i)
236072ae 3593 mac_draw_line (f, gc,
458dbb8c 3594 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
1a578e9b 3595
834263b6 3596 mac_reset_clip_rectangles (f, gc);
1a578e9b
AC
3597}
3598
3599
3600/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3601 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3602 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3603 left side of the rectangle. RIGHT_P non-zero means draw a line
3604 on the right side of the rectangle. CLIP_RECT is the clipping
3605 rectangle to use when drawing. */
3606
3607static void
3608x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3609 left_p, right_p, clip_rect)
3610 struct glyph_string *s;
6b61353c 3611 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
1a578e9b
AC
3612 Rect *clip_rect;
3613{
3614 XGCValues xgcv;
177c0ea7 3615
e4f5e019
YM
3616 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3617 XSetForeground (s->display, s->gc, s->face->box_color);
834263b6 3618 mac_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
177c0ea7 3619
1a578e9b 3620 /* Top. */
236072ae
YM
3621 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3622 right_x - left_x + 1, width);
1a578e9b
AC
3623
3624 /* Left. */
3625 if (left_p)
236072ae
YM
3626 mac_fill_rectangle (s->f, s->gc, left_x, top_y,
3627 width, bottom_y - top_y + 1);
1a578e9b
AC
3628
3629 /* Bottom. */
236072ae
YM
3630 mac_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1,
3631 right_x - left_x + 1, width);
177c0ea7 3632
1a578e9b
AC
3633 /* Right. */
3634 if (right_p)
236072ae
YM
3635 mac_fill_rectangle (s->f, s->gc, right_x - width + 1,
3636 top_y, width, bottom_y - top_y + 1);
1a578e9b 3637
e4f5e019 3638 XSetForeground (s->display, s->gc, xgcv.foreground);
834263b6 3639 mac_reset_clip_rectangles (s->f, s->gc);
1a578e9b
AC
3640}
3641
3642
3643/* Draw a box around glyph string S. */
3644
3645static void
3646x_draw_glyph_string_box (s)
3647 struct glyph_string *s;
3648{
3649 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3650 int left_p, right_p;
3651 struct glyph *last_glyph;
3652 Rect clip_rect;
3653
82ead4b1
KS
3654 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3655 ? WINDOW_RIGHT_EDGE_X (s->w)
3656 : window_box_right (s->w, s->area));
177c0ea7 3657
1a578e9b
AC
3658 /* The glyph that may have a right box line. */
3659 last_glyph = (s->cmp || s->img
3660 ? s->first_glyph
3661 : s->first_glyph + s->nchars - 1);
3662
1ea40aa2 3663 width = eabs (s->face->box_line_width);
1a578e9b
AC
3664 raised_p = s->face->box == FACE_RAISED_BOX;
3665 left_x = s->x;
6b61353c
KH
3666 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3667 ? last_x - 1
3668 : min (last_x, s->x + s->background_width) - 1);
1a578e9b
AC
3669 top_y = s->y;
3670 bottom_y = top_y + s->height - 1;
3671
3672 left_p = (s->first_glyph->left_box_line_p
3673 || (s->hl == DRAW_MOUSE_FACE
3674 && (s->prev == NULL
3675 || s->prev->hl != s->hl)));
3676 right_p = (last_glyph->right_box_line_p
3677 || (s->hl == DRAW_MOUSE_FACE
3678 && (s->next == NULL
3679 || s->next->hl != s->hl)));
177c0ea7 3680
f9e65eb3 3681 get_glyph_string_clip_rect (s, &clip_rect);
1a578e9b
AC
3682
3683 if (s->face->box == FACE_SIMPLE_BOX)
3684 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3685 left_p, right_p, &clip_rect);
3686 else
3687 {
3688 x_setup_relief_colors (s);
3689 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
ffe8b3f4 3690 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
1a578e9b
AC
3691 }
3692}
3693
3694
3695/* Draw foreground of image glyph string S. */
3696
3697static void
3698x_draw_image_foreground (s)
3699 struct glyph_string *s;
3700{
ffe8b3f4
KS
3701 int x = s->x;
3702 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
1a578e9b
AC
3703
3704 /* If first glyph of S has a left box line, start drawing it to the
3705 right of that line. */
3706 if (s->face->box != FACE_NO_BOX
ffe8b3f4
KS
3707 && s->first_glyph->left_box_line_p
3708 && s->slice.x == 0)
1ea40aa2 3709 x += eabs (s->face->box_line_width);
1a578e9b
AC
3710
3711 /* If there is a margin around the image, adjust x- and y-position
3712 by that margin. */
ffe8b3f4
KS
3713 if (s->slice.x == 0)
3714 x += s->img->hmargin;
3715 if (s->slice.y == 0)
3716 y += s->img->vmargin;
1a578e9b
AC
3717
3718 if (s->img->pixmap)
3719 {
fc7a70cc
ST
3720 x_set_glyph_string_clipping (s);
3721
e09ce637
YM
3722#if USE_CG_DRAWING
3723 mac_draw_cg_image (s->img->data.ptr_val,
3724 s->f, s->gc, s->slice.x, s->slice.y,
3725 s->slice.width, s->slice.height, x, y, 1);
3726#endif
1a578e9b 3727 if (s->img->mask)
e09ce637 3728#if !USE_CG_DRAWING
236072ae
YM
3729 mac_copy_area_with_mask (s->img->pixmap, s->img->mask,
3730 s->f, s->gc, s->slice.x, s->slice.y,
fc7a70cc 3731 s->slice.width, s->slice.height, x, y);
e09ce637
YM
3732#else
3733 ;
3734#endif
1a578e9b 3735 else
1a578e9b 3736 {
e09ce637 3737#if !USE_CG_DRAWING
236072ae
YM
3738 mac_copy_area (s->img->pixmap,
3739 s->f, s->gc, s->slice.x, s->slice.y,
fc7a70cc 3740 s->slice.width, s->slice.height, x, y);
e09ce637 3741#endif
177c0ea7 3742
1a578e9b
AC
3743 /* When the image has a mask, we can expect that at
3744 least part of a mouse highlight or a block cursor will
3745 be visible. If the image doesn't have a mask, make
3746 a block cursor visible by drawing a rectangle around
3747 the image. I believe it's looking better if we do
3748 nothing here for mouse-face. */
3749 if (s->hl == DRAW_CURSOR)
534c20b2
KS
3750 {
3751 int r = s->img->relief;
3752 if (r < 0) r = -r;
236072ae 3753 mac_draw_rectangle (s->f, s->gc, x - r, y - r,
ffe8b3f4
KS
3754 s->slice.width + r*2 - 1,
3755 s->slice.height + r*2 - 1);
534c20b2 3756 }
1a578e9b
AC
3757 }
3758 }
3759 else
3760 /* Draw a rectangle if image could not be loaded. */
236072ae 3761 mac_draw_rectangle (s->f, s->gc, x, y,
ffe8b3f4 3762 s->slice.width - 1, s->slice.height - 1);
1a578e9b
AC
3763}
3764
3765
3766/* Draw a relief around the image glyph string S. */
3767
3768static void
3769x_draw_image_relief (s)
3770 struct glyph_string *s;
3771{
3772 int x0, y0, x1, y1, thick, raised_p;
3773 Rect r;
ffe8b3f4
KS
3774 int x = s->x;
3775 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
177c0ea7 3776
1a578e9b
AC
3777 /* If first glyph of S has a left box line, start drawing it to the
3778 right of that line. */
3779 if (s->face->box != FACE_NO_BOX
ffe8b3f4
KS
3780 && s->first_glyph->left_box_line_p
3781 && s->slice.x == 0)
1ea40aa2 3782 x += eabs (s->face->box_line_width);
177c0ea7 3783
1a578e9b
AC
3784 /* If there is a margin around the image, adjust x- and y-position
3785 by that margin. */
ffe8b3f4
KS
3786 if (s->slice.x == 0)
3787 x += s->img->hmargin;
3788 if (s->slice.y == 0)
3789 y += s->img->vmargin;
177c0ea7 3790
1a578e9b
AC
3791 if (s->hl == DRAW_IMAGE_SUNKEN
3792 || s->hl == DRAW_IMAGE_RAISED)
3793 {
e0f712ba 3794 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
1a578e9b
AC
3795 raised_p = s->hl == DRAW_IMAGE_RAISED;
3796 }
3797 else
3798 {
1ea40aa2 3799 thick = eabs (s->img->relief);
1a578e9b
AC
3800 raised_p = s->img->relief > 0;
3801 }
177c0ea7 3802
1a578e9b
AC
3803 x0 = x - thick;
3804 y0 = y - thick;
ffe8b3f4
KS
3805 x1 = x + s->slice.width + thick - 1;
3806 y1 = y + s->slice.height + thick - 1;
177c0ea7 3807
1a578e9b 3808 x_setup_relief_colors (s);
f9e65eb3 3809 get_glyph_string_clip_rect (s, &r);
ffe8b3f4
KS
3810 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
3811 s->slice.y == 0,
3812 s->slice.y + s->slice.height == s->img->height,
3813 s->slice.x == 0,
3814 s->slice.x + s->slice.width == s->img->width,
3815 &r);
1a578e9b
AC
3816}
3817
3818
1a578e9b
AC
3819/* Draw part of the background of glyph string S. X, Y, W, and H
3820 give the rectangle to draw. */
3821
3822static void
3823x_draw_glyph_string_bg_rect (s, x, y, w, h)
3824 struct glyph_string *s;
3825 int x, y, w, h;
3826{
3827#if 0 /* MAC_TODO: stipple */
3828 if (s->stippled_p)
3829 {
3830 /* Fill background with a stipple pattern. */
3831 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3832 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3833 XSetFillStyle (s->display, s->gc, FillSolid);
3834 }
3835 else
e0f712ba 3836#endif /* MAC_TODO */
1a578e9b
AC
3837 x_clear_glyph_string_rect (s, x, y, w, h);
3838}
3839
3840
177c0ea7 3841/* Draw image glyph string S.
1a578e9b
AC
3842
3843 s->y
3844 s->x +-------------------------
3845 | s->face->box
3846 |
3847 | +-------------------------
6b61353c 3848 | | s->img->margin
1a578e9b
AC
3849 | |
3850 | | +-------------------
3851 | | | the image
3852
3853 */
3854
3855static void
3856x_draw_image_glyph_string (s)
3857 struct glyph_string *s;
3858{
3859 int x, y;
1ea40aa2 3860 int box_line_hwidth = eabs (s->face->box_line_width);
e0f712ba 3861 int box_line_vwidth = max (s->face->box_line_width, 0);
1a578e9b 3862 int height;
1a578e9b 3863
e0f712ba 3864 height = s->height - 2 * box_line_vwidth;
1a578e9b 3865
6b61353c 3866
1a578e9b
AC
3867 /* Fill background with face under the image. Do it only if row is
3868 taller than image or if image has a clip mask to reduce
3869 flickering. */
3870 s->stippled_p = s->face->stipple != 0;
ffe8b3f4 3871 if (height > s->slice.height
83a96b4d 3872 || s->img->hmargin
e0f712ba 3873 || s->img->vmargin
1a578e9b 3874 || s->img->mask
1a578e9b
AC
3875 || s->img->pixmap == 0
3876 || s->width != s->background_width)
3877 {
ffe8b3f4
KS
3878 x = s->x;
3879 if (s->first_glyph->left_box_line_p
3880 && s->slice.x == 0)
3881 x += box_line_hwidth;
177c0ea7 3882
ffe8b3f4
KS
3883 y = s->y;
3884 if (s->slice.y == 0)
3885 y += box_line_vwidth;
6b61353c 3886
236072ae 3887 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
177c0ea7 3888
1a578e9b
AC
3889 s->background_filled_p = 1;
3890 }
3891
3892 /* Draw the foreground. */
236072ae 3893 x_draw_image_foreground (s);
1a578e9b
AC
3894
3895 /* If we must draw a relief around the image, do it. */
3896 if (s->img->relief
3897 || s->hl == DRAW_IMAGE_RAISED
3898 || s->hl == DRAW_IMAGE_SUNKEN)
3899 x_draw_image_relief (s);
3900}
3901
3902
3903/* Draw stretch glyph string S. */
3904
3905static void
3906x_draw_stretch_glyph_string (s)
3907 struct glyph_string *s;
3908{
3909 xassert (s->first_glyph->type == STRETCH_GLYPH);
1a578e9b
AC
3910
3911 if (s->hl == DRAW_CURSOR
3912 && !x_stretch_cursor_p)
3913 {
3914 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3915 as wide as the stretch glyph. */
e8f6b0db
KS
3916 int width, background_width = s->background_width;
3917 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3918
3919 if (x < left_x)
3920 {
3921 background_width -= left_x - x;
3922 x = left_x;
3923 }
3924 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
1a578e9b
AC
3925
3926 /* Draw cursor. */
e8f6b0db 3927 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
1a578e9b
AC
3928
3929 /* Clear rest using the GC of the original non-cursor face. */
e8f6b0db 3930 if (width < background_width)
1a578e9b 3931 {
e8f6b0db
KS
3932 int y = s->y;
3933 int w = background_width - width, h = s->height;
1a578e9b 3934 Rect r;
6b61353c 3935 GC gc;
1a578e9b 3936
e8f6b0db 3937 x += width;
e0f712ba
AC
3938 if (s->row->mouse_face_p
3939 && cursor_in_mouse_face_p (s->w))
3940 {
3941 x_set_mouse_face_gc (s);
3942 gc = s->gc;
3943 }
3944 else
3945 gc = s->face->gc;
177c0ea7 3946
f9e65eb3 3947 get_glyph_string_clip_rect (s, &r);
834263b6 3948 mac_set_clip_rectangles (s->f, gc, &r, 1);
1a578e9b
AC
3949
3950#if 0 /* MAC_TODO: stipple */
3951 if (s->face->stipple)
3952 {
3953 /* Fill background with a stipple pattern. */
3954 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3955 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3956 XSetFillStyle (s->display, gc, FillSolid);
3957 }
3958 else
e0f712ba 3959#endif /* MAC_TODO */
236072ae 3960 mac_erase_rectangle (s->f, gc, x, y, w, h);
1a578e9b
AC
3961 }
3962 }
e0f712ba 3963 else if (!s->background_filled_p)
e8f6b0db
KS
3964 {
3965 int background_width = s->background_width;
3966 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3967
6c693929
KS
3968 /* Don't draw into left margin, fringe or scrollbar area
3969 except for header line and mode line. */
3970 if (x < left_x && !s->row->mode_line_p)
e8f6b0db
KS
3971 {
3972 background_width -= left_x - x;
3973 x = left_x;
3974 }
3975 if (background_width > 0)
3976 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3977 }
177c0ea7 3978
1a578e9b
AC
3979 s->background_filled_p = 1;
3980}
3981
3982
3983/* Draw glyph string S. */
3984
3985static void
3986x_draw_glyph_string (s)
3987 struct glyph_string *s;
3988{
e0f712ba
AC
3989 int relief_drawn_p = 0;
3990
8c2da0fa
ST
3991 /* If S draws into the background of its successor that does not
3992 draw a cursor, draw the background of the successor first so that
3993 S can draw into it. This makes S->next use XDrawString instead
3994 of XDrawImageString. */
c2ded1b7 3995 if (s->next && s->right_overhang && !s->for_overlaps
8c2da0fa 3996 && s->next->hl != DRAW_CURSOR)
1a578e9b
AC
3997 {
3998 xassert (s->next->img == NULL);
3999 x_set_glyph_string_gc (s->next);
4000 x_set_glyph_string_clipping (s->next);
4001 x_draw_glyph_string_background (s->next, 1);
4002 }
4003
4004 /* Set up S->gc, set clipping and draw S. */
4005 x_set_glyph_string_gc (s);
e0f712ba
AC
4006
4007 /* Draw relief (if any) in advance for char/composition so that the
4008 glyph string can be drawn over it. */
c2ded1b7 4009 if (!s->for_overlaps
e0f712ba
AC
4010 && s->face->box != FACE_NO_BOX
4011 && (s->first_glyph->type == CHAR_GLYPH
4012 || s->first_glyph->type == COMPOSITE_GLYPH))
4013
4014 {
4015 x_set_glyph_string_clipping (s);
4016 x_draw_glyph_string_background (s, 1);
4017 x_draw_glyph_string_box (s);
4018 x_set_glyph_string_clipping (s);
4019 relief_drawn_p = 1;
4020 }
4021 else
4022 x_set_glyph_string_clipping (s);
1a578e9b
AC
4023
4024 switch (s->first_glyph->type)
4025 {
4026 case IMAGE_GLYPH:
4027 x_draw_image_glyph_string (s);
4028 break;
4029
4030 case STRETCH_GLYPH:
4031 x_draw_stretch_glyph_string (s);
4032 break;
4033
4034 case CHAR_GLYPH:
c2ded1b7 4035 if (s->for_overlaps)
1a578e9b
AC
4036 s->background_filled_p = 1;
4037 else
6b61353c 4038 x_draw_glyph_string_background (s, 0);
1a578e9b
AC
4039 x_draw_glyph_string_foreground (s);
4040 break;
4041
4042 case COMPOSITE_GLYPH:
c2ded1b7 4043 if (s->for_overlaps || s->gidx > 0)
1a578e9b
AC
4044 s->background_filled_p = 1;
4045 else
4046 x_draw_glyph_string_background (s, 1);
4047 x_draw_composite_glyph_string_foreground (s);
4048 break;
4049
4050 default:
4051 abort ();
4052 }
4053
c2ded1b7 4054 if (!s->for_overlaps)
1a578e9b
AC
4055 {
4056 /* Draw underline. */
4057 if (s->face->underline_p)
4058 {
cf2c6835
YM
4059 unsigned long tem, h;
4060 int y;
4061
4062#if 0
4063 /* Get the underline thickness. Default is 1 pixel. */
4064 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4065#endif
4066 h = 1;
4067
4068 y = s->y + s->height - h;
4069 if (!x_underline_at_descent_line)
4070 {
4071 /* Get the underline position. This is the recommended
4072 vertical offset in pixels from the baseline to the top of
4073 the underline. This is a signed value according to the
4074 specs, and its default is
4075
4076 ROUND ((maximum descent) / 2), with
4077 ROUND(x) = floor (x + 0.5) */
4078
4079#if 0
4080 if (x_use_underline_position_properties
4081 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4082 y = s->ybase + (long) tem;
4083 else
4084#endif
4085 if (s->face->font)
4086 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4087 }
177c0ea7 4088
1a578e9b 4089 if (s->face->underline_defaulted_p)
cf2c6835 4090 mac_fill_rectangle (s->f, s->gc, s->x, y,
30f27523 4091 s->background_width, h);
1a578e9b
AC
4092 else
4093 {
4094 XGCValues xgcv;
4095 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4096 XSetForeground (s->display, s->gc, s->face->underline_color);
cf2c6835 4097 mac_fill_rectangle (s->f, s->gc, s->x, y,
30f27523 4098 s->background_width, h);
1a578e9b
AC
4099 XSetForeground (s->display, s->gc, xgcv.foreground);
4100 }
4101 }
4102
4103 /* Draw overline. */
4104 if (s->face->overline_p)
4105 {
4106 unsigned long dy = 0, h = 1;
4107
4108 if (s->face->overline_color_defaulted_p)
236072ae 4109 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
30f27523 4110 s->background_width, h);
1a578e9b
AC
4111 else
4112 {
4113 XGCValues xgcv;
4114 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4115 XSetForeground (s->display, s->gc, s->face->overline_color);
236072ae 4116 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
30f27523 4117 s->background_width, h);
1a578e9b
AC
4118 XSetForeground (s->display, s->gc, xgcv.foreground);
4119 }
4120 }
177c0ea7 4121
1a578e9b
AC
4122 /* Draw strike-through. */
4123 if (s->face->strike_through_p)
4124 {
4125 unsigned long h = 1;
4126 unsigned long dy = (s->height - h) / 2;
4127
4128 if (s->face->strike_through_color_defaulted_p)
236072ae
YM
4129 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4130 s->width, h);
1a578e9b
AC
4131 else
4132 {
4133 XGCValues xgcv;
4134 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4135 XSetForeground (s->display, s->gc, s->face->strike_through_color);
236072ae
YM
4136 mac_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
4137 s->width, h);
1a578e9b
AC
4138 XSetForeground (s->display, s->gc, xgcv.foreground);
4139 }
4140 }
177c0ea7 4141
6b61353c 4142 /* Draw relief if not yet drawn. */
e0f712ba 4143 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
6b61353c 4144 x_draw_glyph_string_box (s);
1a578e9b 4145 }
e0f712ba 4146
1a578e9b 4147 /* Reset clipping. */
834263b6 4148 mac_reset_clip_rectangles (s->f, s->gc);
1a578e9b
AC
4149}
4150
f9e65eb3 4151/* Shift display to make room for inserted glyphs. */
1a578e9b 4152
f9e65eb3
KS
4153void
4154mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
4155 struct frame *f;
4156 int x, y, width, height, shift_by;
1a578e9b 4157{
236072ae 4158 mac_scroll_area (f, f->output_data.mac->normal_gc,
f9e65eb3
KS
4159 x, y, width, height,
4160 x + shift_by, y);
1a578e9b
AC
4161}
4162
1a578e9b
AC
4163/* Delete N glyphs at the nominal cursor position. Not implemented
4164 for X frames. */
4165
e0f712ba 4166static void
1a578e9b
AC
4167x_delete_glyphs (n)
4168 register int n;
4169{
4170 abort ();
4171}
4172
4173
1a578e9b
AC
4174/* Clear entire frame. If updating_frame is non-null, clear that
4175 frame. Otherwise clear the selected frame. */
4176
e0f712ba 4177static void
80ca7302 4178x_clear_frame (struct frame *f)
1a578e9b 4179{
1a578e9b
AC
4180 /* Clearing the frame will erase any cursor, so mark them all as no
4181 longer visible. */
4182 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4183 output_cursor.hpos = output_cursor.vpos = 0;
4184 output_cursor.x = -1;
4185
4186 /* We don't set the output cursor here because there will always
4187 follow an explicit cursor_to. */
4188 BLOCK_INPUT;
236072ae 4189 mac_clear_window (f);
1a578e9b 4190
1a578e9b
AC
4191 /* We have to clear the scroll bars, too. If we have changed
4192 colors or something like that, then they should be notified. */
4193 x_scroll_bar_clear (f);
1a578e9b
AC
4194
4195 XFlush (FRAME_MAC_DISPLAY (f));
4196 UNBLOCK_INPUT;
4197}
4198
4199
4200\f
4201/* Invert the middle quarter of the frame for .15 sec. */
4202
4203/* We use the select system call to do the waiting, so we have to make
4204 sure it's available. If it isn't, we just won't do visual bells. */
4205
4206#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4207
6b61353c 4208
1a578e9b
AC
4209/* Subtract the `struct timeval' values X and Y, storing the result in
4210 *RESULT. Return 1 if the difference is negative, otherwise 0. */
4211
4212static int
4213timeval_subtract (result, x, y)
4214 struct timeval *result, x, y;
4215{
4216 /* Perform the carry for the later subtraction by updating y. This
4217 is safer because on some systems the tv_sec member is unsigned. */
4218 if (x.tv_usec < y.tv_usec)
4219 {
4220 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4221 y.tv_usec -= 1000000 * nsec;
4222 y.tv_sec += nsec;
4223 }
177c0ea7 4224
1a578e9b
AC
4225 if (x.tv_usec - y.tv_usec > 1000000)
4226 {
4227 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4228 y.tv_usec += 1000000 * nsec;
4229 y.tv_sec -= nsec;
4230 }
4231
4232 /* Compute the time remaining to wait. tv_usec is certainly
4233 positive. */
4234 result->tv_sec = x.tv_sec - y.tv_sec;
4235 result->tv_usec = x.tv_usec - y.tv_usec;
4236
4237 /* Return indication of whether the result should be considered
4238 negative. */
4239 return x.tv_sec < y.tv_sec;
4240}
4241
4242void
4243XTflash (f)
4244 struct frame *f;
4245{
d4a8455b
YM
4246 /* Get the height not including a menu bar widget. */
4247 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
4248 /* Height of each line to flash. */
4249 int flash_height = FRAME_LINE_HEIGHT (f);
4250 /* These will be the left and right margins of the rectangles. */
4251 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4252 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4253
4254 int width;
4255
4256 /* Don't flash the area between a scroll bar and the frame
4257 edge it is next to. */
4258 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4259 {
4260 case vertical_scroll_bar_left:
4261 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4262 break;
4263
4264 case vertical_scroll_bar_right:
4265 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4266 break;
4267
4268 default:
4269 break;
4270 }
4271
4272 width = flash_right - flash_left;
4273
1a578e9b
AC
4274 BLOCK_INPUT;
4275
d4a8455b
YM
4276 /* If window is tall, flash top and bottom line. */
4277 if (height > 3 * FRAME_LINE_HEIGHT (f))
4278 {
236072ae 4279 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4280 (FRAME_INTERNAL_BORDER_WIDTH (f)
4281 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4282 width, flash_height);
236072ae 4283 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4284 (height - flash_height
4285 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4286 width, flash_height);
4287 }
4288 else
4289 /* If it is short, flash it all. */
236072ae 4290 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
d4a8455b
YM
4291 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4292
4293 x_flush (f);
1a578e9b
AC
4294
4295 {
4296 struct timeval wakeup;
4297
4298 EMACS_GET_TIME (wakeup);
4299
4300 /* Compute time to wait until, propagating carry from usecs. */
4301 wakeup.tv_usec += 150000;
4302 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4303 wakeup.tv_usec %= 1000000;
4304
d4a8455b
YM
4305 /* Keep waiting until past the time wakeup or any input gets
4306 available. */
4307 while (! detect_input_pending ())
1a578e9b 4308 {
d4a8455b
YM
4309 struct timeval current;
4310 struct timeval timeout;
1a578e9b 4311
d4a8455b 4312 EMACS_GET_TIME (current);
1a578e9b 4313
d4a8455b
YM
4314 /* Break if result would be negative. */
4315 if (timeval_subtract (&current, wakeup, current))
4316 break;
1a578e9b 4317
d4a8455b
YM
4318 /* How long `select' should wait. */
4319 timeout.tv_sec = 0;
4320 timeout.tv_usec = 10000;
1a578e9b 4321
d4a8455b
YM
4322 /* Try to wait that long--but we might wake up sooner. */
4323 select (0, NULL, NULL, NULL, &timeout);
1a578e9b
AC
4324 }
4325 }
177c0ea7 4326
d4a8455b
YM
4327 /* If window is tall, flash top and bottom line. */
4328 if (height > 3 * FRAME_LINE_HEIGHT (f))
4329 {
236072ae 4330 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4331 (FRAME_INTERNAL_BORDER_WIDTH (f)
4332 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
4333 width, flash_height);
236072ae 4334 mac_invert_rectangle (f, flash_left,
d4a8455b
YM
4335 (height - flash_height
4336 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4337 width, flash_height);
4338 }
4339 else
4340 /* If it is short, flash it all. */
236072ae 4341 mac_invert_rectangle (f, flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
d4a8455b
YM
4342 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4343
4344 x_flush (f);
1a578e9b
AC
4345
4346 UNBLOCK_INPUT;
4347}
4348
4349#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
4350
4351
4352/* Make audible bell. */
4353
4354void
4355XTring_bell ()
4356{
4357 struct frame *f = SELECTED_FRAME ();
177c0ea7 4358
1a578e9b
AC
4359#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4360 if (visible_bell)
4361 XTflash (f);
4362 else
4363#endif
4364 {
4365 BLOCK_INPUT;
4366 SysBeep (1);
4367 XFlush (FRAME_MAC_DISPLAY (f));
4368 UNBLOCK_INPUT;
4369 }
4370}
4371
1a578e9b
AC
4372\f
4373/* Specify how many text lines, from the top of the window,
4374 should be affected by insert-lines and delete-lines operations.
4375 This, and those operations, are used only within an update
4376 that is bounded by calls to x_update_begin and x_update_end. */
4377
6b61353c 4378static void
1a578e9b
AC
4379XTset_terminal_window (n)
4380 register int n;
4381{
4382 /* This function intentionally left blank. */
4383}
4384
4385
4386\f
4387/***********************************************************************
4388 Line Dance
4389 ***********************************************************************/
4390
4391/* Perform an insert-lines or delete-lines operation, inserting N
4392 lines or deleting -N lines at vertical position VPOS. */
4393
e0f712ba 4394static void
1a578e9b
AC
4395x_ins_del_lines (vpos, n)
4396 int vpos, n;
4397{
4398 abort ();
4399}
4400
4401
4402/* Scroll part of the display as described by RUN. */
4403
e0f712ba 4404static void
1a578e9b
AC
4405x_scroll_run (w, run)
4406 struct window *w;
4407 struct run *run;
4408{
4409 struct frame *f = XFRAME (w->frame);
4410 int x, y, width, height, from_y, to_y, bottom_y;
4411
4412 /* Get frame-relative bounding box of the text display area of W,
3f332ef3 4413 without mode lines. Include in this box the left and right
6b61353c 4414 fringe of W. */
1a578e9b 4415 window_box (w, -1, &x, &y, &width, &height);
1a578e9b
AC
4416
4417 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4418 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4419 bottom_y = y + height;
4420
4421 if (to_y < from_y)
4422 {
4423 /* Scrolling up. Make sure we don't copy part of the mode
4424 line at the bottom. */
4425 if (from_y + run->height > bottom_y)
4426 height = bottom_y - from_y;
4427 else
4428 height = run->height;
4429 }
4430 else
4431 {
4432 /* Scolling down. Make sure we don't copy over the mode line.
4433 at the bottom. */
4434 if (to_y + run->height > bottom_y)
4435 height = bottom_y - to_y;
4436 else
4437 height = run->height;
4438 }
4439
4440 BLOCK_INPUT;
177c0ea7 4441
1a578e9b
AC
4442 /* Cursor off. Will be switched on again in x_update_window_end. */
4443 updated_window = w;
4444 x_clear_cursor (w);
4445
236072ae
YM
4446 mac_scroll_area (f, f->output_data.mac->normal_gc,
4447 x, from_y,
4448 width, height,
4449 x, to_y);
177c0ea7 4450
1a578e9b
AC
4451 UNBLOCK_INPUT;
4452}
4453
4454
4455\f
4456/***********************************************************************
4457 Exposure Events
4458 ***********************************************************************/
177c0ea7 4459
f9e65eb3
KS
4460\f
4461static void
4462frame_highlight (f)
4463 struct frame *f;
4464{
4465 x_update_cursor (f, 1);
4466}
1a578e9b
AC
4467
4468static void
f9e65eb3 4469frame_unhighlight (f)
1a578e9b 4470 struct frame *f;
1a578e9b 4471{
f9e65eb3
KS
4472 x_update_cursor (f, 1);
4473}
4474
4475/* The focus has changed. Update the frames as necessary to reflect
4476 the new situation. Note that we can't change the selected frame
4477 here, because the Lisp code we are interrupting might become confused.
4478 Each event gets marked with the frame in which it occurred, so the
4479 Lisp code can tell when the switch took place by examining the events. */
1a578e9b 4480
f9e65eb3
KS
4481static void
4482x_new_focus_frame (dpyinfo, frame)
4483 struct x_display_info *dpyinfo;
4484 struct frame *frame;
4485{
4486 struct frame *old_focus = dpyinfo->x_focus_frame;
1a578e9b 4487
f9e65eb3 4488 if (frame != dpyinfo->x_focus_frame)
1a578e9b 4489 {
f9e65eb3
KS
4490 /* Set this before calling other routines, so that they see
4491 the correct value of x_focus_frame. */
4492 dpyinfo->x_focus_frame = frame;
1a578e9b 4493
f9e65eb3
KS
4494 if (old_focus && old_focus->auto_lower)
4495 x_lower_frame (old_focus);
1a578e9b 4496
f9e65eb3
KS
4497#if 0
4498 selected_frame = frame;
4499 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
4500 selected_frame);
f1321dc3 4501 Fselect_window (selected_frame->selected_window, Qnil);
f9e65eb3
KS
4502 choose_minibuf_frame ();
4503#endif /* ! 0 */
1a578e9b 4504
f9e65eb3
KS
4505 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4506 pending_autoraise_frame = dpyinfo->x_focus_frame;
4507 else
4508 pending_autoraise_frame = 0;
68c767a3
YM
4509
4510#if USE_MAC_FONT_PANEL
4511 if (frame)
4cb62a90 4512 mac_set_font_info_for_selection (frame, DEFAULT_FACE_ID, 0);
68c767a3 4513#endif
1a578e9b 4514 }
1a578e9b 4515
f9e65eb3
KS
4516 x_frame_rehighlight (dpyinfo);
4517}
1a578e9b 4518
7ca7ccd5
YM
4519/* Handle FocusIn and FocusOut state changes for FRAME.
4520 If FRAME has focus and there exists more than one frame, puts
4521 a FOCUS_IN_EVENT into *BUFP. */
4522
4523static void
4524mac_focus_changed (type, dpyinfo, frame, bufp)
4525 int type;
4526 struct mac_display_info *dpyinfo;
4527 struct frame *frame;
4528 struct input_event *bufp;
4529{
4530 if (type == activeFlag)
4531 {
4532 if (dpyinfo->x_focus_event_frame != frame)
4533 {
4534 x_new_focus_frame (dpyinfo, frame);
4535 dpyinfo->x_focus_event_frame = frame;
4536
4537 /* Don't stop displaying the initial startup message
4538 for a switch-frame event we don't need. */
8e50cc2d
SM
4539 if (NILP (Vterminal_frame)
4540 && CONSP (Vframe_list)
4541 && !NILP (XCDR (Vframe_list)))
7ca7ccd5
YM
4542 {
4543 bufp->kind = FOCUS_IN_EVENT;
4544 XSETFRAME (bufp->frame_or_window, frame);
4545 }
4546 }
4547 }
4548 else
4549 {
4550 if (dpyinfo->x_focus_event_frame == frame)
4551 {
4552 dpyinfo->x_focus_event_frame = 0;
4553 x_new_focus_frame (dpyinfo, 0);
4554 }
4555 }
4556}
4557
4558/* The focus may have changed. Figure out if it is a real focus change,
4559 by checking both FocusIn/Out and Enter/LeaveNotify events.
4560
4561 Returns FOCUS_IN_EVENT event in *BUFP. */
4562
4563static void
4564x_detect_focus_change (dpyinfo, event, bufp)
4565 struct mac_display_info *dpyinfo;
369a7a37 4566 const EventRecord *event;
7ca7ccd5
YM
4567 struct input_event *bufp;
4568{
4569 struct frame *frame;
4570
3354caee 4571 frame = mac_window_to_frame ((WindowRef) event->message);
7ca7ccd5
YM
4572 if (! frame)
4573 return;
4574
4575 /* On Mac, this is only called from focus events, so no switch needed. */
4576 mac_focus_changed ((event->modifiers & activeFlag),
4577 dpyinfo, frame, bufp);
4578}
4579
4580
f9e65eb3 4581/* Handle an event saying the mouse has moved out of an Emacs frame. */
1a578e9b 4582
f9e65eb3
KS
4583void
4584x_mouse_leave (dpyinfo)
4585 struct x_display_info *dpyinfo;
1a578e9b 4586{
f9e65eb3 4587 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
1a578e9b
AC
4588}
4589
f9e65eb3
KS
4590/* The focus has changed, or we have redirected a frame's focus to
4591 another frame (this happens when a frame uses a surrogate
4592 mini-buffer frame). Shift the highlight as appropriate.
1a578e9b 4593
f9e65eb3
KS
4594 The FRAME argument doesn't necessarily have anything to do with which
4595 frame is being highlighted or un-highlighted; we only use it to find
4596 the appropriate X display info. */
1a578e9b
AC
4597
4598static void
f9e65eb3 4599XTframe_rehighlight (frame)
1a578e9b
AC
4600 struct frame *frame;
4601{
1a578e9b
AC
4602 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
4603}
4604
4605static void
4606x_frame_rehighlight (dpyinfo)
4607 struct x_display_info *dpyinfo;
4608{
4609 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4610
4611 if (dpyinfo->x_focus_frame)
4612 {
4613 dpyinfo->x_highlight_frame
8e50cc2d 4614 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
1a578e9b
AC
4615 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4616 : dpyinfo->x_focus_frame);
4617 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4618 {
4619 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
4620 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4621 }
4622 }
4623 else
4624 dpyinfo->x_highlight_frame = 0;
4625
4626 if (dpyinfo->x_highlight_frame != old_highlight)
4627 {
4628 if (old_highlight)
4629 frame_unhighlight (old_highlight);
4630 if (dpyinfo->x_highlight_frame)
4631 frame_highlight (dpyinfo->x_highlight_frame);
4632 }
4633}
4634
4635
4636\f
1a578e9b
AC
4637/* Convert a keysym to its name. */
4638
4639char *
4640x_get_keysym_name (keysym)
4641 int keysym;
4642{
4643 char *value;
4644
4645 BLOCK_INPUT;
4646#if 0
4647 value = XKeysymToString (keysym);
4648#else
4649 value = 0;
4650#endif
4651 UNBLOCK_INPUT;
4652
4653 return value;
4654}
4655
4656
4657\f
f9e65eb3
KS
4658/* Function to report a mouse movement to the mainstream Emacs code.
4659 The input handler calls this.
4660
4661 We have received a mouse movement event, which is given in *event.
4662 If the mouse is over a different glyph than it was last time, tell
4663 the mainstream emacs code by setting mouse_moved. If not, ask for
4664 another motion event, so we can check again the next time it moves. */
1a578e9b 4665
f9e65eb3
KS
4666static Point last_mouse_motion_position;
4667static Lisp_Object last_mouse_motion_frame;
1a578e9b 4668
af1229d9 4669static int
f9e65eb3
KS
4670note_mouse_movement (frame, pos)
4671 FRAME_PTR frame;
4672 Point *pos;
1a578e9b 4673{
50bf7673 4674 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
f9e65eb3
KS
4675#if TARGET_API_MAC_CARBON
4676 Rect r;
4677#endif
1a578e9b 4678
f9e65eb3
KS
4679 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
4680 last_mouse_motion_position = *pos;
4681 XSETFRAME (last_mouse_motion_frame, frame);
4682
6a0ace5b 4683 if (frame == dpyinfo->mouse_face_mouse_frame
f9e65eb3 4684#if TARGET_API_MAC_CARBON
6a0ace5b 4685 && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))
f9e65eb3 4686#else
6a0ace5b 4687 && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)
f9e65eb3 4688#endif
6a0ace5b 4689 )
f9e65eb3 4690 {
6a0ace5b
YM
4691 /* This case corresponds to LeaveNotify in X11. If we move
4692 outside the frame, then we're certainly no longer on any text
4693 in the frame. */
4694 clear_mouse_face (dpyinfo);
4695 dpyinfo->mouse_face_mouse_frame = 0;
4696 if (!dpyinfo->grabbed)
80ca7302 4697 FRAME_RIF (frame)->define_frame_cursor (frame,
6a0ace5b 4698 frame->output_data.mac->nontext_cursor);
f9e65eb3 4699 }
6a0ace5b 4700
f9e65eb3 4701 /* Has the mouse moved off the glyph it was on at the last sighting? */
05f7d868
YM
4702 if (frame != last_mouse_glyph_frame
4703 || !PtInRect (*pos, &last_mouse_glyph))
f9e65eb3
KS
4704 {
4705 frame->mouse_moved = 1;
4706 last_mouse_scroll_bar = Qnil;
4707 note_mouse_highlight (frame, pos->h, pos->v);
e2570d37
KS
4708 /* Remember which glyph we're now on. */
4709 remember_mouse_glyph (frame, pos->h, pos->v, &last_mouse_glyph);
05f7d868 4710 last_mouse_glyph_frame = frame;
af1229d9 4711 return 1;
f9e65eb3 4712 }
af1229d9
YM
4713
4714 return 0;
1a578e9b
AC
4715}
4716
1a578e9b 4717\f
f9e65eb3
KS
4718/************************************************************************
4719 Mouse Face
4720 ************************************************************************/
4721
f9e65eb3
KS
4722/* MAC TODO: This should be called from somewhere (or removed) ++KFS */
4723
4724static void
4725redo_mouse_highlight ()
4726{
4727 if (!NILP (last_mouse_motion_frame)
4728 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
4729 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
4730 last_mouse_motion_position.h,
4731 last_mouse_motion_position.v);
4732}
4733
4734
7ca7ccd5
YM
4735static struct frame *
4736mac_focus_frame (dpyinfo)
4737 struct mac_display_info *dpyinfo;
50bf7673 4738{
7ca7ccd5
YM
4739 if (dpyinfo->x_focus_frame)
4740 return dpyinfo->x_focus_frame;
4741 else
4742 /* Mac version may get events, such as a menu bar click, even when
4743 all the frames are invisible. In this case, we regard the
4744 event came to the selected frame. */
4745 return SELECTED_FRAME ();
50bf7673
ST
4746}
4747
50bf7673 4748
1a578e9b 4749/* Return the current position of the mouse.
e2570d37 4750 *FP should be a frame which indicates which display to ask about.
1a578e9b 4751
e2570d37
KS
4752 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4753 and *PART to the frame, window, and scroll bar part that the mouse
4754 is over. Set *X and *Y to the portion and whole of the mouse's
1a578e9b
AC
4755 position on the scroll bar.
4756
e2570d37
KS
4757 If the mouse movement started elsewhere, set *FP to the frame the
4758 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
1a578e9b
AC
4759 the mouse is over.
4760
e2570d37 4761 Set *TIME to the server time-stamp for the time at which the mouse
1a578e9b
AC
4762 was at this position.
4763
4764 Don't store anything if we don't have a valid set of values to report.
4765
4766 This clears the mouse_moved flag, so we can wait for the next mouse
4767 movement. */
4768
e0f712ba 4769static void
1a578e9b
AC
4770XTmouse_position (fp, insist, bar_window, part, x, y, time)
4771 FRAME_PTR *fp;
4772 int insist;
4773 Lisp_Object *bar_window;
4774 enum scroll_bar_part *part;
4775 Lisp_Object *x, *y;
4776 unsigned long *time;
4777{
e2570d37 4778 FRAME_PTR f1;
1a578e9b
AC
4779
4780 BLOCK_INPUT;
4781
4782 if (! NILP (last_mouse_scroll_bar) && insist == 0)
4783 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
4784 else
4785 {
e2570d37
KS
4786 Lisp_Object frame, tail;
4787
1a578e9b
AC
4788 /* Clear the mouse-moved flag for every frame on this display. */
4789 FOR_EACH_FRAME (tail, frame)
e2570d37 4790 XFRAME (frame)->mouse_moved = 0;
1a578e9b
AC
4791
4792 last_mouse_scroll_bar = Qnil;
4793
e2570d37
KS
4794 if (FRAME_MAC_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
4795 && FRAME_LIVE_P (last_mouse_frame))
4796 f1 = last_mouse_frame;
4797 else
4798 f1 = mac_focus_frame (FRAME_MAC_DISPLAY_INFO (*fp));
1a578e9b 4799
e2570d37
KS
4800 if (f1)
4801 {
4802 /* Ok, we found a frame. Store all the values.
4803 last_mouse_glyph is a rectangle used to reduce the
4804 generation of mouse events. To not miss any motion
4805 events, we must divide the frame into rectangles of the
4806 size of the smallest character that could be displayed
4807 on it, i.e. into the same rectangles that matrices on
4808 the frame are divided into. */
4809 Point mouse_pos;
4810
7adf3143
YM
4811#if TARGET_API_MAC_CARBON
4812 GetGlobalMouse (&mouse_pos);
4813 mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1);
4814 mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1);
4815#else
e2570d37
KS
4816 SetPortWindowPort (FRAME_MAC_WINDOW (f1));
4817 GetMouse (&mouse_pos);
7adf3143 4818#endif
e2570d37
KS
4819 remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v,
4820 &last_mouse_glyph);
05f7d868 4821 last_mouse_glyph_frame = f1;
e2570d37
KS
4822
4823 *bar_window = Qnil;
4824 *part = 0;
4825 *fp = f1;
4826 XSETINT (*x, mouse_pos.h);
4827 XSETINT (*y, mouse_pos.v);
4828 *time = last_mouse_movement_time;
4829 }
1a578e9b 4830 }
177c0ea7 4831
1a578e9b
AC
4832 UNBLOCK_INPUT;
4833}
4834
4835\f
5b8b73ff
YM
4836/************************************************************************
4837 Toolkit scroll bars
4838 ************************************************************************/
4839
4840#ifdef USE_TOOLKIT_SCROLL_BARS
4841
4842static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
4843static OSStatus install_scroll_bar_timer P_ ((void));
4844static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
e6bdfa32 4845static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
5b8b73ff 4846static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
5b8b73ff 4847 struct input_event *));
3354caee 4848static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
a3510ffa 4849 Rect *));
5b8b73ff 4850static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
e6509087 4851 ControlPartCode, Point,
5b8b73ff
YM
4852 struct input_event *));
4853static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
5b8b73ff 4854 struct input_event *));
3354caee 4855static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
95dfb192 4856 Point, struct input_event *));
5b8b73ff
YM
4857static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4858 int, int, int));
4859
4860/* Last scroll bar part sent in x_scroll_bar_handle_*. */
4861
4862static int last_scroll_bar_part;
4863
4864static EventLoopTimerRef scroll_bar_timer;
4865
4866static int scroll_bar_timer_event_posted_p;
4867
4868#define SCROLL_BAR_FIRST_DELAY 0.5
4869#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
4870
4871static pascal void
4872scroll_bar_timer_callback (timer, data)
4873 EventLoopTimerRef timer;
4874 void *data;
4875{
a733ef16 4876 OSStatus err;
5b8b73ff 4877
a733ef16 4878 err = mac_post_mouse_moved_event ();
5b8b73ff
YM
4879 if (err == noErr)
4880 scroll_bar_timer_event_posted_p = 1;
5b8b73ff
YM
4881}
4882
4883static OSStatus
4884install_scroll_bar_timer ()
4885{
4886 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
4887
4888 if (scroll_bar_timer_callbackUPP == NULL)
4889 scroll_bar_timer_callbackUPP =
4890 NewEventLoopTimerUPP (scroll_bar_timer_callback);
4891
4892 if (scroll_bar_timer == NULL)
4893 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
4894 kEventDurationForever as delays. */
4895 return
4896 InstallEventLoopTimer (GetCurrentEventLoop (),
4897 kEventDurationForever, kEventDurationForever,
4898 scroll_bar_timer_callbackUPP, NULL,
4899 &scroll_bar_timer);
4900}
4901
4902static OSStatus
4903set_scroll_bar_timer (delay)
4904 EventTimerInterval delay;
4905{
4906 if (scroll_bar_timer == NULL)
4907 install_scroll_bar_timer ();
4908
4909 scroll_bar_timer_event_posted_p = 0;
4910
4911 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
4912}
4913
4914static int
4915control_part_code_to_scroll_bar_part (part_code)
4916 ControlPartCode part_code;
4917{
4918 switch (part_code)
4919 {
4920 case kControlUpButtonPart: return scroll_bar_up_arrow;
4921 case kControlDownButtonPart: return scroll_bar_down_arrow;
4922 case kControlPageUpPart: return scroll_bar_above_handle;
4923 case kControlPageDownPart: return scroll_bar_below_handle;
4924 case kControlIndicatorPart: return scroll_bar_handle;
4925 }
4926
4927 return -1;
4928}
f9e65eb3
KS
4929
4930static void
95dfb192 4931construct_scroll_bar_click (bar, part, bufp)
5b8b73ff
YM
4932 struct scroll_bar *bar;
4933 int part;
5b8b73ff
YM
4934 struct input_event *bufp;
4935{
4936 bufp->kind = SCROLL_BAR_CLICK_EVENT;
4937 bufp->frame_or_window = bar->window;
4938 bufp->arg = Qnil;
4939 bufp->part = part;
4940 bufp->code = 0;
5b8b73ff
YM
4941 XSETINT (bufp->x, 0);
4942 XSETINT (bufp->y, 0);
4943 bufp->modifiers = 0;
4944}
4945
a3510ffa 4946static OSStatus
e6bdfa32 4947get_control_part_bounds (ch, part_code, rect)
3354caee 4948 ControlRef ch;
5b8b73ff
YM
4949 ControlPartCode part_code;
4950 Rect *rect;
4951{
4952 RgnHandle region = NewRgn ();
4953 OSStatus err;
4954
4955 err = GetControlRegion (ch, part_code, region);
4956 if (err == noErr)
4957 GetRegionBounds (region, rect);
4958 DisposeRgn (region);
4959
4960 return err;
4961}
4962
4963static void
e6509087 4964x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
5b8b73ff
YM
4965 struct scroll_bar *bar;
4966 ControlPartCode part_code;
e6509087 4967 Point mouse_pos;
5b8b73ff
YM
4968 struct input_event *bufp;
4969{
4970 int part = control_part_code_to_scroll_bar_part (part_code);
4971
4972 if (part < 0)
4973 return;
4974
4975 if (part != scroll_bar_handle)
4976 {
95dfb192 4977 construct_scroll_bar_click (bar, part, bufp);
3354caee 4978 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5b8b73ff 4979 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
e6509087
YM
4980 bar->dragging = Qnil;
4981 }
4982 else
4983 {
4984 Rect r;
4985
3354caee 4986 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
e6509087
YM
4987 kControlIndicatorPart, &r);
4988 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
5b8b73ff
YM
4989 }
4990
4991 last_scroll_bar_part = part;
5b8b73ff
YM
4992 tracked_scroll_bar = bar;
4993}
4994
4995static void
95dfb192 4996x_scroll_bar_handle_release (bar, bufp)
5b8b73ff 4997 struct scroll_bar *bar;
5b8b73ff
YM
4998 struct input_event *bufp;
4999{
5000 if (last_scroll_bar_part != scroll_bar_handle
e6509087 5001 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
95dfb192 5002 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
5b8b73ff 5003
3354caee 5004 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5b8b73ff
YM
5005 set_scroll_bar_timer (kEventDurationForever);
5006
5007 last_scroll_bar_part = -1;
5008 bar->dragging = Qnil;
5009 tracked_scroll_bar = NULL;
5010}
5011
5012static void
95dfb192 5013x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
3354caee 5014 WindowRef win;
5b8b73ff
YM
5015 struct scroll_bar *bar;
5016 Point mouse_pos;
5b8b73ff
YM
5017 struct input_event *bufp;
5018{
3354caee 5019 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5b8b73ff
YM
5020
5021 if (last_scroll_bar_part == scroll_bar_handle)
5022 {
5023 int top, top_range;
5024 Rect r;
5025
3354caee 5026 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
e6bdfa32 5027 kControlIndicatorPart, &r);
5b8b73ff 5028
e6509087
YM
5029 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
5030 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
5b8b73ff
YM
5031
5032 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
4d5724e5 5033 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
95dfb192 5034
5b8b73ff
YM
5035 if (top < 0)
5036 top = 0;
5037 if (top > top_range)
5038 top = top_range;
5039
95dfb192 5040 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
5b8b73ff
YM
5041 XSETINT (bufp->x, top);
5042 XSETINT (bufp->y, top_range);
5043 }
5044 else
5045 {
5046 ControlPartCode part_code;
5047 int unhilite_p = 0, part;
5048
5049 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
5050 unhilite_p = 1;
5051 else
5052 {
5053 part = control_part_code_to_scroll_bar_part (part_code);
5054
5055 switch (last_scroll_bar_part)
5056 {
5057 case scroll_bar_above_handle:
5058 case scroll_bar_below_handle:
5059 if (part != scroll_bar_above_handle
5060 && part != scroll_bar_below_handle)
5061 unhilite_p = 1;
5062 break;
5063
5064 case scroll_bar_up_arrow:
5065 case scroll_bar_down_arrow:
5066 if (part != scroll_bar_up_arrow
5067 && part != scroll_bar_down_arrow)
5068 unhilite_p = 1;
5069 break;
5070 }
5071 }
5072
5073 if (unhilite_p)
3354caee 5074 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
5b8b73ff
YM
5075 else if (part != last_scroll_bar_part
5076 || scroll_bar_timer_event_posted_p)
5077 {
95dfb192 5078 construct_scroll_bar_click (bar, part, bufp);
5b8b73ff 5079 last_scroll_bar_part = part;
3354caee 5080 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
5b8b73ff
YM
5081 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
5082 }
5083 }
5084}
5085
5086/* Set the thumb size and position of scroll bar BAR. We are currently
5087 displaying PORTION out of a whole WHOLE, and our position POSITION. */
5088
5089static void
5090x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
5091 struct scroll_bar *bar;
5092 int portion, position, whole;
f9e65eb3 5093{
3354caee 5094 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
5b8b73ff
YM
5095 int value, viewsize, maximum;
5096
a3510ffa
YM
5097 if (XINT (bar->track_height) == 0)
5098 return;
5099
4d5724e5 5100 if (whole <= portion)
5b8b73ff 5101 value = 0, viewsize = 1, maximum = 0;
f9e65eb3 5102 else
5b8b73ff 5103 {
4d5724e5
YM
5104 float scale;
5105
5106 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
5107 scale = (float) maximum / (whole - portion);
5108 value = position * scale + 0.5f;
5109 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
5b8b73ff
YM
5110 }
5111
5112 BLOCK_INPUT;
5113
a3510ffa
YM
5114 if (GetControlViewSize (ch) != viewsize
5115 || GetControl32BitValue (ch) != value
5116 || GetControl32BitMaximum (ch) != maximum)
5b574e69
YM
5117 {
5118 /* Temporarily hide the scroll bar to avoid multiple redraws. */
5119 SetControlVisibility (ch, false, false);
b6e3efe0 5120
5b574e69
YM
5121 SetControl32BitMaximum (ch, maximum);
5122 SetControl32BitValue (ch, value);
5123 SetControlViewSize (ch, viewsize);
5b8b73ff 5124
5b574e69
YM
5125 SetControlVisibility (ch, true, true);
5126 }
5b8b73ff
YM
5127
5128 UNBLOCK_INPUT;
f9e65eb3
KS
5129}
5130
5b8b73ff
YM
5131#endif /* USE_TOOLKIT_SCROLL_BARS */
5132
5133
f9e65eb3 5134\f
1a578e9b
AC
5135/************************************************************************
5136 Scroll bars, general
5137 ************************************************************************/
177c0ea7 5138
1a578e9b
AC
5139/* Create a scroll bar and return the scroll bar vector for it. W is
5140 the Emacs window on which to create the scroll bar. TOP, LEFT,
e0f712ba 5141 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
1a578e9b
AC
5142 scroll bar. */
5143
5144static struct scroll_bar *
5145x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
5146 struct window *w;
5147 int top, left, width, height, disp_top, disp_height;
5148{
5149 struct frame *f = XFRAME (w->frame);
5150 struct scroll_bar *bar
5151 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
5152 Rect r;
3354caee 5153 ControlRef ch;
1a578e9b
AC
5154
5155 BLOCK_INPUT;
5156
5157 r.left = left;
5158 r.top = disp_top;
5159 r.right = left + width;
5160 r.bottom = disp_top + disp_height;
177c0ea7 5161
4ea08bbf
YM
5162#if USE_CG_DRAWING
5163 mac_prepare_for_quickdraw (f);
5164#endif
b15325b2 5165#if TARGET_API_MAC_CARBON
a3510ffa 5166 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p",
70385fe6 5167#ifdef USE_TOOLKIT_SCROLL_BARS
a3510ffa
YM
5168 false,
5169#else
5170 width < disp_height,
5171#endif
95dfb192 5172 0, 0, 0, kControlScrollBarProc, (long) bar);
e0f712ba 5173#else
95dfb192
YM
5174 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
5175 0, 0, 0, scrollBarProc, (long) bar);
e0f712ba 5176#endif
3354caee 5177 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
1a578e9b
AC
5178
5179 XSETWINDOW (bar->window, w);
5180 XSETINT (bar->top, top);
5181 XSETINT (bar->left, left);
5182 XSETINT (bar->width, width);
5183 XSETINT (bar->height, height);
5184 XSETINT (bar->start, 0);
5185 XSETINT (bar->end, 0);
5186 bar->dragging = Qnil;
c6829f81
YM
5187#ifdef MAC_OSX
5188 bar->fringe_extended_p = Qnil;
5189#endif
1ec6ded9 5190 bar->redraw_needed_p = Qnil;
5b8b73ff
YM
5191#ifdef USE_TOOLKIT_SCROLL_BARS
5192 bar->track_top = Qnil;
5193 bar->track_height = Qnil;
4d5724e5 5194 bar->min_handle = Qnil;
5b8b73ff 5195#endif
1a578e9b
AC
5196
5197 /* Add bar to its frame's list of scroll bars. */
5198 bar->next = FRAME_SCROLL_BARS (f);
5199 bar->prev = Qnil;
5200 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5201 if (!NILP (bar->next))
5202 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5203
5204 UNBLOCK_INPUT;
5205 return bar;
5206}
5207
5208
5209/* Draw BAR's handle in the proper position.
177c0ea7 5210
1a578e9b
AC
5211 If the handle is already drawn from START to END, don't bother
5212 redrawing it, unless REBUILD is non-zero; in that case, always
5213 redraw it. (REBUILD is handy for drawing the handle after expose
5214 events.)
5215
5216 Normally, we want to constrain the start and end of the handle to
5217 fit inside its rectangle, but if the user is dragging the scroll
5218 bar handle, we want to let them drag it down all the way, so that
5219 the bar's top is as far down as it goes; otherwise, there's no way
5220 to move to the very end of the buffer. */
5221
5b8b73ff
YM
5222#ifndef USE_TOOLKIT_SCROLL_BARS
5223
1a578e9b
AC
5224static void
5225x_scroll_bar_set_handle (bar, start, end, rebuild)
5226 struct scroll_bar *bar;
5227 int start, end;
5228 int rebuild;
5229{
5230 int dragging = ! NILP (bar->dragging);
3354caee 5231 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
1a578e9b 5232 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
e0f712ba
AC
5233 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5234 int length = end - start;
1a578e9b
AC
5235
5236 /* If the display is already accurate, do nothing. */
5237 if (! rebuild
5238 && start == XINT (bar->start)
5239 && end == XINT (bar->end))
5240 return;
5241
5242 BLOCK_INPUT;
5243
e0f712ba
AC
5244 /* Make sure the values are reasonable, and try to preserve the
5245 distance between start and end. */
5246 if (start < 0)
5247 start = 0;
5248 else if (start > top_range)
5249 start = top_range;
5250 end = start + length;
177c0ea7 5251
e0f712ba
AC
5252 if (end < start)
5253 end = start;
5254 else if (end > top_range && ! dragging)
5255 end = top_range;
5256
5257 /* Store the adjusted setting in the scroll bar. */
5258 XSETINT (bar->start, start);
5259 XSETINT (bar->end, end);
5260
5261 /* Clip the end position, just for display. */
5262 if (end > top_range)
5263 end = top_range;
5264
5265 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5266 top positions, to make sure the handle is always at least that
5267 many pixels tall. */
5268 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5269
5270 SetControlMinimum (ch, 0);
5271 /* Don't inadvertently activate deactivated scroll bars */
5272 if (GetControlMaximum (ch) != -1)
5273 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5274 - (end - start));
5275 SetControlValue (ch, start);
5276#if TARGET_API_MAC_CARBON
5277 SetControlViewSize (ch, end - start);
1a578e9b 5278#endif
1a578e9b
AC
5279
5280 UNBLOCK_INPUT;
5281}
5282
5b8b73ff 5283#endif /* !USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5284
5285/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5286 nil. */
5287
5288static void
5289x_scroll_bar_remove (bar)
5290 struct scroll_bar *bar;
5291{
5292 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
e0f712ba 5293
1a578e9b
AC
5294 BLOCK_INPUT;
5295
4ea08bbf
YM
5296#if USE_CG_DRAWING
5297 mac_prepare_for_quickdraw (f);
5298#endif
1a578e9b 5299 /* Destroy the Mac scroll bar control */
3354caee 5300 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
1a578e9b
AC
5301
5302 /* Disassociate this scroll bar from its window. */
5303 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5304
5305 UNBLOCK_INPUT;
5306}
5307
95dfb192 5308
1a578e9b
AC
5309/* Set the handle of the vertical scroll bar for WINDOW to indicate
5310 that we are displaying PORTION characters out of a total of WHOLE
5311 characters, starting at POSITION. If WINDOW has no scroll bar,
5312 create one. */
95dfb192 5313
1a578e9b
AC
5314static void
5315XTset_vertical_scroll_bar (w, portion, whole, position)
5316 struct window *w;
5317 int portion, whole, position;
5318{
5319 struct frame *f = XFRAME (w->frame);
5320 struct scroll_bar *bar;
5321 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
f1a83aab 5322 int window_y, window_height;
c6829f81
YM
5323#ifdef MAC_OSX
5324 int fringe_extended_p;
5325#endif
1a578e9b
AC
5326
5327 /* Get window dimensions. */
f1a83aab 5328 window_box (w, -1, 0, &window_y, 0, &window_height);
1a578e9b 5329 top = window_y;
f1a83aab 5330 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
1a578e9b
AC
5331 height = window_height;
5332
5333 /* Compute the left edge of the scroll bar area. */
f1a83aab 5334 left = WINDOW_SCROLL_BAR_AREA_X (w);
1a578e9b
AC
5335
5336 /* Compute the width of the scroll bar which might be less than
5337 the width of the area reserved for the scroll bar. */
f1a83aab
KS
5338 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5339 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
1a578e9b
AC
5340 else
5341 sb_width = width;
5342
5343 /* Compute the left edge of the scroll bar. */
f1a83aab 5344 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
c6829f81 5345 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
1a578e9b 5346 else
c6829f81 5347 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
177c0ea7 5348
1a578e9b
AC
5349 /* Adjustments according to Inside Macintosh to make it look nice */
5350 disp_top = top;
5351 disp_height = height;
a3510ffa 5352#ifdef MAC_OS8
1a578e9b
AC
5353 if (disp_top == 0)
5354 {
5355 disp_top = -1;
5356 disp_height++;
5357 }
f1a83aab 5358 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
1a578e9b
AC
5359 {
5360 disp_top++;
5361 disp_height--;
5362 }
177c0ea7 5363
f1a83aab 5364 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
1a578e9b 5365 sb_left++;
a3510ffa 5366#endif
177c0ea7 5367
c6829f81
YM
5368#ifdef MAC_OSX
5369 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5370 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5371 && WINDOW_LEFT_FRINGE_WIDTH (w)
5372 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5373 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5374 else
5375 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5376 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5377 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5378 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5379#endif
5380
1a578e9b
AC
5381 /* Does the scroll bar exist yet? */
5382 if (NILP (w->vertical_scroll_bar))
5383 {
5384 BLOCK_INPUT;
c6829f81
YM
5385#ifdef MAC_OSX
5386 if (fringe_extended_p)
5387 mac_clear_area (f, sb_left, top, sb_width, height);
5388 else
5389#endif
5390 mac_clear_area (f, left, top, width, height);
1a578e9b
AC
5391 UNBLOCK_INPUT;
5392 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5393 disp_height);
5394 XSETVECTOR (w->vertical_scroll_bar, bar);
5395 }
5396 else
5397 {
5398 /* It may just need to be moved and resized. */
3354caee 5399 ControlRef ch;
177c0ea7 5400
1a578e9b 5401 bar = XSCROLL_BAR (w->vertical_scroll_bar);
3354caee 5402 ch = SCROLL_BAR_CONTROL_REF (bar);
1a578e9b
AC
5403
5404 BLOCK_INPUT;
5405
5406 /* If already correctly positioned, do nothing. */
1ec6ded9
YM
5407 if (XINT (bar->left) == sb_left
5408 && XINT (bar->top) == top
5409 && XINT (bar->width) == sb_width
1bad168e 5410 && XINT (bar->height) == height
c6829f81 5411#ifdef MAC_OSX
1bad168e 5412 && !NILP (bar->fringe_extended_p) == fringe_extended_p
c6829f81 5413#endif
1bad168e 5414 )
1ec6ded9
YM
5415 {
5416 if (!NILP (bar->redraw_needed_p))
5417 {
5418#if USE_CG_DRAWING
5419 mac_prepare_for_quickdraw (f);
5420#endif
8b329dba 5421 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
1ec6ded9
YM
5422 }
5423 }
5424 else
e6bdfa32 5425 {
e4f5e019
YM
5426 /* Since toolkit scroll bars are smaller than the space reserved
5427 for them on the frame, we have to clear "under" them. */
c6829f81
YM
5428#ifdef MAC_OSX
5429 if (fringe_extended_p)
5430 mac_clear_area (f, sb_left, top, sb_width, height);
5431 else
5432#endif
5433 mac_clear_area (f, left, top, width, height);
1a578e9b 5434
4ea08bbf
YM
5435#if USE_CG_DRAWING
5436 mac_prepare_for_quickdraw (f);
5437#endif
1a578e9b
AC
5438 HideControl (ch);
5439 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5440 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5441 disp_height);
a3510ffa 5442#ifndef USE_TOOLKIT_SCROLL_BARS
95dfb192
YM
5443 if (sb_width < disp_height)
5444 ShowControl (ch);
a3510ffa 5445#endif
177c0ea7 5446
1a578e9b
AC
5447 /* Remember new settings. */
5448 XSETINT (bar->left, sb_left);
5449 XSETINT (bar->top, top);
5450 XSETINT (bar->width, sb_width);
5451 XSETINT (bar->height, height);
5b8b73ff
YM
5452#ifdef USE_TOOLKIT_SCROLL_BARS
5453 bar->track_top = Qnil;
5454 bar->track_height = Qnil;
4d5724e5 5455 bar->min_handle = Qnil;
5b8b73ff 5456#endif
1a578e9b
AC
5457 }
5458
5459 UNBLOCK_INPUT;
5460 }
5461
c6829f81
YM
5462#ifdef MAC_OSX
5463 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5464#endif
5465
1ec6ded9
YM
5466 bar->redraw_needed_p = Qnil;
5467
5b8b73ff
YM
5468#ifdef USE_TOOLKIT_SCROLL_BARS
5469 if (NILP (bar->track_top))
f93e4d4f 5470 {
7a844a76
YM
5471 if (sb_width >= disp_height
5472#ifdef MAC_OSX
5473 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5474#endif
5475 )
f93e4d4f
YM
5476 {
5477 XSETINT (bar->track_top, 0);
5478 XSETINT (bar->track_height, 0);
4d5724e5 5479 XSETINT (bar->min_handle, 0);
f93e4d4f
YM
5480 }
5481 else
5482 {
3354caee 5483 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
f93e4d4f 5484 Rect r0, r1;
5b8b73ff 5485
f93e4d4f 5486 BLOCK_INPUT;
5b8b73ff 5487
f93e4d4f 5488 SetControl32BitMinimum (ch, 0);
4d5724e5 5489 SetControl32BitMaximum (ch, 1 << 30);
f93e4d4f 5490 SetControlViewSize (ch, 1);
5b8b73ff 5491
f93e4d4f
YM
5492 /* Move the scroll bar thumb to the top. */
5493 SetControl32BitValue (ch, 0);
5494 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5b8b73ff 5495
f93e4d4f 5496 /* Move the scroll bar thumb to the bottom. */
4d5724e5 5497 SetControl32BitValue (ch, 1 << 30);
f93e4d4f 5498 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5b8b73ff 5499
f93e4d4f
YM
5500 UnionRect (&r0, &r1, &r0);
5501 XSETINT (bar->track_top, r0.top);
5502 XSETINT (bar->track_height, r0.bottom - r0.top);
4d5724e5 5503 XSETINT (bar->min_handle, r1.bottom - r1.top);
5b8b73ff 5504
f93e4d4f
YM
5505 /* Don't show the scroll bar if its height is not enough to
5506 display the scroll bar thumb. */
5507 if (r0.bottom - r0.top > 0)
5508 ShowControl (ch);
a3510ffa 5509
f93e4d4f
YM
5510 UNBLOCK_INPUT;
5511 }
5512 }
5b8b73ff
YM
5513
5514 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5515#else /* not USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5516 /* Set the scroll bar's current state, unless we're currently being
5517 dragged. */
5518 if (NILP (bar->dragging))
5519 {
5520 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5521
5522 if (whole == 0)
5523 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5524 else
5525 {
5526 int start = ((double) position * top_range) / whole;
5527 int end = ((double) (position + portion) * top_range) / whole;
5528 x_scroll_bar_set_handle (bar, start, end, 0);
5529 }
5530 }
5b8b73ff 5531#endif /* not USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5532}
5533
5534
5535/* The following three hooks are used when we're doing a thorough
5536 redisplay of the frame. We don't explicitly know which scroll bars
5537 are going to be deleted, because keeping track of when windows go
5538 away is a real pain - "Can you say set-window-configuration, boys
5539 and girls?" Instead, we just assert at the beginning of redisplay
5540 that *all* scroll bars are to be removed, and then save a scroll bar
5541 from the fiery pit when we actually redisplay its window. */
5542
5543/* Arrange for all scroll bars on FRAME to be removed at the next call
5544 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5545 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5546
5547static void
5548XTcondemn_scroll_bars (frame)
5549 FRAME_PTR frame;
5550{
5551 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5552 while (! NILP (FRAME_SCROLL_BARS (frame)))
5553 {
5554 Lisp_Object bar;
5555 bar = FRAME_SCROLL_BARS (frame);
5556 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5557 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5558 XSCROLL_BAR (bar)->prev = Qnil;
5559 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5560 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5561 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5562 }
5563}
5564
e0f712ba 5565
1a578e9b
AC
5566/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5567 Note that WINDOW isn't necessarily condemned at all. */
e0f712ba 5568
1a578e9b
AC
5569static void
5570XTredeem_scroll_bar (window)
5571 struct window *window;
5572{
5573 struct scroll_bar *bar;
95dfb192 5574 struct frame *f;
1a578e9b
AC
5575
5576 /* We can't redeem this window's scroll bar if it doesn't have one. */
5577 if (NILP (window->vertical_scroll_bar))
5578 abort ();
5579
5580 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5581
5582 /* Unlink it from the condemned list. */
95dfb192
YM
5583 f = XFRAME (WINDOW_FRAME (window));
5584 if (NILP (bar->prev))
5585 {
5586 /* If the prev pointer is nil, it must be the first in one of
5587 the lists. */
5588 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5589 /* It's not condemned. Everything's fine. */
5590 return;
5591 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5592 window->vertical_scroll_bar))
5593 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5594 else
5595 /* If its prev pointer is nil, it must be at the front of
5596 one or the other! */
5597 abort ();
5598 }
5599 else
5600 XSCROLL_BAR (bar->prev)->next = bar->next;
1a578e9b 5601
95dfb192
YM
5602 if (! NILP (bar->next))
5603 XSCROLL_BAR (bar->next)->prev = bar->prev;
1a578e9b 5604
95dfb192
YM
5605 bar->next = FRAME_SCROLL_BARS (f);
5606 bar->prev = Qnil;
5607 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5608 if (! NILP (bar->next))
5609 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
1a578e9b
AC
5610}
5611
5612/* Remove all scroll bars on FRAME that haven't been saved since the
5613 last call to `*condemn_scroll_bars_hook'. */
5614
5615static void
5616XTjudge_scroll_bars (f)
5617 FRAME_PTR f;
5618{
5619 Lisp_Object bar, next;
5620
5621 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5622
5623 /* Clear out the condemned list now so we won't try to process any
5624 more events on the hapless scroll bars. */
5625 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5626
5627 for (; ! NILP (bar); bar = next)
5628 {
5629 struct scroll_bar *b = XSCROLL_BAR (bar);
5630
5631 x_scroll_bar_remove (b);
5632
5633 next = b->next;
5634 b->next = b->prev = Qnil;
5635 }
5636
5637 /* Now there should be no references to the condemned scroll bars,
5638 and they should get garbage-collected. */
5639}
5640
5641
1a578e9b 5642/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3b8f9651 5643 is set to something other than NO_EVENT, it is enqueued.
1a578e9b
AC
5644
5645 This may be called from a signal handler, so we have to ignore GC
5646 mark bits. */
5647
5648static void
5649x_scroll_bar_handle_click (bar, part_code, er, bufp)
5650 struct scroll_bar *bar;
e6bdfa32 5651 ControlPartCode part_code;
369a7a37 5652 const EventRecord *er;
1a578e9b
AC
5653 struct input_event *bufp;
5654{
50bf7673
ST
5655 int win_y, top_range;
5656
8e50cc2d 5657 if (! WINDOWP (bar->window))
1a578e9b
AC
5658 abort ();
5659
3b8f9651 5660 bufp->kind = SCROLL_BAR_CLICK_EVENT;
1a578e9b
AC
5661 bufp->frame_or_window = bar->window;
5662 bufp->arg = Qnil;
5663
5664 bar->dragging = Qnil;
177c0ea7 5665
1a578e9b
AC
5666 switch (part_code)
5667 {
5668 case kControlUpButtonPart:
5669 bufp->part = scroll_bar_up_arrow;
5670 break;
5671 case kControlDownButtonPart:
5672 bufp->part = scroll_bar_down_arrow;
5673 break;
5674 case kControlPageUpPart:
5675 bufp->part = scroll_bar_above_handle;
5676 break;
5677 case kControlPageDownPart:
5678 bufp->part = scroll_bar_below_handle;
5679 break;
b15325b2 5680#if TARGET_API_MAC_CARBON
e0f712ba
AC
5681 default:
5682#else
1a578e9b 5683 case kControlIndicatorPart:
e0f712ba 5684#endif
1a578e9b
AC
5685 if (er->what == mouseDown)
5686 bar->dragging = make_number (0);
5687 XSETVECTOR (last_mouse_scroll_bar, bar);
5688 bufp->part = scroll_bar_handle;
5689 break;
5690 }
50bf7673
ST
5691
5692 win_y = XINT (bufp->y) - XINT (bar->top);
5693 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5694
5695 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5696
5697 win_y -= 24;
5698
5699 if (! NILP (bar->dragging))
5700 win_y -= XINT (bar->dragging);
5701
5702 if (win_y < 0)
5703 win_y = 0;
5704 if (win_y > top_range)
5705 win_y = top_range;
5706
5707 XSETINT (bufp->x, win_y);
5708 XSETINT (bufp->y, top_range);
1a578e9b
AC
5709}
5710
5b8b73ff 5711#ifndef USE_TOOLKIT_SCROLL_BARS
1a578e9b
AC
5712
5713/* Handle some mouse motion while someone is dragging the scroll bar.
5714
5715 This may be called from a signal handler, so we have to ignore GC
5716 mark bits. */
5717
5718static void
5719x_scroll_bar_note_movement (bar, y_pos, t)
5720 struct scroll_bar *bar;
5721 int y_pos;
5722 Time t;
5723{
5724 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5725
5726 last_mouse_movement_time = t;
5727
5728 f->mouse_moved = 1;
5729 XSETVECTOR (last_mouse_scroll_bar, bar);
5730
5731 /* If we're dragging the bar, display it. */
8e50cc2d 5732 if (! NILP (bar->dragging))
1a578e9b
AC
5733 {
5734 /* Where should the handle be now? */
5735 int new_start = y_pos - 24;
5736
5737 if (new_start != XINT (bar->start))
5738 {
5739 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5740
5741 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5742 }
5743 }
5744}
5745
5b8b73ff 5746#endif /* !USE_TOOLKIT_SCROLL_BARS */
1a578e9b 5747
95dfb192
YM
5748/* Return information to the user about the current position of the mouse
5749 on the scroll bar. */
1a578e9b
AC
5750
5751static void
5752x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5753 FRAME_PTR *fp;
5754 Lisp_Object *bar_window;
5755 enum scroll_bar_part *part;
5756 Lisp_Object *x, *y;
5757 unsigned long *time;
5758{
5759 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
3354caee 5760 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
7ca7ccd5 5761#if TARGET_API_MAC_CARBON
3354caee 5762 WindowRef wp = GetControlOwner (ch);
7ca7ccd5 5763#else
3354caee 5764 WindowRef wp = (*ch)->contrlOwner;
7ca7ccd5 5765#endif
1a578e9b 5766 Point mouse_pos;
50bf7673 5767 struct frame *f = mac_window_to_frame (wp);
1a578e9b
AC
5768 int win_y, top_range;
5769
7adf3143
YM
5770#if TARGET_API_MAC_CARBON
5771 GetGlobalMouse (&mouse_pos);
5772 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5773 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5774#else
50bf7673 5775 SetPortWindowPort (wp);
1a578e9b 5776 GetMouse (&mouse_pos);
7adf3143 5777#endif
1a578e9b
AC
5778
5779 win_y = mouse_pos.v - XINT (bar->top);
5780 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5781
5782 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5783
5784 win_y -= 24;
5785
5786 if (! NILP (bar->dragging))
5787 win_y -= XINT (bar->dragging);
5788
5789 if (win_y < 0)
5790 win_y = 0;
5791 if (win_y > top_range)
5792 win_y = top_range;
5793
5794 *fp = f;
5795 *bar_window = bar->window;
5796
5797 if (! NILP (bar->dragging))
5798 *part = scroll_bar_handle;
5799 else if (win_y < XINT (bar->start))
5800 *part = scroll_bar_above_handle;
5801 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5802 *part = scroll_bar_handle;
5803 else
5804 *part = scroll_bar_below_handle;
5805
5806 XSETINT (*x, win_y);
5807 XSETINT (*y, top_range);
5808
5809 f->mouse_moved = 0;
5810 last_mouse_scroll_bar = Qnil;
5811
5812 *time = last_mouse_movement_time;
5813}
e6bdfa32
YM
5814
5815
5816/* The screen has been cleared so we may have changed foreground or
5817 background colors, and the scroll bars may need to be redrawn.
5818 Clear out the scroll bars, and ask for expose events, so we can
5819 redraw them. */
5820
5821void
5822x_scroll_bar_clear (f)
5823 FRAME_PTR f;
5824{
1ec6ded9
YM
5825 Lisp_Object bar;
5826
5827 /* We can have scroll bars even if this is 0,
5828 if we just turned off scroll bar mode.
5829 But in that case we should not clear them. */
5830 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5831 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5832 bar = XSCROLL_BAR (bar)->next)
5833 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
e6bdfa32
YM
5834}
5835
1a578e9b 5836\f
c6829f81
YM
5837/***********************************************************************
5838 Tool-bars
5839 ***********************************************************************/
5840#if USE_MAC_TOOLBAR
5841
5842/* In identifiers such as function/variable names, Emacs tool bar is
5843 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5844
5845#define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5846#define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5847
5848#define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5849#define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5850 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5851#define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5852 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5853#define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5854 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5855
5856static int mac_event_to_emacs_modifiers P_ ((EventRef));
5857static void mac_handle_origin_change P_ ((struct frame *));
5858static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5859 EventRef, void *));
5860
5861static void
5862mac_move_window_with_gravity (f, win_gravity, left, top)
5863 struct frame *f;
5864 int win_gravity;
5865 short left, top;
5866{
5867 Rect inner, outer;
5868
5869 mac_get_window_bounds (f, &inner, &outer);
5870
5871 switch (win_gravity)
5872 {
5873 case NorthWestGravity:
5874 case WestGravity:
5875 case SouthWestGravity:
5876 left += inner.left - outer.left;
5877 break;
5878
5879 case NorthGravity:
5880 case CenterGravity:
5881 case SouthGravity:
5882 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5883 break;
5884
5885 case NorthEastGravity:
5886 case EastGravity:
5887 case SouthEastGravity:
5888 left += inner.right - outer.right;
5889 break;
5890 }
5891
5892 switch (win_gravity)
5893 {
5894 case NorthWestGravity:
5895 case NorthGravity:
5896 case NorthEastGravity:
5897 top += inner.top - outer.top;
5898 break;
5899
5900 case WestGravity:
5901 case CenterGravity:
5902 case EastGravity:
5903 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5904 break;
5905
5906 case SouthWestGravity:
5907 case SouthGravity:
5908 case SouthEastGravity:
5909 top += inner.bottom - outer.bottom;
5910 break;
5911 }
5912
5913 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5914}
5915
5916static void
5917mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5918 struct frame *f;
5919 int win_gravity;
5920 short *left, *top;
5921{
5922 Rect inner, outer;
5923
5924 mac_get_window_bounds (f, &inner, &outer);
5925
5926 switch (win_gravity)
5927 {
5928 case NorthWestGravity:
5929 case WestGravity:
5930 case SouthWestGravity:
5931 *left = outer.left;
5932 break;
5933
5934 case NorthGravity:
5935 case CenterGravity:
5936 case SouthGravity:
5937 *left = outer.left + ((outer.right - outer.left)
5938 - (inner.right - inner.left)) / 2;
5939 break;
5940
5941 case NorthEastGravity:
5942 case EastGravity:
5943 case SouthEastGravity:
5944 *left = outer.right - (inner.right - inner.left);
5945 break;
5946 }
5947
5948 switch (win_gravity)
5949 {
5950 case NorthWestGravity:
5951 case NorthGravity:
5952 case NorthEastGravity:
5953 *top = outer.top;
5954 break;
5955
5956 case WestGravity:
5957 case CenterGravity:
5958 case EastGravity:
5959 *top = outer.top + ((outer.bottom - outer.top)
5960 - (inner.bottom - inner.top)) / 2;
5961 break;
5962
5963 case SouthWestGravity:
5964 case SouthGravity:
5965 case SouthEastGravity:
5966 *top = outer.bottom - (inner.bottom - inner.top);
5967 break;
5968 }
5969}
5970
5971static OSStatus
5972mac_handle_toolbar_event (next_handler, event, data)
5973 EventHandlerCallRef next_handler;
5974 EventRef event;
5975 void *data;
5976{
5977 OSStatus err, result = eventNotHandledErr;
5978
5979 switch (GetEventKind (event))
5980 {
5981 case kEventToolbarGetDefaultIdentifiers:
5982 result = noErr;
5983 break;
5984
5985 case kEventToolbarGetAllowedIdentifiers:
5986 {
5987 CFMutableArrayRef array;
5988
5989 GetEventParameter (event, kEventParamMutableArray,
5990 typeCFMutableArrayRef, NULL,
5991 sizeof (CFMutableArrayRef), NULL, &array);
5992 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5993 result = noErr;
5994 }
5995 break;
5996
5997 case kEventToolbarCreateItemWithIdentifier:
5998 {
5999 CFStringRef identifier;
6000 HIToolbarItemRef item = NULL;
6001
6002 GetEventParameter (event, kEventParamToolbarItemIdentifier,
6003 typeCFStringRef, NULL,
6004 sizeof (CFStringRef), NULL, &identifier);
6005
6006 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
6007 == kCFCompareEqualTo)
6008 HIToolbarItemCreate (identifier,
6009 kHIToolbarItemAllowDuplicates
6010 | kHIToolbarItemCantBeRemoved, &item);
6011
6012 if (item)
6013 {
6014 SetEventParameter (event, kEventParamToolbarItem,
6015 typeHIToolbarItemRef,
6016 sizeof (HIToolbarItemRef), &item);
6017 result = noErr;
6018 }
6019 }
6020 break;
6021
6022 default:
6023 abort ();
6024 }
6025
6026 return result;
6027}
6028
6029static CGImageRef
6030mac_image_spec_to_cg_image (f, image)
6031 struct frame *f;
6032 Lisp_Object image;
6033{
6034 if (!valid_image_p (image))
6035 return NULL;
6036 else
6037 {
6038 int img_id = lookup_image (f, image);
6039 struct image *img = IMAGE_FROM_ID (f, img_id);
6040
6041 prepare_image_for_display (f, img);
6042
6043 return img->data.ptr_val;
6044 }
6045}
6046
6047/* Create a tool bar for frame F. */
6048
6049static OSStatus
6050mac_create_frame_tool_bar (f)
6051 FRAME_PTR f;
6052{
6053 OSStatus err;
6054 HIToolbarRef toolbar;
6055
6056 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
6057 &toolbar);
6058 if (err == noErr)
6059 {
6060 static const EventTypeSpec specs[] =
6061 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
6062 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
6063 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
6064
6065 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
6066 mac_handle_toolbar_event,
6067 GetEventTypeCount (specs), specs,
6068 f, NULL);
6069 }
6070
6071 if (err == noErr)
6072 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
6073 if (err == noErr)
6074 {
6075 static const EventTypeSpec specs[] =
6076 {{kEventClassCommand, kEventCommandProcess}};
6077
6078 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
6079 mac_handle_toolbar_command_event,
6080 GetEventTypeCount (specs),
6081 specs, f, NULL);
6082 }
6083 if (err == noErr)
6084 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
6085
6086 if (toolbar)
6087 CFRelease (toolbar);
6088
6089 return err;
6090}
6091
6092/* Update the tool bar for frame F. Add new buttons and remove old. */
6093
6094void
6095update_frame_tool_bar (f)
6096 FRAME_PTR f;
6097{
6098 HIToolbarRef toolbar = NULL;
6099 short left, top;
6100 CFArrayRef old_items = NULL;
6101 CFIndex old_count;
6102 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
6103 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6104
6105 BLOCK_INPUT;
6106
6107 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6108 if (toolbar == NULL)
6109 {
6110 mac_create_frame_tool_bar (f);
6111 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
6112 if (toolbar == NULL)
6113 goto out;
6114 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6115 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6116 }
6117
6118 HIToolbarCopyItems (toolbar, &old_items);
6119 if (old_items == NULL)
6120 goto out;
6121
6122 old_count = CFArrayGetCount (old_items);
6123 pos = 0;
6124 for (i = 0; i < f->n_tool_bar_items; ++i)
6125 {
6126#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6127
6128 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6129 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6130 int idx;
6131 Lisp_Object image;
6132 CGImageRef cg_image;
6133 CFStringRef label;
6134 HIToolbarItemRef item;
6135
6136 /* If image is a vector, choose the image according to the
6137 button state. */
6138 image = PROP (TOOL_BAR_ITEM_IMAGES);
6139 if (VECTORP (image))
6140 {
6141 if (enabled_p)
6142 idx = (selected_p
6143 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6144 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6145 else
6146 idx = (selected_p
6147 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6148 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6149
6150 xassert (ASIZE (image) >= idx);
6151 image = AREF (image, idx);
6152 }
6153 else
6154 idx = -1;
6155
6156 cg_image = mac_image_spec_to_cg_image (f, image);
6157 /* Ignore invalid image specifications. */
6158 if (cg_image == NULL)
6159 continue;
6160
6161 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6162 if (label == NULL)
6163 label = CFSTR ("");
6164
6165 if (pos < old_count)
6166 {
6167 CGImageRef old_cg_image = NULL;
6168 CFStringRef old_label = NULL;
6169 Boolean old_enabled_p;
6170
6171 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6172
6173 HIToolbarItemCopyImage (item, &old_cg_image);
6174 if (cg_image != old_cg_image)
6175 HIToolbarItemSetImage (item, cg_image);
6176 CGImageRelease (old_cg_image);
6177
6178 HIToolbarItemCopyLabel (item, &old_label);
6179 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6180 HIToolbarItemSetLabel (item, label);
6181 CFRelease (old_label);
6182
6183 old_enabled_p = HIToolbarItemIsEnabled (item);
6184 if ((enabled_p || idx >= 0) != old_enabled_p)
6185 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6186 }
6187 else
6188 {
6189 item = NULL;
6190 HIToolbarCreateItemWithIdentifier (toolbar,
6191 TOOLBAR_ICON_ITEM_IDENTIFIER,
6192 NULL, &item);
6193 if (item)
6194 {
6195 HIToolbarItemSetImage (item, cg_image);
6196 HIToolbarItemSetLabel (item, label);
6197 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6198 HIToolbarAppendItem (toolbar, item);
6199 CFRelease (item);
6200 }
6201 }
6202
6203 CFRelease (label);
6204 if (item)
6205 {
6206 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6207 pos++;
6208 }
6209 }
6210
6211 CFRelease (old_items);
6212
6213 while (pos < old_count)
6214 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6215
6216 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6217 !win_gravity && f == mac_focus_frame (dpyinfo));
6218 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6219 toolbar visibility change. */
6220 mac_handle_origin_change (f);
6221 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6222 {
6223 mac_move_window_with_gravity (f, win_gravity, left, top);
6224 /* If the title bar is completely outside the screen, adjust the
6225 position. */
6226 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6227 kWindowConstrainMoveRegardlessOfFit
6228 | kWindowConstrainAllowPartial, NULL, NULL);
6229 f->output_data.mac->toolbar_win_gravity = 0;
6230 }
6231
6232 out:
6233 UNBLOCK_INPUT;
6234}
6235
6236/* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6237 doesn't deallocate the resources. */
6238
6239void
6240free_frame_tool_bar (f)
6241 FRAME_PTR f;
6242{
6243 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6244 {
6245 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6246
6247 BLOCK_INPUT;
6248 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
7b7d07bb
YM
6249 (NILP (Fsymbol_value
6250 (intern ("frame-notice-user-settings")))
6251 && f == mac_focus_frame (dpyinfo)));
c6829f81
YM
6252 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6253 on toolbar visibility change. */
6254 mac_handle_origin_change (f);
6255 UNBLOCK_INPUT;
6256 }
6257}
6258
6259static void
6260mac_tool_bar_note_mouse_movement (f, event)
6261 struct frame *f;
6262 EventRef event;
6263{
6264 OSStatus err;
6265 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6266 int mouse_down_p;
6267 HIViewRef item_view;
6268 UInt32 command_id;
6269
6270 mouse_down_p = (dpyinfo->grabbed
6271 && f == last_mouse_frame
6272 && FRAME_LIVE_P (f));
6273 if (mouse_down_p)
6274 return;
6275
6276 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6277 event, &item_view);
6278 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6279 toolbar item view seems to have the same command ID with that of
6280 the toolbar item. */
6281 if (err == noErr)
6282 err = GetControlCommandID (item_view, &command_id);
6283 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6284 {
6285 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6286
6287 if (i < f->n_tool_bar_items)
6288 {
6289 HIRect bounds;
6290 HIViewRef content_view;
6291
6292 err = HIViewGetBounds (item_view, &bounds);
6293 if (err == noErr)
6294 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6295 kHIViewWindowContentID, &content_view);
6296 if (err == noErr)
6297 err = HIViewConvertRect (&bounds, item_view, content_view);
6298 if (err == noErr)
6299 SetRect (&last_mouse_glyph,
6300 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6301 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6302
6303 help_echo_object = help_echo_window = Qnil;
6304 help_echo_pos = -1;
6305 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6306 if (NILP (help_echo_string))
6307 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6308 }
6309 }
6310}
6311
6312static OSStatus
6313mac_handle_toolbar_command_event (next_handler, event, data)
6314 EventHandlerCallRef next_handler;
6315 EventRef event;
6316 void *data;
6317{
6318 OSStatus err, result = eventNotHandledErr;
6319 struct frame *f = (struct frame *) data;
6320 HICommand command;
6321
6322 err = GetEventParameter (event, kEventParamDirectObject,
6323 typeHICommand, NULL,
6324 sizeof (HICommand), NULL, &command);
6325 if (err != noErr)
6326 return result;
6327
6328 switch (GetEventKind (event))
6329 {
6330 case kEventCommandProcess:
6331 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6332 result = CallNextEventHandler (next_handler, event);
6333 else
6334 {
6335 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6336
6337 if (i < f->n_tool_bar_items
6338 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6339 {
6340 Lisp_Object frame;
6341 struct input_event buf;
6342
6343 EVENT_INIT (buf);
6344
6345 XSETFRAME (frame, f);
6346 buf.kind = TOOL_BAR_EVENT;
6347 buf.frame_or_window = frame;
6348 buf.arg = frame;
6349 kbd_buffer_store_event (&buf);
6350
6351 buf.kind = TOOL_BAR_EVENT;
6352 buf.frame_or_window = frame;
6353 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6354 buf.modifiers = mac_event_to_emacs_modifiers (event);
6355 kbd_buffer_store_event (&buf);
6356
6357 result = noErr;
6358 }
6359 }
6360 break;
6361
6362 default:
6363 abort ();
6364 }
6365#undef PROP
6366
6367 return result;
6368}
6369#endif /* USE_MAC_TOOLBAR */
6370
6371\f
1a578e9b
AC
6372/***********************************************************************
6373 Text Cursor
6374 ***********************************************************************/
6375
1a578e9b
AC
6376/* Set clipping for output in glyph row ROW. W is the window in which
6377 we operate. GC is the graphics context to set clipping in.
1a578e9b
AC
6378
6379 ROW may be a text row or, e.g., a mode line. Text rows must be
6380 clipped to the interior of the window dedicated to text display,
6381 mode lines must be clipped to the whole window. */
6382
6383static void
08f66682 6384x_clip_to_row (w, row, area, gc)
1a578e9b
AC
6385 struct window *w;
6386 struct glyph_row *row;
08f66682 6387 int area;
1a578e9b 6388 GC gc;
1a578e9b
AC
6389{
6390 struct frame *f = XFRAME (WINDOW_FRAME (w));
6391 Rect clip_rect;
08f66682 6392 int window_x, window_y, window_width;
1a578e9b 6393
08f66682 6394 window_box (w, area, &window_x, &window_y, &window_width, 0);
1a578e9b 6395
08f66682 6396 clip_rect.left = window_x;
1a578e9b
AC
6397 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6398 clip_rect.top = max (clip_rect.top, window_y);
6399 clip_rect.right = clip_rect.left + window_width;
6400 clip_rect.bottom = clip_rect.top + row->visible_height;
6401
1c4ac540 6402 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
1a578e9b
AC
6403}
6404
6405
6406/* Draw a hollow box cursor on window W in glyph row ROW. */
6407
6408static void
6409x_draw_hollow_cursor (w, row)
6410 struct window *w;
6411 struct glyph_row *row;
6412{
6413 struct frame *f = XFRAME (WINDOW_FRAME (w));
6414 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6415 Display *dpy = FRAME_MAC_DISPLAY (f);
6416 int x, y, wd, h;
6417 XGCValues xgcv;
6418 struct glyph *cursor_glyph;
6419 GC gc;
6420
1a578e9b
AC
6421 /* Get the glyph the cursor is on. If we can't tell because
6422 the current matrix is invalid or such, give up. */
6423 cursor_glyph = get_phys_cursor_glyph (w);
6424 if (cursor_glyph == NULL)
6425 return;
6426
4d91ce74 6427 /* Compute frame-relative coordinates for phys cursor. */
e8f6b0db 6428 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
4d91ce74 6429 wd = w->phys_cursor_width;
177c0ea7 6430
1a578e9b
AC
6431 /* The foreground of cursor_gc is typically the same as the normal
6432 background color, which can cause the cursor box to be invisible. */
6433 xgcv.foreground = f->output_data.mac->cursor_pixel;
6434 if (dpyinfo->scratch_cursor_gc)
6435 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6436 else
6437 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6438 GCForeground, &xgcv);
6439 gc = dpyinfo->scratch_cursor_gc;
6440
6441 /* Set clipping, draw the rectangle, and reset clipping again. */
08f66682 6442 x_clip_to_row (w, row, TEXT_AREA, gc);
4ea08bbf 6443 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
1c4ac540 6444 mac_reset_clip_rectangles (dpy, gc);
1a578e9b
AC
6445}
6446
6447
6448/* Draw a bar cursor on window W in glyph row ROW.
6449
6450 Implementation note: One would like to draw a bar cursor with an
6451 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6452 Unfortunately, I didn't find a font yet that has this property set.
6453 --gerd. */
6454
6455static void
6b61353c 6456x_draw_bar_cursor (w, row, width, kind)
1a578e9b
AC
6457 struct window *w;
6458 struct glyph_row *row;
6459 int width;
6b61353c 6460 enum text_cursor_kinds kind;
1a578e9b 6461{
6b61353c
KH
6462 struct frame *f = XFRAME (w->frame);
6463 struct glyph *cursor_glyph;
6464
6465 /* If cursor is out of bounds, don't draw garbage. This can happen
6466 in mini-buffer windows when switching between echo area glyphs
6467 and mini-buffer. */
6468 cursor_glyph = get_phys_cursor_glyph (w);
6469 if (cursor_glyph == NULL)
6470 return;
6471
6472 /* If on an image, draw like a normal cursor. That's usually better
6473 visible than drawing a bar, esp. if the image is large so that
6474 the bar might not be in the window. */
6475 if (cursor_glyph->type == IMAGE_GLYPH)
1a578e9b 6476 {
6b61353c
KH
6477 struct glyph_row *row;
6478 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6479 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6480 }
6481 else
6482 {
6483 Display *dpy = FRAME_MAC_DISPLAY (f);
6484 Window window = FRAME_MAC_WINDOW (f);
6485 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6486 unsigned long mask = GCForeground | GCBackground;
6487 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
1a578e9b 6488 XGCValues xgcv;
177c0ea7 6489
6b61353c
KH
6490 /* If the glyph's background equals the color we normally draw
6491 the bar cursor in, the bar cursor in its normal color is
6492 invisible. Use the glyph's foreground color instead in this
6493 case, on the assumption that the glyph's colors are chosen so
6494 that the glyph is legible. */
6495 if (face->background == f->output_data.mac->cursor_pixel)
6496 xgcv.background = xgcv.foreground = face->foreground;
6497 else
6498 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
177c0ea7 6499
1a578e9b
AC
6500 if (gc)
6501 XChangeGC (dpy, gc, mask, &xgcv);
6502 else
6503 {
6504 gc = XCreateGC (dpy, window, mask, &xgcv);
6505 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6506 }
6507
6508 if (width < 0)
668e2d32 6509 width = FRAME_CURSOR_WIDTH (f);
6b61353c 6510 width = min (cursor_glyph->pixel_width, width);
1a578e9b 6511
6b61353c 6512 w->phys_cursor_width = width;
08f66682 6513 x_clip_to_row (w, row, TEXT_AREA, gc);
6b61353c
KH
6514
6515 if (kind == BAR_CURSOR)
236072ae
YM
6516 mac_fill_rectangle (f, gc,
6517 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6518 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6519 width, row->height);
6b61353c 6520 else
236072ae
YM
6521 mac_fill_rectangle (f, gc,
6522 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6523 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6524 row->height - width),
6525 cursor_glyph->pixel_width,
6526 width);
6b61353c 6527
834263b6 6528 mac_reset_clip_rectangles (f, gc);
1a578e9b
AC
6529 }
6530}
6531
6532
f9e65eb3 6533/* RIF: Define cursor CURSOR on frame F. */
1a578e9b
AC
6534
6535static void
f9e65eb3
KS
6536mac_define_frame_cursor (f, cursor)
6537 struct frame *f;
6538 Cursor cursor;
1a578e9b 6539{
b465419f
YM
6540 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6541
6542 if (dpyinfo->x_focus_frame == f)
6543 SetThemeCursor (cursor);
1a578e9b
AC
6544}
6545
6546
f9e65eb3 6547/* RIF: Clear area on frame F. */
1a578e9b
AC
6548
6549static void
f9e65eb3
KS
6550mac_clear_frame_area (f, x, y, width, height)
6551 struct frame *f;
6552 int x, y, width, height;
1a578e9b 6553{
236072ae 6554 mac_clear_area (f, x, y, width, height);
1a578e9b
AC
6555}
6556
6557
f9e65eb3 6558/* RIF: Draw cursor on window W. */
1a578e9b
AC
6559
6560static void
e5a3b7d9 6561mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
1a578e9b 6562 struct window *w;
f9e65eb3 6563 struct glyph_row *glyph_row;
e5a3b7d9
KS
6564 int x, y;
6565 int cursor_type, cursor_width;
6566 int on_p, active_p;
1a578e9b 6567{
e5a3b7d9 6568 if (on_p)
1a578e9b 6569 {
e5a3b7d9 6570 w->phys_cursor_type = cursor_type;
1a578e9b
AC
6571 w->phys_cursor_on_p = 1;
6572
6b61353c
KH
6573 if (glyph_row->exact_window_width_line_p
6574 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6575 {
6576 glyph_row->cursor_in_fringe_p = 1;
6577 draw_fringe_bitmap (w, glyph_row, 0);
6578 }
6579 else
e5a3b7d9 6580 switch (cursor_type)
1a578e9b
AC
6581 {
6582 case HOLLOW_BOX_CURSOR:
6583 x_draw_hollow_cursor (w, glyph_row);
6584 break;
6585
6586 case FILLED_BOX_CURSOR:
f9e65eb3 6587 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
1a578e9b
AC
6588 break;
6589
6590 case BAR_CURSOR:
6b61353c
KH
6591 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6592 break;
6593
6594 case HBAR_CURSOR:
6595 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
1a578e9b
AC
6596 break;
6597
6598 case NO_CURSOR:
6b61353c 6599 w->phys_cursor_width = 0;
1a578e9b
AC
6600 break;
6601
6602 default:
6603 abort ();
6604 }
1a578e9b 6605 }
1a578e9b
AC
6606}
6607
e0f712ba
AC
6608\f
6609/* Icons. */
1a578e9b 6610
e0f712ba 6611#if 0 /* MAC_TODO: no icon support yet. */
1a578e9b 6612int
e0f712ba 6613x_bitmap_icon (f, icon)
1a578e9b 6614 struct frame *f;
e0f712ba 6615 Lisp_Object icon;
1a578e9b 6616{
e0f712ba 6617 HANDLE hicon;
1a578e9b 6618
e0f712ba 6619 if (FRAME_W32_WINDOW (f) == 0)
1a578e9b
AC
6620 return 1;
6621
e0f712ba
AC
6622 if (NILP (icon))
6623 hicon = LoadIcon (hinst, EMACS_CLASS);
6624 else if (STRINGP (icon))
d5db4077 6625 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
e0f712ba
AC
6626 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6627 else if (SYMBOLP (icon))
6628 {
6629 LPCTSTR name;
6630
6631 if (EQ (icon, intern ("application")))
6632 name = (LPCTSTR) IDI_APPLICATION;
6633 else if (EQ (icon, intern ("hand")))
6634 name = (LPCTSTR) IDI_HAND;
6635 else if (EQ (icon, intern ("question")))
6636 name = (LPCTSTR) IDI_QUESTION;
6637 else if (EQ (icon, intern ("exclamation")))
6638 name = (LPCTSTR) IDI_EXCLAMATION;
6639 else if (EQ (icon, intern ("asterisk")))
6640 name = (LPCTSTR) IDI_ASTERISK;
6641 else if (EQ (icon, intern ("winlogo")))
6642 name = (LPCTSTR) IDI_WINLOGO;
6643 else
6644 return 1;
1a578e9b 6645
e0f712ba 6646 hicon = LoadIcon (NULL, name);
1a578e9b 6647 }
e0f712ba 6648 else
1a578e9b
AC
6649 return 1;
6650
e0f712ba
AC
6651 if (hicon == NULL)
6652 return 1;
1a578e9b 6653
e0f712ba
AC
6654 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6655 (LPARAM) hicon);
1a578e9b
AC
6656
6657 return 0;
6658}
e0f712ba 6659#endif /* MAC_TODO */
1a578e9b 6660\f
e0f712ba
AC
6661/************************************************************************
6662 Handling X errors
6663 ************************************************************************/
1a578e9b 6664
e0f712ba
AC
6665/* Display Error Handling functions not used on W32. Listing them here
6666 helps diff stay in step when comparing w32term.c with xterm.c.
1a578e9b 6667
1a578e9b 6668x_error_catcher (display, error)
1a578e9b 6669x_catch_errors (dpy)
1a578e9b 6670x_catch_errors_unwind (old_val)
1a578e9b 6671x_check_errors (dpy, format)
1a578e9b 6672x_had_errors_p (dpy)
1a578e9b 6673x_clear_errors (dpy)
1a578e9b 6674x_uncatch_errors (dpy, count)
1a578e9b 6675x_trace_wire ()
e0f712ba
AC
6676x_connection_signal (signalnum)
6677x_connection_closed (dpy, error_message)
1a578e9b 6678x_error_quitter (display, error)
1a578e9b 6679x_error_handler (display, error)
1a578e9b 6680x_io_error_quitter (display)
1a578e9b 6681
e0f712ba
AC
6682 */
6683
1a578e9b
AC
6684\f
6685/* Changing the font of the frame. */
6686
6687/* Give frame F the font named FONTNAME as its default font, and
6688 return the full name of that font. FONTNAME may be a wildcard
6689 pattern; in that case, we choose some font that fits the pattern.
6690 The return value shows which font we chose. */
6691
6692Lisp_Object
6693x_new_font (f, fontname)
6694 struct frame *f;
6695 register char *fontname;
6696{
6697 struct font_info *fontp
cc02ceee 6698 = FS_LOAD_FONT (f, fontname);
1a578e9b
AC
6699
6700 if (!fontp)
6701 return Qnil;
6702
cc02ceee
ST
6703 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
6704 /* This font is already set in frame F. There's nothing more to
6705 do. */
6706 return build_string (fontp->full_name);
6707
e0f712ba
AC
6708 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6709 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6710 FRAME_FONTSET (f) = -1;
6711
e169f939
ST
6712 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6713 FRAME_SPACE_WIDTH (f) = fontp->space_width;
f1a83aab
KS
6714 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6715
6716 compute_fringe_widths (f, 1);
6717
1a578e9b 6718 /* Compute the scroll bar width in character columns. */
f1a83aab 6719 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
1a578e9b 6720 {
f1a83aab 6721 int wid = FRAME_COLUMN_WIDTH (f);
ffe8b3f4 6722 FRAME_CONFIG_SCROLL_BAR_COLS (f)
f1a83aab 6723 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
1a578e9b
AC
6724 }
6725 else
6726 {
f1a83aab
KS
6727 int wid = FRAME_COLUMN_WIDTH (f);
6728 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
1a578e9b
AC
6729 }
6730
6731 /* Now make the frame display the given font. */
6732 if (FRAME_MAC_WINDOW (f) != 0)
6733 {
f00691a3 6734 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
f1a83aab 6735 FRAME_FONT (f));
f00691a3 6736 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
f1a83aab 6737 FRAME_FONT (f));
f00691a3 6738 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
f1a83aab 6739 FRAME_FONT (f));
f00691a3 6740
b15325b2
ST
6741 /* Don't change the size of a tip frame; there's no point in
6742 doing it because it's done in Fx_show_tip, and it leads to
6743 problems because the tip frame has no widget. */
e0f712ba 6744 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
f1a83aab 6745 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1a578e9b 6746 }
1a578e9b
AC
6747
6748 return build_string (fontp->full_name);
6749}
6abfb022
YM
6750\f
6751/* Give frame F the fontset named FONTSETNAME as its default fontset,
6752 and return the full name of that fontset. FONTSETNAME may be a
6753 wildcard pattern; in that case, we choose some fontset that fits
6754 the pattern. FONTSETNAME may be a font name for ASCII characters;
6755 in that case, we create a fontset from that font name.
b15325b2 6756
6abfb022
YM
6757 The return value shows which fontset we chose.
6758 If FONTSETNAME specifies the default fontset, return Qt.
6759 If an ASCII font in the specified fontset can't be loaded, return
6760 Qnil. */
1a578e9b
AC
6761
6762Lisp_Object
6763x_new_fontset (f, fontsetname)
6764 struct frame *f;
cc02ceee 6765 Lisp_Object fontsetname;
1a578e9b 6766{
cc02ceee 6767 int fontset = fs_query_fontset (fontsetname, 0);
1a578e9b
AC
6768 Lisp_Object result;
6769
cc02ceee 6770 if (fontset > 0 && FRAME_FONTSET(f) == fontset)
1a578e9b
AC
6771 /* This fontset is already set in frame F. There's nothing more
6772 to do. */
6773 return fontset_name (fontset);
cc02ceee
ST
6774 else if (fontset == 0)
6775 /* The default fontset can't be the default font. */
6776 return Qt;
1a578e9b 6777
cc02ceee
ST
6778 if (fontset > 0)
6779 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6780 else
6781 result = x_new_font (f, SDATA (fontsetname));
1a578e9b
AC
6782
6783 if (!STRINGP (result))
6784 /* Can't load ASCII font. */
6785 return Qnil;
6786
cc02ceee
ST
6787 if (fontset < 0)
6788 fontset = new_fontset_from_font_name (result);
6789
e0f712ba 6790 /* Since x_new_font doesn't update any fontset information, do it now. */
7ca7ccd5 6791 FRAME_FONTSET (f) = fontset;
1a578e9b 6792
cc02ceee 6793 return fontset_name (fontset);
1a578e9b
AC
6794}
6795
1a578e9b
AC
6796\f
6797/***********************************************************************
e0f712ba 6798 TODO: W32 Input Methods
1a578e9b 6799 ***********************************************************************/
e0f712ba 6800/* Listing missing functions from xterm.c helps diff stay in step.
1a578e9b 6801
1a578e9b 6802xim_destroy_callback (xim, client_data, call_data)
1a578e9b 6803xim_open_dpy (dpyinfo, resource_name)
1a578e9b 6804struct xim_inst_t
1a578e9b 6805xim_instantiate_callback (display, client_data, call_data)
1a578e9b 6806xim_initialize (dpyinfo, resource_name)
1a578e9b 6807xim_close_dpy (dpyinfo)
1a578e9b 6808
e0f712ba 6809 */
1a578e9b 6810
1a578e9b 6811\f
bf06c82f
ST
6812void
6813mac_get_window_bounds (f, inner, outer)
6814 struct frame *f;
6815 Rect *inner, *outer;
6816{
6817#if TARGET_API_MAC_CARBON
6818 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6819 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6820#else /* not TARGET_API_MAC_CARBON */
6821 RgnHandle region = NewRgn ();
f94a2622 6822
bf06c82f
ST
6823 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6824 *inner = (*region)->rgnBBox;
6825 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6826 *outer = (*region)->rgnBBox;
6827 DisposeRgn (region);
6828#endif /* not TARGET_API_MAC_CARBON */
6829}
6830
bed0bf95
YM
6831static void
6832mac_handle_origin_change (f)
6833 struct frame *f;
6834{
6835 x_real_positions (f, &f->left_pos, &f->top_pos);
6836}
6837
6838static void
6839mac_handle_size_change (f, pixelwidth, pixelheight)
6840 struct frame *f;
6841 int pixelwidth, pixelheight;
6842{
6843 int cols, rows;
6844
6845 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6846 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6847
6848 if (cols != FRAME_COLS (f)
6849 || rows != FRAME_LINES (f)
6850 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6851 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6852 {
6853 /* We pass 1 for DELAY since we can't run Lisp code inside of
6854 a BLOCK_INPUT. */
6855 change_frame_size (f, rows, cols, 0, 1, 0);
6856 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6857 FRAME_PIXEL_HEIGHT (f) = pixelheight;
bed0bf95
YM
6858
6859 /* If cursor was outside the new size, mark it as off. */
6860 mark_window_cursors_off (XWINDOW (f->root_window));
6861
6862 /* Clear out any recollection of where the mouse highlighting
6863 was, since it might be in a place that's outside the new
6864 frame size. Actually checking whether it is outside is a
6865 pain in the neck, so don't try--just let the highlighting be
6866 done afresh with new size. */
6867 cancel_mouse_face (f);
6868
6869#if TARGET_API_MAC_CARBON
6870 if (f->output_data.mac->hourglass_control)
6871 {
6872#if USE_CG_DRAWING
6873 mac_prepare_for_quickdraw (f);
6874#endif
6875 MoveControl (f->output_data.mac->hourglass_control,
6876 pixelwidth - HOURGLASS_WIDTH, 0);
6877 }
6878#endif
6879 }
6880}
bf06c82f 6881
95dfb192 6882\f
1a578e9b
AC
6883/* Calculate the absolute position in frame F
6884 from its current recorded position values and gravity. */
6885
e0f712ba 6886void
1a578e9b
AC
6887x_calc_absolute_position (f)
6888 struct frame *f;
6889{
f1a83aab 6890 int flags = f->size_hint_flags;
bf06c82f 6891 Rect inner, outer;
1a578e9b 6892
bf06c82f
ST
6893 /* We have nothing to do if the current position
6894 is already for the top-left corner. */
6895 if (! ((flags & XNegative) || (flags & YNegative)))
6896 return;
1a578e9b 6897
bf06c82f 6898 /* Find the offsets of the outside upper-left corner of
1a578e9b 6899 the inner window, with respect to the outer window. */
1d5bcd55 6900 BLOCK_INPUT;
bf06c82f 6901 mac_get_window_bounds (f, &inner, &outer);
1d5bcd55 6902 UNBLOCK_INPUT;
e0f712ba 6903
1a578e9b
AC
6904 /* Treat negative positions as relative to the leftmost bottommost
6905 position that fits on the screen. */
6906 if (flags & XNegative)
834263b6
YM
6907 f->left_pos += (FRAME_MAC_DISPLAY_INFO (f)->width
6908 - (outer.right - outer.left));
bf06c82f 6909
1a578e9b 6910 if (flags & YNegative)
834263b6
YM
6911 f->top_pos += (FRAME_MAC_DISPLAY_INFO (f)->height
6912 - (outer.bottom - outer.top));
bf06c82f 6913
1a578e9b
AC
6914 /* The left_pos and top_pos
6915 are now relative to the top and left screen edges,
6916 so the flags should correspond. */
f1a83aab 6917 f->size_hint_flags &= ~ (XNegative | YNegative);
1a578e9b
AC
6918}
6919
6920/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6921 to really change the position, and 0 when calling from
6922 x_make_frame_visible (in that case, XOFF and YOFF are the current
6923 position values). It is -1 when calling from x_set_frame_parameters,
6924 which means, do adjust for borders but don't change the gravity. */
6925
6926void
6927x_set_offset (f, xoff, yoff, change_gravity)
6928 struct frame *f;
6929 register int xoff, yoff;
6930 int change_gravity;
6931{
6932 if (change_gravity > 0)
6933 {
f1a83aab
KS
6934 f->top_pos = yoff;
6935 f->left_pos = xoff;
6936 f->size_hint_flags &= ~ (XNegative | YNegative);
1a578e9b 6937 if (xoff < 0)
f1a83aab 6938 f->size_hint_flags |= XNegative;
1a578e9b 6939 if (yoff < 0)
f1a83aab
KS
6940 f->size_hint_flags |= YNegative;
6941 f->win_gravity = NorthWestGravity;
1a578e9b
AC
6942 }
6943 x_calc_absolute_position (f);
6944
6945 BLOCK_INPUT;
6946 x_wm_set_size_hint (f, (long) 0, 0);
6947
bf06c82f
ST
6948#if TARGET_API_MAC_CARBON
6949 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6950 /* If the title bar is completely outside the screen, adjust the
6951 position. */
6952 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6953 kWindowConstrainMoveRegardlessOfFit
6954 | kWindowConstrainAllowPartial, NULL, NULL);
bed0bf95 6955 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
bed0bf95 6956 mac_handle_origin_change (f);
bf06c82f
ST
6957#else
6958 {
6959 Rect inner, outer, screen_rect, dummy;
6960 RgnHandle region = NewRgn ();
f94a2622 6961
bf06c82f
ST
6962 mac_get_window_bounds (f, &inner, &outer);
6963 f->x_pixels_diff = inner.left - outer.left;
6964 f->y_pixels_diff = inner.top - outer.top;
6965 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6966 f->top_pos + f->y_pixels_diff, false);
6967
6968 /* If the title bar is completely outside the screen, adjust the
6969 position. The variable `outer' holds the title bar rectangle.
6970 The variable `inner' holds slightly smaller one than `outer',
6971 so that the calculation of overlapping may not become too
6972 strict. */
6973 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6974 outer = (*region)->rgnBBox;
6975 DisposeRgn (region);
6976 inner = outer;
6977 InsetRect (&inner, 8, 8);
6978 screen_rect = qd.screenBits.bounds;
6979 screen_rect.top += GetMBarHeight ();
6980
6981 if (!SectRect (&inner, &screen_rect, &dummy))
6982 {
6983 if (inner.right <= screen_rect.left)
6984 f->left_pos = screen_rect.left;
6985 else if (inner.left >= screen_rect.right)
6986 f->left_pos = screen_rect.right - (outer.right - outer.left);
6987
6988 if (inner.bottom <= screen_rect.top)
6989 f->top_pos = screen_rect.top;
6990 else if (inner.top >= screen_rect.bottom)
6991 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6992
6993 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6994 f->top_pos + f->y_pixels_diff, false);
6995 }
6996 }
6997#endif
1a578e9b
AC
6998
6999 UNBLOCK_INPUT;
7000}
7001
7002/* Call this to change the size of frame F's x-window.
7003 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
7004 for this size change and subsequent size changes.
7005 Otherwise we leave the window gravity unchanged. */
7006
7007void
7008x_set_window_size (f, change_gravity, cols, rows)
7009 struct frame *f;
7010 int change_gravity;
7011 int cols, rows;
7012{
7013 int pixelwidth, pixelheight;
177c0ea7 7014
e0f712ba 7015 BLOCK_INPUT;
177c0ea7 7016
1a578e9b 7017 check_frame_size (f, &rows, &cols);
f1a83aab
KS
7018 f->scroll_bar_actual_width
7019 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
d33c49e8 7020
5958f265 7021 compute_fringe_widths (f, 0);
d33c49e8 7022
f1a83aab
KS
7023 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
7024 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1a578e9b 7025
f1a83aab 7026 f->win_gravity = NorthWestGravity;
1a578e9b
AC
7027 x_wm_set_size_hint (f, (long) 0, 0);
7028
7029 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
1a578e9b 7030
3354caee 7031#if TARGET_API_MAC_CARBON
bed0bf95
YM
7032 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
7033#endif
7034 mac_handle_size_change (f, pixelwidth, pixelheight);
e0f712ba 7035
70385fe6
YM
7036 if (f->output_data.mac->internal_border_width
7037 != FRAME_INTERNAL_BORDER_WIDTH (f))
7038 {
7039 mac_clear_window (f);
7040 f->output_data.mac->internal_border_width
7041 = FRAME_INTERNAL_BORDER_WIDTH (f);
7042 }
7043
7044 SET_FRAME_GARBAGED (f);
7045
e0f712ba 7046 UNBLOCK_INPUT;
1a578e9b
AC
7047}
7048\f
7049/* Mouse warping. */
7050
7051void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
7052
7053void
7054x_set_mouse_position (f, x, y)
7055 struct frame *f;
7056 int x, y;
7057{
7058 int pix_x, pix_y;
7059
f1a83aab
KS
7060 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
7061 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
1a578e9b
AC
7062
7063 if (pix_x < 0) pix_x = 0;
f1a83aab 7064 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1a578e9b
AC
7065
7066 if (pix_y < 0) pix_y = 0;
f1a83aab 7067 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1a578e9b
AC
7068
7069 x_set_mouse_pixel_position (f, pix_x, pix_y);
7070}
7071
1a578e9b
AC
7072void
7073x_set_mouse_pixel_position (f, pix_x, pix_y)
7074 struct frame *f;
7075 int pix_x, pix_y;
7076{
92289429 7077#ifdef MAC_OSX
7adf3143
YM
7078 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
7079 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
92289429
YM
7080
7081 BLOCK_INPUT;
7adf3143 7082 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
92289429
YM
7083 UNBLOCK_INPUT;
7084#else
7085#if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
1a578e9b
AC
7086 BLOCK_INPUT;
7087
7088 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
7089 0, 0, 0, 0, pix_x, pix_y);
7090 UNBLOCK_INPUT;
7091#endif
92289429 7092#endif
1a578e9b
AC
7093}
7094\f
7095/* focus shifting, raising and lowering. */
7096
e0f712ba 7097void
1a578e9b
AC
7098x_focus_on_frame (f)
7099 struct frame *f;
7100{
7101#if 0 /* This proves to be unpleasant. */
7102 x_raise_frame (f);
7103#endif
7104#if 0
7105 /* I don't think that the ICCCM allows programs to do things like this
7106 without the interaction of the window manager. Whatever you end up
7107 doing with this code, do it to x_unfocus_frame too. */
7108 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7109 RevertToPointerRoot, CurrentTime);
7110#endif /* ! 0 */
7111}
7112
e0f712ba 7113void
1a578e9b
AC
7114x_unfocus_frame (f)
7115 struct frame *f;
7116{
1a578e9b
AC
7117}
7118
7119/* Raise frame F. */
95dfb192 7120
1a578e9b
AC
7121void
7122x_raise_frame (f)
7123 struct frame *f;
7124{
7125 if (f->async_visible)
c3f4c690
ST
7126 {
7127 BLOCK_INPUT;
b465419f 7128 BringToFront (FRAME_MAC_WINDOW (f));
c3f4c690
ST
7129 UNBLOCK_INPUT;
7130 }
1a578e9b
AC
7131}
7132
7133/* Lower frame F. */
95dfb192 7134
1a578e9b
AC
7135void
7136x_lower_frame (f)
7137 struct frame *f;
7138{
7139 if (f->async_visible)
c3f4c690
ST
7140 {
7141 BLOCK_INPUT;
b465419f 7142 SendBehind (FRAME_MAC_WINDOW (f), NULL);
c3f4c690
ST
7143 UNBLOCK_INPUT;
7144 }
1a578e9b
AC
7145}
7146
e0f712ba 7147static void
1a578e9b
AC
7148XTframe_raise_lower (f, raise_flag)
7149 FRAME_PTR f;
7150 int raise_flag;
7151{
7152 if (raise_flag)
7153 x_raise_frame (f);
7154 else
7155 x_lower_frame (f);
7156}
7157\f
7158/* Change of visibility. */
7159
1f98fbb4
YM
7160static void
7161mac_handle_visibility_change (f)
7162 struct frame *f;
7163{
3354caee 7164 WindowRef wp = FRAME_MAC_WINDOW (f);
1f98fbb4
YM
7165 int visible = 0, iconified = 0;
7166 struct input_event buf;
7167
7168 if (IsWindowVisible (wp))
f93e4d4f
YM
7169 {
7170 if (IsWindowCollapsed (wp))
7171 iconified = 1;
7172 else
7173 visible = 1;
7174 }
1f98fbb4
YM
7175
7176 if (!f->async_visible && visible)
7177 {
7178 if (f->iconified)
7179 {
7180 /* wait_reading_process_output will notice this and update
7181 the frame's display structures. If we were made
7182 invisible, we should not set garbaged, because that stops
7183 redrawing on Update events. */
7184 SET_FRAME_GARBAGED (f);
7185
7186 EVENT_INIT (buf);
7187 buf.kind = DEICONIFY_EVENT;
7188 XSETFRAME (buf.frame_or_window, f);
36f0107c 7189 buf.arg = Qnil;
1f98fbb4
YM
7190 kbd_buffer_store_event (&buf);
7191 }
7192 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7193 /* Force a redisplay sooner or later to update the
7194 frame titles in case this is the second frame. */
7195 record_asynch_buffer_change ();
7196 }
7197 else if (f->async_visible && !visible)
7198 if (iconified)
7199 {
7200 EVENT_INIT (buf);
7201 buf.kind = ICONIFY_EVENT;
7202 XSETFRAME (buf.frame_or_window, f);
36f0107c 7203 buf.arg = Qnil;
1f98fbb4
YM
7204 kbd_buffer_store_event (&buf);
7205 }
7206
7207 f->async_visible = visible;
7208 f->async_iconified = iconified;
7209}
7210
1a578e9b
AC
7211/* This tries to wait until the frame is really visible.
7212 However, if the window manager asks the user where to position
7213 the frame, this will return before the user finishes doing that.
7214 The frame will not actually be visible at that time,
7215 but it will become visible later when the window manager
7216 finishes with it. */
7217
7218void
7219x_make_frame_visible (f)
7220 struct frame *f;
7221{
1a578e9b
AC
7222 BLOCK_INPUT;
7223
7224 if (! FRAME_VISIBLE_P (f))
7225 {
7226 /* We test FRAME_GARBAGED_P here to make sure we don't
7227 call x_set_offset a second time
7228 if we get to x_make_frame_visible a second time
7229 before the window gets really visible. */
7230 if (! FRAME_ICONIFIED_P (f)
7231 && ! f->output_data.mac->asked_for_visible)
7adf3143 7232 x_set_offset (f, f->left_pos, f->top_pos, 0);
1f98fbb4
YM
7233
7234 f->output_data.mac->asked_for_visible = 1;
7235
1f98fbb4 7236 CollapseWindow (FRAME_MAC_WINDOW (f), false);
1a578e9b
AC
7237 ShowWindow (FRAME_MAC_WINDOW (f));
7238 }
7239
7240 XFlush (FRAME_MAC_DISPLAY (f));
7241
7242 /* Synchronize to ensure Emacs knows the frame is visible
7243 before we do anything else. We do this loop with input not blocked
7244 so that incoming events are handled. */
7245 {
7246 Lisp_Object frame;
7247 int count;
7248
7249 /* This must come after we set COUNT. */
7250 UNBLOCK_INPUT;
7251
7252 XSETFRAME (frame, f);
7253
7254 /* Wait until the frame is visible. Process X events until a
7255 MapNotify event has been seen, or until we think we won't get a
7256 MapNotify at all.. */
7257 for (count = input_signal_count + 10;
7258 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7259 {
7260 /* Force processing of queued events. */
7261 x_sync (f);
7262
7263 /* Machines that do polling rather than SIGIO have been
7264 observed to go into a busy-wait here. So we'll fake an
7265 alarm signal to let the handler know that there's something
7266 to be read. We used to raise a real alarm, but it seems
7267 that the handler isn't always enabled here. This is
7268 probably a bug. */
7269 if (input_polling_used ())
7270 {
7271 /* It could be confusing if a real alarm arrives while
7272 processing the fake one. Turn it off and let the
7273 handler reset it. */
7274 extern void poll_for_input_1 P_ ((void));
7275 int old_poll_suppress_count = poll_suppress_count;
7276 poll_suppress_count = 1;
7277 poll_for_input_1 ();
7278 poll_suppress_count = old_poll_suppress_count;
7279 }
7280
7281 /* See if a MapNotify event has been processed. */
7282 FRAME_SAMPLE_VISIBILITY (f);
7283 }
7284 }
7285}
7286
7287/* Change from mapped state to withdrawn state. */
7288
7289/* Make the frame visible (mapped and not iconified). */
7290
7291void
7292x_make_frame_invisible (f)
7293 struct frame *f;
7294{
1f98fbb4
YM
7295 /* A deactivate event does not occur when the last visible frame is
7296 made invisible. So if we clear the highlight here, it will not
7297 be rehighlighted when it is made visible. */
7298#if 0
1a578e9b
AC
7299 /* Don't keep the highlight on an invisible frame. */
7300 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7301 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
1f98fbb4 7302#endif
177c0ea7 7303
1a578e9b 7304 BLOCK_INPUT;
177c0ea7 7305
7adf3143 7306#if !TARGET_API_MAC_CARBON
7ca7ccd5
YM
7307 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7308 that the current position of the window is user-specified, rather than
7309 program-specified, so that when the window is mapped again, it will be
7310 placed at the same location, without forcing the user to position it
7311 by hand again (they have already done that once for this window.) */
7312 x_wm_set_size_hint (f, (long) 0, 1);
7adf3143 7313#endif
7ca7ccd5 7314
1a578e9b 7315 HideWindow (FRAME_MAC_WINDOW (f));
177c0ea7 7316
1a578e9b 7317 UNBLOCK_INPUT;
1f98fbb4 7318
3354caee 7319#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
7320 mac_handle_visibility_change (f);
7321#endif
1a578e9b
AC
7322}
7323
7324/* Change window state from mapped to iconified. */
7325
7326void
7327x_iconify_frame (f)
7328 struct frame *f;
7329{
3e7424f7 7330 OSStatus err;
1f98fbb4
YM
7331
7332 /* A deactivate event does not occur when the last visible frame is
7333 iconified. So if we clear the highlight here, it will not be
7334 rehighlighted when it is deiconified. */
7335#if 0
1a578e9b 7336 /* Don't keep the highlight on an invisible frame. */
742fbed7
AC
7337 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7338 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
1f98fbb4 7339#endif
1a578e9b
AC
7340
7341 if (f->async_iconified)
7342 return;
7343
7344 BLOCK_INPUT;
7345
1f98fbb4
YM
7346 FRAME_SAMPLE_VISIBILITY (f);
7347
7348 if (! FRAME_VISIBLE_P (f))
7349 ShowWindow (FRAME_MAC_WINDOW (f));
7350
7351 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
177c0ea7 7352
1a578e9b 7353 UNBLOCK_INPUT;
1f98fbb4
YM
7354
7355 if (err != noErr)
7356 error ("Can't notify window manager of iconification");
7357
3354caee 7358#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
7359 mac_handle_visibility_change (f);
7360#endif
1a578e9b 7361}
e0f712ba 7362
1a578e9b 7363\f
6b61353c 7364/* Free X resources of frame F. */
1a578e9b
AC
7365
7366void
6b61353c 7367x_free_frame_resources (f)
1a578e9b
AC
7368 struct frame *f;
7369{
7370 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3354caee 7371 WindowRef wp = FRAME_MAC_WINDOW (f);
1a578e9b
AC
7372
7373 BLOCK_INPUT;
7374
25c9622b
YM
7375 if (wp != tip_window)
7376 remove_window_handler (wp);
7377
c857519f
YM
7378#if USE_CG_DRAWING
7379 mac_prepare_for_quickdraw (f);
7380#endif
50bf7673
ST
7381 DisposeWindow (wp);
7382 if (wp == tip_window)
7383 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7384 closed' event. So we reset tip_window here. */
7385 tip_window = NULL;
1a578e9b
AC
7386
7387 free_frame_menubar (f);
6b61353c
KH
7388
7389 if (FRAME_FACE_CACHE (f))
7390 free_frame_faces (f);
7391
7392 x_free_gcs (f);
1a578e9b 7393
b15325b2
ST
7394 if (FRAME_SIZE_HINTS (f))
7395 xfree (FRAME_SIZE_HINTS (f));
7396
1a578e9b 7397 xfree (f->output_data.mac);
6b61353c
KH
7398 f->output_data.mac = NULL;
7399
1a578e9b 7400 if (f == dpyinfo->x_focus_frame)
4cb62a90
YM
7401 {
7402 dpyinfo->x_focus_frame = 0;
7403#if USE_MAC_FONT_PANEL
7404 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7405#endif
7406 }
1a578e9b
AC
7407 if (f == dpyinfo->x_focus_event_frame)
7408 dpyinfo->x_focus_event_frame = 0;
7409 if (f == dpyinfo->x_highlight_frame)
7410 dpyinfo->x_highlight_frame = 0;
7411
1a578e9b
AC
7412 if (f == dpyinfo->mouse_face_mouse_frame)
7413 {
7414 dpyinfo->mouse_face_beg_row
7415 = dpyinfo->mouse_face_beg_col = -1;
7416 dpyinfo->mouse_face_end_row
7417 = dpyinfo->mouse_face_end_col = -1;
7418 dpyinfo->mouse_face_window = Qnil;
7419 dpyinfo->mouse_face_deferred_gc = 0;
7420 dpyinfo->mouse_face_mouse_frame = 0;
7421 }
7422
7423 UNBLOCK_INPUT;
7424}
6b61353c
KH
7425
7426
7427/* Destroy the X window of frame F. */
7428
7429void
7430x_destroy_window (f)
7431 struct frame *f;
7432{
7433 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7434
7435 x_free_frame_resources (f);
7436
7437 dpyinfo->reference_count--;
7438}
7439
1a578e9b
AC
7440\f
7441/* Setting window manager hints. */
7442
7443/* Set the normal size hints for the window manager, for frame F.
7444 FLAGS is the flags word to use--or 0 meaning preserve the flags
7445 that the window now has.
7446 If USER_POSITION is nonzero, we set the USPosition
7447 flag (this is useful when FLAGS is 0). */
1a578e9b
AC
7448void
7449x_wm_set_size_hint (f, flags, user_position)
7450 struct frame *f;
7451 long flags;
7452 int user_position;
7453{
b15325b2
ST
7454 int base_width, base_height, width_inc, height_inc;
7455 int min_rows = 0, min_cols = 0;
7456 XSizeHints *size_hints;
1a578e9b 7457
b15325b2
ST
7458 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7459 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7460 width_inc = FRAME_COLUMN_WIDTH (f);
7461 height_inc = FRAME_LINE_HEIGHT (f);
1a578e9b 7462
b15325b2 7463 check_frame_size (f, &min_rows, &min_cols);
1a578e9b 7464
b15325b2
ST
7465 size_hints = FRAME_SIZE_HINTS (f);
7466 if (size_hints == NULL)
1a578e9b 7467 {
b15325b2
ST
7468 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7469 bzero (size_hints, sizeof (XSizeHints));
1a578e9b 7470 }
1a578e9b 7471
b15325b2
ST
7472 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7473 size_hints->width_inc = width_inc;
7474 size_hints->height_inc = height_inc;
7475 size_hints->min_width = base_width + min_cols * width_inc;
7476 size_hints->min_height = base_height + min_rows * height_inc;
7477 size_hints->base_width = base_width;
7478 size_hints->base_height = base_height;
1a578e9b 7479
b15325b2
ST
7480 if (flags)
7481 size_hints->flags = flags;
7482 else if (user_position)
1a578e9b 7483 {
b15325b2
ST
7484 size_hints->flags &= ~ PPosition;
7485 size_hints->flags |= USPosition;
1a578e9b 7486 }
1a578e9b
AC
7487}
7488
e0f712ba 7489#if 0 /* MAC_TODO: hide application instead of iconify? */
1a578e9b
AC
7490/* Used for IconicState or NormalState */
7491
7492void
7493x_wm_set_window_state (f, state)
7494 struct frame *f;
7495 int state;
7496{
7497#ifdef USE_X_TOOLKIT
7498 Arg al[1];
7499
7500 XtSetArg (al[0], XtNinitialState, state);
7501 XtSetValues (f->output_data.x->widget, al, 1);
7502#else /* not USE_X_TOOLKIT */
7503 Window window = FRAME_X_WINDOW (f);
7504
7505 f->output_data.x->wm_hints.flags |= StateHint;
7506 f->output_data.x->wm_hints.initial_state = state;
7507
7508 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7509#endif /* not USE_X_TOOLKIT */
7510}
7511
7512void
7513x_wm_set_icon_pixmap (f, pixmap_id)
7514 struct frame *f;
7515 int pixmap_id;
7516{
7517 Pixmap icon_pixmap;
7518
7519#ifndef USE_X_TOOLKIT
7520 Window window = FRAME_X_WINDOW (f);
7521#endif
7522
7523 if (pixmap_id > 0)
7524 {
7525 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7526 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7527 }
7528 else
7529 {
7530 /* It seems there is no way to turn off use of an icon pixmap.
7531 The following line does it, only if no icon has yet been created,
7532 for some window managers. But with mwm it crashes.
7533 Some people say it should clear the IconPixmapHint bit in this case,
7534 but that doesn't work, and the X consortium said it isn't the
7535 right thing at all. Since there is no way to win,
7536 best to explicitly give up. */
7537#if 0
7538 f->output_data.x->wm_hints.icon_pixmap = None;
7539#else
7540 return;
7541#endif
7542 }
7543
7544#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7545
7546 {
7547 Arg al[1];
7548 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7549 XtSetValues (f->output_data.x->widget, al, 1);
7550 }
7551
7552#else /* not USE_X_TOOLKIT */
177c0ea7 7553
1a578e9b
AC
7554 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7555 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7556
7557#endif /* not USE_X_TOOLKIT */
7558}
7559
e0f712ba 7560#endif /* MAC_TODO */
1a578e9b
AC
7561
7562void
7563x_wm_set_icon_position (f, icon_x, icon_y)
7564 struct frame *f;
7565 int icon_x, icon_y;
7566{
7567#if 0 /* MAC_TODO: no icons on Mac */
7568#ifdef USE_X_TOOLKIT
7569 Window window = XtWindow (f->output_data.x->widget);
7570#else
7571 Window window = FRAME_X_WINDOW (f);
7572#endif
7573
7574 f->output_data.x->wm_hints.flags |= IconPositionHint;
7575 f->output_data.x->wm_hints.icon_x = icon_x;
7576 f->output_data.x->wm_hints.icon_y = icon_y;
7577
7578 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
e0f712ba 7579#endif /* MAC_TODO */
1a578e9b
AC
7580}
7581
7582\f
468213f1
YM
7583/***********************************************************************
7584 XLFD Pattern Match
7585 ***********************************************************************/
7586
7587/* An XLFD pattern is divided into blocks delimited by '*'. This
7588 structure holds information for each block. */
7589struct xlfdpat_block
7590{
7591 /* Length of the pattern string in this block. Non-zero except for
7592 the first and the last blocks. */
7593 int len;
7594
7595 /* Pattern string except the last character in this block. The last
7596 character is replaced with NUL in order to use it as a
7597 sentinel. */
7598 unsigned char *pattern;
7599
7600 /* Last character of the pattern string. Must not be '?'. */
7601 unsigned char last_char;
7602
7603 /* One of the tables for the Boyer-Moore string search. It
7604 specifies the number of positions to proceed for each character
7605 with which the match fails. */
7606 int skip[256];
7607
7608 /* The skip value for the last character in the above `skip' is
7609 assigned to `infinity' in order to simplify a loop condition.
7610 The original value is saved here. */
7611 int last_char_skip;
7612};
7613
7614struct xlfdpat
7615{
7616 /* Normalized pattern string. "Normalized" means that capital
7617 letters are lowered, blocks are not empty except the first and
7618 the last ones, and trailing '?'s in a block that is not the last
7619 one are moved to the next one. The last character in each block
7620 is replaced with NUL. */
7621 unsigned char *buf;
7622
7623 /* Number of characters except '*'s and trailing '?'s in the
7624 normalized pattern string. */
7625 int nchars;
7626
7627 /* Number of trailing '?'s in the normalized pattern string. */
7628 int trailing_anychars;
7629
7630 /* Number of blocks and information for each block. The latter is
7631 NULL if the pattern is exact (no '*' or '?' in it). */
7632 int nblocks;
7633 struct xlfdpat_block *blocks;
7634};
7635
7636static void
7637xlfdpat_destroy (pat)
7638 struct xlfdpat *pat;
7639{
7640 if (pat)
7641 {
7642 if (pat->buf)
7643 {
7644 if (pat->blocks)
7645 xfree (pat->blocks);
7646 xfree (pat->buf);
7647 }
7648 xfree (pat);
7649 }
7650}
7651
7652static struct xlfdpat *
7653xlfdpat_create (pattern)
369a7a37 7654 const char *pattern;
468213f1
YM
7655{
7656 struct xlfdpat *pat;
7657 int nblocks, i, skip;
7658 unsigned char last_char, *p, *q, *anychar_head;
369a7a37 7659 const unsigned char *ptr;
468213f1
YM
7660 struct xlfdpat_block *blk;
7661
7662 pat = xmalloc (sizeof (struct xlfdpat));
468213f1 7663 pat->buf = xmalloc (strlen (pattern) + 1);
468213f1
YM
7664
7665 /* Normalize the pattern string and store it to `pat->buf'. */
7666 nblocks = 0;
7667 anychar_head = NULL;
7668 q = pat->buf;
7669 last_char = '\0';
369a7a37 7670 for (ptr = pattern; *ptr; ptr++)
468213f1 7671 {
369a7a37 7672 unsigned char c = *ptr;
468213f1
YM
7673
7674 if (c == '*')
7675 if (last_char == '*')
7676 /* ...a** -> ...a* */
7677 continue;
7678 else
7679 {
7680 if (last_char == '?')
f93e4d4f
YM
7681 {
7682 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7683 /* ...*??* -> ...*?? */
7684 continue;
7685 else
7686 /* ...a??* -> ...a*?? */
7687 {
7688 *anychar_head++ = '*';
7689 c = '?';
7690 }
7691 }
468213f1
YM
7692 nblocks++;
7693 }
7694 else if (c == '?')
7695 {
7696 if (last_char != '?')
7697 anychar_head = q;
7698 }
7699 else
7700 /* On Mac OS X 10.3, tolower also converts non-ASCII
7701 characters for some locales. */
7702 if (isascii (c))
7703 c = tolower (c);
7704
7705 *q++ = last_char = c;
7706 }
7707 *q = '\0';
7708 nblocks++;
7709 pat->nblocks = nblocks;
7710 if (last_char != '?')
7711 pat->trailing_anychars = 0;
7712 else
7713 {
7714 pat->trailing_anychars = q - anychar_head;
7715 q = anychar_head;
7716 }
7717 pat->nchars = q - pat->buf - (nblocks - 1);
7718
7719 if (anychar_head == NULL && nblocks == 1)
7720 {
7721 /* The pattern is exact. */
7722 pat->blocks = NULL;
7723 return pat;
7724 }
7725
7726 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
468213f1
YM
7727
7728 /* Divide the normalized pattern into blocks. */
7729 p = pat->buf;
7730 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7731 {
7732 blk->pattern = p;
7733 while (*p != '*')
7734 p++;
7735 blk->len = p - blk->pattern;
7736 p++;
7737 }
7738 blk->pattern = p;
7739 blk->len = q - blk->pattern;
7740
7741 /* Setup a table for the Boyer-Moore string search. */
7742 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7743 if (blk->len != 0)
7744 {
7745 blk->last_char = blk->pattern[blk->len - 1];
7746 blk->pattern[blk->len - 1] = '\0';
7747
7748 for (skip = 1; skip < blk->len; skip++)
7749 if (blk->pattern[blk->len - skip - 1] == '?')
7750 break;
7751
7752 for (i = 0; i < 256; i++)
7753 blk->skip[i] = skip;
7754
7755 p = blk->pattern + (blk->len - skip);
7756 while (--skip > 0)
7757 blk->skip[*p++] = skip;
7758
7759 blk->last_char_skip = blk->skip[blk->last_char];
7760 }
7761
7762 return pat;
468213f1
YM
7763}
7764
7765static INLINE int
7766xlfdpat_exact_p (pat)
7767 struct xlfdpat *pat;
7768{
7c3d233d 7769 return pat->blocks == NULL;
468213f1
YM
7770}
7771
7772/* Return the first string in STRING + 0, ..., STRING + START_MAX such
7773 that the pattern in *BLK matches with its prefix. Return NULL
7774 there is no such strings. STRING must be lowered in advance. */
7775
369a7a37 7776static const char *
468213f1
YM
7777xlfdpat_block_match_1 (blk, string, start_max)
7778 struct xlfdpat_block *blk;
369a7a37 7779 const unsigned char *string;
468213f1
YM
7780 int start_max;
7781{
7782 int start, infinity;
369a7a37
YM
7783 unsigned char *p;
7784 const unsigned char *s;
468213f1
YM
7785
7786 xassert (blk->len > 0);
7787 xassert (start_max + blk->len <= strlen (string));
7c3d233d 7788 xassert (blk->last_char != '?');
468213f1
YM
7789
7790 /* See the comments in the function `boyer_moore' (search.c) for the
7791 use of `infinity'. */
7792 infinity = start_max + blk->len + 1;
7793 blk->skip[blk->last_char] = infinity;
7794
7795 start = 0;
7796 do
7797 {
7798 /* Check the last character of the pattern. */
7799 s = string + blk->len - 1;
7800 do
7801 {
7802 start += blk->skip[*(s + start)];
7803 }
7804 while (start <= start_max);
7805
7806 if (start < infinity)
7807 /* Couldn't find the last character. */
7808 return NULL;
7809
7810 /* No less than `infinity' means we could find the last
7811 character at `s[start - infinity]'. */
7812 start -= infinity;
7813
7814 /* Check the remaining characters. We prefer making no-'?'
7815 cases faster because the use of '?' is really rare. */
7816 p = blk->pattern;
7817 s = string + start;
7818 do
7819 {
7820 while (*p++ == *s++)
7821 ;
7822 }
7823 while (*(p - 1) == '?');
7824
7825 if (*(p - 1) == '\0')
7826 /* Matched. */
7827 return string + start;
7828
7829 /* Didn't match. */
7830 start += blk->last_char_skip;
7831 }
7832 while (start <= start_max);
7833
7834 return NULL;
7835}
7836
7837#define xlfdpat_block_match(b, s, m) \
7838 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7839 : xlfdpat_block_match_1 (b, s, m))
7840
369a7a37 7841/* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
468213f1
YM
7842 matches with STRING. STRING must be lowered in advance. */
7843
7844static int
7845xlfdpat_match (pat, string)
7846 struct xlfdpat *pat;
369a7a37 7847 const unsigned char *string;
468213f1
YM
7848{
7849 int str_len, nblocks, i, start_max;
7850 struct xlfdpat_block *blk;
369a7a37 7851 const unsigned char *s;
468213f1
YM
7852
7853 xassert (pat->nblocks > 0);
7854
7855 if (xlfdpat_exact_p (pat))
7856 return strcmp (pat->buf, string) == 0;
7857
7858 /* The number of the characters in the string must not be smaller
7859 than that in the pattern. */
7860 str_len = strlen (string);
7861 if (str_len < pat->nchars + pat->trailing_anychars)
7862 return 0;
7863
7864 /* Chop off the trailing '?'s. */
7865 str_len -= pat->trailing_anychars;
7866
7867 /* The last block. When it is non-empty, it must match at the end
7868 of the string. */
7869 nblocks = pat->nblocks;
7870 blk = pat->blocks + (nblocks - 1);
7871 if (nblocks == 1)
7872 /* The last block is also the first one. */
7873 return (str_len == blk->len
7874 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7875 else if (blk->len != 0)
7876 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7877 return 0;
7878
7879 /* The first block. When it is non-empty, it must match at the
7880 beginning of the string. */
7881 blk = pat->blocks;
7882 if (blk->len != 0)
7883 {
7884 s = xlfdpat_block_match (blk, string, 0);
7885 if (s == NULL)
7886 return 0;
7887 string = s + blk->len;
7888 }
7889
7890 /* The rest of the blocks. */
7891 start_max = str_len - pat->nchars;
7892 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7893 {
7894 s = xlfdpat_block_match (blk, string, start_max);
7895 if (s == NULL)
7896 return 0;
7897 start_max -= s - string;
7898 string = s + blk->len;
7899 }
7900
7901 return 1;
7902}
7903
7904\f
1a578e9b
AC
7905/***********************************************************************
7906 Fonts
7907 ***********************************************************************/
7908
7909/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7910
7911struct font_info *
7912x_get_font_info (f, font_idx)
7913 FRAME_PTR f;
7914 int font_idx;
7915{
7916 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7917}
7918
7919/* the global font name table */
95dfb192
YM
7920static char **font_name_table = NULL;
7921static int font_name_table_size = 0;
7922static int font_name_count = 0;
1a578e9b 7923
71b7a47f
YM
7924/* Alist linking font family names to Font Manager font family
7925 references (which can also be used as QuickDraw font IDs). We use
7926 an alist because hash tables are not ready when the terminal frame
7927 for Mac OS Classic is created. */
7928static Lisp_Object fm_font_family_alist;
c3bd8190 7929#if USE_ATSUI
71b7a47f 7930/* Hash table linking font family names to ATSU font IDs. */
c3bd8190 7931static Lisp_Object atsu_font_id_hash;
92289429
YM
7932/* Alist linking Font Manager style to face attributes. */
7933static Lisp_Object fm_style_face_attributes_alist;
68c767a3 7934extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
c3bd8190
YM
7935#endif
7936
94d0e806
YM
7937/* Alist linking character set strings to Mac text encoding and Emacs
7938 coding system. */
7939static Lisp_Object Vmac_charset_info_alist;
1a578e9b 7940
94d0e806
YM
7941static Lisp_Object
7942create_text_encoding_info_alist ()
1a578e9b 7943{
94d0e806 7944 Lisp_Object result = Qnil, rest;
1a578e9b 7945
94d0e806
YM
7946 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7947 {
7948 Lisp_Object charset_info = XCAR (rest);
7949 Lisp_Object charset, coding_system, text_encoding;
7950 Lisp_Object existing_info;
1a578e9b 7951
94d0e806 7952 if (!(CONSP (charset_info)
b51065cf
YM
7953 && (charset = XCAR (charset_info),
7954 STRINGP (charset))
94d0e806 7955 && CONSP (XCDR (charset_info))
b51065cf
YM
7956 && (text_encoding = XCAR (XCDR (charset_info)),
7957 INTEGERP (text_encoding))
94d0e806 7958 && CONSP (XCDR (XCDR (charset_info)))
b51065cf
YM
7959 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7960 SYMBOLP (coding_system))))
94d0e806 7961 continue;
1a578e9b 7962
94d0e806
YM
7963 existing_info = assq_no_quit (text_encoding, result);
7964 if (NILP (existing_info))
7965 result = Fcons (list3 (text_encoding, coding_system, charset),
7966 result);
1a578e9b 7967 else
94d0e806
YM
7968 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7969 XSETCDR (XCDR (existing_info),
7970 Fcons (charset, XCDR (XCDR (existing_info))));
1a578e9b 7971 }
1a578e9b 7972
94d0e806 7973 return result;
1a578e9b 7974}
6b61353c 7975
6b61353c
KH
7976
7977static void
94d0e806 7978decode_mac_font_name (name, size, coding_system)
fc7a70cc
ST
7979 char *name;
7980 int size;
94d0e806 7981 Lisp_Object coding_system;
6b61353c 7982{
6b61353c 7983 struct coding_system coding;
94d0e806 7984 char *buf, *p;
6b61353c 7985
71b7a47f
YM
7986 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7987 {
7988 for (p = name; *p; p++)
7989 if (!isascii (*p) || iscntrl (*p))
7990 break;
94d0e806 7991
71b7a47f
YM
7992 if (*p)
7993 {
7994 setup_coding_system (coding_system, &coding);
7995 coding.src_multibyte = 0;
7996 coding.dst_multibyte = 1;
7997 coding.mode |= CODING_MODE_LAST_BLOCK;
6abfb022
YM
7998 coding.dst_bytes = size;
7999 coding.destination = (unsigned char *) alloca (coding.dst_bytes);
71b7a47f 8000
6abfb022
YM
8001 decode_coding_c_string (&coding, name, strlen (name), Qnil);
8002 bcopy (coding.destination, name, min (coding.produced, size));
8003 name[min (coding.produced, size)] = '\0';
71b7a47f
YM
8004 }
8005 }
6b61353c 8006
71b7a47f
YM
8007 /* If there's just one occurrence of '-' in the family name, it is
8008 replaced with '_'. (More than one occurrence of '-' means a
8009 "FOUNDRY-FAMILY-CHARSET"-style name.) */
8010 p = strchr (name, '-');
8011 if (p && strchr (p + 1, '-') == NULL)
8012 *p = '_';
6b61353c 8013
71b7a47f
YM
8014 for (p = name; *p; p++)
8015 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8016 for some locales. */
8017 if (isascii (*p))
8018 *p = tolower (*p);
6b61353c 8019}
1a578e9b
AC
8020
8021
8022static char *
94d0e806 8023mac_to_x_fontname (name, size, style, charset)
369a7a37 8024 const char *name;
fc7a70cc
ST
8025 int size;
8026 Style style;
94d0e806 8027 char *charset;
1a578e9b 8028{
dd15724d
YM
8029 Str31 foundry, cs;
8030 Str255 family;
468213f1
YM
8031 char xf[256], *result;
8032 unsigned char *p;
1a578e9b 8033
dd15724d 8034 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
94d0e806
YM
8035 charset = cs;
8036 else
1a578e9b
AC
8037 {
8038 strcpy(foundry, "Apple");
8039 strcpy(family, name);
1a578e9b
AC
8040 }
8041
dd15724d
YM
8042 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
8043 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
05f7d868 8044 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
177c0ea7 8045
dd15724d
YM
8046 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
8047 sprintf (result, "-%s-%s-%s", foundry, family, xf);
1a578e9b 8048 for (p = result; *p; p++)
468213f1
YM
8049 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8050 for some locales. */
8051 if (isascii (*p))
8052 *p = tolower (*p);
1a578e9b
AC
8053 return result;
8054}
177c0ea7 8055
1a578e9b 8056
71b7a47f
YM
8057/* Parse fully-specified and instantiated X11 font spec XF, and store
8058 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
8059 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
8060 caller must allocate at least 256 and 32 bytes respectively. For
8061 ordinary Mac fonts, the value stored to FAMILY should just be their
8062 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
8063 intlfonts collection contain their charset designation in their
8064 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
8065 types of font names are handled accordingly. */
8066
8067const int kDefaultFontSize = 12;
8068
8069static int
8070parse_x_font_name (xf, family, size, style, charset)
369a7a37
YM
8071 const char *xf;
8072 char *family;
71b7a47f 8073 int *size;
94d0e806 8074 Style *style;
71b7a47f 8075 char *charset;
1a578e9b 8076{
71b7a47f
YM
8077 Str31 foundry, weight;
8078 int point_size, avgwidth;
8079 char slant[2], *p;
1a578e9b 8080
71b7a47f
YM
8081 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8082 foundry, family, weight, slant, size,
8083 &point_size, &avgwidth, charset) != 8
8084 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
8085 foundry, family, weight, slant, size,
8086 &point_size, &avgwidth, charset) != 8)
8087 return 0;
1a578e9b 8088
71b7a47f
YM
8089 if (*size == 0)
8090 {
8091 if (point_size > 0)
8092 *size = point_size / 10;
8093 else if (avgwidth > 0)
8094 *size = avgwidth / 10;
8095 }
8096 if (*size == 0)
8097 *size = kDefaultFontSize;
1a578e9b 8098
94d0e806
YM
8099 *style = normal;
8100 if (strcmp (weight, "bold") == 0)
8101 *style |= bold;
8102 if (*slant == 'i')
8103 *style |= italic;
8104
71b7a47f 8105 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
94d0e806 8106 {
71b7a47f
YM
8107 int foundry_len = strlen (foundry), family_len = strlen (family);
8108
8109 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
8110 {
8111 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
8112 but take overlap into account. */
8113 memmove (family + foundry_len + 1, family, family_len);
8114 memcpy (family, foundry, foundry_len);
8115 family[foundry_len] = '-';
8116 family[foundry_len + 1 + family_len] = '-';
8117 strcpy (family + foundry_len + 1 + family_len + 1, charset);
8118 }
8119 else
8120 return 0;
94d0e806 8121 }
6b61353c 8122
71b7a47f
YM
8123 for (p = family; *p; p++)
8124 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8125 for some locales. */
8126 if (isascii (*p))
8127 *p = tolower (*p);
40b9c9c2 8128
71b7a47f 8129 return 1;
1a578e9b
AC
8130}
8131
8132
f00691a3
AC
8133static void
8134add_font_name_table_entry (char *font_name)
8135{
8136 if (font_name_table_size == 0)
8137 {
468213f1 8138 font_name_table_size = 256;
f00691a3
AC
8139 font_name_table = (char **)
8140 xmalloc (font_name_table_size * sizeof (char *));
8141 }
8142 else if (font_name_count + 1 >= font_name_table_size)
8143 {
468213f1 8144 font_name_table_size *= 2;
f00691a3
AC
8145 font_name_table = (char **)
8146 xrealloc (font_name_table,
8147 font_name_table_size * sizeof (char *));
8148 }
8149
8150 font_name_table[font_name_count++] = font_name;
8151}
8152
a0c62ca2
YM
8153static void
8154add_mac_font_name (name, size, style, charset)
369a7a37 8155 const char *name;
a0c62ca2
YM
8156 int size;
8157 Style style;
369a7a37 8158 const char *charset;
a0c62ca2
YM
8159{
8160 if (size > 0)
8161 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8162 else
8163 {
8164 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8165 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8166 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8167 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8168 charset));
8169 }
8170}
8171
92289429 8172#if USE_ATSUI
0d36bf23
YM
8173static FMFontStyle
8174fm_get_style_from_font (font)
8175 FMFont font;
8176{
8177 OSStatus err;
8178 FMFontStyle style = normal;
8179 ByteCount len;
8180 UInt16 mac_style;
8181 FMFontFamily font_family;
8182#define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8183
8184 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8185 some font (e.g., Optima) even if it is `bold'. */
8186 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8187 sizeof (mac_style), &mac_style, &len);
8188 if (err == noErr
8189 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8190 style = EndianU16_BtoN (mac_style);
8191 else
8192 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8193
8194 return style;
8195}
8196
8197static ATSUFontID
8198atsu_find_font_from_family_name (family)
8199 const char *family;
8200{
8201 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8202 unsigned hash_code;
8203 int i;
8204 Lisp_Object rest, best;
8205 FMFontStyle min_style, style;
8206
8207 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8208 &hash_code);
8209 if (i < 0)
8210 return kATSUInvalidFontID;
8211
8212 rest = HASH_VALUE (h, i);
8213 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8214 return cons_to_long (rest);
8215
8216 rest = Fnreverse (rest);
8217 best = XCAR (rest);
8218 rest = XCDR (rest);
8219 if (!NILP (rest)
8220 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8221 do
8222 {
8223 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8224 if (style < min_style)
8225 {
8226 best = XCAR (rest);
8227 if (style == normal)
8228 break;
8229 else
8230 min_style = style;
8231 }
8232 rest = XCDR (rest);
8233 }
8234 while (!NILP (rest));
8235
8236 HASH_VALUE (h, i) = best;
8237 return cons_to_long (best);
8238}
8239
92289429
YM
8240static Lisp_Object
8241fm_style_to_face_attributes (fm_style)
8242 FMFontStyle fm_style;
8243{
8244 Lisp_Object tem;
8245
8246 fm_style &= (bold | italic);
8247 tem = assq_no_quit (make_number (fm_style),
8248 fm_style_face_attributes_alist);
8249 if (!NILP (tem))
8250 return XCDR (tem);
8251
8252 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8253 QCslant, fm_style & italic ? Qitalic : Qnormal);
8254 fm_style_face_attributes_alist =
8255 Fcons (Fcons (make_number (fm_style), tem),
8256 fm_style_face_attributes_alist);
8257
8258 return tem;
8259}
0d36bf23
YM
8260
8261static Lisp_Object
8262atsu_find_font_family_name (font_id)
8263 ATSUFontID font_id;
8264{
8265 OSStatus err;
8266 ByteCount len;
8267 Lisp_Object family = Qnil;
8268
8269 err = ATSUFindFontName (font_id, kFontFamilyName,
8270 kFontMacintoshPlatform, kFontNoScript,
8271 kFontNoLanguage, 0, NULL, &len, NULL);
8272 if (err == noErr)
8273 {
8274 family = make_uninit_string (len);
8275 err = ATSUFindFontName (font_id, kFontFamilyName,
8276 kFontMacintoshPlatform, kFontNoScript,
8277 kFontNoLanguage, len, SDATA (family),
8278 NULL, NULL);
8279 }
8280 if (err == noErr)
8281 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8282
8283 return family;
8284}
8285
8286Lisp_Object
8287mac_atsu_font_face_attributes (font_id)
8288 ATSUFontID font_id;
8289{
8290 Lisp_Object family, style_attrs;
8291
8292 family = atsu_find_font_family_name (font_id);
8293 if (NILP (family))
8294 return Qnil;
8295 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8296 return Fcons (QCfamily, Fcons (family, style_attrs));
8297}
92289429
YM
8298#endif
8299
f00691a3
AC
8300/* Sets up the table font_name_table to contain the list of all fonts
8301 in the system the first time the table is used so that the Resource
8302 Manager need not be accessed every time this information is
8303 needed. */
1a578e9b
AC
8304
8305static void
8306init_font_name_table ()
8307{
e0f712ba 8308#if TARGET_API_MAC_CARBON
94d0e806
YM
8309 FMFontFamilyIterator ffi;
8310 FMFontFamilyInstanceIterator ffii;
8311 FMFontFamily ff;
8312 Lisp_Object text_encoding_info_alist;
8313 struct gcpro gcpro1;
8314
c3bd8190
YM
8315 text_encoding_info_alist = create_text_encoding_info_alist ();
8316
8317#if USE_ATSUI
6b9ad469
YM
8318#if USE_CG_TEXT_DRAWING
8319 init_cg_text_anti_aliasing_threshold ();
8320#endif
c3bd8190
YM
8321 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8322 text_encoding_info_alist)))
8323 {
3e7424f7 8324 OSStatus err;
a0c62ca2
YM
8325 struct Lisp_Hash_Table *h;
8326 unsigned hash_code;
c3bd8190
YM
8327 ItemCount nfonts, i;
8328 ATSUFontID *font_ids = NULL;
0d36bf23
YM
8329 Lisp_Object prev_family = Qnil;
8330 int j;
c3bd8190
YM
8331
8332 atsu_font_id_hash =
8333 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8334 make_float (DEFAULT_REHASH_SIZE),
8335 make_float (DEFAULT_REHASH_THRESHOLD),
3b8c0c70 8336 Qnil, Qnil, Qnil);
a0c62ca2
YM
8337 h = XHASH_TABLE (atsu_font_id_hash);
8338
c3bd8190
YM
8339 err = ATSUFontCount (&nfonts);
8340 if (err == noErr)
b96fe6ea
YM
8341 {
8342 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8343 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8344 }
c3bd8190
YM
8345 if (err == noErr)
8346 for (i = 0; i < nfonts; i++)
8347 {
0d36bf23
YM
8348 Lisp_Object family;
8349
8350 family = atsu_find_font_family_name (font_ids[i]);
8351 if (NILP (family) || SREF (family, 0) == '.')
c3bd8190 8352 continue;
0d36bf23
YM
8353 if (!NILP (Fequal (prev_family, family)))
8354 family = prev_family;
8355 else
8356 j = hash_lookup (h, family, &hash_code);
8357 if (j < 0)
c3bd8190 8358 {
0d36bf23
YM
8359 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8360 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8361 Qnil), hash_code);
c3bd8190 8362 }
0d36bf23
YM
8363 else if (EQ (prev_family, family))
8364 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8365 HASH_VALUE (h, j));
8366 prev_family = family;
c3bd8190 8367 }
c3bd8190
YM
8368 if (font_ids)
8369 xfree (font_ids);
8370 }
8371#endif
8372
94d0e806
YM
8373 /* Create a dummy instance iterator here to avoid creating and
8374 destroying it in the loop. */
8375 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8376 return;
8377 /* Create an iterator to enumerate the font families. */
8378 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8379 != noErr)
8380 {
8381 FMDisposeFontFamilyInstanceIterator (&ffii);
8382 return;
8383 }
177c0ea7 8384
94d0e806
YM
8385 GCPRO1 (text_encoding_info_alist);
8386
8387 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
e0f712ba 8388 {
94d0e806
YM
8389 Str255 name;
8390 FMFont font;
8391 FMFontStyle style;
8392 FMFontSize size;
8393 TextEncoding encoding;
8394 TextEncodingBase sc;
a0c62ca2 8395 Lisp_Object text_encoding_info, family;
1a578e9b 8396
94d0e806 8397 if (FMGetFontFamilyName (ff, name) != noErr)
a0c62ca2 8398 continue;
94d0e806
YM
8399 p2cstr (name);
8400 if (*name == '.')
8401 continue;
1a578e9b 8402
94d0e806 8403 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
a0c62ca2 8404 continue;
94d0e806
YM
8405 sc = GetTextEncodingBase (encoding);
8406 text_encoding_info = assq_no_quit (make_number (sc),
8407 text_encoding_info_alist);
71b7a47f 8408 if (NILP (text_encoding_info))
94d0e806
YM
8409 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8410 text_encoding_info_alist);
71b7a47f
YM
8411 decode_mac_font_name (name, sizeof (name),
8412 XCAR (XCDR (text_encoding_info)));
a0c62ca2
YM
8413 family = build_string (name);
8414 if (!NILP (Fassoc (family, fm_font_family_alist)))
8415 continue;
8416 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
71b7a47f 8417 fm_font_family_alist);
177c0ea7 8418
94d0e806
YM
8419 /* Point the instance iterator at the current font family. */
8420 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
a0c62ca2 8421 continue;
b15325b2 8422
94d0e806
YM
8423 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8424 == noErr)
8425 {
8426 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
177c0ea7 8427
7c3d233d 8428 if (size > 0 || style == normal)
9beb8baa 8429 for (; CONSP (rest); rest = XCDR (rest))
a0c62ca2 8430 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
e0f712ba 8431 }
e0f712ba 8432 }
94d0e806
YM
8433
8434 UNGCPRO;
8435
8436 /* Dispose of the iterators. */
8437 FMDisposeFontFamilyIterator (&ffi);
8438 FMDisposeFontFamilyInstanceIterator (&ffii);
8439#else /* !TARGET_API_MAC_CARBON */
8440 GrafPtr port;
8441 SInt16 fontnum, old_fontnum;
8442 int num_mac_fonts = CountResources('FOND');
8443 int i, j;
8444 Handle font_handle, font_handle_2;
8445 short id, scriptcode;
8446 ResType type;
dd15724d 8447 Str255 name;
94d0e806
YM
8448 struct FontAssoc *fat;
8449 struct AsscEntry *assc_entry;
a0c62ca2 8450 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
94d0e806
YM
8451 struct gcpro gcpro1;
8452
8453 GetPort (&port); /* save the current font number used */
8454 old_fontnum = port->txFont;
8455
8456 text_encoding_info_alist = create_text_encoding_info_alist ();
8457
8458 GCPRO1 (text_encoding_info_alist);
8459
8460 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
1a578e9b 8461 {
94d0e806
YM
8462 font_handle = GetIndResource ('FOND', i);
8463 if (!font_handle)
8464 continue;
e0f712ba 8465
94d0e806
YM
8466 GetResInfo (font_handle, &id, &type, name);
8467 GetFNum (name, &fontnum);
8468 p2cstr (name);
a0c62ca2 8469 if (fontnum == 0 || *name == '.')
94d0e806 8470 continue;
177c0ea7 8471
94d0e806
YM
8472 TextFont (fontnum);
8473 scriptcode = FontToScript (fontnum);
8474 text_encoding_info = assq_no_quit (make_number (scriptcode),
8475 text_encoding_info_alist);
71b7a47f 8476 if (NILP (text_encoding_info))
94d0e806
YM
8477 text_encoding_info = assq_no_quit (make_number (smRoman),
8478 text_encoding_info_alist);
71b7a47f
YM
8479 decode_mac_font_name (name, sizeof (name),
8480 XCAR (XCDR (text_encoding_info)));
a0c62ca2
YM
8481 family = build_string (name);
8482 if (!NILP (Fassoc (family, fm_font_family_alist)))
8483 continue;
8484 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
71b7a47f 8485 fm_font_family_alist);
94d0e806
YM
8486 do
8487 {
8488 HLock (font_handle);
177c0ea7 8489
94d0e806
YM
8490 if (GetResourceSizeOnDisk (font_handle)
8491 >= sizeof (struct FamRec))
e0f712ba 8492 {
94d0e806
YM
8493 fat = (struct FontAssoc *) (*font_handle
8494 + sizeof (struct FamRec));
8495 assc_entry
8496 = (struct AsscEntry *) (*font_handle
8497 + sizeof (struct FamRec)
8498 + sizeof (struct FontAssoc));
8499
8500 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
e0f712ba 8501 {
94d0e806
YM
8502 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8503
9beb8baa 8504 for (; CONSP (rest); rest = XCDR (rest))
a0c62ca2
YM
8505 add_mac_font_name (name, assc_entry->fontSize,
8506 assc_entry->fontStyle,
8507 SDATA (XCAR (rest)));
e0f712ba 8508 }
e0f712ba 8509 }
177c0ea7 8510
94d0e806
YM
8511 HUnlock (font_handle);
8512 font_handle_2 = GetNextFOND (font_handle);
8513 ReleaseResource (font_handle);
8514 font_handle = font_handle_2;
8515 }
8516 while (ResError () == noErr && font_handle);
1a578e9b 8517 }
94d0e806
YM
8518
8519 UNGCPRO;
8520
8521 TextFont (old_fontnum);
8522#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
8523}
8524
8525
b15325b2
ST
8526void
8527mac_clear_font_name_table ()
8528{
8529 int i;
8530
8531 for (i = 0; i < font_name_count; i++)
8532 xfree (font_name_table[i]);
8533 xfree (font_name_table);
8534 font_name_table = NULL;
8535 font_name_table_size = font_name_count = 0;
71b7a47f 8536 fm_font_family_alist = Qnil;
b15325b2
ST
8537}
8538
8539
6b61353c
KH
8540enum xlfd_scalable_field_index
8541 {
8542 XLFD_SCL_PIXEL_SIZE,
8543 XLFD_SCL_POINT_SIZE,
8544 XLFD_SCL_AVGWIDTH,
8545 XLFD_SCL_LAST
8546 };
8547
369a7a37 8548static const int xlfd_scalable_fields[] =
6b61353c
KH
8549 {
8550 6, /* PIXEL_SIZE */
8551 7, /* POINT_SIZE */
8552 11, /* AVGWIDTH */
8553 -1
8554 };
8555
8556static Lisp_Object
8557mac_do_list_fonts (pattern, maxnames)
369a7a37 8558 const char *pattern;
6b61353c
KH
8559 int maxnames;
8560{
8561 int i, n_fonts = 0;
468213f1
YM
8562 Lisp_Object font_list = Qnil;
8563 struct xlfdpat *pat;
369a7a37
YM
8564 char *scaled;
8565 const char *ptr;
8566 int scl_val[XLFD_SCL_LAST], *val;
8567 const int *field;
468213f1 8568 int exact;
e3564461 8569
b15325b2
ST
8570 if (font_name_table == NULL) /* Initialize when first used. */
8571 init_font_name_table ();
6b61353c
KH
8572
8573 for (i = 0; i < XLFD_SCL_LAST; i++)
8574 scl_val[i] = -1;
8575
8576 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8577 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8578 fonts are scaled according to the specified size. */
8579 ptr = pattern;
8580 i = 0;
8581 field = xlfd_scalable_fields;
8582 val = scl_val;
8583 if (*ptr == '-')
8584 do
8585 {
8586 ptr++;
8587 if (i == *field)
8588 {
94d0e806 8589 if ('0' <= *ptr && *ptr <= '9')
6b61353c
KH
8590 {
8591 *val = *ptr++ - '0';
8592 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8593 *val = *val * 10 + *ptr++ - '0';
8594 if (*ptr != '-')
8595 *val = -1;
8596 }
8597 field++;
8598 val++;
8599 }
8600 ptr = strchr (ptr, '-');
8601 i++;
8602 }
8603 while (ptr && i < 14);
8604
8605 if (i == 14 && ptr == NULL)
8606 {
94d0e806
YM
8607 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8608 scl_val[XLFD_SCL_PIXEL_SIZE] =
8609 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8610 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8611 : -1));
8612 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8613 scl_val[XLFD_SCL_POINT_SIZE] =
8614 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8615 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8616 : -1));
8617 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8618 scl_val[XLFD_SCL_AVGWIDTH] =
8619 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8620 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8621 : -1));
6b61353c
KH
8622 }
8623 else
8624 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8625
468213f1
YM
8626 pat = xlfdpat_create (pattern);
8627 if (pat == NULL)
8628 return Qnil;
fbe6152f 8629
468213f1 8630 exact = xlfdpat_exact_p (pat);
6b61353c
KH
8631
8632 for (i = 0; i < font_name_count; i++)
8633 {
468213f1 8634 if (xlfdpat_match (pat, font_name_table[i]))
6b61353c 8635 {
468213f1 8636 font_list = Fcons (build_string (font_name_table[i]), font_list);
f93e4d4f 8637 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
68c69027 8638 break;
6b61353c
KH
8639 }
8640 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
b0241f69 8641 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
6b61353c
KH
8642 {
8643 int former_len = ptr - font_name_table[i];
8644
dd15724d 8645 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
6b61353c
KH
8646 memcpy (scaled, font_name_table[i], former_len);
8647 sprintf (scaled + former_len,
05f7d868 8648 "-%d-%d-72-72-m-%d-%s",
6b61353c
KH
8649 scl_val[XLFD_SCL_PIXEL_SIZE],
8650 scl_val[XLFD_SCL_POINT_SIZE],
8651 scl_val[XLFD_SCL_AVGWIDTH],
b0241f69 8652 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
468213f1
YM
8653
8654 if (xlfdpat_match (pat, scaled))
6b61353c 8655 {
468213f1
YM
8656 font_list = Fcons (build_string (scaled), font_list);
8657 xfree (scaled);
f93e4d4f 8658 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
468213f1 8659 break;
6b61353c 8660 }
468213f1
YM
8661 else
8662 xfree (scaled);
6b61353c
KH
8663 }
8664 }
fbe6152f 8665
468213f1 8666 xlfdpat_destroy (pat);
fbe6152f 8667
6b61353c
KH
8668 return font_list;
8669}
8670
94d0e806
YM
8671/* Return a list of names of available fonts matching PATTERN on frame F.
8672
8673 Frame F null means we have not yet created any frame on Mac, and
8674 consult the first display in x_display_list. MAXNAMES sets a limit
8675 on how many fonts to match. */
1a578e9b
AC
8676
8677Lisp_Object
94d0e806
YM
8678x_list_fonts (f, pattern, size, maxnames)
8679 struct frame *f;
8680 Lisp_Object pattern;
8681 int size, maxnames;
1a578e9b 8682{
94d0e806
YM
8683 Lisp_Object list = Qnil, patterns, tem, key;
8684 struct mac_display_info *dpyinfo
8685 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
1a578e9b 8686
94d0e806
YM
8687 xassert (size <= 0);
8688
8689 patterns = Fassoc (pattern, Valternate_fontname_alist);
8690 if (NILP (patterns))
8691 patterns = Fcons (pattern, Qnil);
1a578e9b 8692
94d0e806 8693 for (; CONSP (patterns); patterns = XCDR (patterns))
10ba2aec 8694 {
94d0e806
YM
8695 pattern = XCAR (patterns);
8696
8697 if (!STRINGP (pattern))
8698 continue;
8699
b298e813 8700 tem = XCAR (XCDR (dpyinfo->name_list_element));
10ba2aec
AC
8701 key = Fcons (pattern, make_number (maxnames));
8702
94d0e806
YM
8703 list = Fassoc (key, tem);
8704 if (!NILP (list))
10ba2aec 8705 {
94d0e806
YM
8706 list = Fcdr_safe (list);
8707 /* We have a cashed list. Don't have to get the list again. */
10ba2aec
AC
8708 goto label_cached;
8709 }
10ba2aec 8710
94d0e806
YM
8711 BLOCK_INPUT;
8712 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8713 UNBLOCK_INPUT;
177c0ea7 8714
94d0e806 8715 /* MAC_TODO: add code for matching outline fonts here */
1a578e9b 8716
94d0e806 8717 /* Now store the result in the cache. */
b298e813 8718 XSETCAR (XCDR (dpyinfo->name_list_element),
94d0e806 8719 Fcons (Fcons (key, list),
b298e813 8720 XCAR (XCDR (dpyinfo->name_list_element))));
94d0e806
YM
8721
8722 label_cached:
8723 if (NILP (list)) continue; /* Try the remaining alternatives. */
10ba2aec 8724 }
177c0ea7 8725
94d0e806 8726 return list;
1a578e9b
AC
8727}
8728
8729
8730#if GLYPH_DEBUG
8731
e0f712ba
AC
8732/* Check that FONT is valid on frame F. It is if it can be found in F's
8733 font table. */
1a578e9b
AC
8734
8735static void
8736x_check_font (f, font)
8737 struct frame *f;
8738 XFontStruct *font;
8739{
8740 int i;
8741 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8742
8743 xassert (font != NULL);
8744
8745 for (i = 0; i < dpyinfo->n_fonts; i++)
177c0ea7 8746 if (dpyinfo->font_table[i].name
1a578e9b
AC
8747 && font == dpyinfo->font_table[i].font)
8748 break;
8749
8750 xassert (i < dpyinfo->n_fonts);
8751}
8752
8753#endif /* GLYPH_DEBUG != 0 */
8754
1a578e9b
AC
8755/* Set *W to the minimum width, *H to the minimum font height of FONT.
8756 Note: There are (broken) X fonts out there with invalid XFontStruct
8757 min_bounds contents. For example, handa@etl.go.jp reports that
8758 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8759 have font->min_bounds.width == 0. */
8760
8761static INLINE void
8762x_font_min_bounds (font, w, h)
8763 MacFontStruct *font;
8764 int *w, *h;
8765{
8766 *h = FONT_HEIGHT (font);
e169f939 8767 *w = font->min_bounds.width;
1a578e9b
AC
8768}
8769
8770
8771/* Compute the smallest character width and smallest font height over
8772 all fonts available on frame F. Set the members smallest_char_width
8773 and smallest_font_height in F's x_display_info structure to
8774 the values computed. Value is non-zero if smallest_font_height or
8775 smallest_char_width become smaller than they were before. */
8776
dd15724d 8777static int
1a578e9b
AC
8778x_compute_min_glyph_bounds (f)
8779 struct frame *f;
8780{
8781 int i;
8782 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8783 MacFontStruct *font;
8784 int old_width = dpyinfo->smallest_char_width;
8785 int old_height = dpyinfo->smallest_font_height;
177c0ea7 8786
1a578e9b
AC
8787 dpyinfo->smallest_font_height = 100000;
8788 dpyinfo->smallest_char_width = 100000;
177c0ea7 8789
1a578e9b
AC
8790 for (i = 0; i < dpyinfo->n_fonts; ++i)
8791 if (dpyinfo->font_table[i].name)
8792 {
8793 struct font_info *fontp = dpyinfo->font_table + i;
8794 int w, h;
177c0ea7 8795
1a578e9b
AC
8796 font = (MacFontStruct *) fontp->font;
8797 xassert (font != (MacFontStruct *) ~0);
8798 x_font_min_bounds (font, &w, &h);
177c0ea7 8799
1a578e9b
AC
8800 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8801 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8802 }
8803
8804 xassert (dpyinfo->smallest_char_width > 0
8805 && dpyinfo->smallest_font_height > 0);
8806
8807 return (dpyinfo->n_fonts == 1
8808 || dpyinfo->smallest_char_width < old_width
8809 || dpyinfo->smallest_font_height < old_height);
8810}
8811
8812
8813/* Determine whether given string is a fully-specified XLFD: all 14
8814 fields are present, none is '*'. */
8815
8816static int
369a7a37
YM
8817is_fully_specified_xlfd (p)
8818 const char *p;
1a578e9b
AC
8819{
8820 int i;
8821 char *q;
8822
8823 if (*p != '-')
8824 return 0;
177c0ea7 8825
1a578e9b
AC
8826 for (i = 0; i < 13; i++)
8827 {
8828 q = strchr (p + 1, '-');
8829 if (q == NULL)
8830 return 0;
8831 if (q - p == 2 && *(p + 1) == '*')
8832 return 0;
8833 p = q;
8834 }
8835
8836 if (strchr (p + 1, '-') != NULL)
8837 return 0;
177c0ea7 8838
1a578e9b
AC
8839 if (*(p + 1) == '*' && *(p + 2) == '\0')
8840 return 0;
8841
8842 return 1;
8843}
8844
8845
bb420759
YM
8846/* mac_load_query_font creates and returns an internal representation
8847 for a font in a MacFontStruct struct. There is really no concept
e0f712ba
AC
8848 corresponding to "loading" a font on the Mac. But we check its
8849 existence and find the font number and all other information for it
8850 and store them in the returned MacFontStruct. */
1a578e9b
AC
8851
8852static MacFontStruct *
bb420759
YM
8853mac_load_query_font (f, fontname)
8854 struct frame *f;
8855 char *fontname;
1a578e9b 8856{
b73e4d84 8857 int size;
1a578e9b 8858 char *name;
71b7a47f 8859 Str255 family;
dd15724d 8860 Str31 charset;
1a578e9b 8861 SInt16 fontnum;
c3bd8190 8862#if USE_ATSUI
16805b2e 8863 static ATSUFontID font_id;
c3bd8190
YM
8864 ATSUStyle mac_style = NULL;
8865#endif
94d0e806
YM
8866 Style fontface;
8867#if TARGET_API_MAC_CARBON
8868 TextEncoding encoding;
8869 int scriptcode;
8870#else
8871 short scriptcode;
8872#endif
1a578e9b 8873 MacFontStruct *font;
b73e4d84 8874 XCharStruct *space_bounds = NULL, *pcm;
1a578e9b
AC
8875
8876 if (is_fully_specified_xlfd (fontname))
8877 name = fontname;
8878 else
8879 {
6b61353c 8880 Lisp_Object matched_fonts;
1a578e9b 8881
6b61353c
KH
8882 matched_fonts = mac_do_list_fonts (fontname, 1);
8883 if (NILP (matched_fonts))
8884 return NULL;
8885 name = SDATA (XCAR (matched_fonts));
1a578e9b
AC
8886 }
8887
71b7a47f
YM
8888 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8889 return NULL;
1a578e9b 8890
c3bd8190
YM
8891#if USE_ATSUI
8892 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8893 {
3e7424f7 8894 OSStatus err;
369a7a37
YM
8895 static const ATSUAttributeTag tags[] =
8896 {kATSUFontTag, kATSUSizeTag,
8897 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8898 static const ByteCount sizes[] =
8899 {sizeof (ATSUFontID), sizeof (Fixed),
8900 sizeof (Boolean), sizeof (Boolean)};
c3bd8190
YM
8901 static Fixed size_fixed;
8902 static Boolean bold_p, italic_p;
369a7a37
YM
8903 static const ATSUAttributeValuePtr values[] =
8904 {&font_id, &size_fixed,
8905 &bold_p, &italic_p};
8906 static const ATSUFontFeatureType types[] =
8907 {kAllTypographicFeaturesType, kDiacriticsType};
8908 static const ATSUFontFeatureSelector selectors[] =
8909 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
68c767a3 8910 FMFontStyle style;
1c4ac540 8911
0d36bf23
YM
8912 font_id = atsu_find_font_from_family_name (family);
8913 if (font_id == kATSUInvalidFontID)
cb91e86a 8914 return NULL;
c3bd8190
YM
8915 size_fixed = Long2Fix (size);
8916 bold_p = (fontface & bold) != 0;
8917 italic_p = (fontface & italic) != 0;
8918 err = ATSUCreateStyle (&mac_style);
8919 if (err != noErr)
8920 return NULL;
8921 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8922 types, selectors);
8923 if (err != noErr)
8924 return NULL;
8925 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8926 tags, sizes, values);
68c767a3
YM
8927 if (err != noErr)
8928 return NULL;
8929 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8930 if (err != noErr)
8931 fontnum = -1;
c3bd8190
YM
8932 scriptcode = kTextEncodingMacUnicode;
8933 }
8934 else
c3bd8190 8935#endif
71b7a47f
YM
8936 {
8937 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8938
8939 if (NILP (tmp))
8940 return NULL;
8941 fontnum = XINT (XCDR (tmp));
94d0e806 8942#if TARGET_API_MAC_CARBON
71b7a47f
YM
8943 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8944 return NULL;
8945 scriptcode = GetTextEncodingBase (encoding);
94d0e806 8946#else
71b7a47f 8947 scriptcode = FontToScript (fontnum);
94d0e806 8948#endif
c3bd8190 8949 }
177c0ea7 8950
1a578e9b 8951 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
177c0ea7 8952
1a578e9b
AC
8953 font->mac_fontnum = fontnum;
8954 font->mac_fontsize = size;
8955 font->mac_fontface = fontface;
94d0e806 8956 font->mac_scriptcode = scriptcode;
c3bd8190
YM
8957#if USE_ATSUI
8958 font->mac_style = mac_style;
16805b2e
YM
8959#if USE_CG_TEXT_DRAWING
8960 font->cg_font = NULL;
8961 font->cg_glyphs = NULL;
8962#endif
c3bd8190 8963#endif
1a578e9b 8964
199f9270 8965 /* Apple Japanese (SJIS) font is listed as both
2f64cf3a 8966 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
e0f712ba 8967 (Roman script) in init_font_name_table (). The latter should be
2f64cf3a 8968 treated as a one-byte font. */
94d0e806
YM
8969 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8970 font->mac_scriptcode = smRoman;
199f9270 8971
71b7a47f 8972 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
177c0ea7 8973
c3bd8190
YM
8974#if USE_ATSUI
8975 if (font->mac_style)
8976 {
3e7424f7 8977 OSStatus err;
b73e4d84 8978 UniChar c;
c3bd8190 8979
b73e4d84
YM
8980 font->min_byte1 = 0;
8981 font->max_byte1 = 0xff;
8982 font->min_char_or_byte2 = 0;
8983 font->max_char_or_byte2 = 0xff;
c3bd8190 8984
458dbb8c
YM
8985 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8986 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8987 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8988 pcm_init (font->bounds.rows[0], 0x100);
c3bd8190 8989
16805b2e 8990#if USE_CG_TEXT_DRAWING
68c767a3
YM
8991 if (fontnum != -1)
8992 {
8993 FMFontStyle style;
8994 ATSFontRef ats_font;
16805b2e 8995
68c767a3 8996 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
16805b2e 8997 &font_id, &style);
68c767a3
YM
8998 /* Use CG text drawing if italic/bold is not synthesized. */
8999 if (err == noErr && style == fontface)
9000 {
9001 ats_font = FMGetATSFontRefFromFont (font_id);
9002 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
9003 }
9004 }
16805b2e
YM
9005
9006 if (font->cg_font)
b96fe6ea
YM
9007 {
9008 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
9009 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
9010 }
16805b2e 9011#endif
458dbb8c 9012 space_bounds = font->bounds.rows[0] + 0x20;
b73e4d84
YM
9013 err = mac_query_char_extents (font->mac_style, 0x20,
9014 &font->ascent, &font->descent,
9015 space_bounds,
9016#if USE_CG_TEXT_DRAWING
9017 (font->cg_glyphs ? font->cg_glyphs + 0x20
9018 : NULL)
9019#else
9020 NULL
9021#endif
9022 );
7c682cf1
YM
9023 if (err != noErr
9024 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
c3bd8190
YM
9025 {
9026 mac_unload_font (&one_mac_display_info, font);
9027 return NULL;
9028 }
9029
458dbb8c 9030 pcm = font->bounds.rows[0];
b73e4d84 9031 for (c = 0x21; c <= 0xff; c++)
c3bd8190 9032 {
16805b2e
YM
9033 if (c == 0xad)
9034 /* Soft hyphen is not supported in ATSUI. */
9035 continue;
9036 else if (c == 0x7f)
c3bd8190 9037 {
0d36bf23
YM
9038#if USE_CG_TEXT_DRAWING
9039 if (font->cg_glyphs)
9040 {
9041 c = 0x9f;
9042 pcm = NULL;
9043 continue;
9044 }
9045#endif
9046 break;
16805b2e 9047 }
c3bd8190 9048
0d36bf23
YM
9049 mac_query_char_extents (font->mac_style, c, NULL, NULL,
9050 pcm ? pcm + c : NULL,
b73e4d84
YM
9051#if USE_CG_TEXT_DRAWING
9052 (font->cg_glyphs ? font->cg_glyphs + c
9053 : NULL)
05f7d868 9054#else
b73e4d84 9055 NULL
05f7d868 9056#endif
b73e4d84 9057 );
c3bd8190 9058
16805b2e 9059#if USE_CG_TEXT_DRAWING
b73e4d84 9060 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
16805b2e 9061 {
b73e4d84
YM
9062 /* Don't use CG text drawing if font substitution occurs in
9063 ASCII or Latin-1 characters. */
9064 CGFontRelease (font->cg_font);
9065 font->cg_font = NULL;
9066 xfree (font->cg_glyphs);
9067 font->cg_glyphs = NULL;
0d36bf23
YM
9068 if (pcm == NULL)
9069 break;
c3bd8190 9070 }
16805b2e 9071#endif
c3bd8190 9072 }
c3bd8190
YM
9073 }
9074 else
71b7a47f 9075#endif
c3bd8190 9076 {
0d36bf23 9077 OSStatus err;
71b7a47f
YM
9078 FontInfo the_fontinfo;
9079 int is_two_byte_font;
9080
444a42fd 9081#if USE_CG_DRAWING
bb420759 9082 mac_prepare_for_quickdraw (f);
c3bd8190 9083#endif
bb420759 9084 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1a578e9b 9085
71b7a47f
YM
9086 TextFont (fontnum);
9087 TextSize (size);
9088 TextFace (fontface);
177c0ea7 9089
71b7a47f 9090 GetFontInfo (&the_fontinfo);
1a578e9b 9091
71b7a47f
YM
9092 font->ascent = the_fontinfo.ascent;
9093 font->descent = the_fontinfo.descent;
1a578e9b 9094
71b7a47f
YM
9095 is_two_byte_font = (font->mac_scriptcode == smJapanese
9096 || font->mac_scriptcode == smTradChinese
9097 || font->mac_scriptcode == smSimpChinese
9098 || font->mac_scriptcode == smKorean);
c3bd8190 9099
71b7a47f
YM
9100 if (is_two_byte_font)
9101 {
b73e4d84
YM
9102 int char_width;
9103
71b7a47f
YM
9104 font->min_byte1 = 0xa1;
9105 font->max_byte1 = 0xfe;
9106 font->min_char_or_byte2 = 0xa1;
9107 font->max_char_or_byte2 = 0xfe;
9108
9109 /* Use the width of an "ideographic space" of that font
9110 because the_fontinfo.widMax returns the wrong width for
9111 some fonts. */
9112 switch (font->mac_scriptcode)
9113 {
9114 case smJapanese:
9115 font->min_byte1 = 0x81;
9116 font->max_byte1 = 0xfc;
9117 font->min_char_or_byte2 = 0x40;
9118 font->max_char_or_byte2 = 0xfc;
9119 char_width = StringWidth("\p\x81\x40");
9120 break;
9121 case smTradChinese:
9122 font->min_char_or_byte2 = 0x40;
9123 char_width = StringWidth("\p\xa1\x40");
9124 break;
9125 case smSimpChinese:
9126 char_width = StringWidth("\p\xa1\xa1");
9127 break;
9128 case smKorean:
9129 char_width = StringWidth("\p\xa1\xa1");
9130 break;
9131 }
1a578e9b 9132
b73e4d84 9133 font->bounds.per_char = NULL;
1a578e9b 9134
71b7a47f
YM
9135 if (fontface & italic)
9136 font->max_bounds.rbearing = char_width + 1;
9137 else
9138 font->max_bounds.rbearing = char_width;
9139 font->max_bounds.lbearing = 0;
9140 font->max_bounds.width = char_width;
9141 font->max_bounds.ascent = the_fontinfo.ascent;
9142 font->max_bounds.descent = the_fontinfo.descent;
1a578e9b 9143
71b7a47f
YM
9144 font->min_bounds = font->max_bounds;
9145 }
9146 else
9147 {
b73e4d84 9148 int c;
c3bd8190 9149
b73e4d84
YM
9150 font->min_byte1 = font->max_byte1 = 0;
9151 font->min_char_or_byte2 = 0x20;
9152 font->max_char_or_byte2 = 0xff;
c3bd8190 9153
b73e4d84
YM
9154 font->bounds.per_char =
9155 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
b73e4d84
YM
9156 bzero (font->bounds.per_char,
9157 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9158
9159 space_bounds = font->bounds.per_char;
0d36bf23
YM
9160 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9161 &font->descent, space_bounds, NULL);
9162 if (err != noErr || space_bounds->width <= 0)
9163 {
9164 mac_unload_font (&one_mac_display_info, font);
9165 return NULL;
9166 }
b73e4d84
YM
9167
9168 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9169 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
c3bd8190 9170 }
71b7a47f 9171 }
177c0ea7 9172
b73e4d84
YM
9173 if (space_bounds)
9174 {
9175 int c;
9176
9177 font->min_bounds = font->max_bounds = *space_bounds;
9178 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9179 if (pcm->width > 0)
9180 {
9181 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9182 pcm->lbearing);
9183 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9184 pcm->rbearing);
9185 font->min_bounds.width = min (font->min_bounds.width,
9186 pcm->width);
9187 font->min_bounds.ascent = min (font->min_bounds.ascent,
9188 pcm->ascent);
cf2c6835
YM
9189 font->min_bounds.descent = min (font->min_bounds.descent,
9190 pcm->descent);
b73e4d84
YM
9191
9192 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9193 pcm->lbearing);
9194 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9195 pcm->rbearing);
9196 font->max_bounds.width = max (font->max_bounds.width,
9197 pcm->width);
9198 font->max_bounds.ascent = max (font->max_bounds.ascent,
9199 pcm->ascent);
cf2c6835
YM
9200 font->max_bounds.descent = max (font->max_bounds.descent,
9201 pcm->descent);
b73e4d84
YM
9202 }
9203 if (
9204#if USE_ATSUI
9205 font->mac_style == NULL &&
9206#endif
9207 font->max_bounds.width == font->min_bounds.width
9208 && font->min_bounds.lbearing >= 0
9209 && font->max_bounds.rbearing <= font->max_bounds.width)
9210 {
9211 /* Fixed width and no overhangs. */
9212 xfree (font->bounds.per_char);
9213 font->bounds.per_char = NULL;
9214 }
9215 }
9216
16805b2e
YM
9217#if !defined (MAC_OS8) || USE_ATSUI
9218 /* AppKit and WebKit do some adjustment to the heights of Courier,
9219 Helvetica, and Times. This only works on the environments where
9fb446e3
YM
9220 srcCopy text transfer mode is never used. */
9221 if (
9222#ifdef MAC_OS8 /* implies USE_ATSUI */
9223 font->mac_style &&
9224#endif
9225 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9226 || strcmp (family, "times") == 0))
16805b2e
YM
9227 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9228#endif
9229
1a578e9b
AC
9230 return font;
9231}
9232
9233
b15325b2
ST
9234void
9235mac_unload_font (dpyinfo, font)
9236 struct mac_display_info *dpyinfo;
9237 XFontStruct *font;
9238{
94d0e806 9239 xfree (font->full_name);
c3bd8190
YM
9240#if USE_ATSUI
9241 if (font->mac_style)
b73e4d84
YM
9242 {
9243 int i;
9244
9245 for (i = font->min_byte1; i <= font->max_byte1; i++)
9246 if (font->bounds.rows[i])
9247 xfree (font->bounds.rows[i]);
9248 xfree (font->bounds.rows);
9249 ATSUDisposeStyle (font->mac_style);
9250 }
9251 else
9252#endif
9253 if (font->bounds.per_char)
9254 xfree (font->bounds.per_char);
16805b2e
YM
9255#if USE_CG_TEXT_DRAWING
9256 if (font->cg_font)
9257 CGFontRelease (font->cg_font);
9258 if (font->cg_glyphs)
9259 xfree (font->cg_glyphs);
c3bd8190 9260#endif
b15325b2
ST
9261 xfree (font);
9262}
9263
9264
1a578e9b
AC
9265/* Load font named FONTNAME of the size SIZE for frame F, and return a
9266 pointer to the structure font_info while allocating it dynamically.
9267 If SIZE is 0, load any size of font.
9268 If loading is failed, return NULL. */
9269
9270struct font_info *
9271x_load_font (f, fontname, size)
9272 struct frame *f;
9273 register char *fontname;
9274 int size;
9275{
9276 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9277 Lisp_Object font_names;
9278
9279 /* Get a list of all the fonts that match this name. Once we
9280 have a list of matching fonts, we compare them against the fonts
9281 we already have by comparing names. */
9282 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9283
9284 if (!NILP (font_names))
9285 {
9286 Lisp_Object tail;
9287 int i;
9288
9289 for (i = 0; i < dpyinfo->n_fonts; i++)
9290 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9291 if (dpyinfo->font_table[i].name
9292 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 9293 SDATA (XCAR (tail)))
1a578e9b 9294 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 9295 SDATA (XCAR (tail)))))
1a578e9b
AC
9296 return (dpyinfo->font_table + i);
9297 }
94d0e806
YM
9298 else
9299 return NULL;
1a578e9b
AC
9300
9301 /* Load the font and add it to the table. */
9302 {
1a578e9b
AC
9303 struct MacFontStruct *font;
9304 struct font_info *fontp;
1a578e9b
AC
9305 int i;
9306
94d0e806 9307 fontname = (char *) SDATA (XCAR (font_names));
1a578e9b 9308
b15325b2 9309 BLOCK_INPUT;
bb420759 9310 font = mac_load_query_font (f, fontname);
b15325b2 9311 UNBLOCK_INPUT;
1a578e9b
AC
9312 if (!font)
9313 return NULL;
9314
9315 /* Find a free slot in the font table. */
9316 for (i = 0; i < dpyinfo->n_fonts; ++i)
9317 if (dpyinfo->font_table[i].name == NULL)
9318 break;
9319
9320 /* If no free slot found, maybe enlarge the font table. */
9321 if (i == dpyinfo->n_fonts
9322 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9323 {
9324 int sz;
9325 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9326 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9327 dpyinfo->font_table
9328 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9329 }
9330
9331 fontp = dpyinfo->font_table + i;
9332 if (i == dpyinfo->n_fonts)
9333 ++dpyinfo->n_fonts;
9334
9335 /* Now fill in the slots of *FONTP. */
9336 BLOCK_INPUT;
6b61353c 9337 bzero (fontp, sizeof (*fontp));
1a578e9b
AC
9338 fontp->font = font;
9339 fontp->font_idx = i;
6abfb022 9340 fontp->charset = -1; /* fs_load_font sets it. */
94d0e806
YM
9341 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9342 bcopy (fontname, fontp->name, strlen (fontname) + 1);
1a578e9b 9343
e169f939
ST
9344 if (font->min_bounds.width == font->max_bounds.width)
9345 {
9346 /* Fixed width font. */
9347 fontp->average_width = fontp->space_width = font->min_bounds.width;
9348 }
9349 else
9350 {
9351 XChar2b char2b;
9352 XCharStruct *pcm;
9353
9354 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9355 pcm = mac_per_char_metric (font, &char2b, 0);
9356 if (pcm)
9357 fontp->space_width = pcm->width;
9358 else
9359 fontp->space_width = FONT_WIDTH (font);
9360
9361 if (pcm)
9362 {
9363 int width = pcm->width;
9364 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9365 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9366 width += pcm->width;
9367 fontp->average_width = width / 95;
9368 }
9369 else
9370 fontp->average_width = FONT_WIDTH (font);
9371 }
9372
94d0e806
YM
9373 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9374 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
1a578e9b
AC
9375
9376 fontp->size = font->max_bounds.width;
9377 fontp->height = FONT_HEIGHT (font);
9378 {
9379 /* For some font, ascent and descent in max_bounds field is
9380 larger than the above value. */
9381 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9382 if (max_height > fontp->height)
9383 fontp->height = max_height;
9384 }
9385
cc02ceee 9386 /* MAC_TODO: The script encoding is irrelevant in unicode? */
1a578e9b
AC
9387 /* The slot `encoding' specifies how to map a character
9388 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9389 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9390 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9391 2:0xA020..0xFF7F). For the moment, we don't know which charset
6abfb022 9392 uses this font. So, we set information in fontp->encoding_type
1a578e9b
AC
9393 which is never used by any charset. If mapping can't be
9394 decided, set FONT_ENCODING_NOT_DECIDED. */
9395 if (font->mac_scriptcode == smJapanese)
6abfb022 9396 fontp->encoding_type = 4;
1a578e9b
AC
9397 else
9398 {
6abfb022 9399 fontp->encoding_type
1a578e9b
AC
9400 = (font->max_byte1 == 0
9401 /* 1-byte font */
9402 ? (font->min_char_or_byte2 < 0x80
9403 ? (font->max_char_or_byte2 < 0x80
9404 ? 0 /* 0x20..0x7F */
9405 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9406 : 1) /* 0xA0..0xFF */
9407 /* 2-byte font */
9408 : (font->min_byte1 < 0x80
9409 ? (font->max_byte1 < 0x80
9410 ? (font->min_char_or_byte2 < 0x80
9411 ? (font->max_char_or_byte2 < 0x80
9412 ? 0 /* 0x2020..0x7F7F */
9413 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9414 : 3) /* 0x20A0..0x7FFF */
9415 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9416 : (font->min_char_or_byte2 < 0x80
9417 ? (font->max_char_or_byte2 < 0x80
9418 ? 2 /* 0xA020..0xFF7F */
9419 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9420 : 1))); /* 0xA0A0..0xFFFF */
9421 }
9422
6abfb022 9423#if 0 /* MAC_TODO: fill these out with more reasonably values */
1a578e9b
AC
9424 fontp->baseline_offset
9425 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9426 ? (long) value : 0);
9427 fontp->relative_compose
9428 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9429 ? (long) value : 0);
9430 fontp->default_ascent
9431 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9432 ? (long) value : 0);
9433#else
9434 fontp->baseline_offset = 0;
9435 fontp->relative_compose = 0;
9436 fontp->default_ascent = 0;
9437#endif
9438
9439 /* Set global flag fonts_changed_p to non-zero if the font loaded
9440 has a character with a smaller width than any other character
1f98fbb4 9441 before, or if the font loaded has a smaller height than any
1a578e9b
AC
9442 other font loaded before. If this happens, it will make a
9443 glyph matrix reallocation necessary. */
dd15724d 9444 fonts_changed_p |= x_compute_min_glyph_bounds (f);
1a578e9b
AC
9445 UNBLOCK_INPUT;
9446 return fontp;
9447 }
9448}
9449
9450
9451/* Return a pointer to struct font_info of a font named FONTNAME for
9452 frame F. If no such font is loaded, return NULL. */
9453
9454struct font_info *
9455x_query_font (f, fontname)
9456 struct frame *f;
9457 register char *fontname;
9458{
9459 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9460 int i;
9461
9462 for (i = 0; i < dpyinfo->n_fonts; i++)
9463 if (dpyinfo->font_table[i].name
3e7424f7
YM
9464 && (!xstricmp (dpyinfo->font_table[i].name, fontname)
9465 || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
1a578e9b
AC
9466 return (dpyinfo->font_table + i);
9467 return NULL;
9468}
9469
9470
9471/* Find a CCL program for a font specified by FONTP, and set the member
9472 `encoder' of the structure. */
9473
9474void
9475x_find_ccl_program (fontp)
9476 struct font_info *fontp;
9477{
9478 Lisp_Object list, elt;
9479
9480 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9481 {
9482 elt = XCAR (list);
9483 if (CONSP (elt)
9484 && STRINGP (XCAR (elt))
9485 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9486 >= 0))
9487 break;
9488 }
9489 if (! NILP (list))
9490 {
9491 struct ccl_program *ccl
9492 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9493
9494 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9495 xfree (ccl);
9496 else
9497 fontp->font_encoder = ccl;
9498 }
9499}
9500
68c767a3 9501#if USE_MAC_FONT_PANEL
36f0107c
YM
9502/* Whether Font Panel has been shown before. The first call to font
9503 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9504 slow. This variable is used for deferring such a call as much as
9505 possible. */
b71c381c
YM
9506static int font_panel_shown_p = 0;
9507
7adf3143
YM
9508extern Lisp_Object Qfont;
9509static Lisp_Object Qpanel_closed, Qselection;
9510
9511static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9512 Lisp_Object,
9513 Lisp_Object,
9514 EventRef, UInt32,
9515 const EventParamName *,
9516 const EventParamType *));
9517
b71c381c
YM
9518int
9519mac_font_panel_visible_p ()
9520{
9521 return font_panel_shown_p && FPIsFontPanelVisible ();
9522}
9523
7adf3143
YM
9524static pascal OSStatus
9525mac_handle_font_event (next_handler, event, data)
9526 EventHandlerCallRef next_handler;
9527 EventRef event;
9528 void *data;
9529{
9530 OSStatus result, err;
9531 Lisp_Object id_key;
9532 int num_params;
9533 const EventParamName *names;
9534 const EventParamType *types;
9535 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9536 kEventParamATSUFontSize,
9537 kEventParamFMFontFamily,
7b7d07bb 9538 kEventParamFMFontStyle,
7adf3143
YM
9539 kEventParamFMFontSize,
9540 kEventParamFontColor};
9541 static const EventParamType types_sel[] = {typeATSUFontID,
9542 typeATSUSize,
9543 typeFMFontFamily,
7b7d07bb 9544 typeFMFontStyle,
7adf3143
YM
9545 typeFMFontSize,
9546 typeFontColor};
9547
9548 result = CallNextEventHandler (next_handler, event);
9549 if (result != eventNotHandledErr)
9550 return result;
9551
9552 switch (GetEventKind (event))
9553 {
9554 case kEventFontPanelClosed:
9555 id_key = Qpanel_closed;
9556 num_params = 0;
9557 names = NULL;
9558 types = NULL;
9559 break;
9560
9561 case kEventFontSelection:
9562 id_key = Qselection;
9563 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9564 names = names_sel;
9565 types = types_sel;
9566 break;
9567 }
9568
9569 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9570 event, num_params,
9571 names, types);
9572 if (err == noErr)
9573 result = noErr;
9574
9575 return result;
9576}
9577
b71c381c
YM
9578OSStatus
9579mac_show_hide_font_panel ()
9580{
7adf3143
YM
9581 if (!font_panel_shown_p)
9582 {
9583 OSStatus err;
9584
9585 static const EventTypeSpec specs[] =
9586 {{kEventClassFont, kEventFontPanelClosed},
9587 {kEventClassFont, kEventFontSelection}};
9588
9589 err = InstallApplicationEventHandler (mac_handle_font_event,
9590 GetEventTypeCount (specs),
9591 specs, NULL, NULL);
9592 if (err != noErr)
9593 return err;
9594
9595 font_panel_shown_p = 1;
9596 }
b71c381c
YM
9597
9598 return FPShowHideFontPanel ();
9599}
9600
68c767a3 9601OSStatus
4cb62a90 9602mac_set_font_info_for_selection (f, face_id, c)
68c767a3 9603 struct frame *f;
4cb62a90 9604 int face_id, c;
68c767a3
YM
9605{
9606 OSStatus err;
4cb62a90
YM
9607 EventTargetRef target = NULL;
9608 XFontStruct *font = NULL;
68c767a3 9609
b71c381c
YM
9610 if (!mac_font_panel_visible_p ())
9611 return noErr;
9612
4cb62a90 9613 if (f)
68c767a3 9614 {
4cb62a90 9615 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
68c767a3 9616
4cb62a90
YM
9617 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9618 {
9619 struct face *face;
9620
9621 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9622 face = FACE_FROM_ID (f, face_id);
9623 font = face->font;
9624 }
9625 }
9626
9627 if (font == NULL)
9628 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9629 else
9630 {
9631 if (font->mac_fontnum != -1)
68c767a3
YM
9632 {
9633 FontSelectionQDStyle qd_style;
9634
9635 qd_style.version = kFontSelectionQDStyleVersionZero;
4cb62a90
YM
9636 qd_style.instance.fontFamily = font->mac_fontnum;
9637 qd_style.instance.fontStyle = font->mac_fontface;
9638 qd_style.size = font->mac_fontsize;
68c767a3
YM
9639 qd_style.hasColor = false;
9640
9641 err = SetFontInfoForSelection (kFontSelectionQDType,
9642 1, &qd_style, target);
9643 }
9644 else
9645 err = SetFontInfoForSelection (kFontSelectionATSUIType,
4cb62a90 9646 1, &font->mac_style, target);
68c767a3
YM
9647 }
9648
9649 return err;
9650}
9651#endif
1a578e9b
AC
9652
9653\f
1a578e9b
AC
9654/* The Mac Event loop code */
9655
25c9622b 9656#if !TARGET_API_MAC_CARBON
1a578e9b
AC
9657#include <Events.h>
9658#include <Quickdraw.h>
9659#include <Balloons.h>
9660#include <Devices.h>
9661#include <Fonts.h>
9662#include <Gestalt.h>
9663#include <Menus.h>
9664#include <Processes.h>
9665#include <Sound.h>
9666#include <ToolUtils.h>
9667#include <TextUtils.h>
9668#include <Dialogs.h>
9669#include <Script.h>
1a578e9b 9670#include <Types.h>
1a578e9b
AC
9671#include <Resources.h>
9672
9673#if __MWERKS__
9674#include <unix.h>
9675#endif
25c9622b 9676#endif /* ! TARGET_API_MAC_CARBON */
1a578e9b 9677
20a1fc8b 9678#define M_APPLE 234
1a578e9b
AC
9679#define I_ABOUT 1
9680
1a578e9b
AC
9681#define DEFAULT_NUM_COLS 80
9682
9683#define MIN_DOC_SIZE 64
9684#define MAX_DOC_SIZE 32767
9685
1a578e9b
AC
9686#define EXTRA_STACK_ALLOC (256 * 1024)
9687
9688#define ARGV_STRING_LIST_ID 129
9689#define ABOUT_ALERT_ID 128
2e875e36 9690#define RAM_TOO_LARGE_ALERT_ID 129
1a578e9b 9691
6b61353c
KH
9692/* Contains the string "reverse", which is a constant for mouse button emu.*/
9693Lisp_Object Qreverse;
9694
1a578e9b 9695
b02e3f7b
ST
9696/* Modifier associated with the control key, or nil to ignore. */
9697Lisp_Object Vmac_control_modifier;
9698
9699/* Modifier associated with the option key, or nil to ignore. */
a36f1680
JW
9700Lisp_Object Vmac_option_modifier;
9701
b02e3f7b
ST
9702/* Modifier associated with the command key, or nil to ignore. */
9703Lisp_Object Vmac_command_modifier;
9704
9705/* Modifier associated with the function key, or nil to ignore. */
9706Lisp_Object Vmac_function_modifier;
742fbed7 9707
6b61353c
KH
9708/* True if the option and command modifiers should be used to emulate
9709 a three button mouse */
9710Lisp_Object Vmac_emulate_three_button_mouse;
9711
3354caee 9712#if TARGET_API_MAC_CARBON
70ed951a 9713/* Non-zero if the mouse wheel button (i.e. button 4) should map to
742fbed7 9714 mouse-2, instead of mouse-3. */
70ed951a 9715int mac_wheel_button_is_mouse_2;
5883787c 9716
70ed951a 9717/* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
5883787c 9718 for processing before Emacs sees it. */
70ed951a 9719int mac_pass_command_to_system;
5883787c 9720
70ed951a 9721/* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
5883787c 9722 for processing before Emacs sees it. */
70ed951a 9723int mac_pass_control_to_system;
1f98fbb4 9724#endif
95085023
YM
9725
9726/* Points to the variable `inev' in the function XTread_socket. It is
95dfb192
YM
9727 used for passing an input event to the function back from
9728 Carbon/Apple event handlers. */
95085023 9729static struct input_event *read_socket_inev = NULL;
742fbed7 9730
19ee09cc
YM
9731/* Whether or not the screen configuration has changed. */
9732static int mac_screen_config_changed = 0;
9733
1a578e9b
AC
9734Point saved_menu_event_location;
9735
9736/* Apple Events */
3354caee 9737#if TARGET_API_MAC_CARBON
3e7424f7 9738static Lisp_Object Qhi_command;
68c767a3
YM
9739#ifdef MAC_OSX
9740extern Lisp_Object Qwindow;
9741static Lisp_Object Qtoolbar_switch_mode;
9742#endif
02236cbc
YM
9743#if USE_MAC_TSM
9744static TSMDocumentID tsm_document_id;
f2ec385e
YM
9745Lisp_Object Qtext_input;
9746Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
e1adb139 9747Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
02236cbc 9748extern Lisp_Object Qbefore_string;
b4c51596 9749static Lisp_Object Vmac_ts_script_language_on_focus;
92289429 9750static Lisp_Object saved_ts_script_language_on_focus;
b4c51596
YM
9751static ScriptLanguageRecord saved_ts_language;
9752static Component saved_ts_component;
02236cbc 9753#endif
7adf3143 9754#endif /* TARGET_API_MAC_CARBON */
6a0b5d37
YM
9755extern int mac_ready_for_apple_events;
9756extern Lisp_Object Qundefined;
9757extern void init_apple_event_handler P_ ((void));
9758extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9759 Lisp_Object *, Lisp_Object *,
9760 Lisp_Object *));
0e0a1663 9761extern OSErr init_coercion_handler P_ ((void));
742fbed7
AC
9762
9763/* Drag and Drop */
e2d3b7e1
YM
9764extern OSErr install_drag_handler P_ ((WindowRef));
9765extern void remove_drag_handler P_ ((WindowRef));
9766
7adf3143 9767#if TARGET_API_MAC_CARBON
e2d3b7e1 9768/* Showing help echo string during menu tracking */
7adf3143 9769extern OSStatus install_menu_target_item_handler P_ ((void));
742fbed7 9770
25c9622b 9771#ifdef MAC_OSX
7adf3143 9772extern OSStatus install_service_handler ();
08861c5c
MB
9773Lisp_Object Qservice, Qpaste, Qperform;
9774Lisp_Object Qmouse_drag_overlay;
25c9622b 9775#endif
742fbed7 9776#endif
1a578e9b
AC
9777
9778extern void init_emacs_passwd_dir ();
9779extern int emacs_main (int, char **, char **);
1a578e9b
AC
9780
9781extern void initialize_applescript();
9782extern void terminate_applescript();
9783
1e53bd0e
YM
9784/* Table for translating Mac keycode to X keysym values. Contributed
9785 by Sudhir Shenoy.
9786 Mapping for special keys is now identical to that in Apple X11
9787 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9788 on the right of the Cmd key on laptops, and fn + `enter' (->
9789 <linefeed>). */
369a7a37 9790static const unsigned char keycode_to_xkeysym_table[] = {
1e53bd0e
YM
9791 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9792 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9793 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9794
9795 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9796 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9797 /*0x38*/ 0, 0, 0, 0,
9798 /*0x3C*/ 0, 0, 0, 0,
9799
9800 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9801 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9802 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9803 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9804
9805 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9806 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9807 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9808 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9809
9810 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9811 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9812 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9813 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9814
9815 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9816 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9817 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9818 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9819};
9820
9821#ifdef MAC_OSX
9822/* Table for translating Mac keycode with the laptop `fn' key to that
9823 without it. Destination symbols in comments are keys on US
9824 keyboard, and they may not be the same on other types of keyboards.
9825 If the destination is identical to the source (f1 ... f12), it
9826 doesn't map `fn' key to a modifier. */
369a7a37 9827static const unsigned char fn_keycode_to_keycode_table[] = {
1e53bd0e
YM
9828 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9829 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9830 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9831
9832 /*0x30*/ 0, 0, 0, 0,
9833 /*0x34*/ 0, 0, 0, 0,
9834 /*0x38*/ 0, 0, 0, 0,
9835 /*0x3C*/ 0, 0, 0, 0,
9836
9837 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9838 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9839 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9840 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9841
9842 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9843 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9844 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9845 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9846
9847 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9848 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9849 /*0x68*/ 0, 0, 0, 0,
9850 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9851
9852 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9853 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9854 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9855 /*0x7C*/ 0, 0, 0, 0
9856};
9857#endif /* MAC_OSX */
9858
a84cad70 9859static int
3354caee 9860#if TARGET_API_MAC_CARBON
742fbed7
AC
9861mac_to_emacs_modifiers (UInt32 mods)
9862#else
9863mac_to_emacs_modifiers (EventModifiers mods)
9864#endif
9865{
9866 unsigned int result = 0;
b02e3f7b 9867 if (mods & shiftKey)
742fbed7 9868 result |= shift_modifier;
16805b2e 9869
b02e3f7b
ST
9870 /* Deactivated to simplify configuration:
9871 if Vmac_option_modifier is non-NIL, we fully process the Option
9872 key. Otherwise, we only process it if an additional Ctrl or Command
16805b2e 9873 is pressed. That way the system may convert the character to a
b02e3f7b
ST
9874 composed one.
9875 if ((mods & optionKey) &&
16805b2e 9876 (( !NILP(Vmac_option_modifier) ||
b02e3f7b
ST
9877 ((mods & cmdKey) || (mods & controlKey))))) */
9878
a36f1680 9879 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
b02e3f7b
ST
9880 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9881 if (INTEGERP(val))
9882 result |= XUINT(val);
a36f1680 9883 }
b02e3f7b
ST
9884 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9885 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9886 if (INTEGERP(val))
9887 result |= XUINT(val);
a36f1680 9888 }
b02e3f7b
ST
9889 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9890 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9891 if (INTEGERP(val))
9892 result |= XUINT(val);
16805b2e 9893 }
a36f1680 9894
b02e3f7b
ST
9895#ifdef MAC_OSX
9896 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9897 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9898 if (INTEGERP(val))
9899 result |= XUINT(val);
16805b2e 9900 }
b02e3f7b 9901#endif
a36f1680 9902
742fbed7
AC
9903 return result;
9904}
9905
a84cad70
YM
9906static UInt32
9907mac_mapped_modifiers (modifiers)
9908 UInt32 modifiers;
9909{
9910 UInt32 mapped_modifiers_all =
9911 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9912 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9913 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9914
9915#ifdef MAC_OSX
9916 mapped_modifiers_all |=
9917 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9918#endif
9919
9920 return mapped_modifiers_all & modifiers;
9921}
9922
6b61353c
KH
9923static int
9924mac_get_emulated_btn ( UInt32 modifiers )
9925{
9926 int result = 0;
a433994a
ST
9927 if (!NILP (Vmac_emulate_three_button_mouse)) {
9928 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
c61278bb 9929 if (modifiers & cmdKey)
6b61353c
KH
9930 result = cmdIs3 ? 2 : 1;
9931 else if (modifiers & optionKey)
ffe8b3f4 9932 result = cmdIs3 ? 1 : 2;
6b61353c
KH
9933 }
9934 return result;
9935}
9936
e1adb139
YM
9937#ifdef MAC_OSX
9938void
9939mac_get_selected_range (w, range)
9940 struct window *w;
9941 CFRange *range;
9942{
9943 Lisp_Object overlay = find_symbol_value (Qmouse_drag_overlay);
9944 struct buffer *b = XBUFFER (w->buffer);
9945 int begv = BUF_BEGV (b), zv = BUF_ZV (b);
9946 int start, end;
9947
9948 if (OVERLAYP (overlay)
9949 && EQ (Foverlay_buffer (overlay), w->buffer)
9950 && (start = XINT (Foverlay_start (overlay)),
9951 end = XINT (Foverlay_end (overlay)),
9952 start != end))
9953 ;
9954 else
9955 {
9956 if (w == XWINDOW (selected_window) && b == current_buffer)
9957 start = PT;
9958 else
9959 start = marker_position (w->pointm);
9960
9961 if (NILP (Vtransient_mark_mode) || NILP (b->mark_active))
9962 end = start;
9963 else
9964 {
9965 int mark_pos = marker_position (b->mark);
9966
9967 if (start <= mark_pos)
9968 end = mark_pos;
9969 else
9970 {
9971 end = start;
9972 start = mark_pos;
9973 }
9974 }
9975 }
9976
9977 if (start != end)
9978 {
9979 if (start < begv)
9980 start = begv;
9981 else if (start > zv)
9982 start = zv;
9983
9984 if (end < begv)
9985 end = begv;
9986 else if (end > zv)
9987 end = zv;
9988 }
9989
9990 range->location = start - begv;
9991 range->length = end - start;
9992}
9993
9994/* Store the text of the buffer BUF from START to END as Unicode
9995 characters in CHARACTERS. Return non-zero if successful. */
9996
9997int
9998mac_store_buffer_text_to_unicode_chars (buf, start, end, characters)
9999 struct buffer *buf;
10000 int start, end;
10001 UniChar *characters;
10002{
10003 int start_byte, end_byte, char_count, byte_count;
10004 struct coding_system coding;
10005 unsigned char *dst = (unsigned char *) characters;
10006
10007 start_byte = buf_charpos_to_bytepos (buf, start);
10008 end_byte = buf_charpos_to_bytepos (buf, end);
10009 char_count = end - start;
10010 byte_count = end_byte - start_byte;
10011
10012 if (setup_coding_system (
10013#ifdef WORDS_BIG_ENDIAN
10014 intern ("utf-16be")
10015#else
10016 intern ("utf-16le")
10017#endif
10018 , &coding) < 0)
10019 return 0;
10020
10021 coding.src_multibyte = !NILP (buf->enable_multibyte_characters);
10022 coding.dst_multibyte = 0;
10023 coding.mode |= CODING_MODE_LAST_BLOCK;
10024 coding.composing = COMPOSITION_DISABLED;
10025
10026 if (BUF_GPT_BYTE (buf) <= start_byte || end_byte <= BUF_GPT_BYTE (buf))
10027 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10028 byte_count, char_count * sizeof (UniChar));
10029 else
10030 {
10031 int first_byte_count = BUF_GPT_BYTE (buf) - start_byte;
10032
10033 encode_coding (&coding, BUF_BYTE_ADDRESS (buf, start_byte), dst,
10034 first_byte_count, char_count * sizeof (UniChar));
10035 if (coding.result == CODING_FINISH_NORMAL)
10036 encode_coding (&coding,
10037 BUF_BYTE_ADDRESS (buf, start_byte + first_byte_count),
10038 dst + coding.produced,
10039 byte_count - first_byte_count,
10040 char_count * sizeof (UniChar) - coding.produced);
10041 }
10042
10043 if (coding.result != CODING_FINISH_NORMAL)
10044 return 0;
10045
10046 return 1;
10047}
10048
10049void
10050mac_ax_selected_text_range (f, range)
10051 struct frame *f;
10052 CFRange *range;
10053{
10054 mac_get_selected_range (XWINDOW (f->selected_window), range);
10055}
10056
10057#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
10058unsigned int
10059mac_ax_number_of_characters (f)
10060 struct frame *f;
10061{
10062 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
10063
10064 return BUF_ZV (b) - BUF_BEGV (b);
10065}
10066#endif
10067#endif
10068
f2ec385e
YM
10069#if USE_MAC_TSM
10070OSStatus
10071mac_restore_keyboard_input_source ()
10072{
10073 OSStatus err = noErr;
10074 ScriptLanguageRecord slrec, *slptr = NULL;
10075
10076 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10077 && EQ (saved_ts_script_language_on_focus, Qt))
10078 slptr = &saved_ts_language;
10079 else if (CONSP (Vmac_ts_script_language_on_focus)
10080 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10081 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10082 && CONSP (saved_ts_script_language_on_focus)
10083 && EQ (XCAR (saved_ts_script_language_on_focus),
10084 XCAR (Vmac_ts_script_language_on_focus))
10085 && EQ (XCDR (saved_ts_script_language_on_focus),
10086 XCDR (Vmac_ts_script_language_on_focus)))
10087 {
10088 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10089 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10090 slptr = &slrec;
10091 }
10092
10093 if (slptr)
10094 {
10095#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10096 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10097 kKeyboardInputMethodClass);
10098#else
10099 err = SetDefaultInputMethod (saved_ts_component, slptr);
10100#endif
10101 if (err == noErr)
10102 err = SetTextServiceLanguage (slptr);
10103
10104 /* Seems to be needed on Mac OS X 10.2. */
10105 if (err == noErr)
10106 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10107 }
10108
10109 return err;
10110}
10111
10112void
10113mac_save_keyboard_input_source ()
10114{
10115 OSStatus err;
10116 ScriptLanguageRecord slrec, *slptr = NULL;
10117
10118 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10119
10120 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10121 {
10122 err = GetTextServiceLanguage (&saved_ts_language);
10123 if (err == noErr)
10124 slptr = &saved_ts_language;
10125 }
10126 else if (CONSP (Vmac_ts_script_language_on_focus)
10127 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10128 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10129 {
10130 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10131 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10132 slptr = &slrec;
10133 }
10134
10135 if (slptr)
10136 {
10137#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10138 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10139 kKeyboardInputMethodClass);
10140#else
10141 GetDefaultInputMethod (&saved_ts_component, slptr);
10142#endif
10143 }
10144}
10145#endif
10146
c857519f
YM
10147#if TARGET_API_MAC_CARBON
10148/***** Code to handle C-g testing *****/
10149extern int quit_char;
10150extern int make_ctrl_char P_ ((int));
10151
10152int
10153mac_quit_char_key_p (modifiers, key_code)
10154 UInt32 modifiers, key_code;
10155{
10156 UInt32 char_code;
10157 unsigned long some_state = 0;
10158 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10159 int c, emacs_modifiers;
10160
10161 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
10162 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
10163 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
10164 if (char_code & ~0xff)
10165 return 0;
10166
10167 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
10168 if (emacs_modifiers & ctrl_modifier)
10169 c = make_ctrl_char (char_code);
10170
10171 c |= (emacs_modifiers
10172 & (meta_modifier | alt_modifier
10173 | hyper_modifier | super_modifier));
10174
10175 return c == quit_char;
10176}
10177#endif
10178
3354caee 10179#if TARGET_API_MAC_CARBON
742fbed7
AC
10180/* Obtains the event modifiers from the event ref and then calls
10181 mac_to_emacs_modifiers. */
a84cad70 10182static int
177c0ea7 10183mac_event_to_emacs_modifiers (EventRef eventRef)
742fbed7 10184{
7adf3143
YM
10185 UInt32 mods = 0, class;
10186
742fbed7
AC
10187 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
10188 sizeof (UInt32), NULL, &mods);
7adf3143 10189 class = GetEventClass (eventRef);
a433994a 10190 if (!NILP (Vmac_emulate_three_button_mouse) &&
7adf3143 10191 (class == kEventClassMouse || class == kEventClassCommand))
6b61353c 10192 {
c61278bb 10193 mods &= ~(optionKey | cmdKey);
6b61353c 10194 }
742fbed7
AC
10195 return mac_to_emacs_modifiers (mods);
10196}
10197
10198/* Given an event ref, return the code to use for the mouse button
10199 code in the emacs input_event. */
10200static int
177c0ea7 10201mac_get_mouse_btn (EventRef ref)
742fbed7
AC
10202{
10203 EventMouseButton result = kEventMouseButtonPrimary;
10204 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
10205 sizeof (EventMouseButton), NULL, &result);
177c0ea7 10206 switch (result)
742fbed7
AC
10207 {
10208 case kEventMouseButtonPrimary:
a433994a 10209 if (NILP (Vmac_emulate_three_button_mouse))
6b61353c
KH
10210 return 0;
10211 else {
10212 UInt32 mods = 0;
10213 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
10214 sizeof (UInt32), NULL, &mods);
10215 return mac_get_emulated_btn(mods);
10216 }
742fbed7 10217 case kEventMouseButtonSecondary:
70ed951a 10218 return mac_wheel_button_is_mouse_2 ? 2 : 1;
742fbed7
AC
10219 case kEventMouseButtonTertiary:
10220 case 4: /* 4 is the number for the mouse wheel button */
70ed951a 10221 return mac_wheel_button_is_mouse_2 ? 1 : 2;
742fbed7
AC
10222 default:
10223 return 0;
10224 }
10225}
10226
10227/* Normally, ConvertEventRefToEventRecord will correctly handle all
10228 events. However the click of the mouse wheel is not converted to a
e4f5123f
YM
10229 mouseDown or mouseUp event. Likewise for dead key events. This
10230 calls ConvertEventRefToEventRecord, but then checks to see if it is
10231 a mouse up/down, or a dead key Carbon event that has not been
95085023
YM
10232 converted, and if so, converts it by hand (to be picked up in the
10233 XTread_socket loop). */
177c0ea7 10234static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
742fbed7 10235{
a3510ffa 10236 OSStatus err;
742fbed7 10237 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
e4f5123f 10238 EventKind action;
95085023
YM
10239
10240 if (result)
10241 return result;
10242
10243 switch (GetEventClass (eventRef))
177c0ea7 10244 {
95085023
YM
10245 case kEventClassMouse:
10246 switch (GetEventKind (eventRef))
742fbed7 10247 {
95085023 10248 case kEventMouseDown:
742fbed7 10249 eventRec->what = mouseDown;
95085023
YM
10250 result = 1;
10251 break;
10252
10253 case kEventMouseUp:
742fbed7 10254 eventRec->what = mouseUp;
95085023
YM
10255 result = 1;
10256 break;
10257
10258 default:
10259 break;
742fbed7 10260 }
92de1e01 10261 break;
95085023
YM
10262
10263 case kEventClassKeyboard:
10264 switch (GetEventKind (eventRef))
742fbed7 10265 {
95085023 10266 case kEventRawKeyDown:
e4f5123f
YM
10267 action = keyDown;
10268 goto keystroke_common;
10269 case kEventRawKeyRepeat:
10270 action = autoKey;
10271 goto keystroke_common;
10272 case kEventRawKeyUp:
10273 action = keyUp;
10274 keystroke_common:
95085023
YM
10275 {
10276 unsigned char char_codes;
10277 UInt32 key_code;
10278
a3510ffa
YM
10279 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
10280 typeChar, NULL, sizeof (char),
10281 NULL, &char_codes);
10282 if (err == noErr)
10283 err = GetEventParameter (eventRef, kEventParamKeyCode,
10284 typeUInt32, NULL, sizeof (UInt32),
10285 NULL, &key_code);
10286 if (err == noErr)
10287 {
e4f5123f 10288 eventRec->what = action;
a3510ffa
YM
10289 eventRec->message = char_codes | ((key_code & 0xff) << 8);
10290 result = 1;
10291 }
95085023
YM
10292 }
10293 break;
10294
10295 default:
10296 break;
742fbed7 10297 }
92de1e01 10298 break;
95085023
YM
10299
10300 default:
10301 break;
742fbed7 10302 }
95085023
YM
10303
10304 if (result)
10305 {
10306 /* Need where and when. */
a3510ffa 10307 UInt32 mods = 0;
95085023
YM
10308
10309 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
10310 NULL, sizeof (Point), NULL, &eventRec->where);
10311 /* Use two step process because new event modifiers are 32-bit
10312 and old are 16-bit. Currently, only loss is NumLock & Fn. */
10313 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
10314 NULL, sizeof (UInt32), NULL, &mods);
10315 eventRec->modifiers = mods;
10316
10317 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
10318 }
10319
742fbed7
AC
10320 return result;
10321}
10322
10323#endif
1a578e9b 10324
f93e4d4f 10325#ifdef MAC_OS8
1a578e9b
AC
10326static void
10327do_get_menus (void)
10328{
10329 Handle menubar_handle;
3354caee 10330 MenuRef menu;
177c0ea7 10331
1a578e9b
AC
10332 menubar_handle = GetNewMBar (128);
10333 if(menubar_handle == NULL)
10334 abort ();
10335 SetMenuBar (menubar_handle);
10336 DrawMenuBar ();
10337
1c05c15b 10338#if !TARGET_API_MAC_CARBON
3354caee
YM
10339 menu = GetMenuRef (M_APPLE);
10340 if (menu != NULL)
10341 AppendResMenu (menu, 'DRVR');
1a578e9b
AC
10342 else
10343 abort ();
1c05c15b 10344#endif
1a578e9b
AC
10345}
10346
10347
10348static void
10349do_init_managers (void)
10350{
e0f712ba 10351#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10352 InitGraf (&qd.thePort);
10353 InitFonts ();
10354 FlushEvents (everyEvent, 0);
10355 InitWindows ();
10356 InitMenus ();
10357 TEInit ();
10358 InitDialogs (NULL);
e0f712ba
AC
10359#endif /* !TARGET_API_MAC_CARBON */
10360 InitCursor ();
177c0ea7 10361
e0f712ba 10362#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10363 /* set up some extra stack space for use by emacs */
10364 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10365
10366 /* MaxApplZone must be called for AppleScript to execute more
10367 complicated scripts */
10368 MaxApplZone ();
10369 MoreMasters ();
e0f712ba 10370#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
10371}
10372
2e875e36
AC
10373static void
10374do_check_ram_size (void)
10375{
10376 SInt32 physical_ram_size, logical_ram_size;
177c0ea7 10377
2e875e36
AC
10378 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10379 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
6b61353c
KH
10380 || physical_ram_size > (1 << VALBITS)
10381 || logical_ram_size > (1 << VALBITS))
2e875e36
AC
10382 {
10383 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10384 exit (1);
10385 }
10386}
f93e4d4f 10387#endif /* MAC_OS8 */
2e875e36 10388
1a578e9b 10389static void
3354caee 10390do_window_update (WindowRef win)
1a578e9b 10391{
50bf7673
ST
10392 struct frame *f = mac_window_to_frame (win);
10393
b15325b2 10394 BeginUpdate (win);
1a578e9b 10395
b15325b2
ST
10396 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10397 below. */
10398 if (win != tip_window)
1a578e9b
AC
10399 {
10400 if (f->async_visible == 0)
10401 {
1f98fbb4
YM
10402 /* Update events may occur when a frame gets iconified. */
10403#if 0
1a578e9b
AC
10404 f->async_visible = 1;
10405 f->async_iconified = 0;
10406 SET_FRAME_GARBAGED (f);
1f98fbb4 10407#endif
1a578e9b
AC
10408 }
10409 else
1f98fbb4 10410 {
b15325b2 10411 Rect r;
b15325b2 10412#if TARGET_API_MAC_CARBON
1f98fbb4 10413 RgnHandle region = NewRgn ();
2d97ff8c 10414
1f98fbb4
YM
10415 GetPortVisibleRegion (GetWindowPort (win), region);
10416 GetRegionBounds (region, &r);
10417 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
a84cad70
YM
10418#if USE_CG_DRAWING
10419 mac_prepare_for_quickdraw (f);
10420#endif
1f98fbb4
YM
10421 UpdateControls (win, region);
10422 DisposeRgn (region);
b15325b2 10423#else
b15325b2 10424 r = (*win->visRgn)->rgnBBox;
b15325b2 10425 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
b69efa23
YM
10426 UpdateControls (win, win->visRgn);
10427#endif
1f98fbb4 10428 }
1a578e9b 10429 }
b15325b2
ST
10430
10431 EndUpdate (win);
1a578e9b
AC
10432}
10433
e0f712ba 10434static int
3354caee 10435is_emacs_window (WindowRef win)
e0f712ba
AC
10436{
10437 Lisp_Object tail, frame;
10438
10439 if (!win)
10440 return 0;
10441
10442 FOR_EACH_FRAME (tail, frame)
10443 if (FRAME_MAC_P (XFRAME (frame)))
10444 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10445 return 1;
10446
10447 return 0;
10448}
10449
02236cbc 10450#if USE_MAC_TSM
b4c51596
YM
10451static OSStatus
10452mac_tsm_resume ()
10453{
10454 OSStatus err;
10455 ScriptLanguageRecord slrec, *slptr = NULL;
10456
10457 err = ActivateTSMDocument (tsm_document_id);
10458
10459 if (err == noErr)
10460 {
92289429
YM
10461 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10462 && EQ (saved_ts_script_language_on_focus, Qt))
b4c51596
YM
10463 slptr = &saved_ts_language;
10464 else if (CONSP (Vmac_ts_script_language_on_focus)
10465 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
92289429
YM
10466 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10467 && CONSP (saved_ts_script_language_on_focus)
10468 && EQ (XCAR (saved_ts_script_language_on_focus),
10469 XCAR (Vmac_ts_script_language_on_focus))
10470 && EQ (XCDR (saved_ts_script_language_on_focus),
10471 XCDR (Vmac_ts_script_language_on_focus)))
b4c51596
YM
10472 {
10473 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10474 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10475 slptr = &slrec;
10476 }
10477 }
10478
10479 if (slptr)
10480 {
10481#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10482 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10483 kKeyboardInputMethodClass);
10484#else
10485 err = SetDefaultInputMethod (saved_ts_component, slptr);
02236cbc 10486#endif
b4c51596
YM
10487 if (err == noErr)
10488 err = SetTextServiceLanguage (slptr);
10489
10490 /* Seems to be needed on Mac OS X 10.2. */
10491 if (err == noErr)
10492 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10493 }
10494
10495 return err;
1a578e9b
AC
10496}
10497
b4c51596
YM
10498static OSStatus
10499mac_tsm_suspend ()
1a578e9b 10500{
b4c51596
YM
10501 OSStatus err;
10502 ScriptLanguageRecord slrec, *slptr = NULL;
10503
92289429
YM
10504 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10505
b4c51596
YM
10506 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10507 {
10508 err = GetTextServiceLanguage (&saved_ts_language);
10509 if (err == noErr)
10510 slptr = &saved_ts_language;
10511 }
10512 else if (CONSP (Vmac_ts_script_language_on_focus)
10513 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10514 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10515 {
10516 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10517 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10518 slptr = &slrec;
10519 }
10520
10521 if (slptr)
10522 {
10523#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10524 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10525 kKeyboardInputMethodClass);
10526#else
10527 GetDefaultInputMethod (&saved_ts_component, slptr);
02236cbc 10528#endif
b4c51596 10529 }
1a578e9b 10530
b4c51596
YM
10531 err = DeactivateTSMDocument (tsm_document_id);
10532
10533 return err;
10534}
10535#endif
1a578e9b 10536
20a1fc8b
YM
10537#if !TARGET_API_MAC_CARBON
10538void
1a578e9b
AC
10539do_apple_menu (SInt16 menu_item)
10540{
10541 Str255 item_name;
10542 SInt16 da_driver_refnum;
177c0ea7 10543
1a578e9b
AC
10544 if (menu_item == I_ABOUT)
10545 NoteAlert (ABOUT_ALERT_ID, NULL);
10546 else
10547 {
3354caee 10548 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
1a578e9b
AC
10549 da_driver_refnum = OpenDeskAcc (item_name);
10550 }
1a578e9b 10551}
20a1fc8b 10552#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
10553
10554/* Handle drags in size box. Based on code contributed by Ben
10555 Mesander and IM - Window Manager A. */
10556
10557static void
369a7a37 10558do_grow_window (w, e)
3354caee 10559 WindowRef w;
369a7a37 10560 const EventRecord *e;
1a578e9b 10561{
1a578e9b 10562 Rect limit_rect;
b15325b2 10563 int rows, columns, width, height;
50bf7673 10564 struct frame *f = mac_window_to_frame (w);
b15325b2
ST
10565 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10566 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10567#if TARGET_API_MAC_CARBON
10568 Rect new_rect;
10569#else
10570 long grow_size;
10571#endif
177c0ea7 10572
b15325b2
ST
10573 if (size_hints->flags & PMinSize)
10574 {
10575 min_width = size_hints->min_width;
10576 min_height = size_hints->min_height;
10577 }
10578 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
177c0ea7 10579
b15325b2
ST
10580#if TARGET_API_MAC_CARBON
10581 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10582 return;
10583 height = new_rect.bottom - new_rect.top;
10584 width = new_rect.right - new_rect.left;
10585#else
1a578e9b 10586 grow_size = GrowWindow (w, e->where, &limit_rect);
1a578e9b 10587 /* see if it really changed size */
b15325b2
ST
10588 if (grow_size == 0)
10589 return;
10590 height = HiWord (grow_size);
10591 width = LoWord (grow_size);
10592#endif
10593
10594 if (width != FRAME_PIXEL_WIDTH (f)
10595 || height != FRAME_PIXEL_HEIGHT (f))
1a578e9b 10596 {
b15325b2
ST
10597 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10598 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
177c0ea7 10599
1a578e9b
AC
10600 x_set_window_size (f, 0, columns, rows);
10601 }
10602}
10603
10604
bed0bf95
YM
10605#if TARGET_API_MAC_CARBON
10606static Point
10607mac_get_ideal_size (f)
10608 struct frame *f;
10609{
10610 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3354caee 10611 WindowRef w = FRAME_MAC_WINDOW (f);
bed0bf95
YM
10612 Point ideal_size;
10613 Rect standard_rect;
10614 int height, width, columns, rows;
10615
10616 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10617 ideal_size.v = dpyinfo->height;
10618 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10619 /* Adjust the standard size according to character boundaries. */
10620 width = standard_rect.right - standard_rect.left;
10621 height = standard_rect.bottom - standard_rect.top;
10622 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10623 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10624 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10625 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10626
10627 return ideal_size;
10628}
10629#endif
10630
1a578e9b
AC
10631/* Handle clicks in zoom box. Calculation of "standard state" based
10632 on code in IM - Window Manager A and code contributed by Ben
10633 Mesander. The standard state of an Emacs window is 80-characters
10634 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10635
10636static void
3354caee 10637do_zoom_window (WindowRef w, int zoom_in_or_out)
1a578e9b 10638{
1a578e9b 10639 Rect zoom_rect, port_rect;
bed0bf95 10640 int width, height;
50bf7673 10641 struct frame *f = mac_window_to_frame (w);
e0f712ba 10642#if TARGET_API_MAC_CARBON
bed0bf95 10643 Point ideal_size = mac_get_ideal_size (f);
e0f712ba 10644
bed0bf95
YM
10645 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10646 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10647 && port_rect.left == zoom_rect.left
10648 && port_rect.top == zoom_rect.top)
f93e4d4f
YM
10649 zoom_in_or_out = inZoomIn;
10650 else
bed0bf95 10651 zoom_in_or_out = inZoomOut;
f93e4d4f 10652
bed0bf95
YM
10653#ifdef MAC_OS8
10654 mac_clear_window (f);
10655#endif
10656 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
e0f712ba 10657#else /* not TARGET_API_MAC_CARBON */
f93e4d4f
YM
10658 GrafPtr save_port;
10659 Point top_left;
bed0bf95
YM
10660 int w_title_height, rows;
10661 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
f93e4d4f 10662
bf06c82f
ST
10663 GetPort (&save_port);
10664
10665 SetPortWindowPort (w);
10666
10667 /* Clear window to avoid flicker. */
e0f712ba 10668 EraseRect (&(w->portRect));
1a578e9b
AC
10669 if (zoom_in_or_out == inZoomOut)
10670 {
e0f712ba 10671 SetPt (&top_left, w->portRect.left, w->portRect.top);
1a578e9b
AC
10672 LocalToGlobal (&top_left);
10673
10674 /* calculate height of window's title bar */
10675 w_title_height = top_left.v - 1
e0f712ba 10676 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1a578e9b
AC
10677
10678 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10679 zoom_rect = qd.screenBits.bounds;
10680 zoom_rect.top += w_title_height;
10681 InsetRect (&zoom_rect, 8, 4); /* not too tight */
177c0ea7 10682
1a578e9b 10683 zoom_rect.right = zoom_rect.left
f1a83aab 10684 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1a578e9b 10685
bf06c82f
ST
10686 /* Adjust the standard size according to character boundaries. */
10687 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10688 zoom_rect.bottom =
10689 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10690
e0f712ba
AC
10691 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10692 = zoom_rect;
1a578e9b
AC
10693 }
10694
7ca7ccd5 10695 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
bf06c82f
ST
10696
10697 SetPort (save_port);
10698#endif /* not TARGET_API_MAC_CARBON */
1a578e9b 10699
3354caee 10700#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10701 /* retrieve window size and update application values */
10702 port_rect = w->portRect;
b15325b2
ST
10703 height = port_rect.bottom - port_rect.top;
10704 width = port_rect.right - port_rect.left;
1a578e9b 10705
bed0bf95
YM
10706 mac_handle_size_change (f, width, height);
10707 mac_handle_origin_change (f);
10708#endif
742fbed7 10709}
1a578e9b 10710
7adf3143
YM
10711static void
10712mac_set_unicode_keystroke_event (code, buf)
10713 UniChar code;
10714 struct input_event *buf;
10715{
10716 int charset_id, c1, c2;
10717
10718 if (code < 0x80)
10719 {
10720 buf->kind = ASCII_KEYSTROKE_EVENT;
10721 buf->code = code;
10722 }
10723 else if (code < 0x100)
10724 {
10725 if (code < 0xA0)
10726 charset_id = CHARSET_8_BIT_CONTROL;
10727 else
10728 charset_id = charset_latin_iso8859_1;
10729 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10730 buf->code = MAKE_CHAR (charset_id, code, 0);
10731 }
10732 else
10733 {
10734 if (code < 0x2500)
10735 charset_id = charset_mule_unicode_0100_24ff,
10736 code -= 0x100;
10737 else if (code < 0x33FF)
10738 charset_id = charset_mule_unicode_2500_33ff,
10739 code -= 0x2500;
10740 else if (code >= 0xE000)
10741 charset_id = charset_mule_unicode_e000_ffff,
10742 code -= 0xE000;
10743 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10744 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10745 buf->code = MAKE_CHAR (charset_id, c1, c2);
10746 }
10747}
10748
10749static void
10750do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10751 EventKind action;
10752 unsigned char char_code;
10753 UInt32 key_code, modifiers;
10754 unsigned long timestamp;
10755 struct input_event *buf;
10756{
10757 static SInt16 last_key_script = -1;
10758 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10759 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10760
10761#ifdef MAC_OSX
10762 if (mapped_modifiers & kEventKeyModifierFnMask
10763 && key_code <= 0x7f
10764 && fn_keycode_to_keycode_table[key_code])
10765 key_code = fn_keycode_to_keycode_table[key_code];
10766#endif
10767
10768 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10769 {
10770 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10771 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10772#ifdef MAC_OSX
10773 if (modifiers & kEventKeyModifierFnMask
10774 && key_code <= 0x7f
10775 && fn_keycode_to_keycode_table[key_code] == key_code)
10776 modifiers &= ~kEventKeyModifierFnMask;
10777#endif
10778 }
10779 else if (mapped_modifiers)
10780 {
10781 /* translate the keycode back to determine the original key */
10782#ifdef MAC_OSX
10783 UCKeyboardLayout *uchr_ptr = NULL;
10784#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10785 OSStatus err;
10786 KeyboardLayoutRef layout;
10787
10788 err = KLGetCurrentKeyboardLayout (&layout);
10789 if (err == noErr)
10790 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10791 (const void **) &uchr_ptr);
10792#else
10793 static SInt16 last_key_layout_id = 0;
10794 static Handle uchr_handle = (Handle)-1;
10795 SInt16 current_key_layout_id =
10796 GetScriptVariable (current_key_script, smScriptKeys);
10797
10798 if (uchr_handle == (Handle)-1
10799 || last_key_layout_id != current_key_layout_id)
10800 {
10801 uchr_handle = GetResource ('uchr', current_key_layout_id);
10802 last_key_layout_id = current_key_layout_id;
10803 }
10804 if (uchr_handle)
10805 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10806#endif
10807
10808 if (uchr_ptr)
10809 {
10810 OSStatus status;
10811 UInt16 key_action = action - keyDown;
10812 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10813 UInt32 keyboard_type = LMGetKbdType ();
10814 SInt32 dead_key_state = 0;
10815 UniChar code;
10816 UniCharCount actual_length;
10817
10818 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10819 modifier_key_state, keyboard_type,
10820 kUCKeyTranslateNoDeadKeysMask,
10821 &dead_key_state,
10822 1, &actual_length, &code);
10823 if (status == noErr && actual_length == 1)
10824 mac_set_unicode_keystroke_event (code, buf);
10825 }
10826#endif /* MAC_OSX */
10827
10828 if (buf->kind == NO_EVENT)
10829 {
10830 /* This code comes from Keyboard Resource, Appendix C of IM
10831 - Text. This is necessary since shift is ignored in KCHR
10832 table translation when option or command is pressed. It
10833 also does not translate correctly control-shift chars
10834 like C-% so mask off shift here also. */
10835 /* Mask off modifier keys that are mapped to some Emacs
10836 modifiers. */
10837 int new_modifiers = modifiers & ~mapped_modifiers;
10838 /* set high byte of keycode to modifier high byte*/
10839 int new_key_code = key_code | new_modifiers;
10840 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10841 unsigned long some_state = 0;
10842 UInt32 new_char_code;
10843
10844 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10845 if (new_char_code == 0)
10846 /* Seems like a dead key. Append up-stroke. */
10847 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10848 &some_state);
10849 if (new_char_code)
10850 {
10851 buf->kind = ASCII_KEYSTROKE_EVENT;
10852 buf->code = new_char_code & 0xff;
10853 }
10854 }
10855 }
10856
10857 if (buf->kind == NO_EVENT)
10858 {
10859 buf->kind = ASCII_KEYSTROKE_EVENT;
10860 buf->code = char_code;
10861 }
10862
10863 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10864 buf->modifiers |= (extra_keyboard_modifiers
10865 & (meta_modifier | alt_modifier
10866 | hyper_modifier | super_modifier));
10867
10868#if TARGET_API_MAC_CARBON
10869 if (buf->kind == ASCII_KEYSTROKE_EVENT
10870 && buf->code >= 0x80 && buf->modifiers)
10871 {
10872 OSStatus err;
10873 TextEncoding encoding = kTextEncodingMacRoman;
10874 TextToUnicodeInfo ttu_info;
10875
10876 UpgradeScriptInfoToTextEncoding (current_key_script,
10877 kTextLanguageDontCare,
10878 kTextRegionDontCare,
10879 NULL, &encoding);
10880 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10881 if (err == noErr)
10882 {
10883 UniChar code;
10884 Str255 pstr;
10885 ByteCount unicode_len;
10886
10887 pstr[0] = 1;
10888 pstr[1] = buf->code;
10889 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10890 sizeof (UniChar),
10891 &unicode_len, &code);
10892 if (err == noErr && unicode_len == sizeof (UniChar))
10893 mac_set_unicode_keystroke_event (code, buf);
10894 DisposeTextToUnicodeInfo (&ttu_info);
10895 }
10896 }
10897#endif
10898
10899 if (buf->kind == ASCII_KEYSTROKE_EVENT
10900 && buf->code >= 0x80
10901 && last_key_script != current_key_script)
10902 {
10903 struct input_event event;
10904
10905 EVENT_INIT (event);
10906 event.kind = LANGUAGE_CHANGE_EVENT;
10907 event.arg = Qnil;
10908 event.code = current_key_script;
10909 event.timestamp = timestamp;
10910 kbd_buffer_store_event (&event);
10911 last_key_script = current_key_script;
10912 }
10913}
10914
a733ef16 10915void
6a0b5d37
YM
10916mac_store_apple_event (class, id, desc)
10917 Lisp_Object class, id;
10918 const AEDesc *desc;
742fbed7 10919{
1c05c15b 10920 struct input_event buf;
742fbed7 10921
a733ef16 10922 EVENT_INIT (buf);
1c05c15b 10923
a733ef16
YM
10924 buf.kind = MAC_APPLE_EVENT;
10925 buf.x = class;
10926 buf.y = id;
10927 XSETFRAME (buf.frame_or_window,
10928 mac_focus_frame (&one_mac_display_info));
10929 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10930 is safe to use them during read_socket_hook. */
10931 buf.arg = mac_aedesc_to_lisp (desc);
10932 kbd_buffer_store_event (&buf);
6a0b5d37 10933}
1c05c15b 10934
a733ef16 10935#if TARGET_API_MAC_CARBON
68c767a3
YM
10936static OSStatus
10937mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10938 event, num_params, names, types)
10939 AEEventClass class;
10940 AEEventID id;
10941 Lisp_Object class_key, id_key;
10942 EventRef event;
10943 UInt32 num_params;
369a7a37
YM
10944 const EventParamName *names;
10945 const EventParamType *types;
68c767a3
YM
10946{
10947 OSStatus err = eventNotHandledErr;
10948 Lisp_Object binding;
10949
10950 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10951 if (!NILP (binding) && !EQ (binding, Qundefined))
10952 {
10953 if (INTEGERP (binding))
10954 err = XINT (binding);
10955 else
10956 {
10957 AppleEvent apple_event;
10958 err = create_apple_event_from_event_ref (event, num_params,
10959 names, types,
10960 &apple_event);
10961 if (err == noErr)
10962 {
10963 mac_store_apple_event (class_key, id_key, &apple_event);
10964 AEDisposeDesc (&apple_event);
0d36bf23 10965 mac_wakeup_from_rne ();
68c767a3
YM
10966 }
10967 }
6a0b5d37 10968 }
1c05c15b 10969
6a0b5d37
YM
10970 return err;
10971}
1c05c15b 10972
a733ef16
YM
10973void
10974mac_store_drag_event (window, mouse_pos, modifiers, desc)
10975 WindowRef window;
10976 Point mouse_pos;
10977 SInt16 modifiers;
10978 const AEDesc *desc;
6a0b5d37 10979{
a733ef16 10980 struct input_event buf;
1c05c15b 10981
a733ef16 10982 EVENT_INIT (buf);
b15325b2 10983
a733ef16
YM
10984 buf.kind = DRAG_N_DROP_EVENT;
10985 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10986 buf.timestamp = TickCount () * (1000 / 60);
10987 XSETINT (buf.x, mouse_pos.h);
10988 XSETINT (buf.y, mouse_pos.v);
10989 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10990 buf.arg = mac_aedesc_to_lisp (desc);
10991 kbd_buffer_store_event (&buf);
1c05c15b
YM
10992}
10993
7adf3143
YM
10994#ifdef MAC_OSX
10995OSStatus
10996mac_store_service_event (event)
1c05c15b 10997 EventRef event;
1c05c15b 10998{
7adf3143
YM
10999 OSStatus err;
11000 Lisp_Object id_key;
11001 int num_params;
11002 const EventParamName *names;
11003 const EventParamType *types;
11004 static const EventParamName names_pfm[] =
11005 {kEventParamServiceMessageName, kEventParamServiceUserData};
11006 static const EventParamType types_pfm[] =
11007 {typeCFStringRef, typeCFStringRef};
1c05c15b 11008
7adf3143
YM
11009 switch (GetEventKind (event))
11010 {
11011 case kEventServicePaste:
11012 id_key = Qpaste;
11013 num_params = 0;
11014 names = NULL;
11015 types = NULL;
11016 break;
1c05c15b 11017
7adf3143
YM
11018 case kEventServicePerform:
11019 id_key = Qperform;
11020 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
11021 names = names_pfm;
11022 types = types_pfm;
11023 break;
1c05c15b 11024
7adf3143
YM
11025 default:
11026 abort ();
11027 }
1c05c15b 11028
7adf3143
YM
11029 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
11030 event, num_params,
11031 names, types);
1c05c15b 11032
7adf3143 11033 return err;
1c05c15b 11034}
7adf3143 11035#endif /* MAC_OSX */
1c05c15b 11036
b15325b2
ST
11037static pascal OSStatus
11038mac_handle_window_event (next_handler, event, data)
11039 EventHandlerCallRef next_handler;
11040 EventRef event;
11041 void *data;
11042{
3354caee 11043 WindowRef wp;
7adf3143 11044 OSStatus err, result = eventNotHandledErr;
bed0bf95 11045 struct frame *f;
b15325b2
ST
11046 UInt32 attributes;
11047 XSizeHints *size_hints;
11048
a3510ffa 11049 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
3354caee 11050 NULL, sizeof (WindowRef), NULL, &wp);
a3510ffa
YM
11051 if (err != noErr)
11052 return eventNotHandledErr;
b15325b2 11053
bed0bf95 11054 f = mac_window_to_frame (wp);
b15325b2
ST
11055 switch (GetEventKind (event))
11056 {
7adf3143
YM
11057 /* -- window refresh events -- */
11058
e0e76ab9
ST
11059 case kEventWindowUpdate:
11060 result = CallNextEventHandler (next_handler, event);
11061 if (result != eventNotHandledErr)
7adf3143 11062 break;
e0e76ab9
ST
11063
11064 do_window_update (wp);
7adf3143
YM
11065 result = noErr;
11066 break;
e0e76ab9 11067
7adf3143 11068 /* -- window state change events -- */
bed0bf95 11069
7adf3143
YM
11070 case kEventWindowShowing:
11071 size_hints = FRAME_SIZE_HINTS (f);
11072 if (!(size_hints->flags & (USPosition | PPosition)))
11073 {
11074 struct frame *sf = SELECTED_FRAME ();
bed0bf95 11075
ad3b3e02 11076 if (!(FRAME_MAC_P (sf) && sf->async_visible))
7adf3143
YM
11077 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
11078 else
11079 {
11080 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
11081#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
11082 kWindowCascadeStartAtParentWindowScreen
11083#else
11084 kWindowCascadeOnParentWindowScreen
11085#endif
11086 );
c6829f81
YM
11087#if USE_MAC_TOOLBAR
11088 /* This is a workaround. RepositionWindow fails to put
11089 a window at the cascading position when its parent
11090 window has a Carbon HIToolbar. */
f9426479
YM
11091 if ((f->left_pos == sf->left_pos
11092 && f->top_pos == sf->top_pos)
11093 || (f->left_pos == sf->left_pos + 10 * 2
11094 && f->top_pos == sf->top_pos + 32 * 2))
ad3b3e02 11095 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
c6829f81 11096#endif
7adf3143
YM
11097 }
11098 result = noErr;
11099 }
11100 break;
11101
11102 case kEventWindowHiding:
11103 /* Before unmapping the window, update the WM_SIZE_HINTS
11104 property to claim that the current position of the window is
11105 user-specified, rather than program-specified, so that when
11106 the window is mapped again, it will be placed at the same
11107 location, without forcing the user to position it by hand
11108 again (they have already done that once for this window.) */
11109 x_wm_set_size_hint (f, (long) 0, 1);
11110 result = noErr;
11111 break;
11112
11113 case kEventWindowShown:
11114 case kEventWindowHidden:
11115 case kEventWindowCollapsed:
11116 case kEventWindowExpanded:
11117 mac_handle_visibility_change (f);
11118 result = noErr;
bed0bf95
YM
11119 break;
11120
b15325b2
ST
11121 case kEventWindowBoundsChanging:
11122 result = CallNextEventHandler (next_handler, event);
11123 if (result != eventNotHandledErr)
7adf3143 11124 break;
b15325b2 11125
a3510ffa
YM
11126 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11127 NULL, sizeof (UInt32), NULL, &attributes);
11128 if (err != noErr)
11129 break;
11130
bed0bf95 11131 size_hints = FRAME_SIZE_HINTS (f);
b15325b2
ST
11132 if ((attributes & kWindowBoundsChangeUserResize)
11133 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
11134 == (PResizeInc | PBaseSize | PMinSize)))
11135 {
11136 Rect bounds;
11137 int width, height;
11138
a3510ffa
YM
11139 err = GetEventParameter (event, kEventParamCurrentBounds,
11140 typeQDRectangle, NULL, sizeof (Rect),
11141 NULL, &bounds);
11142 if (err != noErr)
11143 break;
11144
b15325b2
ST
11145 width = bounds.right - bounds.left;
11146 height = bounds.bottom - bounds.top;
11147
11148 if (width < size_hints->min_width)
11149 width = size_hints->min_width;
11150 else
11151 width = size_hints->base_width
11152 + (int) ((width - size_hints->base_width)
11153 / (float) size_hints->width_inc + .5)
11154 * size_hints->width_inc;
11155
11156 if (height < size_hints->min_height)
11157 height = size_hints->min_height;
11158 else
11159 height = size_hints->base_height
11160 + (int) ((height - size_hints->base_height)
11161 / (float) size_hints->height_inc + .5)
11162 * size_hints->height_inc;
11163
11164 bounds.right = bounds.left + width;
11165 bounds.bottom = bounds.top + height;
11166 SetEventParameter (event, kEventParamCurrentBounds,
11167 typeQDRectangle, sizeof (Rect), &bounds);
7adf3143 11168 result = noErr;
b15325b2
ST
11169 }
11170 break;
1f98fbb4 11171
bed0bf95
YM
11172 case kEventWindowBoundsChanged:
11173 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
11174 NULL, sizeof (UInt32), NULL, &attributes);
11175 if (err != noErr)
11176 break;
11177
11178 if (attributes & kWindowBoundsChangeSizeChanged)
11179 {
11180 Rect bounds;
11181
11182 err = GetEventParameter (event, kEventParamCurrentBounds,
11183 typeQDRectangle, NULL, sizeof (Rect),
11184 NULL, &bounds);
11185 if (err == noErr)
11186 {
11187 int width, height;
11188
11189 width = bounds.right - bounds.left;
11190 height = bounds.bottom - bounds.top;
11191 mac_handle_size_change (f, width, height);
262be72a 11192 mac_wakeup_from_rne ();
bed0bf95
YM
11193 }
11194 }
11195
11196 if (attributes & kWindowBoundsChangeOriginChanged)
11197 mac_handle_origin_change (f);
11198
7adf3143 11199 result = noErr;
1f98fbb4 11200 break;
68c767a3 11201
7adf3143
YM
11202 /* -- window action events -- */
11203
750a6cf4
YM
11204 case kEventWindowClose:
11205 {
11206 struct input_event buf;
11207
11208 EVENT_INIT (buf);
11209 buf.kind = DELETE_WINDOW_EVENT;
bed0bf95 11210 XSETFRAME (buf.frame_or_window, f);
750a6cf4
YM
11211 buf.arg = Qnil;
11212 kbd_buffer_store_event (&buf);
11213 }
7adf3143
YM
11214 result = noErr;
11215 break;
11216
11217 case kEventWindowGetIdealSize:
11218 result = CallNextEventHandler (next_handler, event);
11219 if (result != eventNotHandledErr)
11220 break;
11221
11222 {
11223 Point ideal_size = mac_get_ideal_size (f);
11224
11225 err = SetEventParameter (event, kEventParamDimensions,
11226 typeQDPoint, sizeof (Point), &ideal_size);
11227 if (err == noErr)
11228 result = noErr;
11229 }
11230 break;
750a6cf4 11231
68c767a3
YM
11232#ifdef MAC_OSX
11233 case kEventWindowToolbarSwitchMode:
68c767a3 11234 {
369a7a37
YM
11235 static const EventParamName names[] = {kEventParamDirectObject,
11236 kEventParamWindowMouseLocation,
11237 kEventParamKeyModifiers,
11238 kEventParamMouseButton,
11239 kEventParamClickCount,
11240 kEventParamMouseChord};
11241 static const EventParamType types[] = {typeWindowRef,
11242 typeQDPoint,
11243 typeUInt32,
11244 typeMouseButton,
11245 typeUInt32,
11246 typeUInt32};
68c767a3
YM
11247 int num_params = sizeof (names) / sizeof (names[0]);
11248
11249 err = mac_store_event_ref_as_apple_event (0, 0,
11250 Qwindow,
11251 Qtoolbar_switch_mode,
11252 event, num_params,
11253 names, types);
11254 }
7adf3143
YM
11255 if (err == noErr)
11256 result = noErr;
11257 break;
68c767a3 11258#endif
02236cbc
YM
11259
11260#if USE_MAC_TSM
7adf3143
YM
11261 /* -- window focus events -- */
11262
02236cbc 11263 case kEventWindowFocusAcquired:
b4c51596 11264 err = mac_tsm_resume ();
7adf3143
YM
11265 if (err == noErr)
11266 result = noErr;
11267 break;
02236cbc
YM
11268
11269 case kEventWindowFocusRelinquish:
b4c51596 11270 err = mac_tsm_suspend ();
7adf3143
YM
11271 if (err == noErr)
11272 result = noErr;
11273 break;
11274#endif
11275
11276 default:
11277 abort ();
11278 }
11279
11280 return result;
11281}
11282
11283static pascal OSStatus
11284mac_handle_application_event (next_handler, event, data)
11285 EventHandlerCallRef next_handler;
11286 EventRef event;
11287 void *data;
11288{
11289 OSStatus err, result = eventNotHandledErr;
11290
11291 switch (GetEventKind (event))
11292 {
11293#if USE_MAC_TSM
11294 case kEventAppActivated:
11295 err = mac_tsm_resume ();
11296 break;
11297
11298 case kEventAppDeactivated:
11299 err = mac_tsm_suspend ();
11300 break;
11301#endif
11302
11303 default:
11304 abort ();
11305 }
11306
11307 if (err == noErr)
11308 result = noErr;
11309
11310 return result;
11311}
11312
11313static pascal OSStatus
11314mac_handle_keyboard_event (next_handler, event, data)
11315 EventHandlerCallRef next_handler;
11316 EventRef event;
11317 void *data;
11318{
11319 OSStatus err, result = eventNotHandledErr;
7b7d07bb 11320 UInt32 event_kind, key_code, modifiers;
7adf3143
YM
11321 unsigned char char_code;
11322
11323 event_kind = GetEventKind (event);
11324 switch (event_kind)
11325 {
11326 case kEventRawKeyDown:
11327 case kEventRawKeyRepeat:
11328 case kEventRawKeyUp:
7adf3143
YM
11329 /* When using Carbon Events, we need to pass raw keyboard events
11330 to the TSM ourselves. If TSM handles it, it will pass back
11331 noErr, otherwise it will pass back "eventNotHandledErr" and
11332 we can process it normally. */
7b7d07bb
YM
11333 result = CallNextEventHandler (next_handler, event);
11334 if (result != eventNotHandledErr)
11335 break;
11336
11337 if (read_socket_inev == NULL)
11338 break;
7adf3143
YM
11339
11340#if USE_MAC_TSM
11341 if (read_socket_inev->kind != NO_EVENT)
11342 {
11343 result = noErr;
11344 break;
11345 }
02236cbc 11346#endif
7adf3143
YM
11347
11348 if (event_kind == kEventRawKeyUp)
11349 break;
11350
11351 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11352 typeChar, NULL,
11353 sizeof (char), NULL, &char_code);
11354 if (err != noErr)
11355 break;
11356
11357 err = GetEventParameter (event, kEventParamKeyCode,
11358 typeUInt32, NULL,
11359 sizeof (UInt32), NULL, &key_code);
11360 if (err != noErr)
11361 break;
11362
7b7d07bb
YM
11363 err = GetEventParameter (event, kEventParamKeyModifiers,
11364 typeUInt32, NULL,
11365 sizeof (UInt32), NULL, &modifiers);
11366 if (err != noErr)
11367 break;
11368
c6829f81 11369 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
7adf3143
YM
11370 char_code, key_code, modifiers,
11371 ((unsigned long)
11372 (GetEventTime (event) / kEventDurationMillisecond)),
11373 read_socket_inev);
11374 result = noErr;
11375 break;
11376
11377 default:
11378 abort ();
11379 }
11380
11381 return result;
11382}
11383
11384static pascal OSStatus
11385mac_handle_command_event (next_handler, event, data)
11386 EventHandlerCallRef next_handler;
11387 EventRef event;
11388 void *data;
11389{
11390 OSStatus err, result = eventNotHandledErr;
11391 HICommand command;
11392 static const EventParamName names[] =
11393 {kEventParamDirectObject, kEventParamKeyModifiers};
11394 static const EventParamType types[] =
11395 {typeHICommand, typeUInt32};
11396 int num_params = sizeof (names) / sizeof (names[0]);
11397
11398 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11399 NULL, sizeof (HICommand), NULL, &command);
11400 if (err != noErr)
11401 return eventNotHandledErr;
11402
11403 switch (GetEventKind (event))
11404 {
11405 case kEventCommandProcess:
11406 result = CallNextEventHandler (next_handler, event);
11407 if (result != eventNotHandledErr)
11408 break;
11409
11410 err = GetEventParameter (event, kEventParamDirectObject,
11411 typeHICommand, NULL,
11412 sizeof (HICommand), NULL, &command);
11413
11414 if (err != noErr || command.commandID == 0)
11415 break;
11416
11417 /* A HI command event is mapped to an Apple event whose event
11418 class symbol is `hi-command' and event ID is its command
11419 ID. */
11420 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11421 Qhi_command, Qnil,
11422 event, num_params,
11423 names, types);
11424 if (err == noErr)
11425 result = noErr;
11426 break;
11427
11428 default:
11429 abort ();
b15325b2
ST
11430 }
11431
7adf3143 11432 return result;
b15325b2 11433}
95085023
YM
11434
11435static pascal OSStatus
11436mac_handle_mouse_event (next_handler, event, data)
11437 EventHandlerCallRef next_handler;
11438 EventRef event;
11439 void *data;
11440{
7adf3143 11441 OSStatus err, result = eventNotHandledErr;
95085023
YM
11442
11443 switch (GetEventKind (event))
11444 {
11445 case kEventMouseWheelMoved:
11446 {
3354caee 11447 WindowRef wp;
95085023
YM
11448 struct frame *f;
11449 EventMouseWheelAxis axis;
11450 SInt32 delta;
11451 Point point;
11452
11453 result = CallNextEventHandler (next_handler, event);
11454 if (result != eventNotHandledErr || read_socket_inev == NULL)
7adf3143
YM
11455 break;
11456
11457 f = mac_focus_frame (&one_mac_display_info);
95085023 11458
a3510ffa
YM
11459 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11460 NULL, sizeof (WindowRef), NULL, &wp);
7adf3143
YM
11461 if (err != noErr
11462 || wp != FRAME_MAC_WINDOW (f))
95085023
YM
11463 break;
11464
a3510ffa
YM
11465 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11466 typeMouseWheelAxis, NULL,
11467 sizeof (EventMouseWheelAxis), NULL, &axis);
11468 if (err != noErr || axis != kEventMouseWheelAxisY)
95085023
YM
11469 break;
11470
a3510ffa
YM
11471 err = GetEventParameter (event, kEventParamMouseLocation,
11472 typeQDPoint, NULL, sizeof (Point),
11473 NULL, &point);
11474 if (err != noErr)
11475 break;
5bc21f35 11476
7adf3143
YM
11477 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11478 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5bc21f35
YM
11479 if (point.h < 0 || point.v < 0
11480 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11481 f->tool_bar_window))
11482 break;
11483
11484 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11485 typeSInt32, NULL, sizeof (SInt32),
11486 NULL, &delta);
11487 if (err != noErr)
11488 break;
11489
95085023
YM
11490 read_socket_inev->kind = WHEEL_EVENT;
11491 read_socket_inev->code = 0;
11492 read_socket_inev->modifiers =
11493 (mac_event_to_emacs_modifiers (event)
11494 | ((delta < 0) ? down_modifier : up_modifier));
95085023
YM
11495 XSETINT (read_socket_inev->x, point.h);
11496 XSETINT (read_socket_inev->y, point.v);
11497 XSETFRAME (read_socket_inev->frame_or_window, f);
95085023 11498
7adf3143 11499 result = noErr;
95085023
YM
11500 }
11501 break;
11502
11503 default:
7adf3143 11504 abort ();
68c767a3
YM
11505 }
11506
7adf3143 11507 return result;
68c767a3 11508}
68c767a3 11509
02236cbc
YM
11510#if USE_MAC_TSM
11511static pascal OSStatus
11512mac_handle_text_input_event (next_handler, event, data)
11513 EventHandlerCallRef next_handler;
11514 EventRef event;
11515 void *data;
11516{
a56dd283 11517 OSStatus err, result;
02236cbc
YM
11518 Lisp_Object id_key = Qnil;
11519 int num_params;
369a7a37
YM
11520 const EventParamName *names;
11521 const EventParamType *types;
02236cbc 11522 static UInt32 seqno_uaia = 0;
369a7a37 11523 static const EventParamName names_uaia[] =
02236cbc
YM
11524 {kEventParamTextInputSendComponentInstance,
11525 kEventParamTextInputSendRefCon,
11526 kEventParamTextInputSendSLRec,
11527 kEventParamTextInputSendFixLen,
11528 kEventParamTextInputSendText,
11529 kEventParamTextInputSendUpdateRng,
11530 kEventParamTextInputSendHiliteRng,
11531 kEventParamTextInputSendClauseRng,
11532 kEventParamTextInputSendPinRng,
11533 kEventParamTextInputSendTextServiceEncoding,
11534 kEventParamTextInputSendTextServiceMacEncoding,
11535 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
369a7a37 11536 static const EventParamType types_uaia[] =
02236cbc
YM
11537 {typeComponentInstance,
11538 typeLongInteger,
11539 typeIntlWritingCode,
11540 typeLongInteger,
92289429 11541#ifdef MAC_OSX
02236cbc 11542 typeUnicodeText,
92289429
YM
11543#else
11544 typeChar,
11545#endif
02236cbc
YM
11546 typeTextRangeArray,
11547 typeTextRangeArray,
11548 typeOffsetArray,
11549 typeTextRange,
11550 typeUInt32,
11551 typeUInt32,
11552 typeUInt32};
369a7a37 11553 static const EventParamName names_ufke[] =
02236cbc
YM
11554 {kEventParamTextInputSendComponentInstance,
11555 kEventParamTextInputSendRefCon,
11556 kEventParamTextInputSendSLRec,
11557 kEventParamTextInputSendText};
369a7a37 11558 static const EventParamType types_ufke[] =
02236cbc
YM
11559 {typeComponentInstance,
11560 typeLongInteger,
11561 typeIntlWritingCode,
11562 typeUnicodeText};
11563
11564 result = CallNextEventHandler (next_handler, event);
7adf3143
YM
11565 if (result != eventNotHandledErr)
11566 return result;
02236cbc
YM
11567
11568 switch (GetEventKind (event))
11569 {
11570 case kEventTextInputUpdateActiveInputArea:
11571 id_key = Qupdate_active_input_area;
11572 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11573 names = names_uaia;
11574 types = types_uaia;
11575 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11576 typeUInt32, sizeof (UInt32), &seqno_uaia);
11577 seqno_uaia++;
a56dd283 11578 result = noErr;
02236cbc
YM
11579 break;
11580
11581 case kEventTextInputUnicodeForKeyEvent:
11582 {
11583 EventRef kbd_event;
d8506697 11584 UInt32 actual_size, modifiers;
02236cbc
YM
11585
11586 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11587 typeEventRef, NULL, sizeof (EventRef), NULL,
11588 &kbd_event);
11589 if (err == noErr)
11590 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11591 typeUInt32, NULL,
11592 sizeof (UInt32), NULL, &modifiers);
a84cad70
YM
11593 if (err == noErr && mac_mapped_modifiers (modifiers))
11594 /* There're mapped modifier keys. Process it in
7adf3143 11595 do_keystroke. */
a56dd283 11596 break;
02236cbc
YM
11597 if (err == noErr)
11598 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11599 typeUnicodeText, NULL, 0, &actual_size,
11600 NULL);
1e53bd0e 11601 if (err == noErr && actual_size == sizeof (UniChar))
02236cbc 11602 {
1e53bd0e
YM
11603 UniChar code;
11604
11605 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11606 typeUnicodeText, NULL,
11607 sizeof (UniChar), NULL, &code);
02236cbc
YM
11608 if (err == noErr && code < 0x80)
11609 {
7adf3143 11610 /* ASCII character. Process it in do_keystroke. */
67b5f809 11611 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
02236cbc 11612 {
1e53bd0e
YM
11613 UInt32 key_code;
11614
11615 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11616 typeUInt32, NULL, sizeof (UInt32),
11617 NULL, &key_code);
11618 if (!(err == noErr && key_code <= 0x7f
11619 && keycode_to_xkeysym_table [key_code]))
11620 {
11621 struct frame *f =
11622 mac_focus_frame (&one_mac_display_info);
11623
11624 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11625 read_socket_inev->code = code;
11626 read_socket_inev->modifiers =
750a6cf4
YM
11627 mac_to_emacs_modifiers (modifiers);
11628 read_socket_inev->modifiers |=
1e53bd0e
YM
11629 (extra_keyboard_modifiers
11630 & (meta_modifier | alt_modifier
11631 | hyper_modifier | super_modifier));
11632 XSETFRAME (read_socket_inev->frame_or_window, f);
11633 }
02236cbc 11634 }
a56dd283 11635 break;
02236cbc
YM
11636 }
11637 }
a56dd283
YM
11638 if (err == noErr)
11639 {
11640 /* Non-ASCII keystrokes without mapped modifiers are
11641 processed at the Lisp level. */
11642 id_key = Qunicode_for_key_event;
11643 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11644 names = names_ufke;
11645 types = types_ufke;
11646 result = noErr;
11647 }
02236cbc 11648 }
02236cbc
YM
11649 break;
11650
11651 case kEventTextInputOffsetToPos:
11652 {
11653 struct frame *f;
11654 struct window *w;
11655 Point p;
11656
11657 if (!OVERLAYP (Vmac_ts_active_input_overlay))
a56dd283 11658 break;
02236cbc
YM
11659
11660 /* Strictly speaking, this is not always correct because
11661 previous events may change some states about display. */
a56dd283
YM
11662 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11663 {
11664 /* Active input area is displayed around the current point. */
11665 f = SELECTED_FRAME ();
11666 w = XWINDOW (f->selected_window);
11667 }
11668 else if (WINDOWP (echo_area_window))
02236cbc
YM
11669 {
11670 /* Active input area is displayed in the echo area. */
11671 w = XWINDOW (echo_area_window);
11672 f = WINDOW_XFRAME (w);
11673 }
11674 else
a56dd283 11675 break;
02236cbc
YM
11676
11677 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
7adf3143
YM
11678 + WINDOW_LEFT_FRINGE_WIDTH (w)
11679 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
02236cbc 11680 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
7adf3143
YM
11681 + FONT_BASE (FRAME_FONT (f))
11682 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
02236cbc
YM
11683 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11684 typeQDPoint, sizeof (typeQDPoint), &p);
a56dd283
YM
11685 if (err == noErr)
11686 result = noErr;
02236cbc
YM
11687 }
11688 break;
11689
11690 default:
11691 abort ();
11692 }
11693
11694 if (!NILP (id_key))
11695 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11696 event, num_params,
11697 names, types);
7adf3143 11698 return result;
02236cbc
YM
11699}
11700#endif
3354caee 11701#endif /* TARGET_API_MAC_CARBON */
b15325b2 11702
02236cbc 11703
68c767a3 11704OSStatus
b15325b2 11705install_window_handler (window)
3354caee 11706 WindowRef window;
6a0b5d37 11707{
3e7424f7 11708 OSStatus err = noErr;
6a0b5d37 11709
3354caee 11710#if TARGET_API_MAC_CARBON
7adf3143 11711 if (err == noErr)
6a0b5d37 11712 {
7adf3143
YM
11713 static const EventTypeSpec specs[] =
11714 {
11715 /* -- window refresh events -- */
11716 {kEventClassWindow, kEventWindowUpdate},
11717 /* -- window state change events -- */
11718 {kEventClassWindow, kEventWindowShowing},
11719 {kEventClassWindow, kEventWindowHiding},
11720 {kEventClassWindow, kEventWindowShown},
11721 {kEventClassWindow, kEventWindowHidden},
11722 {kEventClassWindow, kEventWindowCollapsed},
11723 {kEventClassWindow, kEventWindowExpanded},
11724 {kEventClassWindow, kEventWindowBoundsChanging},
11725 {kEventClassWindow, kEventWindowBoundsChanged},
11726 /* -- window action events -- */
11727 {kEventClassWindow, kEventWindowClose},
11728 {kEventClassWindow, kEventWindowGetIdealSize},
68c767a3 11729#ifdef MAC_OSX
7adf3143 11730 {kEventClassWindow, kEventWindowToolbarSwitchMode},
68c767a3 11731#endif
02236cbc 11732#if USE_MAC_TSM
7adf3143
YM
11733 /* -- window focus events -- */
11734 {kEventClassWindow, kEventWindowFocusAcquired},
11735 {kEventClassWindow, kEventWindowFocusRelinquish},
02236cbc 11736#endif
7adf3143
YM
11737 };
11738 static EventHandlerUPP handle_window_eventUPP = NULL;
6a0b5d37 11739
7adf3143
YM
11740 if (handle_window_eventUPP == NULL)
11741 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
6a0b5d37 11742
7adf3143
YM
11743 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11744 GetEventTypeCount (specs),
11745 specs, NULL, NULL);
6a0b5d37 11746 }
30c92fab 11747#endif
6a0b5d37 11748
30c92fab 11749 if (err == noErr)
a733ef16 11750 err = install_drag_handler (window);
6a0b5d37
YM
11751
11752 return err;
11753}
b15325b2 11754
25c9622b
YM
11755void
11756remove_window_handler (window)
3354caee 11757 WindowRef window;
25c9622b 11758{
a733ef16 11759 remove_drag_handler (window);
742fbed7 11760}
b15325b2 11761
7adf3143
YM
11762#if TARGET_API_MAC_CARBON
11763static OSStatus
11764install_application_handler ()
b15325b2 11765{
3e7424f7 11766 OSStatus err = noErr;
95085023 11767
7adf3143
YM
11768 if (err == noErr)
11769 {
11770 static const EventTypeSpec specs[] = {
02236cbc 11771#if USE_MAC_TSM
7adf3143
YM
11772 {kEventClassApplication, kEventAppActivated},
11773 {kEventClassApplication, kEventAppDeactivated},
68c767a3 11774#endif
7adf3143
YM
11775 };
11776
11777 err = InstallApplicationEventHandler (NewEventHandlerUPP
11778 (mac_handle_application_event),
11779 GetEventTypeCount (specs),
11780 specs, NULL, NULL);
11781 }
11782
95085023 11783 if (err == noErr)
7adf3143
YM
11784 {
11785 static const EventTypeSpec specs[] =
11786 {{kEventClassKeyboard, kEventRawKeyDown},
11787 {kEventClassKeyboard, kEventRawKeyRepeat},
11788 {kEventClassKeyboard, kEventRawKeyUp}};
11789
11790 err = InstallApplicationEventHandler (NewEventHandlerUPP
11791 (mac_handle_keyboard_event),
11792 GetEventTypeCount (specs),
11793 specs, NULL, NULL);
11794 }
11795
30c92fab 11796 if (err == noErr)
7adf3143
YM
11797 {
11798 static const EventTypeSpec specs[] =
11799 {{kEventClassCommand, kEventCommandProcess}};
11800
11801 err = InstallApplicationEventHandler (NewEventHandlerUPP
11802 (mac_handle_command_event),
11803 GetEventTypeCount (specs),
11804 specs, NULL, NULL);
11805 }
11806
11807 if (err == noErr)
11808 {
11809 static const EventTypeSpec specs[] =
11810 {{kEventClassMouse, kEventMouseWheelMoved}};
11811
11812 err = InstallApplicationEventHandler (NewEventHandlerUPP
11813 (mac_handle_mouse_event),
11814 GetEventTypeCount (specs),
11815 specs, NULL, NULL);
11816 }
11817
02236cbc
YM
11818#if USE_MAC_TSM
11819 if (err == noErr)
7adf3143
YM
11820 {
11821 static const EventTypeSpec spec[] =
11822 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11823 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11824 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11825
11826 err = InstallApplicationEventHandler (NewEventHandlerUPP
11827 (mac_handle_text_input_event),
11828 GetEventTypeCount (spec),
11829 spec, NULL, NULL);
11830 }
742fbed7 11831#endif
7adf3143 11832
30c92fab 11833 if (err == noErr)
7adf3143
YM
11834 err = install_menu_target_item_handler ();
11835
11836#ifdef MAC_OSX
e2d3b7e1 11837 if (err == noErr)
7adf3143
YM
11838 err = install_service_handler ();
11839#endif
a733ef16 11840
30c92fab 11841 return err;
b15325b2 11842}
7adf3143 11843#endif
742fbed7 11844
19ee09cc
YM
11845static pascal void
11846mac_handle_dm_notification (event)
11847 AppleEvent *event;
11848{
11849 mac_screen_config_changed = 1;
11850}
11851
7adf3143
YM
11852#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11853static void
11854mac_handle_cg_display_reconfig (display, flags, user_info)
11855 CGDirectDisplayID display;
11856 CGDisplayChangeSummaryFlags flags;
11857 void *user_info;
11858{
11859 mac_screen_config_changed = 1;
11860}
11861#endif
11862
19ee09cc
YM
11863static OSErr
11864init_dm_notification_handler ()
11865{
7adf3143
YM
11866 OSErr err = noErr;
11867
11868#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11869#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11870 if (CGDisplayRegisterReconfigurationCallback != NULL)
11871#endif
11872 {
11873 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11874 NULL);
11875 }
11876#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11877 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11878#endif
11879#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11880#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11881 {
11882 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11883 ProcessSerialNumber psn;
19ee09cc 11884
7adf3143
YM
11885 if (handle_dm_notificationUPP == NULL)
11886 handle_dm_notificationUPP =
11887 NewDMNotificationUPP (mac_handle_dm_notification);
19ee09cc 11888
7adf3143
YM
11889 err = GetCurrentProcess (&psn);
11890 if (err == noErr)
11891 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11892 }
11893#endif
19ee09cc
YM
11894
11895 return err;
11896}
11897
11898static void
11899mac_get_screen_info (dpyinfo)
11900 struct mac_display_info *dpyinfo;
11901{
11902#ifdef MAC_OSX
11903 /* HasDepth returns true if it is possible to have a 32 bit display,
11904 but this may not be what is actually used. Mac OSX can do better. */
11905 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11906 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11907 {
11908 CGDisplayErr err;
11909 CGDisplayCount ndisps;
11910 CGDirectDisplayID *displays;
11911
11912 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11913 if (err == noErr)
11914 {
11915 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11916 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11917 }
11918 if (err == noErr)
11919 {
11920 CGRect bounds = CGRectZero;
11921
11922 while (ndisps-- > 0)
11923 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11924 dpyinfo->height = CGRectGetHeight (bounds);
11925 dpyinfo->width = CGRectGetWidth (bounds);
11926 }
11927 else
11928 {
11929 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11930 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11931 }
11932 }
11933#else /* !MAC_OSX */
11934 {
11935 GDHandle gdh = GetMainDevice ();
11936 Rect rect = (**gdh).gdRect;
11937
11938 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11939 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11940 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11941 break;
11942
11943 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11944 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11945 UnionRect (&rect, &(**gdh).gdRect, &rect);
11946
11947 dpyinfo->height = rect.bottom - rect.top;
11948 dpyinfo->width = rect.right - rect.left;
11949 }
11950#endif /* !MAC_OSX */
11951}
11952
11953
1a578e9b
AC
11954#if __profile__
11955void
11956profiler_exit_proc ()
11957{
11958 ProfilerDump ("\pEmacs.prof");
11959 ProfilerTerm ();
11960}
11961#endif
11962
11963/* These few functions implement Emacs as a normal Mac application
e6bdfa32
YM
11964 (almost): set up the heap and the Toolbox, handle necessary system
11965 events plus a few simple menu events. They also set up Emacs's
11966 access to functions defined in the rest of this file. Emacs uses
11967 function hooks to perform all its terminal I/O. A complete list of
11968 these functions appear in termhooks.h. For what they do, read the
11969 comments there and see also w32term.c and xterm.c. What's
11970 noticeably missing here is the event loop, which is normally
11971 present in most Mac application. After performing the necessary
11972 Mac initializations, main passes off control to emacs_main
11973 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11974 (defined further below) to read input. This is where
11975 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
1a578e9b 11976
25c9622b 11977#ifdef MAC_OS8
1a578e9b 11978#undef main
177c0ea7 11979int
1a578e9b
AC
11980main (void)
11981{
11982#if __profile__ /* is the profiler on? */
11983 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11984 exit(1);
11985#endif
11986
11987#if __MWERKS__
11988 /* set creator and type for files created by MSL */
e2d3b7e1 11989 _fcreator = MAC_EMACS_CREATOR_CODE;
1a578e9b
AC
11990 _ftype = 'TEXT';
11991#endif
11992
11993 do_init_managers ();
177c0ea7 11994
1a578e9b 11995 do_get_menus ();
177c0ea7 11996
6b61353c 11997#ifndef USE_LSB_TAG
2e875e36 11998 do_check_ram_size ();
6b61353c 11999#endif
2e875e36 12000
1a578e9b
AC
12001 init_emacs_passwd_dir ();
12002
12003 init_environ ();
12004
0e0a1663
YM
12005 init_coercion_handler ();
12006
1a578e9b
AC
12007 initialize_applescript ();
12008
6a0b5d37 12009 init_apple_event_handler ();
177c0ea7 12010
19ee09cc
YM
12011 init_dm_notification_handler ();
12012
1a578e9b
AC
12013 {
12014 char **argv;
12015 int argc = 0;
12016
12017 /* set up argv array from STR# resource */
12018 get_string_list (&argv, ARGV_STRING_LIST_ID);
12019 while (argv[argc])
12020 argc++;
12021
12022 /* free up AppleScript resources on exit */
12023 atexit (terminate_applescript);
12024
12025#if __profile__ /* is the profiler on? */
12026 atexit (profiler_exit_proc);
12027#endif
12028
12029 /* 3rd param "envp" never used in emacs_main */
12030 (void) emacs_main (argc, argv, 0);
12031 }
12032
12033 /* Never reached - real exit in Fkill_emacs */
12034 return 0;
12035}
e0f712ba 12036#endif
1a578e9b 12037
3354caee 12038#if !TARGET_API_MAC_CARBON
b15325b2
ST
12039static RgnHandle mouse_region = NULL;
12040
12041Boolean
12042mac_wait_next_event (er, sleep_time, dequeue)
12043 EventRecord *er;
12044 UInt32 sleep_time;
12045 Boolean dequeue;
12046{
12047 static EventRecord er_buf = {nullEvent};
12048 UInt32 target_tick, current_tick;
12049 EventMask event_mask;
12050
12051 if (mouse_region == NULL)
12052 mouse_region = NewRgn ();
12053
12054 event_mask = everyEvent;
6a0b5d37 12055 if (!mac_ready_for_apple_events)
b15325b2
ST
12056 event_mask -= highLevelEventMask;
12057
12058 current_tick = TickCount ();
12059 target_tick = current_tick + sleep_time;
12060
12061 if (er_buf.what == nullEvent)
12062 while (!WaitNextEvent (event_mask, &er_buf,
12063 target_tick - current_tick, mouse_region))
12064 {
12065 current_tick = TickCount ();
12066 if (target_tick <= current_tick)
12067 return false;
12068 }
12069
12070 *er = er_buf;
12071 if (dequeue)
12072 er_buf.what = nullEvent;
12073 return true;
12074}
3354caee 12075#endif /* not TARGET_API_MAC_CARBON */
b15325b2 12076
a733ef16
YM
12077#if TARGET_API_MAC_CARBON
12078OSStatus
12079mac_post_mouse_moved_event ()
12080{
12081 EventRef event = NULL;
12082 OSStatus err;
12083
12084 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
12085 kEventAttributeNone, &event);
12086 if (err == noErr)
12087 {
12088 Point mouse_pos;
12089
2a953eae 12090 GetGlobalMouse (&mouse_pos);
a733ef16
YM
12091 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
12092 sizeof (Point), &mouse_pos);
12093 }
12094 if (err == noErr)
12095 {
12096 UInt32 modifiers = GetCurrentKeyModifiers ();
12097
12098 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
12099 sizeof (UInt32), &modifiers);
12100 }
12101 if (err == noErr)
12102 err = PostEventToQueue (GetCurrentEventQueue (), event,
12103 kEventPriorityStandard);
12104 if (event)
12105 ReleaseEvent (event);
12106
12107 return err;
12108}
12109#endif
12110
1a578e9b
AC
12111/* Emacs calls this whenever it wants to read an input event from the
12112 user. */
12113int
50bf7673
ST
12114XTread_socket (sd, expected, hold_quit)
12115 int sd, expected;
12116 struct input_event *hold_quit;
1a578e9b 12117{
6b61353c 12118 struct input_event inev;
177c0ea7 12119 int count = 0;
3354caee 12120#if TARGET_API_MAC_CARBON
742fbed7 12121 EventRef eventRef;
b15325b2 12122 EventTargetRef toolbox_dispatcher;
742fbed7 12123#endif
1a578e9b 12124 EventRecord er;
50bf7673 12125 struct mac_display_info *dpyinfo = &one_mac_display_info;
1a578e9b
AC
12126
12127 if (interrupt_input_blocked)
12128 {
12129 interrupt_input_pending = 1;
12130 return -1;
12131 }
12132
12133 interrupt_input_pending = 0;
12134 BLOCK_INPUT;
12135
12136 /* So people can tell when we have read the available input. */
12137 input_signal_count++;
12138
b465419f
YM
12139 ++handling_signal;
12140
3354caee 12141#if TARGET_API_MAC_CARBON
b15325b2 12142 toolbox_dispatcher = GetEventDispatcherTarget ();
1a578e9b 12143
4ea08bbf
YM
12144 while (
12145#if USE_CG_DRAWING
12146 mac_prepare_for_quickdraw (NULL),
12147#endif
12148 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
50bf7673 12149 kEventRemoveFromQueue, &eventRef))
3354caee 12150#else /* !TARGET_API_MAC_CARBON */
b15325b2 12151 while (mac_wait_next_event (&er, 0, true))
3354caee 12152#endif /* !TARGET_API_MAC_CARBON */
742fbed7 12153 {
50bf7673
ST
12154 int do_help = 0;
12155 struct frame *f;
95dfb192 12156 unsigned long timestamp;
50bf7673 12157
50bf7673
ST
12158 EVENT_INIT (inev);
12159 inev.kind = NO_EVENT;
12160 inev.arg = Qnil;
12161
3354caee 12162#if TARGET_API_MAC_CARBON
95dfb192 12163 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
95dfb192 12164
177c0ea7 12165 if (!mac_convert_event_ref (eventRef, &er))
7adf3143
YM
12166 goto OTHER;
12167#else /* !TARGET_API_MAC_CARBON */
12168 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12169#endif /* !TARGET_API_MAC_CARBON */
12170
50bf7673 12171 switch (er.what)
1a578e9b 12172 {
50bf7673
ST
12173 case mouseDown:
12174 case mouseUp:
12175 {
3354caee 12176 WindowRef window_ptr;
e6bdfa32 12177 ControlPartCode part_code;
50bf7673
ST
12178 int tool_bar_p = 0;
12179
3354caee 12180#if TARGET_API_MAC_CARBON
7adf3143
YM
12181 OSStatus err;
12182
59feca74
ST
12183 /* This is needed to send mouse events like aqua window
12184 buttons to the correct handler. */
7adf3143
YM
12185 read_socket_inev = &inev;
12186 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12187 read_socket_inev = NULL;
12188 if (err != eventNotHandledErr)
59feca74
ST
12189 break;
12190#endif
05f7d868 12191 last_mouse_glyph_frame = 0;
59feca74 12192
50bf7673
ST
12193 if (dpyinfo->grabbed && last_mouse_frame
12194 && FRAME_LIVE_P (last_mouse_frame))
12195 {
12196 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
12197 part_code = inContent;
12198 }
12199 else
12200 {
bf06c82f 12201 part_code = FindWindow (er.where, &window_ptr);
50bf7673
ST
12202 if (tip_window && window_ptr == tip_window)
12203 {
12204 HideWindow (tip_window);
bf06c82f 12205 part_code = FindWindow (er.where, &window_ptr);
50bf7673 12206 }
50bf7673
ST
12207 }
12208
0e41b66d
YM
12209 if (er.what != mouseDown &&
12210 (part_code != inContent || dpyinfo->grabbed == 0))
bf06c82f
ST
12211 break;
12212
50bf7673
ST
12213 switch (part_code)
12214 {
12215 case inMenuBar:
7ca7ccd5 12216 f = mac_focus_frame (dpyinfo);
bf06c82f
ST
12217 saved_menu_event_location = er.where;
12218 inev.kind = MENU_BAR_ACTIVATE_EVENT;
12219 XSETFRAME (inev.frame_or_window, f);
50bf7673 12220 break;
742fbed7 12221
50bf7673 12222 case inContent:
4cb62a90
YM
12223 if (
12224#if TARGET_API_MAC_CARBON
12225 FrontNonFloatingWindow ()
12226#else
12227 FrontWindow ()
12228#endif
0d36bf23
YM
12229 != window_ptr
12230 || (mac_window_to_frame (window_ptr)
12231 != dpyinfo->x_focus_frame))
50bf7673
ST
12232 SelectWindow (window_ptr);
12233 else
12234 {
e6bdfa32 12235 ControlPartCode control_part_code;
3354caee 12236 ControlRef ch;
7adf3143 12237 Point mouse_loc;
5b8b73ff
YM
12238#ifdef MAC_OSX
12239 ControlKind control_kind;
12240#endif
177c0ea7 12241
50bf7673
ST
12242 f = mac_window_to_frame (window_ptr);
12243 /* convert to local coordinates of new window */
7adf3143
YM
12244 mouse_loc.h = (er.where.h
12245 - (f->left_pos
12246 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12247 mouse_loc.v = (er.where.v
12248 - (f->top_pos
12249 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
e0f712ba 12250#if TARGET_API_MAC_CARBON
50bf7673
ST
12251 ch = FindControlUnderMouse (mouse_loc, window_ptr,
12252 &control_part_code);
5b8b73ff
YM
12253#ifdef MAC_OSX
12254 if (ch)
12255 GetControlKind (ch, &control_kind);
12256#endif
e0f712ba 12257#else
50bf7673
ST
12258 control_part_code = FindControl (mouse_loc, window_ptr,
12259 &ch);
e0f712ba
AC
12260#endif
12261
3354caee 12262#if TARGET_API_MAC_CARBON
50bf7673
ST
12263 inev.code = mac_get_mouse_btn (eventRef);
12264 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
742fbed7 12265#else
50bf7673
ST
12266 inev.code = mac_get_emulated_btn (er.modifiers);
12267 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
742fbed7 12268#endif
50bf7673
ST
12269 XSETINT (inev.x, mouse_loc.h);
12270 XSETINT (inev.y, mouse_loc.v);
50bf7673 12271
f93e4d4f
YM
12272 if ((dpyinfo->grabbed && tracked_scroll_bar)
12273 || (ch != 0
5b8b73ff 12274#ifndef USE_TOOLKIT_SCROLL_BARS
f93e4d4f
YM
12275 /* control_part_code becomes kControlNoPart if
12276 a progress indicator is clicked. */
12277 && control_part_code != kControlNoPart
5b8b73ff
YM
12278#else /* USE_TOOLKIT_SCROLL_BARS */
12279#ifdef MAC_OSX
f93e4d4f 12280 && control_kind.kind == kControlKindScrollBar
5b8b73ff
YM
12281#endif /* MAC_OSX */
12282#endif /* USE_TOOLKIT_SCROLL_BARS */
f93e4d4f 12283 ))
50bf7673
ST
12284 {
12285 struct scroll_bar *bar;
12286
12287 if (dpyinfo->grabbed && tracked_scroll_bar)
12288 {
12289 bar = tracked_scroll_bar;
5b8b73ff 12290#ifndef USE_TOOLKIT_SCROLL_BARS
50bf7673 12291 control_part_code = kControlIndicatorPart;
5b8b73ff 12292#endif
50bf7673
ST
12293 }
12294 else
12295 bar = (struct scroll_bar *) GetControlReference (ch);
5b8b73ff
YM
12296#ifdef USE_TOOLKIT_SCROLL_BARS
12297 /* Make the "Ctrl-Mouse-2 splits window" work
12298 for toolkit scroll bars. */
e6509087 12299 if (inev.modifiers & ctrl_modifier)
5b8b73ff
YM
12300 x_scroll_bar_handle_click (bar, control_part_code,
12301 &er, &inev);
12302 else if (er.what == mouseDown)
12303 x_scroll_bar_handle_press (bar, control_part_code,
e6509087 12304 mouse_loc, &inev);
5b8b73ff 12305 else
95dfb192 12306 x_scroll_bar_handle_release (bar, &inev);
5b8b73ff 12307#else /* not USE_TOOLKIT_SCROLL_BARS */
50bf7673
ST
12308 x_scroll_bar_handle_click (bar, control_part_code,
12309 &er, &inev);
12310 if (er.what == mouseDown
12311 && control_part_code == kControlIndicatorPart)
12312 tracked_scroll_bar = bar;
12313 else
12314 tracked_scroll_bar = NULL;
5b8b73ff 12315#endif /* not USE_TOOLKIT_SCROLL_BARS */
50bf7673
ST
12316 }
12317 else
12318 {
12319 Lisp_Object window;
12320 int x = mouse_loc.h;
12321 int y = mouse_loc.v;
12322
12323 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
12324 if (EQ (window, f->tool_bar_window))
12325 {
12326 if (er.what == mouseDown)
12327 handle_tool_bar_click (f, x, y, 1, 0);
12328 else
12329 handle_tool_bar_click (f, x, y, 0,
12330 inev.modifiers);
12331 tool_bar_p = 1;
12332 }
12333 else
12334 {
12335 XSETFRAME (inev.frame_or_window, f);
12336 inev.kind = MOUSE_CLICK_EVENT;
12337 }
12338 }
12339
12340 if (er.what == mouseDown)
12341 {
12342 dpyinfo->grabbed |= (1 << inev.code);
12343 last_mouse_frame = f;
50bf7673
ST
12344
12345 if (!tool_bar_p)
12346 last_tool_bar_item = -1;
12347 }
12348 else
12349 {
bf06c82f 12350 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
50bf7673
ST
12351 /* If a button is released though it was not
12352 previously pressed, that would be because
12353 of multi-button emulation. */
12354 dpyinfo->grabbed = 0;
12355 else
12356 dpyinfo->grabbed &= ~(1 << inev.code);
12357 }
12358
0e41b66d
YM
12359 /* Ignore any mouse motion that happened before
12360 this event; any subsequent mouse-movement Emacs
12361 events should reflect only motion after the
12362 ButtonPress. */
12363 if (f != 0)
12364 f->mouse_moved = 0;
12365
5b8b73ff 12366#ifdef USE_TOOLKIT_SCROLL_BARS
e6509087
YM
12367 if (inev.kind == MOUSE_CLICK_EVENT
12368 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12369 && (inev.modifiers & ctrl_modifier)))
5b8b73ff
YM
12370#endif
12371 switch (er.what)
12372 {
12373 case mouseDown:
12374 inev.modifiers |= down_modifier;
12375 break;
12376 case mouseUp:
12377 inev.modifiers |= up_modifier;
12378 break;
12379 }
50bf7673
ST
12380 }
12381 break;
1a578e9b 12382
50bf7673
ST
12383 case inDrag:
12384#if TARGET_API_MAC_CARBON
a733ef16 12385 case inProxyIcon:
458dbb8c
YM
12386 if (IsWindowPathSelectClick (window_ptr, &er))
12387 {
12388 WindowPathSelect (window_ptr, NULL, NULL);
12389 break;
12390 }
a733ef16
YM
12391 if (part_code == inProxyIcon
12392 && (TrackWindowProxyDrag (window_ptr, er.where)
12393 != errUserWantsToDragWindow))
12394 break;
bf06c82f 12395 DragWindow (window_ptr, er.where, NULL);
50bf7673
ST
12396#else /* not TARGET_API_MAC_CARBON */
12397 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
e439b925
ST
12398 /* Update the frame parameters. */
12399 {
12400 struct frame *f = mac_window_to_frame (window_ptr);
bf06c82f 12401
e439b925 12402 if (f && !f->async_iconified)
bed0bf95 12403 mac_handle_origin_change (f);
e439b925 12404 }
3354caee 12405#endif /* not TARGET_API_MAC_CARBON */
50bf7673 12406 break;
177c0ea7 12407
50bf7673
ST
12408 case inGoAway:
12409 if (TrackGoAway (window_ptr, er.where))
12410 {
12411 inev.kind = DELETE_WINDOW_EVENT;
12412 XSETFRAME (inev.frame_or_window,
12413 mac_window_to_frame (window_ptr));
12414 }
12415 break;
1a578e9b 12416
50bf7673
ST
12417 /* window resize handling added --ben */
12418 case inGrow:
bf06c82f
ST
12419 do_grow_window (window_ptr, &er);
12420 break;
e0f712ba 12421
50bf7673
ST
12422 /* window zoom handling added --ben */
12423 case inZoomIn:
12424 case inZoomOut:
12425 if (TrackBox (window_ptr, er.where, part_code))
12426 do_zoom_window (window_ptr, part_code);
12427 break;
742fbed7 12428
c6829f81
YM
12429#if USE_MAC_TOOLBAR
12430 case inStructure:
12431 {
12432 OSStatus err;
12433 HIViewRef ch;
12434
12435 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12436 eventRef, &ch);
12437 /* This doesn't work on Mac OS X 10.2. */
12438 if (err == noErr)
12439 HIViewClick (ch, eventRef);
12440 }
12441 break;
12442#endif /* USE_MAC_TOOLBAR */
12443
50bf7673
ST
12444 default:
12445 break;
12446 }
12447 }
12448 break;
e0f712ba 12449
7adf3143 12450#if !TARGET_API_MAC_CARBON
50bf7673 12451 case updateEvt:
3354caee 12452 do_window_update ((WindowRef) er.message);
50bf7673 12453 break;
7adf3143 12454#endif
177c0ea7 12455
50bf7673 12456 case osEvt:
50bf7673
ST
12457 switch ((er.message >> 24) & 0x000000FF)
12458 {
50bf7673 12459 case mouseMovedMessage:
3354caee 12460#if !TARGET_API_MAC_CARBON
b15325b2
ST
12461 SetRectRgn (mouse_region, er.where.h, er.where.v,
12462 er.where.h + 1, er.where.v + 1);
12463#endif
50bf7673 12464 previous_help_echo_string = help_echo_string;
af1229d9 12465 help_echo_string = Qnil;
1a578e9b 12466
7ca7ccd5
YM
12467 if (dpyinfo->grabbed && last_mouse_frame
12468 && FRAME_LIVE_P (last_mouse_frame))
12469 f = last_mouse_frame;
12470 else
12471 f = dpyinfo->x_focus_frame;
12472
12473 if (dpyinfo->mouse_face_hidden)
12474 {
12475 dpyinfo->mouse_face_hidden = 0;
12476 clear_mouse_face (dpyinfo);
12477 }
12478
12479 if (f)
12480 {
3354caee 12481 WindowRef wp = FRAME_MAC_WINDOW (f);
7adf3143
YM
12482 Point mouse_pos;
12483
12484 mouse_pos.h = (er.where.h
12485 - (f->left_pos
12486 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12487 mouse_pos.v = (er.where.v
12488 - (f->top_pos
12489 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
7ca7ccd5 12490 if (dpyinfo->grabbed && tracked_scroll_bar)
5b8b73ff
YM
12491#ifdef USE_TOOLKIT_SCROLL_BARS
12492 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
95dfb192 12493 mouse_pos, &inev);
5b8b73ff 12494#else /* not USE_TOOLKIT_SCROLL_BARS */
7ca7ccd5
YM
12495 x_scroll_bar_note_movement (tracked_scroll_bar,
12496 mouse_pos.v
12497 - XINT (tracked_scroll_bar->top),
5b8b73ff
YM
12498 er.when * (1000 / 60));
12499#endif /* not USE_TOOLKIT_SCROLL_BARS */
7ca7ccd5
YM
12500 else
12501 {
12502 /* Generate SELECT_WINDOW_EVENTs when needed. */
92b23323 12503 if (!NILP (Vmouse_autoselect_window))
7ca7ccd5
YM
12504 {
12505 Lisp_Object window;
12506
12507 window = window_from_coordinates (f,
12508 mouse_pos.h,
12509 mouse_pos.v,
12510 0, 0, 0, 0);
12511
12512 /* Window will be selected only when it is
12513 not selected now and last mouse movement
12514 event was not in it. Minibuffer window
e0f24100 12515 will be selected only when it is active. */
7ca7ccd5
YM
12516 if (WINDOWP (window)
12517 && !EQ (window, last_window)
b0c6cec4
MR
12518 && !EQ (window, selected_window)
12519 /* For click-to-focus window managers
12520 create event iff we don't leave the
12521 selected frame. */
12522 && (focus_follows_mouse
12523 || (EQ (XWINDOW (window)->frame,
12524 XWINDOW (selected_window)->frame))))
7ca7ccd5
YM
12525 {
12526 inev.kind = SELECT_WINDOW_EVENT;
12527 inev.frame_or_window = window;
12528 }
12529
12530 last_window=window;
12531 }
af1229d9
YM
12532 if (!note_mouse_movement (f, &mouse_pos))
12533 help_echo_string = previous_help_echo_string;
c6829f81
YM
12534#if USE_MAC_TOOLBAR
12535 else
12536 mac_tool_bar_note_mouse_movement (f, eventRef);
12537#endif
7ca7ccd5
YM
12538 }
12539 }
1a578e9b 12540
50bf7673
ST
12541 /* If the contents of the global variable
12542 help_echo_string has changed, generate a
12543 HELP_EVENT. */
12544 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12545 do_help = 1;
1a578e9b 12546 break;
7adf3143
YM
12547
12548 default:
12549 goto OTHER;
1a578e9b 12550 }
50bf7673
ST
12551 break;
12552
12553 case activateEvt:
12554 {
3354caee 12555 WindowRef window_ptr = (WindowRef) er.message;
7b7d07bb
YM
12556 OSErr err;
12557 ControlRef root_control;
177c0ea7 12558
50bf7673
ST
12559 if (window_ptr == tip_window)
12560 {
12561 HideWindow (tip_window);
12562 break;
12563 }
177c0ea7 12564
59feca74 12565 if (!is_emacs_window (window_ptr))
7adf3143
YM
12566 goto OTHER;
12567
12568 f = mac_window_to_frame (window_ptr);
f94a2622 12569
50bf7673
ST
12570 if ((er.modifiers & activeFlag) != 0)
12571 {
59feca74 12572 /* A window has been activated */
7adf3143 12573 Point mouse_loc;
177c0ea7 12574
7b7d07bb
YM
12575 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12576 if (err == noErr)
12577 ActivateControl (root_control);
12578
7ca7ccd5 12579 x_detect_focus_change (dpyinfo, &er, &inev);
177c0ea7 12580
7adf3143
YM
12581 mouse_loc.h = (er.where.h
12582 - (f->left_pos
12583 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12584 mouse_loc.v = (er.where.v
12585 - (f->top_pos
12586 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
59feca74 12587 /* Window-activated event counts as mouse movement,
50bf7673 12588 so update things that depend on mouse position. */
7adf3143 12589 note_mouse_movement (f, &mouse_loc);
50bf7673
ST
12590 }
12591 else
12592 {
59feca74 12593 /* A window has been deactivated */
7b7d07bb
YM
12594 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12595 if (err == noErr)
12596 DeactivateControl (root_control);
12597
70385fe6 12598#ifdef USE_TOOLKIT_SCROLL_BARS
5b8b73ff
YM
12599 if (dpyinfo->grabbed && tracked_scroll_bar)
12600 {
12601 struct input_event event;
12602
12603 EVENT_INIT (event);
12604 event.kind = NO_EVENT;
95dfb192 12605 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
5b8b73ff
YM
12606 if (event.kind != NO_EVENT)
12607 {
95dfb192 12608 event.timestamp = timestamp;
5b8b73ff
YM
12609 kbd_buffer_store_event_hold (&event, hold_quit);
12610 count++;
12611 }
12612 }
12613#endif
59feca74
ST
12614 dpyinfo->grabbed = 0;
12615
7ca7ccd5 12616 x_detect_focus_change (dpyinfo, &er, &inev);
177c0ea7 12617
50bf7673
ST
12618 if (f == dpyinfo->mouse_face_mouse_frame)
12619 {
12620 /* If we move outside the frame, then we're
12621 certainly no longer on any text in the
12622 frame. */
12623 clear_mouse_face (dpyinfo);
12624 dpyinfo->mouse_face_mouse_frame = 0;
12625 }
177c0ea7 12626
50bf7673
ST
12627 /* Generate a nil HELP_EVENT to cancel a help-echo.
12628 Do it only if there's something to cancel.
12629 Otherwise, the startup message is cleared when the
12630 mouse leaves the frame. */
12631 if (any_help_event_p)
12632 do_help = -1;
12633 }
12634 }
12635 break;
177c0ea7 12636
50bf7673 12637 case keyDown:
2abb0fde 12638 case keyUp:
50bf7673 12639 case autoKey:
7adf3143 12640 ObscureCursor ();
b8c6940e 12641
7adf3143
YM
12642 f = mac_focus_frame (dpyinfo);
12643 XSETFRAME (inev.frame_or_window, f);
b8c6940e 12644
7adf3143
YM
12645 /* If mouse-highlight is an integer, input clears out mouse
12646 highlighting. */
12647 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12648 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12649 {
12650 clear_mouse_face (dpyinfo);
12651 dpyinfo->mouse_face_hidden = 1;
12652 }
7b7d07bb
YM
12653
12654 {
12655 UInt32 modifiers = er.modifiers, mapped_modifiers;
12656
12657#ifdef MAC_OSX
12658 GetEventParameter (eventRef, kEventParamKeyModifiers,
12659 typeUInt32, NULL,
12660 sizeof (UInt32), NULL, &modifiers);
12661#endif
12662 mapped_modifiers = mac_mapped_modifiers (modifiers);
12663
b8c6940e 12664#if TARGET_API_MAC_CARBON
7b7d07bb
YM
12665 if (!(mapped_modifiers
12666 & ~(mac_pass_command_to_system ? cmdKey : 0)
12667 & ~(mac_pass_control_to_system ? controlKey : 0)))
12668 goto OTHER;
12669 else
742fbed7 12670#endif
7b7d07bb
YM
12671 if (er.what != keyUp)
12672 do_keystroke (er.what, er.message & charCodeMask,
12673 (er.message & keyCodeMask) >> 8,
12674 modifiers, timestamp, &inev);
12675 }
50bf7673 12676 break;
177c0ea7 12677
50bf7673 12678 case kHighLevelEvent:
95dfb192 12679 AEProcessAppleEvent (&er);
95dfb192 12680 break;
177c0ea7 12681
50bf7673 12682 default:
7adf3143
YM
12683 OTHER:
12684#if TARGET_API_MAC_CARBON
12685 {
12686 OSStatus err;
12687
12688 read_socket_inev = &inev;
12689 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12690 read_socket_inev = NULL;
12691 }
12692#endif
50bf7673
ST
12693 break;
12694 }
3354caee 12695#if TARGET_API_MAC_CARBON
742fbed7 12696 ReleaseEvent (eventRef);
742fbed7 12697#endif
1a578e9b 12698
50bf7673
ST
12699 if (inev.kind != NO_EVENT)
12700 {
95dfb192 12701 inev.timestamp = timestamp;
50bf7673
ST
12702 kbd_buffer_store_event_hold (&inev, hold_quit);
12703 count++;
12704 }
12705
12706 if (do_help
12707 && !(hold_quit && hold_quit->kind != NO_EVENT))
12708 {
12709 Lisp_Object frame;
12710
12711 if (f)
12712 XSETFRAME (frame, f);
12713 else
12714 frame = Qnil;
12715
12716 if (do_help > 0)
12717 {
12718 any_help_event_p = 1;
12719 gen_help_event (help_echo_string, frame, help_echo_window,
12720 help_echo_object, help_echo_pos);
12721 }
12722 else
12723 {
12724 help_echo_string = Qnil;
12725 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12726 }
12727 count++;
12728 }
50bf7673
ST
12729 }
12730
1a578e9b
AC
12731 /* If the focus was just given to an autoraising frame,
12732 raise it now. */
12733 /* ??? This ought to be able to handle more than one such frame. */
12734 if (pending_autoraise_frame)
12735 {
12736 x_raise_frame (pending_autoraise_frame);
12737 pending_autoraise_frame = 0;
12738 }
12739
19ee09cc
YM
12740 if (mac_screen_config_changed)
12741 {
12742 mac_get_screen_info (dpyinfo);
12743 mac_screen_config_changed = 0;
12744 }
12745
3354caee 12746#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
12747 /* Check which frames are still visible. We do this here because
12748 there doesn't seem to be any direct notification from the Window
12749 Manager that the visibility of a window has changed (at least,
12750 not in all cases). */
12751 {
12752 Lisp_Object tail, frame;
12753
12754 FOR_EACH_FRAME (tail, frame)
12755 {
12756 struct frame *f = XFRAME (frame);
12757
12758 /* The tooltip has been drawn already. Avoid the
12759 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12760 if (EQ (frame, tip_frame))
12761 continue;
12762
12763 if (FRAME_MAC_P (f))
12764 mac_handle_visibility_change (f);
12765 }
12766 }
12767#endif
12768
b465419f 12769 --handling_signal;
6b61353c 12770 UNBLOCK_INPUT;
1a578e9b
AC
12771 return count;
12772}
12773
12774
12775/* Need to override CodeWarrior's input function so no conversion is
12776 done on newlines Otherwise compiled functions in .elc files will be
12777 read incorrectly. Defined in ...:MSL C:MSL
12778 Common:Source:buffer_io.c. */
12779#ifdef __MWERKS__
12780void
12781__convert_to_newlines (unsigned char * p, size_t * n)
12782{
12783#pragma unused(p,n)
12784}
12785
12786void
12787__convert_from_newlines (unsigned char * p, size_t * n)
12788{
12789#pragma unused(p,n)
12790}
12791#endif
12792
b15325b2 12793#ifdef MAC_OS8
770136ad 12794void
50bf7673 12795make_mac_terminal_frame (struct frame *f)
1a578e9b 12796{
50bf7673 12797 Lisp_Object frame;
b15325b2 12798 Rect r;
177c0ea7 12799
50bf7673
ST
12800 XSETFRAME (frame, f);
12801
12802 f->output_method = output_mac;
12803 f->output_data.mac = (struct mac_output *)
12804 xmalloc (sizeof (struct mac_output));
12805 bzero (f->output_data.mac, sizeof (struct mac_output));
12806
12807 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
177c0ea7 12808
50bf7673
ST
12809 FRAME_COLS (f) = 96;
12810 FRAME_LINES (f) = 4;
12811
12812 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12813 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12814
12815 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
1a578e9b
AC
12816
12817 f->output_data.mac->cursor_pixel = 0;
12818 f->output_data.mac->border_pixel = 0x00ff00;
12819 f->output_data.mac->mouse_pixel = 0xff00ff;
12820 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12821
25c9622b
YM
12822 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12823 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12824 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12825 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12826 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12827 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
b15325b2 12828
f1a83aab 12829 FRAME_FONTSET (f) = -1;
1a578e9b 12830 f->output_data.mac->explicit_parent = 0;
b15325b2
ST
12831 f->left_pos = 8;
12832 f->top_pos = 32;
f1a83aab 12833 f->border_width = 0;
177c0ea7 12834
f1a83aab 12835 f->internal_border_width = 0;
1a578e9b 12836
1a578e9b
AC
12837 f->auto_raise = 1;
12838 f->auto_lower = 1;
177c0ea7 12839
f1a83aab
KS
12840 f->new_text_cols = 0;
12841 f->new_text_lines = 0;
6b61353c 12842
b15325b2
ST
12843 SetRect (&r, f->left_pos, f->top_pos,
12844 f->left_pos + FRAME_PIXEL_WIDTH (f),
12845 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12846
12847 BLOCK_INPUT;
12848
12849 if (!(FRAME_MAC_WINDOW (f) =
12850 NewCWindow (NULL, &r, "\p", true, dBoxProc,
3354caee 12851 (WindowRef) -1, 1, (long) f->output_data.mac)))
b15325b2
ST
12852 abort ();
12853 /* so that update events can find this mac_output struct */
12854 f->output_data.mac->mFP = f; /* point back to emacs frame */
12855
12856 UNBLOCK_INPUT;
e0f712ba
AC
12857
12858 x_make_gc (f);
177c0ea7 12859
e0f712ba
AC
12860 /* Need to be initialized for unshow_buffer in window.c. */
12861 selected_window = f->selected_window;
12862
1a578e9b
AC
12863 Fmodify_frame_parameters (frame,
12864 Fcons (Fcons (Qfont,
12865 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12866 Fmodify_frame_parameters (frame,
12867 Fcons (Fcons (Qforeground_color,
12868 build_string ("black")), Qnil));
12869 Fmodify_frame_parameters (frame,
12870 Fcons (Fcons (Qbackground_color,
12871 build_string ("white")), Qnil));
12872}
b15325b2 12873#endif
1a578e9b 12874
e0f712ba
AC
12875\f
12876/***********************************************************************
12877 Initialization
12878 ***********************************************************************/
12879
19ee09cc 12880static int mac_initialized = 0;
b15325b2 12881
b298e813 12882static XrmDatabase
b15325b2 12883mac_make_rdb (xrm_option)
369a7a37 12884 const char *xrm_option;
b15325b2 12885{
b298e813 12886 XrmDatabase database;
b15325b2 12887
b298e813
YM
12888 database = xrm_get_preference_database (NULL);
12889 if (xrm_option)
12890 xrm_merge_string_database (database, xrm_option);
b15325b2 12891
b298e813 12892 return database;
b15325b2
ST
12893}
12894
e0f712ba
AC
12895struct mac_display_info *
12896mac_term_init (display_name, xrm_option, resource_name)
12897 Lisp_Object display_name;
12898 char *xrm_option;
12899 char *resource_name;
12900{
12901 struct mac_display_info *dpyinfo;
80ca7302 12902 struct terminal *terminal;
b15325b2
ST
12903
12904 BLOCK_INPUT;
e0f712ba
AC
12905
12906 if (!mac_initialized)
12907 {
12908 mac_initialize ();
12909 mac_initialized = 1;
12910 }
12911
b15325b2
ST
12912 if (x_display_list)
12913 error ("Sorry, this version can only handle one display");
12914
e0f712ba 12915 dpyinfo = &one_mac_display_info;
19ee09cc
YM
12916 bzero (dpyinfo, sizeof (*dpyinfo));
12917
80ca7302
DN
12918 terminal = mac_create_terminal (dpyinfo);
12919
12920 /* Set the name of the terminal. */
12921 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12922 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12923 terminal->name[SBYTES (display_name)] = 0;
12924
19ee09cc
YM
12925#ifdef MAC_OSX
12926 dpyinfo->mac_id_name
12927 = (char *) xmalloc (SCHARS (Vinvocation_name)
12928 + SCHARS (Vsystem_name)
12929 + 2);
12930 sprintf (dpyinfo->mac_id_name, "%s@%s",
12931 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12932#else
12933 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12934 strcpy (dpyinfo->mac_id_name, "Mac Display");
12935#endif
12936
12937 dpyinfo->reference_count = 0;
12938 dpyinfo->resx = 72.0;
12939 dpyinfo->resy = 72.0;
12940
12941 mac_get_screen_info (dpyinfo);
12942
12943 dpyinfo->grabbed = 0;
12944 dpyinfo->root_window = NULL;
354884c4 12945 dpyinfo->terminal->image_cache = make_image_cache ();
19ee09cc
YM
12946
12947 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12948 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12949 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12950 dpyinfo->mouse_face_window = Qnil;
12951 dpyinfo->mouse_face_overlay = Qnil;
12952 dpyinfo->mouse_face_hidden = 0;
e0f712ba 12953
b298e813 12954 dpyinfo->xrdb = mac_make_rdb (xrm_option);
e0f712ba 12955
b15325b2
ST
12956 /* Put this display on the chain. */
12957 dpyinfo->next = x_display_list;
12958 x_display_list = dpyinfo;
12959
12960 /* Put it on x_display_name_list. */
b298e813
YM
12961 x_display_name_list = Fcons (Fcons (display_name,
12962 Fcons (Qnil, dpyinfo->xrdb)),
b15325b2
ST
12963 x_display_name_list);
12964 dpyinfo->name_list_element = XCAR (x_display_name_list);
12965
b951420f
DN
12966 /* FIXME: Untested.
12967 Add the default keyboard. */
12968 add_keyboard_wait_descriptor (0);
12969
9c7c716d
JR
12970#if USE_CG_DRAWING
12971 mac_init_fringe (terminal->rif);
12972#endif
12973
b15325b2 12974 UNBLOCK_INPUT;
1a578e9b 12975
e0f712ba 12976 return dpyinfo;
1a578e9b 12977}
19ee09cc 12978\f
b15325b2
ST
12979/* Get rid of display DPYINFO, assuming all frames are already gone. */
12980
12981void
12982x_delete_display (dpyinfo)
12983 struct mac_display_info *dpyinfo;
12984{
12985 int i;
12986
12987 /* Discard this display from x_display_name_list and x_display_list.
12988 We can't use Fdelq because that can quit. */
12989 if (! NILP (x_display_name_list)
12990 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12991 x_display_name_list = XCDR (x_display_name_list);
12992 else
12993 {
12994 Lisp_Object tail;
12995
12996 tail = x_display_name_list;
12997 while (CONSP (tail) && CONSP (XCDR (tail)))
12998 {
12999 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
13000 {
13001 XSETCDR (tail, XCDR (XCDR (tail)));
13002 break;
13003 }
13004 tail = XCDR (tail);
13005 }
13006 }
13007
13008 if (x_display_list == dpyinfo)
13009 x_display_list = dpyinfo->next;
13010 else
13011 {
13012 struct x_display_info *tail;
13013
13014 for (tail = x_display_list; tail; tail = tail->next)
13015 if (tail->next == dpyinfo)
13016 tail->next = tail->next->next;
13017 }
13018
13019 /* Free the font names in the font table. */
13020 for (i = 0; i < dpyinfo->n_fonts; i++)
13021 if (dpyinfo->font_table[i].name)
13022 {
13023 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
13024 xfree (dpyinfo->font_table[i].full_name);
13025 xfree (dpyinfo->font_table[i].name);
13026 }
13027
1e53bd0e
YM
13028 if (dpyinfo->font_table)
13029 {
13030 if (dpyinfo->font_table->font_encoder)
13031 xfree (dpyinfo->font_table->font_encoder);
13032 xfree (dpyinfo->font_table);
13033 }
13034 if (dpyinfo->mac_id_name)
13035 xfree (dpyinfo->mac_id_name);
b15325b2
ST
13036
13037 if (x_display_list == 0)
13038 {
13039 mac_clear_font_name_table ();
13040 bzero (dpyinfo, sizeof (*dpyinfo));
13041 }
13042}
13043
e0f712ba 13044\f
1c05c15b
YM
13045static void
13046init_menu_bar ()
13047{
13048#ifdef MAC_OSX
3e7424f7 13049 OSStatus err;
1c05c15b
YM
13050 MenuRef menu;
13051 MenuItemIndex menu_index;
13052
13053 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
13054 &menu, &menu_index);
13055 if (err == noErr)
13056 SetMenuItemCommandKey (menu, menu_index, false, 0);
1c05c15b
YM
13057 EnableMenuCommand (NULL, kHICommandPreferences);
13058 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
13059 &menu, &menu_index);
13060 if (err == noErr)
13061 {
13062 SetMenuItemCommandKey (menu, menu_index, false, 0);
13063 InsertMenuItemTextWithCFString (menu, NULL,
13064 0, kMenuItemAttrSeparator, 0);
13065 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
13066 0, 0, kHICommandAbout);
13067 }
1c05c15b 13068#else /* !MAC_OSX */
3354caee
YM
13069#if TARGET_API_MAC_CARBON
13070 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
1c05c15b
YM
13071#endif
13072#endif
13073}
13074
02236cbc
YM
13075#if USE_MAC_TSM
13076static void
13077init_tsm ()
13078{
92289429 13079#ifdef MAC_OSX
02236cbc 13080 static InterfaceTypeList types = {kUnicodeDocument};
92289429
YM
13081#else
13082 static InterfaceTypeList types = {kTextService};
13083#endif
02236cbc
YM
13084
13085 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
13086 &tsm_document_id, 0);
13087}
13088#endif
1c05c15b 13089
e0f712ba
AC
13090/* Set up use of X before we make the first connection. */
13091
88cd462d
KS
13092extern frame_parm_handler mac_frame_parm_handlers[];
13093
e0f712ba
AC
13094static struct redisplay_interface x_redisplay_interface =
13095{
88cd462d 13096 mac_frame_parm_handlers,
e0f712ba
AC
13097 x_produce_glyphs,
13098 x_write_glyphs,
13099 x_insert_glyphs,
13100 x_clear_end_of_line,
13101 x_scroll_run,
13102 x_after_update_window_line,
13103 x_update_window_begin,
13104 x_update_window_end,
f9e65eb3
KS
13105 x_cursor_to,
13106 x_flush,
e6509087
YM
13107#if USE_CG_DRAWING
13108 mac_flush_display_optional,
13109#else
fc7a70cc 13110 0, /* flush_display_optional */
e6509087 13111#endif
f9e65eb3 13112 x_clear_window_mouse_face,
e0f712ba 13113 x_get_glyph_overhangs,
5958f265 13114 x_fix_overlapping_area,
750fc673 13115 x_draw_fringe_bitmap,
ad21830e
YM
13116#if USE_CG_DRAWING
13117 mac_define_fringe_bitmap,
13118 mac_destroy_fringe_bitmap,
13119#else
6b61353c
KH
13120 0, /* define_fringe_bitmap */
13121 0, /* destroy_fringe_bitmap */
ad21830e 13122#endif
750fc673
KS
13123 mac_per_char_metric,
13124 mac_encode_char,
8c2da0fa 13125 mac_compute_glyph_string_overhangs,
f9e65eb3
KS
13126 x_draw_glyph_string,
13127 mac_define_frame_cursor,
13128 mac_clear_frame_area,
13129 mac_draw_window_cursor,
efcf4234 13130 mac_draw_vertical_window_border,
f9e65eb3 13131 mac_shift_glyphs_for_insert
e0f712ba 13132};
1a578e9b 13133
80ca7302
DN
13134static struct terminal *
13135mac_create_terminal (struct mac_display_info *dpyinfo)
13136{
13137 struct terminal *terminal;
13138
13139 terminal = create_terminal ();
13140
13141 terminal->type = output_mac;
13142 terminal->display_info.mac = dpyinfo;
13143 dpyinfo->terminal = terminal;
13144
80ca7302
DN
13145 terminal->clear_frame_hook = x_clear_frame;
13146 terminal->ins_del_lines_hook = x_ins_del_lines;
13147 terminal->delete_glyphs_hook = x_delete_glyphs;
13148 terminal->ring_bell_hook = XTring_bell;
13149 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
13150 terminal->set_terminal_modes_hook = XTset_terminal_modes;
13151 terminal->update_begin_hook = x_update_begin;
13152 terminal->update_end_hook = x_update_end;
13153 terminal->set_terminal_window_hook = XTset_terminal_window;
13154 terminal->read_socket_hook = XTread_socket;
13155 terminal->frame_up_to_date_hook = XTframe_up_to_date;
13156 terminal->mouse_position_hook = XTmouse_position;
13157 terminal->frame_rehighlight_hook = XTframe_rehighlight;
13158 terminal->frame_raise_lower_hook = XTframe_raise_lower;
88acaaf2
DN
13159 /* terminal->fullscreen_hook = XTfullscreen_hook; */
13160 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13161 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13162 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
13163 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
13164 terminal->delete_frame_hook = x_destroy_window;
13165 /* terminal->delete_terminal_hook = x_delete_terminal; */
80ca7302 13166
88acaaf2 13167 terminal->rif = &x_redisplay_interface;
80ca7302 13168#if 0
28d440ab
KL
13169 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
13170 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
13171 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
13172 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
13173 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
8a56675d
KL
13174 scrolls off the
13175 bottom */
80ca7302
DN
13176#else
13177 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
13178 terminal->char_ins_del_ok = 1;
13179 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
13180 terminal->fast_clear_end_of_line = 1; /* X does this well. */
13181 terminal->memory_below_frame = 0; /* We don't remember what scrolls
13182 off the bottom. */
13183
70b8d0a4
SM
13184#endif
13185
13186 /* FIXME: This keyboard setup is 100% untested, just copied from
13187 w32_create_terminal in order to set window-system now that it's
13188 a keyboard object. */
70b8d0a4
SM
13189 /* We don't yet support separate terminals on Mac, so don't try to share
13190 keyboards between virtual terminals that are on the same physical
13191 terminal like X does. */
13192 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13193 init_kboard (terminal->kboard);
13194 terminal->kboard->Vwindow_system = intern ("mac");
13195 terminal->kboard->next_kboard = all_kboards;
13196 all_kboards = terminal->kboard;
13197 /* Don't let the initial kboard remain current longer than necessary.
13198 That would cause problems if a file loaded on startup tries to
13199 prompt in the mini-buffer. */
13200 if (current_kboard == initial_kboard)
13201 current_kboard = terminal->kboard;
13202 terminal->kboard->reference_count++;
9c7c716d 13203
80ca7302
DN
13204 return terminal;
13205}
13206
13207static void
e0f712ba 13208mac_initialize ()
1a578e9b 13209{
80ca7302 13210
1a578e9b
AC
13211 baud_rate = 19200;
13212
1a578e9b
AC
13213 last_tool_bar_item = -1;
13214 any_help_event_p = 0;
177c0ea7 13215
1a578e9b 13216 /* Try to use interrupt input; if we can't, then start polling. */
a712a8c3 13217 Fset_input_interrupt_mode (Qt);
1a578e9b 13218
c3f4c690 13219 BLOCK_INPUT;
bc21bf11
AC
13220
13221#if TARGET_API_MAC_CARBON
bc21bf11 13222
7adf3143 13223 install_application_handler ();
1c05c15b
YM
13224
13225 init_menu_bar ();
02236cbc
YM
13226
13227#if USE_MAC_TSM
13228 init_tsm ();
13229#endif
8030369c 13230
25c9622b 13231#ifdef MAC_OSX
0e0a1663
YM
13232 init_coercion_handler ();
13233
6a0b5d37
YM
13234 init_apple_event_handler ();
13235
19ee09cc
YM
13236 init_dm_notification_handler ();
13237
8030369c 13238 if (!inhibit_window_system)
5eafe967
YM
13239 {
13240 static const ProcessSerialNumber psn = {0, kCurrentProcess};
13241
13242 SetFrontProcess (&psn);
13243 }
25c9622b 13244#endif
bc21bf11 13245#endif
ad21830e
YM
13246
13247#if USE_CG_DRAWING
e2d3b7e1 13248 init_cg_color ();
ad21830e
YM
13249#endif
13250
c3f4c690 13251 UNBLOCK_INPUT;
80ca7302 13252
1a578e9b
AC
13253}
13254
13255
13256void
13257syms_of_macterm ()
13258{
13259#if 0
13260 staticpro (&x_error_message_string);
13261 x_error_message_string = Qnil;
13262#endif
13263
f2d8779b
YM
13264 Qcontrol = intern ("control"); staticpro (&Qcontrol);
13265 Qmeta = intern ("meta"); staticpro (&Qmeta);
13266 Qalt = intern ("alt"); staticpro (&Qalt);
13267 Qhyper = intern ("hyper"); staticpro (&Qhyper);
13268 Qsuper = intern ("super"); staticpro (&Qsuper);
a36f1680 13269 Qmodifier_value = intern ("modifier-value");
f2d8779b 13270 staticpro (&Qmodifier_value);
a36f1680 13271
f2d8779b
YM
13272 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
13273 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
13274 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
13275 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
13276 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
1c05c15b 13277
3354caee 13278#if TARGET_API_MAC_CARBON
3e7424f7 13279 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
6a0b5d37 13280#ifdef MAC_OSX
68c767a3
YM
13281 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
13282 staticpro (&Qtoolbar_switch_mode);
13283#if USE_MAC_FONT_PANEL
13284 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
13285 Qselection = intern ("selection"); staticpro (&Qselection);
13286#endif
13287
4cb62a90 13288 Qservice = intern ("service"); staticpro (&Qservice);
1c05c15b
YM
13289 Qpaste = intern ("paste"); staticpro (&Qpaste);
13290 Qperform = intern ("perform"); staticpro (&Qperform);
e1adb139
YM
13291
13292 Qmouse_drag_overlay = intern ("mouse-drag-overlay");
13293 staticpro (&Qmouse_drag_overlay);
1c05c15b 13294#endif
02236cbc
YM
13295#if USE_MAC_TSM
13296 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
13297 Qupdate_active_input_area = intern ("update-active-input-area");
13298 staticpro (&Qupdate_active_input_area);
13299 Qunicode_for_key_event = intern ("unicode-for-key-event");
13300 staticpro (&Qunicode_for_key_event);
13301#endif
6a0b5d37 13302#endif
1c05c15b 13303
b15325b2 13304#ifdef MAC_OSX
8c609cff 13305 Fprovide (intern ("mac-carbon"), Qnil);
b15325b2 13306#endif
8c609cff 13307
6b61353c
KH
13308 staticpro (&Qreverse);
13309 Qreverse = intern ("reverse");
13310
1a578e9b
AC
13311 staticpro (&x_display_name_list);
13312 x_display_name_list = Qnil;
13313
13314 staticpro (&last_mouse_scroll_bar);
13315 last_mouse_scroll_bar = Qnil;
13316
71b7a47f
YM
13317 staticpro (&fm_font_family_alist);
13318 fm_font_family_alist = Qnil;
8f47302e 13319
c3bd8190
YM
13320#if USE_ATSUI
13321 staticpro (&atsu_font_id_hash);
13322 atsu_font_id_hash = Qnil;
92289429
YM
13323
13324 staticpro (&fm_style_face_attributes_alist);
13325 fm_style_face_attributes_alist = Qnil;
13326#endif
13327
13328#if USE_MAC_TSM
13329 staticpro (&saved_ts_script_language_on_focus);
13330 saved_ts_script_language_on_focus = Qnil;
c3bd8190
YM
13331#endif
13332
70ed951a
YM
13333 /* We don't yet support this, but defining this here avoids whining
13334 from cus-start.el and other places, like "M-x set-variable". */
13335 DEFVAR_BOOL ("x-use-underline-position-properties",
13336 &x_use_underline_position_properties,
13337 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
17cf2c3e 13338A value of nil means ignore them. If you encounter fonts with bogus
70ed951a
YM
13339UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
13340to 4.1, set this to nil.
13341
13342NOTE: Not supported on Mac yet. */);
13343 x_use_underline_position_properties = 0;
13344
cf2c6835
YM
13345 DEFVAR_BOOL ("x-underline-at-descent-line",
13346 &x_underline_at_descent_line,
13347 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
17cf2c3e
JB
13348A value of nil means to draw the underline according to the value of the
13349variable `x-use-underline-position-properties', which is usually at the
13350baseline level. The default value is nil. */);
cf2c6835
YM
13351 x_underline_at_descent_line = 0;
13352
e0f712ba 13353 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
68c767a3 13354 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
5b8b73ff 13355#ifdef USE_TOOLKIT_SCROLL_BARS
e0f712ba 13356 Vx_toolkit_scroll_bars = Qt;
5b8b73ff
YM
13357#else
13358 Vx_toolkit_scroll_bars = Qnil;
13359#endif
e0f712ba 13360
1a578e9b
AC
13361 staticpro (&last_mouse_motion_frame);
13362 last_mouse_motion_frame = Qnil;
177c0ea7 13363
b02e3f7b 13364/* Variables to configure modifier key assignment. */
16805b2e 13365
b02e3f7b 13366 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
70ed951a
YM
13367 doc: /* *Modifier key assumed when the Mac control key is pressed.
13368The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13369respective modifier. The default is `control'. */);
13370 Vmac_control_modifier = Qcontrol;
1a578e9b 13371
a36f1680 13372 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
70ed951a
YM
13373 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13374The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13375respective modifier. If the value is nil then the key will act as the
13376normal Mac control modifier, and the option key can be used to compose
13377characters depending on the chosen Mac keyboard setting. */);
a36f1680
JW
13378 Vmac_option_modifier = Qnil;
13379
b02e3f7b 13380 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
70ed951a
YM
13381 doc: /* *Modifier key assumed when the Mac command key is pressed.
13382The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b 13383respective modifier. The default is `meta'. */);
b02e3f7b
ST
13384 Vmac_command_modifier = Qmeta;
13385
13386 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
70ed951a
YM
13387 doc: /* *Modifier key assumed when the Mac function key is pressed.
13388The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13389respective modifier. Note that remapping the function key may lead to
13390unexpected results for some keys on non-US/GB keyboards. */);
b02e3f7b 13391 Vmac_function_modifier = Qnil;
742fbed7 13392
ffe8b3f4 13393 DEFVAR_LISP ("mac-emulate-three-button-mouse",
6b61353c 13394 &Vmac_emulate_three_button_mouse,
70ed951a 13395 doc: /* *Specify a way of three button mouse emulation.
f2d8779b 13396The value can be nil, t, or the symbol `reverse'.
17cf2c3e
JB
13397A value of nil means that no emulation should be done and the modifiers
13398should be placed on the mouse-1 event.
f2d8779b
YM
13399t means that when the option-key is held down while pressing the mouse
13400button, the click will register as mouse-2 and while the command-key
13401is held down, the click will register as mouse-3.
13402The symbol `reverse' means that the option-key will register for
13403mouse-3 and the command-key will register for mouse-2. */);
6b61353c
KH
13404 Vmac_emulate_three_button_mouse = Qnil;
13405
3354caee 13406#if TARGET_API_MAC_CARBON
70ed951a 13407 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
68c767a3 13408 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
f2d8779b
YM
13409Otherwise, the right click will be treated as mouse-2 and the wheel
13410button will be mouse-3. */);
70ed951a 13411 mac_wheel_button_is_mouse_2 = 1;
5883787c 13412
70ed951a 13413 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
68c767a3 13414 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
70ed951a 13415 mac_pass_command_to_system = 1;
5883787c 13416
70ed951a 13417 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
68c767a3 13418 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
70ed951a 13419 mac_pass_control_to_system = 1;
743d0696 13420
742fbed7
AC
13421#endif
13422
70ed951a 13423 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
68c767a3 13424 doc: /* *If non-nil, allow anti-aliasing.
e24531b7
KS
13425The text will be rendered using Core Graphics text rendering which
13426may anti-alias the text. */);
458dbb8c
YM
13427#if USE_CG_DRAWING
13428 mac_use_core_graphics = 1;
13429#else
faef8681 13430 mac_use_core_graphics = 0;
458dbb8c 13431#endif
94d0e806
YM
13432
13433 /* Register an entry for `mac-roman' so that it can be used when
13434 creating the terminal frame on Mac OS 9 before loading
13435 term/mac-win.elc. */
13436 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
68c767a3 13437 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
94d0e806
YM
13438Each entry should be of the form:
13439
13440 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13441
13442where CHARSET-NAME is a string used in font names to identify the
f2d8779b
YM
13443charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13444CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
94d0e806
YM
13445 Vmac_charset_info_alist =
13446 Fcons (list3 (build_string ("mac-roman"),
13447 make_number (smRoman), Qnil), Qnil);
68c767a3 13448
02236cbc
YM
13449#if USE_MAC_TSM
13450 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13451 doc: /* Overlay used to display Mac TSM active input area. */);
13452 Vmac_ts_active_input_overlay = Qnil;
b4c51596 13453
e1adb139
YM
13454 DEFVAR_LISP ("mac-ts-active-input-buf", &Vmac_ts_active_input_buf,
13455 doc: /* Byte sequence of the current Mac TSM active input area. */);
13456 /* `empty_string' is not ready yet on Mac OS Classic. */
13457 Vmac_ts_active_input_buf = build_string ("");
13458
b4c51596
YM
13459 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13460 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13461If the value is t, the input script and language are restored to those
13462used in the last focus frame. If the value is a pair of integers, the
13463input script and language codes, which are defined in the Script
13464Manager, are set to its car and cdr parts, respectively. Otherwise,
13465Emacs doesn't set them and thus follows the system default behavior. */);
13466 Vmac_ts_script_language_on_focus = Qnil;
02236cbc 13467#endif
1a578e9b 13468}
6b61353c
KH
13469
13470/* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13471 (do not change this comment) */