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