]> code.delx.au - gnu-emacs/blob - src/macterm.c
Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-86
[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->last_char != '?');
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 if (size > 0 || style == normal)
6710 for (; !NILP (rest); rest = XCDR (rest))
6711 {
6712 char *cs = SDATA (XCAR (rest));
6713
6714 if (size == 0)
6715 {
6716 add_font_name_table_entry (mac_to_x_fontname (name, size,
6717 style, cs));
6718 add_font_name_table_entry (mac_to_x_fontname (name, size,
6719 italic, cs));
6720 add_font_name_table_entry (mac_to_x_fontname (name, size,
6721 bold, cs));
6722 add_font_name_table_entry (mac_to_x_fontname (name, size,
6723 italic | bold,
6724 cs));
6725 }
6726 else
6727 {
6728 add_font_name_table_entry (mac_to_x_fontname (name, size,
6729 style, cs));
6730 }
6731 }
6732 }
6733 }
6734
6735 UNGCPRO;
6736
6737 /* Dispose of the iterators. */
6738 FMDisposeFontFamilyIterator (&ffi);
6739 FMDisposeFontFamilyInstanceIterator (&ffii);
6740 #else /* !TARGET_API_MAC_CARBON */
6741 GrafPtr port;
6742 SInt16 fontnum, old_fontnum;
6743 int num_mac_fonts = CountResources('FOND');
6744 int i, j;
6745 Handle font_handle, font_handle_2;
6746 short id, scriptcode;
6747 ResType type;
6748 Str255 name;
6749 struct FontAssoc *fat;
6750 struct AsscEntry *assc_entry;
6751 Lisp_Object text_encoding_info_alist, text_encoding_info;
6752 struct gcpro gcpro1;
6753
6754 GetPort (&port); /* save the current font number used */
6755 old_fontnum = port->txFont;
6756
6757 text_encoding_info_alist = create_text_encoding_info_alist ();
6758
6759 GCPRO1 (text_encoding_info_alist);
6760
6761 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
6762 {
6763 font_handle = GetIndResource ('FOND', i);
6764 if (!font_handle)
6765 continue;
6766
6767 GetResInfo (font_handle, &id, &type, name);
6768 GetFNum (name, &fontnum);
6769 p2cstr (name);
6770 if (fontnum == 0)
6771 continue;
6772
6773 TextFont (fontnum);
6774 scriptcode = FontToScript (fontnum);
6775 text_encoding_info = assq_no_quit (make_number (scriptcode),
6776 text_encoding_info_alist);
6777 if (!NILP (text_encoding_info))
6778 decode_mac_font_name (name, sizeof (name),
6779 XCAR (XCDR (text_encoding_info)));
6780 else
6781 text_encoding_info = assq_no_quit (make_number (smRoman),
6782 text_encoding_info_alist);
6783 do
6784 {
6785 HLock (font_handle);
6786
6787 if (GetResourceSizeOnDisk (font_handle)
6788 >= sizeof (struct FamRec))
6789 {
6790 fat = (struct FontAssoc *) (*font_handle
6791 + sizeof (struct FamRec));
6792 assc_entry
6793 = (struct AsscEntry *) (*font_handle
6794 + sizeof (struct FamRec)
6795 + sizeof (struct FontAssoc));
6796
6797 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
6798 {
6799 Lisp_Object rest = XCDR (XCDR (text_encoding_info));
6800
6801 for (; !NILP (rest); rest = XCDR (rest))
6802 {
6803 char *cs = SDATA (XCAR (rest));
6804
6805 add_font_name_table_entry (mac_to_x_fontname (name,
6806 assc_entry->fontSize,
6807 assc_entry->fontStyle,
6808 cs));
6809 }
6810 }
6811 }
6812
6813 HUnlock (font_handle);
6814 font_handle_2 = GetNextFOND (font_handle);
6815 ReleaseResource (font_handle);
6816 font_handle = font_handle_2;
6817 }
6818 while (ResError () == noErr && font_handle);
6819 }
6820
6821 UNGCPRO;
6822
6823 TextFont (old_fontnum);
6824 #endif /* !TARGET_API_MAC_CARBON */
6825 }
6826
6827
6828 void
6829 mac_clear_font_name_table ()
6830 {
6831 int i;
6832
6833 for (i = 0; i < font_name_count; i++)
6834 xfree (font_name_table[i]);
6835 xfree (font_name_table);
6836 font_name_table = NULL;
6837 font_name_table_size = font_name_count = 0;
6838 }
6839
6840
6841 enum xlfd_scalable_field_index
6842 {
6843 XLFD_SCL_PIXEL_SIZE,
6844 XLFD_SCL_POINT_SIZE,
6845 XLFD_SCL_AVGWIDTH,
6846 XLFD_SCL_LAST
6847 };
6848
6849 static int xlfd_scalable_fields[] =
6850 {
6851 6, /* PIXEL_SIZE */
6852 7, /* POINT_SIZE */
6853 11, /* AVGWIDTH */
6854 -1
6855 };
6856
6857 static Lisp_Object
6858 mac_do_list_fonts (pattern, maxnames)
6859 char *pattern;
6860 int maxnames;
6861 {
6862 int i, n_fonts = 0;
6863 Lisp_Object font_list = Qnil;
6864 struct xlfdpat *pat;
6865 char *scaled, *ptr;
6866 int scl_val[XLFD_SCL_LAST], *field, *val;
6867 int exact;
6868
6869 if (font_name_table == NULL) /* Initialize when first used. */
6870 init_font_name_table ();
6871
6872 for (i = 0; i < XLFD_SCL_LAST; i++)
6873 scl_val[i] = -1;
6874
6875 /* If the pattern contains 14 dashes and one of PIXEL_SIZE,
6876 POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable
6877 fonts are scaled according to the specified size. */
6878 ptr = pattern;
6879 i = 0;
6880 field = xlfd_scalable_fields;
6881 val = scl_val;
6882 if (*ptr == '-')
6883 do
6884 {
6885 ptr++;
6886 if (i == *field)
6887 {
6888 if ('0' <= *ptr && *ptr <= '9')
6889 {
6890 *val = *ptr++ - '0';
6891 while ('0' <= *ptr && *ptr <= '9' && *val < 10000)
6892 *val = *val * 10 + *ptr++ - '0';
6893 if (*ptr != '-')
6894 *val = -1;
6895 }
6896 field++;
6897 val++;
6898 }
6899 ptr = strchr (ptr, '-');
6900 i++;
6901 }
6902 while (ptr && i < 14);
6903
6904 if (i == 14 && ptr == NULL)
6905 {
6906 if (scl_val[XLFD_SCL_PIXEL_SIZE] < 0)
6907 scl_val[XLFD_SCL_PIXEL_SIZE] =
6908 (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE] / 10
6909 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH] / 10
6910 : -1));
6911 if (scl_val[XLFD_SCL_POINT_SIZE] < 0)
6912 scl_val[XLFD_SCL_POINT_SIZE] =
6913 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
6914 : (scl_val[XLFD_SCL_AVGWIDTH] > 0 ? scl_val[XLFD_SCL_AVGWIDTH]
6915 : -1));
6916 if (scl_val[XLFD_SCL_AVGWIDTH] < 0)
6917 scl_val[XLFD_SCL_AVGWIDTH] =
6918 (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 ? scl_val[XLFD_SCL_PIXEL_SIZE] * 10
6919 : (scl_val[XLFD_SCL_POINT_SIZE] > 0 ? scl_val[XLFD_SCL_POINT_SIZE]
6920 : -1));
6921 }
6922 else
6923 scl_val[XLFD_SCL_PIXEL_SIZE] = -1;
6924
6925 pat = xlfdpat_create (pattern);
6926 if (pat == NULL)
6927 return Qnil;
6928
6929 exact = xlfdpat_exact_p (pat);
6930
6931 for (i = 0; i < font_name_count; i++)
6932 {
6933 if (xlfdpat_match (pat, font_name_table[i]))
6934 {
6935 font_list = Fcons (build_string (font_name_table[i]), font_list);
6936 if (exact || maxnames > 0 && ++n_fonts >= maxnames)
6937 break;
6938 }
6939 else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0
6940 && (ptr = strstr (font_name_table[i], "-0-0-0-0-m-0-")))
6941 {
6942 int former_len = ptr - font_name_table[i];
6943
6944 scaled = xmalloc (strlen (font_name_table[i]) + 20 + 1);
6945 if (scaled == NULL)
6946 continue;
6947 memcpy (scaled, font_name_table[i], former_len);
6948 sprintf (scaled + former_len,
6949 "-%d-%d-75-75-m-%d-%s",
6950 scl_val[XLFD_SCL_PIXEL_SIZE],
6951 scl_val[XLFD_SCL_POINT_SIZE],
6952 scl_val[XLFD_SCL_AVGWIDTH],
6953 ptr + sizeof ("-0-0-0-0-m-0-") - 1);
6954
6955 if (xlfdpat_match (pat, scaled))
6956 {
6957 font_list = Fcons (build_string (scaled), font_list);
6958 xfree (scaled);
6959 if (exact || maxnames > 0 && ++n_fonts >= maxnames)
6960 break;
6961 }
6962 else
6963 xfree (scaled);
6964 }
6965 }
6966
6967 xlfdpat_destroy (pat);
6968
6969 return font_list;
6970 }
6971
6972 /* Return a list of names of available fonts matching PATTERN on frame F.
6973
6974 Frame F null means we have not yet created any frame on Mac, and
6975 consult the first display in x_display_list. MAXNAMES sets a limit
6976 on how many fonts to match. */
6977
6978 Lisp_Object
6979 x_list_fonts (f, pattern, size, maxnames)
6980 struct frame *f;
6981 Lisp_Object pattern;
6982 int size, maxnames;
6983 {
6984 Lisp_Object list = Qnil, patterns, tem, key;
6985 struct mac_display_info *dpyinfo
6986 = f ? FRAME_MAC_DISPLAY_INFO (f) : x_display_list;
6987
6988 xassert (size <= 0);
6989
6990 patterns = Fassoc (pattern, Valternate_fontname_alist);
6991 if (NILP (patterns))
6992 patterns = Fcons (pattern, Qnil);
6993
6994 for (; CONSP (patterns); patterns = XCDR (patterns))
6995 {
6996 pattern = XCAR (patterns);
6997
6998 if (!STRINGP (pattern))
6999 continue;
7000
7001 tem = XCAR (XCDR (dpyinfo->name_list_element));
7002 key = Fcons (pattern, make_number (maxnames));
7003
7004 list = Fassoc (key, tem);
7005 if (!NILP (list))
7006 {
7007 list = Fcdr_safe (list);
7008 /* We have a cashed list. Don't have to get the list again. */
7009 goto label_cached;
7010 }
7011
7012 BLOCK_INPUT;
7013 list = mac_do_list_fonts (SDATA (pattern), maxnames);
7014 UNBLOCK_INPUT;
7015
7016 /* MAC_TODO: add code for matching outline fonts here */
7017
7018 /* Now store the result in the cache. */
7019 XSETCAR (XCDR (dpyinfo->name_list_element),
7020 Fcons (Fcons (key, list),
7021 XCAR (XCDR (dpyinfo->name_list_element))));
7022
7023 label_cached:
7024 if (NILP (list)) continue; /* Try the remaining alternatives. */
7025 }
7026
7027 return list;
7028 }
7029
7030
7031 #if GLYPH_DEBUG
7032
7033 /* Check that FONT is valid on frame F. It is if it can be found in F's
7034 font table. */
7035
7036 static void
7037 x_check_font (f, font)
7038 struct frame *f;
7039 XFontStruct *font;
7040 {
7041 int i;
7042 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7043
7044 xassert (font != NULL);
7045
7046 for (i = 0; i < dpyinfo->n_fonts; i++)
7047 if (dpyinfo->font_table[i].name
7048 && font == dpyinfo->font_table[i].font)
7049 break;
7050
7051 xassert (i < dpyinfo->n_fonts);
7052 }
7053
7054 #endif /* GLYPH_DEBUG != 0 */
7055
7056 /* Set *W to the minimum width, *H to the minimum font height of FONT.
7057 Note: There are (broken) X fonts out there with invalid XFontStruct
7058 min_bounds contents. For example, handa@etl.go.jp reports that
7059 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
7060 have font->min_bounds.width == 0. */
7061
7062 static INLINE void
7063 x_font_min_bounds (font, w, h)
7064 MacFontStruct *font;
7065 int *w, *h;
7066 {
7067 *h = FONT_HEIGHT (font);
7068 *w = font->min_bounds.width;
7069 }
7070
7071
7072 /* Compute the smallest character width and smallest font height over
7073 all fonts available on frame F. Set the members smallest_char_width
7074 and smallest_font_height in F's x_display_info structure to
7075 the values computed. Value is non-zero if smallest_font_height or
7076 smallest_char_width become smaller than they were before. */
7077
7078 static int
7079 x_compute_min_glyph_bounds (f)
7080 struct frame *f;
7081 {
7082 int i;
7083 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7084 MacFontStruct *font;
7085 int old_width = dpyinfo->smallest_char_width;
7086 int old_height = dpyinfo->smallest_font_height;
7087
7088 dpyinfo->smallest_font_height = 100000;
7089 dpyinfo->smallest_char_width = 100000;
7090
7091 for (i = 0; i < dpyinfo->n_fonts; ++i)
7092 if (dpyinfo->font_table[i].name)
7093 {
7094 struct font_info *fontp = dpyinfo->font_table + i;
7095 int w, h;
7096
7097 font = (MacFontStruct *) fontp->font;
7098 xassert (font != (MacFontStruct *) ~0);
7099 x_font_min_bounds (font, &w, &h);
7100
7101 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
7102 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
7103 }
7104
7105 xassert (dpyinfo->smallest_char_width > 0
7106 && dpyinfo->smallest_font_height > 0);
7107
7108 return (dpyinfo->n_fonts == 1
7109 || dpyinfo->smallest_char_width < old_width
7110 || dpyinfo->smallest_font_height < old_height);
7111 }
7112
7113
7114 /* Determine whether given string is a fully-specified XLFD: all 14
7115 fields are present, none is '*'. */
7116
7117 static int
7118 is_fully_specified_xlfd (char *p)
7119 {
7120 int i;
7121 char *q;
7122
7123 if (*p != '-')
7124 return 0;
7125
7126 for (i = 0; i < 13; i++)
7127 {
7128 q = strchr (p + 1, '-');
7129 if (q == NULL)
7130 return 0;
7131 if (q - p == 2 && *(p + 1) == '*')
7132 return 0;
7133 p = q;
7134 }
7135
7136 if (strchr (p + 1, '-') != NULL)
7137 return 0;
7138
7139 if (*(p + 1) == '*' && *(p + 2) == '\0')
7140 return 0;
7141
7142 return 1;
7143 }
7144
7145
7146 const int kDefaultFontSize = 12;
7147
7148
7149 /* XLoadQueryFont creates and returns an internal representation for a
7150 font in a MacFontStruct struct. There is really no concept
7151 corresponding to "loading" a font on the Mac. But we check its
7152 existence and find the font number and all other information for it
7153 and store them in the returned MacFontStruct. */
7154
7155 static MacFontStruct *
7156 XLoadQueryFont (Display *dpy, char *fontname)
7157 {
7158 int i, size, point_size, avgwidth, is_two_byte_font, char_width;
7159 char *name;
7160 GrafPtr port;
7161 SInt16 old_fontnum, old_fontsize;
7162 Style old_fontface;
7163 Str255 mfontname, mfontname_decoded;
7164 Str31 charset;
7165 SInt16 fontnum;
7166 Style fontface;
7167 #if TARGET_API_MAC_CARBON
7168 TextEncoding encoding;
7169 int scriptcode;
7170 #else
7171 short scriptcode;
7172 #endif
7173 MacFontStruct *font;
7174 FontInfo the_fontinfo;
7175 #ifdef MAC_OSX
7176 UInt32 old_flags, new_flags;
7177 #endif
7178
7179 if (is_fully_specified_xlfd (fontname))
7180 name = fontname;
7181 else
7182 {
7183 Lisp_Object matched_fonts;
7184
7185 matched_fonts = mac_do_list_fonts (fontname, 1);
7186 if (NILP (matched_fonts))
7187 return NULL;
7188 name = SDATA (XCAR (matched_fonts));
7189 }
7190
7191 GetPort (&port); /* save the current font number used */
7192 #if TARGET_API_MAC_CARBON
7193 old_fontnum = GetPortTextFont (port);
7194 old_fontsize = GetPortTextSize (port);
7195 old_fontface = GetPortTextFace (port);
7196 #else
7197 old_fontnum = port->txFont;
7198 old_fontsize = port->txSize;
7199 old_fontface = port->txFace;
7200 #endif
7201
7202 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%d-%d-%*[^-]-%*[^-]-%*c-%d-%*s", &size, &point_size, &avgwidth) != 3)
7203 size = 0;
7204 else
7205 {
7206 if (size == 0)
7207 if (point_size > 0)
7208 size = point_size / 10;
7209 else if (avgwidth > 0)
7210 size = avgwidth / 10;
7211 }
7212 if (size == 0)
7213 size = kDefaultFontSize;
7214
7215 x_font_name_to_mac_font_name (name, mfontname, mfontname_decoded,
7216 &fontface, charset);
7217 c2pstr (mfontname);
7218 #if TARGET_API_MAC_CARBON
7219 fontnum = FMGetFontFamilyFromName (mfontname);
7220 if (fontnum == kInvalidFontFamily
7221 || FMGetFontFamilyTextEncoding (fontnum, &encoding) != noErr)
7222 return NULL;
7223 scriptcode = GetTextEncodingBase (encoding);
7224 #else
7225 GetFNum (mfontname, &fontnum);
7226 if (fontnum == 0)
7227 return NULL;
7228 scriptcode = FontToScript (fontnum);
7229 #endif
7230
7231 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
7232
7233 font->mac_fontnum = fontnum;
7234 font->mac_fontsize = size;
7235 font->mac_fontface = fontface;
7236 font->mac_scriptcode = scriptcode;
7237
7238 /* Apple Japanese (SJIS) font is listed as both
7239 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
7240 (Roman script) in init_font_name_table (). The latter should be
7241 treated as a one-byte font. */
7242 if (scriptcode == smJapanese && strcmp (charset, "jisx0201.1976-0") == 0)
7243 font->mac_scriptcode = smRoman;
7244
7245 font->full_name = mac_to_x_fontname (mfontname_decoded, size, fontface, charset);
7246
7247 is_two_byte_font = font->mac_scriptcode == smJapanese ||
7248 font->mac_scriptcode == smTradChinese ||
7249 font->mac_scriptcode == smSimpChinese ||
7250 font->mac_scriptcode == smKorean;
7251
7252 TextFont (fontnum);
7253 TextSize (size);
7254 TextFace (fontface);
7255
7256 GetFontInfo (&the_fontinfo);
7257
7258 font->ascent = the_fontinfo.ascent;
7259 font->descent = the_fontinfo.descent;
7260
7261 font->min_byte1 = 0;
7262 if (is_two_byte_font)
7263 font->max_byte1 = 1;
7264 else
7265 font->max_byte1 = 0;
7266 font->min_char_or_byte2 = 0x20;
7267 font->max_char_or_byte2 = 0xff;
7268
7269 if (is_two_byte_font)
7270 {
7271 /* Use the width of an "ideographic space" of that font because
7272 the_fontinfo.widMax returns the wrong width for some fonts. */
7273 switch (font->mac_scriptcode)
7274 {
7275 case smJapanese:
7276 char_width = StringWidth("\p\x81\x40");
7277 break;
7278 case smTradChinese:
7279 char_width = StringWidth("\p\xa1\x40");
7280 break;
7281 case smSimpChinese:
7282 char_width = StringWidth("\p\xa1\xa1");
7283 break;
7284 case smKorean:
7285 char_width = StringWidth("\p\xa1\xa1");
7286 break;
7287 }
7288 }
7289 else
7290 /* Do this instead of use the_fontinfo.widMax, which incorrectly
7291 returns 15 for 12-point Monaco! */
7292 char_width = CharWidth ('m');
7293
7294 if (is_two_byte_font)
7295 {
7296 font->per_char = NULL;
7297
7298 if (fontface & italic)
7299 font->max_bounds.rbearing = char_width + 1;
7300 else
7301 font->max_bounds.rbearing = char_width;
7302 font->max_bounds.lbearing = 0;
7303 font->max_bounds.width = char_width;
7304 font->max_bounds.ascent = the_fontinfo.ascent;
7305 font->max_bounds.descent = the_fontinfo.descent;
7306
7307 font->min_bounds = font->max_bounds;
7308 }
7309 else
7310 {
7311 font->per_char = (XCharStruct *)
7312 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
7313 {
7314 int c, min_width, max_width;
7315 Rect char_bounds, min_bounds, max_bounds;
7316 char ch;
7317
7318 min_width = max_width = char_width;
7319 SetRect (&min_bounds, -32767, -32767, 32767, 32767);
7320 SetRect (&max_bounds, 0, 0, 0, 0);
7321 for (c = 0x20; c <= 0xff; c++)
7322 {
7323 ch = c;
7324 char_width = CharWidth (ch);
7325 QDTextBounds (1, &ch, &char_bounds);
7326 STORE_XCHARSTRUCT (font->per_char[c - 0x20],
7327 char_width, char_bounds);
7328 /* Some Japanese fonts (in SJIS encoding) return 0 as the
7329 character width of 0x7f. */
7330 if (char_width > 0)
7331 {
7332 min_width = min (min_width, char_width);
7333 max_width = max (max_width, char_width);
7334 }
7335 if (!EmptyRect (&char_bounds))
7336 {
7337 SetRect (&min_bounds,
7338 max (min_bounds.left, char_bounds.left),
7339 max (min_bounds.top, char_bounds.top),
7340 min (min_bounds.right, char_bounds.right),
7341 min (min_bounds.bottom, char_bounds.bottom));
7342 UnionRect (&max_bounds, &char_bounds, &max_bounds);
7343 }
7344 }
7345 STORE_XCHARSTRUCT (font->min_bounds, min_width, min_bounds);
7346 STORE_XCHARSTRUCT (font->max_bounds, max_width, max_bounds);
7347 if (min_width == max_width
7348 && max_bounds.left >= 0 && max_bounds.right <= max_width)
7349 {
7350 /* Fixed width and no overhangs. */
7351 xfree (font->per_char);
7352 font->per_char = NULL;
7353 }
7354 }
7355 }
7356
7357 TextFont (old_fontnum); /* restore previous font number, size and face */
7358 TextSize (old_fontsize);
7359 TextFace (old_fontface);
7360
7361 return font;
7362 }
7363
7364
7365 void
7366 mac_unload_font (dpyinfo, font)
7367 struct mac_display_info *dpyinfo;
7368 XFontStruct *font;
7369 {
7370 xfree (font->full_name);
7371 if (font->per_char)
7372 xfree (font->per_char);
7373 xfree (font);
7374 }
7375
7376
7377 /* Load font named FONTNAME of the size SIZE for frame F, and return a
7378 pointer to the structure font_info while allocating it dynamically.
7379 If SIZE is 0, load any size of font.
7380 If loading is failed, return NULL. */
7381
7382 struct font_info *
7383 x_load_font (f, fontname, size)
7384 struct frame *f;
7385 register char *fontname;
7386 int size;
7387 {
7388 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7389 Lisp_Object font_names;
7390
7391 /* Get a list of all the fonts that match this name. Once we
7392 have a list of matching fonts, we compare them against the fonts
7393 we already have by comparing names. */
7394 font_names = x_list_fonts (f, build_string (fontname), size, 1);
7395
7396 if (!NILP (font_names))
7397 {
7398 Lisp_Object tail;
7399 int i;
7400
7401 for (i = 0; i < dpyinfo->n_fonts; i++)
7402 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
7403 if (dpyinfo->font_table[i].name
7404 && (!strcmp (dpyinfo->font_table[i].name,
7405 SDATA (XCAR (tail)))
7406 || !strcmp (dpyinfo->font_table[i].full_name,
7407 SDATA (XCAR (tail)))))
7408 return (dpyinfo->font_table + i);
7409 }
7410 else
7411 return NULL;
7412
7413 /* Load the font and add it to the table. */
7414 {
7415 char *full_name;
7416 struct MacFontStruct *font;
7417 struct font_info *fontp;
7418 unsigned long value;
7419 int i;
7420
7421 fontname = (char *) SDATA (XCAR (font_names));
7422
7423 BLOCK_INPUT;
7424 font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname);
7425 UNBLOCK_INPUT;
7426 if (!font)
7427 return NULL;
7428
7429 /* Find a free slot in the font table. */
7430 for (i = 0; i < dpyinfo->n_fonts; ++i)
7431 if (dpyinfo->font_table[i].name == NULL)
7432 break;
7433
7434 /* If no free slot found, maybe enlarge the font table. */
7435 if (i == dpyinfo->n_fonts
7436 && dpyinfo->n_fonts == dpyinfo->font_table_size)
7437 {
7438 int sz;
7439 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
7440 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
7441 dpyinfo->font_table
7442 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
7443 }
7444
7445 fontp = dpyinfo->font_table + i;
7446 if (i == dpyinfo->n_fonts)
7447 ++dpyinfo->n_fonts;
7448
7449 /* Now fill in the slots of *FONTP. */
7450 BLOCK_INPUT;
7451 bzero (fontp, sizeof (*fontp));
7452 fontp->font = font;
7453 fontp->font_idx = i;
7454 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
7455 bcopy (fontname, fontp->name, strlen (fontname) + 1);
7456
7457 if (font->min_bounds.width == font->max_bounds.width)
7458 {
7459 /* Fixed width font. */
7460 fontp->average_width = fontp->space_width = font->min_bounds.width;
7461 }
7462 else
7463 {
7464 XChar2b char2b;
7465 XCharStruct *pcm;
7466
7467 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
7468 pcm = mac_per_char_metric (font, &char2b, 0);
7469 if (pcm)
7470 fontp->space_width = pcm->width;
7471 else
7472 fontp->space_width = FONT_WIDTH (font);
7473
7474 if (pcm)
7475 {
7476 int width = pcm->width;
7477 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
7478 if ((pcm = mac_per_char_metric (font, &char2b, 0)) != NULL)
7479 width += pcm->width;
7480 fontp->average_width = width / 95;
7481 }
7482 else
7483 fontp->average_width = FONT_WIDTH (font);
7484 }
7485
7486 fontp->full_name = (char *) xmalloc (strlen (font->full_name) + 1);
7487 bcopy (font->full_name, fontp->full_name, strlen (font->full_name) + 1);
7488
7489 fontp->size = font->max_bounds.width;
7490 fontp->height = FONT_HEIGHT (font);
7491 {
7492 /* For some font, ascent and descent in max_bounds field is
7493 larger than the above value. */
7494 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
7495 if (max_height > fontp->height)
7496 fontp->height = max_height;
7497 }
7498
7499 #if 0 /* MAC_TODO: fill these out with more reasonably values */
7500
7501 /* MAC_TODO: The script encoding is irrelevant in unicode? */
7502 /* The slot `encoding' specifies how to map a character
7503 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
7504 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
7505 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
7506 2:0xA020..0xFF7F). For the moment, we don't know which charset
7507 uses this font. So, we set information in fontp->encoding[1]
7508 which is never used by any charset. If mapping can't be
7509 decided, set FONT_ENCODING_NOT_DECIDED. */
7510 if (font->mac_scriptcode == smJapanese)
7511 fontp->encoding[1] = 4;
7512 else
7513 {
7514 fontp->encoding[1]
7515 = (font->max_byte1 == 0
7516 /* 1-byte font */
7517 ? (font->min_char_or_byte2 < 0x80
7518 ? (font->max_char_or_byte2 < 0x80
7519 ? 0 /* 0x20..0x7F */
7520 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
7521 : 1) /* 0xA0..0xFF */
7522 /* 2-byte font */
7523 : (font->min_byte1 < 0x80
7524 ? (font->max_byte1 < 0x80
7525 ? (font->min_char_or_byte2 < 0x80
7526 ? (font->max_char_or_byte2 < 0x80
7527 ? 0 /* 0x2020..0x7F7F */
7528 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
7529 : 3) /* 0x20A0..0x7FFF */
7530 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
7531 : (font->min_char_or_byte2 < 0x80
7532 ? (font->max_char_or_byte2 < 0x80
7533 ? 2 /* 0xA020..0xFF7F */
7534 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
7535 : 1))); /* 0xA0A0..0xFFFF */
7536 }
7537
7538 fontp->baseline_offset
7539 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
7540 ? (long) value : 0);
7541 fontp->relative_compose
7542 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
7543 ? (long) value : 0);
7544 fontp->default_ascent
7545 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
7546 ? (long) value : 0);
7547 #else
7548 fontp->baseline_offset = 0;
7549 fontp->relative_compose = 0;
7550 fontp->default_ascent = 0;
7551 #endif
7552
7553 /* Set global flag fonts_changed_p to non-zero if the font loaded
7554 has a character with a smaller width than any other character
7555 before, or if the font loaded has a smaller height than any
7556 other font loaded before. If this happens, it will make a
7557 glyph matrix reallocation necessary. */
7558 fonts_changed_p |= x_compute_min_glyph_bounds (f);
7559 UNBLOCK_INPUT;
7560 return fontp;
7561 }
7562 }
7563
7564
7565 /* Return a pointer to struct font_info of a font named FONTNAME for
7566 frame F. If no such font is loaded, return NULL. */
7567
7568 struct font_info *
7569 x_query_font (f, fontname)
7570 struct frame *f;
7571 register char *fontname;
7572 {
7573 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7574 int i;
7575
7576 for (i = 0; i < dpyinfo->n_fonts; i++)
7577 if (dpyinfo->font_table[i].name
7578 && (!strcmp (dpyinfo->font_table[i].name, fontname)
7579 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
7580 return (dpyinfo->font_table + i);
7581 return NULL;
7582 }
7583
7584
7585 /* Find a CCL program for a font specified by FONTP, and set the member
7586 `encoder' of the structure. */
7587
7588 void
7589 x_find_ccl_program (fontp)
7590 struct font_info *fontp;
7591 {
7592 Lisp_Object list, elt;
7593
7594 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7595 {
7596 elt = XCAR (list);
7597 if (CONSP (elt)
7598 && STRINGP (XCAR (elt))
7599 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7600 >= 0))
7601 break;
7602 }
7603 if (! NILP (list))
7604 {
7605 struct ccl_program *ccl
7606 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7607
7608 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7609 xfree (ccl);
7610 else
7611 fontp->font_encoder = ccl;
7612 }
7613 }
7614
7615
7616 \f
7617 /* The Mac Event loop code */
7618
7619 #if !TARGET_API_MAC_CARBON
7620 #include <Events.h>
7621 #include <Quickdraw.h>
7622 #include <Balloons.h>
7623 #include <Devices.h>
7624 #include <Fonts.h>
7625 #include <Gestalt.h>
7626 #include <Menus.h>
7627 #include <Processes.h>
7628 #include <Sound.h>
7629 #include <ToolUtils.h>
7630 #include <TextUtils.h>
7631 #include <Dialogs.h>
7632 #include <Script.h>
7633 #include <Types.h>
7634 #include <Resources.h>
7635
7636 #if __MWERKS__
7637 #include <unix.h>
7638 #endif
7639 #endif /* ! TARGET_API_MAC_CARBON */
7640
7641 #define M_APPLE 128
7642 #define I_ABOUT 1
7643
7644 #define WINDOW_RESOURCE 128
7645 #define TERM_WINDOW_RESOURCE 129
7646
7647 #define DEFAULT_NUM_COLS 80
7648
7649 #define MIN_DOC_SIZE 64
7650 #define MAX_DOC_SIZE 32767
7651
7652 #define EXTRA_STACK_ALLOC (256 * 1024)
7653
7654 #define ARGV_STRING_LIST_ID 129
7655 #define ABOUT_ALERT_ID 128
7656 #define RAM_TOO_LARGE_ALERT_ID 129
7657
7658 /* Contains the string "reverse", which is a constant for mouse button emu.*/
7659 Lisp_Object Qreverse;
7660
7661 /* True if using command key as meta key. */
7662 Lisp_Object Vmac_command_key_is_meta;
7663
7664 /* Modifier associated with the option key, or nil for normal behavior. */
7665 Lisp_Object Vmac_option_modifier;
7666
7667 /* True if the ctrl and meta keys should be reversed. */
7668 Lisp_Object Vmac_reverse_ctrl_meta;
7669
7670 /* True if the option and command modifiers should be used to emulate
7671 a three button mouse */
7672 Lisp_Object Vmac_emulate_three_button_mouse;
7673
7674 #if USE_CARBON_EVENTS
7675 /* True if the mouse wheel button (i.e. button 4) should map to
7676 mouse-2, instead of mouse-3. */
7677 Lisp_Object Vmac_wheel_button_is_mouse_2;
7678
7679 /* If Non-nil, the Mac "Command" key is passed on to the Mac Toolbox
7680 for processing before Emacs sees it. */
7681 Lisp_Object Vmac_pass_command_to_system;
7682
7683 /* If Non-nil, the Mac "Control" key is passed on to the Mac Toolbox
7684 for processing before Emacs sees it. */
7685 Lisp_Object Vmac_pass_control_to_system;
7686 #endif
7687
7688 /* Points to the variable `inev' in the function XTread_socket. It is
7689 used for passing an input event to the function back from
7690 Carbon/Apple event handlers. */
7691 static struct input_event *read_socket_inev = NULL;
7692
7693 /* Set in term/mac-win.el to indicate that event loop can now generate
7694 drag and drop events. */
7695 Lisp_Object Qmac_ready_for_drag_n_drop;
7696
7697 Point saved_menu_event_location;
7698
7699 /* Apple Events */
7700 static void init_required_apple_events (void);
7701 static pascal OSErr
7702 do_ae_open_application (const AppleEvent *, AppleEvent *, long);
7703 static pascal OSErr
7704 do_ae_print_documents (const AppleEvent *, AppleEvent *, long);
7705 static pascal OSErr do_ae_open_documents (AppleEvent *, AppleEvent *, long);
7706 static pascal OSErr do_ae_quit_application (AppleEvent *, AppleEvent *, long);
7707
7708 #if TARGET_API_MAC_CARBON
7709 /* Drag and Drop */
7710 static pascal OSErr mac_do_track_drag (DragTrackingMessage, WindowPtr, void*, DragReference);
7711 static pascal OSErr mac_do_receive_drag (WindowPtr, void*, DragReference);
7712 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
7713 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
7714 #endif
7715
7716 static Lisp_Object Qapplication, Qabout;
7717 #if USE_CARBON_EVENTS
7718 #ifdef MAC_OSX
7719 extern void init_service_handler ();
7720 static Lisp_Object Qpreferences, Qservices, Qpaste, Qperform;
7721 #endif
7722 /* Window Event Handler */
7723 static pascal OSStatus mac_handle_window_event (EventHandlerCallRef,
7724 EventRef, void *);
7725 #endif
7726 OSErr install_window_handler (WindowPtr);
7727
7728 extern void init_emacs_passwd_dir ();
7729 extern int emacs_main (int, char **, char **);
7730
7731 extern void initialize_applescript();
7732 extern void terminate_applescript();
7733
7734 static unsigned int
7735 #if USE_CARBON_EVENTS
7736 mac_to_emacs_modifiers (UInt32 mods)
7737 #else
7738 mac_to_emacs_modifiers (EventModifiers mods)
7739 #endif
7740 {
7741 unsigned int result = 0;
7742 if (mods & macShiftKey)
7743 result |= shift_modifier;
7744 if (mods & macCtrlKey)
7745 result |= ctrl_modifier;
7746 if (mods & macMetaKey)
7747 result |= meta_modifier;
7748 if (NILP (Vmac_command_key_is_meta) && (mods & macAltKey))
7749 result |= alt_modifier;
7750 if (!NILP (Vmac_option_modifier) && (mods & optionKey)) {
7751 Lisp_Object val = Fget(Vmac_option_modifier, Qmodifier_value);
7752 if (!NILP(val))
7753 result |= XUINT(val);
7754 }
7755
7756 return result;
7757 }
7758
7759 static int
7760 mac_get_emulated_btn ( UInt32 modifiers )
7761 {
7762 int result = 0;
7763 if (!NILP (Vmac_emulate_three_button_mouse)) {
7764 int cmdIs3 = !EQ (Vmac_emulate_three_button_mouse, Qreverse);
7765 if (modifiers & cmdKey)
7766 result = cmdIs3 ? 2 : 1;
7767 else if (modifiers & optionKey)
7768 result = cmdIs3 ? 1 : 2;
7769 }
7770 return result;
7771 }
7772
7773 #if USE_CARBON_EVENTS
7774 /* Obtains the event modifiers from the event ref and then calls
7775 mac_to_emacs_modifiers. */
7776 static int
7777 mac_event_to_emacs_modifiers (EventRef eventRef)
7778 {
7779 UInt32 mods = 0;
7780 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
7781 sizeof (UInt32), NULL, &mods);
7782 if (!NILP (Vmac_emulate_three_button_mouse) &&
7783 GetEventClass(eventRef) == kEventClassMouse)
7784 {
7785 mods &= ~(optionKey | cmdKey);
7786 }
7787 return mac_to_emacs_modifiers (mods);
7788 }
7789
7790 /* Given an event ref, return the code to use for the mouse button
7791 code in the emacs input_event. */
7792 static int
7793 mac_get_mouse_btn (EventRef ref)
7794 {
7795 EventMouseButton result = kEventMouseButtonPrimary;
7796 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
7797 sizeof (EventMouseButton), NULL, &result);
7798 switch (result)
7799 {
7800 case kEventMouseButtonPrimary:
7801 if (NILP (Vmac_emulate_three_button_mouse))
7802 return 0;
7803 else {
7804 UInt32 mods = 0;
7805 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
7806 sizeof (UInt32), NULL, &mods);
7807 return mac_get_emulated_btn(mods);
7808 }
7809 case kEventMouseButtonSecondary:
7810 return NILP (Vmac_wheel_button_is_mouse_2) ? 1 : 2;
7811 case kEventMouseButtonTertiary:
7812 case 4: /* 4 is the number for the mouse wheel button */
7813 return NILP (Vmac_wheel_button_is_mouse_2) ? 2 : 1;
7814 default:
7815 return 0;
7816 }
7817 }
7818
7819 /* Normally, ConvertEventRefToEventRecord will correctly handle all
7820 events. However the click of the mouse wheel is not converted to a
7821 mouseDown or mouseUp event. Likewise for dead key down events.
7822 This calls ConvertEventRef, but then checks to see if it is a mouse
7823 up/down, or a dead key down carbon event that has not been
7824 converted, and if so, converts it by hand (to be picked up in the
7825 XTread_socket loop). */
7826 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
7827 {
7828 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
7829
7830 if (result)
7831 return result;
7832
7833 switch (GetEventClass (eventRef))
7834 {
7835 case kEventClassMouse:
7836 switch (GetEventKind (eventRef))
7837 {
7838 case kEventMouseDown:
7839 eventRec->what = mouseDown;
7840 result = 1;
7841 break;
7842
7843 case kEventMouseUp:
7844 eventRec->what = mouseUp;
7845 result = 1;
7846 break;
7847
7848 default:
7849 break;
7850 }
7851 break;
7852
7853 case kEventClassKeyboard:
7854 switch (GetEventKind (eventRef))
7855 {
7856 case kEventRawKeyDown:
7857 {
7858 unsigned char char_codes;
7859 UInt32 key_code;
7860
7861 eventRec->what = keyDown;
7862 GetEventParameter (eventRef, kEventParamKeyMacCharCodes, typeChar,
7863 NULL, sizeof (char), NULL, &char_codes);
7864 GetEventParameter (eventRef, kEventParamKeyCode, typeUInt32,
7865 NULL, sizeof (UInt32), NULL, &key_code);
7866 eventRec->message = char_codes | ((key_code & 0xff) << 8);
7867 result = 1;
7868 }
7869 break;
7870
7871 default:
7872 break;
7873 }
7874 break;
7875
7876 default:
7877 break;
7878 }
7879
7880 if (result)
7881 {
7882 /* Need where and when. */
7883 UInt32 mods;
7884
7885 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
7886 NULL, sizeof (Point), NULL, &eventRec->where);
7887 /* Use two step process because new event modifiers are 32-bit
7888 and old are 16-bit. Currently, only loss is NumLock & Fn. */
7889 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
7890 NULL, sizeof (UInt32), NULL, &mods);
7891 eventRec->modifiers = mods;
7892
7893 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
7894 }
7895
7896 return result;
7897 }
7898
7899 #endif
7900
7901 static void
7902 do_get_menus (void)
7903 {
7904 Handle menubar_handle;
7905 MenuHandle menu_handle;
7906
7907 menubar_handle = GetNewMBar (128);
7908 if(menubar_handle == NULL)
7909 abort ();
7910 SetMenuBar (menubar_handle);
7911 DrawMenuBar ();
7912
7913 #if !TARGET_API_MAC_CARBON
7914 menu_handle = GetMenuHandle (M_APPLE);
7915 if(menu_handle != NULL)
7916 AppendResMenu (menu_handle,'DRVR');
7917 else
7918 abort ();
7919 #endif
7920 }
7921
7922
7923 static void
7924 do_init_managers (void)
7925 {
7926 #if !TARGET_API_MAC_CARBON
7927 InitGraf (&qd.thePort);
7928 InitFonts ();
7929 FlushEvents (everyEvent, 0);
7930 InitWindows ();
7931 InitMenus ();
7932 TEInit ();
7933 InitDialogs (NULL);
7934 #endif /* !TARGET_API_MAC_CARBON */
7935 InitCursor ();
7936
7937 #if !TARGET_API_MAC_CARBON
7938 /* set up some extra stack space for use by emacs */
7939 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
7940
7941 /* MaxApplZone must be called for AppleScript to execute more
7942 complicated scripts */
7943 MaxApplZone ();
7944 MoreMasters ();
7945 #endif /* !TARGET_API_MAC_CARBON */
7946 }
7947
7948 static void
7949 do_check_ram_size (void)
7950 {
7951 SInt32 physical_ram_size, logical_ram_size;
7952
7953 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
7954 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
7955 || physical_ram_size > (1 << VALBITS)
7956 || logical_ram_size > (1 << VALBITS))
7957 {
7958 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
7959 exit (1);
7960 }
7961 }
7962
7963 static void
7964 do_window_update (WindowPtr win)
7965 {
7966 struct frame *f = mac_window_to_frame (win);
7967
7968 BeginUpdate (win);
7969
7970 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
7971 below. */
7972 if (win != tip_window)
7973 {
7974 if (f->async_visible == 0)
7975 {
7976 /* Update events may occur when a frame gets iconified. */
7977 #if 0
7978 f->async_visible = 1;
7979 f->async_iconified = 0;
7980 SET_FRAME_GARBAGED (f);
7981 #endif
7982 }
7983 else
7984 {
7985 Rect r;
7986 #if TARGET_API_MAC_CARBON
7987 RgnHandle region = NewRgn ();
7988
7989 GetPortVisibleRegion (GetWindowPort (win), region);
7990 GetRegionBounds (region, &r);
7991 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
7992 UpdateControls (win, region);
7993 DisposeRgn (region);
7994 #else
7995 r = (*win->visRgn)->rgnBBox;
7996 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
7997 UpdateControls (win, win->visRgn);
7998 #endif
7999 }
8000 }
8001
8002 EndUpdate (win);
8003 }
8004
8005 static int
8006 is_emacs_window (WindowPtr win)
8007 {
8008 Lisp_Object tail, frame;
8009
8010 if (!win)
8011 return 0;
8012
8013 FOR_EACH_FRAME (tail, frame)
8014 if (FRAME_MAC_P (XFRAME (frame)))
8015 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
8016 return 1;
8017
8018 return 0;
8019 }
8020
8021 static void
8022 do_app_resume ()
8023 {
8024 /* Window-activate events will do the job. */
8025 }
8026
8027 static void
8028 do_app_suspend ()
8029 {
8030 /* Window-deactivate events will do the job. */
8031 }
8032
8033
8034 static void
8035 do_apple_menu (SInt16 menu_item)
8036 {
8037 #if !TARGET_API_MAC_CARBON
8038 Str255 item_name;
8039 SInt16 da_driver_refnum;
8040
8041 if (menu_item == I_ABOUT)
8042 NoteAlert (ABOUT_ALERT_ID, NULL);
8043 else
8044 {
8045 GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name);
8046 da_driver_refnum = OpenDeskAcc (item_name);
8047 }
8048 #endif /* !TARGET_API_MAC_CARBON */
8049 }
8050
8051 void
8052 do_menu_choice (SInt32 menu_choice)
8053 {
8054 SInt16 menu_id, menu_item;
8055
8056 menu_id = HiWord (menu_choice);
8057 menu_item = LoWord (menu_choice);
8058
8059 switch (menu_id)
8060 {
8061 case 0:
8062 break;
8063
8064 case M_APPLE:
8065 do_apple_menu (menu_item);
8066 break;
8067
8068 default:
8069 {
8070 struct frame *f = mac_focus_frame (&one_mac_display_info);
8071 MenuHandle menu = GetMenuHandle (menu_id);
8072 if (menu)
8073 {
8074 UInt32 refcon;
8075
8076 GetMenuItemRefCon (menu, menu_item, &refcon);
8077 menubar_selection_callback (f, refcon);
8078 }
8079 }
8080 }
8081
8082 HiliteMenu (0);
8083 }
8084
8085
8086 /* Handle drags in size box. Based on code contributed by Ben
8087 Mesander and IM - Window Manager A. */
8088
8089 static void
8090 do_grow_window (WindowPtr w, EventRecord *e)
8091 {
8092 Rect limit_rect;
8093 int rows, columns, width, height;
8094 struct frame *f = mac_window_to_frame (w);
8095 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
8096 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
8097 #if TARGET_API_MAC_CARBON
8098 Rect new_rect;
8099 #else
8100 long grow_size;
8101 #endif
8102
8103 if (size_hints->flags & PMinSize)
8104 {
8105 min_width = size_hints->min_width;
8106 min_height = size_hints->min_height;
8107 }
8108 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
8109
8110 #if TARGET_API_MAC_CARBON
8111 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
8112 return;
8113 height = new_rect.bottom - new_rect.top;
8114 width = new_rect.right - new_rect.left;
8115 #else
8116 grow_size = GrowWindow (w, e->where, &limit_rect);
8117 /* see if it really changed size */
8118 if (grow_size == 0)
8119 return;
8120 height = HiWord (grow_size);
8121 width = LoWord (grow_size);
8122 #endif
8123
8124 if (width != FRAME_PIXEL_WIDTH (f)
8125 || height != FRAME_PIXEL_HEIGHT (f))
8126 {
8127 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
8128 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
8129
8130 x_set_window_size (f, 0, columns, rows);
8131 }
8132 }
8133
8134
8135 /* Handle clicks in zoom box. Calculation of "standard state" based
8136 on code in IM - Window Manager A and code contributed by Ben
8137 Mesander. The standard state of an Emacs window is 80-characters
8138 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
8139
8140 static void
8141 do_zoom_window (WindowPtr w, int zoom_in_or_out)
8142 {
8143 GrafPtr save_port;
8144 Rect zoom_rect, port_rect;
8145 Point top_left;
8146 int w_title_height, columns, rows, width, height;
8147 struct frame *f = mac_window_to_frame (w);
8148 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8149
8150 #if TARGET_API_MAC_CARBON
8151 {
8152 Point standard_size;
8153
8154 standard_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
8155 standard_size.v = dpyinfo->height;
8156
8157 if (IsWindowInStandardState (w, &standard_size, &zoom_rect))
8158 zoom_in_or_out = inZoomIn;
8159 else
8160 {
8161 /* Adjust the standard size according to character boundaries. */
8162
8163 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, zoom_rect.right - zoom_rect.left);
8164 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
8165 standard_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
8166 standard_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
8167 GetWindowBounds (w, kWindowContentRgn, &port_rect);
8168 if (IsWindowInStandardState (w, &standard_size, &zoom_rect)
8169 && port_rect.left == zoom_rect.left
8170 && port_rect.top == zoom_rect.top)
8171 zoom_in_or_out = inZoomIn;
8172 else
8173 zoom_in_or_out = inZoomOut;
8174 }
8175
8176 ZoomWindowIdeal (w, zoom_in_or_out, &standard_size);
8177 }
8178 #else /* not TARGET_API_MAC_CARBON */
8179 GetPort (&save_port);
8180
8181 SetPortWindowPort (w);
8182
8183 /* Clear window to avoid flicker. */
8184 EraseRect (&(w->portRect));
8185 if (zoom_in_or_out == inZoomOut)
8186 {
8187 SetPt (&top_left, w->portRect.left, w->portRect.top);
8188 LocalToGlobal (&top_left);
8189
8190 /* calculate height of window's title bar */
8191 w_title_height = top_left.v - 1
8192 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
8193
8194 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
8195 zoom_rect = qd.screenBits.bounds;
8196 zoom_rect.top += w_title_height;
8197 InsetRect (&zoom_rect, 8, 4); /* not too tight */
8198
8199 zoom_rect.right = zoom_rect.left
8200 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
8201
8202 /* Adjust the standard size according to character boundaries. */
8203 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
8204 zoom_rect.bottom =
8205 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
8206
8207 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
8208 = zoom_rect;
8209 }
8210
8211 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
8212
8213 SetPort (save_port);
8214 #endif /* not TARGET_API_MAC_CARBON */
8215
8216 /* retrieve window size and update application values */
8217 #if TARGET_API_MAC_CARBON
8218 GetWindowPortBounds (w, &port_rect);
8219 #else
8220 port_rect = w->portRect;
8221 #endif
8222 height = port_rect.bottom - port_rect.top;
8223 width = port_rect.right - port_rect.left;
8224
8225 if (width != FRAME_PIXEL_WIDTH (f)
8226 || height != FRAME_PIXEL_HEIGHT (f))
8227 {
8228 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
8229 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
8230
8231 change_frame_size (f, rows, columns, 0, 1, 0);
8232 SET_FRAME_GARBAGED (f);
8233 cancel_mouse_face (f);
8234
8235 FRAME_PIXEL_WIDTH (f) = width;
8236 FRAME_PIXEL_HEIGHT (f) = height;
8237 }
8238 x_real_positions (f, &f->left_pos, &f->top_pos);
8239 }
8240
8241 /* Intialize AppleEvent dispatcher table for the required events. */
8242 void
8243 init_required_apple_events ()
8244 {
8245 OSErr err;
8246 long result;
8247
8248 /* Make sure we have apple events before starting. */
8249 err = Gestalt (gestaltAppleEventsAttr, &result);
8250 if (err != noErr)
8251 abort ();
8252
8253 if (!(result & (1 << gestaltAppleEventsPresent)))
8254 abort ();
8255
8256 #if TARGET_API_MAC_CARBON
8257 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
8258 NewAEEventHandlerUPP
8259 ((AEEventHandlerProcPtr) do_ae_open_application),
8260 0L, false);
8261 #else
8262 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
8263 NewAEEventHandlerProc
8264 ((AEEventHandlerProcPtr) do_ae_open_application),
8265 0L, false);
8266 #endif
8267 if (err != noErr)
8268 abort ();
8269
8270 #if TARGET_API_MAC_CARBON
8271 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
8272 NewAEEventHandlerUPP
8273 ((AEEventHandlerProcPtr) do_ae_open_documents),
8274 0L, false);
8275 #else
8276 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
8277 NewAEEventHandlerProc
8278 ((AEEventHandlerProcPtr) do_ae_open_documents),
8279 0L, false);
8280 #endif
8281 if (err != noErr)
8282 abort ();
8283
8284 #if TARGET_API_MAC_CARBON
8285 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
8286 NewAEEventHandlerUPP
8287 ((AEEventHandlerProcPtr) do_ae_print_documents),
8288 0L, false);
8289 #else
8290 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
8291 NewAEEventHandlerProc
8292 ((AEEventHandlerProcPtr) do_ae_print_documents),
8293 0L, false);
8294 #endif
8295 if (err != noErr)
8296 abort ();
8297
8298 #if TARGET_API_MAC_CARBON
8299 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
8300 NewAEEventHandlerUPP
8301 ((AEEventHandlerProcPtr) do_ae_quit_application),
8302 0L, false);
8303 #else
8304 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
8305 NewAEEventHandlerProc
8306 ((AEEventHandlerProcPtr) do_ae_quit_application),
8307 0L, false);
8308 #endif
8309 if (err != noErr)
8310 abort ();
8311 }
8312
8313 void
8314 mac_store_application_menu_event (event)
8315 #if USE_CARBON_EVENTS
8316 EventRef event;
8317 #else
8318 UInt32 event;
8319 #endif
8320 {
8321 struct input_event buf;
8322 Lisp_Object frame, entry;
8323
8324 EVENT_INIT (buf);
8325
8326 XSETFRAME (frame, mac_focus_frame (&one_mac_display_info));
8327 buf.kind = MENU_BAR_EVENT;
8328 buf.frame_or_window = frame;
8329 buf.arg = frame;
8330 kbd_buffer_store_event (&buf);
8331
8332 buf.arg = Qapplication;
8333 kbd_buffer_store_event (&buf);
8334
8335 #if USE_CARBON_EVENTS
8336 switch (GetEventClass (event))
8337 {
8338 #ifdef MAC_OSX
8339 case kEventClassService:
8340 buf.arg = Qservices;
8341 kbd_buffer_store_event (&buf);
8342 switch (GetEventKind (event))
8343 {
8344 case kEventServicePaste:
8345 entry = Qpaste;
8346 break;
8347
8348 case kEventServicePerform:
8349 {
8350 OSErr err;
8351 CFStringRef message;
8352
8353 err = GetEventParameter (event, kEventParamServiceMessageName,
8354 typeCFStringRef, NULL,
8355 sizeof (CFStringRef), NULL, &message);
8356 buf.arg = Qperform;
8357 kbd_buffer_store_event (&buf);
8358 if (err == noErr && message)
8359 entry = intern (SDATA (cfstring_to_lisp (message)));
8360 else
8361 entry = Qnil;
8362 }
8363 break;
8364
8365 default:
8366 abort ();
8367 }
8368 break;
8369 #endif /* MAC_OSX */
8370 case kEventClassCommand:
8371 {
8372 HICommand command;
8373
8374 GetEventParameter(event, kEventParamDirectObject, typeHICommand,
8375 NULL, sizeof (HICommand), NULL, &command);
8376 switch (command.commandID)
8377 {
8378 case kHICommandAbout:
8379 entry = Qabout;
8380 break;
8381 #ifdef MAC_OSX
8382 case kHICommandPreferences:
8383 entry = Qpreferences;
8384 break;
8385 #endif /* MAC_OSX */
8386 case kHICommandQuit:
8387 entry = Qquit;
8388 break;
8389 default:
8390 abort ();
8391 }
8392 }
8393 break;
8394
8395 default:
8396 abort ();
8397 }
8398 #else /* USE_CARBON_EVENTS */
8399 switch (event)
8400 {
8401 case kHICommandAbout:
8402 entry = Qabout;
8403 break;
8404 case kHICommandQuit:
8405 entry = Qquit;
8406 break;
8407 default:
8408 abort ();
8409 }
8410 #endif
8411
8412 buf.arg = entry;
8413 kbd_buffer_store_event (&buf);
8414 }
8415
8416 #if USE_CARBON_EVENTS
8417 static pascal OSStatus
8418 mac_handle_command_event (next_handler, event, data)
8419 EventHandlerCallRef next_handler;
8420 EventRef event;
8421 void *data;
8422 {
8423 HICommand command;
8424 OSErr result;
8425
8426 GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL,
8427 sizeof (HICommand), NULL, &command);
8428
8429 switch (command.commandID)
8430 {
8431 case kHICommandAbout:
8432 #ifdef MAC_OSX
8433 case kHICommandPreferences:
8434 #endif /* MAC_OSX */
8435 result = CallNextEventHandler (next_handler, event);
8436 if (result != eventNotHandledErr)
8437 return result;
8438
8439 mac_store_application_menu_event (event);
8440 return noErr;
8441
8442 default:
8443 break;
8444 }
8445
8446 return eventNotHandledErr;
8447 }
8448
8449 static OSErr
8450 init_command_handler ()
8451 {
8452 OSErr err = noErr;
8453 EventTypeSpec specs[] = {{kEventClassCommand, kEventCommandProcess}};
8454 static EventHandlerUPP handle_command_eventUPP = NULL;
8455
8456 if (handle_command_eventUPP == NULL)
8457 handle_command_eventUPP = NewEventHandlerUPP (mac_handle_command_event);
8458 return InstallApplicationEventHandler (handle_command_eventUPP,
8459 GetEventTypeCount (specs), specs,
8460 NULL, NULL);
8461 }
8462
8463 static pascal OSStatus
8464 mac_handle_window_event (next_handler, event, data)
8465 EventHandlerCallRef next_handler;
8466 EventRef event;
8467 void *data;
8468 {
8469 WindowPtr wp;
8470 OSStatus result;
8471 UInt32 attributes;
8472 XSizeHints *size_hints;
8473
8474 GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
8475 NULL, sizeof (WindowPtr), NULL, &wp);
8476
8477 switch (GetEventKind (event))
8478 {
8479 case kEventWindowUpdate:
8480 result = CallNextEventHandler (next_handler, event);
8481 if (result != eventNotHandledErr)
8482 return result;
8483
8484 do_window_update (wp);
8485 return noErr;
8486
8487 case kEventWindowBoundsChanging:
8488 result = CallNextEventHandler (next_handler, event);
8489 if (result != eventNotHandledErr)
8490 return result;
8491
8492 GetEventParameter (event, kEventParamAttributes, typeUInt32,
8493 NULL, sizeof (UInt32), NULL, &attributes);
8494 size_hints = FRAME_SIZE_HINTS (mac_window_to_frame (wp));
8495 if ((attributes & kWindowBoundsChangeUserResize)
8496 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
8497 == (PResizeInc | PBaseSize | PMinSize)))
8498 {
8499 Rect bounds;
8500 int width, height;
8501
8502 GetEventParameter (event, kEventParamCurrentBounds,
8503 typeQDRectangle,
8504 NULL, sizeof (Rect), NULL, &bounds);
8505 width = bounds.right - bounds.left;
8506 height = bounds.bottom - bounds.top;
8507
8508 if (width < size_hints->min_width)
8509 width = size_hints->min_width;
8510 else
8511 width = size_hints->base_width
8512 + (int) ((width - size_hints->base_width)
8513 / (float) size_hints->width_inc + .5)
8514 * size_hints->width_inc;
8515
8516 if (height < size_hints->min_height)
8517 height = size_hints->min_height;
8518 else
8519 height = size_hints->base_height
8520 + (int) ((height - size_hints->base_height)
8521 / (float) size_hints->height_inc + .5)
8522 * size_hints->height_inc;
8523
8524 bounds.right = bounds.left + width;
8525 bounds.bottom = bounds.top + height;
8526 SetEventParameter (event, kEventParamCurrentBounds,
8527 typeQDRectangle, sizeof (Rect), &bounds);
8528 return noErr;
8529 }
8530 break;
8531
8532 case kEventWindowShown:
8533 case kEventWindowHidden:
8534 case kEventWindowExpanded:
8535 case kEventWindowCollapsed:
8536 result = CallNextEventHandler (next_handler, event);
8537
8538 mac_handle_visibility_change (mac_window_to_frame (wp));
8539 return noErr;
8540
8541 break;
8542 }
8543
8544 return eventNotHandledErr;
8545 }
8546
8547 static pascal OSStatus
8548 mac_handle_mouse_event (next_handler, event, data)
8549 EventHandlerCallRef next_handler;
8550 EventRef event;
8551 void *data;
8552 {
8553 OSStatus result;
8554
8555 switch (GetEventKind (event))
8556 {
8557 case kEventMouseWheelMoved:
8558 {
8559 WindowPtr wp;
8560 struct frame *f;
8561 EventMouseWheelAxis axis;
8562 SInt32 delta;
8563 Point point;
8564
8565 result = CallNextEventHandler (next_handler, event);
8566 if (result != eventNotHandledErr || read_socket_inev == NULL)
8567 return result;
8568
8569 GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
8570 NULL, sizeof (WindowRef), NULL, &wp);
8571 f = mac_window_to_frame (wp);
8572 if (f != mac_focus_frame (&one_mac_display_info))
8573 break;
8574
8575 GetEventParameter (event, kEventParamMouseWheelAxis,
8576 typeMouseWheelAxis, NULL,
8577 sizeof (EventMouseWheelAxis), NULL, &axis);
8578 if (axis != kEventMouseWheelAxisY)
8579 break;
8580
8581 GetEventParameter (event, kEventParamMouseWheelDelta, typeSInt32,
8582 NULL, sizeof (SInt32), NULL, &delta);
8583 GetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
8584 NULL, sizeof (Point), NULL, &point);
8585 read_socket_inev->kind = WHEEL_EVENT;
8586 read_socket_inev->code = 0;
8587 read_socket_inev->modifiers =
8588 (mac_event_to_emacs_modifiers (event)
8589 | ((delta < 0) ? down_modifier : up_modifier));
8590 SetPortWindowPort (wp);
8591 GlobalToLocal (&point);
8592 XSETINT (read_socket_inev->x, point.h);
8593 XSETINT (read_socket_inev->y, point.v);
8594 XSETFRAME (read_socket_inev->frame_or_window, f);
8595
8596 return noErr;
8597 }
8598 break;
8599
8600 default:
8601 break;
8602 }
8603
8604 return eventNotHandledErr;
8605 }
8606 #endif /* USE_CARBON_EVENTS */
8607
8608
8609 OSErr
8610 install_window_handler (window)
8611 WindowPtr window;
8612 {
8613 OSErr err = noErr;
8614 #if USE_CARBON_EVENTS
8615 EventTypeSpec specs_window[] =
8616 {{kEventClassWindow, kEventWindowUpdate},
8617 {kEventClassWindow, kEventWindowBoundsChanging},
8618 {kEventClassWindow, kEventWindowShown},
8619 {kEventClassWindow, kEventWindowHidden},
8620 {kEventClassWindow, kEventWindowExpanded},
8621 {kEventClassWindow, kEventWindowCollapsed}};
8622 EventTypeSpec specs_mouse[] = {{kEventClassMouse, kEventMouseWheelMoved}};
8623 static EventHandlerUPP handle_window_eventUPP = NULL;
8624 static EventHandlerUPP handle_mouse_eventUPP = NULL;
8625
8626 if (handle_window_eventUPP == NULL)
8627 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
8628 if (handle_mouse_eventUPP == NULL)
8629 handle_mouse_eventUPP = NewEventHandlerUPP (mac_handle_mouse_event);
8630 err = InstallWindowEventHandler (window, handle_window_eventUPP,
8631 GetEventTypeCount (specs_window),
8632 specs_window, NULL, NULL);
8633 if (err == noErr)
8634 err = InstallWindowEventHandler (window, handle_mouse_eventUPP,
8635 GetEventTypeCount (specs_mouse),
8636 specs_mouse, NULL, NULL);
8637 #endif
8638 #if TARGET_API_MAC_CARBON
8639 if (mac_do_track_dragUPP == NULL)
8640 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
8641 if (mac_do_receive_dragUPP == NULL)
8642 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
8643
8644 if (err == noErr)
8645 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
8646 if (err == noErr)
8647 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
8648 #endif
8649 return err;
8650 }
8651
8652 void
8653 remove_window_handler (window)
8654 WindowPtr window;
8655 {
8656 #if TARGET_API_MAC_CARBON
8657 if (mac_do_track_dragUPP)
8658 RemoveTrackingHandler (mac_do_track_dragUPP, window);
8659 if (mac_do_receive_dragUPP)
8660 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
8661 #endif
8662 }
8663
8664 /* Open Application Apple Event */
8665 static pascal OSErr
8666 do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon)
8667 {
8668 return noErr;
8669 }
8670
8671
8672 /* Called when we receive an AppleEvent with an ID of
8673 "kAEOpenDocuments". This routine gets the direct parameter,
8674 extracts the FSSpecs in it, and puts their names on a list. */
8675 #pragma options align=mac68k
8676 typedef struct SelectionRange {
8677 short unused1; // 0 (not used)
8678 short lineNum; // line to select (<0 to specify range)
8679 long startRange; // start of selection range (if line < 0)
8680 long endRange; // end of selection range (if line < 0)
8681 long unused2; // 0 (not used)
8682 long theDate; // modification date/time
8683 } SelectionRange;
8684 #pragma options align=reset
8685
8686 static pascal OSErr
8687 do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
8688 {
8689 OSErr err, err2;
8690 AEDesc the_desc;
8691 AEKeyword keyword;
8692 DescType actual_type;
8693 Size actual_size;
8694 SelectionRange position;
8695 Lisp_Object file_list = Qnil;
8696
8697 xassert (read_socket_inev);
8698
8699 err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc);
8700 if (err != noErr)
8701 goto descriptor_error_exit;
8702
8703 err = AEGetParamPtr (message, keyAEPosition, typeChar, &actual_type, &position, sizeof(SelectionRange), &actual_size);
8704 if (err == noErr)
8705 file_list = Fcons (list3 (make_number (position.lineNum + 1),
8706 make_number (position.startRange + 1),
8707 make_number (position.endRange + 1)),
8708 file_list);
8709
8710 /* Check to see that we got all of the required parameters from the
8711 event descriptor. For an 'odoc' event this should just be the
8712 file list. */
8713 err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
8714 &actual_type, (Ptr) &keyword,
8715 sizeof (keyword), &actual_size);
8716 /* No error means that we found some unused parameters.
8717 errAEDescNotFound means that there are no more parameters. If we
8718 get an error code other than that, flag it. */
8719 if ((err == noErr) || (err != errAEDescNotFound))
8720 {
8721 err = errAEEventNotHandled;
8722 goto error_exit;
8723 }
8724 err = noErr;
8725
8726 /* Got all the parameters we need. Now, go through the direct
8727 object list and parse it up. */
8728 {
8729 long num_files_to_open;
8730
8731 err = AECountItems (&the_desc, &num_files_to_open);
8732 if (err == noErr)
8733 {
8734 int i;
8735
8736 /* AE file list is one based so just use that for indexing here. */
8737 for (i = 1; i <= num_files_to_open; i++)
8738 {
8739 char unix_path_name[MAXPATHLEN];
8740 #ifdef MAC_OSX
8741 FSRef fref;
8742
8743 err = AEGetNthPtr (&the_desc, i, typeFSRef, &keyword,
8744 &actual_type, &fref, sizeof (FSRef),
8745 &actual_size);
8746 if (err != noErr || actual_type != typeFSRef)
8747 continue;
8748
8749 if (FSRefMakePath (&fref, unix_path_name, sizeof (unix_path_name))
8750 == noErr)
8751 #else
8752 FSSpec fs;
8753
8754 err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type,
8755 (Ptr) &fs, sizeof (fs), &actual_size);
8756 if (err != noErr) continue;
8757
8758 if (fsspec_to_posix_pathname (&fs, unix_path_name,
8759 sizeof (unix_path_name) - 1) == noErr)
8760 #endif
8761 /* x-dnd functions expect undecoded filenames. */
8762 file_list = Fcons (make_unibyte_string (unix_path_name,
8763 strlen (unix_path_name)),
8764 file_list);
8765 }
8766 }
8767
8768 /* Build a DRAG_N_DROP_EVENT type event as is done in
8769 constuct_drag_n_drop in w32term.c. */
8770 if (!NILP (file_list))
8771 {
8772 struct frame *f = mac_focus_frame (&one_mac_display_info);
8773 WindowPtr wp;
8774 Lisp_Object frame;
8775
8776 read_socket_inev->kind = DRAG_N_DROP_EVENT;
8777 read_socket_inev->code = 0;
8778 read_socket_inev->modifiers = 0;
8779
8780 XSETINT (read_socket_inev->x, 0);
8781 XSETINT (read_socket_inev->y, 0);
8782
8783 XSETFRAME (frame, f);
8784 read_socket_inev->frame_or_window = Fcons (frame, file_list);
8785
8786 #if 0
8787 /* Regardless of whether Emacs was suspended or in the
8788 foreground, ask it to redraw its entire screen. Otherwise
8789 parts of the screen can be left in an inconsistent
8790 state. */
8791 wp = FRAME_MAC_WINDOW (f);
8792 if (wp)
8793 #if TARGET_API_MAC_CARBON
8794 {
8795 Rect r;
8796
8797 GetWindowPortBounds (wp, &r);
8798 InvalWindowRect (wp, &r);
8799 }
8800 #else /* not TARGET_API_MAC_CARBON */
8801 InvalRect (&(wp->portRect));
8802 #endif /* not TARGET_API_MAC_CARBON */
8803 #endif
8804 }
8805 }
8806
8807 error_exit:
8808 /* Nuke the coerced file list in any case */
8809 err2 = AEDisposeDesc(&the_desc);
8810
8811 descriptor_error_exit:
8812 /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */
8813 return err;
8814 }
8815
8816
8817 #if TARGET_API_MAC_CARBON
8818 static pascal OSErr
8819 mac_do_track_drag (DragTrackingMessage message, WindowPtr window,
8820 void *handlerRefCon, DragReference theDrag)
8821 {
8822 static int can_accept;
8823 short items;
8824 short index;
8825 ItemReference theItem;
8826 FlavorFlags theFlags;
8827 OSErr result;
8828
8829 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
8830 return dragNotAcceptedErr;
8831
8832 switch (message)
8833 {
8834 case kDragTrackingEnterHandler:
8835 CountDragItems (theDrag, &items);
8836 can_accept = 0;
8837 for (index = 1; index <= items; index++)
8838 {
8839 GetDragItemReferenceNumber (theDrag, index, &theItem);
8840 result = GetFlavorFlags (theDrag, theItem, flavorTypeHFS, &theFlags);
8841 if (result == noErr)
8842 {
8843 can_accept = 1;
8844 break;
8845 }
8846 }
8847 break;
8848
8849 case kDragTrackingEnterWindow:
8850 if (can_accept)
8851 {
8852 RgnHandle hilite_rgn = NewRgn ();
8853 Rect r;
8854 struct frame *f = mac_window_to_frame (window);
8855
8856 GetWindowPortBounds (window, &r);
8857 OffsetRect (&r, -r.left, -r.top);
8858 RectRgn (hilite_rgn, &r);
8859 ShowDragHilite (theDrag, hilite_rgn, true);
8860 DisposeRgn (hilite_rgn);
8861 SetThemeCursor (kThemeCopyArrowCursor);
8862 }
8863 break;
8864
8865 case kDragTrackingInWindow:
8866 break;
8867
8868 case kDragTrackingLeaveWindow:
8869 if (can_accept)
8870 {
8871 struct frame *f = mac_window_to_frame (window);
8872
8873 HideDragHilite (theDrag);
8874 SetThemeCursor (kThemeArrowCursor);
8875 }
8876 break;
8877
8878 case kDragTrackingLeaveHandler:
8879 break;
8880 }
8881
8882 return noErr;
8883 }
8884
8885 static pascal OSErr
8886 mac_do_receive_drag (WindowPtr window, void *handlerRefCon,
8887 DragReference theDrag)
8888 {
8889 short items;
8890 short index;
8891 FlavorFlags theFlags;
8892 Point mouse;
8893 OSErr result;
8894 ItemReference theItem;
8895 HFSFlavor data;
8896 Size size = sizeof (HFSFlavor);
8897 Lisp_Object file_list;
8898
8899 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
8900 return dragNotAcceptedErr;
8901
8902 file_list = Qnil;
8903 GetDragMouse (theDrag, &mouse, 0L);
8904 CountDragItems (theDrag, &items);
8905 for (index = 1; index <= items; index++)
8906 {
8907 /* Only handle file references. */
8908 GetDragItemReferenceNumber (theDrag, index, &theItem);
8909 result = GetFlavorFlags (theDrag, theItem, flavorTypeHFS, &theFlags);
8910 if (result == noErr)
8911 {
8912 #ifdef MAC_OSX
8913 FSRef fref;
8914 #endif
8915 char unix_path_name[MAXPATHLEN];
8916
8917 GetFlavorData (theDrag, theItem, flavorTypeHFS, &data, &size, 0L);
8918 #ifdef MAC_OSX
8919 /* Use Carbon routines, otherwise it converts the file name
8920 to /Macintosh HD/..., which is not correct. */
8921 FSpMakeFSRef (&data.fileSpec, &fref);
8922 if (! FSRefMakePath (&fref, unix_path_name, sizeof (unix_path_name)));
8923 #else
8924 if (fsspec_to_posix_pathname (&data.fileSpec, unix_path_name,
8925 sizeof (unix_path_name) - 1) == noErr)
8926 #endif
8927 /* x-dnd functions expect undecoded filenames. */
8928 file_list = Fcons (make_unibyte_string (unix_path_name,
8929 strlen (unix_path_name)),
8930 file_list);
8931 }
8932 }
8933 /* If there are items in the list, construct an event and post it to
8934 the queue like an interrupt using kbd_buffer_store_event. */
8935 if (!NILP (file_list))
8936 {
8937 struct input_event event;
8938 Lisp_Object frame;
8939 struct frame *f = mac_window_to_frame (window);
8940 SInt16 modifiers;
8941
8942 GlobalToLocal (&mouse);
8943 GetDragModifiers (theDrag, NULL, NULL, &modifiers);
8944
8945 event.kind = DRAG_N_DROP_EVENT;
8946 event.code = 0;
8947 event.modifiers = mac_to_emacs_modifiers (modifiers);
8948 event.timestamp = TickCount () * (1000 / 60);
8949 XSETINT (event.x, mouse.h);
8950 XSETINT (event.y, mouse.v);
8951 XSETFRAME (frame, f);
8952 event.frame_or_window = Fcons (frame, file_list);
8953 event.arg = Qnil;
8954 /* Post to the interrupt queue */
8955 kbd_buffer_store_event (&event);
8956 /* MAC_TODO: Mimic behavior of windows by switching contexts to Emacs */
8957 {
8958 ProcessSerialNumber psn;
8959 GetCurrentProcess (&psn);
8960 SetFrontProcess (&psn);
8961 }
8962
8963 return noErr;
8964 }
8965 else
8966 return dragNotAcceptedErr;
8967 }
8968 #endif
8969
8970
8971 /* Print Document Apple Event */
8972 static pascal OSErr
8973 do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon)
8974 {
8975 return errAEEventNotHandled;
8976 }
8977
8978
8979 static pascal OSErr
8980 do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon)
8981 {
8982 #if USE_CARBON_EVENTS
8983 OSErr err;
8984 EventRef event = NULL;
8985 static const HICommand quit_command = {kEventAttributeNone, kHICommandQuit};
8986
8987 err = CreateEvent (NULL, kEventClassCommand, kEventCommandProcess, 0,
8988 kEventAttributeUserEvent, &event);
8989 if (err == noErr)
8990 err = SetEventParameter (event, kEventParamDirectObject, typeHICommand,
8991 sizeof (HICommand), &quit_command);
8992 if (err == noErr)
8993 mac_store_application_menu_event (event);
8994 if (event)
8995 ReleaseEvent (event);
8996
8997 if (err == noErr)
8998 return noErr;
8999 else
9000 return errAEEventNotHandled;
9001 #else
9002 mac_store_application_menu_event (kHICommandQuit);
9003
9004 return noErr;
9005 #endif
9006 }
9007
9008
9009 #if __profile__
9010 void
9011 profiler_exit_proc ()
9012 {
9013 ProfilerDump ("\pEmacs.prof");
9014 ProfilerTerm ();
9015 }
9016 #endif
9017
9018 /* These few functions implement Emacs as a normal Mac application
9019 (almost): set up the heap and the Toolbox, handle necessary system
9020 events plus a few simple menu events. They also set up Emacs's
9021 access to functions defined in the rest of this file. Emacs uses
9022 function hooks to perform all its terminal I/O. A complete list of
9023 these functions appear in termhooks.h. For what they do, read the
9024 comments there and see also w32term.c and xterm.c. What's
9025 noticeably missing here is the event loop, which is normally
9026 present in most Mac application. After performing the necessary
9027 Mac initializations, main passes off control to emacs_main
9028 (corresponding to main in emacs.c). Emacs_main calls XTread_socket
9029 (defined further below) to read input. This is where
9030 WaitNextEvent/ReceiveNextEvent is called to process Mac events. */
9031
9032 #ifdef MAC_OS8
9033 #undef main
9034 int
9035 main (void)
9036 {
9037 #if __profile__ /* is the profiler on? */
9038 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
9039 exit(1);
9040 #endif
9041
9042 #if __MWERKS__
9043 /* set creator and type for files created by MSL */
9044 _fcreator = 'EMAx';
9045 _ftype = 'TEXT';
9046 #endif
9047
9048 do_init_managers ();
9049
9050 do_get_menus ();
9051
9052 #ifndef USE_LSB_TAG
9053 do_check_ram_size ();
9054 #endif
9055
9056 init_emacs_passwd_dir ();
9057
9058 init_environ ();
9059
9060 initialize_applescript ();
9061
9062 init_required_apple_events ();
9063
9064 {
9065 char **argv;
9066 int argc = 0;
9067
9068 /* set up argv array from STR# resource */
9069 get_string_list (&argv, ARGV_STRING_LIST_ID);
9070 while (argv[argc])
9071 argc++;
9072
9073 /* free up AppleScript resources on exit */
9074 atexit (terminate_applescript);
9075
9076 #if __profile__ /* is the profiler on? */
9077 atexit (profiler_exit_proc);
9078 #endif
9079
9080 /* 3rd param "envp" never used in emacs_main */
9081 (void) emacs_main (argc, argv, 0);
9082 }
9083
9084 /* Never reached - real exit in Fkill_emacs */
9085 return 0;
9086 }
9087 #endif
9088
9089 /* Table for translating Mac keycode to X keysym values. Contributed
9090 by Sudhir Shenoy.
9091 Mapping for special keys is now identical to that in Apple X11
9092 except `clear' (-> <clear>) on the KeyPad, `enter' (-> <kp-enter>)
9093 on the right of the Cmd key on laptops, and fn + `enter' (->
9094 <linefeed>). */
9095 static unsigned char keycode_to_xkeysym_table[] = {
9096 /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9097 /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9098 /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9099
9100 /*0x30*/ 0x09 /*tab*/, 0 /*0x0020 space*/, 0, 0x08 /*backspace*/,
9101 /*0x34*/ 0x8d /*enter on laptops*/, 0x1b /*escape*/, 0, 0,
9102 /*0x38*/ 0, 0, 0, 0,
9103 /*0x3C*/ 0, 0, 0, 0,
9104
9105 /*0x40*/ 0, 0xae /*kp-.*/, 0, 0xaa /*kp-**/,
9106 /*0x44*/ 0, 0xab /*kp-+*/, 0, 0x0b /*clear*/,
9107 /*0x48*/ 0, 0, 0, 0xaf /*kp-/*/,
9108 /*0x4C*/ 0x8d /*kp-enter*/, 0, 0xad /*kp--*/, 0,
9109
9110 /*0x50*/ 0, 0xbd /*kp-=*/, 0xb0 /*kp-0*/, 0xb1 /*kp-1*/,
9111 /*0x54*/ 0xb2 /*kp-2*/, 0xb3 /*kp-3*/, 0xb4 /*kp-4*/, 0xb5 /*kp-5*/,
9112 /*0x58*/ 0xb6 /*kp-6*/, 0xb7 /*kp-7*/, 0, 0xb8 /*kp-8*/,
9113 /*0x5C*/ 0xb9 /*kp-9*/, 0, 0, 0,
9114
9115 /*0x60*/ 0xc2 /*f5*/, 0xc3 /*f6*/, 0xc4 /*f7*/, 0xc0 /*f3*/,
9116 /*0x64*/ 0xc5 /*f8*/, 0xc6 /*f9*/, 0, 0xc8 /*f11*/,
9117 /*0x68*/ 0, 0xca /*f13*/, 0, 0xcb /*f14*/,
9118 /*0x6C*/ 0, 0xc7 /*f10*/, 0x0a /*fn+enter on laptops*/, 0xc9 /*f12*/,
9119
9120 /*0x70*/ 0, 0xcc /*f15*/, 0x6a /*help*/, 0x50 /*home*/,
9121 /*0x74*/ 0x55 /*pgup*/, 0xff /*delete*/, 0xc1 /*f4*/, 0x57 /*end*/,
9122 /*0x78*/ 0xbf /*f2*/, 0x56 /*pgdown*/, 0xbe /*f1*/, 0x51 /*left*/,
9123 /*0x7C*/ 0x53 /*right*/, 0x54 /*down*/, 0x52 /*up*/, 0
9124 };
9125
9126 static int
9127 keycode_to_xkeysym (int keyCode, int *xKeySym)
9128 {
9129 *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f];
9130 return *xKeySym != 0;
9131 }
9132
9133 #if !USE_CARBON_EVENTS
9134 static RgnHandle mouse_region = NULL;
9135
9136 Boolean
9137 mac_wait_next_event (er, sleep_time, dequeue)
9138 EventRecord *er;
9139 UInt32 sleep_time;
9140 Boolean dequeue;
9141 {
9142 static EventRecord er_buf = {nullEvent};
9143 UInt32 target_tick, current_tick;
9144 EventMask event_mask;
9145
9146 if (mouse_region == NULL)
9147 mouse_region = NewRgn ();
9148
9149 event_mask = everyEvent;
9150 if (NILP (Fboundp (Qmac_ready_for_drag_n_drop)))
9151 event_mask -= highLevelEventMask;
9152
9153 current_tick = TickCount ();
9154 target_tick = current_tick + sleep_time;
9155
9156 if (er_buf.what == nullEvent)
9157 while (!WaitNextEvent (event_mask, &er_buf,
9158 target_tick - current_tick, mouse_region))
9159 {
9160 current_tick = TickCount ();
9161 if (target_tick <= current_tick)
9162 return false;
9163 }
9164
9165 *er = er_buf;
9166 if (dequeue)
9167 er_buf.what = nullEvent;
9168 return true;
9169 }
9170 #endif /* not USE_CARBON_EVENTS */
9171
9172 /* Emacs calls this whenever it wants to read an input event from the
9173 user. */
9174 int
9175 XTread_socket (sd, expected, hold_quit)
9176 int sd, expected;
9177 struct input_event *hold_quit;
9178 {
9179 struct input_event inev;
9180 int count = 0;
9181 #if USE_CARBON_EVENTS
9182 EventRef eventRef;
9183 EventTargetRef toolbox_dispatcher;
9184 #endif
9185 EventRecord er;
9186 struct mac_display_info *dpyinfo = &one_mac_display_info;
9187
9188 if (interrupt_input_blocked)
9189 {
9190 interrupt_input_pending = 1;
9191 return -1;
9192 }
9193
9194 interrupt_input_pending = 0;
9195 BLOCK_INPUT;
9196
9197 /* So people can tell when we have read the available input. */
9198 input_signal_count++;
9199
9200 #if USE_CARBON_EVENTS
9201 toolbox_dispatcher = GetEventDispatcherTarget ();
9202
9203 while (!ReceiveNextEvent (0, NULL, kEventDurationNoWait,
9204 kEventRemoveFromQueue, &eventRef))
9205 #else /* !USE_CARBON_EVENTS */
9206 while (mac_wait_next_event (&er, 0, true))
9207 #endif /* !USE_CARBON_EVENTS */
9208 {
9209 int do_help = 0;
9210 struct frame *f;
9211 unsigned long timestamp;
9212
9213 /* It is necessary to set this (additional) argument slot of an
9214 event to nil because keyboard.c protects incompletely
9215 processed event from being garbage collected by placing them
9216 in the kbd_buffer_gcpro vector. */
9217 EVENT_INIT (inev);
9218 inev.kind = NO_EVENT;
9219 inev.arg = Qnil;
9220
9221 #if USE_CARBON_EVENTS
9222 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
9223 #else
9224 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
9225 #endif
9226
9227 #if USE_CARBON_EVENTS
9228 /* Handle new events */
9229 if (!mac_convert_event_ref (eventRef, &er))
9230 {
9231 /* There used to be a handler for the kEventMouseWheelMoved
9232 event here. But as of Mac OS X 10.4, this kind of event
9233 is not directly posted to the main event queue by
9234 two-finger scrolling on the trackpad. Instead, some
9235 private event is posted and it is converted to a wheel
9236 event by the default handler for the application target.
9237 The converted one can be received by a Carbon event
9238 handler installed on a window target. */
9239 read_socket_inev = &inev;
9240 SendEventToEventTarget (eventRef, toolbox_dispatcher);
9241 read_socket_inev = NULL;
9242 }
9243 else
9244 #endif /* USE_CARBON_EVENTS */
9245 switch (er.what)
9246 {
9247 case mouseDown:
9248 case mouseUp:
9249 {
9250 WindowPtr window_ptr;
9251 ControlPartCode part_code;
9252 int tool_bar_p = 0;
9253
9254 #if USE_CARBON_EVENTS
9255 /* This is needed to send mouse events like aqua window
9256 buttons to the correct handler. */
9257 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
9258 != eventNotHandledErr)
9259 break;
9260 #endif
9261
9262 if (dpyinfo->grabbed && last_mouse_frame
9263 && FRAME_LIVE_P (last_mouse_frame))
9264 {
9265 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
9266 part_code = inContent;
9267 }
9268 else
9269 {
9270 part_code = FindWindow (er.where, &window_ptr);
9271 if (tip_window && window_ptr == tip_window)
9272 {
9273 HideWindow (tip_window);
9274 part_code = FindWindow (er.where, &window_ptr);
9275 }
9276 }
9277
9278 if (er.what != mouseDown && part_code != inContent)
9279 break;
9280
9281 switch (part_code)
9282 {
9283 case inMenuBar:
9284 f = mac_focus_frame (dpyinfo);
9285 saved_menu_event_location = er.where;
9286 inev.kind = MENU_BAR_ACTIVATE_EVENT;
9287 XSETFRAME (inev.frame_or_window, f);
9288 break;
9289
9290 case inContent:
9291 if (window_ptr != FRAME_MAC_WINDOW (mac_focus_frame (dpyinfo)))
9292 SelectWindow (window_ptr);
9293 else
9294 {
9295 ControlPartCode control_part_code;
9296 ControlHandle ch;
9297 Point mouse_loc = er.where;
9298 #ifdef MAC_OSX
9299 ControlKind control_kind;
9300 #endif
9301
9302 f = mac_window_to_frame (window_ptr);
9303 /* convert to local coordinates of new window */
9304 SetPortWindowPort (window_ptr);
9305
9306 GlobalToLocal (&mouse_loc);
9307 #if TARGET_API_MAC_CARBON
9308 ch = FindControlUnderMouse (mouse_loc, window_ptr,
9309 &control_part_code);
9310 #ifdef MAC_OSX
9311 if (ch)
9312 GetControlKind (ch, &control_kind);
9313 #endif
9314 #else
9315 control_part_code = FindControl (mouse_loc, window_ptr,
9316 &ch);
9317 #endif
9318
9319 #if USE_CARBON_EVENTS
9320 inev.code = mac_get_mouse_btn (eventRef);
9321 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
9322 #else
9323 inev.code = mac_get_emulated_btn (er.modifiers);
9324 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
9325 #endif
9326 XSETINT (inev.x, mouse_loc.h);
9327 XSETINT (inev.y, mouse_loc.v);
9328
9329 if (dpyinfo->grabbed && tracked_scroll_bar
9330 || ch != 0
9331 #ifndef USE_TOOLKIT_SCROLL_BARS
9332 /* control_part_code becomes kControlNoPart if
9333 a progress indicator is clicked. */
9334 && control_part_code != kControlNoPart
9335 #else /* USE_TOOLKIT_SCROLL_BARS */
9336 #ifdef MAC_OSX
9337 && control_kind.kind == kControlKindScrollBar
9338 #endif /* MAC_OSX */
9339 #endif /* USE_TOOLKIT_SCROLL_BARS */
9340 )
9341 {
9342 struct scroll_bar *bar;
9343
9344 if (dpyinfo->grabbed && tracked_scroll_bar)
9345 {
9346 bar = tracked_scroll_bar;
9347 #ifndef USE_TOOLKIT_SCROLL_BARS
9348 control_part_code = kControlIndicatorPart;
9349 #endif
9350 }
9351 else
9352 bar = (struct scroll_bar *) GetControlReference (ch);
9353 #ifdef USE_TOOLKIT_SCROLL_BARS
9354 /* Make the "Ctrl-Mouse-2 splits window" work
9355 for toolkit scroll bars. */
9356 if (er.modifiers & controlKey)
9357 x_scroll_bar_handle_click (bar, control_part_code,
9358 &er, &inev);
9359 else if (er.what == mouseDown)
9360 x_scroll_bar_handle_press (bar, control_part_code,
9361 &inev);
9362 else
9363 x_scroll_bar_handle_release (bar, &inev);
9364 #else /* not USE_TOOLKIT_SCROLL_BARS */
9365 x_scroll_bar_handle_click (bar, control_part_code,
9366 &er, &inev);
9367 if (er.what == mouseDown
9368 && control_part_code == kControlIndicatorPart)
9369 tracked_scroll_bar = bar;
9370 else
9371 tracked_scroll_bar = NULL;
9372 #endif /* not USE_TOOLKIT_SCROLL_BARS */
9373 }
9374 else
9375 {
9376 Lisp_Object window;
9377 int x = mouse_loc.h;
9378 int y = mouse_loc.v;
9379
9380 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
9381 if (EQ (window, f->tool_bar_window))
9382 {
9383 if (er.what == mouseDown)
9384 handle_tool_bar_click (f, x, y, 1, 0);
9385 else
9386 handle_tool_bar_click (f, x, y, 0,
9387 inev.modifiers);
9388 tool_bar_p = 1;
9389 }
9390 else
9391 {
9392 XSETFRAME (inev.frame_or_window, f);
9393 inev.kind = MOUSE_CLICK_EVENT;
9394 }
9395 }
9396
9397 if (er.what == mouseDown)
9398 {
9399 dpyinfo->grabbed |= (1 << inev.code);
9400 last_mouse_frame = f;
9401 /* Ignore any mouse motion that happened
9402 before this event; any subsequent
9403 mouse-movement Emacs events should reflect
9404 only motion after the ButtonPress. */
9405 if (f != 0)
9406 f->mouse_moved = 0;
9407
9408 if (!tool_bar_p)
9409 last_tool_bar_item = -1;
9410 }
9411 else
9412 {
9413 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
9414 /* If a button is released though it was not
9415 previously pressed, that would be because
9416 of multi-button emulation. */
9417 dpyinfo->grabbed = 0;
9418 else
9419 dpyinfo->grabbed &= ~(1 << inev.code);
9420 }
9421
9422 #ifdef USE_TOOLKIT_SCROLL_BARS
9423 if (inev.kind == MOUSE_CLICK_EVENT)
9424 #endif
9425 switch (er.what)
9426 {
9427 case mouseDown:
9428 inev.modifiers |= down_modifier;
9429 break;
9430 case mouseUp:
9431 inev.modifiers |= up_modifier;
9432 break;
9433 }
9434 }
9435 break;
9436
9437 case inDrag:
9438 #if TARGET_API_MAC_CARBON
9439 DragWindow (window_ptr, er.where, NULL);
9440 #else /* not TARGET_API_MAC_CARBON */
9441 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
9442 #endif /* not TARGET_API_MAC_CARBON */
9443 /* Update the frame parameters. */
9444 {
9445 struct frame *f = mac_window_to_frame (window_ptr);
9446
9447 if (f && !f->async_iconified)
9448 x_real_positions (f, &f->left_pos, &f->top_pos);
9449 }
9450 break;
9451
9452 case inGoAway:
9453 if (TrackGoAway (window_ptr, er.where))
9454 {
9455 inev.kind = DELETE_WINDOW_EVENT;
9456 XSETFRAME (inev.frame_or_window,
9457 mac_window_to_frame (window_ptr));
9458 }
9459 break;
9460
9461 /* window resize handling added --ben */
9462 case inGrow:
9463 do_grow_window (window_ptr, &er);
9464 break;
9465
9466 /* window zoom handling added --ben */
9467 case inZoomIn:
9468 case inZoomOut:
9469 if (TrackBox (window_ptr, er.where, part_code))
9470 do_zoom_window (window_ptr, part_code);
9471 break;
9472
9473 default:
9474 break;
9475 }
9476 }
9477 break;
9478
9479 case updateEvt:
9480 #if USE_CARBON_EVENTS
9481 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
9482 != eventNotHandledErr)
9483 break;
9484 #else
9485 do_window_update ((WindowPtr) er.message);
9486 #endif
9487 break;
9488
9489 case osEvt:
9490 #if USE_CARBON_EVENTS
9491 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
9492 != eventNotHandledErr)
9493 break;
9494 #endif
9495 switch ((er.message >> 24) & 0x000000FF)
9496 {
9497 case suspendResumeMessage:
9498 if ((er.message & resumeFlag) == 1)
9499 do_app_resume ();
9500 else
9501 do_app_suspend ();
9502 break;
9503
9504 case mouseMovedMessage:
9505 #if !USE_CARBON_EVENTS
9506 SetRectRgn (mouse_region, er.where.h, er.where.v,
9507 er.where.h + 1, er.where.v + 1);
9508 #endif
9509 previous_help_echo_string = help_echo_string;
9510 help_echo_string = help_echo_object = help_echo_window = Qnil;
9511 help_echo_pos = -1;
9512
9513 if (dpyinfo->grabbed && last_mouse_frame
9514 && FRAME_LIVE_P (last_mouse_frame))
9515 f = last_mouse_frame;
9516 else
9517 f = dpyinfo->x_focus_frame;
9518
9519 if (dpyinfo->mouse_face_hidden)
9520 {
9521 dpyinfo->mouse_face_hidden = 0;
9522 clear_mouse_face (dpyinfo);
9523 }
9524
9525 if (f)
9526 {
9527 WindowPtr wp = FRAME_MAC_WINDOW (f);
9528 Point mouse_pos = er.where;
9529
9530 SetPortWindowPort (wp);
9531
9532 GlobalToLocal (&mouse_pos);
9533
9534 if (dpyinfo->grabbed && tracked_scroll_bar)
9535 #ifdef USE_TOOLKIT_SCROLL_BARS
9536 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
9537 mouse_pos, &inev);
9538 #else /* not USE_TOOLKIT_SCROLL_BARS */
9539 x_scroll_bar_note_movement (tracked_scroll_bar,
9540 mouse_pos.v
9541 - XINT (tracked_scroll_bar->top),
9542 er.when * (1000 / 60));
9543 #endif /* not USE_TOOLKIT_SCROLL_BARS */
9544 else
9545 {
9546 /* Generate SELECT_WINDOW_EVENTs when needed. */
9547 if (mouse_autoselect_window)
9548 {
9549 Lisp_Object window;
9550
9551 window = window_from_coordinates (f,
9552 mouse_pos.h,
9553 mouse_pos.v,
9554 0, 0, 0, 0);
9555
9556 /* Window will be selected only when it is
9557 not selected now and last mouse movement
9558 event was not in it. Minibuffer window
9559 will be selected iff it is active. */
9560 if (WINDOWP (window)
9561 && !EQ (window, last_window)
9562 && !EQ (window, selected_window))
9563 {
9564 inev.kind = SELECT_WINDOW_EVENT;
9565 inev.frame_or_window = window;
9566 }
9567
9568 last_window=window;
9569 }
9570 note_mouse_movement (f, &mouse_pos);
9571 }
9572 }
9573
9574 /* If the contents of the global variable
9575 help_echo_string has changed, generate a
9576 HELP_EVENT. */
9577 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
9578 do_help = 1;
9579 break;
9580 }
9581 break;
9582
9583 case activateEvt:
9584 {
9585 WindowPtr window_ptr = (WindowPtr) er.message;
9586
9587 #if USE_CARBON_EVENTS
9588 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
9589 != eventNotHandledErr)
9590 break;
9591 #endif
9592 if (window_ptr == tip_window)
9593 {
9594 HideWindow (tip_window);
9595 break;
9596 }
9597
9598 if (!is_emacs_window (window_ptr))
9599 break;
9600
9601 if ((er.modifiers & activeFlag) != 0)
9602 {
9603 /* A window has been activated */
9604 Point mouse_loc = er.where;
9605
9606 x_detect_focus_change (dpyinfo, &er, &inev);
9607
9608 SetPortWindowPort (window_ptr);
9609 GlobalToLocal (&mouse_loc);
9610 /* Window-activated event counts as mouse movement,
9611 so update things that depend on mouse position. */
9612 note_mouse_movement (mac_window_to_frame (window_ptr),
9613 &mouse_loc);
9614 }
9615 else
9616 {
9617 /* A window has been deactivated */
9618 #if USE_TOOLKIT_SCROLL_BARS
9619 if (dpyinfo->grabbed && tracked_scroll_bar)
9620 {
9621 struct input_event event;
9622
9623 EVENT_INIT (event);
9624 event.kind = NO_EVENT;
9625 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
9626 if (event.kind != NO_EVENT)
9627 {
9628 event.timestamp = timestamp;
9629 kbd_buffer_store_event_hold (&event, hold_quit);
9630 count++;
9631 }
9632 }
9633 #endif
9634 dpyinfo->grabbed = 0;
9635
9636 x_detect_focus_change (dpyinfo, &er, &inev);
9637
9638 f = mac_window_to_frame (window_ptr);
9639 if (f == dpyinfo->mouse_face_mouse_frame)
9640 {
9641 /* If we move outside the frame, then we're
9642 certainly no longer on any text in the
9643 frame. */
9644 clear_mouse_face (dpyinfo);
9645 dpyinfo->mouse_face_mouse_frame = 0;
9646 }
9647
9648 /* Generate a nil HELP_EVENT to cancel a help-echo.
9649 Do it only if there's something to cancel.
9650 Otherwise, the startup message is cleared when the
9651 mouse leaves the frame. */
9652 if (any_help_event_p)
9653 do_help = -1;
9654 }
9655 }
9656 break;
9657
9658 case keyDown:
9659 case autoKey:
9660 {
9661 int keycode = (er.message & keyCodeMask) >> 8;
9662 int xkeysym;
9663
9664 #if USE_CARBON_EVENTS && defined (MAC_OSX)
9665 /* When using Carbon Events, we need to pass raw keyboard
9666 events to the TSM ourselves. If TSM handles it, it
9667 will pass back noErr, otherwise it will pass back
9668 "eventNotHandledErr" and we can process it
9669 normally. */
9670 if ((!NILP (Vmac_pass_command_to_system)
9671 || !(er.modifiers & cmdKey))
9672 && (!NILP (Vmac_pass_control_to_system)
9673 || !(er.modifiers & controlKey))
9674 && (!NILP (Vmac_command_key_is_meta)
9675 && NILP (Vmac_option_modifier)
9676 || !(er.modifiers & optionKey)))
9677 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
9678 != eventNotHandledErr)
9679 break;
9680 #endif
9681
9682 #if 0
9683 if (dpyinfo->x_focus_frame == NULL)
9684 {
9685 /* Beep if keyboard input occurs when all the frames
9686 are invisible. */
9687 SysBeep (1);
9688 break;
9689 }
9690 #endif
9691
9692 {
9693 static SInt16 last_key_script = -1;
9694 SInt16 current_key_script = GetScriptManagerVariable (smKeyScript);
9695
9696 if (last_key_script != current_key_script)
9697 {
9698 struct input_event event;
9699
9700 EVENT_INIT (event);
9701 event.kind = LANGUAGE_CHANGE_EVENT;
9702 event.arg = Qnil;
9703 event.code = current_key_script;
9704 event.timestamp = timestamp;
9705 kbd_buffer_store_event (&event);
9706 count++;
9707 }
9708 last_key_script = current_key_script;
9709 }
9710
9711 ObscureCursor ();
9712
9713 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
9714 {
9715 clear_mouse_face (dpyinfo);
9716 dpyinfo->mouse_face_hidden = 1;
9717 }
9718
9719 if (keycode_to_xkeysym (keycode, &xkeysym))
9720 {
9721 inev.code = 0xff00 | xkeysym;
9722 inev.kind = NON_ASCII_KEYSTROKE_EVENT;
9723 }
9724 else
9725 {
9726 if (er.modifiers & (controlKey |
9727 (NILP (Vmac_command_key_is_meta) ? optionKey
9728 : cmdKey)))
9729 {
9730 /* This code comes from Keyboard Resource,
9731 Appendix C of IM - Text. This is necessary
9732 since shift is ignored in KCHR table
9733 translation when option or command is pressed.
9734 It also does not translate correctly
9735 control-shift chars like C-% so mask off shift
9736 here also */
9737 int new_modifiers = er.modifiers & 0xe600;
9738 /* mask off option and command */
9739 int new_keycode = keycode | new_modifiers;
9740 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
9741 unsigned long some_state = 0;
9742 inev.code = KeyTranslate (kchr_ptr, new_keycode,
9743 &some_state) & 0xff;
9744 }
9745 else if (!NILP (Vmac_option_modifier)
9746 && (er.modifiers & optionKey))
9747 {
9748 /* When using the option key as an emacs modifier,
9749 convert the pressed key code back to one
9750 without the Mac option modifier applied. */
9751 int new_modifiers = er.modifiers & ~optionKey;
9752 int new_keycode = keycode | new_modifiers;
9753 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
9754 unsigned long some_state = 0;
9755 inev.code = KeyTranslate (kchr_ptr, new_keycode,
9756 &some_state) & 0xff;
9757 }
9758 else
9759 inev.code = er.message & charCodeMask;
9760 inev.kind = ASCII_KEYSTROKE_EVENT;
9761 }
9762 }
9763
9764 #if USE_CARBON_EVENTS
9765 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
9766 #else
9767 inev.modifiers = mac_to_emacs_modifiers (er.modifiers);
9768 #endif
9769 inev.modifiers |= (extra_keyboard_modifiers
9770 & (meta_modifier | alt_modifier
9771 | hyper_modifier | super_modifier));
9772 XSETFRAME (inev.frame_or_window, mac_focus_frame (dpyinfo));
9773 break;
9774
9775 case kHighLevelEvent:
9776 read_socket_inev = &inev;
9777 AEProcessAppleEvent (&er);
9778 read_socket_inev = NULL;
9779 break;
9780
9781 default:
9782 break;
9783 }
9784 #if USE_CARBON_EVENTS
9785 ReleaseEvent (eventRef);
9786 #endif
9787
9788 if (inev.kind != NO_EVENT)
9789 {
9790 inev.timestamp = timestamp;
9791 kbd_buffer_store_event_hold (&inev, hold_quit);
9792 count++;
9793 }
9794
9795 if (do_help
9796 && !(hold_quit && hold_quit->kind != NO_EVENT))
9797 {
9798 Lisp_Object frame;
9799
9800 if (f)
9801 XSETFRAME (frame, f);
9802 else
9803 frame = Qnil;
9804
9805 if (do_help > 0)
9806 {
9807 any_help_event_p = 1;
9808 gen_help_event (help_echo_string, frame, help_echo_window,
9809 help_echo_object, help_echo_pos);
9810 }
9811 else
9812 {
9813 help_echo_string = Qnil;
9814 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
9815 }
9816 count++;
9817 }
9818
9819 }
9820
9821 /* If the focus was just given to an autoraising frame,
9822 raise it now. */
9823 /* ??? This ought to be able to handle more than one such frame. */
9824 if (pending_autoraise_frame)
9825 {
9826 x_raise_frame (pending_autoraise_frame);
9827 pending_autoraise_frame = 0;
9828 }
9829
9830 #if !USE_CARBON_EVENTS
9831 /* Check which frames are still visible. We do this here because
9832 there doesn't seem to be any direct notification from the Window
9833 Manager that the visibility of a window has changed (at least,
9834 not in all cases). */
9835 {
9836 Lisp_Object tail, frame;
9837
9838 FOR_EACH_FRAME (tail, frame)
9839 {
9840 struct frame *f = XFRAME (frame);
9841
9842 /* The tooltip has been drawn already. Avoid the
9843 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
9844 if (EQ (frame, tip_frame))
9845 continue;
9846
9847 if (FRAME_MAC_P (f))
9848 mac_handle_visibility_change (f);
9849 }
9850 }
9851 #endif
9852
9853 UNBLOCK_INPUT;
9854 return count;
9855 }
9856
9857
9858 /* Need to override CodeWarrior's input function so no conversion is
9859 done on newlines Otherwise compiled functions in .elc files will be
9860 read incorrectly. Defined in ...:MSL C:MSL
9861 Common:Source:buffer_io.c. */
9862 #ifdef __MWERKS__
9863 void
9864 __convert_to_newlines (unsigned char * p, size_t * n)
9865 {
9866 #pragma unused(p,n)
9867 }
9868
9869 void
9870 __convert_from_newlines (unsigned char * p, size_t * n)
9871 {
9872 #pragma unused(p,n)
9873 }
9874 #endif
9875
9876 #ifdef MAC_OS8
9877 void
9878 make_mac_terminal_frame (struct frame *f)
9879 {
9880 Lisp_Object frame;
9881 Rect r;
9882
9883 XSETFRAME (frame, f);
9884
9885 f->output_method = output_mac;
9886 f->output_data.mac = (struct mac_output *)
9887 xmalloc (sizeof (struct mac_output));
9888 bzero (f->output_data.mac, sizeof (struct mac_output));
9889
9890 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
9891
9892 FRAME_COLS (f) = 96;
9893 FRAME_LINES (f) = 4;
9894
9895 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
9896 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
9897
9898 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
9899
9900 f->output_data.mac->cursor_pixel = 0;
9901 f->output_data.mac->border_pixel = 0x00ff00;
9902 f->output_data.mac->mouse_pixel = 0xff00ff;
9903 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
9904
9905 f->output_data.mac->text_cursor = kThemeIBeamCursor;
9906 f->output_data.mac->nontext_cursor = kThemeArrowCursor;
9907 f->output_data.mac->modeline_cursor = kThemeArrowCursor;
9908 f->output_data.mac->hand_cursor = kThemePointingHandCursor;
9909 f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
9910 f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
9911
9912 FRAME_FONTSET (f) = -1;
9913 f->output_data.mac->explicit_parent = 0;
9914 f->left_pos = 8;
9915 f->top_pos = 32;
9916 f->border_width = 0;
9917
9918 f->internal_border_width = 0;
9919
9920 f->auto_raise = 1;
9921 f->auto_lower = 1;
9922
9923 f->new_text_cols = 0;
9924 f->new_text_lines = 0;
9925
9926 SetRect (&r, f->left_pos, f->top_pos,
9927 f->left_pos + FRAME_PIXEL_WIDTH (f),
9928 f->top_pos + FRAME_PIXEL_HEIGHT (f));
9929
9930 BLOCK_INPUT;
9931
9932 if (!(FRAME_MAC_WINDOW (f) =
9933 NewCWindow (NULL, &r, "\p", true, dBoxProc,
9934 (WindowPtr) -1, 1, (long) f->output_data.mac)))
9935 abort ();
9936 /* so that update events can find this mac_output struct */
9937 f->output_data.mac->mFP = f; /* point back to emacs frame */
9938
9939 UNBLOCK_INPUT;
9940
9941 x_make_gc (f);
9942
9943 /* Need to be initialized for unshow_buffer in window.c. */
9944 selected_window = f->selected_window;
9945
9946 Fmodify_frame_parameters (frame,
9947 Fcons (Fcons (Qfont,
9948 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
9949 Fmodify_frame_parameters (frame,
9950 Fcons (Fcons (Qforeground_color,
9951 build_string ("black")), Qnil));
9952 Fmodify_frame_parameters (frame,
9953 Fcons (Fcons (Qbackground_color,
9954 build_string ("white")), Qnil));
9955 }
9956 #endif
9957
9958 \f
9959 /***********************************************************************
9960 Initialization
9961 ***********************************************************************/
9962
9963 int mac_initialized = 0;
9964
9965 void
9966 mac_initialize_display_info ()
9967 {
9968 struct mac_display_info *dpyinfo = &one_mac_display_info;
9969 GDHandle main_device_handle;
9970
9971 bzero (dpyinfo, sizeof (*dpyinfo));
9972
9973 #ifdef MAC_OSX
9974 dpyinfo->mac_id_name
9975 = (char *) xmalloc (SCHARS (Vinvocation_name)
9976 + SCHARS (Vsystem_name)
9977 + 2);
9978 sprintf (dpyinfo->mac_id_name, "%s@%s",
9979 SDATA (Vinvocation_name), SDATA (Vsystem_name));
9980 #else
9981 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
9982 strcpy (dpyinfo->mac_id_name, "Mac Display");
9983 #endif
9984
9985 main_device_handle = LMGetMainDevice();
9986
9987 dpyinfo->reference_count = 0;
9988 dpyinfo->resx = 75.0;
9989 dpyinfo->resy = 75.0;
9990 dpyinfo->color_p = TestDeviceAttribute (main_device_handle, gdDevType);
9991 #ifdef MAC_OSX
9992 /* HasDepth returns true if it is possible to have a 32 bit display,
9993 but this may not be what is actually used. Mac OSX can do better.
9994 CGMainDisplayID is only available on OSX 10.2 and higher, but the
9995 header for CGGetActiveDisplayList says that the first display returned
9996 is the active one, so we use that. */
9997 {
9998 CGDirectDisplayID disp_id[1];
9999 CGDisplayCount disp_count;
10000 CGDisplayErr error_code;
10001
10002 error_code = CGGetActiveDisplayList (1, disp_id, &disp_count);
10003 if (error_code != 0)
10004 error ("No display found, CGGetActiveDisplayList error %d", error_code);
10005
10006 dpyinfo->n_planes = CGDisplayBitsPerPixel (disp_id[0]);
10007 }
10008 #else
10009 for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1)
10010 if (HasDepth (main_device_handle, dpyinfo->n_planes,
10011 gdDevType, dpyinfo->color_p))
10012 break;
10013 #endif
10014 dpyinfo->height = (**main_device_handle).gdRect.bottom;
10015 dpyinfo->width = (**main_device_handle).gdRect.right;
10016 dpyinfo->grabbed = 0;
10017 dpyinfo->root_window = NULL;
10018 dpyinfo->image_cache = make_image_cache ();
10019
10020 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
10021 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
10022 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
10023 dpyinfo->mouse_face_window = Qnil;
10024 dpyinfo->mouse_face_overlay = Qnil;
10025 dpyinfo->mouse_face_hidden = 0;
10026 }
10027
10028
10029 static XrmDatabase
10030 mac_make_rdb (xrm_option)
10031 char *xrm_option;
10032 {
10033 XrmDatabase database;
10034
10035 database = xrm_get_preference_database (NULL);
10036 if (xrm_option)
10037 xrm_merge_string_database (database, xrm_option);
10038
10039 return database;
10040 }
10041
10042 struct mac_display_info *
10043 mac_term_init (display_name, xrm_option, resource_name)
10044 Lisp_Object display_name;
10045 char *xrm_option;
10046 char *resource_name;
10047 {
10048 struct mac_display_info *dpyinfo;
10049
10050 BLOCK_INPUT;
10051
10052 if (!mac_initialized)
10053 {
10054 mac_initialize ();
10055 mac_initialized = 1;
10056 }
10057
10058 if (x_display_list)
10059 error ("Sorry, this version can only handle one display");
10060
10061 mac_initialize_display_info ();
10062
10063 dpyinfo = &one_mac_display_info;
10064
10065 dpyinfo->xrdb = mac_make_rdb (xrm_option);
10066
10067 /* Put this display on the chain. */
10068 dpyinfo->next = x_display_list;
10069 x_display_list = dpyinfo;
10070
10071 /* Put it on x_display_name_list. */
10072 x_display_name_list = Fcons (Fcons (display_name,
10073 Fcons (Qnil, dpyinfo->xrdb)),
10074 x_display_name_list);
10075 dpyinfo->name_list_element = XCAR (x_display_name_list);
10076
10077 UNBLOCK_INPUT;
10078
10079 return dpyinfo;
10080 }
10081 /* Get rid of display DPYINFO, assuming all frames are already gone. */
10082
10083 void
10084 x_delete_display (dpyinfo)
10085 struct mac_display_info *dpyinfo;
10086 {
10087 int i;
10088
10089 /* Discard this display from x_display_name_list and x_display_list.
10090 We can't use Fdelq because that can quit. */
10091 if (! NILP (x_display_name_list)
10092 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
10093 x_display_name_list = XCDR (x_display_name_list);
10094 else
10095 {
10096 Lisp_Object tail;
10097
10098 tail = x_display_name_list;
10099 while (CONSP (tail) && CONSP (XCDR (tail)))
10100 {
10101 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
10102 {
10103 XSETCDR (tail, XCDR (XCDR (tail)));
10104 break;
10105 }
10106 tail = XCDR (tail);
10107 }
10108 }
10109
10110 if (x_display_list == dpyinfo)
10111 x_display_list = dpyinfo->next;
10112 else
10113 {
10114 struct x_display_info *tail;
10115
10116 for (tail = x_display_list; tail; tail = tail->next)
10117 if (tail->next == dpyinfo)
10118 tail->next = tail->next->next;
10119 }
10120
10121 /* Free the font names in the font table. */
10122 for (i = 0; i < dpyinfo->n_fonts; i++)
10123 if (dpyinfo->font_table[i].name)
10124 {
10125 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
10126 xfree (dpyinfo->font_table[i].full_name);
10127 xfree (dpyinfo->font_table[i].name);
10128 }
10129
10130 if (dpyinfo->font_table->font_encoder)
10131 xfree (dpyinfo->font_table->font_encoder);
10132
10133 xfree (dpyinfo->font_table);
10134 xfree (dpyinfo->mac_id_name);
10135
10136 if (x_display_list == 0)
10137 {
10138 mac_clear_font_name_table ();
10139 bzero (dpyinfo, sizeof (*dpyinfo));
10140 }
10141 }
10142
10143 \f
10144 #ifdef MAC_OSX
10145 void
10146 mac_check_bundle()
10147 {
10148 extern int inhibit_window_system;
10149 extern int noninteractive;
10150 CFBundleRef appsBundle;
10151 pid_t child;
10152
10153 /* No need to test if already -nw*/
10154 if (inhibit_window_system || noninteractive)
10155 return;
10156
10157 appsBundle = CFBundleGetMainBundle();
10158 if (appsBundle != NULL)
10159 {
10160 CFStringRef cfBI = CFSTR("CFBundleIdentifier");
10161 CFTypeRef res = CFBundleGetValueForInfoDictionaryKey(appsBundle, cfBI);
10162 /* We found the bundle identifier, now we know we are valid. */
10163 if (res != NULL)
10164 {
10165 CFRelease(res);
10166 return;
10167 }
10168 }
10169 /* MAC_TODO: Have this start the bundled executable */
10170
10171 /* For now, prevent the fatal error by bringing it up in the terminal */
10172 inhibit_window_system = 1;
10173 }
10174
10175 void
10176 MakeMeTheFrontProcess ()
10177 {
10178 ProcessSerialNumber psn;
10179 OSErr err;
10180
10181 err = GetCurrentProcess (&psn);
10182 if (err == noErr)
10183 (void) SetFrontProcess (&psn);
10184 }
10185
10186 /***** Code to handle C-g testing *****/
10187
10188 /* Contains the Mac modifier formed from quit_char */
10189 int mac_quit_char_modifiers = 0;
10190 int mac_quit_char_keycode;
10191 extern int quit_char;
10192
10193 static void
10194 mac_determine_quit_char_modifiers()
10195 {
10196 /* Todo: Determine modifiers from quit_char. */
10197 UInt32 qc_modifiers = ctrl_modifier;
10198
10199 /* Map modifiers */
10200 mac_quit_char_modifiers = 0;
10201 if (qc_modifiers & ctrl_modifier) mac_quit_char_modifiers |= macCtrlKey;
10202 if (qc_modifiers & shift_modifier) mac_quit_char_modifiers |= macShiftKey;
10203 if (qc_modifiers & meta_modifier) mac_quit_char_modifiers |= macMetaKey;
10204 if (qc_modifiers & alt_modifier) mac_quit_char_modifiers |= macAltKey;
10205 }
10206
10207 static void
10208 init_quit_char_handler ()
10209 {
10210 /* TODO: Let this support keys other the 'g' */
10211 mac_quit_char_keycode = 5;
10212 /* Look at <architecture/adb_kb_map.h> for details */
10213 /* http://gemma.apple.com/techpubs/mac/Toolbox/Toolbox-40.html#MARKER-9-184*/
10214
10215 mac_determine_quit_char_modifiers();
10216 }
10217
10218 static Boolean
10219 quit_char_comp (EventRef inEvent, void *inCompData)
10220 {
10221 if (GetEventClass(inEvent) != kEventClassKeyboard)
10222 return false;
10223 if (GetEventKind(inEvent) != kEventRawKeyDown)
10224 return false;
10225 {
10226 UInt32 keyCode;
10227 UInt32 keyModifiers;
10228 GetEventParameter(inEvent, kEventParamKeyCode,
10229 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
10230 if (keyCode != mac_quit_char_keycode)
10231 return false;
10232 GetEventParameter(inEvent, kEventParamKeyModifiers,
10233 typeUInt32, NULL, sizeof(UInt32), NULL, &keyModifiers);
10234 if (keyModifiers != mac_quit_char_modifiers)
10235 return false;
10236 }
10237 return true;
10238 }
10239
10240 void
10241 mac_check_for_quit_char ()
10242 {
10243 EventRef event;
10244 static EMACS_TIME last_check_time = { 0, 0 };
10245 static EMACS_TIME one_second = { 1, 0 };
10246 EMACS_TIME now, t;
10247
10248 /* If windows are not initialized, return immediately (keep it bouncin'). */
10249 if (!mac_quit_char_modifiers)
10250 return;
10251
10252 /* Don't check if last check is less than a second ago. */
10253 EMACS_GET_TIME (now);
10254 EMACS_SUB_TIME (t, now, last_check_time);
10255 if (EMACS_TIME_LT (t, one_second))
10256 return;
10257 last_check_time = now;
10258
10259 /* Redetermine modifiers because they are based on lisp variables */
10260 mac_determine_quit_char_modifiers ();
10261
10262 /* Fill the queue with events */
10263 BLOCK_INPUT;
10264 ReceiveNextEvent (0, NULL, kEventDurationNoWait, false, &event);
10265 event = FindSpecificEventInQueue (GetMainEventQueue (), quit_char_comp,
10266 NULL);
10267 UNBLOCK_INPUT;
10268 if (event)
10269 {
10270 struct input_event e;
10271
10272 /* Use an input_event to emulate what the interrupt handler does. */
10273 EVENT_INIT (e);
10274 e.kind = ASCII_KEYSTROKE_EVENT;
10275 e.code = quit_char;
10276 e.arg = Qnil;
10277 e.modifiers = NULL;
10278 e.timestamp = EventTimeToTicks (GetEventTime (event)) * (1000/60);
10279 XSETFRAME (e.frame_or_window, mac_focus_frame (&one_mac_display_info));
10280 /* Remove event from queue to prevent looping. */
10281 RemoveEventFromQueue (GetMainEventQueue (), event);
10282 ReleaseEvent (event);
10283 kbd_buffer_store_event (&e);
10284 }
10285 }
10286 #endif /* MAC_OSX */
10287
10288 static void
10289 init_menu_bar ()
10290 {
10291 #ifdef MAC_OSX
10292 OSErr err;
10293 MenuRef menu;
10294 MenuItemIndex menu_index;
10295
10296 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
10297 &menu, &menu_index);
10298 if (err == noErr)
10299 SetMenuItemCommandKey (menu, menu_index, false, 0);
10300 #if USE_CARBON_EVENTS
10301 EnableMenuCommand (NULL, kHICommandPreferences);
10302 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
10303 &menu, &menu_index);
10304 if (err == noErr)
10305 {
10306 SetMenuItemCommandKey (menu, menu_index, false, 0);
10307 InsertMenuItemTextWithCFString (menu, NULL,
10308 0, kMenuItemAttrSeparator, 0);
10309 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
10310 0, 0, kHICommandAbout);
10311 }
10312 #endif /* USE_CARBON_EVENTS */
10313 #else /* !MAC_OSX */
10314 #if USE_CARBON_EVENTS
10315 SetMenuItemCommandID (GetMenuHandle (M_APPLE), I_ABOUT, kHICommandAbout);
10316 #endif
10317 #endif
10318 }
10319
10320
10321 /* Set up use of X before we make the first connection. */
10322
10323 extern frame_parm_handler mac_frame_parm_handlers[];
10324
10325 static struct redisplay_interface x_redisplay_interface =
10326 {
10327 mac_frame_parm_handlers,
10328 x_produce_glyphs,
10329 x_write_glyphs,
10330 x_insert_glyphs,
10331 x_clear_end_of_line,
10332 x_scroll_run,
10333 x_after_update_window_line,
10334 x_update_window_begin,
10335 x_update_window_end,
10336 x_cursor_to,
10337 x_flush,
10338 0, /* flush_display_optional */
10339 x_clear_window_mouse_face,
10340 x_get_glyph_overhangs,
10341 x_fix_overlapping_area,
10342 x_draw_fringe_bitmap,
10343 0, /* define_fringe_bitmap */
10344 0, /* destroy_fringe_bitmap */
10345 mac_per_char_metric,
10346 mac_encode_char,
10347 mac_compute_glyph_string_overhangs,
10348 x_draw_glyph_string,
10349 mac_define_frame_cursor,
10350 mac_clear_frame_area,
10351 mac_draw_window_cursor,
10352 mac_draw_vertical_window_border,
10353 mac_shift_glyphs_for_insert
10354 };
10355
10356 void
10357 mac_initialize ()
10358 {
10359 rif = &x_redisplay_interface;
10360
10361 clear_frame_hook = x_clear_frame;
10362 ins_del_lines_hook = x_ins_del_lines;
10363 delete_glyphs_hook = x_delete_glyphs;
10364 ring_bell_hook = XTring_bell;
10365 reset_terminal_modes_hook = XTreset_terminal_modes;
10366 set_terminal_modes_hook = XTset_terminal_modes;
10367 update_begin_hook = x_update_begin;
10368 update_end_hook = x_update_end;
10369 set_terminal_window_hook = XTset_terminal_window;
10370 read_socket_hook = XTread_socket;
10371 frame_up_to_date_hook = XTframe_up_to_date;
10372 mouse_position_hook = XTmouse_position;
10373 frame_rehighlight_hook = XTframe_rehighlight;
10374 frame_raise_lower_hook = XTframe_raise_lower;
10375
10376 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
10377 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
10378 redeem_scroll_bar_hook = XTredeem_scroll_bar;
10379 judge_scroll_bars_hook = XTjudge_scroll_bars;
10380
10381 scroll_region_ok = 1; /* we'll scroll partial frames */
10382 char_ins_del_ok = 1;
10383 line_ins_del_ok = 1; /* we'll just blt 'em */
10384 fast_clear_end_of_line = 1; /* X does this well */
10385 memory_below_frame = 0; /* we don't remember what scrolls
10386 off the bottom */
10387 baud_rate = 19200;
10388
10389 last_tool_bar_item = -1;
10390 any_help_event_p = 0;
10391
10392 /* Try to use interrupt input; if we can't, then start polling. */
10393 Fset_input_mode (Qt, Qnil, Qt, Qnil);
10394
10395 BLOCK_INPUT;
10396
10397 #if TARGET_API_MAC_CARBON
10398 init_required_apple_events ();
10399
10400 #if USE_CARBON_EVENTS
10401 #ifdef MAC_OSX
10402 init_service_handler ();
10403
10404 init_quit_char_handler ();
10405 #endif /* MAC_OSX */
10406
10407 init_command_handler ();
10408
10409 init_menu_bar ();
10410 #endif /* USE_CARBON_EVENTS */
10411
10412 #ifdef MAC_OSX
10413 if (!inhibit_window_system)
10414 MakeMeTheFrontProcess ();
10415 #endif
10416 #endif
10417 UNBLOCK_INPUT;
10418 }
10419
10420
10421 void
10422 syms_of_macterm ()
10423 {
10424 #if 0
10425 staticpro (&x_error_message_string);
10426 x_error_message_string = Qnil;
10427 #endif
10428
10429 Qmodifier_value = intern ("modifier-value");
10430 Qalt = intern ("alt");
10431 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
10432 Qhyper = intern ("hyper");
10433 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
10434 Qsuper = intern ("super");
10435 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
10436
10437 Qapplication = intern ("application"); staticpro (&Qapplication);
10438 Qabout = intern ("about"); staticpro (&Qabout);
10439
10440 #if USE_CARBON_EVENTS && defined (MAC_OSX)
10441 Qpreferences = intern ("preferences"); staticpro (&Qpreferences);
10442 Qservices = intern ("services"); staticpro (&Qservices);
10443 Qpaste = intern ("paste"); staticpro (&Qpaste);
10444 Qperform = intern ("perform"); staticpro (&Qperform);
10445 #endif
10446
10447 #ifdef MAC_OSX
10448 Fprovide (intern ("mac-carbon"), Qnil);
10449 #endif
10450
10451 staticpro (&Qreverse);
10452 Qreverse = intern ("reverse");
10453
10454 staticpro (&x_display_name_list);
10455 x_display_name_list = Qnil;
10456
10457 staticpro (&last_mouse_scroll_bar);
10458 last_mouse_scroll_bar = Qnil;
10459
10460 Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop");
10461 staticpro (&Qmac_ready_for_drag_n_drop);
10462
10463 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
10464 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
10465 #ifdef USE_TOOLKIT_SCROLL_BARS
10466 Vx_toolkit_scroll_bars = Qt;
10467 #else
10468 Vx_toolkit_scroll_bars = Qnil;
10469 #endif
10470
10471 staticpro (&last_mouse_motion_frame);
10472 last_mouse_motion_frame = Qnil;
10473
10474 DEFVAR_LISP ("mac-command-key-is-meta", &Vmac_command_key_is_meta,
10475 doc: /* Non-nil means that the command key is used as the Emacs meta key.
10476 Otherwise the option key is used. */);
10477 Vmac_command_key_is_meta = Qt;
10478
10479 DEFVAR_LISP ("mac-option-modifier", &Vmac_option_modifier,
10480 doc: /* Modifier to use for the Mac alt/option key. The value can
10481 be alt, hyper, or super for the respective modifier. If the value is
10482 nil then the key will act as the normal Mac option modifier. */);
10483 Vmac_option_modifier = Qnil;
10484
10485 DEFVAR_LISP ("mac-reverse-ctrl-meta", &Vmac_reverse_ctrl_meta,
10486 doc: /* Non-nil means that the control and meta keys are reversed. This is
10487 useful for non-standard keyboard layouts. */);
10488 Vmac_reverse_ctrl_meta = Qnil;
10489
10490 DEFVAR_LISP ("mac-emulate-three-button-mouse",
10491 &Vmac_emulate_three_button_mouse,
10492 doc: /* t means that when the option-key is held down while pressing the
10493 mouse button, the click will register as mouse-2 and while the
10494 command-key is held down, the click will register as mouse-3.
10495 'reverse means that the option-key will register for mouse-3
10496 and the command-key will register for mouse-2. nil means that
10497 no emulation should be done and the modifiers should be placed
10498 on the mouse-1 event. */);
10499 Vmac_emulate_three_button_mouse = Qnil;
10500
10501 #if USE_CARBON_EVENTS
10502 DEFVAR_LISP ("mac-wheel-button-is-mouse-2", &Vmac_wheel_button_is_mouse_2,
10503 doc: /* Non-nil means that the wheel button will be treated as mouse-2 and
10504 the right click will be mouse-3.
10505 Otherwise, the right click will be mouse-2 and the wheel button mouse-3.*/);
10506 Vmac_wheel_button_is_mouse_2 = Qt;
10507
10508 DEFVAR_LISP ("mac-pass-command-to-system", &Vmac_pass_command_to_system,
10509 doc: /* If non-nil, the Mac \"Command\" key is passed on to the Mac
10510 Toolbox for processing before Emacs sees it. */);
10511 Vmac_pass_command_to_system = Qt;
10512
10513 DEFVAR_LISP ("mac-pass-control-to-system", &Vmac_pass_control_to_system,
10514 doc: /* If non-nil, the Mac \"Control\" key is passed on to the Mac
10515 Toolbox for processing before Emacs sees it. */);
10516 Vmac_pass_control_to_system = Qt;
10517
10518 #endif
10519
10520 DEFVAR_LISP ("mac-allow-anti-aliasing", &Vmac_use_core_graphics,
10521 doc: /* If non-nil, allow anti-aliasing.
10522 The text will be rendered using Core Graphics text rendering which
10523 may anti-alias the text. */);
10524 Vmac_use_core_graphics = Qnil;
10525
10526 /* Register an entry for `mac-roman' so that it can be used when
10527 creating the terminal frame on Mac OS 9 before loading
10528 term/mac-win.elc. */
10529 DEFVAR_LISP ("mac-charset-info-alist", &Vmac_charset_info_alist,
10530 doc: /* Alist linking Emacs character sets to Mac text encoding and Emacs coding system.
10531 Each entry should be of the form:
10532
10533 (CHARSET-NAME TEXT-ENCODING CODING-SYSTEM)
10534
10535 where CHARSET-NAME is a string used in font names to identify the
10536 charset, TEXT-ENCODING is a TextEncodingBase value, and CODING_SYSTEM
10537 is a coding system corresponding to TEXT-ENCODING. */);
10538 Vmac_charset_info_alist =
10539 Fcons (list3 (build_string ("mac-roman"),
10540 make_number (smRoman), Qnil), Qnil);
10541 }
10542
10543 /* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b
10544 (do not change this comment) */