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