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