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