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