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