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