(diary-file): Doc fix.
[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,
8cabe764 3 2005, 2006, 2007, 2008 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
1ec6ded9 5074 bar->redraw_needed_p = Qnil;
5b8b73ff
YM
5075#ifdef USE_TOOLKIT_SCROLL_BARS
5076 bar->track_top = Qnil;
5077 bar->track_height = Qnil;
4d5724e5 5078 bar->min_handle = Qnil;
5b8b73ff 5079#endif
1a578e9b
AC
5080
5081 /* Add bar to its frame's list of scroll bars. */
5082 bar->next = FRAME_SCROLL_BARS (f);
5083 bar->prev = Qnil;
5084 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5085 if (!NILP (bar->next))
5086 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
5087
5088 UNBLOCK_INPUT;
5089 return bar;
5090}
5091
5092
5093/* Draw BAR's handle in the proper position.
177c0ea7 5094
1a578e9b
AC
5095 If the handle is already drawn from START to END, don't bother
5096 redrawing it, unless REBUILD is non-zero; in that case, always
5097 redraw it. (REBUILD is handy for drawing the handle after expose
5098 events.)
5099
5100 Normally, we want to constrain the start and end of the handle to
5101 fit inside its rectangle, but if the user is dragging the scroll
5102 bar handle, we want to let them drag it down all the way, so that
5103 the bar's top is as far down as it goes; otherwise, there's no way
5104 to move to the very end of the buffer. */
5105
5b8b73ff
YM
5106#ifndef USE_TOOLKIT_SCROLL_BARS
5107
1a578e9b
AC
5108static void
5109x_scroll_bar_set_handle (bar, start, end, rebuild)
5110 struct scroll_bar *bar;
5111 int start, end;
5112 int rebuild;
5113{
5114 int dragging = ! NILP (bar->dragging);
3354caee 5115 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
1a578e9b 5116 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
e0f712ba
AC
5117 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5118 int length = end - start;
1a578e9b
AC
5119
5120 /* If the display is already accurate, do nothing. */
5121 if (! rebuild
5122 && start == XINT (bar->start)
5123 && end == XINT (bar->end))
5124 return;
5125
5126 BLOCK_INPUT;
5127
e0f712ba
AC
5128 /* Make sure the values are reasonable, and try to preserve the
5129 distance between start and end. */
5130 if (start < 0)
5131 start = 0;
5132 else if (start > top_range)
5133 start = top_range;
5134 end = start + length;
177c0ea7 5135
e0f712ba
AC
5136 if (end < start)
5137 end = start;
5138 else if (end > top_range && ! dragging)
5139 end = top_range;
5140
5141 /* Store the adjusted setting in the scroll bar. */
5142 XSETINT (bar->start, start);
5143 XSETINT (bar->end, end);
5144
5145 /* Clip the end position, just for display. */
5146 if (end > top_range)
5147 end = top_range;
5148
5149 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
5150 top positions, to make sure the handle is always at least that
5151 many pixels tall. */
5152 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
5153
5154 SetControlMinimum (ch, 0);
5155 /* Don't inadvertently activate deactivated scroll bars */
5156 if (GetControlMaximum (ch) != -1)
5157 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
5158 - (end - start));
5159 SetControlValue (ch, start);
5160#if TARGET_API_MAC_CARBON
5161 SetControlViewSize (ch, end - start);
1a578e9b 5162#endif
1a578e9b
AC
5163
5164 UNBLOCK_INPUT;
5165}
5166
5b8b73ff 5167#endif /* !USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5168
5169/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5170 nil. */
5171
5172static void
5173x_scroll_bar_remove (bar)
5174 struct scroll_bar *bar;
5175{
5176 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
e0f712ba 5177
1a578e9b
AC
5178 BLOCK_INPUT;
5179
4ea08bbf
YM
5180#if USE_CG_DRAWING
5181 mac_prepare_for_quickdraw (f);
5182#endif
1a578e9b 5183 /* Destroy the Mac scroll bar control */
3354caee 5184 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
1a578e9b
AC
5185
5186 /* Disassociate this scroll bar from its window. */
5187 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
5188
5189 UNBLOCK_INPUT;
5190}
5191
95dfb192 5192
1a578e9b
AC
5193/* Set the handle of the vertical scroll bar for WINDOW to indicate
5194 that we are displaying PORTION characters out of a total of WHOLE
5195 characters, starting at POSITION. If WINDOW has no scroll bar,
5196 create one. */
95dfb192 5197
1a578e9b
AC
5198static void
5199XTset_vertical_scroll_bar (w, portion, whole, position)
5200 struct window *w;
5201 int portion, whole, position;
5202{
5203 struct frame *f = XFRAME (w->frame);
5204 struct scroll_bar *bar;
5205 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
f1a83aab 5206 int window_y, window_height;
c6829f81
YM
5207#ifdef MAC_OSX
5208 int fringe_extended_p;
5209#endif
1a578e9b
AC
5210
5211 /* Get window dimensions. */
f1a83aab 5212 window_box (w, -1, 0, &window_y, 0, &window_height);
1a578e9b 5213 top = window_y;
f1a83aab 5214 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
1a578e9b
AC
5215 height = window_height;
5216
5217 /* Compute the left edge of the scroll bar area. */
f1a83aab 5218 left = WINDOW_SCROLL_BAR_AREA_X (w);
1a578e9b
AC
5219
5220 /* Compute the width of the scroll bar which might be less than
5221 the width of the area reserved for the scroll bar. */
f1a83aab
KS
5222 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5223 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
1a578e9b
AC
5224 else
5225 sb_width = width;
5226
5227 /* Compute the left edge of the scroll bar. */
f1a83aab 5228 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
c6829f81 5229 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
1a578e9b 5230 else
c6829f81 5231 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
177c0ea7 5232
1a578e9b
AC
5233 /* Adjustments according to Inside Macintosh to make it look nice */
5234 disp_top = top;
5235 disp_height = height;
a3510ffa 5236#ifdef MAC_OS8
1a578e9b
AC
5237 if (disp_top == 0)
5238 {
5239 disp_top = -1;
5240 disp_height++;
5241 }
f1a83aab 5242 else if (disp_top == FRAME_PIXEL_HEIGHT (f) - 16)
1a578e9b
AC
5243 {
5244 disp_top++;
5245 disp_height--;
5246 }
177c0ea7 5247
f1a83aab 5248 if (sb_left + sb_width == FRAME_PIXEL_WIDTH (f))
1a578e9b 5249 sb_left++;
a3510ffa 5250#endif
177c0ea7 5251
c6829f81
YM
5252#ifdef MAC_OSX
5253 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
5254 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
5255 && WINDOW_LEFT_FRINGE_WIDTH (w)
5256 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5257 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
5258 else
5259 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
5260 && WINDOW_RIGHT_FRINGE_WIDTH (w)
5261 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
5262 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
5263#endif
5264
1a578e9b
AC
5265 /* Does the scroll bar exist yet? */
5266 if (NILP (w->vertical_scroll_bar))
5267 {
5268 BLOCK_INPUT;
c6829f81
YM
5269#ifdef MAC_OSX
5270 if (fringe_extended_p)
5271 mac_clear_area (f, sb_left, top, sb_width, height);
5272 else
5273#endif
5274 mac_clear_area (f, left, top, width, height);
1a578e9b
AC
5275 UNBLOCK_INPUT;
5276 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
5277 disp_height);
5278 XSETVECTOR (w->vertical_scroll_bar, bar);
5279 }
5280 else
5281 {
5282 /* It may just need to be moved and resized. */
3354caee 5283 ControlRef ch;
177c0ea7 5284
1a578e9b 5285 bar = XSCROLL_BAR (w->vertical_scroll_bar);
3354caee 5286 ch = SCROLL_BAR_CONTROL_REF (bar);
1a578e9b
AC
5287
5288 BLOCK_INPUT;
5289
5290 /* If already correctly positioned, do nothing. */
1ec6ded9
YM
5291 if (XINT (bar->left) == sb_left
5292 && XINT (bar->top) == top
5293 && XINT (bar->width) == sb_width
1bad168e 5294 && XINT (bar->height) == height
c6829f81 5295#ifdef MAC_OSX
1bad168e 5296 && !NILP (bar->fringe_extended_p) == fringe_extended_p
c6829f81 5297#endif
1bad168e 5298 )
1ec6ded9
YM
5299 {
5300 if (!NILP (bar->redraw_needed_p))
5301 {
5302#if USE_CG_DRAWING
5303 mac_prepare_for_quickdraw (f);
5304#endif
8b329dba 5305 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
1ec6ded9
YM
5306 }
5307 }
5308 else
e6bdfa32 5309 {
e4f5e019
YM
5310 /* Since toolkit scroll bars are smaller than the space reserved
5311 for them on the frame, we have to clear "under" them. */
c6829f81
YM
5312#ifdef MAC_OSX
5313 if (fringe_extended_p)
5314 mac_clear_area (f, sb_left, top, sb_width, height);
5315 else
5316#endif
5317 mac_clear_area (f, left, top, width, height);
1a578e9b 5318
4ea08bbf
YM
5319#if USE_CG_DRAWING
5320 mac_prepare_for_quickdraw (f);
5321#endif
1a578e9b
AC
5322 HideControl (ch);
5323 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
5324 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5325 disp_height);
a3510ffa 5326#ifndef USE_TOOLKIT_SCROLL_BARS
95dfb192
YM
5327 if (sb_width < disp_height)
5328 ShowControl (ch);
a3510ffa 5329#endif
177c0ea7 5330
1a578e9b
AC
5331 /* Remember new settings. */
5332 XSETINT (bar->left, sb_left);
5333 XSETINT (bar->top, top);
5334 XSETINT (bar->width, sb_width);
5335 XSETINT (bar->height, height);
5b8b73ff
YM
5336#ifdef USE_TOOLKIT_SCROLL_BARS
5337 bar->track_top = Qnil;
5338 bar->track_height = Qnil;
4d5724e5 5339 bar->min_handle = Qnil;
5b8b73ff 5340#endif
1a578e9b
AC
5341 }
5342
5343 UNBLOCK_INPUT;
5344 }
5345
c6829f81
YM
5346#ifdef MAC_OSX
5347 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
5348#endif
5349
1ec6ded9
YM
5350 bar->redraw_needed_p = Qnil;
5351
5b8b73ff
YM
5352#ifdef USE_TOOLKIT_SCROLL_BARS
5353 if (NILP (bar->track_top))
f93e4d4f 5354 {
7a844a76
YM
5355 if (sb_width >= disp_height
5356#ifdef MAC_OSX
5357 || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
5358#endif
5359 )
f93e4d4f
YM
5360 {
5361 XSETINT (bar->track_top, 0);
5362 XSETINT (bar->track_height, 0);
4d5724e5 5363 XSETINT (bar->min_handle, 0);
f93e4d4f
YM
5364 }
5365 else
5366 {
3354caee 5367 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
f93e4d4f 5368 Rect r0, r1;
5b8b73ff 5369
f93e4d4f 5370 BLOCK_INPUT;
5b8b73ff 5371
f93e4d4f 5372 SetControl32BitMinimum (ch, 0);
4d5724e5 5373 SetControl32BitMaximum (ch, 1 << 30);
f93e4d4f 5374 SetControlViewSize (ch, 1);
5b8b73ff 5375
f93e4d4f
YM
5376 /* Move the scroll bar thumb to the top. */
5377 SetControl32BitValue (ch, 0);
5378 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
5b8b73ff 5379
f93e4d4f 5380 /* Move the scroll bar thumb to the bottom. */
4d5724e5 5381 SetControl32BitValue (ch, 1 << 30);
f93e4d4f 5382 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
5b8b73ff 5383
f93e4d4f
YM
5384 UnionRect (&r0, &r1, &r0);
5385 XSETINT (bar->track_top, r0.top);
5386 XSETINT (bar->track_height, r0.bottom - r0.top);
4d5724e5 5387 XSETINT (bar->min_handle, r1.bottom - r1.top);
5b8b73ff 5388
f93e4d4f
YM
5389 /* Don't show the scroll bar if its height is not enough to
5390 display the scroll bar thumb. */
5391 if (r0.bottom - r0.top > 0)
5392 ShowControl (ch);
a3510ffa 5393
f93e4d4f
YM
5394 UNBLOCK_INPUT;
5395 }
5396 }
5b8b73ff
YM
5397
5398 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5399#else /* not USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5400 /* Set the scroll bar's current state, unless we're currently being
5401 dragged. */
5402 if (NILP (bar->dragging))
5403 {
5404 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
5405
5406 if (whole == 0)
5407 x_scroll_bar_set_handle (bar, 0, top_range, 0);
5408 else
5409 {
5410 int start = ((double) position * top_range) / whole;
5411 int end = ((double) (position + portion) * top_range) / whole;
5412 x_scroll_bar_set_handle (bar, start, end, 0);
5413 }
5414 }
5b8b73ff 5415#endif /* not USE_TOOLKIT_SCROLL_BARS */
1a578e9b
AC
5416}
5417
5418
5419/* The following three hooks are used when we're doing a thorough
5420 redisplay of the frame. We don't explicitly know which scroll bars
5421 are going to be deleted, because keeping track of when windows go
5422 away is a real pain - "Can you say set-window-configuration, boys
5423 and girls?" Instead, we just assert at the beginning of redisplay
5424 that *all* scroll bars are to be removed, and then save a scroll bar
5425 from the fiery pit when we actually redisplay its window. */
5426
5427/* Arrange for all scroll bars on FRAME to be removed at the next call
5428 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
5429 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5430
5431static void
5432XTcondemn_scroll_bars (frame)
5433 FRAME_PTR frame;
5434{
5435 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5436 while (! NILP (FRAME_SCROLL_BARS (frame)))
5437 {
5438 Lisp_Object bar;
5439 bar = FRAME_SCROLL_BARS (frame);
5440 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5441 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5442 XSCROLL_BAR (bar)->prev = Qnil;
5443 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5444 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5445 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5446 }
5447}
5448
e0f712ba 5449
1a578e9b
AC
5450/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
5451 Note that WINDOW isn't necessarily condemned at all. */
e0f712ba 5452
1a578e9b
AC
5453static void
5454XTredeem_scroll_bar (window)
5455 struct window *window;
5456{
5457 struct scroll_bar *bar;
95dfb192 5458 struct frame *f;
1a578e9b
AC
5459
5460 /* We can't redeem this window's scroll bar if it doesn't have one. */
5461 if (NILP (window->vertical_scroll_bar))
5462 abort ();
5463
5464 bar = XSCROLL_BAR (window->vertical_scroll_bar);
5465
5466 /* Unlink it from the condemned list. */
95dfb192
YM
5467 f = XFRAME (WINDOW_FRAME (window));
5468 if (NILP (bar->prev))
5469 {
5470 /* If the prev pointer is nil, it must be the first in one of
5471 the lists. */
5472 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5473 /* It's not condemned. Everything's fine. */
5474 return;
5475 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5476 window->vertical_scroll_bar))
5477 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5478 else
5479 /* If its prev pointer is nil, it must be at the front of
5480 one or the other! */
5481 abort ();
5482 }
5483 else
5484 XSCROLL_BAR (bar->prev)->next = bar->next;
1a578e9b 5485
95dfb192
YM
5486 if (! NILP (bar->next))
5487 XSCROLL_BAR (bar->next)->prev = bar->prev;
1a578e9b 5488
95dfb192
YM
5489 bar->next = FRAME_SCROLL_BARS (f);
5490 bar->prev = Qnil;
5491 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5492 if (! NILP (bar->next))
5493 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
1a578e9b
AC
5494}
5495
5496/* Remove all scroll bars on FRAME that haven't been saved since the
5497 last call to `*condemn_scroll_bars_hook'. */
5498
5499static void
5500XTjudge_scroll_bars (f)
5501 FRAME_PTR f;
5502{
5503 Lisp_Object bar, next;
5504
5505 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
5506
5507 /* Clear out the condemned list now so we won't try to process any
5508 more events on the hapless scroll bars. */
5509 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
5510
5511 for (; ! NILP (bar); bar = next)
5512 {
5513 struct scroll_bar *b = XSCROLL_BAR (bar);
5514
5515 x_scroll_bar_remove (b);
5516
5517 next = b->next;
5518 b->next = b->prev = Qnil;
5519 }
5520
5521 /* Now there should be no references to the condemned scroll bars,
5522 and they should get garbage-collected. */
5523}
5524
5525
1a578e9b 5526/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3b8f9651 5527 is set to something other than NO_EVENT, it is enqueued.
1a578e9b
AC
5528
5529 This may be called from a signal handler, so we have to ignore GC
5530 mark bits. */
5531
5532static void
5533x_scroll_bar_handle_click (bar, part_code, er, bufp)
5534 struct scroll_bar *bar;
e6bdfa32 5535 ControlPartCode part_code;
369a7a37 5536 const EventRecord *er;
1a578e9b
AC
5537 struct input_event *bufp;
5538{
50bf7673
ST
5539 int win_y, top_range;
5540
8e50cc2d 5541 if (! WINDOWP (bar->window))
1a578e9b
AC
5542 abort ();
5543
3b8f9651 5544 bufp->kind = SCROLL_BAR_CLICK_EVENT;
1a578e9b
AC
5545 bufp->frame_or_window = bar->window;
5546 bufp->arg = Qnil;
5547
5548 bar->dragging = Qnil;
177c0ea7 5549
1a578e9b
AC
5550 switch (part_code)
5551 {
5552 case kControlUpButtonPart:
5553 bufp->part = scroll_bar_up_arrow;
5554 break;
5555 case kControlDownButtonPart:
5556 bufp->part = scroll_bar_down_arrow;
5557 break;
5558 case kControlPageUpPart:
5559 bufp->part = scroll_bar_above_handle;
5560 break;
5561 case kControlPageDownPart:
5562 bufp->part = scroll_bar_below_handle;
5563 break;
b15325b2 5564#if TARGET_API_MAC_CARBON
e0f712ba
AC
5565 default:
5566#else
1a578e9b 5567 case kControlIndicatorPart:
e0f712ba 5568#endif
1a578e9b
AC
5569 if (er->what == mouseDown)
5570 bar->dragging = make_number (0);
5571 XSETVECTOR (last_mouse_scroll_bar, bar);
5572 bufp->part = scroll_bar_handle;
5573 break;
5574 }
50bf7673
ST
5575
5576 win_y = XINT (bufp->y) - XINT (bar->top);
5577 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
5578
5579 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5580
5581 win_y -= 24;
5582
5583 if (! NILP (bar->dragging))
5584 win_y -= XINT (bar->dragging);
5585
5586 if (win_y < 0)
5587 win_y = 0;
5588 if (win_y > top_range)
5589 win_y = top_range;
5590
5591 XSETINT (bufp->x, win_y);
5592 XSETINT (bufp->y, top_range);
1a578e9b
AC
5593}
5594
5b8b73ff 5595#ifndef USE_TOOLKIT_SCROLL_BARS
1a578e9b
AC
5596
5597/* Handle some mouse motion while someone is dragging the scroll bar.
5598
5599 This may be called from a signal handler, so we have to ignore GC
5600 mark bits. */
5601
5602static void
5603x_scroll_bar_note_movement (bar, y_pos, t)
5604 struct scroll_bar *bar;
5605 int y_pos;
5606 Time t;
5607{
5608 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5609
5610 last_mouse_movement_time = t;
5611
5612 f->mouse_moved = 1;
5613 XSETVECTOR (last_mouse_scroll_bar, bar);
5614
5615 /* If we're dragging the bar, display it. */
8e50cc2d 5616 if (! NILP (bar->dragging))
1a578e9b
AC
5617 {
5618 /* Where should the handle be now? */
5619 int new_start = y_pos - 24;
5620
5621 if (new_start != XINT (bar->start))
5622 {
5623 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
5624
5625 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
5626 }
5627 }
5628}
5629
5b8b73ff 5630#endif /* !USE_TOOLKIT_SCROLL_BARS */
1a578e9b 5631
95dfb192
YM
5632/* Return information to the user about the current position of the mouse
5633 on the scroll bar. */
1a578e9b
AC
5634
5635static void
5636x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5637 FRAME_PTR *fp;
5638 Lisp_Object *bar_window;
5639 enum scroll_bar_part *part;
5640 Lisp_Object *x, *y;
5641 unsigned long *time;
5642{
5643 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
3354caee 5644 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
7ca7ccd5 5645#if TARGET_API_MAC_CARBON
3354caee 5646 WindowRef wp = GetControlOwner (ch);
7ca7ccd5 5647#else
3354caee 5648 WindowRef wp = (*ch)->contrlOwner;
7ca7ccd5 5649#endif
1a578e9b 5650 Point mouse_pos;
50bf7673 5651 struct frame *f = mac_window_to_frame (wp);
1a578e9b
AC
5652 int win_y, top_range;
5653
7adf3143
YM
5654#if TARGET_API_MAC_CARBON
5655 GetGlobalMouse (&mouse_pos);
5656 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
5657 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5658#else
50bf7673 5659 SetPortWindowPort (wp);
1a578e9b 5660 GetMouse (&mouse_pos);
7adf3143 5661#endif
1a578e9b
AC
5662
5663 win_y = mouse_pos.v - XINT (bar->top);
5664 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
5665
5666 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5667
5668 win_y -= 24;
5669
5670 if (! NILP (bar->dragging))
5671 win_y -= XINT (bar->dragging);
5672
5673 if (win_y < 0)
5674 win_y = 0;
5675 if (win_y > top_range)
5676 win_y = top_range;
5677
5678 *fp = f;
5679 *bar_window = bar->window;
5680
5681 if (! NILP (bar->dragging))
5682 *part = scroll_bar_handle;
5683 else if (win_y < XINT (bar->start))
5684 *part = scroll_bar_above_handle;
5685 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5686 *part = scroll_bar_handle;
5687 else
5688 *part = scroll_bar_below_handle;
5689
5690 XSETINT (*x, win_y);
5691 XSETINT (*y, top_range);
5692
5693 f->mouse_moved = 0;
5694 last_mouse_scroll_bar = Qnil;
5695
5696 *time = last_mouse_movement_time;
5697}
e6bdfa32
YM
5698
5699
5700/* The screen has been cleared so we may have changed foreground or
5701 background colors, and the scroll bars may need to be redrawn.
5702 Clear out the scroll bars, and ask for expose events, so we can
5703 redraw them. */
5704
5705void
5706x_scroll_bar_clear (f)
5707 FRAME_PTR f;
5708{
1ec6ded9
YM
5709 Lisp_Object bar;
5710
5711 /* We can have scroll bars even if this is 0,
5712 if we just turned off scroll bar mode.
5713 But in that case we should not clear them. */
5714 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5715 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5716 bar = XSCROLL_BAR (bar)->next)
5717 XSCROLL_BAR (bar)->redraw_needed_p = Qt;
e6bdfa32
YM
5718}
5719
1a578e9b 5720\f
c6829f81
YM
5721/***********************************************************************
5722 Tool-bars
5723 ***********************************************************************/
5724#if USE_MAC_TOOLBAR
5725
5726/* In identifiers such as function/variable names, Emacs tool bar is
5727 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
5728
5729#define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
5730#define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
5731
5732#define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
5733#define TOOLBAR_ITEM_COMMAND_ID_P(id) \
5734 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5735#define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
5736 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5737#define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
5738 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
5739
5740static int mac_event_to_emacs_modifiers P_ ((EventRef));
5741static void mac_handle_origin_change P_ ((struct frame *));
5742static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
5743 EventRef, void *));
5744
5745static void
5746mac_move_window_with_gravity (f, win_gravity, left, top)
5747 struct frame *f;
5748 int win_gravity;
5749 short left, top;
5750{
5751 Rect inner, outer;
5752
5753 mac_get_window_bounds (f, &inner, &outer);
5754
5755 switch (win_gravity)
5756 {
5757 case NorthWestGravity:
5758 case WestGravity:
5759 case SouthWestGravity:
5760 left += inner.left - outer.left;
5761 break;
5762
5763 case NorthGravity:
5764 case CenterGravity:
5765 case SouthGravity:
5766 left += ((inner.left - outer.left) + (inner.right - outer.right)) / 2;
5767 break;
5768
5769 case NorthEastGravity:
5770 case EastGravity:
5771 case SouthEastGravity:
5772 left += inner.right - outer.right;
5773 break;
5774 }
5775
5776 switch (win_gravity)
5777 {
5778 case NorthWestGravity:
5779 case NorthGravity:
5780 case NorthEastGravity:
5781 top += inner.top - outer.top;
5782 break;
5783
5784 case WestGravity:
5785 case CenterGravity:
5786 case EastGravity:
5787 top += ((inner.top - outer.top) + (inner.bottom - outer.bottom)) / 2;
5788 break;
5789
5790 case SouthWestGravity:
5791 case SouthGravity:
5792 case SouthEastGravity:
5793 top += inner.bottom - outer.bottom;
5794 break;
5795 }
5796
5797 MoveWindow (FRAME_MAC_WINDOW (f), left, top, false);
5798}
5799
5800static void
5801mac_get_window_origin_with_gravity (f, win_gravity, left, top)
5802 struct frame *f;
5803 int win_gravity;
5804 short *left, *top;
5805{
5806 Rect inner, outer;
5807
5808 mac_get_window_bounds (f, &inner, &outer);
5809
5810 switch (win_gravity)
5811 {
5812 case NorthWestGravity:
5813 case WestGravity:
5814 case SouthWestGravity:
5815 *left = outer.left;
5816 break;
5817
5818 case NorthGravity:
5819 case CenterGravity:
5820 case SouthGravity:
5821 *left = outer.left + ((outer.right - outer.left)
5822 - (inner.right - inner.left)) / 2;
5823 break;
5824
5825 case NorthEastGravity:
5826 case EastGravity:
5827 case SouthEastGravity:
5828 *left = outer.right - (inner.right - inner.left);
5829 break;
5830 }
5831
5832 switch (win_gravity)
5833 {
5834 case NorthWestGravity:
5835 case NorthGravity:
5836 case NorthEastGravity:
5837 *top = outer.top;
5838 break;
5839
5840 case WestGravity:
5841 case CenterGravity:
5842 case EastGravity:
5843 *top = outer.top + ((outer.bottom - outer.top)
5844 - (inner.bottom - inner.top)) / 2;
5845 break;
5846
5847 case SouthWestGravity:
5848 case SouthGravity:
5849 case SouthEastGravity:
5850 *top = outer.bottom - (inner.bottom - inner.top);
5851 break;
5852 }
5853}
5854
5855static OSStatus
5856mac_handle_toolbar_event (next_handler, event, data)
5857 EventHandlerCallRef next_handler;
5858 EventRef event;
5859 void *data;
5860{
5861 OSStatus err, result = eventNotHandledErr;
5862
5863 switch (GetEventKind (event))
5864 {
5865 case kEventToolbarGetDefaultIdentifiers:
5866 result = noErr;
5867 break;
5868
5869 case kEventToolbarGetAllowedIdentifiers:
5870 {
5871 CFMutableArrayRef array;
5872
5873 GetEventParameter (event, kEventParamMutableArray,
5874 typeCFMutableArrayRef, NULL,
5875 sizeof (CFMutableArrayRef), NULL, &array);
5876 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
5877 result = noErr;
5878 }
5879 break;
5880
5881 case kEventToolbarCreateItemWithIdentifier:
5882 {
5883 CFStringRef identifier;
5884 HIToolbarItemRef item = NULL;
5885
5886 GetEventParameter (event, kEventParamToolbarItemIdentifier,
5887 typeCFStringRef, NULL,
5888 sizeof (CFStringRef), NULL, &identifier);
5889
5890 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
5891 == kCFCompareEqualTo)
5892 HIToolbarItemCreate (identifier,
5893 kHIToolbarItemAllowDuplicates
5894 | kHIToolbarItemCantBeRemoved, &item);
5895
5896 if (item)
5897 {
5898 SetEventParameter (event, kEventParamToolbarItem,
5899 typeHIToolbarItemRef,
5900 sizeof (HIToolbarItemRef), &item);
5901 result = noErr;
5902 }
5903 }
5904 break;
5905
5906 default:
5907 abort ();
5908 }
5909
5910 return result;
5911}
5912
5913static CGImageRef
5914mac_image_spec_to_cg_image (f, image)
5915 struct frame *f;
5916 Lisp_Object image;
5917{
5918 if (!valid_image_p (image))
5919 return NULL;
5920 else
5921 {
5922 int img_id = lookup_image (f, image);
5923 struct image *img = IMAGE_FROM_ID (f, img_id);
5924
5925 prepare_image_for_display (f, img);
5926
5927 return img->data.ptr_val;
5928 }
5929}
5930
5931/* Create a tool bar for frame F. */
5932
5933static OSStatus
5934mac_create_frame_tool_bar (f)
5935 FRAME_PTR f;
5936{
5937 OSStatus err;
5938 HIToolbarRef toolbar;
5939
5940 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
5941 &toolbar);
5942 if (err == noErr)
5943 {
5944 static const EventTypeSpec specs[] =
5945 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
5946 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
5947 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
5948
5949 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
5950 mac_handle_toolbar_event,
5951 GetEventTypeCount (specs), specs,
5952 f, NULL);
5953 }
5954
5955 if (err == noErr)
5956 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
5957 if (err == noErr)
5958 {
5959 static const EventTypeSpec specs[] =
5960 {{kEventClassCommand, kEventCommandProcess}};
5961
5962 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
5963 mac_handle_toolbar_command_event,
5964 GetEventTypeCount (specs),
5965 specs, f, NULL);
5966 }
5967 if (err == noErr)
5968 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
5969
5970 if (toolbar)
5971 CFRelease (toolbar);
5972
5973 return err;
5974}
5975
5976/* Update the tool bar for frame F. Add new buttons and remove old. */
5977
5978void
5979update_frame_tool_bar (f)
5980 FRAME_PTR f;
5981{
5982 HIToolbarRef toolbar = NULL;
5983 short left, top;
5984 CFArrayRef old_items = NULL;
5985 CFIndex old_count;
5986 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
5987 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
5988
5989 BLOCK_INPUT;
5990
5991 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
5992 if (toolbar == NULL)
5993 {
5994 mac_create_frame_tool_bar (f);
5995 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
5996 if (toolbar == NULL)
5997 goto out;
5998 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
5999 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
6000 }
6001
6002 HIToolbarCopyItems (toolbar, &old_items);
6003 if (old_items == NULL)
6004 goto out;
6005
6006 old_count = CFArrayGetCount (old_items);
6007 pos = 0;
6008 for (i = 0; i < f->n_tool_bar_items; ++i)
6009 {
6010#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
6011
6012 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
6013 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
6014 int idx;
6015 Lisp_Object image;
6016 CGImageRef cg_image;
6017 CFStringRef label;
6018 HIToolbarItemRef item;
6019
6020 /* If image is a vector, choose the image according to the
6021 button state. */
6022 image = PROP (TOOL_BAR_ITEM_IMAGES);
6023 if (VECTORP (image))
6024 {
6025 if (enabled_p)
6026 idx = (selected_p
6027 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
6028 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
6029 else
6030 idx = (selected_p
6031 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
6032 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
6033
6034 xassert (ASIZE (image) >= idx);
6035 image = AREF (image, idx);
6036 }
6037 else
6038 idx = -1;
6039
6040 cg_image = mac_image_spec_to_cg_image (f, image);
6041 /* Ignore invalid image specifications. */
6042 if (cg_image == NULL)
6043 continue;
6044
6045 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
6046 if (label == NULL)
6047 label = CFSTR ("");
6048
6049 if (pos < old_count)
6050 {
6051 CGImageRef old_cg_image = NULL;
6052 CFStringRef old_label = NULL;
6053 Boolean old_enabled_p;
6054
6055 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
6056
6057 HIToolbarItemCopyImage (item, &old_cg_image);
6058 if (cg_image != old_cg_image)
6059 HIToolbarItemSetImage (item, cg_image);
6060 CGImageRelease (old_cg_image);
6061
6062 HIToolbarItemCopyLabel (item, &old_label);
6063 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
6064 HIToolbarItemSetLabel (item, label);
6065 CFRelease (old_label);
6066
6067 old_enabled_p = HIToolbarItemIsEnabled (item);
6068 if ((enabled_p || idx >= 0) != old_enabled_p)
6069 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6070 }
6071 else
6072 {
6073 item = NULL;
6074 HIToolbarCreateItemWithIdentifier (toolbar,
6075 TOOLBAR_ICON_ITEM_IDENTIFIER,
6076 NULL, &item);
6077 if (item)
6078 {
6079 HIToolbarItemSetImage (item, cg_image);
6080 HIToolbarItemSetLabel (item, label);
6081 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
6082 HIToolbarAppendItem (toolbar, item);
6083 CFRelease (item);
6084 }
6085 }
6086
6087 CFRelease (label);
6088 if (item)
6089 {
6090 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
6091 pos++;
6092 }
6093 }
6094
6095 CFRelease (old_items);
6096
6097 while (pos < old_count)
6098 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
6099
6100 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
6101 !win_gravity && f == mac_focus_frame (dpyinfo));
6102 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
6103 toolbar visibility change. */
6104 mac_handle_origin_change (f);
6105 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
6106 {
6107 mac_move_window_with_gravity (f, win_gravity, left, top);
6108 /* If the title bar is completely outside the screen, adjust the
6109 position. */
6110 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6111 kWindowConstrainMoveRegardlessOfFit
6112 | kWindowConstrainAllowPartial, NULL, NULL);
6113 f->output_data.mac->toolbar_win_gravity = 0;
6114 }
6115
6116 out:
6117 UNBLOCK_INPUT;
6118}
6119
6120/* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
6121 doesn't deallocate the resources. */
6122
6123void
6124free_frame_tool_bar (f)
6125 FRAME_PTR f;
6126{
6127 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
6128 {
6129 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6130
6131 BLOCK_INPUT;
6132 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
7b7d07bb
YM
6133 (NILP (Fsymbol_value
6134 (intern ("frame-notice-user-settings")))
6135 && f == mac_focus_frame (dpyinfo)));
c6829f81
YM
6136 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
6137 on toolbar visibility change. */
6138 mac_handle_origin_change (f);
6139 UNBLOCK_INPUT;
6140 }
6141}
6142
6143static void
6144mac_tool_bar_note_mouse_movement (f, event)
6145 struct frame *f;
6146 EventRef event;
6147{
6148 OSStatus err;
6149 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6150 int mouse_down_p;
6151 HIViewRef item_view;
6152 UInt32 command_id;
6153
6154 mouse_down_p = (dpyinfo->grabbed
6155 && f == last_mouse_frame
6156 && FRAME_LIVE_P (f));
6157 if (mouse_down_p)
6158 return;
6159
6160 err = HIViewGetViewForMouseEvent (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6161 event, &item_view);
6162 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
6163 toolbar item view seems to have the same command ID with that of
6164 the toolbar item. */
6165 if (err == noErr)
6166 err = GetControlCommandID (item_view, &command_id);
6167 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
6168 {
6169 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
6170
6171 if (i < f->n_tool_bar_items)
6172 {
6173 HIRect bounds;
6174 HIViewRef content_view;
6175
6176 err = HIViewGetBounds (item_view, &bounds);
6177 if (err == noErr)
6178 err = HIViewFindByID (HIViewGetRoot (FRAME_MAC_WINDOW (f)),
6179 kHIViewWindowContentID, &content_view);
6180 if (err == noErr)
6181 err = HIViewConvertRect (&bounds, item_view, content_view);
6182 if (err == noErr)
6183 SetRect (&last_mouse_glyph,
6184 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
6185 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
6186
6187 help_echo_object = help_echo_window = Qnil;
6188 help_echo_pos = -1;
6189 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
6190 if (NILP (help_echo_string))
6191 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
6192 }
6193 }
6194}
6195
6196static OSStatus
6197mac_handle_toolbar_command_event (next_handler, event, data)
6198 EventHandlerCallRef next_handler;
6199 EventRef event;
6200 void *data;
6201{
6202 OSStatus err, result = eventNotHandledErr;
6203 struct frame *f = (struct frame *) data;
6204 HICommand command;
6205
6206 err = GetEventParameter (event, kEventParamDirectObject,
6207 typeHICommand, NULL,
6208 sizeof (HICommand), NULL, &command);
6209 if (err != noErr)
6210 return result;
6211
6212 switch (GetEventKind (event))
6213 {
6214 case kEventCommandProcess:
6215 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
6216 result = CallNextEventHandler (next_handler, event);
6217 else
6218 {
6219 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
6220
6221 if (i < f->n_tool_bar_items
6222 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
6223 {
6224 Lisp_Object frame;
6225 struct input_event buf;
6226
6227 EVENT_INIT (buf);
6228
6229 XSETFRAME (frame, f);
6230 buf.kind = TOOL_BAR_EVENT;
6231 buf.frame_or_window = frame;
6232 buf.arg = frame;
6233 kbd_buffer_store_event (&buf);
6234
6235 buf.kind = TOOL_BAR_EVENT;
6236 buf.frame_or_window = frame;
6237 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
6238 buf.modifiers = mac_event_to_emacs_modifiers (event);
6239 kbd_buffer_store_event (&buf);
6240
6241 result = noErr;
6242 }
6243 }
6244 break;
6245
6246 default:
6247 abort ();
6248 }
6249#undef PROP
6250
6251 return result;
6252}
6253#endif /* USE_MAC_TOOLBAR */
6254
6255\f
1a578e9b
AC
6256/***********************************************************************
6257 Text Cursor
6258 ***********************************************************************/
6259
1a578e9b
AC
6260/* Set clipping for output in glyph row ROW. W is the window in which
6261 we operate. GC is the graphics context to set clipping in.
1a578e9b
AC
6262
6263 ROW may be a text row or, e.g., a mode line. Text rows must be
6264 clipped to the interior of the window dedicated to text display,
6265 mode lines must be clipped to the whole window. */
6266
6267static void
08f66682 6268x_clip_to_row (w, row, area, gc)
1a578e9b
AC
6269 struct window *w;
6270 struct glyph_row *row;
08f66682 6271 int area;
1a578e9b 6272 GC gc;
1a578e9b
AC
6273{
6274 struct frame *f = XFRAME (WINDOW_FRAME (w));
6275 Rect clip_rect;
08f66682 6276 int window_x, window_y, window_width;
1a578e9b 6277
08f66682 6278 window_box (w, area, &window_x, &window_y, &window_width, 0);
1a578e9b 6279
08f66682 6280 clip_rect.left = window_x;
1a578e9b
AC
6281 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
6282 clip_rect.top = max (clip_rect.top, window_y);
6283 clip_rect.right = clip_rect.left + window_width;
6284 clip_rect.bottom = clip_rect.top + row->visible_height;
6285
1c4ac540 6286 mac_set_clip_rectangles (FRAME_MAC_DISPLAY (f), gc, &clip_rect, 1);
1a578e9b
AC
6287}
6288
6289
6290/* Draw a hollow box cursor on window W in glyph row ROW. */
6291
6292static void
6293x_draw_hollow_cursor (w, row)
6294 struct window *w;
6295 struct glyph_row *row;
6296{
6297 struct frame *f = XFRAME (WINDOW_FRAME (w));
6298 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6299 Display *dpy = FRAME_MAC_DISPLAY (f);
6300 int x, y, wd, h;
6301 XGCValues xgcv;
6302 struct glyph *cursor_glyph;
6303 GC gc;
6304
1a578e9b
AC
6305 /* Get the glyph the cursor is on. If we can't tell because
6306 the current matrix is invalid or such, give up. */
6307 cursor_glyph = get_phys_cursor_glyph (w);
6308 if (cursor_glyph == NULL)
6309 return;
6310
4d91ce74 6311 /* Compute frame-relative coordinates for phys cursor. */
e8f6b0db 6312 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
4d91ce74 6313 wd = w->phys_cursor_width;
177c0ea7 6314
1a578e9b
AC
6315 /* The foreground of cursor_gc is typically the same as the normal
6316 background color, which can cause the cursor box to be invisible. */
6317 xgcv.foreground = f->output_data.mac->cursor_pixel;
6318 if (dpyinfo->scratch_cursor_gc)
6319 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
6320 else
6321 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
6322 GCForeground, &xgcv);
6323 gc = dpyinfo->scratch_cursor_gc;
6324
6325 /* Set clipping, draw the rectangle, and reset clipping again. */
08f66682 6326 x_clip_to_row (w, row, TEXT_AREA, gc);
4ea08bbf 6327 mac_draw_rectangle (f, gc, x, y, wd, h - 1);
1c4ac540 6328 mac_reset_clip_rectangles (dpy, gc);
1a578e9b
AC
6329}
6330
6331
6332/* Draw a bar cursor on window W in glyph row ROW.
6333
6334 Implementation note: One would like to draw a bar cursor with an
6335 angle equal to the one given by the font property XA_ITALIC_ANGLE.
6336 Unfortunately, I didn't find a font yet that has this property set.
6337 --gerd. */
6338
6339static void
6b61353c 6340x_draw_bar_cursor (w, row, width, kind)
1a578e9b
AC
6341 struct window *w;
6342 struct glyph_row *row;
6343 int width;
6b61353c 6344 enum text_cursor_kinds kind;
1a578e9b 6345{
6b61353c
KH
6346 struct frame *f = XFRAME (w->frame);
6347 struct glyph *cursor_glyph;
6348
6349 /* If cursor is out of bounds, don't draw garbage. This can happen
6350 in mini-buffer windows when switching between echo area glyphs
6351 and mini-buffer. */
6352 cursor_glyph = get_phys_cursor_glyph (w);
6353 if (cursor_glyph == NULL)
6354 return;
6355
6356 /* If on an image, draw like a normal cursor. That's usually better
6357 visible than drawing a bar, esp. if the image is large so that
6358 the bar might not be in the window. */
6359 if (cursor_glyph->type == IMAGE_GLYPH)
1a578e9b 6360 {
6b61353c
KH
6361 struct glyph_row *row;
6362 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
6363 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
6364 }
6365 else
6366 {
6367 Display *dpy = FRAME_MAC_DISPLAY (f);
6368 Window window = FRAME_MAC_WINDOW (f);
6369 GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc;
6370 unsigned long mask = GCForeground | GCBackground;
6371 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
1a578e9b 6372 XGCValues xgcv;
177c0ea7 6373
6b61353c
KH
6374 /* If the glyph's background equals the color we normally draw
6375 the bar cursor in, the bar cursor in its normal color is
6376 invisible. Use the glyph's foreground color instead in this
6377 case, on the assumption that the glyph's colors are chosen so
6378 that the glyph is legible. */
6379 if (face->background == f->output_data.mac->cursor_pixel)
6380 xgcv.background = xgcv.foreground = face->foreground;
6381 else
6382 xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel;
177c0ea7 6383
1a578e9b
AC
6384 if (gc)
6385 XChangeGC (dpy, gc, mask, &xgcv);
6386 else
6387 {
6388 gc = XCreateGC (dpy, window, mask, &xgcv);
6389 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
6390 }
6391
6392 if (width < 0)
668e2d32 6393 width = FRAME_CURSOR_WIDTH (f);
6b61353c 6394 width = min (cursor_glyph->pixel_width, width);
1a578e9b 6395
6b61353c 6396 w->phys_cursor_width = width;
08f66682 6397 x_clip_to_row (w, row, TEXT_AREA, gc);
6b61353c
KH
6398
6399 if (kind == BAR_CURSOR)
236072ae
YM
6400 mac_fill_rectangle (f, gc,
6401 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6402 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
6403 width, row->height);
6b61353c 6404 else
236072ae
YM
6405 mac_fill_rectangle (f, gc,
6406 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
6407 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
6408 row->height - width),
6409 cursor_glyph->pixel_width,
6410 width);
6b61353c 6411
1c4ac540 6412 mac_reset_clip_rectangles (dpy, gc);
1a578e9b
AC
6413 }
6414}
6415
6416
f9e65eb3 6417/* RIF: Define cursor CURSOR on frame F. */
1a578e9b
AC
6418
6419static void
f9e65eb3
KS
6420mac_define_frame_cursor (f, cursor)
6421 struct frame *f;
6422 Cursor cursor;
1a578e9b 6423{
b465419f
YM
6424 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6425
6426 if (dpyinfo->x_focus_frame == f)
6427 SetThemeCursor (cursor);
1a578e9b
AC
6428}
6429
6430
f9e65eb3 6431/* RIF: Clear area on frame F. */
1a578e9b
AC
6432
6433static void
f9e65eb3
KS
6434mac_clear_frame_area (f, x, y, width, height)
6435 struct frame *f;
6436 int x, y, width, height;
1a578e9b 6437{
236072ae 6438 mac_clear_area (f, x, y, width, height);
1a578e9b
AC
6439}
6440
6441
f9e65eb3 6442/* RIF: Draw cursor on window W. */
1a578e9b
AC
6443
6444static void
e5a3b7d9 6445mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
1a578e9b 6446 struct window *w;
f9e65eb3 6447 struct glyph_row *glyph_row;
e5a3b7d9
KS
6448 int x, y;
6449 int cursor_type, cursor_width;
6450 int on_p, active_p;
1a578e9b 6451{
e5a3b7d9 6452 if (on_p)
1a578e9b 6453 {
e5a3b7d9 6454 w->phys_cursor_type = cursor_type;
1a578e9b
AC
6455 w->phys_cursor_on_p = 1;
6456
6b61353c
KH
6457 if (glyph_row->exact_window_width_line_p
6458 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
6459 {
6460 glyph_row->cursor_in_fringe_p = 1;
6461 draw_fringe_bitmap (w, glyph_row, 0);
6462 }
6463 else
e5a3b7d9 6464 switch (cursor_type)
1a578e9b
AC
6465 {
6466 case HOLLOW_BOX_CURSOR:
6467 x_draw_hollow_cursor (w, glyph_row);
6468 break;
6469
6470 case FILLED_BOX_CURSOR:
f9e65eb3 6471 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
1a578e9b
AC
6472 break;
6473
6474 case BAR_CURSOR:
6b61353c
KH
6475 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
6476 break;
6477
6478 case HBAR_CURSOR:
6479 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
1a578e9b
AC
6480 break;
6481
6482 case NO_CURSOR:
6b61353c 6483 w->phys_cursor_width = 0;
1a578e9b
AC
6484 break;
6485
6486 default:
6487 abort ();
6488 }
1a578e9b 6489 }
1a578e9b
AC
6490}
6491
e0f712ba
AC
6492\f
6493/* Icons. */
1a578e9b 6494
e0f712ba 6495#if 0 /* MAC_TODO: no icon support yet. */
1a578e9b 6496int
e0f712ba 6497x_bitmap_icon (f, icon)
1a578e9b 6498 struct frame *f;
e0f712ba 6499 Lisp_Object icon;
1a578e9b 6500{
e0f712ba 6501 HANDLE hicon;
1a578e9b 6502
e0f712ba 6503 if (FRAME_W32_WINDOW (f) == 0)
1a578e9b
AC
6504 return 1;
6505
e0f712ba
AC
6506 if (NILP (icon))
6507 hicon = LoadIcon (hinst, EMACS_CLASS);
6508 else if (STRINGP (icon))
d5db4077 6509 hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
e0f712ba
AC
6510 LR_DEFAULTSIZE | LR_LOADFROMFILE);
6511 else if (SYMBOLP (icon))
6512 {
6513 LPCTSTR name;
6514
6515 if (EQ (icon, intern ("application")))
6516 name = (LPCTSTR) IDI_APPLICATION;
6517 else if (EQ (icon, intern ("hand")))
6518 name = (LPCTSTR) IDI_HAND;
6519 else if (EQ (icon, intern ("question")))
6520 name = (LPCTSTR) IDI_QUESTION;
6521 else if (EQ (icon, intern ("exclamation")))
6522 name = (LPCTSTR) IDI_EXCLAMATION;
6523 else if (EQ (icon, intern ("asterisk")))
6524 name = (LPCTSTR) IDI_ASTERISK;
6525 else if (EQ (icon, intern ("winlogo")))
6526 name = (LPCTSTR) IDI_WINLOGO;
6527 else
6528 return 1;
1a578e9b 6529
e0f712ba 6530 hicon = LoadIcon (NULL, name);
1a578e9b 6531 }
e0f712ba 6532 else
1a578e9b
AC
6533 return 1;
6534
e0f712ba
AC
6535 if (hicon == NULL)
6536 return 1;
1a578e9b 6537
e0f712ba
AC
6538 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
6539 (LPARAM) hicon);
1a578e9b
AC
6540
6541 return 0;
6542}
e0f712ba 6543#endif /* MAC_TODO */
1a578e9b 6544\f
e0f712ba
AC
6545/************************************************************************
6546 Handling X errors
6547 ************************************************************************/
1a578e9b 6548
e0f712ba
AC
6549/* Display Error Handling functions not used on W32. Listing them here
6550 helps diff stay in step when comparing w32term.c with xterm.c.
1a578e9b 6551
1a578e9b 6552x_error_catcher (display, error)
1a578e9b 6553x_catch_errors (dpy)
1a578e9b 6554x_catch_errors_unwind (old_val)
1a578e9b 6555x_check_errors (dpy, format)
1a578e9b 6556x_had_errors_p (dpy)
1a578e9b 6557x_clear_errors (dpy)
1a578e9b 6558x_uncatch_errors (dpy, count)
1a578e9b 6559x_trace_wire ()
e0f712ba
AC
6560x_connection_signal (signalnum)
6561x_connection_closed (dpy, error_message)
1a578e9b 6562x_error_quitter (display, error)
1a578e9b 6563x_error_handler (display, error)
1a578e9b 6564x_io_error_quitter (display)
1a578e9b 6565
e0f712ba
AC
6566 */
6567
1a578e9b
AC
6568\f
6569/* Changing the font of the frame. */
6570
6571/* Give frame F the font named FONTNAME as its default font, and
6572 return the full name of that font. FONTNAME may be a wildcard
6573 pattern; in that case, we choose some font that fits the pattern.
6574 The return value shows which font we chose. */
6575
6576Lisp_Object
6577x_new_font (f, fontname)
6578 struct frame *f;
6579 register char *fontname;
6580{
6581 struct font_info *fontp
cc02ceee 6582 = FS_LOAD_FONT (f, fontname);
1a578e9b
AC
6583
6584 if (!fontp)
6585 return Qnil;
6586
cc02ceee
ST
6587 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
6588 /* This font is already set in frame F. There's nothing more to
6589 do. */
6590 return build_string (fontp->full_name);
6591
e0f712ba
AC
6592 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
6593 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
6594 FRAME_FONTSET (f) = -1;
6595
e169f939
ST
6596 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
6597 FRAME_SPACE_WIDTH (f) = fontp->space_width;
f1a83aab
KS
6598 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
6599
6600 compute_fringe_widths (f, 1);
6601
1a578e9b 6602 /* Compute the scroll bar width in character columns. */
f1a83aab 6603 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
1a578e9b 6604 {
f1a83aab 6605 int wid = FRAME_COLUMN_WIDTH (f);
ffe8b3f4 6606 FRAME_CONFIG_SCROLL_BAR_COLS (f)
f1a83aab 6607 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
1a578e9b
AC
6608 }
6609 else
6610 {
f1a83aab
KS
6611 int wid = FRAME_COLUMN_WIDTH (f);
6612 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
1a578e9b
AC
6613 }
6614
6615 /* Now make the frame display the given font. */
6616 if (FRAME_MAC_WINDOW (f) != 0)
6617 {
f00691a3 6618 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
f1a83aab 6619 FRAME_FONT (f));
f00691a3 6620 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
f1a83aab 6621 FRAME_FONT (f));
f00691a3 6622 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
f1a83aab 6623 FRAME_FONT (f));
f00691a3 6624
b15325b2
ST
6625 /* Don't change the size of a tip frame; there's no point in
6626 doing it because it's done in Fx_show_tip, and it leads to
6627 problems because the tip frame has no widget. */
e0f712ba 6628 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
f1a83aab 6629 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1a578e9b 6630 }
1a578e9b
AC
6631
6632 return build_string (fontp->full_name);
6633}
6abfb022
YM
6634\f
6635/* Give frame F the fontset named FONTSETNAME as its default fontset,
6636 and return the full name of that fontset. FONTSETNAME may be a
6637 wildcard pattern; in that case, we choose some fontset that fits
6638 the pattern. FONTSETNAME may be a font name for ASCII characters;
6639 in that case, we create a fontset from that font name.
b15325b2 6640
6abfb022
YM
6641 The return value shows which fontset we chose.
6642 If FONTSETNAME specifies the default fontset, return Qt.
6643 If an ASCII font in the specified fontset can't be loaded, return
6644 Qnil. */
1a578e9b
AC
6645
6646Lisp_Object
6647x_new_fontset (f, fontsetname)
6648 struct frame *f;
cc02ceee 6649 Lisp_Object fontsetname;
1a578e9b 6650{
cc02ceee 6651 int fontset = fs_query_fontset (fontsetname, 0);
1a578e9b
AC
6652 Lisp_Object result;
6653
cc02ceee 6654 if (fontset > 0 && FRAME_FONTSET(f) == fontset)
1a578e9b
AC
6655 /* This fontset is already set in frame F. There's nothing more
6656 to do. */
6657 return fontset_name (fontset);
cc02ceee
ST
6658 else if (fontset == 0)
6659 /* The default fontset can't be the default font. */
6660 return Qt;
1a578e9b 6661
cc02ceee
ST
6662 if (fontset > 0)
6663 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
6664 else
6665 result = x_new_font (f, SDATA (fontsetname));
1a578e9b
AC
6666
6667 if (!STRINGP (result))
6668 /* Can't load ASCII font. */
6669 return Qnil;
6670
cc02ceee
ST
6671 if (fontset < 0)
6672 fontset = new_fontset_from_font_name (result);
6673
e0f712ba 6674 /* Since x_new_font doesn't update any fontset information, do it now. */
7ca7ccd5 6675 FRAME_FONTSET (f) = fontset;
1a578e9b 6676
cc02ceee 6677 return fontset_name (fontset);
1a578e9b
AC
6678}
6679
1a578e9b
AC
6680\f
6681/***********************************************************************
e0f712ba 6682 TODO: W32 Input Methods
1a578e9b 6683 ***********************************************************************/
e0f712ba 6684/* Listing missing functions from xterm.c helps diff stay in step.
1a578e9b 6685
1a578e9b 6686xim_destroy_callback (xim, client_data, call_data)
1a578e9b 6687xim_open_dpy (dpyinfo, resource_name)
1a578e9b 6688struct xim_inst_t
1a578e9b 6689xim_instantiate_callback (display, client_data, call_data)
1a578e9b 6690xim_initialize (dpyinfo, resource_name)
1a578e9b 6691xim_close_dpy (dpyinfo)
1a578e9b 6692
e0f712ba 6693 */
1a578e9b 6694
1a578e9b 6695\f
bf06c82f
ST
6696void
6697mac_get_window_bounds (f, inner, outer)
6698 struct frame *f;
6699 Rect *inner, *outer;
6700{
6701#if TARGET_API_MAC_CARBON
6702 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
6703 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
6704#else /* not TARGET_API_MAC_CARBON */
6705 RgnHandle region = NewRgn ();
f94a2622 6706
bf06c82f
ST
6707 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
6708 *inner = (*region)->rgnBBox;
6709 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
6710 *outer = (*region)->rgnBBox;
6711 DisposeRgn (region);
6712#endif /* not TARGET_API_MAC_CARBON */
6713}
6714
bed0bf95
YM
6715static void
6716mac_handle_origin_change (f)
6717 struct frame *f;
6718{
6719 x_real_positions (f, &f->left_pos, &f->top_pos);
6720}
6721
6722static void
6723mac_handle_size_change (f, pixelwidth, pixelheight)
6724 struct frame *f;
6725 int pixelwidth, pixelheight;
6726{
6727 int cols, rows;
6728
6729 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
6730 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
6731
6732 if (cols != FRAME_COLS (f)
6733 || rows != FRAME_LINES (f)
6734 || pixelwidth != FRAME_PIXEL_WIDTH (f)
6735 || pixelheight != FRAME_PIXEL_HEIGHT (f))
6736 {
6737 /* We pass 1 for DELAY since we can't run Lisp code inside of
6738 a BLOCK_INPUT. */
6739 change_frame_size (f, rows, cols, 0, 1, 0);
6740 FRAME_PIXEL_WIDTH (f) = pixelwidth;
6741 FRAME_PIXEL_HEIGHT (f) = pixelheight;
6742 SET_FRAME_GARBAGED (f);
6743
6744 /* If cursor was outside the new size, mark it as off. */
6745 mark_window_cursors_off (XWINDOW (f->root_window));
6746
6747 /* Clear out any recollection of where the mouse highlighting
6748 was, since it might be in a place that's outside the new
6749 frame size. Actually checking whether it is outside is a
6750 pain in the neck, so don't try--just let the highlighting be
6751 done afresh with new size. */
6752 cancel_mouse_face (f);
6753
6754#if TARGET_API_MAC_CARBON
6755 if (f->output_data.mac->hourglass_control)
6756 {
6757#if USE_CG_DRAWING
6758 mac_prepare_for_quickdraw (f);
6759#endif
6760 MoveControl (f->output_data.mac->hourglass_control,
6761 pixelwidth - HOURGLASS_WIDTH, 0);
6762 }
6763#endif
6764 }
6765}
bf06c82f 6766
95dfb192 6767\f
1a578e9b
AC
6768/* Calculate the absolute position in frame F
6769 from its current recorded position values and gravity. */
6770
e0f712ba 6771void
1a578e9b
AC
6772x_calc_absolute_position (f)
6773 struct frame *f;
6774{
bf06c82f 6775 int width_diff = 0, height_diff = 0;
f1a83aab 6776 int flags = f->size_hint_flags;
bf06c82f 6777 Rect inner, outer;
1a578e9b 6778
bf06c82f
ST
6779 /* We have nothing to do if the current position
6780 is already for the top-left corner. */
6781 if (! ((flags & XNegative) || (flags & YNegative)))
6782 return;
1a578e9b 6783
bf06c82f 6784 /* Find the offsets of the outside upper-left corner of
1a578e9b 6785 the inner window, with respect to the outer window. */
1d5bcd55 6786 BLOCK_INPUT;
bf06c82f 6787 mac_get_window_bounds (f, &inner, &outer);
1d5bcd55 6788 UNBLOCK_INPUT;
e0f712ba 6789
bf06c82f
ST
6790 width_diff = (outer.right - outer.left) - (inner.right - inner.left);
6791 height_diff = (outer.bottom - outer.top) - (inner.bottom - inner.top);
1a578e9b
AC
6792
6793 /* Treat negative positions as relative to the leftmost bottommost
6794 position that fits on the screen. */
6795 if (flags & XNegative)
f1a83aab 6796 f->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
bf06c82f 6797 - width_diff
f1a83aab
KS
6798 - FRAME_PIXEL_WIDTH (f)
6799 + f->left_pos);
bf06c82f 6800
1a578e9b 6801 if (flags & YNegative)
f1a83aab 6802 f->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
bf06c82f 6803 - height_diff
f1a83aab
KS
6804 - FRAME_PIXEL_HEIGHT (f)
6805 + f->top_pos);
bf06c82f 6806
1a578e9b
AC
6807 /* The left_pos and top_pos
6808 are now relative to the top and left screen edges,
6809 so the flags should correspond. */
f1a83aab 6810 f->size_hint_flags &= ~ (XNegative | YNegative);
1a578e9b
AC
6811}
6812
6813/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6814 to really change the position, and 0 when calling from
6815 x_make_frame_visible (in that case, XOFF and YOFF are the current
6816 position values). It is -1 when calling from x_set_frame_parameters,
6817 which means, do adjust for borders but don't change the gravity. */
6818
6819void
6820x_set_offset (f, xoff, yoff, change_gravity)
6821 struct frame *f;
6822 register int xoff, yoff;
6823 int change_gravity;
6824{
6825 if (change_gravity > 0)
6826 {
f1a83aab
KS
6827 f->top_pos = yoff;
6828 f->left_pos = xoff;
6829 f->size_hint_flags &= ~ (XNegative | YNegative);
1a578e9b 6830 if (xoff < 0)
f1a83aab 6831 f->size_hint_flags |= XNegative;
1a578e9b 6832 if (yoff < 0)
f1a83aab
KS
6833 f->size_hint_flags |= YNegative;
6834 f->win_gravity = NorthWestGravity;
1a578e9b
AC
6835 }
6836 x_calc_absolute_position (f);
6837
6838 BLOCK_INPUT;
6839 x_wm_set_size_hint (f, (long) 0, 0);
6840
bf06c82f
ST
6841#if TARGET_API_MAC_CARBON
6842 MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos);
6843 /* If the title bar is completely outside the screen, adjust the
6844 position. */
6845 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
6846 kWindowConstrainMoveRegardlessOfFit
6847 | kWindowConstrainAllowPartial, NULL, NULL);
bed0bf95 6848 if (!NILP (tip_frame) && XFRAME (tip_frame) == f)
bed0bf95 6849 mac_handle_origin_change (f);
bf06c82f
ST
6850#else
6851 {
6852 Rect inner, outer, screen_rect, dummy;
6853 RgnHandle region = NewRgn ();
f94a2622 6854
bf06c82f
ST
6855 mac_get_window_bounds (f, &inner, &outer);
6856 f->x_pixels_diff = inner.left - outer.left;
6857 f->y_pixels_diff = inner.top - outer.top;
6858 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6859 f->top_pos + f->y_pixels_diff, false);
6860
6861 /* If the title bar is completely outside the screen, adjust the
6862 position. The variable `outer' holds the title bar rectangle.
6863 The variable `inner' holds slightly smaller one than `outer',
6864 so that the calculation of overlapping may not become too
6865 strict. */
6866 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, region);
6867 outer = (*region)->rgnBBox;
6868 DisposeRgn (region);
6869 inner = outer;
6870 InsetRect (&inner, 8, 8);
6871 screen_rect = qd.screenBits.bounds;
6872 screen_rect.top += GetMBarHeight ();
6873
6874 if (!SectRect (&inner, &screen_rect, &dummy))
6875 {
6876 if (inner.right <= screen_rect.left)
6877 f->left_pos = screen_rect.left;
6878 else if (inner.left >= screen_rect.right)
6879 f->left_pos = screen_rect.right - (outer.right - outer.left);
6880
6881 if (inner.bottom <= screen_rect.top)
6882 f->top_pos = screen_rect.top;
6883 else if (inner.top >= screen_rect.bottom)
6884 f->top_pos = screen_rect.bottom - (outer.bottom - outer.top);
6885
6886 MoveWindow (FRAME_MAC_WINDOW (f), f->left_pos + f->x_pixels_diff,
6887 f->top_pos + f->y_pixels_diff, false);
6888 }
6889 }
6890#endif
1a578e9b
AC
6891
6892 UNBLOCK_INPUT;
6893}
6894
6895/* Call this to change the size of frame F's x-window.
6896 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
6897 for this size change and subsequent size changes.
6898 Otherwise we leave the window gravity unchanged. */
6899
6900void
6901x_set_window_size (f, change_gravity, cols, rows)
6902 struct frame *f;
6903 int change_gravity;
6904 int cols, rows;
6905{
6906 int pixelwidth, pixelheight;
177c0ea7 6907
e0f712ba 6908 BLOCK_INPUT;
177c0ea7 6909
1a578e9b 6910 check_frame_size (f, &rows, &cols);
f1a83aab
KS
6911 f->scroll_bar_actual_width
6912 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
d33c49e8 6913
5958f265 6914 compute_fringe_widths (f, 0);
d33c49e8 6915
f1a83aab
KS
6916 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
6917 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1a578e9b 6918
f1a83aab 6919 f->win_gravity = NorthWestGravity;
1a578e9b
AC
6920 x_wm_set_size_hint (f, (long) 0, 0);
6921
6922 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
1a578e9b 6923
3354caee 6924#if TARGET_API_MAC_CARBON
bed0bf95
YM
6925 if (!NILP (tip_frame) && f == XFRAME (tip_frame))
6926#endif
6927 mac_handle_size_change (f, pixelwidth, pixelheight);
e0f712ba 6928
70385fe6
YM
6929 if (f->output_data.mac->internal_border_width
6930 != FRAME_INTERNAL_BORDER_WIDTH (f))
6931 {
6932 mac_clear_window (f);
6933 f->output_data.mac->internal_border_width
6934 = FRAME_INTERNAL_BORDER_WIDTH (f);
6935 }
6936
6937 SET_FRAME_GARBAGED (f);
6938
e0f712ba 6939 UNBLOCK_INPUT;
1a578e9b
AC
6940}
6941\f
6942/* Mouse warping. */
6943
6944void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
6945
6946void
6947x_set_mouse_position (f, x, y)
6948 struct frame *f;
6949 int x, y;
6950{
6951 int pix_x, pix_y;
6952
f1a83aab
KS
6953 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
6954 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
1a578e9b
AC
6955
6956 if (pix_x < 0) pix_x = 0;
f1a83aab 6957 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1a578e9b
AC
6958
6959 if (pix_y < 0) pix_y = 0;
f1a83aab 6960 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1a578e9b
AC
6961
6962 x_set_mouse_pixel_position (f, pix_x, pix_y);
6963}
6964
1a578e9b
AC
6965void
6966x_set_mouse_pixel_position (f, pix_x, pix_y)
6967 struct frame *f;
6968 int pix_x, pix_y;
6969{
92289429 6970#ifdef MAC_OSX
7adf3143
YM
6971 pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
6972 pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
92289429
YM
6973
6974 BLOCK_INPUT;
7adf3143 6975 CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y));
92289429
YM
6976 UNBLOCK_INPUT;
6977#else
6978#if 0 /* MAC_TODO: LMSetMouseLocation and CursorDeviceMoveTo are non-Carbon */
1a578e9b
AC
6979 BLOCK_INPUT;
6980
6981 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
6982 0, 0, 0, 0, pix_x, pix_y);
6983 UNBLOCK_INPUT;
6984#endif
92289429 6985#endif
1a578e9b
AC
6986}
6987\f
6988/* focus shifting, raising and lowering. */
6989
e0f712ba 6990void
1a578e9b
AC
6991x_focus_on_frame (f)
6992 struct frame *f;
6993{
6994#if 0 /* This proves to be unpleasant. */
6995 x_raise_frame (f);
6996#endif
6997#if 0
6998 /* I don't think that the ICCCM allows programs to do things like this
6999 without the interaction of the window manager. Whatever you end up
7000 doing with this code, do it to x_unfocus_frame too. */
7001 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7002 RevertToPointerRoot, CurrentTime);
7003#endif /* ! 0 */
7004}
7005
e0f712ba 7006void
1a578e9b
AC
7007x_unfocus_frame (f)
7008 struct frame *f;
7009{
1a578e9b
AC
7010}
7011
7012/* Raise frame F. */
95dfb192 7013
1a578e9b
AC
7014void
7015x_raise_frame (f)
7016 struct frame *f;
7017{
7018 if (f->async_visible)
c3f4c690
ST
7019 {
7020 BLOCK_INPUT;
b465419f 7021 BringToFront (FRAME_MAC_WINDOW (f));
c3f4c690
ST
7022 UNBLOCK_INPUT;
7023 }
1a578e9b
AC
7024}
7025
7026/* Lower frame F. */
95dfb192 7027
1a578e9b
AC
7028void
7029x_lower_frame (f)
7030 struct frame *f;
7031{
7032 if (f->async_visible)
c3f4c690
ST
7033 {
7034 BLOCK_INPUT;
b465419f 7035 SendBehind (FRAME_MAC_WINDOW (f), NULL);
c3f4c690
ST
7036 UNBLOCK_INPUT;
7037 }
1a578e9b
AC
7038}
7039
e0f712ba 7040static void
1a578e9b
AC
7041XTframe_raise_lower (f, raise_flag)
7042 FRAME_PTR f;
7043 int raise_flag;
7044{
7045 if (raise_flag)
7046 x_raise_frame (f);
7047 else
7048 x_lower_frame (f);
7049}
7050\f
7051/* Change of visibility. */
7052
1f98fbb4
YM
7053static void
7054mac_handle_visibility_change (f)
7055 struct frame *f;
7056{
3354caee 7057 WindowRef wp = FRAME_MAC_WINDOW (f);
1f98fbb4
YM
7058 int visible = 0, iconified = 0;
7059 struct input_event buf;
7060
7061 if (IsWindowVisible (wp))
f93e4d4f
YM
7062 {
7063 if (IsWindowCollapsed (wp))
7064 iconified = 1;
7065 else
7066 visible = 1;
7067 }
1f98fbb4
YM
7068
7069 if (!f->async_visible && visible)
7070 {
7071 if (f->iconified)
7072 {
7073 /* wait_reading_process_output will notice this and update
7074 the frame's display structures. If we were made
7075 invisible, we should not set garbaged, because that stops
7076 redrawing on Update events. */
7077 SET_FRAME_GARBAGED (f);
7078
7079 EVENT_INIT (buf);
7080 buf.kind = DEICONIFY_EVENT;
7081 XSETFRAME (buf.frame_or_window, f);
36f0107c 7082 buf.arg = Qnil;
1f98fbb4
YM
7083 kbd_buffer_store_event (&buf);
7084 }
7085 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7086 /* Force a redisplay sooner or later to update the
7087 frame titles in case this is the second frame. */
7088 record_asynch_buffer_change ();
7089 }
7090 else if (f->async_visible && !visible)
7091 if (iconified)
7092 {
7093 EVENT_INIT (buf);
7094 buf.kind = ICONIFY_EVENT;
7095 XSETFRAME (buf.frame_or_window, f);
36f0107c 7096 buf.arg = Qnil;
1f98fbb4
YM
7097 kbd_buffer_store_event (&buf);
7098 }
7099
7100 f->async_visible = visible;
7101 f->async_iconified = iconified;
7102}
7103
1a578e9b
AC
7104/* This tries to wait until the frame is really visible.
7105 However, if the window manager asks the user where to position
7106 the frame, this will return before the user finishes doing that.
7107 The frame will not actually be visible at that time,
7108 but it will become visible later when the window manager
7109 finishes with it. */
7110
7111void
7112x_make_frame_visible (f)
7113 struct frame *f;
7114{
1a578e9b
AC
7115 BLOCK_INPUT;
7116
7117 if (! FRAME_VISIBLE_P (f))
7118 {
7119 /* We test FRAME_GARBAGED_P here to make sure we don't
7120 call x_set_offset a second time
7121 if we get to x_make_frame_visible a second time
7122 before the window gets really visible. */
7123 if (! FRAME_ICONIFIED_P (f)
7124 && ! f->output_data.mac->asked_for_visible)
7adf3143 7125 x_set_offset (f, f->left_pos, f->top_pos, 0);
1f98fbb4
YM
7126
7127 f->output_data.mac->asked_for_visible = 1;
7128
1f98fbb4 7129 CollapseWindow (FRAME_MAC_WINDOW (f), false);
1a578e9b
AC
7130 ShowWindow (FRAME_MAC_WINDOW (f));
7131 }
7132
7133 XFlush (FRAME_MAC_DISPLAY (f));
7134
7135 /* Synchronize to ensure Emacs knows the frame is visible
7136 before we do anything else. We do this loop with input not blocked
7137 so that incoming events are handled. */
7138 {
7139 Lisp_Object frame;
7140 int count;
7141
7142 /* This must come after we set COUNT. */
7143 UNBLOCK_INPUT;
7144
7145 XSETFRAME (frame, f);
7146
7147 /* Wait until the frame is visible. Process X events until a
7148 MapNotify event has been seen, or until we think we won't get a
7149 MapNotify at all.. */
7150 for (count = input_signal_count + 10;
7151 input_signal_count < count && !FRAME_VISIBLE_P (f);)
7152 {
7153 /* Force processing of queued events. */
7154 x_sync (f);
7155
7156 /* Machines that do polling rather than SIGIO have been
7157 observed to go into a busy-wait here. So we'll fake an
7158 alarm signal to let the handler know that there's something
7159 to be read. We used to raise a real alarm, but it seems
7160 that the handler isn't always enabled here. This is
7161 probably a bug. */
7162 if (input_polling_used ())
7163 {
7164 /* It could be confusing if a real alarm arrives while
7165 processing the fake one. Turn it off and let the
7166 handler reset it. */
7167 extern void poll_for_input_1 P_ ((void));
7168 int old_poll_suppress_count = poll_suppress_count;
7169 poll_suppress_count = 1;
7170 poll_for_input_1 ();
7171 poll_suppress_count = old_poll_suppress_count;
7172 }
7173
7174 /* See if a MapNotify event has been processed. */
7175 FRAME_SAMPLE_VISIBILITY (f);
7176 }
7177 }
7178}
7179
7180/* Change from mapped state to withdrawn state. */
7181
7182/* Make the frame visible (mapped and not iconified). */
7183
7184void
7185x_make_frame_invisible (f)
7186 struct frame *f;
7187{
1f98fbb4
YM
7188 /* A deactivate event does not occur when the last visible frame is
7189 made invisible. So if we clear the highlight here, it will not
7190 be rehighlighted when it is made visible. */
7191#if 0
1a578e9b
AC
7192 /* Don't keep the highlight on an invisible frame. */
7193 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7194 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
1f98fbb4 7195#endif
177c0ea7 7196
1a578e9b 7197 BLOCK_INPUT;
177c0ea7 7198
7adf3143 7199#if !TARGET_API_MAC_CARBON
7ca7ccd5
YM
7200 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
7201 that the current position of the window is user-specified, rather than
7202 program-specified, so that when the window is mapped again, it will be
7203 placed at the same location, without forcing the user to position it
7204 by hand again (they have already done that once for this window.) */
7205 x_wm_set_size_hint (f, (long) 0, 1);
7adf3143 7206#endif
7ca7ccd5 7207
1a578e9b 7208 HideWindow (FRAME_MAC_WINDOW (f));
177c0ea7 7209
1a578e9b 7210 UNBLOCK_INPUT;
1f98fbb4 7211
3354caee 7212#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
7213 mac_handle_visibility_change (f);
7214#endif
1a578e9b
AC
7215}
7216
7217/* Change window state from mapped to iconified. */
7218
7219void
7220x_iconify_frame (f)
7221 struct frame *f;
7222{
3e7424f7 7223 OSStatus err;
1f98fbb4
YM
7224
7225 /* A deactivate event does not occur when the last visible frame is
7226 iconified. So if we clear the highlight here, it will not be
7227 rehighlighted when it is deiconified. */
7228#if 0
1a578e9b 7229 /* Don't keep the highlight on an invisible frame. */
742fbed7
AC
7230 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
7231 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
1f98fbb4 7232#endif
1a578e9b
AC
7233
7234 if (f->async_iconified)
7235 return;
7236
7237 BLOCK_INPUT;
7238
1f98fbb4
YM
7239 FRAME_SAMPLE_VISIBILITY (f);
7240
7241 if (! FRAME_VISIBLE_P (f))
7242 ShowWindow (FRAME_MAC_WINDOW (f));
7243
7244 err = CollapseWindow (FRAME_MAC_WINDOW (f), true);
177c0ea7 7245
1a578e9b 7246 UNBLOCK_INPUT;
1f98fbb4
YM
7247
7248 if (err != noErr)
7249 error ("Can't notify window manager of iconification");
7250
3354caee 7251#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
7252 mac_handle_visibility_change (f);
7253#endif
1a578e9b 7254}
e0f712ba 7255
1a578e9b 7256\f
6b61353c 7257/* Free X resources of frame F. */
1a578e9b
AC
7258
7259void
6b61353c 7260x_free_frame_resources (f)
1a578e9b
AC
7261 struct frame *f;
7262{
7263 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3354caee 7264 WindowRef wp = FRAME_MAC_WINDOW (f);
1a578e9b
AC
7265
7266 BLOCK_INPUT;
7267
25c9622b
YM
7268 if (wp != tip_window)
7269 remove_window_handler (wp);
7270
c857519f
YM
7271#if USE_CG_DRAWING
7272 mac_prepare_for_quickdraw (f);
7273#endif
50bf7673
ST
7274 DisposeWindow (wp);
7275 if (wp == tip_window)
7276 /* Neither WaitNextEvent nor ReceiveNextEvent receives `window
7277 closed' event. So we reset tip_window here. */
7278 tip_window = NULL;
1a578e9b
AC
7279
7280 free_frame_menubar (f);
6b61353c
KH
7281
7282 if (FRAME_FACE_CACHE (f))
7283 free_frame_faces (f);
7284
7285 x_free_gcs (f);
1a578e9b 7286
b15325b2
ST
7287 if (FRAME_SIZE_HINTS (f))
7288 xfree (FRAME_SIZE_HINTS (f));
7289
1a578e9b 7290 xfree (f->output_data.mac);
6b61353c
KH
7291 f->output_data.mac = NULL;
7292
1a578e9b 7293 if (f == dpyinfo->x_focus_frame)
4cb62a90
YM
7294 {
7295 dpyinfo->x_focus_frame = 0;
7296#if USE_MAC_FONT_PANEL
7297 mac_set_font_info_for_selection (NULL, DEFAULT_FACE_ID, 0);
7298#endif
7299 }
1a578e9b
AC
7300 if (f == dpyinfo->x_focus_event_frame)
7301 dpyinfo->x_focus_event_frame = 0;
7302 if (f == dpyinfo->x_highlight_frame)
7303 dpyinfo->x_highlight_frame = 0;
7304
1a578e9b
AC
7305 if (f == dpyinfo->mouse_face_mouse_frame)
7306 {
7307 dpyinfo->mouse_face_beg_row
7308 = dpyinfo->mouse_face_beg_col = -1;
7309 dpyinfo->mouse_face_end_row
7310 = dpyinfo->mouse_face_end_col = -1;
7311 dpyinfo->mouse_face_window = Qnil;
7312 dpyinfo->mouse_face_deferred_gc = 0;
7313 dpyinfo->mouse_face_mouse_frame = 0;
7314 }
7315
7316 UNBLOCK_INPUT;
7317}
6b61353c
KH
7318
7319
7320/* Destroy the X window of frame F. */
7321
7322void
7323x_destroy_window (f)
7324 struct frame *f;
7325{
7326 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7327
7328 x_free_frame_resources (f);
7329
7330 dpyinfo->reference_count--;
7331}
7332
1a578e9b
AC
7333\f
7334/* Setting window manager hints. */
7335
7336/* Set the normal size hints for the window manager, for frame F.
7337 FLAGS is the flags word to use--or 0 meaning preserve the flags
7338 that the window now has.
7339 If USER_POSITION is nonzero, we set the USPosition
7340 flag (this is useful when FLAGS is 0). */
1a578e9b
AC
7341void
7342x_wm_set_size_hint (f, flags, user_position)
7343 struct frame *f;
7344 long flags;
7345 int user_position;
7346{
b15325b2
ST
7347 int base_width, base_height, width_inc, height_inc;
7348 int min_rows = 0, min_cols = 0;
7349 XSizeHints *size_hints;
1a578e9b 7350
b15325b2
ST
7351 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
7352 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
7353 width_inc = FRAME_COLUMN_WIDTH (f);
7354 height_inc = FRAME_LINE_HEIGHT (f);
1a578e9b 7355
b15325b2 7356 check_frame_size (f, &min_rows, &min_cols);
1a578e9b 7357
b15325b2
ST
7358 size_hints = FRAME_SIZE_HINTS (f);
7359 if (size_hints == NULL)
1a578e9b 7360 {
b15325b2
ST
7361 size_hints = FRAME_SIZE_HINTS (f) = xmalloc (sizeof (XSizeHints));
7362 bzero (size_hints, sizeof (XSizeHints));
1a578e9b 7363 }
1a578e9b 7364
b15325b2
ST
7365 size_hints->flags |= PResizeInc | PMinSize | PBaseSize ;
7366 size_hints->width_inc = width_inc;
7367 size_hints->height_inc = height_inc;
7368 size_hints->min_width = base_width + min_cols * width_inc;
7369 size_hints->min_height = base_height + min_rows * height_inc;
7370 size_hints->base_width = base_width;
7371 size_hints->base_height = base_height;
1a578e9b 7372
b15325b2
ST
7373 if (flags)
7374 size_hints->flags = flags;
7375 else if (user_position)
1a578e9b 7376 {
b15325b2
ST
7377 size_hints->flags &= ~ PPosition;
7378 size_hints->flags |= USPosition;
1a578e9b 7379 }
1a578e9b
AC
7380}
7381
e0f712ba 7382#if 0 /* MAC_TODO: hide application instead of iconify? */
1a578e9b
AC
7383/* Used for IconicState or NormalState */
7384
7385void
7386x_wm_set_window_state (f, state)
7387 struct frame *f;
7388 int state;
7389{
7390#ifdef USE_X_TOOLKIT
7391 Arg al[1];
7392
7393 XtSetArg (al[0], XtNinitialState, state);
7394 XtSetValues (f->output_data.x->widget, al, 1);
7395#else /* not USE_X_TOOLKIT */
7396 Window window = FRAME_X_WINDOW (f);
7397
7398 f->output_data.x->wm_hints.flags |= StateHint;
7399 f->output_data.x->wm_hints.initial_state = state;
7400
7401 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7402#endif /* not USE_X_TOOLKIT */
7403}
7404
7405void
7406x_wm_set_icon_pixmap (f, pixmap_id)
7407 struct frame *f;
7408 int pixmap_id;
7409{
7410 Pixmap icon_pixmap;
7411
7412#ifndef USE_X_TOOLKIT
7413 Window window = FRAME_X_WINDOW (f);
7414#endif
7415
7416 if (pixmap_id > 0)
7417 {
7418 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7419 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
7420 }
7421 else
7422 {
7423 /* It seems there is no way to turn off use of an icon pixmap.
7424 The following line does it, only if no icon has yet been created,
7425 for some window managers. But with mwm it crashes.
7426 Some people say it should clear the IconPixmapHint bit in this case,
7427 but that doesn't work, and the X consortium said it isn't the
7428 right thing at all. Since there is no way to win,
7429 best to explicitly give up. */
7430#if 0
7431 f->output_data.x->wm_hints.icon_pixmap = None;
7432#else
7433 return;
7434#endif
7435 }
7436
7437#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
7438
7439 {
7440 Arg al[1];
7441 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
7442 XtSetValues (f->output_data.x->widget, al, 1);
7443 }
7444
7445#else /* not USE_X_TOOLKIT */
177c0ea7 7446
1a578e9b
AC
7447 f->output_data.x->wm_hints.flags |= IconPixmapHint;
7448 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
7449
7450#endif /* not USE_X_TOOLKIT */
7451}
7452
e0f712ba 7453#endif /* MAC_TODO */
1a578e9b
AC
7454
7455void
7456x_wm_set_icon_position (f, icon_x, icon_y)
7457 struct frame *f;
7458 int icon_x, icon_y;
7459{
7460#if 0 /* MAC_TODO: no icons on Mac */
7461#ifdef USE_X_TOOLKIT
7462 Window window = XtWindow (f->output_data.x->widget);
7463#else
7464 Window window = FRAME_X_WINDOW (f);
7465#endif
7466
7467 f->output_data.x->wm_hints.flags |= IconPositionHint;
7468 f->output_data.x->wm_hints.icon_x = icon_x;
7469 f->output_data.x->wm_hints.icon_y = icon_y;
7470
7471 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
e0f712ba 7472#endif /* MAC_TODO */
1a578e9b
AC
7473}
7474
7475\f
468213f1
YM
7476/***********************************************************************
7477 XLFD Pattern Match
7478 ***********************************************************************/
7479
7480/* An XLFD pattern is divided into blocks delimited by '*'. This
7481 structure holds information for each block. */
7482struct xlfdpat_block
7483{
7484 /* Length of the pattern string in this block. Non-zero except for
7485 the first and the last blocks. */
7486 int len;
7487
7488 /* Pattern string except the last character in this block. The last
7489 character is replaced with NUL in order to use it as a
7490 sentinel. */
7491 unsigned char *pattern;
7492
7493 /* Last character of the pattern string. Must not be '?'. */
7494 unsigned char last_char;
7495
7496 /* One of the tables for the Boyer-Moore string search. It
7497 specifies the number of positions to proceed for each character
7498 with which the match fails. */
7499 int skip[256];
7500
7501 /* The skip value for the last character in the above `skip' is
7502 assigned to `infinity' in order to simplify a loop condition.
7503 The original value is saved here. */
7504 int last_char_skip;
7505};
7506
7507struct xlfdpat
7508{
7509 /* Normalized pattern string. "Normalized" means that capital
7510 letters are lowered, blocks are not empty except the first and
7511 the last ones, and trailing '?'s in a block that is not the last
7512 one are moved to the next one. The last character in each block
7513 is replaced with NUL. */
7514 unsigned char *buf;
7515
7516 /* Number of characters except '*'s and trailing '?'s in the
7517 normalized pattern string. */
7518 int nchars;
7519
7520 /* Number of trailing '?'s in the normalized pattern string. */
7521 int trailing_anychars;
7522
7523 /* Number of blocks and information for each block. The latter is
7524 NULL if the pattern is exact (no '*' or '?' in it). */
7525 int nblocks;
7526 struct xlfdpat_block *blocks;
7527};
7528
7529static void
7530xlfdpat_destroy (pat)
7531 struct xlfdpat *pat;
7532{
7533 if (pat)
7534 {
7535 if (pat->buf)
7536 {
7537 if (pat->blocks)
7538 xfree (pat->blocks);
7539 xfree (pat->buf);
7540 }
7541 xfree (pat);
7542 }
7543}
7544
7545static struct xlfdpat *
7546xlfdpat_create (pattern)
369a7a37 7547 const char *pattern;
468213f1
YM
7548{
7549 struct xlfdpat *pat;
7550 int nblocks, i, skip;
7551 unsigned char last_char, *p, *q, *anychar_head;
369a7a37 7552 const unsigned char *ptr;
468213f1
YM
7553 struct xlfdpat_block *blk;
7554
7555 pat = xmalloc (sizeof (struct xlfdpat));
468213f1 7556 pat->buf = xmalloc (strlen (pattern) + 1);
468213f1
YM
7557
7558 /* Normalize the pattern string and store it to `pat->buf'. */
7559 nblocks = 0;
7560 anychar_head = NULL;
7561 q = pat->buf;
7562 last_char = '\0';
369a7a37 7563 for (ptr = pattern; *ptr; ptr++)
468213f1 7564 {
369a7a37 7565 unsigned char c = *ptr;
468213f1
YM
7566
7567 if (c == '*')
7568 if (last_char == '*')
7569 /* ...a** -> ...a* */
7570 continue;
7571 else
7572 {
7573 if (last_char == '?')
f93e4d4f
YM
7574 {
7575 if (anychar_head > pat->buf && *(anychar_head - 1) == '*')
7576 /* ...*??* -> ...*?? */
7577 continue;
7578 else
7579 /* ...a??* -> ...a*?? */
7580 {
7581 *anychar_head++ = '*';
7582 c = '?';
7583 }
7584 }
468213f1
YM
7585 nblocks++;
7586 }
7587 else if (c == '?')
7588 {
7589 if (last_char != '?')
7590 anychar_head = q;
7591 }
7592 else
7593 /* On Mac OS X 10.3, tolower also converts non-ASCII
7594 characters for some locales. */
7595 if (isascii (c))
7596 c = tolower (c);
7597
7598 *q++ = last_char = c;
7599 }
7600 *q = '\0';
7601 nblocks++;
7602 pat->nblocks = nblocks;
7603 if (last_char != '?')
7604 pat->trailing_anychars = 0;
7605 else
7606 {
7607 pat->trailing_anychars = q - anychar_head;
7608 q = anychar_head;
7609 }
7610 pat->nchars = q - pat->buf - (nblocks - 1);
7611
7612 if (anychar_head == NULL && nblocks == 1)
7613 {
7614 /* The pattern is exact. */
7615 pat->blocks = NULL;
7616 return pat;
7617 }
7618
7619 pat->blocks = xmalloc (sizeof (struct xlfdpat_block) * nblocks);
468213f1
YM
7620
7621 /* Divide the normalized pattern into blocks. */
7622 p = pat->buf;
7623 for (blk = pat->blocks; blk < pat->blocks + nblocks - 1; blk++)
7624 {
7625 blk->pattern = p;
7626 while (*p != '*')
7627 p++;
7628 blk->len = p - blk->pattern;
7629 p++;
7630 }
7631 blk->pattern = p;
7632 blk->len = q - blk->pattern;
7633
7634 /* Setup a table for the Boyer-Moore string search. */
7635 for (blk = pat->blocks; blk < pat->blocks + nblocks; blk++)
7636 if (blk->len != 0)
7637 {
7638 blk->last_char = blk->pattern[blk->len - 1];
7639 blk->pattern[blk->len - 1] = '\0';
7640
7641 for (skip = 1; skip < blk->len; skip++)
7642 if (blk->pattern[blk->len - skip - 1] == '?')
7643 break;
7644
7645 for (i = 0; i < 256; i++)
7646 blk->skip[i] = skip;
7647
7648 p = blk->pattern + (blk->len - skip);
7649 while (--skip > 0)
7650 blk->skip[*p++] = skip;
7651
7652 blk->last_char_skip = blk->skip[blk->last_char];
7653 }
7654
7655 return pat;
468213f1
YM
7656}
7657
7658static INLINE int
7659xlfdpat_exact_p (pat)
7660 struct xlfdpat *pat;
7661{
7c3d233d 7662 return pat->blocks == NULL;
468213f1
YM
7663}
7664
7665/* Return the first string in STRING + 0, ..., STRING + START_MAX such
7666 that the pattern in *BLK matches with its prefix. Return NULL
7667 there is no such strings. STRING must be lowered in advance. */
7668
369a7a37 7669static const char *
468213f1
YM
7670xlfdpat_block_match_1 (blk, string, start_max)
7671 struct xlfdpat_block *blk;
369a7a37 7672 const unsigned char *string;
468213f1
YM
7673 int start_max;
7674{
7675 int start, infinity;
369a7a37
YM
7676 unsigned char *p;
7677 const unsigned char *s;
468213f1
YM
7678
7679 xassert (blk->len > 0);
7680 xassert (start_max + blk->len <= strlen (string));
7c3d233d 7681 xassert (blk->last_char != '?');
468213f1
YM
7682
7683 /* See the comments in the function `boyer_moore' (search.c) for the
7684 use of `infinity'. */
7685 infinity = start_max + blk->len + 1;
7686 blk->skip[blk->last_char] = infinity;
7687
7688 start = 0;
7689 do
7690 {
7691 /* Check the last character of the pattern. */
7692 s = string + blk->len - 1;
7693 do
7694 {
7695 start += blk->skip[*(s + start)];
7696 }
7697 while (start <= start_max);
7698
7699 if (start < infinity)
7700 /* Couldn't find the last character. */
7701 return NULL;
7702
7703 /* No less than `infinity' means we could find the last
7704 character at `s[start - infinity]'. */
7705 start -= infinity;
7706
7707 /* Check the remaining characters. We prefer making no-'?'
7708 cases faster because the use of '?' is really rare. */
7709 p = blk->pattern;
7710 s = string + start;
7711 do
7712 {
7713 while (*p++ == *s++)
7714 ;
7715 }
7716 while (*(p - 1) == '?');
7717
7718 if (*(p - 1) == '\0')
7719 /* Matched. */
7720 return string + start;
7721
7722 /* Didn't match. */
7723 start += blk->last_char_skip;
7724 }
7725 while (start <= start_max);
7726
7727 return NULL;
7728}
7729
7730#define xlfdpat_block_match(b, s, m) \
7731 ((b)->len == 1 ? memchr ((s), (b)->last_char, (m) + 1) \
7732 : xlfdpat_block_match_1 (b, s, m))
7733
369a7a37 7734/* Check if XLFD pattern PAT, which is generated by `xlfdpat_create',
468213f1
YM
7735 matches with STRING. STRING must be lowered in advance. */
7736
7737static int
7738xlfdpat_match (pat, string)
7739 struct xlfdpat *pat;
369a7a37 7740 const unsigned char *string;
468213f1
YM
7741{
7742 int str_len, nblocks, i, start_max;
7743 struct xlfdpat_block *blk;
369a7a37 7744 const unsigned char *s;
468213f1
YM
7745
7746 xassert (pat->nblocks > 0);
7747
7748 if (xlfdpat_exact_p (pat))
7749 return strcmp (pat->buf, string) == 0;
7750
7751 /* The number of the characters in the string must not be smaller
7752 than that in the pattern. */
7753 str_len = strlen (string);
7754 if (str_len < pat->nchars + pat->trailing_anychars)
7755 return 0;
7756
7757 /* Chop off the trailing '?'s. */
7758 str_len -= pat->trailing_anychars;
7759
7760 /* The last block. When it is non-empty, it must match at the end
7761 of the string. */
7762 nblocks = pat->nblocks;
7763 blk = pat->blocks + (nblocks - 1);
7764 if (nblocks == 1)
7765 /* The last block is also the first one. */
7766 return (str_len == blk->len
7767 && (blk->len == 0 || xlfdpat_block_match (blk, string, 0)));
7768 else if (blk->len != 0)
7769 if (!xlfdpat_block_match (blk, string + (str_len - blk->len), 0))
7770 return 0;
7771
7772 /* The first block. When it is non-empty, it must match at the
7773 beginning of the string. */
7774 blk = pat->blocks;
7775 if (blk->len != 0)
7776 {
7777 s = xlfdpat_block_match (blk, string, 0);
7778 if (s == NULL)
7779 return 0;
7780 string = s + blk->len;
7781 }
7782
7783 /* The rest of the blocks. */
7784 start_max = str_len - pat->nchars;
7785 for (i = 1, blk++; i < nblocks - 1; i++, blk++)
7786 {
7787 s = xlfdpat_block_match (blk, string, start_max);
7788 if (s == NULL)
7789 return 0;
7790 start_max -= s - string;
7791 string = s + blk->len;
7792 }
7793
7794 return 1;
7795}
7796
7797\f
1a578e9b
AC
7798/***********************************************************************
7799 Fonts
7800 ***********************************************************************/
7801
7802/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7803
7804struct font_info *
7805x_get_font_info (f, font_idx)
7806 FRAME_PTR f;
7807 int font_idx;
7808{
7809 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
7810}
7811
7812/* the global font name table */
95dfb192
YM
7813static char **font_name_table = NULL;
7814static int font_name_table_size = 0;
7815static int font_name_count = 0;
1a578e9b 7816
71b7a47f
YM
7817/* Alist linking font family names to Font Manager font family
7818 references (which can also be used as QuickDraw font IDs). We use
7819 an alist because hash tables are not ready when the terminal frame
7820 for Mac OS Classic is created. */
7821static Lisp_Object fm_font_family_alist;
c3bd8190 7822#if USE_ATSUI
71b7a47f 7823/* Hash table linking font family names to ATSU font IDs. */
c3bd8190 7824static Lisp_Object atsu_font_id_hash;
92289429
YM
7825/* Alist linking Font Manager style to face attributes. */
7826static Lisp_Object fm_style_face_attributes_alist;
68c767a3 7827extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic;
c3bd8190
YM
7828#endif
7829
94d0e806
YM
7830/* Alist linking character set strings to Mac text encoding and Emacs
7831 coding system. */
7832static Lisp_Object Vmac_charset_info_alist;
1a578e9b 7833
94d0e806
YM
7834static Lisp_Object
7835create_text_encoding_info_alist ()
1a578e9b 7836{
94d0e806 7837 Lisp_Object result = Qnil, rest;
1a578e9b 7838
94d0e806
YM
7839 for (rest = Vmac_charset_info_alist; CONSP (rest); rest = XCDR (rest))
7840 {
7841 Lisp_Object charset_info = XCAR (rest);
7842 Lisp_Object charset, coding_system, text_encoding;
7843 Lisp_Object existing_info;
1a578e9b 7844
94d0e806 7845 if (!(CONSP (charset_info)
b51065cf
YM
7846 && (charset = XCAR (charset_info),
7847 STRINGP (charset))
94d0e806 7848 && CONSP (XCDR (charset_info))
b51065cf
YM
7849 && (text_encoding = XCAR (XCDR (charset_info)),
7850 INTEGERP (text_encoding))
94d0e806 7851 && CONSP (XCDR (XCDR (charset_info)))
b51065cf
YM
7852 && (coding_system = XCAR (XCDR (XCDR (charset_info))),
7853 SYMBOLP (coding_system))))
94d0e806 7854 continue;
1a578e9b 7855
94d0e806
YM
7856 existing_info = assq_no_quit (text_encoding, result);
7857 if (NILP (existing_info))
7858 result = Fcons (list3 (text_encoding, coding_system, charset),
7859 result);
1a578e9b 7860 else
94d0e806
YM
7861 if (NILP (Fmember (charset, XCDR (XCDR (existing_info)))))
7862 XSETCDR (XCDR (existing_info),
7863 Fcons (charset, XCDR (XCDR (existing_info))));
1a578e9b 7864 }
1a578e9b 7865
94d0e806 7866 return result;
1a578e9b 7867}
6b61353c 7868
6b61353c
KH
7869
7870static void
94d0e806 7871decode_mac_font_name (name, size, coding_system)
fc7a70cc
ST
7872 char *name;
7873 int size;
94d0e806 7874 Lisp_Object coding_system;
6b61353c 7875{
6b61353c 7876 struct coding_system coding;
94d0e806 7877 char *buf, *p;
6b61353c 7878
71b7a47f
YM
7879 if (!NILP (coding_system) && !NILP (Fcoding_system_p (coding_system)))
7880 {
7881 for (p = name; *p; p++)
7882 if (!isascii (*p) || iscntrl (*p))
7883 break;
94d0e806 7884
71b7a47f
YM
7885 if (*p)
7886 {
7887 setup_coding_system (coding_system, &coding);
7888 coding.src_multibyte = 0;
7889 coding.dst_multibyte = 1;
7890 coding.mode |= CODING_MODE_LAST_BLOCK;
6abfb022
YM
7891 coding.dst_bytes = size;
7892 coding.destination = (unsigned char *) alloca (coding.dst_bytes);
71b7a47f 7893
6abfb022
YM
7894 decode_coding_c_string (&coding, name, strlen (name), Qnil);
7895 bcopy (coding.destination, name, min (coding.produced, size));
7896 name[min (coding.produced, size)] = '\0';
71b7a47f
YM
7897 }
7898 }
6b61353c 7899
71b7a47f
YM
7900 /* If there's just one occurrence of '-' in the family name, it is
7901 replaced with '_'. (More than one occurrence of '-' means a
7902 "FOUNDRY-FAMILY-CHARSET"-style name.) */
7903 p = strchr (name, '-');
7904 if (p && strchr (p + 1, '-') == NULL)
7905 *p = '_';
6b61353c 7906
71b7a47f
YM
7907 for (p = name; *p; p++)
7908 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7909 for some locales. */
7910 if (isascii (*p))
7911 *p = tolower (*p);
6b61353c 7912}
1a578e9b
AC
7913
7914
7915static char *
94d0e806 7916mac_to_x_fontname (name, size, style, charset)
369a7a37 7917 const char *name;
fc7a70cc
ST
7918 int size;
7919 Style style;
94d0e806 7920 char *charset;
1a578e9b 7921{
dd15724d
YM
7922 Str31 foundry, cs;
7923 Str255 family;
468213f1
YM
7924 char xf[256], *result;
7925 unsigned char *p;
1a578e9b 7926
dd15724d 7927 if (sscanf (name, "%31[^-]-%255[^-]-%31s", foundry, family, cs) == 3)
94d0e806
YM
7928 charset = cs;
7929 else
1a578e9b
AC
7930 {
7931 strcpy(foundry, "Apple");
7932 strcpy(family, name);
1a578e9b
AC
7933 }
7934
dd15724d
YM
7935 sprintf (xf, "%s-%c-normal--%d-%d-%d-%d-m-%d-%s",
7936 style & bold ? "bold" : "medium", style & italic ? 'i' : 'r',
05f7d868 7937 size, size * 10, size ? 72 : 0, size ? 72 : 0, size * 10, charset);
177c0ea7 7938
dd15724d
YM
7939 result = xmalloc (strlen (foundry) + strlen (family) + strlen (xf) + 3 + 1);
7940 sprintf (result, "-%s-%s-%s", foundry, family, xf);
1a578e9b 7941 for (p = result; *p; p++)
468213f1
YM
7942 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
7943 for some locales. */
7944 if (isascii (*p))
7945 *p = tolower (*p);
1a578e9b
AC
7946 return result;
7947}
177c0ea7 7948
1a578e9b 7949
71b7a47f
YM
7950/* Parse fully-specified and instantiated X11 font spec XF, and store
7951 the results to FAMILY, *SIZE, *STYLE, and CHARSET. Return 1 if the
7952 parsing succeeded, and 0 otherwise. For FAMILY and CHARSET, the
7953 caller must allocate at least 256 and 32 bytes respectively. For
7954 ordinary Mac fonts, the value stored to FAMILY should just be their
7955 names, like "monaco", "Taipei", etc. Fonts converted from the GNU
7956 intlfonts collection contain their charset designation in their
7957 names, like "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both
7958 types of font names are handled accordingly. */
7959
7960const int kDefaultFontSize = 12;
7961
7962static int
7963parse_x_font_name (xf, family, size, style, charset)
369a7a37
YM
7964 const char *xf;
7965 char *family;
71b7a47f 7966 int *size;
94d0e806 7967 Style *style;
71b7a47f 7968 char *charset;
1a578e9b 7969{
71b7a47f
YM
7970 Str31 foundry, weight;
7971 int point_size, avgwidth;
7972 char slant[2], *p;
1a578e9b 7973
71b7a47f
YM
7974 if (sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]-%*[^-]-%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
7975 foundry, family, weight, slant, size,
7976 &point_size, &avgwidth, charset) != 8
7977 && sscanf (xf, "-%31[^-]-%255[^-]-%31[^-]-%1[^-]-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%31s",
7978 foundry, family, weight, slant, size,
7979 &point_size, &avgwidth, charset) != 8)
7980 return 0;
1a578e9b 7981
71b7a47f
YM
7982 if (*size == 0)
7983 {
7984 if (point_size > 0)
7985 *size = point_size / 10;
7986 else if (avgwidth > 0)
7987 *size = avgwidth / 10;
7988 }
7989 if (*size == 0)
7990 *size = kDefaultFontSize;
1a578e9b 7991
94d0e806
YM
7992 *style = normal;
7993 if (strcmp (weight, "bold") == 0)
7994 *style |= bold;
7995 if (*slant == 'i')
7996 *style |= italic;
7997
71b7a47f 7998 if (NILP (Fassoc (build_string (charset), Vmac_charset_info_alist)))
94d0e806 7999 {
71b7a47f
YM
8000 int foundry_len = strlen (foundry), family_len = strlen (family);
8001
8002 if (foundry_len + family_len + strlen (charset) + 2 < sizeof (Str255))
8003 {
8004 /* Like sprintf (family, "%s-%s-%s", foundry, family, charset),
8005 but take overlap into account. */
8006 memmove (family + foundry_len + 1, family, family_len);
8007 memcpy (family, foundry, foundry_len);
8008 family[foundry_len] = '-';
8009 family[foundry_len + 1 + family_len] = '-';
8010 strcpy (family + foundry_len + 1 + family_len + 1, charset);
8011 }
8012 else
8013 return 0;
94d0e806 8014 }
6b61353c 8015
71b7a47f
YM
8016 for (p = family; *p; p++)
8017 /* On Mac OS X 10.3, tolower also converts non-ASCII characters
8018 for some locales. */
8019 if (isascii (*p))
8020 *p = tolower (*p);
40b9c9c2 8021
71b7a47f 8022 return 1;
1a578e9b
AC
8023}
8024
8025
f00691a3
AC
8026static void
8027add_font_name_table_entry (char *font_name)
8028{
8029 if (font_name_table_size == 0)
8030 {
468213f1 8031 font_name_table_size = 256;
f00691a3
AC
8032 font_name_table = (char **)
8033 xmalloc (font_name_table_size * sizeof (char *));
8034 }
8035 else if (font_name_count + 1 >= font_name_table_size)
8036 {
468213f1 8037 font_name_table_size *= 2;
f00691a3
AC
8038 font_name_table = (char **)
8039 xrealloc (font_name_table,
8040 font_name_table_size * sizeof (char *));
8041 }
8042
8043 font_name_table[font_name_count++] = font_name;
8044}
8045
a0c62ca2
YM
8046static void
8047add_mac_font_name (name, size, style, charset)
369a7a37 8048 const char *name;
a0c62ca2
YM
8049 int size;
8050 Style style;
369a7a37 8051 const char *charset;
a0c62ca2
YM
8052{
8053 if (size > 0)
8054 add_font_name_table_entry (mac_to_x_fontname (name, size, style, charset));
8055 else
8056 {
8057 add_font_name_table_entry (mac_to_x_fontname (name, 0, style, charset));
8058 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic, charset));
8059 add_font_name_table_entry (mac_to_x_fontname (name, 0, bold, charset));
8060 add_font_name_table_entry (mac_to_x_fontname (name, 0, italic | bold,
8061 charset));
8062 }
8063}
8064
92289429 8065#if USE_ATSUI
0d36bf23
YM
8066static FMFontStyle
8067fm_get_style_from_font (font)
8068 FMFont font;
8069{
8070 OSStatus err;
8071 FMFontStyle style = normal;
8072 ByteCount len;
8073 UInt16 mac_style;
8074 FMFontFamily font_family;
8075#define FONT_HEADER_MAC_STYLE_OFFSET (4*4 + 2*2 + 8*2 + 2*4)
8076
8077 /* FMGetFontFamilyInstanceFromFont returns `normal' as the style of
8078 some font (e.g., Optima) even if it is `bold'. */
8079 err = FMGetFontTable (font, 'head', FONT_HEADER_MAC_STYLE_OFFSET,
8080 sizeof (mac_style), &mac_style, &len);
8081 if (err == noErr
8082 && len >= FONT_HEADER_MAC_STYLE_OFFSET + sizeof (mac_style))
8083 style = EndianU16_BtoN (mac_style);
8084 else
8085 FMGetFontFamilyInstanceFromFont (font, &font_family, &style);
8086
8087 return style;
8088}
8089
8090static ATSUFontID
8091atsu_find_font_from_family_name (family)
8092 const char *family;
8093{
8094 struct Lisp_Hash_Table *h = XHASH_TABLE (atsu_font_id_hash);
8095 unsigned hash_code;
8096 int i;
8097 Lisp_Object rest, best;
8098 FMFontStyle min_style, style;
8099
8100 i = hash_lookup (h, make_unibyte_string (family, strlen (family)),
8101 &hash_code);
8102 if (i < 0)
8103 return kATSUInvalidFontID;
8104
8105 rest = HASH_VALUE (h, i);
8106 if (INTEGERP (rest) || (CONSP (rest) && INTEGERP (XCDR (rest))))
8107 return cons_to_long (rest);
8108
8109 rest = Fnreverse (rest);
8110 best = XCAR (rest);
8111 rest = XCDR (rest);
8112 if (!NILP (rest)
8113 && (min_style = fm_get_style_from_font (cons_to_long (best))) != normal)
8114 do
8115 {
8116 style = fm_get_style_from_font (cons_to_long (XCAR (rest)));
8117 if (style < min_style)
8118 {
8119 best = XCAR (rest);
8120 if (style == normal)
8121 break;
8122 else
8123 min_style = style;
8124 }
8125 rest = XCDR (rest);
8126 }
8127 while (!NILP (rest));
8128
8129 HASH_VALUE (h, i) = best;
8130 return cons_to_long (best);
8131}
8132
92289429
YM
8133static Lisp_Object
8134fm_style_to_face_attributes (fm_style)
8135 FMFontStyle fm_style;
8136{
8137 Lisp_Object tem;
8138
8139 fm_style &= (bold | italic);
8140 tem = assq_no_quit (make_number (fm_style),
8141 fm_style_face_attributes_alist);
8142 if (!NILP (tem))
8143 return XCDR (tem);
8144
8145 tem = list4 (QCweight, fm_style & bold ? Qbold : Qnormal,
8146 QCslant, fm_style & italic ? Qitalic : Qnormal);
8147 fm_style_face_attributes_alist =
8148 Fcons (Fcons (make_number (fm_style), tem),
8149 fm_style_face_attributes_alist);
8150
8151 return tem;
8152}
0d36bf23
YM
8153
8154static Lisp_Object
8155atsu_find_font_family_name (font_id)
8156 ATSUFontID font_id;
8157{
8158 OSStatus err;
8159 ByteCount len;
8160 Lisp_Object family = Qnil;
8161
8162 err = ATSUFindFontName (font_id, kFontFamilyName,
8163 kFontMacintoshPlatform, kFontNoScript,
8164 kFontNoLanguage, 0, NULL, &len, NULL);
8165 if (err == noErr)
8166 {
8167 family = make_uninit_string (len);
8168 err = ATSUFindFontName (font_id, kFontFamilyName,
8169 kFontMacintoshPlatform, kFontNoScript,
8170 kFontNoLanguage, len, SDATA (family),
8171 NULL, NULL);
8172 }
8173 if (err == noErr)
8174 decode_mac_font_name (SDATA (family), len + 1, Qnil);
8175
8176 return family;
8177}
8178
8179Lisp_Object
8180mac_atsu_font_face_attributes (font_id)
8181 ATSUFontID font_id;
8182{
8183 Lisp_Object family, style_attrs;
8184
8185 family = atsu_find_font_family_name (font_id);
8186 if (NILP (family))
8187 return Qnil;
8188 style_attrs = fm_style_to_face_attributes (fm_get_style_from_font (font_id));
8189 return Fcons (QCfamily, Fcons (family, style_attrs));
8190}
92289429
YM
8191#endif
8192
f00691a3
AC
8193/* Sets up the table font_name_table to contain the list of all fonts
8194 in the system the first time the table is used so that the Resource
8195 Manager need not be accessed every time this information is
8196 needed. */
1a578e9b
AC
8197
8198static void
8199init_font_name_table ()
8200{
e0f712ba 8201#if TARGET_API_MAC_CARBON
94d0e806
YM
8202 FMFontFamilyIterator ffi;
8203 FMFontFamilyInstanceIterator ffii;
8204 FMFontFamily ff;
8205 Lisp_Object text_encoding_info_alist;
8206 struct gcpro gcpro1;
8207
c3bd8190
YM
8208 text_encoding_info_alist = create_text_encoding_info_alist ();
8209
8210#if USE_ATSUI
6b9ad469
YM
8211#if USE_CG_TEXT_DRAWING
8212 init_cg_text_anti_aliasing_threshold ();
8213#endif
c3bd8190
YM
8214 if (!NILP (assq_no_quit (make_number (kTextEncodingMacUnicode),
8215 text_encoding_info_alist)))
8216 {
3e7424f7 8217 OSStatus err;
a0c62ca2
YM
8218 struct Lisp_Hash_Table *h;
8219 unsigned hash_code;
c3bd8190
YM
8220 ItemCount nfonts, i;
8221 ATSUFontID *font_ids = NULL;
0d36bf23
YM
8222 Lisp_Object prev_family = Qnil;
8223 int j;
c3bd8190
YM
8224
8225 atsu_font_id_hash =
8226 make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
8227 make_float (DEFAULT_REHASH_SIZE),
8228 make_float (DEFAULT_REHASH_THRESHOLD),
3b8c0c70 8229 Qnil, Qnil, Qnil);
a0c62ca2
YM
8230 h = XHASH_TABLE (atsu_font_id_hash);
8231
c3bd8190
YM
8232 err = ATSUFontCount (&nfonts);
8233 if (err == noErr)
b96fe6ea
YM
8234 {
8235 font_ids = xmalloc (sizeof (ATSUFontID) * nfonts);
8236 err = ATSUGetFontIDs (font_ids, nfonts, NULL);
8237 }
c3bd8190
YM
8238 if (err == noErr)
8239 for (i = 0; i < nfonts; i++)
8240 {
0d36bf23
YM
8241 Lisp_Object family;
8242
8243 family = atsu_find_font_family_name (font_ids[i]);
8244 if (NILP (family) || SREF (family, 0) == '.')
c3bd8190 8245 continue;
0d36bf23
YM
8246 if (!NILP (Fequal (prev_family, family)))
8247 family = prev_family;
8248 else
8249 j = hash_lookup (h, family, &hash_code);
8250 if (j < 0)
c3bd8190 8251 {
0d36bf23
YM
8252 add_mac_font_name (SDATA (family), 0, normal, "iso10646-1");
8253 j = hash_put (h, family, Fcons (long_to_cons (font_ids[i]),
8254 Qnil), hash_code);
c3bd8190 8255 }
0d36bf23
YM
8256 else if (EQ (prev_family, family))
8257 HASH_VALUE (h, j) = Fcons (long_to_cons (font_ids[i]),
8258 HASH_VALUE (h, j));
8259 prev_family = family;
c3bd8190 8260 }
c3bd8190
YM
8261 if (font_ids)
8262 xfree (font_ids);
8263 }
8264#endif
8265
94d0e806
YM
8266 /* Create a dummy instance iterator here to avoid creating and
8267 destroying it in the loop. */
8268 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
8269 return;
8270 /* Create an iterator to enumerate the font families. */
8271 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
8272 != noErr)
8273 {
8274 FMDisposeFontFamilyInstanceIterator (&ffii);
8275 return;
8276 }
177c0ea7 8277
94d0e806
YM
8278 GCPRO1 (text_encoding_info_alist);
8279
8280 while (FMGetNextFontFamily (&ffi, &ff) == noErr)
e0f712ba 8281 {
94d0e806
YM
8282 Str255 name;
8283 FMFont font;
8284 FMFontStyle style;
8285 FMFontSize size;
8286 TextEncoding encoding;
8287 TextEncodingBase sc;
a0c62ca2 8288 Lisp_Object text_encoding_info, family;
1a578e9b 8289
94d0e806 8290 if (FMGetFontFamilyName (ff, name) != noErr)
a0c62ca2 8291 continue;
94d0e806
YM
8292 p2cstr (name);
8293 if (*name == '.')
8294 continue;
1a578e9b 8295
94d0e806 8296 if (FMGetFontFamilyTextEncoding (ff, &encoding) != noErr)
a0c62ca2 8297 continue;
94d0e806
YM
8298 sc = GetTextEncodingBase (encoding);
8299 text_encoding_info = assq_no_quit (make_number (sc),
8300 text_encoding_info_alist);
71b7a47f 8301 if (NILP (text_encoding_info))
94d0e806
YM
8302 text_encoding_info = assq_no_quit (make_number (kTextEncodingMacRoman),
8303 text_encoding_info_alist);
71b7a47f
YM
8304 decode_mac_font_name (name, sizeof (name),
8305 XCAR (XCDR (text_encoding_info)));
a0c62ca2
YM
8306 family = build_string (name);
8307 if (!NILP (Fassoc (family, fm_font_family_alist)))
8308 continue;
8309 fm_font_family_alist = Fcons (Fcons (family, make_number (ff)),
71b7a47f 8310 fm_font_family_alist);
177c0ea7 8311
94d0e806
YM
8312 /* Point the instance iterator at the current font family. */
8313 if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr)
a0c62ca2 8314 continue;
b15325b2 8315
94d0e806
YM
8316 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
8317 == noErr)
8318 {
8319 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
177c0ea7 8320
7c3d233d 8321 if (size > 0 || style == normal)
9beb8baa 8322 for (; CONSP (rest); rest = XCDR (rest))
a0c62ca2 8323 add_mac_font_name (name, size, style, SDATA (XCAR (rest)));
e0f712ba 8324 }
e0f712ba 8325 }
94d0e806
YM
8326
8327 UNGCPRO;
8328
8329 /* Dispose of the iterators. */
8330 FMDisposeFontFamilyIterator (&ffi);
8331 FMDisposeFontFamilyInstanceIterator (&ffii);
8332#else /* !TARGET_API_MAC_CARBON */
8333 GrafPtr port;
8334 SInt16 fontnum, old_fontnum;
8335 int num_mac_fonts = CountResources('FOND');
8336 int i, j;
8337 Handle font_handle, font_handle_2;
8338 short id, scriptcode;
8339 ResType type;
dd15724d 8340 Str255 name;
94d0e806
YM
8341 struct FontAssoc *fat;
8342 struct AsscEntry *assc_entry;
a0c62ca2 8343 Lisp_Object text_encoding_info_alist, text_encoding_info, family;
94d0e806
YM
8344 struct gcpro gcpro1;
8345
8346 GetPort (&port); /* save the current font number used */
8347 old_fontnum = port->txFont;
8348
8349 text_encoding_info_alist = create_text_encoding_info_alist ();
8350
8351 GCPRO1 (text_encoding_info_alist);
8352
8353 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
1a578e9b 8354 {
94d0e806
YM
8355 font_handle = GetIndResource ('FOND', i);
8356 if (!font_handle)
8357 continue;
e0f712ba 8358
94d0e806
YM
8359 GetResInfo (font_handle, &id, &type, name);
8360 GetFNum (name, &fontnum);
8361 p2cstr (name);
a0c62ca2 8362 if (fontnum == 0 || *name == '.')
94d0e806 8363 continue;
177c0ea7 8364
94d0e806
YM
8365 TextFont (fontnum);
8366 scriptcode = FontToScript (fontnum);
8367 text_encoding_info = assq_no_quit (make_number (scriptcode),
8368 text_encoding_info_alist);
71b7a47f 8369 if (NILP (text_encoding_info))
94d0e806
YM
8370 text_encoding_info = assq_no_quit (make_number (smRoman),
8371 text_encoding_info_alist);
71b7a47f
YM
8372 decode_mac_font_name (name, sizeof (name),
8373 XCAR (XCDR (text_encoding_info)));
a0c62ca2
YM
8374 family = build_string (name);
8375 if (!NILP (Fassoc (family, fm_font_family_alist)))
8376 continue;
8377 fm_font_family_alist = Fcons (Fcons (family, make_number (fontnum)),
71b7a47f 8378 fm_font_family_alist);
94d0e806
YM
8379 do
8380 {
8381 HLock (font_handle);
177c0ea7 8382
94d0e806
YM
8383 if (GetResourceSizeOnDisk (font_handle)
8384 >= sizeof (struct FamRec))
e0f712ba 8385 {
94d0e806
YM
8386 fat = (struct FontAssoc *) (*font_handle
8387 + sizeof (struct FamRec));
8388 assc_entry
8389 = (struct AsscEntry *) (*font_handle
8390 + sizeof (struct FamRec)
8391 + sizeof (struct FontAssoc));
8392
8393 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
e0f712ba 8394 {
94d0e806
YM
8395 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
8396
9beb8baa 8397 for (; CONSP (rest); rest = XCDR (rest))
a0c62ca2
YM
8398 add_mac_font_name (name, assc_entry->fontSize,
8399 assc_entry->fontStyle,
8400 SDATA (XCAR (rest)));
e0f712ba 8401 }
e0f712ba 8402 }
177c0ea7 8403
94d0e806
YM
8404 HUnlock (font_handle);
8405 font_handle_2 = GetNextFOND (font_handle);
8406 ReleaseResource (font_handle);
8407 font_handle = font_handle_2;
8408 }
8409 while (ResError () == noErr && font_handle);
1a578e9b 8410 }
94d0e806
YM
8411
8412 UNGCPRO;
8413
8414 TextFont (old_fontnum);
8415#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
8416}
8417
8418
b15325b2
ST
8419void
8420mac_clear_font_name_table ()
8421{
8422 int i;
8423
8424 for (i = 0; i < font_name_count; i++)
8425 xfree (font_name_table[i]);
8426 xfree (font_name_table);
8427 font_name_table = NULL;
8428 font_name_table_size = font_name_count = 0;
71b7a47f 8429 fm_font_family_alist = Qnil;
b15325b2
ST
8430}
8431
8432
6b61353c
KH
8433enum xlfd_scalable_field_index
8434 {
8435 XLFD_SCL_PIXEL_SIZE,
8436 XLFD_SCL_POINT_SIZE,
8437 XLFD_SCL_AVGWIDTH,
8438 XLFD_SCL_LAST
8439 };
8440
369a7a37 8441static const int xlfd_scalable_fields[] =
6b61353c
KH
8442 {
8443 6, /* PIXEL_SIZE */
8444 7, /* POINT_SIZE */
8445 11, /* AVGWIDTH */
8446 -1
8447 };
8448
8449static Lisp_Object
8450mac_do_list_fonts (pattern, maxnames)
369a7a37 8451 const char *pattern;
6b61353c
KH
8452 int maxnames;
8453{
8454 int i, n_fonts = 0;
468213f1
YM
8455 Lisp_Object font_list = Qnil;
8456 struct xlfdpat *pat;
369a7a37
YM
8457 char *scaled;
8458 const char *ptr;
8459 int scl_val[XLFD_SCL_LAST], *val;
8460 const int *field;
468213f1 8461 int exact;
e3564461 8462
b15325b2
ST
8463 if (font_name_table == NULL) /* Initialize when first used. */
8464 init_font_name_table ();
6b61353c
KH
8465
8466 for (i = 0; i < XLFD_SCL_LAST; i++)
8467 scl_val[i] = -1;
8468
8469 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
8470 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
8471 fonts are scaled according to the specified size. */
8472 ptr = pattern;
8473 i = 0;
8474 field = xlfd_scalable_fields;
8475 val = scl_val;
8476 if (*ptr == '-')
8477 do
8478 {
8479 ptr++;
8480 if (i == *field)
8481 {
94d0e806 8482 if ('0' <= *ptr && *ptr <= '9')
6b61353c
KH
8483 {
8484 *val = *ptr++ - '0';
8485 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
8486 *val = *val * 10 + *ptr++ - '0';
8487 if (*ptr != '-')
8488 *val = -1;
8489 }
8490 field++;
8491 val++;
8492 }
8493 ptr = strchr (ptr, '-');
8494 i++;
8495 }
8496 while (ptr && i < 14);
8497
8498 if (i == 14 && ptr == NULL)
8499 {
94d0e806
YM
8500 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
8501 scl_val[XLFD_SCL_PIXEL_SIZE] =
8502 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
8503 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
8504 : -1));
8505 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
8506 scl_val[XLFD_SCL_POINT_SIZE] =
8507 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8508 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
8509 : -1));
8510 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
8511 scl_val[XLFD_SCL_AVGWIDTH] =
8512 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
8513 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
8514 : -1));
6b61353c
KH
8515 }
8516 else
8517 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
8518
468213f1
YM
8519 pat = xlfdpat_create (pattern);
8520 if (pat == NULL)
8521 return Qnil;
fbe6152f 8522
468213f1 8523 exact = xlfdpat_exact_p (pat);
6b61353c
KH
8524
8525 for (i = 0; i < font_name_count; i++)
8526 {
468213f1 8527 if (xlfdpat_match (pat, font_name_table[i]))
6b61353c 8528 {
468213f1 8529 font_list = Fcons (build_string (font_name_table[i]), font_list);
f93e4d4f 8530 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
68c69027 8531 break;
6b61353c
KH
8532 }
8533 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
b0241f69 8534 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
6b61353c
KH
8535 {
8536 int former_len = ptr - font_name_table[i];
8537
dd15724d 8538 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
6b61353c
KH
8539 memcpy (scaled, font_name_table[i], former_len);
8540 sprintf (scaled + former_len,
05f7d868 8541 "-%d-%d-72-72-m-%d-%s",
6b61353c
KH
8542 scl_val[XLFD_SCL_PIXEL_SIZE],
8543 scl_val[XLFD_SCL_POINT_SIZE],
8544 scl_val[XLFD_SCL_AVGWIDTH],
b0241f69 8545 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
468213f1
YM
8546
8547 if (xlfdpat_match (pat, scaled))
6b61353c 8548 {
468213f1
YM
8549 font_list = Fcons (build_string (scaled), font_list);
8550 xfree (scaled);
f93e4d4f 8551 if (exact || (maxnames > 0 && ++n_fonts >= maxnames))
468213f1 8552 break;
6b61353c 8553 }
468213f1
YM
8554 else
8555 xfree (scaled);
6b61353c
KH
8556 }
8557 }
fbe6152f 8558
468213f1 8559 xlfdpat_destroy (pat);
fbe6152f 8560
6b61353c
KH
8561 return font_list;
8562}
8563
94d0e806
YM
8564/* Return a list of names of available fonts matching PATTERN on frame F.
8565
8566 Frame F null means we have not yet created any frame on Mac, and
8567 consult the first display in x_display_list. MAXNAMES sets a limit
8568 on how many fonts to match. */
1a578e9b
AC
8569
8570Lisp_Object
94d0e806
YM
8571x_list_fonts (f, pattern, size, maxnames)
8572 struct frame *f;
8573 Lisp_Object pattern;
8574 int size, maxnames;
1a578e9b 8575{
94d0e806
YM
8576 Lisp_Object list = Qnil, patterns, tem, key;
8577 struct mac_display_info *dpyinfo
8578 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
1a578e9b 8579
94d0e806
YM
8580 xassert (size <= 0);
8581
8582 patterns = Fassoc (pattern, Valternate_fontname_alist);
8583 if (NILP (patterns))
8584 patterns = Fcons (pattern, Qnil);
1a578e9b 8585
94d0e806 8586 for (; CONSP (patterns); patterns = XCDR (patterns))
10ba2aec 8587 {
94d0e806
YM
8588 pattern = XCAR (patterns);
8589
8590 if (!STRINGP (pattern))
8591 continue;
8592
b298e813 8593 tem = XCAR (XCDR (dpyinfo->name_list_element));
10ba2aec
AC
8594 key = Fcons (pattern, make_number (maxnames));
8595
94d0e806
YM
8596 list = Fassoc (key, tem);
8597 if (!NILP (list))
10ba2aec 8598 {
94d0e806
YM
8599 list = Fcdr_safe (list);
8600 /* We have a cashed list. Don't have to get the list again. */
10ba2aec
AC
8601 goto label_cached;
8602 }
10ba2aec 8603
94d0e806
YM
8604 BLOCK_INPUT;
8605 list = mac_do_list_fonts (SDATA (pattern), maxnames);
8606 UNBLOCK_INPUT;
177c0ea7 8607
94d0e806 8608 /* MAC_TODO: add code for matching outline fonts here */
1a578e9b 8609
94d0e806 8610 /* Now store the result in the cache. */
b298e813 8611 XSETCAR (XCDR (dpyinfo->name_list_element),
94d0e806 8612 Fcons (Fcons (key, list),
b298e813 8613 XCAR (XCDR (dpyinfo->name_list_element))));
94d0e806
YM
8614
8615 label_cached:
8616 if (NILP (list)) continue; /* Try the remaining alternatives. */
10ba2aec 8617 }
177c0ea7 8618
94d0e806 8619 return list;
1a578e9b
AC
8620}
8621
8622
8623#if GLYPH_DEBUG
8624
e0f712ba
AC
8625/* Check that FONT is valid on frame F. It is if it can be found in F's
8626 font table. */
1a578e9b
AC
8627
8628static void
8629x_check_font (f, font)
8630 struct frame *f;
8631 XFontStruct *font;
8632{
8633 int i;
8634 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8635
8636 xassert (font != NULL);
8637
8638 for (i = 0; i < dpyinfo->n_fonts; i++)
177c0ea7 8639 if (dpyinfo->font_table[i].name
1a578e9b
AC
8640 && font == dpyinfo->font_table[i].font)
8641 break;
8642
8643 xassert (i < dpyinfo->n_fonts);
8644}
8645
8646#endif /* GLYPH_DEBUG != 0 */
8647
1a578e9b
AC
8648/* Set *W to the minimum width, *H to the minimum font height of FONT.
8649 Note: There are (broken) X fonts out there with invalid XFontStruct
8650 min_bounds contents. For example, handa@etl.go.jp reports that
8651 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
8652 have font->min_bounds.width == 0. */
8653
8654static INLINE void
8655x_font_min_bounds (font, w, h)
8656 MacFontStruct *font;
8657 int *w, *h;
8658{
8659 *h = FONT_HEIGHT (font);
e169f939 8660 *w = font->min_bounds.width;
1a578e9b
AC
8661}
8662
8663
8664/* Compute the smallest character width and smallest font height over
8665 all fonts available on frame F. Set the members smallest_char_width
8666 and smallest_font_height in F's x_display_info structure to
8667 the values computed. Value is non-zero if smallest_font_height or
8668 smallest_char_width become smaller than they were before. */
8669
dd15724d 8670static int
1a578e9b
AC
8671x_compute_min_glyph_bounds (f)
8672 struct frame *f;
8673{
8674 int i;
8675 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8676 MacFontStruct *font;
8677 int old_width = dpyinfo->smallest_char_width;
8678 int old_height = dpyinfo->smallest_font_height;
177c0ea7 8679
1a578e9b
AC
8680 dpyinfo->smallest_font_height = 100000;
8681 dpyinfo->smallest_char_width = 100000;
177c0ea7 8682
1a578e9b
AC
8683 for (i = 0; i < dpyinfo->n_fonts; ++i)
8684 if (dpyinfo->font_table[i].name)
8685 {
8686 struct font_info *fontp = dpyinfo->font_table + i;
8687 int w, h;
177c0ea7 8688
1a578e9b
AC
8689 font = (MacFontStruct *) fontp->font;
8690 xassert (font != (MacFontStruct *) ~0);
8691 x_font_min_bounds (font, &w, &h);
177c0ea7 8692
1a578e9b
AC
8693 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
8694 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
8695 }
8696
8697 xassert (dpyinfo->smallest_char_width > 0
8698 && dpyinfo->smallest_font_height > 0);
8699
8700 return (dpyinfo->n_fonts == 1
8701 || dpyinfo->smallest_char_width < old_width
8702 || dpyinfo->smallest_font_height < old_height);
8703}
8704
8705
8706/* Determine whether given string is a fully-specified XLFD: all 14
8707 fields are present, none is '*'. */
8708
8709static int
369a7a37
YM
8710is_fully_specified_xlfd (p)
8711 const char *p;
1a578e9b
AC
8712{
8713 int i;
8714 char *q;
8715
8716 if (*p != '-')
8717 return 0;
177c0ea7 8718
1a578e9b
AC
8719 for (i = 0; i < 13; i++)
8720 {
8721 q = strchr (p + 1, '-');
8722 if (q == NULL)
8723 return 0;
8724 if (q - p == 2 && *(p + 1) == '*')
8725 return 0;
8726 p = q;
8727 }
8728
8729 if (strchr (p + 1, '-') != NULL)
8730 return 0;
177c0ea7 8731
1a578e9b
AC
8732 if (*(p + 1) == '*' && *(p + 2) == '\0')
8733 return 0;
8734
8735 return 1;
8736}
8737
8738
bb420759
YM
8739/* mac_load_query_font creates and returns an internal representation
8740 for a font in a MacFontStruct struct. There is really no concept
e0f712ba
AC
8741 corresponding to "loading" a font on the Mac. But we check its
8742 existence and find the font number and all other information for it
8743 and store them in the returned MacFontStruct. */
1a578e9b
AC
8744
8745static MacFontStruct *
bb420759
YM
8746mac_load_query_font (f, fontname)
8747 struct frame *f;
8748 char *fontname;
1a578e9b 8749{
b73e4d84 8750 int size;
1a578e9b 8751 char *name;
71b7a47f 8752 Str255 family;
dd15724d 8753 Str31 charset;
1a578e9b 8754 SInt16 fontnum;
c3bd8190 8755#if USE_ATSUI
16805b2e 8756 static ATSUFontID font_id;
c3bd8190
YM
8757 ATSUStyle mac_style = NULL;
8758#endif
94d0e806
YM
8759 Style fontface;
8760#if TARGET_API_MAC_CARBON
8761 TextEncoding encoding;
8762 int scriptcode;
8763#else
8764 short scriptcode;
8765#endif
1a578e9b 8766 MacFontStruct *font;
b73e4d84 8767 XCharStruct *space_bounds = NULL, *pcm;
1a578e9b
AC
8768
8769 if (is_fully_specified_xlfd (fontname))
8770 name = fontname;
8771 else
8772 {
6b61353c 8773 Lisp_Object matched_fonts;
1a578e9b 8774
6b61353c
KH
8775 matched_fonts = mac_do_list_fonts (fontname, 1);
8776 if (NILP (matched_fonts))
8777 return NULL;
8778 name = SDATA (XCAR (matched_fonts));
1a578e9b
AC
8779 }
8780
71b7a47f
YM
8781 if (parse_x_font_name (name, family, &size, &fontface, charset) == 0)
8782 return NULL;
1a578e9b 8783
c3bd8190
YM
8784#if USE_ATSUI
8785 if (strcmp (charset, "iso10646-1") == 0) /* XXX */
8786 {
3e7424f7 8787 OSStatus err;
369a7a37
YM
8788 static const ATSUAttributeTag tags[] =
8789 {kATSUFontTag, kATSUSizeTag,
8790 kATSUQDBoldfaceTag, kATSUQDItalicTag};
8791 static const ByteCount sizes[] =
8792 {sizeof (ATSUFontID), sizeof (Fixed),
8793 sizeof (Boolean), sizeof (Boolean)};
c3bd8190
YM
8794 static Fixed size_fixed;
8795 static Boolean bold_p, italic_p;
369a7a37
YM
8796 static const ATSUAttributeValuePtr values[] =
8797 {&font_id, &size_fixed,
8798 &bold_p, &italic_p};
8799 static const ATSUFontFeatureType types[] =
8800 {kAllTypographicFeaturesType, kDiacriticsType};
8801 static const ATSUFontFeatureSelector selectors[] =
8802 {kAllTypeFeaturesOffSelector, kDecomposeDiacriticsSelector};
68c767a3 8803 FMFontStyle style;
1c4ac540 8804
0d36bf23
YM
8805 font_id = atsu_find_font_from_family_name (family);
8806 if (font_id == kATSUInvalidFontID)
cb91e86a 8807 return NULL;
c3bd8190
YM
8808 size_fixed = Long2Fix (size);
8809 bold_p = (fontface & bold) != 0;
8810 italic_p = (fontface & italic) != 0;
8811 err = ATSUCreateStyle (&mac_style);
8812 if (err != noErr)
8813 return NULL;
8814 err = ATSUSetFontFeatures (mac_style, sizeof (types) / sizeof (types[0]),
8815 types, selectors);
8816 if (err != noErr)
8817 return NULL;
8818 err = ATSUSetAttributes (mac_style, sizeof (tags) / sizeof (tags[0]),
8819 tags, sizes, values);
68c767a3
YM
8820 if (err != noErr)
8821 return NULL;
8822 err = FMGetFontFamilyInstanceFromFont (font_id, &fontnum, &style);
8823 if (err != noErr)
8824 fontnum = -1;
c3bd8190
YM
8825 scriptcode = kTextEncodingMacUnicode;
8826 }
8827 else
c3bd8190 8828#endif
71b7a47f
YM
8829 {
8830 Lisp_Object tmp = Fassoc (build_string (family), fm_font_family_alist);
8831
8832 if (NILP (tmp))
8833 return NULL;
8834 fontnum = XINT (XCDR (tmp));
94d0e806 8835#if TARGET_API_MAC_CARBON
71b7a47f
YM
8836 if (FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
8837 return NULL;
8838 scriptcode = GetTextEncodingBase (encoding);
94d0e806 8839#else
71b7a47f 8840 scriptcode = FontToScript (fontnum);
94d0e806 8841#endif
c3bd8190 8842 }
177c0ea7 8843
1a578e9b 8844 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
177c0ea7 8845
1a578e9b
AC
8846 font->mac_fontnum = fontnum;
8847 font->mac_fontsize = size;
8848 font->mac_fontface = fontface;
94d0e806 8849 font->mac_scriptcode = scriptcode;
c3bd8190
YM
8850#if USE_ATSUI
8851 font->mac_style = mac_style;
16805b2e
YM
8852#if USE_CG_TEXT_DRAWING
8853 font->cg_font = NULL;
8854 font->cg_glyphs = NULL;
8855#endif
c3bd8190 8856#endif
1a578e9b 8857
199f9270 8858 /* Apple Japanese (SJIS) font is listed as both
2f64cf3a 8859 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
e0f712ba 8860 (Roman script) in init_font_name_table (). The latter should be
2f64cf3a 8861 treated as a one-byte font. */
94d0e806
YM
8862 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
8863 font->mac_scriptcode = smRoman;
199f9270 8864
71b7a47f 8865 font->full_name = mac_to_x_fontname (family, size, fontface, charset);
177c0ea7 8866
c3bd8190
YM
8867#if USE_ATSUI
8868 if (font->mac_style)
8869 {
3e7424f7 8870 OSStatus err;
b73e4d84 8871 UniChar c;
c3bd8190 8872
b73e4d84
YM
8873 font->min_byte1 = 0;
8874 font->max_byte1 = 0xff;
8875 font->min_char_or_byte2 = 0;
8876 font->max_char_or_byte2 = 0xff;
c3bd8190 8877
458dbb8c
YM
8878 font->bounds.rows = xmalloc (sizeof (XCharStruct *) * 0x100);
8879 bzero (font->bounds.rows, sizeof (XCharStruct *) * 0x100);
8880 font->bounds.rows[0] = xmalloc (sizeof (XCharStruct) * 0x100);
8881 pcm_init (font->bounds.rows[0], 0x100);
c3bd8190 8882
16805b2e 8883#if USE_CG_TEXT_DRAWING
68c767a3
YM
8884 if (fontnum != -1)
8885 {
8886 FMFontStyle style;
8887 ATSFontRef ats_font;
16805b2e 8888
68c767a3 8889 err = FMGetFontFromFontFamilyInstance (fontnum, fontface,
16805b2e 8890 &font_id, &style);
68c767a3
YM
8891 /* Use CG text drawing if italic/bold is not synthesized. */
8892 if (err == noErr && style == fontface)
8893 {
8894 ats_font = FMGetATSFontRefFromFont (font_id);
8895 font->cg_font = CGFontCreateWithPlatformFont (&ats_font);
8896 }
8897 }
16805b2e
YM
8898
8899 if (font->cg_font)
b96fe6ea
YM
8900 {
8901 font->cg_glyphs = xmalloc (sizeof (CGGlyph) * 0x100);
8902 bzero (font->cg_glyphs, sizeof (CGGlyph) * 0x100);
8903 }
16805b2e 8904#endif
458dbb8c 8905 space_bounds = font->bounds.rows[0] + 0x20;
b73e4d84
YM
8906 err = mac_query_char_extents (font->mac_style, 0x20,
8907 &font->ascent, &font->descent,
8908 space_bounds,
8909#if USE_CG_TEXT_DRAWING
8910 (font->cg_glyphs ? font->cg_glyphs + 0x20
8911 : NULL)
8912#else
8913 NULL
8914#endif
8915 );
7c682cf1
YM
8916 if (err != noErr
8917 || space_bounds->width <= 0 || FONT_HEIGHT (font) <= 0)
c3bd8190
YM
8918 {
8919 mac_unload_font (&one_mac_display_info, font);
8920 return NULL;
8921 }
8922
458dbb8c 8923 pcm = font->bounds.rows[0];
b73e4d84 8924 for (c = 0x21; c <= 0xff; c++)
c3bd8190 8925 {
16805b2e
YM
8926 if (c == 0xad)
8927 /* Soft hyphen is not supported in ATSUI. */
8928 continue;
8929 else if (c == 0x7f)
c3bd8190 8930 {
0d36bf23
YM
8931#if USE_CG_TEXT_DRAWING
8932 if (font->cg_glyphs)
8933 {
8934 c = 0x9f;
8935 pcm = NULL;
8936 continue;
8937 }
8938#endif
8939 break;
16805b2e 8940 }
c3bd8190 8941
0d36bf23
YM
8942 mac_query_char_extents (font->mac_style, c, NULL, NULL,
8943 pcm ? pcm + c : NULL,
b73e4d84
YM
8944#if USE_CG_TEXT_DRAWING
8945 (font->cg_glyphs ? font->cg_glyphs + c
8946 : NULL)
05f7d868 8947#else
b73e4d84 8948 NULL
05f7d868 8949#endif
b73e4d84 8950 );
c3bd8190 8951
16805b2e 8952#if USE_CG_TEXT_DRAWING
b73e4d84 8953 if (font->cg_glyphs && font->cg_glyphs[c] == 0)
16805b2e 8954 {
b73e4d84
YM
8955 /* Don't use CG text drawing if font substitution occurs in
8956 ASCII or Latin-1 characters. */
8957 CGFontRelease (font->cg_font);
8958 font->cg_font = NULL;
8959 xfree (font->cg_glyphs);
8960 font->cg_glyphs = NULL;
0d36bf23
YM
8961 if (pcm == NULL)
8962 break;
c3bd8190 8963 }
16805b2e 8964#endif
c3bd8190 8965 }
c3bd8190
YM
8966 }
8967 else
71b7a47f 8968#endif
c3bd8190 8969 {
0d36bf23 8970 OSStatus err;
71b7a47f
YM
8971 FontInfo the_fontinfo;
8972 int is_two_byte_font;
8973
444a42fd 8974#if USE_CG_DRAWING
bb420759 8975 mac_prepare_for_quickdraw (f);
c3bd8190 8976#endif
bb420759 8977 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1a578e9b 8978
71b7a47f
YM
8979 TextFont (fontnum);
8980 TextSize (size);
8981 TextFace (fontface);
177c0ea7 8982
71b7a47f 8983 GetFontInfo (&the_fontinfo);
1a578e9b 8984
71b7a47f
YM
8985 font->ascent = the_fontinfo.ascent;
8986 font->descent = the_fontinfo.descent;
1a578e9b 8987
71b7a47f
YM
8988 is_two_byte_font = (font->mac_scriptcode == smJapanese
8989 || font->mac_scriptcode == smTradChinese
8990 || font->mac_scriptcode == smSimpChinese
8991 || font->mac_scriptcode == smKorean);
c3bd8190 8992
71b7a47f
YM
8993 if (is_two_byte_font)
8994 {
b73e4d84
YM
8995 int char_width;
8996
71b7a47f
YM
8997 font->min_byte1 = 0xa1;
8998 font->max_byte1 = 0xfe;
8999 font->min_char_or_byte2 = 0xa1;
9000 font->max_char_or_byte2 = 0xfe;
9001
9002 /* Use the width of an "ideographic space" of that font
9003 because the_fontinfo.widMax returns the wrong width for
9004 some fonts. */
9005 switch (font->mac_scriptcode)
9006 {
9007 case smJapanese:
9008 font->min_byte1 = 0x81;
9009 font->max_byte1 = 0xfc;
9010 font->min_char_or_byte2 = 0x40;
9011 font->max_char_or_byte2 = 0xfc;
9012 char_width = StringWidth("\p\x81\x40");
9013 break;
9014 case smTradChinese:
9015 font->min_char_or_byte2 = 0x40;
9016 char_width = StringWidth("\p\xa1\x40");
9017 break;
9018 case smSimpChinese:
9019 char_width = StringWidth("\p\xa1\xa1");
9020 break;
9021 case smKorean:
9022 char_width = StringWidth("\p\xa1\xa1");
9023 break;
9024 }
1a578e9b 9025
b73e4d84 9026 font->bounds.per_char = NULL;
1a578e9b 9027
71b7a47f
YM
9028 if (fontface & italic)
9029 font->max_bounds.rbearing = char_width + 1;
9030 else
9031 font->max_bounds.rbearing = char_width;
9032 font->max_bounds.lbearing = 0;
9033 font->max_bounds.width = char_width;
9034 font->max_bounds.ascent = the_fontinfo.ascent;
9035 font->max_bounds.descent = the_fontinfo.descent;
1a578e9b 9036
71b7a47f
YM
9037 font->min_bounds = font->max_bounds;
9038 }
9039 else
9040 {
b73e4d84 9041 int c;
c3bd8190 9042
b73e4d84
YM
9043 font->min_byte1 = font->max_byte1 = 0;
9044 font->min_char_or_byte2 = 0x20;
9045 font->max_char_or_byte2 = 0xff;
c3bd8190 9046
b73e4d84
YM
9047 font->bounds.per_char =
9048 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
b73e4d84
YM
9049 bzero (font->bounds.per_char,
9050 sizeof (XCharStruct) * (0xff - 0x20 + 1));
9051
9052 space_bounds = font->bounds.per_char;
0d36bf23
YM
9053 err = mac_query_char_extents (NULL, 0x20, &font->ascent,
9054 &font->descent, space_bounds, NULL);
9055 if (err != noErr || space_bounds->width <= 0)
9056 {
9057 mac_unload_font (&one_mac_display_info, font);
9058 return NULL;
9059 }
b73e4d84
YM
9060
9061 for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++)
9062 mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL);
c3bd8190 9063 }
71b7a47f 9064 }
177c0ea7 9065
b73e4d84
YM
9066 if (space_bounds)
9067 {
9068 int c;
9069
9070 font->min_bounds = font->max_bounds = *space_bounds;
9071 for (c = 0x21, pcm = space_bounds + 1; c <= 0x7f; c++, pcm++)
9072 if (pcm->width > 0)
9073 {
9074 font->min_bounds.lbearing = min (font->min_bounds.lbearing,
9075 pcm->lbearing);
9076 font->min_bounds.rbearing = min (font->min_bounds.rbearing,
9077 pcm->rbearing);
9078 font->min_bounds.width = min (font->min_bounds.width,
9079 pcm->width);
9080 font->min_bounds.ascent = min (font->min_bounds.ascent,
9081 pcm->ascent);
cf2c6835
YM
9082 font->min_bounds.descent = min (font->min_bounds.descent,
9083 pcm->descent);
b73e4d84
YM
9084
9085 font->max_bounds.lbearing = max (font->max_bounds.lbearing,
9086 pcm->lbearing);
9087 font->max_bounds.rbearing = max (font->max_bounds.rbearing,
9088 pcm->rbearing);
9089 font->max_bounds.width = max (font->max_bounds.width,
9090 pcm->width);
9091 font->max_bounds.ascent = max (font->max_bounds.ascent,
9092 pcm->ascent);
cf2c6835
YM
9093 font->max_bounds.descent = max (font->max_bounds.descent,
9094 pcm->descent);
b73e4d84
YM
9095 }
9096 if (
9097#if USE_ATSUI
9098 font->mac_style == NULL &&
9099#endif
9100 font->max_bounds.width == font->min_bounds.width
9101 && font->min_bounds.lbearing >= 0
9102 && font->max_bounds.rbearing <= font->max_bounds.width)
9103 {
9104 /* Fixed width and no overhangs. */
9105 xfree (font->bounds.per_char);
9106 font->bounds.per_char = NULL;
9107 }
9108 }
9109
16805b2e
YM
9110#if !defined (MAC_OS8) || USE_ATSUI
9111 /* AppKit and WebKit do some adjustment to the heights of Courier,
9112 Helvetica, and Times. This only works on the environments where
9fb446e3
YM
9113 srcCopy text transfer mode is never used. */
9114 if (
9115#ifdef MAC_OS8 /* implies USE_ATSUI */
9116 font->mac_style &&
9117#endif
9118 (strcmp (family, "courier") == 0 || strcmp (family, "helvetica") == 0
9119 || strcmp (family, "times") == 0))
16805b2e
YM
9120 font->ascent += (font->ascent + font->descent) * .15 + 0.5;
9121#endif
9122
1a578e9b
AC
9123 return font;
9124}
9125
9126
b15325b2
ST
9127void
9128mac_unload_font (dpyinfo, font)
9129 struct mac_display_info *dpyinfo;
9130 XFontStruct *font;
9131{
94d0e806 9132 xfree (font->full_name);
c3bd8190
YM
9133#if USE_ATSUI
9134 if (font->mac_style)
b73e4d84
YM
9135 {
9136 int i;
9137
9138 for (i = font->min_byte1; i <= font->max_byte1; i++)
9139 if (font->bounds.rows[i])
9140 xfree (font->bounds.rows[i]);
9141 xfree (font->bounds.rows);
9142 ATSUDisposeStyle (font->mac_style);
9143 }
9144 else
9145#endif
9146 if (font->bounds.per_char)
9147 xfree (font->bounds.per_char);
16805b2e
YM
9148#if USE_CG_TEXT_DRAWING
9149 if (font->cg_font)
9150 CGFontRelease (font->cg_font);
9151 if (font->cg_glyphs)
9152 xfree (font->cg_glyphs);
c3bd8190 9153#endif
b15325b2
ST
9154 xfree (font);
9155}
9156
9157
1a578e9b
AC
9158/* Load font named FONTNAME of the size SIZE for frame F, and return a
9159 pointer to the structure font_info while allocating it dynamically.
9160 If SIZE is 0, load any size of font.
9161 If loading is failed, return NULL. */
9162
9163struct font_info *
9164x_load_font (f, fontname, size)
9165 struct frame *f;
9166 register char *fontname;
9167 int size;
9168{
9169 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9170 Lisp_Object font_names;
9171
9172 /* Get a list of all the fonts that match this name. Once we
9173 have a list of matching fonts, we compare them against the fonts
9174 we already have by comparing names. */
9175 font_names = x_list_fonts (f, build_string (fontname), size, 1);
9176
9177 if (!NILP (font_names))
9178 {
9179 Lisp_Object tail;
9180 int i;
9181
9182 for (i = 0; i < dpyinfo->n_fonts; i++)
9183 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
9184 if (dpyinfo->font_table[i].name
9185 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 9186 SDATA (XCAR (tail)))
1a578e9b 9187 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 9188 SDATA (XCAR (tail)))))
1a578e9b
AC
9189 return (dpyinfo->font_table + i);
9190 }
94d0e806
YM
9191 else
9192 return NULL;
1a578e9b
AC
9193
9194 /* Load the font and add it to the table. */
9195 {
1a578e9b
AC
9196 struct MacFontStruct *font;
9197 struct font_info *fontp;
1a578e9b
AC
9198 int i;
9199
94d0e806 9200 fontname = (char *) SDATA (XCAR (font_names));
1a578e9b 9201
b15325b2 9202 BLOCK_INPUT;
bb420759 9203 font = mac_load_query_font (f, fontname);
b15325b2 9204 UNBLOCK_INPUT;
1a578e9b
AC
9205 if (!font)
9206 return NULL;
9207
9208 /* Find a free slot in the font table. */
9209 for (i = 0; i < dpyinfo->n_fonts; ++i)
9210 if (dpyinfo->font_table[i].name == NULL)
9211 break;
9212
9213 /* If no free slot found, maybe enlarge the font table. */
9214 if (i == dpyinfo->n_fonts
9215 && dpyinfo->n_fonts == dpyinfo->font_table_size)
9216 {
9217 int sz;
9218 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
9219 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
9220 dpyinfo->font_table
9221 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
9222 }
9223
9224 fontp = dpyinfo->font_table + i;
9225 if (i == dpyinfo->n_fonts)
9226 ++dpyinfo->n_fonts;
9227
9228 /* Now fill in the slots of *FONTP. */
9229 BLOCK_INPUT;
6b61353c 9230 bzero (fontp, sizeof (*fontp));
1a578e9b
AC
9231 fontp->font = font;
9232 fontp->font_idx = i;
6abfb022 9233 fontp->charset = -1; /* fs_load_font sets it. */
94d0e806
YM
9234 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
9235 bcopy (fontname, fontp->name, strlen (fontname) + 1);
1a578e9b 9236
e169f939
ST
9237 if (font->min_bounds.width == font->max_bounds.width)
9238 {
9239 /* Fixed width font. */
9240 fontp->average_width = fontp->space_width = font->min_bounds.width;
9241 }
9242 else
9243 {
9244 XChar2b char2b;
9245 XCharStruct *pcm;
9246
9247 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
9248 pcm = mac_per_char_metric (font, &char2b, 0);
9249 if (pcm)
9250 fontp->space_width = pcm->width;
9251 else
9252 fontp->space_width = FONT_WIDTH (font);
9253
9254 if (pcm)
9255 {
9256 int width = pcm->width;
9257 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
9258 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
9259 width += pcm->width;
9260 fontp->average_width = width / 95;
9261 }
9262 else
9263 fontp->average_width = FONT_WIDTH (font);
9264 }
9265
94d0e806
YM
9266 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
9267 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
1a578e9b
AC
9268
9269 fontp->size = font->max_bounds.width;
9270 fontp->height = FONT_HEIGHT (font);
9271 {
9272 /* For some font, ascent and descent in max_bounds field is
9273 larger than the above value. */
9274 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
9275 if (max_height > fontp->height)
9276 fontp->height = max_height;
9277 }
9278
cc02ceee 9279 /* MAC_TODO: The script encoding is irrelevant in unicode? */
1a578e9b
AC
9280 /* The slot `encoding' specifies how to map a character
9281 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
9282 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
9283 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
9284 2:0xA020..0xFF7F). For the moment, we don't know which charset
6abfb022 9285 uses this font. So, we set information in fontp->encoding_type
1a578e9b
AC
9286 which is never used by any charset. If mapping can't be
9287 decided, set FONT_ENCODING_NOT_DECIDED. */
9288 if (font->mac_scriptcode == smJapanese)
6abfb022 9289 fontp->encoding_type = 4;
1a578e9b
AC
9290 else
9291 {
6abfb022 9292 fontp->encoding_type
1a578e9b
AC
9293 = (font->max_byte1 == 0
9294 /* 1-byte font */
9295 ? (font->min_char_or_byte2 < 0x80
9296 ? (font->max_char_or_byte2 < 0x80
9297 ? 0 /* 0x20..0x7F */
9298 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
9299 : 1) /* 0xA0..0xFF */
9300 /* 2-byte font */
9301 : (font->min_byte1 < 0x80
9302 ? (font->max_byte1 < 0x80
9303 ? (font->min_char_or_byte2 < 0x80
9304 ? (font->max_char_or_byte2 < 0x80
9305 ? 0 /* 0x2020..0x7F7F */
9306 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
9307 : 3) /* 0x20A0..0x7FFF */
9308 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
9309 : (font->min_char_or_byte2 < 0x80
9310 ? (font->max_char_or_byte2 < 0x80
9311 ? 2 /* 0xA020..0xFF7F */
9312 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
9313 : 1))); /* 0xA0A0..0xFFFF */
9314 }
9315
6abfb022 9316#if 0 /* MAC_TODO: fill these out with more reasonably values */
1a578e9b
AC
9317 fontp->baseline_offset
9318 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
9319 ? (long) value : 0);
9320 fontp->relative_compose
9321 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
9322 ? (long) value : 0);
9323 fontp->default_ascent
9324 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
9325 ? (long) value : 0);
9326#else
9327 fontp->baseline_offset = 0;
9328 fontp->relative_compose = 0;
9329 fontp->default_ascent = 0;
9330#endif
9331
9332 /* Set global flag fonts_changed_p to non-zero if the font loaded
9333 has a character with a smaller width than any other character
1f98fbb4 9334 before, or if the font loaded has a smaller height than any
1a578e9b
AC
9335 other font loaded before. If this happens, it will make a
9336 glyph matrix reallocation necessary. */
dd15724d 9337 fonts_changed_p |= x_compute_min_glyph_bounds (f);
1a578e9b
AC
9338 UNBLOCK_INPUT;
9339 return fontp;
9340 }
9341}
9342
9343
9344/* Return a pointer to struct font_info of a font named FONTNAME for
9345 frame F. If no such font is loaded, return NULL. */
9346
9347struct font_info *
9348x_query_font (f, fontname)
9349 struct frame *f;
9350 register char *fontname;
9351{
9352 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9353 int i;
9354
9355 for (i = 0; i < dpyinfo->n_fonts; i++)
9356 if (dpyinfo->font_table[i].name
3e7424f7
YM
9357 && (!xstricmp (dpyinfo->font_table[i].name, fontname)
9358 || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
1a578e9b
AC
9359 return (dpyinfo->font_table + i);
9360 return NULL;
9361}
9362
9363
9364/* Find a CCL program for a font specified by FONTP, and set the member
9365 `encoder' of the structure. */
9366
9367void
9368x_find_ccl_program (fontp)
9369 struct font_info *fontp;
9370{
9371 Lisp_Object list, elt;
9372
9373 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
9374 {
9375 elt = XCAR (list);
9376 if (CONSP (elt)
9377 && STRINGP (XCAR (elt))
9378 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
9379 >= 0))
9380 break;
9381 }
9382 if (! NILP (list))
9383 {
9384 struct ccl_program *ccl
9385 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
9386
9387 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
9388 xfree (ccl);
9389 else
9390 fontp->font_encoder = ccl;
9391 }
9392}
9393
68c767a3 9394#if USE_MAC_FONT_PANEL
36f0107c
YM
9395/* Whether Font Panel has been shown before. The first call to font
9396 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
9397 slow. This variable is used for deferring such a call as much as
9398 possible. */
b71c381c
YM
9399static int font_panel_shown_p = 0;
9400
7adf3143
YM
9401extern Lisp_Object Qfont;
9402static Lisp_Object Qpanel_closed, Qselection;
9403
9404static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
9405 Lisp_Object,
9406 Lisp_Object,
9407 EventRef, UInt32,
9408 const EventParamName *,
9409 const EventParamType *));
9410
b71c381c
YM
9411int
9412mac_font_panel_visible_p ()
9413{
9414 return font_panel_shown_p && FPIsFontPanelVisible ();
9415}
9416
7adf3143
YM
9417static pascal OSStatus
9418mac_handle_font_event (next_handler, event, data)
9419 EventHandlerCallRef next_handler;
9420 EventRef event;
9421 void *data;
9422{
9423 OSStatus result, err;
9424 Lisp_Object id_key;
9425 int num_params;
9426 const EventParamName *names;
9427 const EventParamType *types;
9428 static const EventParamName names_sel[] = {kEventParamATSUFontID,
9429 kEventParamATSUFontSize,
9430 kEventParamFMFontFamily,
7b7d07bb 9431 kEventParamFMFontStyle,
7adf3143
YM
9432 kEventParamFMFontSize,
9433 kEventParamFontColor};
9434 static const EventParamType types_sel[] = {typeATSUFontID,
9435 typeATSUSize,
9436 typeFMFontFamily,
7b7d07bb 9437 typeFMFontStyle,
7adf3143
YM
9438 typeFMFontSize,
9439 typeFontColor};
9440
9441 result = CallNextEventHandler (next_handler, event);
9442 if (result != eventNotHandledErr)
9443 return result;
9444
9445 switch (GetEventKind (event))
9446 {
9447 case kEventFontPanelClosed:
9448 id_key = Qpanel_closed;
9449 num_params = 0;
9450 names = NULL;
9451 types = NULL;
9452 break;
9453
9454 case kEventFontSelection:
9455 id_key = Qselection;
9456 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
9457 names = names_sel;
9458 types = types_sel;
9459 break;
9460 }
9461
9462 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
9463 event, num_params,
9464 names, types);
9465 if (err == noErr)
9466 result = noErr;
9467
9468 return result;
9469}
9470
b71c381c
YM
9471OSStatus
9472mac_show_hide_font_panel ()
9473{
7adf3143
YM
9474 if (!font_panel_shown_p)
9475 {
9476 OSStatus err;
9477
9478 static const EventTypeSpec specs[] =
9479 {{kEventClassFont, kEventFontPanelClosed},
9480 {kEventClassFont, kEventFontSelection}};
9481
9482 err = InstallApplicationEventHandler (mac_handle_font_event,
9483 GetEventTypeCount (specs),
9484 specs, NULL, NULL);
9485 if (err != noErr)
9486 return err;
9487
9488 font_panel_shown_p = 1;
9489 }
b71c381c
YM
9490
9491 return FPShowHideFontPanel ();
9492}
9493
68c767a3 9494OSStatus
4cb62a90 9495mac_set_font_info_for_selection (f, face_id, c)
68c767a3 9496 struct frame *f;
4cb62a90 9497 int face_id, c;
68c767a3
YM
9498{
9499 OSStatus err;
4cb62a90
YM
9500 EventTargetRef target = NULL;
9501 XFontStruct *font = NULL;
68c767a3 9502
b71c381c
YM
9503 if (!mac_font_panel_visible_p ())
9504 return noErr;
9505
4cb62a90 9506 if (f)
68c767a3 9507 {
4cb62a90 9508 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
68c767a3 9509
4cb62a90
YM
9510 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
9511 {
9512 struct face *face;
9513
9514 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
9515 face = FACE_FROM_ID (f, face_id);
9516 font = face->font;
9517 }
9518 }
9519
9520 if (font == NULL)
9521 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
9522 else
9523 {
9524 if (font->mac_fontnum != -1)
68c767a3
YM
9525 {
9526 FontSelectionQDStyle qd_style;
9527
9528 qd_style.version = kFontSelectionQDStyleVersionZero;
4cb62a90
YM
9529 qd_style.instance.fontFamily = font->mac_fontnum;
9530 qd_style.instance.fontStyle = font->mac_fontface;
9531 qd_style.size = font->mac_fontsize;
68c767a3
YM
9532 qd_style.hasColor = false;
9533
9534 err = SetFontInfoForSelection (kFontSelectionQDType,
9535 1, &qd_style, target);
9536 }
9537 else
9538 err = SetFontInfoForSelection (kFontSelectionATSUIType,
4cb62a90 9539 1, &font->mac_style, target);
68c767a3
YM
9540 }
9541
9542 return err;
9543}
9544#endif
1a578e9b
AC
9545
9546\f
1a578e9b
AC
9547/* The Mac Event loop code */
9548
25c9622b 9549#if !TARGET_API_MAC_CARBON
1a578e9b
AC
9550#include <Events.h>
9551#include <Quickdraw.h>
9552#include <Balloons.h>
9553#include <Devices.h>
9554#include <Fonts.h>
9555#include <Gestalt.h>
9556#include <Menus.h>
9557#include <Processes.h>
9558#include <Sound.h>
9559#include <ToolUtils.h>
9560#include <TextUtils.h>
9561#include <Dialogs.h>
9562#include <Script.h>
1a578e9b 9563#include <Types.h>
1a578e9b
AC
9564#include <Resources.h>
9565
9566#if __MWERKS__
9567#include <unix.h>
9568#endif
25c9622b 9569#endif /* ! TARGET_API_MAC_CARBON */
1a578e9b 9570
20a1fc8b 9571#define M_APPLE 234
1a578e9b
AC
9572#define I_ABOUT 1
9573
1a578e9b
AC
9574#define DEFAULT_NUM_COLS 80
9575
9576#define MIN_DOC_SIZE 64
9577#define MAX_DOC_SIZE 32767
9578
1a578e9b
AC
9579#define EXTRA_STACK_ALLOC (256 * 1024)
9580
9581#define ARGV_STRING_LIST_ID 129
9582#define ABOUT_ALERT_ID 128
2e875e36 9583#define RAM_TOO_LARGE_ALERT_ID 129
1a578e9b 9584
6b61353c
KH
9585/* Contains the string "reverse", which is a constant for mouse button emu.*/
9586Lisp_Object Qreverse;
9587
1a578e9b 9588
b02e3f7b
ST
9589/* Modifier associated with the control key, or nil to ignore. */
9590Lisp_Object Vmac_control_modifier;
9591
9592/* Modifier associated with the option key, or nil to ignore. */
a36f1680
JW
9593Lisp_Object Vmac_option_modifier;
9594
b02e3f7b
ST
9595/* Modifier associated with the command key, or nil to ignore. */
9596Lisp_Object Vmac_command_modifier;
9597
9598/* Modifier associated with the function key, or nil to ignore. */
9599Lisp_Object Vmac_function_modifier;
742fbed7 9600
6b61353c
KH
9601/* True if the option and command modifiers should be used to emulate
9602 a three button mouse */
9603Lisp_Object Vmac_emulate_three_button_mouse;
9604
3354caee 9605#if TARGET_API_MAC_CARBON
70ed951a 9606/* Non-zero if the mouse wheel button (i.e. button 4) should map to
742fbed7 9607 mouse-2, instead of mouse-3. */
70ed951a 9608int mac_wheel_button_is_mouse_2;
5883787c 9609
70ed951a 9610/* If non-zero, the Mac "Command" key is passed on to the Mac Toolbox
5883787c 9611 for processing before Emacs sees it. */
70ed951a 9612int mac_pass_command_to_system;
5883787c 9613
70ed951a 9614/* If non-zero, the Mac "Control" key is passed on to the Mac Toolbox
5883787c 9615 for processing before Emacs sees it. */
70ed951a 9616int mac_pass_control_to_system;
1f98fbb4 9617#endif
95085023
YM
9618
9619/* Points to the variable `inev' in the function XTread_socket. It is
95dfb192
YM
9620 used for passing an input event to the function back from
9621 Carbon/Apple event handlers. */
95085023 9622static struct input_event *read_socket_inev = NULL;
742fbed7 9623
19ee09cc
YM
9624/* Whether or not the screen configuration has changed. */
9625static int mac_screen_config_changed = 0;
9626
1a578e9b
AC
9627Point saved_menu_event_location;
9628
9629/* Apple Events */
3354caee 9630#if TARGET_API_MAC_CARBON
3e7424f7 9631static Lisp_Object Qhi_command;
68c767a3
YM
9632#ifdef MAC_OSX
9633extern Lisp_Object Qwindow;
9634static Lisp_Object Qtoolbar_switch_mode;
9635#endif
02236cbc
YM
9636#if USE_MAC_TSM
9637static TSMDocumentID tsm_document_id;
9638static Lisp_Object Qtext_input;
9639static Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
9640static Lisp_Object Vmac_ts_active_input_overlay;
9641extern Lisp_Object Qbefore_string;
b4c51596 9642static Lisp_Object Vmac_ts_script_language_on_focus;
92289429 9643static Lisp_Object saved_ts_script_language_on_focus;
b4c51596
YM
9644static ScriptLanguageRecord saved_ts_language;
9645static Component saved_ts_component;
02236cbc 9646#endif
7adf3143 9647#endif /* TARGET_API_MAC_CARBON */
6a0b5d37
YM
9648extern int mac_ready_for_apple_events;
9649extern Lisp_Object Qundefined;
9650extern void init_apple_event_handler P_ ((void));
9651extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID,
9652 Lisp_Object *, Lisp_Object *,
9653 Lisp_Object *));
0e0a1663 9654extern OSErr init_coercion_handler P_ ((void));
742fbed7
AC
9655
9656/* Drag and Drop */
e2d3b7e1
YM
9657extern OSErr install_drag_handler P_ ((WindowRef));
9658extern void remove_drag_handler P_ ((WindowRef));
9659
7adf3143 9660#if TARGET_API_MAC_CARBON
e2d3b7e1 9661/* Showing help echo string during menu tracking */
7adf3143 9662extern OSStatus install_menu_target_item_handler P_ ((void));
742fbed7 9663
25c9622b 9664#ifdef MAC_OSX
7adf3143 9665extern OSStatus install_service_handler ();
4cb62a90 9666static Lisp_Object Qservice, Qpaste, Qperform;
25c9622b 9667#endif
742fbed7 9668#endif
1a578e9b
AC
9669
9670extern void init_emacs_passwd_dir ();
9671extern int emacs_main (int, char **, char **);
1a578e9b
AC
9672
9673extern void initialize_applescript();
9674extern void terminate_applescript();
9675
1e53bd0e
YM
9676/* Table for translating Mac keycode to X keysym values. Contributed
9677 by Sudhir Shenoy.
9678 Mapping for special keys is now identical to that in Apple X11
9679 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9680 on the right of the Cmd key on laptops, and fn + `enter' (->
9681 <linefeed>). */
369a7a37 9682static const unsigned char keycode_to_xkeysym_table[] = {
1e53bd0e
YM
9683 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9684 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9685 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9686
9687 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9688 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9689 /*0x38*/ 0, 0, 0, 0,
9690 /*0x3C*/ 0, 0, 0, 0,
9691
9692 /*0x40*/ 0, 0xae /*kp-decimal*/, 0, 0xaa /*kp-multiply*/,
9693 /*0x44*/ 0, 0xab /*kp-add*/, 0, 0x0b /*clear*/,
9694 /*0x48*/ 0, 0, 0, 0xaf /*kp-divide*/,
9695 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp-subtract*/, 0,
9696
9697 /*0x50*/ 0, 0xbd /*kp-equal*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9698 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9699 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9700 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9701
9702 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9703 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9704 /*0x68*/ 0, 0xca /*f13*/, 0xcd /*f16*/, 0xcb /*f14*/,
9705 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9706
9707 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9708 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9709 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9710 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9711};
9712
9713#ifdef MAC_OSX
9714/* Table for translating Mac keycode with the laptop `fn' key to that
9715 without it. Destination symbols in comments are keys on US
9716 keyboard, and they may not be the same on other types of keyboards.
9717 If the destination is identical to the source (f1 ... f12), it
9718 doesn't map `fn' key to a modifier. */
369a7a37 9719static const unsigned char fn_keycode_to_keycode_table[] = {
1e53bd0e
YM
9720 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9721 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9722 /*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9723
9724 /*0x30*/ 0, 0, 0, 0,
9725 /*0x34*/ 0, 0, 0, 0,
9726 /*0x38*/ 0, 0, 0, 0,
9727 /*0x3C*/ 0, 0, 0, 0,
9728
9729 /*0x40*/ 0, 0x2f /*kp-decimal -> '.'*/, 0, 0x23 /*kp-multiply -> 'p'*/,
9730 /*0x44*/ 0, 0x2c /*kp-add -> '/'*/, 0, 0x16 /*clear -> '6'*/,
9731 /*0x48*/ 0, 0, 0, 0x1d /*kp-/ -> '0'*/,
9732 /*0x4C*/ 0x24 /*kp-enter -> return*/, 0, 0x29 /*kp-subtract -> ';'*/, 0,
9733
9734 /*0x50*/ 0, 0x1b /*kp-equal -> '-'*/, 0x2e /*kp-0 -> 'm'*/, 0x26 /*kp-1 -> 'j'*/,
9735 /*0x54*/ 0x28 /*kp-2 -> 'k'*/, 0x25 /*kp-3 -> 'l'*/, 0x20 /*kp-4 -> 'u'*/, 0x22 /*kp-5 ->'i'*/,
9736 /*0x58*/ 0x1f /*kp-6 -> 'o'*/, 0x1a /*kp-7 -> '7'*/, 0, 0x1c /*kp-8 -> '8'*/,
9737 /*0x5C*/ 0x19 /*kp-9 -> '9'*/, 0, 0, 0,
9738
9739 /*0x60*/ 0x60 /*f5 = f5*/, 0x61 /*f6 = f6*/, 0x62 /*f7 = f7*/, 0x63 /*f3 = f3*/,
9740 /*0x64*/ 0x64 /*f8 = f8*/, 0x65 /*f9 = f9*/, 0, 0x67 /*f11 = f11*/,
9741 /*0x68*/ 0, 0, 0, 0,
9742 /*0x6C*/ 0, 0x6d /*f10 = f10*/, 0, 0x6f /*f12 = f12*/,
9743
9744 /*0x70*/ 0, 0, 0, 0x7b /*home -> left*/,
9745 /*0x74*/ 0x7e /*pgup -> up*/, 0x33 /*delete -> backspace*/, 0x76 /*f4 = f4*/, 0x7c /*end -> right*/,
9746 /*0x78*/ 0x78 /*f2 = f2*/, 0x7d /*pgdown -> down*/, 0x7a /*f1 = f1*/, 0,
9747 /*0x7C*/ 0, 0, 0, 0
9748};
9749#endif /* MAC_OSX */
9750
a84cad70 9751static int
3354caee 9752#if TARGET_API_MAC_CARBON
742fbed7
AC
9753mac_to_emacs_modifiers (UInt32 mods)
9754#else
9755mac_to_emacs_modifiers (EventModifiers mods)
9756#endif
9757{
9758 unsigned int result = 0;
b02e3f7b 9759 if (mods & shiftKey)
742fbed7 9760 result |= shift_modifier;
16805b2e 9761
b02e3f7b
ST
9762 /* Deactivated to simplify configuration:
9763 if Vmac_option_modifier is non-NIL, we fully process the Option
9764 key. Otherwise, we only process it if an additional Ctrl or Command
16805b2e 9765 is pressed. That way the system may convert the character to a
b02e3f7b
ST
9766 composed one.
9767 if ((mods & optionKey) &&
16805b2e 9768 (( !NILP(Vmac_option_modifier) ||
b02e3f7b
ST
9769 ((mods & cmdKey) || (mods & controlKey))))) */
9770
a36f1680 9771 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
b02e3f7b
ST
9772 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
9773 if (INTEGERP(val))
9774 result |= XUINT(val);
a36f1680 9775 }
b02e3f7b
ST
9776 if (!NILP (Vmac_command_modifier) && (mods & cmdKey)) {
9777 Lisp_Object val = Fget(Vmac_command_modifier, Qmodifier_value);
9778 if (INTEGERP(val))
9779 result |= XUINT(val);
a36f1680 9780 }
b02e3f7b
ST
9781 if (!NILP (Vmac_control_modifier) && (mods & controlKey)) {
9782 Lisp_Object val = Fget(Vmac_control_modifier, Qmodifier_value);
9783 if (INTEGERP(val))
9784 result |= XUINT(val);
16805b2e 9785 }
a36f1680 9786
b02e3f7b
ST
9787#ifdef MAC_OSX
9788 if (!NILP (Vmac_function_modifier) && (mods & kEventKeyModifierFnMask)) {
9789 Lisp_Object val = Fget(Vmac_function_modifier, Qmodifier_value);
9790 if (INTEGERP(val))
9791 result |= XUINT(val);
16805b2e 9792 }
b02e3f7b 9793#endif
a36f1680 9794
742fbed7
AC
9795 return result;
9796}
9797
a84cad70
YM
9798static UInt32
9799mac_mapped_modifiers (modifiers)
9800 UInt32 modifiers;
9801{
9802 UInt32 mapped_modifiers_all =
9803 (NILP (Vmac_control_modifier) ? 0 : controlKey)
9804 | (NILP (Vmac_option_modifier) ? 0 : optionKey)
9805 | (NILP (Vmac_command_modifier) ? 0 : cmdKey);
9806
9807#ifdef MAC_OSX
9808 mapped_modifiers_all |=
9809 (NILP (Vmac_function_modifier) ? 0 : kEventKeyModifierFnMask);
9810#endif
9811
9812 return mapped_modifiers_all & modifiers;
9813}
9814
6b61353c
KH
9815static int
9816mac_get_emulated_btn ( UInt32 modifiers )
9817{
9818 int result = 0;
a433994a
ST
9819 if (!NILP (Vmac_emulate_three_button_mouse)) {
9820 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
c61278bb 9821 if (modifiers & cmdKey)
6b61353c
KH
9822 result = cmdIs3 ? 2 : 1;
9823 else if (modifiers & optionKey)
ffe8b3f4 9824 result = cmdIs3 ? 1 : 2;
6b61353c
KH
9825 }
9826 return result;
9827}
9828
c857519f
YM
9829#if TARGET_API_MAC_CARBON
9830/***** Code to handle C-g testing *****/
9831extern int quit_char;
9832extern int make_ctrl_char P_ ((int));
9833
9834int
9835mac_quit_char_key_p (modifiers, key_code)
9836 UInt32 modifiers, key_code;
9837{
9838 UInt32 char_code;
9839 unsigned long some_state = 0;
9840 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
9841 int c, emacs_modifiers;
9842
9843 /* Mask off modifier keys that are mapped to some Emacs modifiers. */
9844 key_code |= (modifiers & ~(mac_mapped_modifiers (modifiers)));
9845 char_code = KeyTranslate (kchr_ptr, key_code, &some_state);
9846 if (char_code & ~0xff)
9847 return 0;
9848
9849 emacs_modifiers = mac_to_emacs_modifiers (modifiers);
9850 if (emacs_modifiers & ctrl_modifier)
9851 c = make_ctrl_char (char_code);
9852
9853 c |= (emacs_modifiers
9854 & (meta_modifier | alt_modifier
9855 | hyper_modifier | super_modifier));
9856
9857 return c == quit_char;
9858}
9859#endif
9860
3354caee 9861#if TARGET_API_MAC_CARBON
742fbed7
AC
9862/* Obtains the event modifiers from the event ref and then calls
9863 mac_to_emacs_modifiers. */
a84cad70 9864static int
177c0ea7 9865mac_event_to_emacs_modifiers (EventRef eventRef)
742fbed7 9866{
7adf3143
YM
9867 UInt32 mods = 0, class;
9868
742fbed7
AC
9869 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
9870 sizeof (UInt32), NULL, &mods);
7adf3143 9871 class = GetEventClass (eventRef);
a433994a 9872 if (!NILP (Vmac_emulate_three_button_mouse) &&
7adf3143 9873 (class == kEventClassMouse || class == kEventClassCommand))
6b61353c 9874 {
c61278bb 9875 mods &= ~(optionKey | cmdKey);
6b61353c 9876 }
742fbed7
AC
9877 return mac_to_emacs_modifiers (mods);
9878}
9879
9880/* Given an event ref, return the code to use for the mouse button
9881 code in the emacs input_event. */
9882static int
177c0ea7 9883mac_get_mouse_btn (EventRef ref)
742fbed7
AC
9884{
9885 EventMouseButton result = kEventMouseButtonPrimary;
9886 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
9887 sizeof (EventMouseButton), NULL, &result);
177c0ea7 9888 switch (result)
742fbed7
AC
9889 {
9890 case kEventMouseButtonPrimary:
a433994a 9891 if (NILP (Vmac_emulate_three_button_mouse))
6b61353c
KH
9892 return 0;
9893 else {
9894 UInt32 mods = 0;
9895 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
9896 sizeof (UInt32), NULL, &mods);
9897 return mac_get_emulated_btn(mods);
9898 }
742fbed7 9899 case kEventMouseButtonSecondary:
70ed951a 9900 return mac_wheel_button_is_mouse_2 ? 2 : 1;
742fbed7
AC
9901 case kEventMouseButtonTertiary:
9902 case 4: /* 4 is the number for the mouse wheel button */
70ed951a 9903 return mac_wheel_button_is_mouse_2 ? 1 : 2;
742fbed7
AC
9904 default:
9905 return 0;
9906 }
9907}
9908
9909/* Normally, ConvertEventRefToEventRecord will correctly handle all
9910 events. However the click of the mouse wheel is not converted to a
e4f5123f
YM
9911 mouseDown or mouseUp event. Likewise for dead key events. This
9912 calls ConvertEventRefToEventRecord, but then checks to see if it is
9913 a mouse up/down, or a dead key Carbon event that has not been
95085023
YM
9914 converted, and if so, converts it by hand (to be picked up in the
9915 XTread_socket loop). */
177c0ea7 9916static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
742fbed7 9917{
a3510ffa 9918 OSStatus err;
742fbed7 9919 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
e4f5123f 9920 EventKind action;
95085023
YM
9921
9922 if (result)
9923 return result;
9924
9925 switch (GetEventClass (eventRef))
177c0ea7 9926 {
95085023
YM
9927 case kEventClassMouse:
9928 switch (GetEventKind (eventRef))
742fbed7 9929 {
95085023 9930 case kEventMouseDown:
742fbed7 9931 eventRec->what = mouseDown;
95085023
YM
9932 result = 1;
9933 break;
9934
9935 case kEventMouseUp:
742fbed7 9936 eventRec->what = mouseUp;
95085023
YM
9937 result = 1;
9938 break;
9939
9940 default:
9941 break;
742fbed7 9942 }
92de1e01 9943 break;
95085023
YM
9944
9945 case kEventClassKeyboard:
9946 switch (GetEventKind (eventRef))
742fbed7 9947 {
95085023 9948 case kEventRawKeyDown:
e4f5123f
YM
9949 action = keyDown;
9950 goto keystroke_common;
9951 case kEventRawKeyRepeat:
9952 action = autoKey;
9953 goto keystroke_common;
9954 case kEventRawKeyUp:
9955 action = keyUp;
9956 keystroke_common:
95085023
YM
9957 {
9958 unsigned char char_codes;
9959 UInt32 key_code;
9960
a3510ffa
YM
9961 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
9962 typeChar, NULL, sizeof (char),
9963 NULL, &char_codes);
9964 if (err == noErr)
9965 err = GetEventParameter (eventRef, kEventParamKeyCode,
9966 typeUInt32, NULL, sizeof (UInt32),
9967 NULL, &key_code);
9968 if (err == noErr)
9969 {
e4f5123f 9970 eventRec->what = action;
a3510ffa
YM
9971 eventRec->message = char_codes | ((key_code & 0xff) << 8);
9972 result = 1;
9973 }
95085023
YM
9974 }
9975 break;
9976
9977 default:
9978 break;
742fbed7 9979 }
92de1e01 9980 break;
95085023
YM
9981
9982 default:
9983 break;
742fbed7 9984 }
95085023
YM
9985
9986 if (result)
9987 {
9988 /* Need where and when. */
a3510ffa 9989 UInt32 mods = 0;
95085023
YM
9990
9991 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
9992 NULL, sizeof (Point), NULL, &eventRec->where);
9993 /* Use two step process because new event modifiers are 32-bit
9994 and old are 16-bit. Currently, only loss is NumLock & Fn. */
9995 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
9996 NULL, sizeof (UInt32), NULL, &mods);
9997 eventRec->modifiers = mods;
9998
9999 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
10000 }
10001
742fbed7
AC
10002 return result;
10003}
10004
10005#endif
1a578e9b 10006
f93e4d4f 10007#ifdef MAC_OS8
1a578e9b
AC
10008static void
10009do_get_menus (void)
10010{
10011 Handle menubar_handle;
3354caee 10012 MenuRef menu;
177c0ea7 10013
1a578e9b
AC
10014 menubar_handle = GetNewMBar (128);
10015 if(menubar_handle == NULL)
10016 abort ();
10017 SetMenuBar (menubar_handle);
10018 DrawMenuBar ();
10019
1c05c15b 10020#if !TARGET_API_MAC_CARBON
3354caee
YM
10021 menu = GetMenuRef (M_APPLE);
10022 if (menu != NULL)
10023 AppendResMenu (menu, 'DRVR');
1a578e9b
AC
10024 else
10025 abort ();
1c05c15b 10026#endif
1a578e9b
AC
10027}
10028
10029
10030static void
10031do_init_managers (void)
10032{
e0f712ba 10033#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10034 InitGraf (&qd.thePort);
10035 InitFonts ();
10036 FlushEvents (everyEvent, 0);
10037 InitWindows ();
10038 InitMenus ();
10039 TEInit ();
10040 InitDialogs (NULL);
e0f712ba
AC
10041#endif /* !TARGET_API_MAC_CARBON */
10042 InitCursor ();
177c0ea7 10043
e0f712ba 10044#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10045 /* set up some extra stack space for use by emacs */
10046 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
10047
10048 /* MaxApplZone must be called for AppleScript to execute more
10049 complicated scripts */
10050 MaxApplZone ();
10051 MoreMasters ();
e0f712ba 10052#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
10053}
10054
2e875e36
AC
10055static void
10056do_check_ram_size (void)
10057{
10058 SInt32 physical_ram_size, logical_ram_size;
177c0ea7 10059
2e875e36
AC
10060 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
10061 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
6b61353c
KH
10062 || physical_ram_size > (1 << VALBITS)
10063 || logical_ram_size > (1 << VALBITS))
2e875e36
AC
10064 {
10065 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
10066 exit (1);
10067 }
10068}
f93e4d4f 10069#endif /* MAC_OS8 */
2e875e36 10070
1a578e9b 10071static void
3354caee 10072do_window_update (WindowRef win)
1a578e9b 10073{
50bf7673
ST
10074 struct frame *f = mac_window_to_frame (win);
10075
b15325b2 10076 BeginUpdate (win);
1a578e9b 10077
b15325b2
ST
10078 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
10079 below. */
10080 if (win != tip_window)
1a578e9b
AC
10081 {
10082 if (f->async_visible == 0)
10083 {
1f98fbb4
YM
10084 /* Update events may occur when a frame gets iconified. */
10085#if 0
1a578e9b
AC
10086 f->async_visible = 1;
10087 f->async_iconified = 0;
10088 SET_FRAME_GARBAGED (f);
1f98fbb4 10089#endif
1a578e9b
AC
10090 }
10091 else
1f98fbb4 10092 {
b15325b2 10093 Rect r;
b15325b2 10094#if TARGET_API_MAC_CARBON
1f98fbb4 10095 RgnHandle region = NewRgn ();
2d97ff8c 10096
1f98fbb4
YM
10097 GetPortVisibleRegion (GetWindowPort (win), region);
10098 GetRegionBounds (region, &r);
10099 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
a84cad70
YM
10100#if USE_CG_DRAWING
10101 mac_prepare_for_quickdraw (f);
10102#endif
1f98fbb4
YM
10103 UpdateControls (win, region);
10104 DisposeRgn (region);
b15325b2 10105#else
b15325b2 10106 r = (*win->visRgn)->rgnBBox;
b15325b2 10107 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
b69efa23
YM
10108 UpdateControls (win, win->visRgn);
10109#endif
1f98fbb4 10110 }
1a578e9b 10111 }
b15325b2
ST
10112
10113 EndUpdate (win);
1a578e9b
AC
10114}
10115
e0f712ba 10116static int
3354caee 10117is_emacs_window (WindowRef win)
e0f712ba
AC
10118{
10119 Lisp_Object tail, frame;
10120
10121 if (!win)
10122 return 0;
10123
10124 FOR_EACH_FRAME (tail, frame)
10125 if (FRAME_MAC_P (XFRAME (frame)))
10126 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
10127 return 1;
10128
10129 return 0;
10130}
10131
02236cbc 10132#if USE_MAC_TSM
b4c51596
YM
10133static OSStatus
10134mac_tsm_resume ()
10135{
10136 OSStatus err;
10137 ScriptLanguageRecord slrec, *slptr = NULL;
10138
10139 err = ActivateTSMDocument (tsm_document_id);
10140
10141 if (err == noErr)
10142 {
92289429
YM
10143 if (EQ (Vmac_ts_script_language_on_focus, Qt)
10144 && EQ (saved_ts_script_language_on_focus, Qt))
b4c51596
YM
10145 slptr = &saved_ts_language;
10146 else if (CONSP (Vmac_ts_script_language_on_focus)
10147 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
92289429
YM
10148 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))
10149 && CONSP (saved_ts_script_language_on_focus)
10150 && EQ (XCAR (saved_ts_script_language_on_focus),
10151 XCAR (Vmac_ts_script_language_on_focus))
10152 && EQ (XCDR (saved_ts_script_language_on_focus),
10153 XCDR (Vmac_ts_script_language_on_focus)))
b4c51596
YM
10154 {
10155 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10156 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10157 slptr = &slrec;
10158 }
10159 }
10160
10161 if (slptr)
10162 {
10163#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10164 err = SetDefaultInputMethodOfClass (saved_ts_component, slptr,
10165 kKeyboardInputMethodClass);
10166#else
10167 err = SetDefaultInputMethod (saved_ts_component, slptr);
02236cbc 10168#endif
b4c51596
YM
10169 if (err == noErr)
10170 err = SetTextServiceLanguage (slptr);
10171
10172 /* Seems to be needed on Mac OS X 10.2. */
10173 if (err == noErr)
10174 KeyScript (slptr->fScript | smKeyForceKeyScriptMask);
10175 }
10176
10177 return err;
1a578e9b
AC
10178}
10179
b4c51596
YM
10180static OSStatus
10181mac_tsm_suspend ()
1a578e9b 10182{
b4c51596
YM
10183 OSStatus err;
10184 ScriptLanguageRecord slrec, *slptr = NULL;
10185
92289429
YM
10186 saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus;
10187
b4c51596
YM
10188 if (EQ (Vmac_ts_script_language_on_focus, Qt))
10189 {
10190 err = GetTextServiceLanguage (&saved_ts_language);
10191 if (err == noErr)
10192 slptr = &saved_ts_language;
10193 }
10194 else if (CONSP (Vmac_ts_script_language_on_focus)
10195 && INTEGERP (XCAR (Vmac_ts_script_language_on_focus))
10196 && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)))
10197 {
10198 slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus));
10199 slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus));
10200 slptr = &slrec;
10201 }
10202
10203 if (slptr)
10204 {
10205#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10206 GetDefaultInputMethodOfClass (&saved_ts_component, slptr,
10207 kKeyboardInputMethodClass);
10208#else
10209 GetDefaultInputMethod (&saved_ts_component, slptr);
02236cbc 10210#endif
b4c51596 10211 }
1a578e9b 10212
b4c51596
YM
10213 err = DeactivateTSMDocument (tsm_document_id);
10214
10215 return err;
10216}
10217#endif
1a578e9b 10218
20a1fc8b
YM
10219#if !TARGET_API_MAC_CARBON
10220void
1a578e9b
AC
10221do_apple_menu (SInt16 menu_item)
10222{
10223 Str255 item_name;
10224 SInt16 da_driver_refnum;
177c0ea7 10225
1a578e9b
AC
10226 if (menu_item == I_ABOUT)
10227 NoteAlert (ABOUT_ALERT_ID, NULL);
10228 else
10229 {
3354caee 10230 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
1a578e9b
AC
10231 da_driver_refnum = OpenDeskAcc (item_name);
10232 }
1a578e9b 10233}
20a1fc8b 10234#endif /* !TARGET_API_MAC_CARBON */
1a578e9b
AC
10235
10236/* Handle drags in size box. Based on code contributed by Ben
10237 Mesander and IM - Window Manager A. */
10238
10239static void
369a7a37 10240do_grow_window (w, e)
3354caee 10241 WindowRef w;
369a7a37 10242 const EventRecord *e;
1a578e9b 10243{
1a578e9b 10244 Rect limit_rect;
b15325b2 10245 int rows, columns, width, height;
50bf7673 10246 struct frame *f = mac_window_to_frame (w);
b15325b2
ST
10247 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
10248 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
10249#if TARGET_API_MAC_CARBON
10250 Rect new_rect;
10251#else
10252 long grow_size;
10253#endif
177c0ea7 10254
b15325b2
ST
10255 if (size_hints->flags & PMinSize)
10256 {
10257 min_width = size_hints->min_width;
10258 min_height = size_hints->min_height;
10259 }
10260 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
177c0ea7 10261
b15325b2
ST
10262#if TARGET_API_MAC_CARBON
10263 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
10264 return;
10265 height = new_rect.bottom - new_rect.top;
10266 width = new_rect.right - new_rect.left;
10267#else
1a578e9b 10268 grow_size = GrowWindow (w, e->where, &limit_rect);
1a578e9b 10269 /* see if it really changed size */
b15325b2
ST
10270 if (grow_size == 0)
10271 return;
10272 height = HiWord (grow_size);
10273 width = LoWord (grow_size);
10274#endif
10275
10276 if (width != FRAME_PIXEL_WIDTH (f)
10277 || height != FRAME_PIXEL_HEIGHT (f))
1a578e9b 10278 {
b15325b2
ST
10279 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10280 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
177c0ea7 10281
1a578e9b
AC
10282 x_set_window_size (f, 0, columns, rows);
10283 }
10284}
10285
10286
bed0bf95
YM
10287#if TARGET_API_MAC_CARBON
10288static Point
10289mac_get_ideal_size (f)
10290 struct frame *f;
10291{
10292 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3354caee 10293 WindowRef w = FRAME_MAC_WINDOW (f);
bed0bf95
YM
10294 Point ideal_size;
10295 Rect standard_rect;
10296 int height, width, columns, rows;
10297
10298 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
10299 ideal_size.v = dpyinfo->height;
10300 IsWindowInStandardState (w, &ideal_size, &standard_rect);
10301 /* Adjust the standard size according to character boundaries. */
10302 width = standard_rect.right - standard_rect.left;
10303 height = standard_rect.bottom - standard_rect.top;
10304 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
10305 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
10306 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
10307 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10308
10309 return ideal_size;
10310}
10311#endif
10312
1a578e9b
AC
10313/* Handle clicks in zoom box. Calculation of "standard state" based
10314 on code in IM - Window Manager A and code contributed by Ben
10315 Mesander. The standard state of an Emacs window is 80-characters
10316 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
10317
10318static void
3354caee 10319do_zoom_window (WindowRef w, int zoom_in_or_out)
1a578e9b 10320{
1a578e9b 10321 Rect zoom_rect, port_rect;
bed0bf95 10322 int width, height;
50bf7673 10323 struct frame *f = mac_window_to_frame (w);
e0f712ba 10324#if TARGET_API_MAC_CARBON
bed0bf95 10325 Point ideal_size = mac_get_ideal_size (f);
e0f712ba 10326
bed0bf95
YM
10327 GetWindowBounds (w, kWindowContentRgn, &port_rect);
10328 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
10329 && port_rect.left == zoom_rect.left
10330 && port_rect.top == zoom_rect.top)
f93e4d4f
YM
10331 zoom_in_or_out = inZoomIn;
10332 else
bed0bf95 10333 zoom_in_or_out = inZoomOut;
f93e4d4f 10334
bed0bf95
YM
10335#ifdef MAC_OS8
10336 mac_clear_window (f);
10337#endif
10338 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
e0f712ba 10339#else /* not TARGET_API_MAC_CARBON */
f93e4d4f
YM
10340 GrafPtr save_port;
10341 Point top_left;
bed0bf95
YM
10342 int w_title_height, rows;
10343 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
f93e4d4f 10344
bf06c82f
ST
10345 GetPort (&save_port);
10346
10347 SetPortWindowPort (w);
10348
10349 /* Clear window to avoid flicker. */
e0f712ba 10350 EraseRect (&(w->portRect));
1a578e9b
AC
10351 if (zoom_in_or_out == inZoomOut)
10352 {
e0f712ba 10353 SetPt (&top_left, w->portRect.left, w->portRect.top);
1a578e9b
AC
10354 LocalToGlobal (&top_left);
10355
10356 /* calculate height of window's title bar */
10357 w_title_height = top_left.v - 1
e0f712ba 10358 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1a578e9b
AC
10359
10360 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
10361 zoom_rect = qd.screenBits.bounds;
10362 zoom_rect.top += w_title_height;
10363 InsetRect (&zoom_rect, 8, 4); /* not too tight */
177c0ea7 10364
1a578e9b 10365 zoom_rect.right = zoom_rect.left
f1a83aab 10366 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1a578e9b 10367
bf06c82f
ST
10368 /* Adjust the standard size according to character boundaries. */
10369 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
10370 zoom_rect.bottom =
10371 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
10372
e0f712ba
AC
10373 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
10374 = zoom_rect;
1a578e9b
AC
10375 }
10376
7ca7ccd5 10377 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
bf06c82f
ST
10378
10379 SetPort (save_port);
10380#endif /* not TARGET_API_MAC_CARBON */
1a578e9b 10381
3354caee 10382#if !TARGET_API_MAC_CARBON
1a578e9b
AC
10383 /* retrieve window size and update application values */
10384 port_rect = w->portRect;
b15325b2
ST
10385 height = port_rect.bottom - port_rect.top;
10386 width = port_rect.right - port_rect.left;
1a578e9b 10387
bed0bf95
YM
10388 mac_handle_size_change (f, width, height);
10389 mac_handle_origin_change (f);
10390#endif
742fbed7 10391}
1a578e9b 10392
7adf3143
YM
10393static void
10394mac_set_unicode_keystroke_event (code, buf)
10395 UniChar code;
10396 struct input_event *buf;
10397{
10398 int charset_id, c1, c2;
10399
10400 if (code < 0x80)
10401 {
10402 buf->kind = ASCII_KEYSTROKE_EVENT;
10403 buf->code = code;
10404 }
10405 else if (code < 0x100)
10406 {
10407 if (code < 0xA0)
10408 charset_id = CHARSET_8_BIT_CONTROL;
10409 else
10410 charset_id = charset_latin_iso8859_1;
10411 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10412 buf->code = MAKE_CHAR (charset_id, code, 0);
10413 }
10414 else
10415 {
10416 if (code < 0x2500)
10417 charset_id = charset_mule_unicode_0100_24ff,
10418 code -= 0x100;
10419 else if (code < 0x33FF)
10420 charset_id = charset_mule_unicode_2500_33ff,
10421 code -= 0x2500;
10422 else if (code >= 0xE000)
10423 charset_id = charset_mule_unicode_e000_ffff,
10424 code -= 0xE000;
10425 c1 = (code / 96) + 32, c2 = (code % 96) + 32;
10426 buf->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10427 buf->code = MAKE_CHAR (charset_id, c1, c2);
10428 }
10429}
10430
10431static void
10432do_keystroke (action, char_code, key_code, modifiers, timestamp, buf)
10433 EventKind action;
10434 unsigned char char_code;
10435 UInt32 key_code, modifiers;
10436 unsigned long timestamp;
10437 struct input_event *buf;
10438{
10439 static SInt16 last_key_script = -1;
10440 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
10441 UInt32 mapped_modifiers = mac_mapped_modifiers (modifiers);
10442
10443#ifdef MAC_OSX
10444 if (mapped_modifiers & kEventKeyModifierFnMask
10445 && key_code <= 0x7f
10446 && fn_keycode_to_keycode_table[key_code])
10447 key_code = fn_keycode_to_keycode_table[key_code];
10448#endif
10449
10450 if (key_code <= 0x7f && keycode_to_xkeysym_table[key_code])
10451 {
10452 buf->kind = NON_ASCII_KEYSTROKE_EVENT;
10453 buf->code = 0xff00 | keycode_to_xkeysym_table[key_code];
10454#ifdef MAC_OSX
10455 if (modifiers & kEventKeyModifierFnMask
10456 && key_code <= 0x7f
10457 && fn_keycode_to_keycode_table[key_code] == key_code)
10458 modifiers &= ~kEventKeyModifierFnMask;
10459#endif
10460 }
10461 else if (mapped_modifiers)
10462 {
10463 /* translate the keycode back to determine the original key */
10464#ifdef MAC_OSX
10465 UCKeyboardLayout *uchr_ptr = NULL;
10466#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10467 OSStatus err;
10468 KeyboardLayoutRef layout;
10469
10470 err = KLGetCurrentKeyboardLayout (&layout);
10471 if (err == noErr)
10472 err = KLGetKeyboardLayoutProperty (layout, kKLuchrData,
10473 (const void **) &uchr_ptr);
10474#else
10475 static SInt16 last_key_layout_id = 0;
10476 static Handle uchr_handle = (Handle)-1;
10477 SInt16 current_key_layout_id =
10478 GetScriptVariable (current_key_script, smScriptKeys);
10479
10480 if (uchr_handle == (Handle)-1
10481 || last_key_layout_id != current_key_layout_id)
10482 {
10483 uchr_handle = GetResource ('uchr', current_key_layout_id);
10484 last_key_layout_id = current_key_layout_id;
10485 }
10486 if (uchr_handle)
10487 uchr_ptr = (UCKeyboardLayout *)*uchr_handle;
10488#endif
10489
10490 if (uchr_ptr)
10491 {
10492 OSStatus status;
10493 UInt16 key_action = action - keyDown;
10494 UInt32 modifier_key_state = (modifiers & ~mapped_modifiers) >> 8;
10495 UInt32 keyboard_type = LMGetKbdType ();
10496 SInt32 dead_key_state = 0;
10497 UniChar code;
10498 UniCharCount actual_length;
10499
10500 status = UCKeyTranslate (uchr_ptr, key_code, key_action,
10501 modifier_key_state, keyboard_type,
10502 kUCKeyTranslateNoDeadKeysMask,
10503 &dead_key_state,
10504 1, &actual_length, &code);
10505 if (status == noErr && actual_length == 1)
10506 mac_set_unicode_keystroke_event (code, buf);
10507 }
10508#endif /* MAC_OSX */
10509
10510 if (buf->kind == NO_EVENT)
10511 {
10512 /* This code comes from Keyboard Resource, Appendix C of IM
10513 - Text. This is necessary since shift is ignored in KCHR
10514 table translation when option or command is pressed. It
10515 also does not translate correctly control-shift chars
10516 like C-% so mask off shift here also. */
10517 /* Mask off modifier keys that are mapped to some Emacs
10518 modifiers. */
10519 int new_modifiers = modifiers & ~mapped_modifiers;
10520 /* set high byte of keycode to modifier high byte*/
10521 int new_key_code = key_code | new_modifiers;
10522 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
10523 unsigned long some_state = 0;
10524 UInt32 new_char_code;
10525
10526 new_char_code = KeyTranslate (kchr_ptr, new_key_code, &some_state);
10527 if (new_char_code == 0)
10528 /* Seems like a dead key. Append up-stroke. */
10529 new_char_code = KeyTranslate (kchr_ptr, new_key_code | 0x80,
10530 &some_state);
10531 if (new_char_code)
10532 {
10533 buf->kind = ASCII_KEYSTROKE_EVENT;
10534 buf->code = new_char_code & 0xff;
10535 }
10536 }
10537 }
10538
10539 if (buf->kind == NO_EVENT)
10540 {
10541 buf->kind = ASCII_KEYSTROKE_EVENT;
10542 buf->code = char_code;
10543 }
10544
10545 buf->modifiers = mac_to_emacs_modifiers (modifiers);
10546 buf->modifiers |= (extra_keyboard_modifiers
10547 & (meta_modifier | alt_modifier
10548 | hyper_modifier | super_modifier));
10549
10550#if TARGET_API_MAC_CARBON
10551 if (buf->kind == ASCII_KEYSTROKE_EVENT
10552 && buf->code >= 0x80 && buf->modifiers)
10553 {
10554 OSStatus err;
10555 TextEncoding encoding = kTextEncodingMacRoman;
10556 TextToUnicodeInfo ttu_info;
10557
10558 UpgradeScriptInfoToTextEncoding (current_key_script,
10559 kTextLanguageDontCare,
10560 kTextRegionDontCare,
10561 NULL, &encoding);
10562 err = CreateTextToUnicodeInfoByEncoding (encoding, &ttu_info);
10563 if (err == noErr)
10564 {
10565 UniChar code;
10566 Str255 pstr;
10567 ByteCount unicode_len;
10568
10569 pstr[0] = 1;
10570 pstr[1] = buf->code;
10571 err = ConvertFromPStringToUnicode (ttu_info, pstr,
10572 sizeof (UniChar),
10573 &unicode_len, &code);
10574 if (err == noErr && unicode_len == sizeof (UniChar))
10575 mac_set_unicode_keystroke_event (code, buf);
10576 DisposeTextToUnicodeInfo (&ttu_info);
10577 }
10578 }
10579#endif
10580
10581 if (buf->kind == ASCII_KEYSTROKE_EVENT
10582 && buf->code >= 0x80
10583 && last_key_script != current_key_script)
10584 {
10585 struct input_event event;
10586
10587 EVENT_INIT (event);
10588 event.kind = LANGUAGE_CHANGE_EVENT;
10589 event.arg = Qnil;
10590 event.code = current_key_script;
10591 event.timestamp = timestamp;
10592 kbd_buffer_store_event (&event);
10593 last_key_script = current_key_script;
10594 }
10595}
10596
a733ef16 10597void
6a0b5d37
YM
10598mac_store_apple_event (class, id, desc)
10599 Lisp_Object class, id;
10600 const AEDesc *desc;
742fbed7 10601{
1c05c15b 10602 struct input_event buf;
742fbed7 10603
a733ef16 10604 EVENT_INIT (buf);
1c05c15b 10605
a733ef16
YM
10606 buf.kind = MAC_APPLE_EVENT;
10607 buf.x = class;
10608 buf.y = id;
10609 XSETFRAME (buf.frame_or_window,
10610 mac_focus_frame (&one_mac_display_info));
10611 /* Now that Lisp object allocations are protected by BLOCK_INPUT, it
10612 is safe to use them during read_socket_hook. */
10613 buf.arg = mac_aedesc_to_lisp (desc);
10614 kbd_buffer_store_event (&buf);
6a0b5d37 10615}
1c05c15b 10616
a733ef16 10617#if TARGET_API_MAC_CARBON
68c767a3
YM
10618static OSStatus
10619mac_store_event_ref_as_apple_event (class, id, class_key, id_key,
10620 event, num_params, names, types)
10621 AEEventClass class;
10622 AEEventID id;
10623 Lisp_Object class_key, id_key;
10624 EventRef event;
10625 UInt32 num_params;
369a7a37
YM
10626 const EventParamName *names;
10627 const EventParamType *types;
68c767a3
YM
10628{
10629 OSStatus err = eventNotHandledErr;
10630 Lisp_Object binding;
10631
10632 mac_find_apple_event_spec (class, id, &class_key, &id_key, &binding);
10633 if (!NILP (binding) && !EQ (binding, Qundefined))
10634 {
10635 if (INTEGERP (binding))
10636 err = XINT (binding);
10637 else
10638 {
10639 AppleEvent apple_event;
10640 err = create_apple_event_from_event_ref (event, num_params,
10641 names, types,
10642 &apple_event);
10643 if (err == noErr)
10644 {
10645 mac_store_apple_event (class_key, id_key, &apple_event);
10646 AEDisposeDesc (&apple_event);
0d36bf23 10647 mac_wakeup_from_rne ();
68c767a3
YM
10648 }
10649 }
6a0b5d37 10650 }
1c05c15b 10651
6a0b5d37
YM
10652 return err;
10653}
1c05c15b 10654
a733ef16
YM
10655void
10656mac_store_drag_event (window, mouse_pos, modifiers, desc)
10657 WindowRef window;
10658 Point mouse_pos;
10659 SInt16 modifiers;
10660 const AEDesc *desc;
6a0b5d37 10661{
a733ef16 10662 struct input_event buf;
1c05c15b 10663
a733ef16 10664 EVENT_INIT (buf);
b15325b2 10665
a733ef16
YM
10666 buf.kind = DRAG_N_DROP_EVENT;
10667 buf.modifiers = mac_to_emacs_modifiers (modifiers);
10668 buf.timestamp = TickCount () * (1000 / 60);
10669 XSETINT (buf.x, mouse_pos.h);
10670 XSETINT (buf.y, mouse_pos.v);
10671 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
10672 buf.arg = mac_aedesc_to_lisp (desc);
10673 kbd_buffer_store_event (&buf);
1c05c15b
YM
10674}
10675
7adf3143
YM
10676#ifdef MAC_OSX
10677OSStatus
10678mac_store_service_event (event)
1c05c15b 10679 EventRef event;
1c05c15b 10680{
7adf3143
YM
10681 OSStatus err;
10682 Lisp_Object id_key;
10683 int num_params;
10684 const EventParamName *names;
10685 const EventParamType *types;
10686 static const EventParamName names_pfm[] =
10687 {kEventParamServiceMessageName, kEventParamServiceUserData};
10688 static const EventParamType types_pfm[] =
10689 {typeCFStringRef, typeCFStringRef};
1c05c15b 10690
7adf3143
YM
10691 switch (GetEventKind (event))
10692 {
10693 case kEventServicePaste:
10694 id_key = Qpaste;
10695 num_params = 0;
10696 names = NULL;
10697 types = NULL;
10698 break;
1c05c15b 10699
7adf3143
YM
10700 case kEventServicePerform:
10701 id_key = Qperform;
10702 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
10703 names = names_pfm;
10704 types = types_pfm;
10705 break;
1c05c15b 10706
7adf3143
YM
10707 default:
10708 abort ();
10709 }
1c05c15b 10710
7adf3143
YM
10711 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
10712 event, num_params,
10713 names, types);
1c05c15b 10714
7adf3143 10715 return err;
1c05c15b 10716}
7adf3143 10717#endif /* MAC_OSX */
1c05c15b 10718
b15325b2
ST
10719static pascal OSStatus
10720mac_handle_window_event (next_handler, event, data)
10721 EventHandlerCallRef next_handler;
10722 EventRef event;
10723 void *data;
10724{
3354caee 10725 WindowRef wp;
7adf3143 10726 OSStatus err, result = eventNotHandledErr;
bed0bf95 10727 struct frame *f;
b15325b2
ST
10728 UInt32 attributes;
10729 XSizeHints *size_hints;
10730
a3510ffa 10731 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
3354caee 10732 NULL, sizeof (WindowRef), NULL, &wp);
a3510ffa
YM
10733 if (err != noErr)
10734 return eventNotHandledErr;
b15325b2 10735
bed0bf95 10736 f = mac_window_to_frame (wp);
b15325b2
ST
10737 switch (GetEventKind (event))
10738 {
7adf3143
YM
10739 /* -- window refresh events -- */
10740
e0e76ab9
ST
10741 case kEventWindowUpdate:
10742 result = CallNextEventHandler (next_handler, event);
10743 if (result != eventNotHandledErr)
7adf3143 10744 break;
e0e76ab9
ST
10745
10746 do_window_update (wp);
7adf3143
YM
10747 result = noErr;
10748 break;
e0e76ab9 10749
7adf3143 10750 /* -- window state change events -- */
bed0bf95 10751
7adf3143
YM
10752 case kEventWindowShowing:
10753 size_hints = FRAME_SIZE_HINTS (f);
10754 if (!(size_hints->flags & (USPosition | PPosition)))
10755 {
10756 struct frame *sf = SELECTED_FRAME ();
bed0bf95 10757
ad3b3e02 10758 if (!(FRAME_MAC_P (sf) && sf->async_visible))
7adf3143
YM
10759 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
10760 else
10761 {
10762 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
10763#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
10764 kWindowCascadeStartAtParentWindowScreen
10765#else
10766 kWindowCascadeOnParentWindowScreen
10767#endif
10768 );
c6829f81
YM
10769#if USE_MAC_TOOLBAR
10770 /* This is a workaround. RepositionWindow fails to put
10771 a window at the cascading position when its parent
10772 window has a Carbon HIToolbar. */
f9426479
YM
10773 if ((f->left_pos == sf->left_pos
10774 && f->top_pos == sf->top_pos)
10775 || (f->left_pos == sf->left_pos + 10 * 2
10776 && f->top_pos == sf->top_pos + 32 * 2))
ad3b3e02 10777 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
c6829f81 10778#endif
7adf3143
YM
10779 }
10780 result = noErr;
10781 }
10782 break;
10783
10784 case kEventWindowHiding:
10785 /* Before unmapping the window, update the WM_SIZE_HINTS
10786 property to claim that the current position of the window is
10787 user-specified, rather than program-specified, so that when
10788 the window is mapped again, it will be placed at the same
10789 location, without forcing the user to position it by hand
10790 again (they have already done that once for this window.) */
10791 x_wm_set_size_hint (f, (long) 0, 1);
10792 result = noErr;
10793 break;
10794
10795 case kEventWindowShown:
10796 case kEventWindowHidden:
10797 case kEventWindowCollapsed:
10798 case kEventWindowExpanded:
10799 mac_handle_visibility_change (f);
10800 result = noErr;
bed0bf95
YM
10801 break;
10802
b15325b2
ST
10803 case kEventWindowBoundsChanging:
10804 result = CallNextEventHandler (next_handler, event);
10805 if (result != eventNotHandledErr)
7adf3143 10806 break;
b15325b2 10807
a3510ffa
YM
10808 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
10809 NULL, sizeof (UInt32), NULL, &attributes);
10810 if (err != noErr)
10811 break;
10812
bed0bf95 10813 size_hints = FRAME_SIZE_HINTS (f);
b15325b2
ST
10814 if ((attributes & kWindowBoundsChangeUserResize)
10815 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
10816 == (PResizeInc | PBaseSize | PMinSize)))
10817 {
10818 Rect bounds;
10819 int width, height;
10820
a3510ffa
YM
10821 err = GetEventParameter (event, kEventParamCurrentBounds,
10822 typeQDRectangle, NULL, sizeof (Rect),
10823 NULL, &bounds);
10824 if (err != noErr)
10825 break;
10826
b15325b2
ST
10827 width = bounds.right - bounds.left;
10828 height = bounds.bottom - bounds.top;
10829
10830 if (width < size_hints->min_width)
10831 width = size_hints->min_width;
10832 else
10833 width = size_hints->base_width
10834 + (int) ((width - size_hints->base_width)
10835 / (float) size_hints->width_inc + .5)
10836 * size_hints->width_inc;
10837
10838 if (height < size_hints->min_height)
10839 height = size_hints->min_height;
10840 else
10841 height = size_hints->base_height
10842 + (int) ((height - size_hints->base_height)
10843 / (float) size_hints->height_inc + .5)
10844 * size_hints->height_inc;
10845
10846 bounds.right = bounds.left + width;
10847 bounds.bottom = bounds.top + height;
10848 SetEventParameter (event, kEventParamCurrentBounds,
10849 typeQDRectangle, sizeof (Rect), &bounds);
7adf3143 10850 result = noErr;
b15325b2
ST
10851 }
10852 break;
1f98fbb4 10853
bed0bf95
YM
10854 case kEventWindowBoundsChanged:
10855 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
10856 NULL, sizeof (UInt32), NULL, &attributes);
10857 if (err != noErr)
10858 break;
10859
10860 if (attributes & kWindowBoundsChangeSizeChanged)
10861 {
10862 Rect bounds;
10863
10864 err = GetEventParameter (event, kEventParamCurrentBounds,
10865 typeQDRectangle, NULL, sizeof (Rect),
10866 NULL, &bounds);
10867 if (err == noErr)
10868 {
10869 int width, height;
10870
10871 width = bounds.right - bounds.left;
10872 height = bounds.bottom - bounds.top;
10873 mac_handle_size_change (f, width, height);
262be72a 10874 mac_wakeup_from_rne ();
bed0bf95
YM
10875 }
10876 }
10877
10878 if (attributes & kWindowBoundsChangeOriginChanged)
10879 mac_handle_origin_change (f);
10880
7adf3143 10881 result = noErr;
1f98fbb4 10882 break;
68c767a3 10883
7adf3143
YM
10884 /* -- window action events -- */
10885
750a6cf4
YM
10886 case kEventWindowClose:
10887 {
10888 struct input_event buf;
10889
10890 EVENT_INIT (buf);
10891 buf.kind = DELETE_WINDOW_EVENT;
bed0bf95 10892 XSETFRAME (buf.frame_or_window, f);
750a6cf4
YM
10893 buf.arg = Qnil;
10894 kbd_buffer_store_event (&buf);
10895 }
7adf3143
YM
10896 result = noErr;
10897 break;
10898
10899 case kEventWindowGetIdealSize:
10900 result = CallNextEventHandler (next_handler, event);
10901 if (result != eventNotHandledErr)
10902 break;
10903
10904 {
10905 Point ideal_size = mac_get_ideal_size (f);
10906
10907 err = SetEventParameter (event, kEventParamDimensions,
10908 typeQDPoint, sizeof (Point), &ideal_size);
10909 if (err == noErr)
10910 result = noErr;
10911 }
10912 break;
750a6cf4 10913
68c767a3
YM
10914#ifdef MAC_OSX
10915 case kEventWindowToolbarSwitchMode:
68c767a3 10916 {
369a7a37
YM
10917 static const EventParamName names[] = {kEventParamDirectObject,
10918 kEventParamWindowMouseLocation,
10919 kEventParamKeyModifiers,
10920 kEventParamMouseButton,
10921 kEventParamClickCount,
10922 kEventParamMouseChord};
10923 static const EventParamType types[] = {typeWindowRef,
10924 typeQDPoint,
10925 typeUInt32,
10926 typeMouseButton,
10927 typeUInt32,
10928 typeUInt32};
68c767a3
YM
10929 int num_params = sizeof (names) / sizeof (names[0]);
10930
10931 err = mac_store_event_ref_as_apple_event (0, 0,
10932 Qwindow,
10933 Qtoolbar_switch_mode,
10934 event, num_params,
10935 names, types);
10936 }
7adf3143
YM
10937 if (err == noErr)
10938 result = noErr;
10939 break;
68c767a3 10940#endif
02236cbc
YM
10941
10942#if USE_MAC_TSM
7adf3143
YM
10943 /* -- window focus events -- */
10944
02236cbc 10945 case kEventWindowFocusAcquired:
b4c51596 10946 err = mac_tsm_resume ();
7adf3143
YM
10947 if (err == noErr)
10948 result = noErr;
10949 break;
02236cbc
YM
10950
10951 case kEventWindowFocusRelinquish:
b4c51596 10952 err = mac_tsm_suspend ();
7adf3143
YM
10953 if (err == noErr)
10954 result = noErr;
10955 break;
10956#endif
10957
10958 default:
10959 abort ();
10960 }
10961
10962 return result;
10963}
10964
10965static pascal OSStatus
10966mac_handle_application_event (next_handler, event, data)
10967 EventHandlerCallRef next_handler;
10968 EventRef event;
10969 void *data;
10970{
10971 OSStatus err, result = eventNotHandledErr;
10972
10973 switch (GetEventKind (event))
10974 {
10975#if USE_MAC_TSM
10976 case kEventAppActivated:
10977 err = mac_tsm_resume ();
10978 break;
10979
10980 case kEventAppDeactivated:
10981 err = mac_tsm_suspend ();
10982 break;
10983#endif
10984
10985 default:
10986 abort ();
10987 }
10988
10989 if (err == noErr)
10990 result = noErr;
10991
10992 return result;
10993}
10994
10995static pascal OSStatus
10996mac_handle_keyboard_event (next_handler, event, data)
10997 EventHandlerCallRef next_handler;
10998 EventRef event;
10999 void *data;
11000{
11001 OSStatus err, result = eventNotHandledErr;
7b7d07bb 11002 UInt32 event_kind, key_code, modifiers;
7adf3143
YM
11003 unsigned char char_code;
11004
11005 event_kind = GetEventKind (event);
11006 switch (event_kind)
11007 {
11008 case kEventRawKeyDown:
11009 case kEventRawKeyRepeat:
11010 case kEventRawKeyUp:
7adf3143
YM
11011 /* When using Carbon Events, we need to pass raw keyboard events
11012 to the TSM ourselves. If TSM handles it, it will pass back
11013 noErr, otherwise it will pass back "eventNotHandledErr" and
11014 we can process it normally. */
7b7d07bb
YM
11015 result = CallNextEventHandler (next_handler, event);
11016 if (result != eventNotHandledErr)
11017 break;
11018
11019 if (read_socket_inev == NULL)
11020 break;
7adf3143
YM
11021
11022#if USE_MAC_TSM
11023 if (read_socket_inev->kind != NO_EVENT)
11024 {
11025 result = noErr;
11026 break;
11027 }
02236cbc 11028#endif
7adf3143
YM
11029
11030 if (event_kind == kEventRawKeyUp)
11031 break;
11032
11033 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
11034 typeChar, NULL,
11035 sizeof (char), NULL, &char_code);
11036 if (err != noErr)
11037 break;
11038
11039 err = GetEventParameter (event, kEventParamKeyCode,
11040 typeUInt32, NULL,
11041 sizeof (UInt32), NULL, &key_code);
11042 if (err != noErr)
11043 break;
11044
7b7d07bb
YM
11045 err = GetEventParameter (event, kEventParamKeyModifiers,
11046 typeUInt32, NULL,
11047 sizeof (UInt32), NULL, &modifiers);
11048 if (err != noErr)
11049 break;
11050
c6829f81 11051 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
7adf3143
YM
11052 char_code, key_code, modifiers,
11053 ((unsigned long)
11054 (GetEventTime (event) / kEventDurationMillisecond)),
11055 read_socket_inev);
11056 result = noErr;
11057 break;
11058
11059 default:
11060 abort ();
11061 }
11062
11063 return result;
11064}
11065
11066static pascal OSStatus
11067mac_handle_command_event (next_handler, event, data)
11068 EventHandlerCallRef next_handler;
11069 EventRef event;
11070 void *data;
11071{
11072 OSStatus err, result = eventNotHandledErr;
11073 HICommand command;
11074 static const EventParamName names[] =
11075 {kEventParamDirectObject, kEventParamKeyModifiers};
11076 static const EventParamType types[] =
11077 {typeHICommand, typeUInt32};
11078 int num_params = sizeof (names) / sizeof (names[0]);
11079
11080 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
11081 NULL, sizeof (HICommand), NULL, &command);
11082 if (err != noErr)
11083 return eventNotHandledErr;
11084
11085 switch (GetEventKind (event))
11086 {
11087 case kEventCommandProcess:
11088 result = CallNextEventHandler (next_handler, event);
11089 if (result != eventNotHandledErr)
11090 break;
11091
11092 err = GetEventParameter (event, kEventParamDirectObject,
11093 typeHICommand, NULL,
11094 sizeof (HICommand), NULL, &command);
11095
11096 if (err != noErr || command.commandID == 0)
11097 break;
11098
11099 /* A HI command event is mapped to an Apple event whose event
11100 class symbol is `hi-command' and event ID is its command
11101 ID. */
11102 err = mac_store_event_ref_as_apple_event (0, command.commandID,
11103 Qhi_command, Qnil,
11104 event, num_params,
11105 names, types);
11106 if (err == noErr)
11107 result = noErr;
11108 break;
11109
11110 default:
11111 abort ();
b15325b2
ST
11112 }
11113
7adf3143 11114 return result;
b15325b2 11115}
95085023
YM
11116
11117static pascal OSStatus
11118mac_handle_mouse_event (next_handler, event, data)
11119 EventHandlerCallRef next_handler;
11120 EventRef event;
11121 void *data;
11122{
7adf3143 11123 OSStatus err, result = eventNotHandledErr;
95085023
YM
11124
11125 switch (GetEventKind (event))
11126 {
11127 case kEventMouseWheelMoved:
11128 {
3354caee 11129 WindowRef wp;
95085023
YM
11130 struct frame *f;
11131 EventMouseWheelAxis axis;
11132 SInt32 delta;
11133 Point point;
11134
11135 result = CallNextEventHandler (next_handler, event);
11136 if (result != eventNotHandledErr || read_socket_inev == NULL)
7adf3143
YM
11137 break;
11138
11139 f = mac_focus_frame (&one_mac_display_info);
95085023 11140
a3510ffa
YM
11141 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
11142 NULL, sizeof (WindowRef), NULL, &wp);
7adf3143
YM
11143 if (err != noErr
11144 || wp != FRAME_MAC_WINDOW (f))
95085023
YM
11145 break;
11146
a3510ffa
YM
11147 err = GetEventParameter (event, kEventParamMouseWheelAxis,
11148 typeMouseWheelAxis, NULL,
11149 sizeof (EventMouseWheelAxis), NULL, &axis);
11150 if (err != noErr || axis != kEventMouseWheelAxisY)
95085023
YM
11151 break;
11152
a3510ffa
YM
11153 err = GetEventParameter (event, kEventParamMouseLocation,
11154 typeQDPoint, NULL, sizeof (Point),
11155 NULL, &point);
11156 if (err != noErr)
11157 break;
5bc21f35 11158
7adf3143
YM
11159 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
11160 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
5bc21f35
YM
11161 if (point.h < 0 || point.v < 0
11162 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
11163 f->tool_bar_window))
11164 break;
11165
11166 err = GetEventParameter (event, kEventParamMouseWheelDelta,
11167 typeSInt32, NULL, sizeof (SInt32),
11168 NULL, &delta);
11169 if (err != noErr)
11170 break;
11171
95085023
YM
11172 read_socket_inev->kind = WHEEL_EVENT;
11173 read_socket_inev->code = 0;
11174 read_socket_inev->modifiers =
11175 (mac_event_to_emacs_modifiers (event)
11176 | ((delta < 0) ? down_modifier : up_modifier));
95085023
YM
11177 XSETINT (read_socket_inev->x, point.h);
11178 XSETINT (read_socket_inev->y, point.v);
11179 XSETFRAME (read_socket_inev->frame_or_window, f);
95085023 11180
7adf3143 11181 result = noErr;
95085023
YM
11182 }
11183 break;
11184
11185 default:
7adf3143 11186 abort ();
68c767a3
YM
11187 }
11188
7adf3143 11189 return result;
68c767a3 11190}
68c767a3 11191
02236cbc
YM
11192#if USE_MAC_TSM
11193static pascal OSStatus
11194mac_handle_text_input_event (next_handler, event, data)
11195 EventHandlerCallRef next_handler;
11196 EventRef event;
11197 void *data;
11198{
a56dd283 11199 OSStatus err, result;
02236cbc
YM
11200 Lisp_Object id_key = Qnil;
11201 int num_params;
369a7a37
YM
11202 const EventParamName *names;
11203 const EventParamType *types;
02236cbc 11204 static UInt32 seqno_uaia = 0;
369a7a37 11205 static const EventParamName names_uaia[] =
02236cbc
YM
11206 {kEventParamTextInputSendComponentInstance,
11207 kEventParamTextInputSendRefCon,
11208 kEventParamTextInputSendSLRec,
11209 kEventParamTextInputSendFixLen,
11210 kEventParamTextInputSendText,
11211 kEventParamTextInputSendUpdateRng,
11212 kEventParamTextInputSendHiliteRng,
11213 kEventParamTextInputSendClauseRng,
11214 kEventParamTextInputSendPinRng,
11215 kEventParamTextInputSendTextServiceEncoding,
11216 kEventParamTextInputSendTextServiceMacEncoding,
11217 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
369a7a37 11218 static const EventParamType types_uaia[] =
02236cbc
YM
11219 {typeComponentInstance,
11220 typeLongInteger,
11221 typeIntlWritingCode,
11222 typeLongInteger,
92289429 11223#ifdef MAC_OSX
02236cbc 11224 typeUnicodeText,
92289429
YM
11225#else
11226 typeChar,
11227#endif
02236cbc
YM
11228 typeTextRangeArray,
11229 typeTextRangeArray,
11230 typeOffsetArray,
11231 typeTextRange,
11232 typeUInt32,
11233 typeUInt32,
11234 typeUInt32};
369a7a37 11235 static const EventParamName names_ufke[] =
02236cbc
YM
11236 {kEventParamTextInputSendComponentInstance,
11237 kEventParamTextInputSendRefCon,
11238 kEventParamTextInputSendSLRec,
11239 kEventParamTextInputSendText};
369a7a37 11240 static const EventParamType types_ufke[] =
02236cbc
YM
11241 {typeComponentInstance,
11242 typeLongInteger,
11243 typeIntlWritingCode,
11244 typeUnicodeText};
11245
11246 result = CallNextEventHandler (next_handler, event);
7adf3143
YM
11247 if (result != eventNotHandledErr)
11248 return result;
02236cbc
YM
11249
11250 switch (GetEventKind (event))
11251 {
11252 case kEventTextInputUpdateActiveInputArea:
11253 id_key = Qupdate_active_input_area;
11254 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
11255 names = names_uaia;
11256 types = types_uaia;
11257 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
11258 typeUInt32, sizeof (UInt32), &seqno_uaia);
11259 seqno_uaia++;
a56dd283 11260 result = noErr;
02236cbc
YM
11261 break;
11262
11263 case kEventTextInputUnicodeForKeyEvent:
11264 {
11265 EventRef kbd_event;
d8506697 11266 UInt32 actual_size, modifiers;
02236cbc
YM
11267
11268 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
11269 typeEventRef, NULL, sizeof (EventRef), NULL,
11270 &kbd_event);
11271 if (err == noErr)
11272 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
11273 typeUInt32, NULL,
11274 sizeof (UInt32), NULL, &modifiers);
a84cad70
YM
11275 if (err == noErr && mac_mapped_modifiers (modifiers))
11276 /* There're mapped modifier keys. Process it in
7adf3143 11277 do_keystroke. */
a56dd283 11278 break;
02236cbc
YM
11279 if (err == noErr)
11280 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11281 typeUnicodeText, NULL, 0, &actual_size,
11282 NULL);
1e53bd0e 11283 if (err == noErr && actual_size == sizeof (UniChar))
02236cbc 11284 {
1e53bd0e
YM
11285 UniChar code;
11286
11287 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
11288 typeUnicodeText, NULL,
11289 sizeof (UniChar), NULL, &code);
02236cbc
YM
11290 if (err == noErr && code < 0x80)
11291 {
7adf3143 11292 /* ASCII character. Process it in do_keystroke. */
67b5f809 11293 if (read_socket_inev && code >= 0x20 && code <= 0x7e)
02236cbc 11294 {
1e53bd0e
YM
11295 UInt32 key_code;
11296
11297 err = GetEventParameter (kbd_event, kEventParamKeyCode,
11298 typeUInt32, NULL, sizeof (UInt32),
11299 NULL, &key_code);
11300 if (!(err == noErr && key_code <= 0x7f
11301 && keycode_to_xkeysym_table [key_code]))
11302 {
11303 struct frame *f =
11304 mac_focus_frame (&one_mac_display_info);
11305
11306 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
11307 read_socket_inev->code = code;
11308 read_socket_inev->modifiers =
750a6cf4
YM
11309 mac_to_emacs_modifiers (modifiers);
11310 read_socket_inev->modifiers |=
1e53bd0e
YM
11311 (extra_keyboard_modifiers
11312 & (meta_modifier | alt_modifier
11313 | hyper_modifier | super_modifier));
11314 XSETFRAME (read_socket_inev->frame_or_window, f);
11315 }
02236cbc 11316 }
a56dd283 11317 break;
02236cbc
YM
11318 }
11319 }
a56dd283
YM
11320 if (err == noErr)
11321 {
11322 /* Non-ASCII keystrokes without mapped modifiers are
11323 processed at the Lisp level. */
11324 id_key = Qunicode_for_key_event;
11325 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
11326 names = names_ufke;
11327 types = types_ufke;
11328 result = noErr;
11329 }
02236cbc 11330 }
02236cbc
YM
11331 break;
11332
11333 case kEventTextInputOffsetToPos:
11334 {
11335 struct frame *f;
11336 struct window *w;
11337 Point p;
11338
11339 if (!OVERLAYP (Vmac_ts_active_input_overlay))
a56dd283 11340 break;
02236cbc
YM
11341
11342 /* Strictly speaking, this is not always correct because
11343 previous events may change some states about display. */
a56dd283
YM
11344 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
11345 {
11346 /* Active input area is displayed around the current point. */
11347 f = SELECTED_FRAME ();
11348 w = XWINDOW (f->selected_window);
11349 }
11350 else if (WINDOWP (echo_area_window))
02236cbc
YM
11351 {
11352 /* Active input area is displayed in the echo area. */
11353 w = XWINDOW (echo_area_window);
11354 f = WINDOW_XFRAME (w);
11355 }
11356 else
a56dd283 11357 break;
02236cbc
YM
11358
11359 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
7adf3143
YM
11360 + WINDOW_LEFT_FRINGE_WIDTH (w)
11361 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
02236cbc 11362 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
7adf3143
YM
11363 + FONT_BASE (FRAME_FONT (f))
11364 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
02236cbc
YM
11365 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
11366 typeQDPoint, sizeof (typeQDPoint), &p);
a56dd283
YM
11367 if (err == noErr)
11368 result = noErr;
02236cbc
YM
11369 }
11370 break;
11371
11372 default:
11373 abort ();
11374 }
11375
11376 if (!NILP (id_key))
11377 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
11378 event, num_params,
11379 names, types);
7adf3143 11380 return result;
02236cbc
YM
11381}
11382#endif
3354caee 11383#endif /* TARGET_API_MAC_CARBON */
b15325b2 11384
02236cbc 11385
68c767a3 11386OSStatus
b15325b2 11387install_window_handler (window)
3354caee 11388 WindowRef window;
6a0b5d37 11389{
3e7424f7 11390 OSStatus err = noErr;
6a0b5d37 11391
3354caee 11392#if TARGET_API_MAC_CARBON
7adf3143 11393 if (err == noErr)
6a0b5d37 11394 {
7adf3143
YM
11395 static const EventTypeSpec specs[] =
11396 {
11397 /* -- window refresh events -- */
11398 {kEventClassWindow, kEventWindowUpdate},
11399 /* -- window state change events -- */
11400 {kEventClassWindow, kEventWindowShowing},
11401 {kEventClassWindow, kEventWindowHiding},
11402 {kEventClassWindow, kEventWindowShown},
11403 {kEventClassWindow, kEventWindowHidden},
11404 {kEventClassWindow, kEventWindowCollapsed},
11405 {kEventClassWindow, kEventWindowExpanded},
11406 {kEventClassWindow, kEventWindowBoundsChanging},
11407 {kEventClassWindow, kEventWindowBoundsChanged},
11408 /* -- window action events -- */
11409 {kEventClassWindow, kEventWindowClose},
11410 {kEventClassWindow, kEventWindowGetIdealSize},
68c767a3 11411#ifdef MAC_OSX
7adf3143 11412 {kEventClassWindow, kEventWindowToolbarSwitchMode},
68c767a3 11413#endif
02236cbc 11414#if USE_MAC_TSM
7adf3143
YM
11415 /* -- window focus events -- */
11416 {kEventClassWindow, kEventWindowFocusAcquired},
11417 {kEventClassWindow, kEventWindowFocusRelinquish},
02236cbc 11418#endif
7adf3143
YM
11419 };
11420 static EventHandlerUPP handle_window_eventUPP = NULL;
6a0b5d37 11421
7adf3143
YM
11422 if (handle_window_eventUPP == NULL)
11423 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
6a0b5d37 11424
7adf3143
YM
11425 err = InstallWindowEventHandler (window, handle_window_eventUPP,
11426 GetEventTypeCount (specs),
11427 specs, NULL, NULL);
6a0b5d37 11428 }
30c92fab 11429#endif
6a0b5d37 11430
30c92fab 11431 if (err == noErr)
a733ef16 11432 err = install_drag_handler (window);
6a0b5d37
YM
11433
11434 return err;
11435}
b15325b2 11436
25c9622b
YM
11437void
11438remove_window_handler (window)
3354caee 11439 WindowRef window;
25c9622b 11440{
a733ef16 11441 remove_drag_handler (window);
742fbed7 11442}
b15325b2 11443
7adf3143
YM
11444#if TARGET_API_MAC_CARBON
11445static OSStatus
11446install_application_handler ()
b15325b2 11447{
3e7424f7 11448 OSStatus err = noErr;
95085023 11449
7adf3143
YM
11450 if (err == noErr)
11451 {
11452 static const EventTypeSpec specs[] = {
02236cbc 11453#if USE_MAC_TSM
7adf3143
YM
11454 {kEventClassApplication, kEventAppActivated},
11455 {kEventClassApplication, kEventAppDeactivated},
68c767a3 11456#endif
7adf3143
YM
11457 };
11458
11459 err = InstallApplicationEventHandler (NewEventHandlerUPP
11460 (mac_handle_application_event),
11461 GetEventTypeCount (specs),
11462 specs, NULL, NULL);
11463 }
11464
95085023 11465 if (err == noErr)
7adf3143
YM
11466 {
11467 static const EventTypeSpec specs[] =
11468 {{kEventClassKeyboard, kEventRawKeyDown},
11469 {kEventClassKeyboard, kEventRawKeyRepeat},
11470 {kEventClassKeyboard, kEventRawKeyUp}};
11471
11472 err = InstallApplicationEventHandler (NewEventHandlerUPP
11473 (mac_handle_keyboard_event),
11474 GetEventTypeCount (specs),
11475 specs, NULL, NULL);
11476 }
11477
30c92fab 11478 if (err == noErr)
7adf3143
YM
11479 {
11480 static const EventTypeSpec specs[] =
11481 {{kEventClassCommand, kEventCommandProcess}};
11482
11483 err = InstallApplicationEventHandler (NewEventHandlerUPP
11484 (mac_handle_command_event),
11485 GetEventTypeCount (specs),
11486 specs, NULL, NULL);
11487 }
11488
11489 if (err == noErr)
11490 {
11491 static const EventTypeSpec specs[] =
11492 {{kEventClassMouse, kEventMouseWheelMoved}};
11493
11494 err = InstallApplicationEventHandler (NewEventHandlerUPP
11495 (mac_handle_mouse_event),
11496 GetEventTypeCount (specs),
11497 specs, NULL, NULL);
11498 }
11499
02236cbc
YM
11500#if USE_MAC_TSM
11501 if (err == noErr)
7adf3143
YM
11502 {
11503 static const EventTypeSpec spec[] =
11504 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
11505 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
11506 {kEventClassTextInput, kEventTextInputOffsetToPos}};
11507
11508 err = InstallApplicationEventHandler (NewEventHandlerUPP
11509 (mac_handle_text_input_event),
11510 GetEventTypeCount (spec),
11511 spec, NULL, NULL);
11512 }
742fbed7 11513#endif
7adf3143 11514
30c92fab 11515 if (err == noErr)
7adf3143
YM
11516 err = install_menu_target_item_handler ();
11517
11518#ifdef MAC_OSX
e2d3b7e1 11519 if (err == noErr)
7adf3143
YM
11520 err = install_service_handler ();
11521#endif
a733ef16 11522
30c92fab 11523 return err;
b15325b2 11524}
7adf3143 11525#endif
742fbed7 11526
19ee09cc
YM
11527static pascal void
11528mac_handle_dm_notification (event)
11529 AppleEvent *event;
11530{
11531 mac_screen_config_changed = 1;
11532}
11533
7adf3143
YM
11534#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11535static void
11536mac_handle_cg_display_reconfig (display, flags, user_info)
11537 CGDirectDisplayID display;
11538 CGDisplayChangeSummaryFlags flags;
11539 void *user_info;
11540{
11541 mac_screen_config_changed = 1;
11542}
11543#endif
11544
19ee09cc
YM
11545static OSErr
11546init_dm_notification_handler ()
11547{
7adf3143
YM
11548 OSErr err = noErr;
11549
11550#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
11551#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11552 if (CGDisplayRegisterReconfigurationCallback != NULL)
11553#endif
11554 {
11555 CGDisplayRegisterReconfigurationCallback (mac_handle_cg_display_reconfig,
11556 NULL);
11557 }
11558#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11559 else /* CGDisplayRegisterReconfigurationCallback == NULL */
11560#endif
11561#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
11562#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 || MAC_OS_X_VERSION_MIN_REQUIRED == 1020
11563 {
11564 static DMNotificationUPP handle_dm_notificationUPP = NULL;
11565 ProcessSerialNumber psn;
19ee09cc 11566
7adf3143
YM
11567 if (handle_dm_notificationUPP == NULL)
11568 handle_dm_notificationUPP =
11569 NewDMNotificationUPP (mac_handle_dm_notification);
19ee09cc 11570
7adf3143
YM
11571 err = GetCurrentProcess (&psn);
11572 if (err == noErr)
11573 err = DMRegisterNotifyProc (handle_dm_notificationUPP, &psn);
11574 }
11575#endif
19ee09cc
YM
11576
11577 return err;
11578}
11579
11580static void
11581mac_get_screen_info (dpyinfo)
11582 struct mac_display_info *dpyinfo;
11583{
11584#ifdef MAC_OSX
11585 /* HasDepth returns true if it is possible to have a 32 bit display,
11586 but this may not be what is actually used. Mac OSX can do better. */
11587 dpyinfo->color_p = CGDisplaySamplesPerPixel (kCGDirectMainDisplay) > 1;
11588 dpyinfo->n_planes = CGDisplayBitsPerPixel (kCGDirectMainDisplay);
11589 {
11590 CGDisplayErr err;
11591 CGDisplayCount ndisps;
11592 CGDirectDisplayID *displays;
11593
11594 err = CGGetActiveDisplayList (0, NULL, &ndisps);
11595 if (err == noErr)
11596 {
11597 displays = alloca (sizeof (CGDirectDisplayID) * ndisps);
11598 err = CGGetActiveDisplayList (ndisps, displays, &ndisps);
11599 }
11600 if (err == noErr)
11601 {
11602 CGRect bounds = CGRectZero;
11603
11604 while (ndisps-- > 0)
11605 bounds = CGRectUnion (bounds, CGDisplayBounds (displays[ndisps]));
11606 dpyinfo->height = CGRectGetHeight (bounds);
11607 dpyinfo->width = CGRectGetWidth (bounds);
11608 }
11609 else
11610 {
11611 dpyinfo->height = CGDisplayPixelsHigh (kCGDirectMainDisplay);
11612 dpyinfo->width = CGDisplayPixelsWide (kCGDirectMainDisplay);
11613 }
11614 }
11615#else /* !MAC_OSX */
11616 {
11617 GDHandle gdh = GetMainDevice ();
11618 Rect rect = (**gdh).gdRect;
11619
11620 dpyinfo->color_p = TestDeviceAttribute (gdh, gdDevType);
11621 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
11622 if (HasDepth (gdh, dpyinfo->n_planes, gdDevType, dpyinfo->color_p))
11623 break;
11624
11625 for (gdh = DMGetFirstScreenDevice (dmOnlyActiveDisplays); gdh;
11626 gdh = DMGetNextScreenDevice (gdh, dmOnlyActiveDisplays))
11627 UnionRect (&rect, &(**gdh).gdRect, &rect);
11628
11629 dpyinfo->height = rect.bottom - rect.top;
11630 dpyinfo->width = rect.right - rect.left;
11631 }
11632#endif /* !MAC_OSX */
11633}
11634
11635
1a578e9b
AC
11636#if __profile__
11637void
11638profiler_exit_proc ()
11639{
11640 ProfilerDump ("\pEmacs.prof");
11641 ProfilerTerm ();
11642}
11643#endif
11644
11645/* These few functions implement Emacs as a normal Mac application
e6bdfa32
YM
11646 (almost): set up the heap and the Toolbox, handle necessary system
11647 events plus a few simple menu events. They also set up Emacs's
11648 access to functions defined in the rest of this file. Emacs uses
11649 function hooks to perform all its terminal I/O. A complete list of
11650 these functions appear in termhooks.h. For what they do, read the
11651 comments there and see also w32term.c and xterm.c. What's
11652 noticeably missing here is the event loop, which is normally
11653 present in most Mac application. After performing the necessary
11654 Mac initializations, main passes off control to emacs_main
11655 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
11656 (defined further below) to read input. This is where
11657 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
1a578e9b 11658
25c9622b 11659#ifdef MAC_OS8
1a578e9b 11660#undef main
177c0ea7 11661int
1a578e9b
AC
11662main (void)
11663{
11664#if __profile__ /* is the profiler on? */
11665 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11666 exit(1);
11667#endif
11668
11669#if __MWERKS__
11670 /* set creator and type for files created by MSL */
e2d3b7e1 11671 _fcreator = MAC_EMACS_CREATOR_CODE;
1a578e9b
AC
11672 _ftype = 'TEXT';
11673#endif
11674
11675 do_init_managers ();
177c0ea7 11676
1a578e9b 11677 do_get_menus ();
177c0ea7 11678
6b61353c 11679#ifndef USE_LSB_TAG
2e875e36 11680 do_check_ram_size ();
6b61353c 11681#endif
2e875e36 11682
1a578e9b
AC
11683 init_emacs_passwd_dir ();
11684
11685 init_environ ();
11686
0e0a1663
YM
11687 init_coercion_handler ();
11688
1a578e9b
AC
11689 initialize_applescript ();
11690
6a0b5d37 11691 init_apple_event_handler ();
177c0ea7 11692
19ee09cc
YM
11693 init_dm_notification_handler ();
11694
1a578e9b
AC
11695 {
11696 char **argv;
11697 int argc = 0;
11698
11699 /* set up argv array from STR# resource */
11700 get_string_list (&argv, ARGV_STRING_LIST_ID);
11701 while (argv[argc])
11702 argc++;
11703
11704 /* free up AppleScript resources on exit */
11705 atexit (terminate_applescript);
11706
11707#if __profile__ /* is the profiler on? */
11708 atexit (profiler_exit_proc);
11709#endif
11710
11711 /* 3rd param "envp" never used in emacs_main */
11712 (void) emacs_main (argc, argv, 0);
11713 }
11714
11715 /* Never reached - real exit in Fkill_emacs */
11716 return 0;
11717}
e0f712ba 11718#endif
1a578e9b 11719
3354caee 11720#if !TARGET_API_MAC_CARBON
b15325b2
ST
11721static RgnHandle mouse_region = NULL;
11722
11723Boolean
11724mac_wait_next_event (er, sleep_time, dequeue)
11725 EventRecord *er;
11726 UInt32 sleep_time;
11727 Boolean dequeue;
11728{
11729 static EventRecord er_buf = {nullEvent};
11730 UInt32 target_tick, current_tick;
11731 EventMask event_mask;
11732
11733 if (mouse_region == NULL)
11734 mouse_region = NewRgn ();
11735
11736 event_mask = everyEvent;
6a0b5d37 11737 if (!mac_ready_for_apple_events)
b15325b2
ST
11738 event_mask -= highLevelEventMask;
11739
11740 current_tick = TickCount ();
11741 target_tick = current_tick + sleep_time;
11742
11743 if (er_buf.what == nullEvent)
11744 while (!WaitNextEvent (event_mask, &er_buf,
11745 target_tick - current_tick, mouse_region))
11746 {
11747 current_tick = TickCount ();
11748 if (target_tick <= current_tick)
11749 return false;
11750 }
11751
11752 *er = er_buf;
11753 if (dequeue)
11754 er_buf.what = nullEvent;
11755 return true;
11756}
3354caee 11757#endif /* not TARGET_API_MAC_CARBON */
b15325b2 11758
a733ef16
YM
11759#if TARGET_API_MAC_CARBON
11760OSStatus
11761mac_post_mouse_moved_event ()
11762{
11763 EventRef event = NULL;
11764 OSStatus err;
11765
11766 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
11767 kEventAttributeNone, &event);
11768 if (err == noErr)
11769 {
11770 Point mouse_pos;
11771
2a953eae 11772 GetGlobalMouse (&mouse_pos);
a733ef16
YM
11773 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
11774 sizeof (Point), &mouse_pos);
11775 }
11776 if (err == noErr)
11777 {
11778 UInt32 modifiers = GetCurrentKeyModifiers ();
11779
11780 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
11781 sizeof (UInt32), &modifiers);
11782 }
11783 if (err == noErr)
11784 err = PostEventToQueue (GetCurrentEventQueue (), event,
11785 kEventPriorityStandard);
11786 if (event)
11787 ReleaseEvent (event);
11788
11789 return err;
11790}
11791#endif
11792
1a578e9b
AC
11793/* Emacs calls this whenever it wants to read an input event from the
11794 user. */
11795int
50bf7673
ST
11796XTread_socket (sd, expected, hold_quit)
11797 int sd, expected;
11798 struct input_event *hold_quit;
1a578e9b 11799{
6b61353c 11800 struct input_event inev;
177c0ea7 11801 int count = 0;
3354caee 11802#if TARGET_API_MAC_CARBON
742fbed7 11803 EventRef eventRef;
b15325b2 11804 EventTargetRef toolbox_dispatcher;
742fbed7 11805#endif
1a578e9b 11806 EventRecord er;
50bf7673 11807 struct mac_display_info *dpyinfo = &one_mac_display_info;
1a578e9b
AC
11808
11809 if (interrupt_input_blocked)
11810 {
11811 interrupt_input_pending = 1;
11812 return -1;
11813 }
11814
11815 interrupt_input_pending = 0;
11816 BLOCK_INPUT;
11817
11818 /* So people can tell when we have read the available input. */
11819 input_signal_count++;
11820
b465419f
YM
11821 ++handling_signal;
11822
3354caee 11823#if TARGET_API_MAC_CARBON
b15325b2 11824 toolbox_dispatcher = GetEventDispatcherTarget ();
1a578e9b 11825
4ea08bbf
YM
11826 while (
11827#if USE_CG_DRAWING
11828 mac_prepare_for_quickdraw (NULL),
11829#endif
11830 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
50bf7673 11831 kEventRemoveFromQueue, &eventRef))
3354caee 11832#else /* !TARGET_API_MAC_CARBON */
b15325b2 11833 while (mac_wait_next_event (&er, 0, true))
3354caee 11834#endif /* !TARGET_API_MAC_CARBON */
742fbed7 11835 {
50bf7673
ST
11836 int do_help = 0;
11837 struct frame *f;
95dfb192 11838 unsigned long timestamp;
50bf7673 11839
50bf7673
ST
11840 EVENT_INIT (inev);
11841 inev.kind = NO_EVENT;
11842 inev.arg = Qnil;
11843
3354caee 11844#if TARGET_API_MAC_CARBON
95dfb192 11845 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
95dfb192 11846
177c0ea7 11847 if (!mac_convert_event_ref (eventRef, &er))
7adf3143
YM
11848 goto OTHER;
11849#else /* !TARGET_API_MAC_CARBON */
11850 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
11851#endif /* !TARGET_API_MAC_CARBON */
11852
50bf7673 11853 switch (er.what)
1a578e9b 11854 {
50bf7673
ST
11855 case mouseDown:
11856 case mouseUp:
11857 {
3354caee 11858 WindowRef window_ptr;
e6bdfa32 11859 ControlPartCode part_code;
50bf7673
ST
11860 int tool_bar_p = 0;
11861
3354caee 11862#if TARGET_API_MAC_CARBON
7adf3143
YM
11863 OSStatus err;
11864
59feca74
ST
11865 /* This is needed to send mouse events like aqua window
11866 buttons to the correct handler. */
7adf3143
YM
11867 read_socket_inev = &inev;
11868 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
11869 read_socket_inev = NULL;
11870 if (err != eventNotHandledErr)
59feca74
ST
11871 break;
11872#endif
05f7d868 11873 last_mouse_glyph_frame = 0;
59feca74 11874
50bf7673
ST
11875 if (dpyinfo->grabbed && last_mouse_frame
11876 && FRAME_LIVE_P (last_mouse_frame))
11877 {
11878 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
11879 part_code = inContent;
11880 }
11881 else
11882 {
bf06c82f 11883 part_code = FindWindow (er.where, &window_ptr);
50bf7673
ST
11884 if (tip_window && window_ptr == tip_window)
11885 {
11886 HideWindow (tip_window);
bf06c82f 11887 part_code = FindWindow (er.where, &window_ptr);
50bf7673 11888 }
50bf7673
ST
11889 }
11890
0e41b66d
YM
11891 if (er.what != mouseDown &&
11892 (part_code != inContent || dpyinfo->grabbed == 0))
bf06c82f
ST
11893 break;
11894
50bf7673
ST
11895 switch (part_code)
11896 {
11897 case inMenuBar:
7ca7ccd5 11898 f = mac_focus_frame (dpyinfo);
bf06c82f
ST
11899 saved_menu_event_location = er.where;
11900 inev.kind = MENU_BAR_ACTIVATE_EVENT;
11901 XSETFRAME (inev.frame_or_window, f);
50bf7673 11902 break;
742fbed7 11903
50bf7673 11904 case inContent:
4cb62a90
YM
11905 if (
11906#if TARGET_API_MAC_CARBON
11907 FrontNonFloatingWindow ()
11908#else
11909 FrontWindow ()
11910#endif
0d36bf23
YM
11911 != window_ptr
11912 || (mac_window_to_frame (window_ptr)
11913 != dpyinfo->x_focus_frame))
50bf7673
ST
11914 SelectWindow (window_ptr);
11915 else
11916 {
e6bdfa32 11917 ControlPartCode control_part_code;
3354caee 11918 ControlRef ch;
7adf3143 11919 Point mouse_loc;
5b8b73ff
YM
11920#ifdef MAC_OSX
11921 ControlKind control_kind;
11922#endif
177c0ea7 11923
50bf7673
ST
11924 f = mac_window_to_frame (window_ptr);
11925 /* convert to local coordinates of new window */
7adf3143
YM
11926 mouse_loc.h = (er.where.h
11927 - (f->left_pos
11928 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
11929 mouse_loc.v = (er.where.v
11930 - (f->top_pos
11931 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
e0f712ba 11932#if TARGET_API_MAC_CARBON
50bf7673
ST
11933 ch = FindControlUnderMouse (mouse_loc, window_ptr,
11934 &control_part_code);
5b8b73ff
YM
11935#ifdef MAC_OSX
11936 if (ch)
11937 GetControlKind (ch, &control_kind);
11938#endif
e0f712ba 11939#else
50bf7673
ST
11940 control_part_code = FindControl (mouse_loc, window_ptr,
11941 &ch);
e0f712ba
AC
11942#endif
11943
3354caee 11944#if TARGET_API_MAC_CARBON
50bf7673
ST
11945 inev.code = mac_get_mouse_btn (eventRef);
11946 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
742fbed7 11947#else
50bf7673
ST
11948 inev.code = mac_get_emulated_btn (er.modifiers);
11949 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
742fbed7 11950#endif
50bf7673
ST
11951 XSETINT (inev.x, mouse_loc.h);
11952 XSETINT (inev.y, mouse_loc.v);
50bf7673 11953
f93e4d4f
YM
11954 if ((dpyinfo->grabbed && tracked_scroll_bar)
11955 || (ch != 0
5b8b73ff 11956#ifndef USE_TOOLKIT_SCROLL_BARS
f93e4d4f
YM
11957 /* control_part_code becomes kControlNoPart if
11958 a progress indicator is clicked. */
11959 && control_part_code != kControlNoPart
5b8b73ff
YM
11960#else /* USE_TOOLKIT_SCROLL_BARS */
11961#ifdef MAC_OSX
f93e4d4f 11962 && control_kind.kind == kControlKindScrollBar
5b8b73ff
YM
11963#endif /* MAC_OSX */
11964#endif /* USE_TOOLKIT_SCROLL_BARS */
f93e4d4f 11965 ))
50bf7673
ST
11966 {
11967 struct scroll_bar *bar;
11968
11969 if (dpyinfo->grabbed && tracked_scroll_bar)
11970 {
11971 bar = tracked_scroll_bar;
5b8b73ff 11972#ifndef USE_TOOLKIT_SCROLL_BARS
50bf7673 11973 control_part_code = kControlIndicatorPart;
5b8b73ff 11974#endif
50bf7673
ST
11975 }
11976 else
11977 bar = (struct scroll_bar *) GetControlReference (ch);
5b8b73ff
YM
11978#ifdef USE_TOOLKIT_SCROLL_BARS
11979 /* Make the "Ctrl-Mouse-2 splits window" work
11980 for toolkit scroll bars. */
e6509087 11981 if (inev.modifiers & ctrl_modifier)
5b8b73ff
YM
11982 x_scroll_bar_handle_click (bar, control_part_code,
11983 &er, &inev);
11984 else if (er.what == mouseDown)
11985 x_scroll_bar_handle_press (bar, control_part_code,
e6509087 11986 mouse_loc, &inev);
5b8b73ff 11987 else
95dfb192 11988 x_scroll_bar_handle_release (bar, &inev);
5b8b73ff 11989#else /* not USE_TOOLKIT_SCROLL_BARS */
50bf7673
ST
11990 x_scroll_bar_handle_click (bar, control_part_code,
11991 &er, &inev);
11992 if (er.what == mouseDown
11993 && control_part_code == kControlIndicatorPart)
11994 tracked_scroll_bar = bar;
11995 else
11996 tracked_scroll_bar = NULL;
5b8b73ff 11997#endif /* not USE_TOOLKIT_SCROLL_BARS */
50bf7673
ST
11998 }
11999 else
12000 {
12001 Lisp_Object window;
12002 int x = mouse_loc.h;
12003 int y = mouse_loc.v;
12004
12005 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
12006 if (EQ (window, f->tool_bar_window))
12007 {
12008 if (er.what == mouseDown)
12009 handle_tool_bar_click (f, x, y, 1, 0);
12010 else
12011 handle_tool_bar_click (f, x, y, 0,
12012 inev.modifiers);
12013 tool_bar_p = 1;
12014 }
12015 else
12016 {
12017 XSETFRAME (inev.frame_or_window, f);
12018 inev.kind = MOUSE_CLICK_EVENT;
12019 }
12020 }
12021
12022 if (er.what == mouseDown)
12023 {
12024 dpyinfo->grabbed |= (1 << inev.code);
12025 last_mouse_frame = f;
50bf7673
ST
12026
12027 if (!tool_bar_p)
12028 last_tool_bar_item = -1;
12029 }
12030 else
12031 {
bf06c82f 12032 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
50bf7673
ST
12033 /* If a button is released though it was not
12034 previously pressed, that would be because
12035 of multi-button emulation. */
12036 dpyinfo->grabbed = 0;
12037 else
12038 dpyinfo->grabbed &= ~(1 << inev.code);
12039 }
12040
0e41b66d
YM
12041 /* Ignore any mouse motion that happened before
12042 this event; any subsequent mouse-movement Emacs
12043 events should reflect only motion after the
12044 ButtonPress. */
12045 if (f != 0)
12046 f->mouse_moved = 0;
12047
5b8b73ff 12048#ifdef USE_TOOLKIT_SCROLL_BARS
e6509087
YM
12049 if (inev.kind == MOUSE_CLICK_EVENT
12050 || (inev.kind == SCROLL_BAR_CLICK_EVENT
12051 && (inev.modifiers & ctrl_modifier)))
5b8b73ff
YM
12052#endif
12053 switch (er.what)
12054 {
12055 case mouseDown:
12056 inev.modifiers |= down_modifier;
12057 break;
12058 case mouseUp:
12059 inev.modifiers |= up_modifier;
12060 break;
12061 }
50bf7673
ST
12062 }
12063 break;
1a578e9b 12064
50bf7673
ST
12065 case inDrag:
12066#if TARGET_API_MAC_CARBON
a733ef16 12067 case inProxyIcon:
458dbb8c
YM
12068 if (IsWindowPathSelectClick (window_ptr, &er))
12069 {
12070 WindowPathSelect (window_ptr, NULL, NULL);
12071 break;
12072 }
a733ef16
YM
12073 if (part_code == inProxyIcon
12074 && (TrackWindowProxyDrag (window_ptr, er.where)
12075 != errUserWantsToDragWindow))
12076 break;
bf06c82f 12077 DragWindow (window_ptr, er.where, NULL);
50bf7673
ST
12078#else /* not TARGET_API_MAC_CARBON */
12079 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
e439b925
ST
12080 /* Update the frame parameters. */
12081 {
12082 struct frame *f = mac_window_to_frame (window_ptr);
bf06c82f 12083
e439b925 12084 if (f && !f->async_iconified)
bed0bf95 12085 mac_handle_origin_change (f);
e439b925 12086 }
3354caee 12087#endif /* not TARGET_API_MAC_CARBON */
50bf7673 12088 break;
177c0ea7 12089
50bf7673
ST
12090 case inGoAway:
12091 if (TrackGoAway (window_ptr, er.where))
12092 {
12093 inev.kind = DELETE_WINDOW_EVENT;
12094 XSETFRAME (inev.frame_or_window,
12095 mac_window_to_frame (window_ptr));
12096 }
12097 break;
1a578e9b 12098
50bf7673
ST
12099 /* window resize handling added --ben */
12100 case inGrow:
bf06c82f
ST
12101 do_grow_window (window_ptr, &er);
12102 break;
e0f712ba 12103
50bf7673
ST
12104 /* window zoom handling added --ben */
12105 case inZoomIn:
12106 case inZoomOut:
12107 if (TrackBox (window_ptr, er.where, part_code))
12108 do_zoom_window (window_ptr, part_code);
12109 break;
742fbed7 12110
c6829f81
YM
12111#if USE_MAC_TOOLBAR
12112 case inStructure:
12113 {
12114 OSStatus err;
12115 HIViewRef ch;
12116
12117 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
12118 eventRef, &ch);
12119 /* This doesn't work on Mac OS X 10.2. */
12120 if (err == noErr)
12121 HIViewClick (ch, eventRef);
12122 }
12123 break;
12124#endif /* USE_MAC_TOOLBAR */
12125
50bf7673
ST
12126 default:
12127 break;
12128 }
12129 }
12130 break;
e0f712ba 12131
7adf3143 12132#if !TARGET_API_MAC_CARBON
50bf7673 12133 case updateEvt:
3354caee 12134 do_window_update ((WindowRef) er.message);
50bf7673 12135 break;
7adf3143 12136#endif
177c0ea7 12137
50bf7673 12138 case osEvt:
50bf7673
ST
12139 switch ((er.message >> 24) & 0x000000FF)
12140 {
50bf7673 12141 case mouseMovedMessage:
3354caee 12142#if !TARGET_API_MAC_CARBON
b15325b2
ST
12143 SetRectRgn (mouse_region, er.where.h, er.where.v,
12144 er.where.h + 1, er.where.v + 1);
12145#endif
50bf7673 12146 previous_help_echo_string = help_echo_string;
af1229d9 12147 help_echo_string = Qnil;
1a578e9b 12148
7ca7ccd5
YM
12149 if (dpyinfo->grabbed && last_mouse_frame
12150 && FRAME_LIVE_P (last_mouse_frame))
12151 f = last_mouse_frame;
12152 else
12153 f = dpyinfo->x_focus_frame;
12154
12155 if (dpyinfo->mouse_face_hidden)
12156 {
12157 dpyinfo->mouse_face_hidden = 0;
12158 clear_mouse_face (dpyinfo);
12159 }
12160
12161 if (f)
12162 {
3354caee 12163 WindowRef wp = FRAME_MAC_WINDOW (f);
7adf3143
YM
12164 Point mouse_pos;
12165
12166 mouse_pos.h = (er.where.h
12167 - (f->left_pos
12168 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12169 mouse_pos.v = (er.where.v
12170 - (f->top_pos
12171 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
7ca7ccd5 12172 if (dpyinfo->grabbed && tracked_scroll_bar)
5b8b73ff
YM
12173#ifdef USE_TOOLKIT_SCROLL_BARS
12174 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
95dfb192 12175 mouse_pos, &inev);
5b8b73ff 12176#else /* not USE_TOOLKIT_SCROLL_BARS */
7ca7ccd5
YM
12177 x_scroll_bar_note_movement (tracked_scroll_bar,
12178 mouse_pos.v
12179 - XINT (tracked_scroll_bar->top),
5b8b73ff
YM
12180 er.when * (1000 / 60));
12181#endif /* not USE_TOOLKIT_SCROLL_BARS */
7ca7ccd5
YM
12182 else
12183 {
12184 /* Generate SELECT_WINDOW_EVENTs when needed. */
92b23323 12185 if (!NILP (Vmouse_autoselect_window))
7ca7ccd5
YM
12186 {
12187 Lisp_Object window;
12188
12189 window = window_from_coordinates (f,
12190 mouse_pos.h,
12191 mouse_pos.v,
12192 0, 0, 0, 0);
12193
12194 /* Window will be selected only when it is
12195 not selected now and last mouse movement
12196 event was not in it. Minibuffer window
e0f24100 12197 will be selected only when it is active. */
7ca7ccd5
YM
12198 if (WINDOWP (window)
12199 && !EQ (window, last_window)
b0c6cec4
MR
12200 && !EQ (window, selected_window)
12201 /* For click-to-focus window managers
12202 create event iff we don't leave the
12203 selected frame. */
12204 && (focus_follows_mouse
12205 || (EQ (XWINDOW (window)->frame,
12206 XWINDOW (selected_window)->frame))))
7ca7ccd5
YM
12207 {
12208 inev.kind = SELECT_WINDOW_EVENT;
12209 inev.frame_or_window = window;
12210 }
12211
12212 last_window=window;
12213 }
af1229d9
YM
12214 if (!note_mouse_movement (f, &mouse_pos))
12215 help_echo_string = previous_help_echo_string;
c6829f81
YM
12216#if USE_MAC_TOOLBAR
12217 else
12218 mac_tool_bar_note_mouse_movement (f, eventRef);
12219#endif
7ca7ccd5
YM
12220 }
12221 }
1a578e9b 12222
50bf7673
ST
12223 /* If the contents of the global variable
12224 help_echo_string has changed, generate a
12225 HELP_EVENT. */
12226 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
12227 do_help = 1;
1a578e9b 12228 break;
7adf3143
YM
12229
12230 default:
12231 goto OTHER;
1a578e9b 12232 }
50bf7673
ST
12233 break;
12234
12235 case activateEvt:
12236 {
3354caee 12237 WindowRef window_ptr = (WindowRef) er.message;
7b7d07bb
YM
12238 OSErr err;
12239 ControlRef root_control;
177c0ea7 12240
50bf7673
ST
12241 if (window_ptr == tip_window)
12242 {
12243 HideWindow (tip_window);
12244 break;
12245 }
177c0ea7 12246
59feca74 12247 if (!is_emacs_window (window_ptr))
7adf3143
YM
12248 goto OTHER;
12249
12250 f = mac_window_to_frame (window_ptr);
f94a2622 12251
50bf7673
ST
12252 if ((er.modifiers & activeFlag) != 0)
12253 {
59feca74 12254 /* A window has been activated */
7adf3143 12255 Point mouse_loc;
177c0ea7 12256
7b7d07bb
YM
12257 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12258 if (err == noErr)
12259 ActivateControl (root_control);
12260
7ca7ccd5 12261 x_detect_focus_change (dpyinfo, &er, &inev);
177c0ea7 12262
7adf3143
YM
12263 mouse_loc.h = (er.where.h
12264 - (f->left_pos
12265 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
12266 mouse_loc.v = (er.where.v
12267 - (f->top_pos
12268 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
59feca74 12269 /* Window-activated event counts as mouse movement,
50bf7673 12270 so update things that depend on mouse position. */
7adf3143 12271 note_mouse_movement (f, &mouse_loc);
50bf7673
ST
12272 }
12273 else
12274 {
59feca74 12275 /* A window has been deactivated */
7b7d07bb
YM
12276 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
12277 if (err == noErr)
12278 DeactivateControl (root_control);
12279
70385fe6 12280#ifdef USE_TOOLKIT_SCROLL_BARS
5b8b73ff
YM
12281 if (dpyinfo->grabbed && tracked_scroll_bar)
12282 {
12283 struct input_event event;
12284
12285 EVENT_INIT (event);
12286 event.kind = NO_EVENT;
95dfb192 12287 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
5b8b73ff
YM
12288 if (event.kind != NO_EVENT)
12289 {
95dfb192 12290 event.timestamp = timestamp;
5b8b73ff
YM
12291 kbd_buffer_store_event_hold (&event, hold_quit);
12292 count++;
12293 }
12294 }
12295#endif
59feca74
ST
12296 dpyinfo->grabbed = 0;
12297
7ca7ccd5 12298 x_detect_focus_change (dpyinfo, &er, &inev);
177c0ea7 12299
50bf7673
ST
12300 if (f == dpyinfo->mouse_face_mouse_frame)
12301 {
12302 /* If we move outside the frame, then we're
12303 certainly no longer on any text in the
12304 frame. */
12305 clear_mouse_face (dpyinfo);
12306 dpyinfo->mouse_face_mouse_frame = 0;
12307 }
177c0ea7 12308
50bf7673
ST
12309 /* Generate a nil HELP_EVENT to cancel a help-echo.
12310 Do it only if there's something to cancel.
12311 Otherwise, the startup message is cleared when the
12312 mouse leaves the frame. */
12313 if (any_help_event_p)
12314 do_help = -1;
12315 }
12316 }
12317 break;
177c0ea7 12318
50bf7673 12319 case keyDown:
2abb0fde 12320 case keyUp:
50bf7673 12321 case autoKey:
7adf3143 12322 ObscureCursor ();
b8c6940e 12323
7adf3143
YM
12324 f = mac_focus_frame (dpyinfo);
12325 XSETFRAME (inev.frame_or_window, f);
b8c6940e 12326
7adf3143
YM
12327 /* If mouse-highlight is an integer, input clears out mouse
12328 highlighting. */
12329 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
12330 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
12331 {
12332 clear_mouse_face (dpyinfo);
12333 dpyinfo->mouse_face_hidden = 1;
12334 }
7b7d07bb
YM
12335
12336 {
12337 UInt32 modifiers = er.modifiers, mapped_modifiers;
12338
12339#ifdef MAC_OSX
12340 GetEventParameter (eventRef, kEventParamKeyModifiers,
12341 typeUInt32, NULL,
12342 sizeof (UInt32), NULL, &modifiers);
12343#endif
12344 mapped_modifiers = mac_mapped_modifiers (modifiers);
12345
b8c6940e 12346#if TARGET_API_MAC_CARBON
7b7d07bb
YM
12347 if (!(mapped_modifiers
12348 & ~(mac_pass_command_to_system ? cmdKey : 0)
12349 & ~(mac_pass_control_to_system ? controlKey : 0)))
12350 goto OTHER;
12351 else
742fbed7 12352#endif
7b7d07bb
YM
12353 if (er.what != keyUp)
12354 do_keystroke (er.what, er.message & charCodeMask,
12355 (er.message & keyCodeMask) >> 8,
12356 modifiers, timestamp, &inev);
12357 }
50bf7673 12358 break;
177c0ea7 12359
50bf7673 12360 case kHighLevelEvent:
95dfb192 12361 AEProcessAppleEvent (&er);
95dfb192 12362 break;
177c0ea7 12363
50bf7673 12364 default:
7adf3143
YM
12365 OTHER:
12366#if TARGET_API_MAC_CARBON
12367 {
12368 OSStatus err;
12369
12370 read_socket_inev = &inev;
12371 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
12372 read_socket_inev = NULL;
12373 }
12374#endif
50bf7673
ST
12375 break;
12376 }
3354caee 12377#if TARGET_API_MAC_CARBON
742fbed7 12378 ReleaseEvent (eventRef);
742fbed7 12379#endif
1a578e9b 12380
50bf7673
ST
12381 if (inev.kind != NO_EVENT)
12382 {
95dfb192 12383 inev.timestamp = timestamp;
50bf7673
ST
12384 kbd_buffer_store_event_hold (&inev, hold_quit);
12385 count++;
12386 }
12387
12388 if (do_help
12389 && !(hold_quit && hold_quit->kind != NO_EVENT))
12390 {
12391 Lisp_Object frame;
12392
12393 if (f)
12394 XSETFRAME (frame, f);
12395 else
12396 frame = Qnil;
12397
12398 if (do_help > 0)
12399 {
12400 any_help_event_p = 1;
12401 gen_help_event (help_echo_string, frame, help_echo_window,
12402 help_echo_object, help_echo_pos);
12403 }
12404 else
12405 {
12406 help_echo_string = Qnil;
12407 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
12408 }
12409 count++;
12410 }
50bf7673
ST
12411 }
12412
1a578e9b
AC
12413 /* If the focus was just given to an autoraising frame,
12414 raise it now. */
12415 /* ??? This ought to be able to handle more than one such frame. */
12416 if (pending_autoraise_frame)
12417 {
12418 x_raise_frame (pending_autoraise_frame);
12419 pending_autoraise_frame = 0;
12420 }
12421
19ee09cc
YM
12422 if (mac_screen_config_changed)
12423 {
12424 mac_get_screen_info (dpyinfo);
12425 mac_screen_config_changed = 0;
12426 }
12427
3354caee 12428#if !TARGET_API_MAC_CARBON
1f98fbb4
YM
12429 /* Check which frames are still visible. We do this here because
12430 there doesn't seem to be any direct notification from the Window
12431 Manager that the visibility of a window has changed (at least,
12432 not in all cases). */
12433 {
12434 Lisp_Object tail, frame;
12435
12436 FOR_EACH_FRAME (tail, frame)
12437 {
12438 struct frame *f = XFRAME (frame);
12439
12440 /* The tooltip has been drawn already. Avoid the
12441 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
12442 if (EQ (frame, tip_frame))
12443 continue;
12444
12445 if (FRAME_MAC_P (f))
12446 mac_handle_visibility_change (f);
12447 }
12448 }
12449#endif
12450
b465419f 12451 --handling_signal;
6b61353c 12452 UNBLOCK_INPUT;
1a578e9b
AC
12453 return count;
12454}
12455
12456
12457/* Need to override CodeWarrior's input function so no conversion is
12458 done on newlines Otherwise compiled functions in .elc files will be
12459 read incorrectly. Defined in ...:MSL C:MSL
12460 Common:Source:buffer_io.c. */
12461#ifdef __MWERKS__
12462void
12463__convert_to_newlines (unsigned char * p, size_t * n)
12464{
12465#pragma unused(p,n)
12466}
12467
12468void
12469__convert_from_newlines (unsigned char * p, size_t * n)
12470{
12471#pragma unused(p,n)
12472}
12473#endif
12474
b15325b2 12475#ifdef MAC_OS8
770136ad 12476void
50bf7673 12477make_mac_terminal_frame (struct frame *f)
1a578e9b 12478{
50bf7673 12479 Lisp_Object frame;
b15325b2 12480 Rect r;
177c0ea7 12481
50bf7673
ST
12482 XSETFRAME (frame, f);
12483
12484 f->output_method = output_mac;
12485 f->output_data.mac = (struct mac_output *)
12486 xmalloc (sizeof (struct mac_output));
12487 bzero (f->output_data.mac, sizeof (struct mac_output));
12488
12489 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
177c0ea7 12490
50bf7673
ST
12491 FRAME_COLS (f) = 96;
12492 FRAME_LINES (f) = 4;
12493
12494 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12495 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12496
12497 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
1a578e9b
AC
12498
12499 f->output_data.mac->cursor_pixel = 0;
12500 f->output_data.mac->border_pixel = 0x00ff00;
12501 f->output_data.mac->mouse_pixel = 0xff00ff;
12502 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12503
25c9622b
YM
12504 f->output_data.mac->text_cursor = kThemeIBeamCursor;
12505 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
12506 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
12507 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
12508 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
12509 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
b15325b2 12510
f1a83aab 12511 FRAME_FONTSET (f) = -1;
1a578e9b 12512 f->output_data.mac->explicit_parent = 0;
b15325b2
ST
12513 f->left_pos = 8;
12514 f->top_pos = 32;
f1a83aab 12515 f->border_width = 0;
177c0ea7 12516
f1a83aab 12517 f->internal_border_width = 0;
1a578e9b 12518
1a578e9b
AC
12519 f->auto_raise = 1;
12520 f->auto_lower = 1;
177c0ea7 12521
f1a83aab
KS
12522 f->new_text_cols = 0;
12523 f->new_text_lines = 0;
6b61353c 12524
b15325b2
ST
12525 SetRect (&r, f->left_pos, f->top_pos,
12526 f->left_pos + FRAME_PIXEL_WIDTH (f),
12527 f->top_pos + FRAME_PIXEL_HEIGHT (f));
12528
12529 BLOCK_INPUT;
12530
12531 if (!(FRAME_MAC_WINDOW (f) =
12532 NewCWindow (NULL, &r, "\p", true, dBoxProc,
3354caee 12533 (WindowRef) -1, 1, (long) f->output_data.mac)))
b15325b2
ST
12534 abort ();
12535 /* so that update events can find this mac_output struct */
12536 f->output_data.mac->mFP = f; /* point back to emacs frame */
12537
12538 UNBLOCK_INPUT;
e0f712ba
AC
12539
12540 x_make_gc (f);
177c0ea7 12541
e0f712ba
AC
12542 /* Need to be initialized for unshow_buffer in window.c. */
12543 selected_window = f->selected_window;
12544
1a578e9b
AC
12545 Fmodify_frame_parameters (frame,
12546 Fcons (Fcons (Qfont,
12547 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12548 Fmodify_frame_parameters (frame,
12549 Fcons (Fcons (Qforeground_color,
12550 build_string ("black")), Qnil));
12551 Fmodify_frame_parameters (frame,
12552 Fcons (Fcons (Qbackground_color,
12553 build_string ("white")), Qnil));
12554}
b15325b2 12555#endif
1a578e9b 12556
e0f712ba
AC
12557\f
12558/***********************************************************************
12559 Initialization
12560 ***********************************************************************/
12561
19ee09cc 12562static int mac_initialized = 0;
b15325b2 12563
b298e813 12564static XrmDatabase
b15325b2 12565mac_make_rdb (xrm_option)
369a7a37 12566 const char *xrm_option;
b15325b2 12567{
b298e813 12568 XrmDatabase database;
b15325b2 12569
b298e813
YM
12570 database = xrm_get_preference_database (NULL);
12571 if (xrm_option)
12572 xrm_merge_string_database (database, xrm_option);
b15325b2 12573
b298e813 12574 return database;
b15325b2
ST
12575}
12576
e0f712ba
AC
12577struct mac_display_info *
12578mac_term_init (display_name, xrm_option, resource_name)
12579 Lisp_Object display_name;
12580 char *xrm_option;
12581 char *resource_name;
12582{
12583 struct mac_display_info *dpyinfo;
80ca7302 12584 struct terminal *terminal;
b15325b2
ST
12585
12586 BLOCK_INPUT;
e0f712ba
AC
12587
12588 if (!mac_initialized)
12589 {
12590 mac_initialize ();
12591 mac_initialized = 1;
12592 }
12593
b15325b2
ST
12594 if (x_display_list)
12595 error ("Sorry, this version can only handle one display");
12596
e0f712ba 12597 dpyinfo = &one_mac_display_info;
19ee09cc
YM
12598 bzero (dpyinfo, sizeof (*dpyinfo));
12599
80ca7302
DN
12600 terminal = mac_create_terminal (dpyinfo);
12601
12602 /* Set the name of the terminal. */
12603 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
12604 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
12605 terminal->name[SBYTES (display_name)] = 0;
12606
19ee09cc
YM
12607#ifdef MAC_OSX
12608 dpyinfo->mac_id_name
12609 = (char *) xmalloc (SCHARS (Vinvocation_name)
12610 + SCHARS (Vsystem_name)
12611 + 2);
12612 sprintf (dpyinfo->mac_id_name, "%s@%s",
12613 SDATA (Vinvocation_name), SDATA (Vsystem_name));
12614#else
12615 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
12616 strcpy (dpyinfo->mac_id_name, "Mac Display");
12617#endif
12618
12619 dpyinfo->reference_count = 0;
12620 dpyinfo->resx = 72.0;
12621 dpyinfo->resy = 72.0;
12622
12623 mac_get_screen_info (dpyinfo);
12624
12625 dpyinfo->grabbed = 0;
12626 dpyinfo->root_window = NULL;
354884c4 12627 dpyinfo->terminal->image_cache = make_image_cache ();
19ee09cc
YM
12628
12629 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12630 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12631 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12632 dpyinfo->mouse_face_window = Qnil;
12633 dpyinfo->mouse_face_overlay = Qnil;
12634 dpyinfo->mouse_face_hidden = 0;
e0f712ba 12635
b298e813 12636 dpyinfo->xrdb = mac_make_rdb (xrm_option);
e0f712ba 12637
b15325b2
ST
12638 /* Put this display on the chain. */
12639 dpyinfo->next = x_display_list;
12640 x_display_list = dpyinfo;
12641
12642 /* Put it on x_display_name_list. */
b298e813
YM
12643 x_display_name_list = Fcons (Fcons (display_name,
12644 Fcons (Qnil, dpyinfo->xrdb)),
b15325b2
ST
12645 x_display_name_list);
12646 dpyinfo->name_list_element = XCAR (x_display_name_list);
12647
b951420f
DN
12648 /* FIXME: Untested.
12649 Add the default keyboard. */
12650 add_keyboard_wait_descriptor (0);
12651
9c7c716d
JR
12652#if USE_CG_DRAWING
12653 mac_init_fringe (terminal->rif);
12654#endif
12655
b15325b2 12656 UNBLOCK_INPUT;
1a578e9b 12657
e0f712ba 12658 return dpyinfo;
1a578e9b 12659}
19ee09cc 12660\f
b15325b2
ST
12661/* Get rid of display DPYINFO, assuming all frames are already gone. */
12662
12663void
12664x_delete_display (dpyinfo)
12665 struct mac_display_info *dpyinfo;
12666{
12667 int i;
12668
12669 /* Discard this display from x_display_name_list and x_display_list.
12670 We can't use Fdelq because that can quit. */
12671 if (! NILP (x_display_name_list)
12672 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12673 x_display_name_list = XCDR (x_display_name_list);
12674 else
12675 {
12676 Lisp_Object tail;
12677
12678 tail = x_display_name_list;
12679 while (CONSP (tail) && CONSP (XCDR (tail)))
12680 {
12681 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
12682 {
12683 XSETCDR (tail, XCDR (XCDR (tail)));
12684 break;
12685 }
12686 tail = XCDR (tail);
12687 }
12688 }
12689
12690 if (x_display_list == dpyinfo)
12691 x_display_list = dpyinfo->next;
12692 else
12693 {
12694 struct x_display_info *tail;
12695
12696 for (tail = x_display_list; tail; tail = tail->next)
12697 if (tail->next == dpyinfo)
12698 tail->next = tail->next->next;
12699 }
12700
12701 /* Free the font names in the font table. */
12702 for (i = 0; i < dpyinfo->n_fonts; i++)
12703 if (dpyinfo->font_table[i].name)
12704 {
12705 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
12706 xfree (dpyinfo->font_table[i].full_name);
12707 xfree (dpyinfo->font_table[i].name);
12708 }
12709
1e53bd0e
YM
12710 if (dpyinfo->font_table)
12711 {
12712 if (dpyinfo->font_table->font_encoder)
12713 xfree (dpyinfo->font_table->font_encoder);
12714 xfree (dpyinfo->font_table);
12715 }
12716 if (dpyinfo->mac_id_name)
12717 xfree (dpyinfo->mac_id_name);
b15325b2
ST
12718
12719 if (x_display_list == 0)
12720 {
12721 mac_clear_font_name_table ();
12722 bzero (dpyinfo, sizeof (*dpyinfo));
12723 }
12724}
12725
e0f712ba 12726\f
1c05c15b
YM
12727static void
12728init_menu_bar ()
12729{
12730#ifdef MAC_OSX
3e7424f7 12731 OSStatus err;
1c05c15b
YM
12732 MenuRef menu;
12733 MenuItemIndex menu_index;
12734
12735 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
12736 &menu, &menu_index);
12737 if (err == noErr)
12738 SetMenuItemCommandKey (menu, menu_index, false, 0);
1c05c15b
YM
12739 EnableMenuCommand (NULL, kHICommandPreferences);
12740 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
12741 &menu, &menu_index);
12742 if (err == noErr)
12743 {
12744 SetMenuItemCommandKey (menu, menu_index, false, 0);
12745 InsertMenuItemTextWithCFString (menu, NULL,
12746 0, kMenuItemAttrSeparator, 0);
12747 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
12748 0, 0, kHICommandAbout);
12749 }
1c05c15b 12750#else /* !MAC_OSX */
3354caee
YM
12751#if TARGET_API_MAC_CARBON
12752 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
1c05c15b
YM
12753#endif
12754#endif
12755}
12756
02236cbc
YM
12757#if USE_MAC_TSM
12758static void
12759init_tsm ()
12760{
92289429 12761#ifdef MAC_OSX
02236cbc 12762 static InterfaceTypeList types = {kUnicodeDocument};
92289429
YM
12763#else
12764 static InterfaceTypeList types = {kTextService};
12765#endif
02236cbc
YM
12766
12767 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
12768 &tsm_document_id, 0);
12769}
12770#endif
1c05c15b 12771
e0f712ba
AC
12772/* Set up use of X before we make the first connection. */
12773
88cd462d
KS
12774extern frame_parm_handler mac_frame_parm_handlers[];
12775
e0f712ba
AC
12776static struct redisplay_interface x_redisplay_interface =
12777{
88cd462d 12778 mac_frame_parm_handlers,
e0f712ba
AC
12779 x_produce_glyphs,
12780 x_write_glyphs,
12781 x_insert_glyphs,
12782 x_clear_end_of_line,
12783 x_scroll_run,
12784 x_after_update_window_line,
12785 x_update_window_begin,
12786 x_update_window_end,
f9e65eb3
KS
12787 x_cursor_to,
12788 x_flush,
e6509087
YM
12789#if USE_CG_DRAWING
12790 mac_flush_display_optional,
12791#else
fc7a70cc 12792 0, /* flush_display_optional */
e6509087 12793#endif
f9e65eb3 12794 x_clear_window_mouse_face,
e0f712ba 12795 x_get_glyph_overhangs,
5958f265 12796 x_fix_overlapping_area,
750fc673 12797 x_draw_fringe_bitmap,
ad21830e
YM
12798#if USE_CG_DRAWING
12799 mac_define_fringe_bitmap,
12800 mac_destroy_fringe_bitmap,
12801#else
6b61353c
KH
12802 0, /* define_fringe_bitmap */
12803 0, /* destroy_fringe_bitmap */
ad21830e 12804#endif
750fc673
KS
12805 mac_per_char_metric,
12806 mac_encode_char,
8c2da0fa 12807 mac_compute_glyph_string_overhangs,
f9e65eb3
KS
12808 x_draw_glyph_string,
12809 mac_define_frame_cursor,
12810 mac_clear_frame_area,
12811 mac_draw_window_cursor,
efcf4234 12812 mac_draw_vertical_window_border,
f9e65eb3 12813 mac_shift_glyphs_for_insert
e0f712ba 12814};
1a578e9b 12815
80ca7302
DN
12816static struct terminal *
12817mac_create_terminal (struct mac_display_info *dpyinfo)
12818{
12819 struct terminal *terminal;
12820
12821 terminal = create_terminal ();
12822
12823 terminal->type = output_mac;
12824 terminal->display_info.mac = dpyinfo;
12825 dpyinfo->terminal = terminal;
12826
80ca7302
DN
12827 terminal->clear_frame_hook = x_clear_frame;
12828 terminal->ins_del_lines_hook = x_ins_del_lines;
12829 terminal->delete_glyphs_hook = x_delete_glyphs;
12830 terminal->ring_bell_hook = XTring_bell;
12831 terminal->reset_terminal_modes_hook = XTreset_terminal_modes;
12832 terminal->set_terminal_modes_hook = XTset_terminal_modes;
12833 terminal->update_begin_hook = x_update_begin;
12834 terminal->update_end_hook = x_update_end;
12835 terminal->set_terminal_window_hook = XTset_terminal_window;
12836 terminal->read_socket_hook = XTread_socket;
12837 terminal->frame_up_to_date_hook = XTframe_up_to_date;
12838 terminal->mouse_position_hook = XTmouse_position;
12839 terminal->frame_rehighlight_hook = XTframe_rehighlight;
12840 terminal->frame_raise_lower_hook = XTframe_raise_lower;
88acaaf2
DN
12841 /* terminal->fullscreen_hook = XTfullscreen_hook; */
12842 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12843 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12844 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
12845 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
12846 terminal->delete_frame_hook = x_destroy_window;
12847 /* terminal->delete_terminal_hook = x_delete_terminal; */
80ca7302 12848
88acaaf2 12849 terminal->rif = &x_redisplay_interface;
80ca7302 12850#if 0
28d440ab
KL
12851 TTY_SCROLL_REGION_OK (CURTTY ()) = 1; /* we'll scroll partial frames */
12852 TTY_CHAR_INS_DEL_OK (CURTTY ()) = 1;
12853 TTY_LINE_INS_DEL_OK (CURTTY ()) = 1; /* we'll just blt 'em */
12854 TTY_FAST_CLEAR_END_OF_LINE (CURTTY ()) = 1; /* X does this well */
12855 TTY_MEMORY_BELOW_FRAME (CURTTY ()) = 0; /* we don't remember what
8a56675d
KL
12856 scrolls off the
12857 bottom */
80ca7302
DN
12858#else
12859 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
12860 terminal->char_ins_del_ok = 1;
12861 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
12862 terminal->fast_clear_end_of_line = 1; /* X does this well. */
12863 terminal->memory_below_frame = 0; /* We don't remember what scrolls
12864 off the bottom. */
12865
70b8d0a4
SM
12866#endif
12867
12868 /* FIXME: This keyboard setup is 100% untested, just copied from
12869 w32_create_terminal in order to set window-system now that it's
12870 a keyboard object. */
70b8d0a4
SM
12871 /* We don't yet support separate terminals on Mac, so don't try to share
12872 keyboards between virtual terminals that are on the same physical
12873 terminal like X does. */
12874 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
12875 init_kboard (terminal->kboard);
12876 terminal->kboard->Vwindow_system = intern ("mac");
12877 terminal->kboard->next_kboard = all_kboards;
12878 all_kboards = terminal->kboard;
12879 /* Don't let the initial kboard remain current longer than necessary.
12880 That would cause problems if a file loaded on startup tries to
12881 prompt in the mini-buffer. */
12882 if (current_kboard == initial_kboard)
12883 current_kboard = terminal->kboard;
12884 terminal->kboard->reference_count++;
9c7c716d 12885
80ca7302
DN
12886 return terminal;
12887}
12888
12889static void
e0f712ba 12890mac_initialize ()
1a578e9b 12891{
80ca7302 12892
1a578e9b
AC
12893 baud_rate = 19200;
12894
1a578e9b
AC
12895 last_tool_bar_item = -1;
12896 any_help_event_p = 0;
177c0ea7 12897
1a578e9b 12898 /* Try to use interrupt input; if we can't, then start polling. */
a712a8c3 12899 Fset_input_interrupt_mode (Qt);
1a578e9b 12900
c3f4c690 12901 BLOCK_INPUT;
bc21bf11
AC
12902
12903#if TARGET_API_MAC_CARBON
bc21bf11 12904
7adf3143 12905 install_application_handler ();
1c05c15b
YM
12906
12907 init_menu_bar ();
02236cbc
YM
12908
12909#if USE_MAC_TSM
12910 init_tsm ();
12911#endif
8030369c 12912
25c9622b 12913#ifdef MAC_OSX
0e0a1663
YM
12914 init_coercion_handler ();
12915
6a0b5d37
YM
12916 init_apple_event_handler ();
12917
19ee09cc
YM
12918 init_dm_notification_handler ();
12919
8030369c 12920 if (!inhibit_window_system)
5eafe967
YM
12921 {
12922 static const ProcessSerialNumber psn = {0, kCurrentProcess};
12923
12924 SetFrontProcess (&psn);
12925 }
25c9622b 12926#endif
bc21bf11 12927#endif
ad21830e
YM
12928
12929#if USE_CG_DRAWING
e2d3b7e1 12930 init_cg_color ();
ad21830e
YM
12931#endif
12932
c3f4c690 12933 UNBLOCK_INPUT;
80ca7302 12934
1a578e9b
AC
12935}
12936
12937
12938void
12939syms_of_macterm ()
12940{
12941#if 0
12942 staticpro (&x_error_message_string);
12943 x_error_message_string = Qnil;
12944#endif
12945
f2d8779b
YM
12946 Qcontrol = intern ("control"); staticpro (&Qcontrol);
12947 Qmeta = intern ("meta"); staticpro (&Qmeta);
12948 Qalt = intern ("alt"); staticpro (&Qalt);
12949 Qhyper = intern ("hyper"); staticpro (&Qhyper);
12950 Qsuper = intern ("super"); staticpro (&Qsuper);
a36f1680 12951 Qmodifier_value = intern ("modifier-value");
f2d8779b 12952 staticpro (&Qmodifier_value);
a36f1680 12953
f2d8779b
YM
12954 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
12955 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
12956 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
12957 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
12958 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
1c05c15b 12959
3354caee 12960#if TARGET_API_MAC_CARBON
3e7424f7 12961 Qhi_command = intern ("hi-command"); staticpro (&Qhi_command);
6a0b5d37 12962#ifdef MAC_OSX
68c767a3
YM
12963 Qtoolbar_switch_mode = intern ("toolbar-switch-mode");
12964 staticpro (&Qtoolbar_switch_mode);
12965#if USE_MAC_FONT_PANEL
12966 Qpanel_closed = intern ("panel-closed"); staticpro (&Qpanel_closed);
12967 Qselection = intern ("selection"); staticpro (&Qselection);
12968#endif
12969
4cb62a90 12970 Qservice = intern ("service"); staticpro (&Qservice);
1c05c15b
YM
12971 Qpaste = intern ("paste"); staticpro (&Qpaste);
12972 Qperform = intern ("perform"); staticpro (&Qperform);
12973#endif
02236cbc
YM
12974#if USE_MAC_TSM
12975 Qtext_input = intern ("text-input"); staticpro (&Qtext_input);
12976 Qupdate_active_input_area = intern ("update-active-input-area");
12977 staticpro (&Qupdate_active_input_area);
12978 Qunicode_for_key_event = intern ("unicode-for-key-event");
12979 staticpro (&Qunicode_for_key_event);
12980#endif
6a0b5d37 12981#endif
1c05c15b 12982
b15325b2 12983#ifdef MAC_OSX
8c609cff 12984 Fprovide (intern ("mac-carbon"), Qnil);
b15325b2 12985#endif
8c609cff 12986
6b61353c
KH
12987 staticpro (&Qreverse);
12988 Qreverse = intern ("reverse");
12989
1a578e9b
AC
12990 staticpro (&x_display_name_list);
12991 x_display_name_list = Qnil;
12992
12993 staticpro (&last_mouse_scroll_bar);
12994 last_mouse_scroll_bar = Qnil;
12995
71b7a47f
YM
12996 staticpro (&fm_font_family_alist);
12997 fm_font_family_alist = Qnil;
8f47302e 12998
c3bd8190
YM
12999#if USE_ATSUI
13000 staticpro (&atsu_font_id_hash);
13001 atsu_font_id_hash = Qnil;
92289429
YM
13002
13003 staticpro (&fm_style_face_attributes_alist);
13004 fm_style_face_attributes_alist = Qnil;
13005#endif
13006
13007#if USE_MAC_TSM
13008 staticpro (&saved_ts_script_language_on_focus);
13009 saved_ts_script_language_on_focus = Qnil;
c3bd8190
YM
13010#endif
13011
70ed951a
YM
13012 /* We don't yet support this, but defining this here avoids whining
13013 from cus-start.el and other places, like "M-x set-variable". */
13014 DEFVAR_BOOL ("x-use-underline-position-properties",
13015 &x_use_underline_position_properties,
13016 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
17cf2c3e 13017A value of nil means ignore them. If you encounter fonts with bogus
70ed951a
YM
13018UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
13019to 4.1, set this to nil.
13020
13021NOTE: Not supported on Mac yet. */);
13022 x_use_underline_position_properties = 0;
13023
cf2c6835
YM
13024 DEFVAR_BOOL ("x-underline-at-descent-line",
13025 &x_underline_at_descent_line,
13026 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
17cf2c3e
JB
13027A value of nil means to draw the underline according to the value of the
13028variable `x-use-underline-position-properties', which is usually at the
13029baseline level. The default value is nil. */);
cf2c6835
YM
13030 x_underline_at_descent_line = 0;
13031
e0f712ba 13032 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
68c767a3 13033 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
5b8b73ff 13034#ifdef USE_TOOLKIT_SCROLL_BARS
e0f712ba 13035 Vx_toolkit_scroll_bars = Qt;
5b8b73ff
YM
13036#else
13037 Vx_toolkit_scroll_bars = Qnil;
13038#endif
e0f712ba 13039
1a578e9b
AC
13040 staticpro (&last_mouse_motion_frame);
13041 last_mouse_motion_frame = Qnil;
177c0ea7 13042
b02e3f7b 13043/* Variables to configure modifier key assignment. */
16805b2e 13044
b02e3f7b 13045 DEFVAR_LISP ("mac-control-modifier", &Vmac_control_modifier,
70ed951a
YM
13046 doc: /* *Modifier key assumed when the Mac control key is pressed.
13047The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13048respective modifier. The default is `control'. */);
13049 Vmac_control_modifier = Qcontrol;
1a578e9b 13050
a36f1680 13051 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
70ed951a
YM
13052 doc: /* *Modifier key assumed when the Mac alt/option key is pressed.
13053The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13054respective modifier. If the value is nil then the key will act as the
13055normal Mac control modifier, and the option key can be used to compose
13056characters depending on the chosen Mac keyboard setting. */);
a36f1680
JW
13057 Vmac_option_modifier = Qnil;
13058
b02e3f7b 13059 DEFVAR_LISP ("mac-command-modifier", &Vmac_command_modifier,
70ed951a
YM
13060 doc: /* *Modifier key assumed when the Mac command key is pressed.
13061The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b 13062respective modifier. The default is `meta'. */);
b02e3f7b
ST
13063 Vmac_command_modifier = Qmeta;
13064
13065 DEFVAR_LISP ("mac-function-modifier", &Vmac_function_modifier,
70ed951a
YM
13066 doc: /* *Modifier key assumed when the Mac function key is pressed.
13067The value can be `control', `meta', `alt', `hyper', or `super' for the
f2d8779b
YM
13068respective modifier. Note that remapping the function key may lead to
13069unexpected results for some keys on non-US/GB keyboards. */);
b02e3f7b 13070 Vmac_function_modifier = Qnil;
742fbed7 13071
ffe8b3f4 13072 DEFVAR_LISP ("mac-emulate-three-button-mouse",
6b61353c 13073 &Vmac_emulate_three_button_mouse,
70ed951a 13074 doc: /* *Specify a way of three button mouse emulation.
f2d8779b 13075The value can be nil, t, or the symbol `reverse'.
17cf2c3e
JB
13076A value of nil means that no emulation should be done and the modifiers
13077should be placed on the mouse-1 event.
f2d8779b
YM
13078t means that when the option-key is held down while pressing the mouse
13079button, the click will register as mouse-2 and while the command-key
13080is held down, the click will register as mouse-3.
13081The symbol `reverse' means that the option-key will register for
13082mouse-3 and the command-key will register for mouse-2. */);
6b61353c
KH
13083 Vmac_emulate_three_button_mouse = Qnil;
13084
3354caee 13085#if TARGET_API_MAC_CARBON
70ed951a 13086 DEFVAR_BOOL ("mac-wheel-button-is-mouse-2", &mac_wheel_button_is_mouse_2,
68c767a3 13087 doc: /* *Non-nil if the wheel button is mouse-2 and the right click mouse-3.
f2d8779b
YM
13088Otherwise, the right click will be treated as mouse-2 and the wheel
13089button will be mouse-3. */);
70ed951a 13090 mac_wheel_button_is_mouse_2 = 1;
5883787c 13091
70ed951a 13092 DEFVAR_BOOL ("mac-pass-command-to-system", &mac_pass_command_to_system,
68c767a3 13093 doc: /* *Non-nil if command key presses are passed on to the Mac Toolbox. */);
70ed951a 13094 mac_pass_command_to_system = 1;
5883787c 13095
70ed951a 13096 DEFVAR_BOOL ("mac-pass-control-to-system", &mac_pass_control_to_system,
68c767a3 13097 doc: /* *Non-nil if control key presses are passed on to the Mac Toolbox. */);
70ed951a 13098 mac_pass_control_to_system = 1;
743d0696 13099
742fbed7
AC
13100#endif
13101
70ed951a 13102 DEFVAR_BOOL ("mac-allow-anti-aliasing", &mac_use_core_graphics,
68c767a3 13103 doc: /* *If non-nil, allow anti-aliasing.
e24531b7
KS
13104The text will be rendered using Core Graphics text rendering which
13105may anti-alias the text. */);
458dbb8c
YM
13106#if USE_CG_DRAWING
13107 mac_use_core_graphics = 1;
13108#else
faef8681 13109 mac_use_core_graphics = 0;
458dbb8c 13110#endif
94d0e806
YM
13111
13112 /* Register an entry for `mac-roman' so that it can be used when
13113 creating the terminal frame on Mac OS 9 before loading
13114 term/mac-win.elc. */
13115 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
68c767a3 13116 doc: /* Alist of Emacs character sets vs text encodings and coding systems.
94d0e806
YM
13117Each entry should be of the form:
13118
13119 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
13120
13121where CHARSET-NAME is a string used in font names to identify the
f2d8779b
YM
13122charset, TEXT-ENCODING is a TextEncodingBase value in Mac, and
13123CODING_SYSTEM is a coding system corresponding to TEXT-ENCODING. */);
94d0e806
YM
13124 Vmac_charset_info_alist =
13125 Fcons (list3 (build_string ("mac-roman"),
13126 make_number (smRoman), Qnil), Qnil);
68c767a3 13127
02236cbc
YM
13128#if USE_MAC_TSM
13129 DEFVAR_LISP ("mac-ts-active-input-overlay", &Vmac_ts_active_input_overlay,
13130 doc: /* Overlay used to display Mac TSM active input area. */);
13131 Vmac_ts_active_input_overlay = Qnil;
b4c51596
YM
13132
13133 DEFVAR_LISP ("mac-ts-script-language-on-focus", &Vmac_ts_script_language_on_focus,
13134 doc: /* *How to change Mac TSM script/language when a frame gets focus.
13135If the value is t, the input script and language are restored to those
13136used in the last focus frame. If the value is a pair of integers, the
13137input script and language codes, which are defined in the Script
13138Manager, are set to its car and cdr parts, respectively. Otherwise,
13139Emacs doesn't set them and thus follows the system default behavior. */);
13140 Vmac_ts_script_language_on_focus = Qnil;
02236cbc 13141#endif
1a578e9b 13142}
6b61353c
KH
13143
13144/* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
13145 (do not change this comment) */