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