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