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