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