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