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