summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Choi <akochoi@shaw.ca>2002-04-26 23:39:06 +0000
committerAndrew Choi <akochoi@shaw.ca>2002-04-26 23:39:06 +0000
commite0f712ba55fa0d073f6ab93606e428f61fc7caf2 (patch)
tree7dc6d3403fafcbee1a83288ac840f7eba1d92b44 /src
parent501d8923ae2cdec4ef50f050bb66d3715ba2a8f6 (diff)
downloademacs-e0f712ba55fa0d073f6ab93606e428f61fc7caf2.tar.gz
Patch for building Emacs on Mac OS X. April 26, 2002. See ChangeLog,
lisp/ChangeLog, and src/ChangeLog for list of changes.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog33
-rw-r--r--src/Makefile.in54
-rw-r--r--src/alloc.c2
-rw-r--r--src/callproc.c22
-rw-r--r--src/config.in12
-rw-r--r--src/dispextern.h2
-rw-r--r--src/dispnew.c8
-rw-r--r--src/editfns.c6
-rw-r--r--src/emacs.c48
-rw-r--r--src/fontset.c4
-rw-r--r--src/frame.c10
-rw-r--r--src/frame.h10
-rw-r--r--src/keyboard.c12
-rw-r--r--src/m/powermac.h121
-rw-r--r--src/mac.c2758
-rw-r--r--src/macfns.c10255
-rw-r--r--src/macgui.h157
-rw-r--r--src/macmenu.c2346
-rw-r--r--src/macterm.c13192
-rw-r--r--src/macterm.h670
-rw-r--r--src/process.c13
-rw-r--r--src/s/darwin.h291
-rw-r--r--src/sysdep.c12
-rw-r--r--src/term.c2
-rw-r--r--src/termcap.c17
-rw-r--r--src/tparam.c4
-rw-r--r--src/unexmacosx.c914
-rw-r--r--src/window.c2
-rw-r--r--src/xdisp.c16
-rw-r--r--src/xfaces.c63
30 files changed, 30958 insertions, 98 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 990f10d02ec..a2db98db431 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,36 @@
+2002-04-26 Andrew Choi <akochoi@shaw.ca>
+
+ * Makefile.in (C_SWITCH_SYSTEM_TEMACS): Add.
+ [HAVE_CARBON]: Include Mac object files.
+
+ * alloc.c, callproc.c, dispextern.h, dispnew.c, emacs.c,
+ fontset.c, frame.c, frame.h, keyboard.c, sysdep.c, term.c,
+ termcap.c, window.c, xdisp.c, xfaces.c: Use macros MAC_OS8,
+ MAC_OSX, and MAC_OS instead of macintosh.
+
+ * editfns.c [MAC_OS8]: Include stdio.h.
+
+ * emacs.c [MAC_OS8]: Call mac_initialize instead of x_term_init.
+
+ * fontset.c [MAC_OS]: Set Vdefault_fontset to ETL Fixed instead of
+ Apple Monaco.
+
+ * process.c: Declare QCfamily and QCfilter as extern.
+ (wait_reading_process_input) [MAC_OSX]: Clear bit for stdin before
+ calling select.
+
+ * termcap.c [MAC_OSX]: Don't define tgetnum, PC, tputs, and
+ tgetent.
+
+ * tparam.c [MAC_OSX]: Don't define BC and UP.
+
+ * config.in [HAVE_CARBON]: Add.
+
+ * mac.c, macgui.h, macfns.c, macmenu.c, macterm.c, macterm.h: Move
+ here from mac/src and mac/inc.
+
+ * s/darwin.h, m/powermac.h, unexmacosx.c: New files.
+
2002-04-26 Gerd Moellmann <gerd@gnu.org>
* xterm.c (x_draw_phys_cursor_glyph): Undo last change. Compute
diff --git a/src/Makefile.in b/src/Makefile.in
index 1d8f1adb4cb..82d1e78aaa0 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -159,6 +159,12 @@ CC = C_COMPILER
#define LD_SWITCH_SYSTEM_TEMACS
#endif
+/* Some s/SYSTEM.h files define this to request special switches
+ for compiling temacs. */
+#ifndef C_SWITCH_SYSTEM_TEMACS
+#define C_SWITCH_SYSTEM_TEMACS
+#endif
+
/* Some m/MACHINE.h files define this to request special switches in ld. */
#ifndef LD_SWITCH_MACHINE
#define LD_SWITCH_MACHINE
@@ -266,7 +272,7 @@ TOOLKIT_DEFINES =
/* C_SWITCH_X_SITE must come before C_SWITCH_X_MACHINE and C_SWITCH_X_SYSTEM
since it may have -I options that should override those two. */
-ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAG) -I. -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM ${CFLAGS}
+ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAG) -I. -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS}
.c.o:
$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<
@@ -531,10 +537,17 @@ MSDOS_OBJ = dosfns.o msdos.o w16select.o
#endif
#endif
+#ifdef HAVE_CARBON
+XMENU_OBJ =
+MAC_OBJ = mac.o macterm.o macfns.o macmenu.o fontset.o
+emacsapp = ../mac/Emacs.app/
+#else
+XMENU_OBJ = xmenu.o
+#endif
/* lastfile must follow all files
whose initialized data areas should be dumped as pure by dump-emacs. */
-obj= dispnew.o frame.o scroll.o xdisp.o xmenu.o window.o \
+obj= dispnew.o frame.o scroll.o xdisp.o $(XMENU_OBJ) window.o \
charset.o coding.o category.o ccl.o\
cm.o term.o xfaces.o $(XOBJ) \
emacs.o keyboard.o macros.o keymap.o sysdep.o \
@@ -547,13 +560,14 @@ obj= dispnew.o frame.o scroll.o xdisp.o xmenu.o window.o \
process.o callproc.o \
region-cache.o sound.o atimer.o \
doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \
- $(MSDOS_OBJ)
+ $(MSDOS_OBJ) $(MAC_OBJ)
/* Object files used on some machine or other.
These go in the DOC file on all machines
in case they are needed there. */
SOME_MACHINE_OBJECTS = sunfns.o dosfns.o msdos.o \
- xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o
+ xterm.o xfns.o xmenu.o xselect.o xrdb.o \
+ mac.o macterm.o macfns.o macmenu.o
#ifdef TERMINFO
@@ -1168,6 +1182,38 @@ composite.o: composite.c buffer.h charset.h $(INTERVAL_SRC) $(config_h)
sunfns.o: sunfns.c buffer.h window.h dispextern.h $(config_h)
+#ifdef HAVE_CARBON
+abbrev.o buffer.o callint.o cmds.o dispnew.o editfns.o fileio.o frame.o \
+ fontset.o indent.o insdel.o keyboard.o macros.o minibuf.o msdos.o process.o \
+ scroll.o sysdep.o term.o widget.o window.o xdisp.o xfaces.o xfns.o xmenu.o \
+ xterm.o xselect.o sound.o: macgui.h
+mac.o: mac.c process.h sysselect.h systime.h $(config_h)
+macfns.o: macfns.c charset.h macterm.h macgui.h frame.h window.h buffer.h \
+ dispextern.h macgui.h fontset.h $(INTERVAL_SRC) keyboard.h blockinput.h \
+ atimer.h systime.h epaths.h termhooks.h coding.h ccl.h systime.h $(config_h)
+macmenu.o: macmenu.c termhooks.h frame.h window.h dispextern.h macgui.h \
+ keyboard.h blockinput.h atimer.h systime.h buffer.h macterm.h $(config_h)
+macterm.o: blockinput.h atimer.h systime.h syssignal.h macterm.h macgui.h \
+ frame.h charset.h ccl.h dispextern.h fontset.h termhooks.h termopts.h \
+ termchar.h gnu.h disptab.h buffer.h window.h keyboard.h $(INTERVAL_SRC) \
+ process.h coding.h $(config_h)
+
+macosx-app: ${emacsapp}Contents/MacOS/Emacs \
+ ${emacsapp}Contents/Resources/Emacs.rsrc
+
+${emacsapp}Contents/MacOS/Emacs: emacs
+ if [ -d ${emacsapp}Contents/MacOS/ ]; then true; else \
+ mkdir ${emacsapp}Contents/MacOS/; \
+ fi
+ cd ${emacsapp}Contents/MacOS/; cp ../../../../src/emacs Emacs
+
+${emacsapp}Contents/Resources/Emacs.rsrc: ../mac/src/Emacs.r
+ /Developer/Tools/Rez -useDF -o \
+ ${emacsapp}Contents/Resources/Emacs.rsrc \
+ /System/Library/Frameworks/Carbon.framework/Headers/Carbon.r \
+ ../mac/src/Emacs.r
+#endif
+
${libsrc}emacstool: ${libsrc}emacstool.c
cd ${libsrc}; ${MAKE} ${MFLAGS} emacstool
bootstrapclean:
diff --git a/src/alloc.c b/src/alloc.c
index 067dd7b753e..9116508bf6a 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -1341,7 +1341,7 @@ allocate_string ()
#ifdef GC_CHECK_STRING_BYTES
if (!noninteractive
-#ifdef macintosh
+#ifdef MAC_OS8
&& current_sblock
#endif
)
diff --git a/src/callproc.c b/src/callproc.c
index 92e6e479eaf..77d8b40e921 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -154,14 +154,14 @@ Lisp_Object
call_process_cleanup (fdpid)
Lisp_Object fdpid;
{
-#if defined (MSDOS) || defined (macintosh)
+#if defined (MSDOS) || defined (MAC_OS8)
/* for MSDOS fdpid is really (fd . tempfile) */
register Lisp_Object file;
file = Fcdr (fdpid);
emacs_close (XFASTINT (Fcar (fdpid)));
if (strcmp (XSTRING (file)-> data, NULL_DEVICE) != 0)
unlink (XSTRING (file)->data);
-#else /* not MSDOS and not macintosh */
+#else /* not MSDOS and not MAC_OS8 */
register int pid = XFASTINT (Fcdr (fdpid));
if (call_process_exited)
@@ -232,7 +232,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
char *outf, *tempfile;
int outfilefd;
#endif
-#ifdef macintosh
+#ifdef MAC_OS8
char *tempfile;
int outfilefd;
#endif
@@ -440,7 +440,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
fd[1] = outfilefd;
#endif /* MSDOS */
-#ifdef macintosh
+#ifdef MAC_OS8
/* Since we don't have pipes on the Mac, create a temporary file to
hold the output of the subprocess. */
tempfile = (char *) alloca (STRING_BYTES (XSTRING (Vtemp_file_name_pattern)) + 1);
@@ -458,14 +458,14 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
}
fd[0] = filefd;
fd[1] = outfilefd;
-#endif /* macintosh */
+#endif /* MAC_OS8 */
if (INTEGERP (buffer))
fd[1] = emacs_open (NULL_DEVICE, O_WRONLY, 0), fd[0] = -1;
else
{
#ifndef MSDOS
-#ifndef macintosh
+#ifndef MAC_OS8
errno = 0;
if (pipe (fd) == -1)
{
@@ -531,7 +531,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
current_dir = ENCODE_FILE (current_dir);
-#ifdef macintosh
+#ifdef MAC_OS8
{
/* Call run_mac_command in sysdep.c here directly instead of doing
a child_setup as for MSDOS and other platforms. Note that this
@@ -576,7 +576,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
report_file_error ("Cannot re-open temporary file", Qnil);
}
}
-#else /* not macintosh */
+#else /* not MAC_OS8 */
#ifdef MSDOS /* MW, July 1993 */
/* Note that on MSDOS `child_setup' actually returns the child process
exit status, not its PID, so we assign it to `synch_process_retcode'
@@ -635,7 +635,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
if (fd_error >= 0)
emacs_close (fd_error);
#endif /* not MSDOS */
-#endif /* not macintosh */
+#endif /* not MAC_OS8 */
environ = save_environ;
@@ -669,14 +669,14 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
/* Enable sending signal if user quits below. */
call_process_exited = 0;
-#if defined(MSDOS) || defined(macintosh)
+#if defined(MSDOS) || defined(MAC_OS8)
/* MSDOS needs different cleanup information. */
record_unwind_protect (call_process_cleanup,
Fcons (make_number (fd[0]), build_string (tempfile)));
#else
record_unwind_protect (call_process_cleanup,
Fcons (make_number (fd[0]), make_number (pid)));
-#endif /* not MSDOS and not macintosh */
+#endif /* not MSDOS and not MAC_OS8 */
if (BUFFERP (buffer))
diff --git a/src/config.in b/src/config.in
index fe68725897c..e54ecc659a1 100644
--- a/src/config.in
+++ b/src/config.in
@@ -717,6 +717,18 @@ Boston, MA 02111-1307, USA. */
/* Define as `fork' if `vfork' does not work. */
#undef vfork
+/* Define if we should use the Carbon API on Mac OS X. */
+#undef HAVE_CARBON
+
+#ifdef HAVE_CARBON
+#define HAVE_WINDOW_SYSTEM
+#define HAVE_MOUSE
+#define HAVE_MENUS
+#endif
+
+/* Define if we have the session management (SM) library. */
+#undef HAVE_X_SM
+
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
#undef volatile
diff --git a/src/dispextern.h b/src/dispextern.h
index 135eaec0ac8..b4442d4426d 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -39,7 +39,7 @@ Boston, MA 02111-1307, USA. */
#include "w32gui.h"
#endif
-#ifdef macintosh
+#ifdef MAC_OS
#include "macgui.h"
#endif
diff --git a/src/dispnew.c b/src/dispnew.c
index f19f111a728..35c1b87a886 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -60,9 +60,9 @@ Boston, MA 02111-1307, USA. */
#include "w32term.h"
#endif /* HAVE_NTGUI */
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
-#endif /* macintosh */
+#endif /* MAC_OS */
/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
@@ -6469,7 +6469,7 @@ init_display ()
}
#endif /* HAVE_NTGUI */
-#ifdef macintosh
+#ifdef MAC_OS
if (!inhibit_window_system)
{
Vwindow_system = intern ("mac");
@@ -6477,7 +6477,7 @@ init_display ()
adjust_frame_glyphs_initially ();
return;
}
-#endif /* macintosh */
+#endif /* MAC_OS */
/* If no window system has been specified, try to use the terminal. */
if (! isatty (0))
diff --git a/src/editfns.c b/src/editfns.c
index bfc982b9dbe..86129c63698 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -33,6 +33,12 @@ Boston, MA 02111-1307, USA. */
#include <unistd.h>
#endif
+/* Without this, sprintf on Mac OS Classic will produce wrong
+ result. */
+#ifdef MAC_OS8
+#include <stdio.h>
+#endif
+
#include <ctype.h>
#include "lisp.h"
diff --git a/src/emacs.c b/src/emacs.c
index fdd53555309..d0bd50222a0 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -793,6 +793,11 @@ main (argc, argv, envp)
run_time_remap (argv[0]);
#endif
+#ifdef MAC_OSX
+ if (!initialized)
+ unexec_init_emacs_zone ();
+#endif
+
sort_args (argc, argv);
argc = 0;
while (argv[argc]) argc++;
@@ -848,6 +853,13 @@ main (argc, argv, envp)
}
#endif /* NeXT */
+#ifdef MAC_OSX
+ /* Skip process serial number passed in the form -psn_x_y as
+ command-line argument. */
+ if (argc > skip_args + 1 && strncmp (argv[skip_args+1], "-psn_", 5) == 0)
+ skip_args++;
+#endif /* MAC_OSX */
+
#ifdef VMS
/* If -map specified, map the data file in. */
{
@@ -1175,12 +1187,12 @@ main (argc, argv, envp)
CANNOT_DUMP is defined. */
syms_of_keyboard ();
-#ifdef macintosh
+#ifdef MAC_OS8
/* init_window_once calls make_terminal_frame which on Mac OS
creates a full-fledge output_mac type frame. This does not
work correctly before syms_of_textprop, syms_of_macfns,
syms_of_ccl, syms_of_fontset, syms_of_xterm, syms_of_search,
- syms_of_frame, x_term_init, and init_keyboard have already
+ syms_of_frame, mac_initialize, and init_keyboard have already
been called. */
syms_of_textprop ();
syms_of_macfns ();
@@ -1192,7 +1204,7 @@ main (argc, argv, envp)
syms_of_search ();
syms_of_frame ();
- x_term_init ();
+ mac_initialize ();
init_keyboard ();
#endif
@@ -1388,8 +1400,8 @@ main (argc, argv, envp)
/* The basic levels of Lisp must come first. */
/* And data must come first of all
for the sake of symbols like error-message. */
-#ifndef macintosh
- /* Called before init_window_once for Mac OS. */
+#ifndef MAC_OS8
+ /* Called before init_window_once for Mac OS Classic. */
syms_of_data ();
#endif
syms_of_alloc ();
@@ -1407,8 +1419,8 @@ main (argc, argv, envp)
syms_of_casetab ();
syms_of_callproc ();
syms_of_category ();
-#ifndef macintosh
- /* Called before init_window_once for Mac OS. */
+#ifndef MAC_OS8
+ /* Called before init_window_once for Mac OS Classic. */
syms_of_ccl ();
#endif
syms_of_charset ();
@@ -1432,8 +1444,8 @@ main (argc, argv, envp)
syms_of_marker ();
syms_of_minibuf ();
syms_of_process ();
-#ifndef macintosh
- /* Called before init_window_once for Mac OS. */
+#ifndef MAC_OS8
+ /* Called before init_window_once for Mac OS Classic. */
syms_of_search ();
syms_of_frame ();
#endif
@@ -1443,8 +1455,8 @@ main (argc, argv, envp)
#ifdef HAVE_SOUND
syms_of_sound ();
#endif
-#ifndef macintosh
- /* Called before init_window_once for Mac OS. */
+#ifndef MAC_OS8
+ /* Called before init_window_once for Mac OS Classic. */
syms_of_textprop ();
#endif
syms_of_composite ();
@@ -1469,7 +1481,8 @@ main (argc, argv, envp)
#endif /* HAVE_X_WINDOWS */
#ifndef HAVE_NTGUI
-#ifndef macintosh
+#ifndef MAC_OS
+ /* Called before init_window_once for Mac OS Classic. */
syms_of_xmenu ();
#endif
#endif
@@ -1482,6 +1495,13 @@ main (argc, argv, envp)
syms_of_fontset ();
#endif /* HAVE_NTGUI */
+#ifdef HAVE_CARBON
+ syms_of_macterm ();
+ syms_of_macfns ();
+ syms_of_macmenu ();
+ syms_of_fontset ();
+#endif /* HAVE_CARBON */
+
#ifdef SYMS_SYSTEM
SYMS_SYSTEM;
#endif
@@ -1506,8 +1526,8 @@ main (argc, argv, envp)
#endif /* VMS */
init_display (); /* Determine terminal type. init_sys_modes uses results. */
}
-#ifndef macintosh
- /* Called before init_window_once for Mac OS. */
+#ifndef MAC_OS8
+ /* Called before init_window_once for Mac OS Classic. */
init_keyboard (); /* This too must precede init_sys_modes. */
#endif
#ifdef VMS
diff --git a/src/fontset.c b/src/fontset.c
index 30bec52f024..6679b1f728f 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -1410,10 +1410,10 @@ syms_of_fontset ()
FONTSET_ID (Vdefault_fontset) = make_number (0);
FONTSET_NAME (Vdefault_fontset)
= build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default");
-#if defined (macintosh)
+#if defined (MAC_OS)
FONTSET_ASCII (Vdefault_fontset)
= Fcons (make_number (0),
- build_string ("-apple-monaco-medium-r-*--*-120-*-*-*-*-mac-roman"));
+ build_string ("-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1"));
#elif defined (WINDOWSNT)
FONTSET_ASCII (Vdefault_fontset)
= Fcons (make_number (0),
diff --git a/src/frame.c b/src/frame.c
index 5525e2a9964..795183b2a2f 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -30,7 +30,7 @@ Boston, MA 02111-1307, USA. */
#ifdef WINDOWSNT
#include "w32term.h"
#endif
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
#endif
#include "buffer.h"
@@ -486,11 +486,11 @@ make_terminal_frame ()
f->output_method = output_termcap;
f->output_data.x = &tty_display;
#else
-#ifdef macintosh
+#ifdef MAC_OS8
make_mac_terminal_frame (f);
#else
f->output_data.x = &tty_display;
-#endif /* macintosh */
+#endif /* MAC_OS8 */
#endif /* WINDOWSNT */
#endif /* MSDOS */
@@ -521,7 +521,7 @@ Note that changing the size of one terminal frame automatically affects all. */
abort ();
#else /* not MSDOS */
-#ifdef macintosh
+#ifdef MAC_OS
if (sf->output_method != output_mac)
error ("Not running on a Macintosh screen; cannot make a new Macintosh frame");
#else
@@ -1112,7 +1112,7 @@ frame. The hook is called with one argument FRAME. */)
return Qnil;
if (NILP (force) && !other_visible_frames (f)
-#ifdef macintosh
+#ifdef MAC_OS8
/* Terminal frame deleted before any other visible frames are
created. */
&& strcmp (XSTRING (f->name)->data, "F1") != 0
diff --git a/src/frame.h b/src/frame.h
index bcfb208a9a6..9f6f6474e9c 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -57,7 +57,7 @@ enum vertical_scroll_bar_type
vertical_scroll_bar_right
};
-#if !defined(MSDOS) && !defined(WINDOWSNT) && !defined(macintosh)
+#if !defined(MSDOS) && !defined(WINDOWSNT) && !defined(MAC_OS)
#if !defined(HAVE_X_WINDOWS)
@@ -82,7 +82,7 @@ struct x_output
/* A structure describing a termcap frame display. */
extern struct x_output tty_display;
-#endif /* ! MSDOS && ! WINDOWSNT && ! macintosh */
+#endif /* ! MSDOS && ! WINDOWSNT && ! MAC_OS */
struct frame
{
@@ -260,7 +260,7 @@ struct frame
/* Number of lines of menu bar. */
int menu_bar_lines;
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
/* Nonzero means using a menu bar that comes from the X toolkit. */
int external_menu_bar;
#endif
@@ -404,7 +404,7 @@ typedef struct frame *FRAME_PTR;
#ifdef HAVE_NTGUI
#define FRAME_WINDOW_P(f) FRAME_W32_P (f)
#endif
-#ifdef macintosh
+#ifdef MAC_OS
#define FRAME_WINDOW_P(f) FRAME_MAC_P (f)
#endif
#ifndef FRAME_WINDOW_P
@@ -444,7 +444,7 @@ typedef struct frame *FRAME_PTR;
/* Nonzero if this frame should display a menu bar
in a way that does not use any text lines. */
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
#define FRAME_EXTERNAL_MENU_BAR(f) (f)->external_menu_bar
#else
#define FRAME_EXTERNAL_MENU_BAR(f) 0
diff --git a/src/keyboard.c b/src/keyboard.c
index cd3aa3793fb..d1c3681fdbc 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -71,7 +71,7 @@ Boston, MA 02111-1307, USA. */
#include "w32term.h"
#endif /* HAVE_NTGUI */
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
#endif
@@ -94,8 +94,8 @@ extern int input_fd;
#ifdef HAVE_WINDOW_SYSTEM
/* Make all keyboard buffers much bigger when using X windows. */
-#ifdef macintosh
-/* But not too big (local data > 32K error) if on macintosh. */
+#ifdef MAC_OS8
+/* But not too big (local data > 32K error) if on Mac OS Classic. */
#define KBD_BUFFER_SIZE 512
#else
#define KBD_BUFFER_SIZE 4096
@@ -3687,7 +3687,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
abort ();
#endif
}
-#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
else if (event->kind == delete_window_event)
{
/* Make an event (delete-frame (FRAME)). */
@@ -3718,7 +3718,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
XSETBUFFER (obj, current_buffer);
kbd_fetch_ptr = event + 1;
}
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
else if (event->kind == menu_bar_activate_event)
{
kbd_fetch_ptr = event + 1;
@@ -5373,7 +5373,7 @@ make_lispy_event (event)
}
#endif /* HAVE_MOUSE */
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
case MENU_BAR_EVENT:
if (EQ (event->arg, event->frame_or_window))
/* This is the prefix key. We translate this to
diff --git a/src/m/powermac.h b/src/m/powermac.h
new file mode 100644
index 00000000000..0f54d18c839
--- /dev/null
+++ b/src/m/powermac.h
@@ -0,0 +1,121 @@
+/* Machine description file for Apple Power Macintosh
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* The following line tells the configuration script what sort of
+ operating system this machine is likely to run.
+ USUAL-OPSYS="darwin" */
+
+/* Define WORDS_BIG_ENDIAN iff lowest-numbered byte in a word
+ is the most significant byte. */
+
+#define WORDS_BIG_ENDIAN
+
+/* Define NO_ARG_ARRAY if you cannot take the address of the first of a
+ * group of arguments and treat it as an array of the arguments. */
+
+#define NO_ARG_ARRAY
+
+/* Define WORD_MACHINE if addresses and such have
+ * to be corrected before they can be used as byte counts. */
+
+/* #define WORD_MACHINE */
+
+/* Now define a symbol for the cpu type, if your compiler
+ does not define it automatically:
+ Ones defined so far include vax, m68000, ns16000, pyramid,
+ orion, tahoe, APOLLO and many others */
+
+/* Use type int rather than a union, to represent Lisp_Object */
+/* This is desirable for most machines. */
+
+#define NO_UNION_TYPE
+
+/* Define EXPLICIT_SIGN_EXTEND if XINT must explicitly sign-extend
+ the 24-bit bit field into an int. In other words, if bit fields
+ are always unsigned.
+
+ If you use NO_UNION_TYPE, this flag does not matter. */
+
+/* #define EXPLICIT_SIGN_EXTEND */
+
+/* Data type of load average, as read out of kmem. */
+
+#define LOAD_AVE_TYPE long
+
+/* Convert that into an integer that is 100 for a load average of 1.0 */
+
+#define LOAD_AVE_CVT(x) (int) (((double) (x)) * 100.0 / FSCALE)
+
+/* Define CANNOT_DUMP on machines where unexec does not work.
+ Then the function dump-emacs will not be defined
+ and temacs will do (load "loadup") automatically unless told otherwise. */
+
+/* #define CANNOT_DUMP */
+
+/* Define VIRT_ADDR_VARIES if the virtual addresses of
+ pure and impure space as loaded can vary, and even their
+ relative order cannot be relied on.
+
+ Otherwise Emacs assumes that text space precedes data space,
+ numerically. */
+
+/* #define VIRT_ADDR_VARIES * */
+
+/* Define C_ALLOCA if this machine does not support a true alloca
+ and the one written in C should be used instead.
+ Define HAVE_ALLOCA to say that the system provides a properly
+ working alloca function and it should be used.
+ Define neither one if an assembler-language alloca
+ in the file alloca.s should be used. */
+
+/* #define C_ALLOCA */
+/* #define HAVE_ALLOCA */
+
+/* Define NO_REMAP if memory segmentation makes it not work well
+ to change the boundary between the text section and data section
+ when Emacs is dumped. If you define this, the preloaded Lisp
+ code will not be sharable; but that's better than failing completely. */
+
+#define NO_REMAP
+
+/* Some really obscure 4.2-based systems (like Sequent DYNIX)
+ * do not support asynchronous I/O (using SIGIO) on sockets,
+ * even though it works fine on tty's. If you have one of
+ * these systems, define the following, and then use it in
+ * config.h (or elsewhere) to decide when (not) to use SIGIO.
+ *
+ * You'd think this would go in an operating-system description file,
+ * but since it only occurs on some, but not all, BSD systems, the
+ * reasonable place to select for it is in the machine description
+ * file.
+ */
+
+/* #define NO_SOCK_SIGIO */
+
+
+/* After adding support for a new system, modify the large case
+ statement in the `configure' script to recognize reasonable
+ configuration names, and add a description of the system to
+ `etc/MACHINES'.
+
+ If you've just fixed a problem in an existing configuration file,
+ you should also check `etc/MACHINES' to make sure its descriptions
+ of known problems in that configuration should be updated. */
diff --git a/src/mac.c b/src/mac.c
new file mode 100644
index 00000000000..4e6ee4bb8ff
--- /dev/null
+++ b/src/mac.c
@@ -0,0 +1,2758 @@
+/* Unix emulation routines for GNU Emacs on the Mac OS.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <utime.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/param.h>
+#if __MWERKS__
+#include <unistd.h>
+#endif
+
+#ifdef MAC_OSX
+#undef mktime
+#undef DEBUG
+#undef free
+#undef malloc
+#undef realloc
+#include <Carbon/Carbon.h>
+#undef free
+#define free unexec_free
+#undef malloc
+#define malloc unexec_malloc
+#undef realloc
+#define realloc unexec_realloc
+#else /* not MAC_OSX */
+#include <Files.h>
+#include <MacTypes.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Resources.h>
+#include <Aliases.h>
+#include <FixMath.h>
+#include <Timer.h>
+#include <OSA.h>
+#include <AppleScript.h>
+#include <Scrap.h>
+#endif /* not MAC_OSX */
+
+#include "lisp.h"
+#include "process.h"
+#include "sysselect.h"
+#include "systime.h"
+
+Lisp_Object QCLIPBOARD;
+
+/* An instance of the AppleScript component. */
+static ComponentInstance as_scripting_component;
+/* The single script context used for all script executions. */
+static OSAID as_script_context;
+
+
+/* When converting from Mac to Unix pathnames, /'s in folder names are
+ converted to :'s. This function, used in copying folder names,
+ performs a strncat and converts all character a to b in the copy of
+ the string s2 appended to the end of s1. */
+
+void
+string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
+{
+ int l1 = strlen (s1);
+ int l2 = strlen (s2);
+ char *p = s1 + l1;
+ int i;
+
+ strncat (s1, s2, n);
+ for (i = 0; i < l2; i++)
+ {
+ if (*p == a)
+ *p = b;
+ p++;
+ }
+}
+
+
+/* Convert a Mac pathname to Posix form. A Mac full pathname is one
+ that does not begin with a ':' and contains at least one ':'. A Mac
+ full pathname causes an '/' to be prepended to the Posix pathname.
+ The algorithm for the rest of the pathname is as follows:
+ For each segment between two ':',
+ if it is non-null, copy as is and then add a '/' at the end,
+ otherwise, insert a "../" into the Posix pathname.
+ Returns 1 if successful; 0 if fails. */
+
+int
+mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
+{
+ const char *p, *q, *pe;
+
+ strcpy (ufn, "");
+
+ if (*mfn == '\0')
+ return 1;
+
+ p = strchr (mfn, ':');
+ if (p != 0 && p != mfn) /* full pathname */
+ strcat (ufn, "/");
+
+ p = mfn;
+ if (*p == ':')
+ p++;
+
+ pe = mfn + strlen (mfn);
+ while (p < pe)
+ {
+ q = strchr (p, ':');
+ if (q)
+ {
+ if (q == p)
+ { /* two consecutive ':' */
+ if (strlen (ufn) + 3 >= ufnbuflen)
+ return 0;
+ strcat (ufn, "../");
+ }
+ else
+ {
+ if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
+ return 0;
+ string_cat_and_replace (ufn, p, q - p, '/', ':');
+ strcat (ufn, "/");
+ }
+ p = q + 1;
+ }
+ else
+ {
+ if (strlen (ufn) + (pe - p) >= ufnbuflen)
+ return 0;
+ string_cat_and_replace (ufn, p, pe - p, '/', ':');
+ /* no separator for last one */
+ p = pe;
+ }
+ }
+
+ return 1;
+}
+
+
+extern char *get_temp_dir_name ();
+
+
+/* Convert a Posix pathname to Mac form. Approximately reverse of the
+ above in algorithm. */
+
+int
+posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
+{
+ const char *p, *q, *pe;
+ char expanded_pathname[MAXPATHLEN+1];
+
+ strcpy (mfn, "");
+
+ if (*ufn == '\0')
+ return 1;
+
+ p = ufn;
+
+ /* Check for and handle volume names. Last comparison: strangely
+ somewhere "/.emacs" is passed. A temporary fix for now. */
+ if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
+ {
+ if (strlen (p) + 1 > mfnbuflen)
+ return 0;
+ strcpy (mfn, p+1);
+ strcat (mfn, ":");
+ return 1;
+ }
+
+ /* expand to emacs dir found by init_emacs_passwd_dir */
+ if (strncmp (p, "~emacs/", 7) == 0)
+ {
+ struct passwd *pw = getpwnam ("emacs");
+ p += 7;
+ if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
+ return 0;
+ strcpy (expanded_pathname, pw->pw_dir);
+ strcat (expanded_pathname, p);
+ p = expanded_pathname;
+ /* now p points to the pathname with emacs dir prefix */
+ }
+ else if (strncmp (p, "/tmp/", 5) == 0)
+ {
+ char *t = get_temp_dir_name ();
+ p += 5;
+ if (strlen (t) + strlen (p) > MAXPATHLEN)
+ return 0;
+ strcpy (expanded_pathname, t);
+ strcat (expanded_pathname, p);
+ p = expanded_pathname;
+ /* now p points to the pathname with emacs dir prefix */
+ }
+ else if (*p != '/') /* relative pathname */
+ strcat (mfn, ":");
+
+ if (*p == '/')
+ p++;
+
+ pe = p + strlen (p);
+ while (p < pe)
+ {
+ q = strchr (p, '/');
+ if (q)
+ {
+ if (q - p == 2 && *p == '.' && *(p+1) == '.')
+ {
+ if (strlen (mfn) + 1 >= mfnbuflen)
+ return 0;
+ strcat (mfn, ":");
+ }
+ else
+ {
+ if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
+ return 0;
+ string_cat_and_replace (mfn, p, q - p, ':', '/');
+ strcat (mfn, ":");
+ }
+ p = q + 1;
+ }
+ else
+ {
+ if (strlen (mfn) + (pe - p) >= mfnbuflen)
+ return 0;
+ string_cat_and_replace (mfn, p, pe - p, ':', '/');
+ p = pe;
+ }
+ }
+
+ return 1;
+}
+
+#ifndef MAC_OSX
+
+/* The following functions with "sys_" prefix are stubs to Unix
+ functions that have already been implemented by CW or MPW. The
+ calls to them in Emacs source course are #define'd to call the sys_
+ versions by the header files s-mac.h. In these stubs pathnames are
+ converted between their Unix and Mac forms. */
+
+
+/* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
+ + 17 leap days. These are for adjusting time values returned by
+ MacOS Toolbox functions. */
+
+#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
+
+#ifdef __MWERKS__
+#if __MSL__ < 0x6000
+/* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
+ a leap year! This is for adjusting time_t values returned by MSL
+ functions. */
+#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
+#else /* __MSL__ >= 0x6000 */
+/* CW changes Pro 6 to follow Unix! */
+#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
+#endif /* __MSL__ >= 0x6000 */
+#elif __MRC__
+/* MPW library functions follow Unix (confused?). */
+#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
+#else /* not __MRC__ */
+You lose!!!
+#endif /* not __MRC__ */
+
+
+/* Define our own stat function for both MrC and CW. The reason for
+ doing this: "stat" is both the name of a struct and function name:
+ can't use the same trick like that for sys_open, sys_close, etc. to
+ redirect Emacs's calls to our own version that converts Unix style
+ filenames to Mac style filename because all sorts of compilation
+ errors will be generated if stat is #define'd to be sys_stat. */
+
+int
+stat_noalias (const char *path, struct stat *buf)
+{
+ char mac_pathname[MAXPATHLEN+1];
+ CInfoPBRec cipb;
+
+ if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno == -43) /* -43: fnfErr defined in Errors.h */
+ errno = ENOENT;
+ if (errno != noErr)
+ return -1;
+
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
+ {
+ buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
+
+ if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
+ buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
+ buf->st_ino = cipb.dirInfo.ioDrDirID;
+ buf->st_dev = cipb.dirInfo.ioVRefNum;
+ buf->st_size = cipb.dirInfo.ioDrNmFls;
+ /* size of dir = number of files and dirs */
+ buf->st_atime
+ = buf->st_mtime
+ = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
+ buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
+ }
+ else
+ {
+ buf->st_mode = S_IFREG | S_IREAD;
+ if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
+ buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
+ if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
+ buf->st_mode |= S_IEXEC;
+ buf->st_ino = cipb.hFileInfo.ioDirID;
+ buf->st_dev = cipb.hFileInfo.ioVRefNum;
+ buf->st_size = cipb.hFileInfo.ioFlLgLen;
+ buf->st_atime
+ = buf->st_mtime
+ = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
+ buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
+ }
+
+ if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
+ {
+ /* identify alias files as symlinks */
+ buf->st_mode &= ~S_IFREG;
+ buf->st_mode |= S_IFLNK;
+ }
+
+ buf->st_nlink = 1;
+ buf->st_uid = getuid ();
+ buf->st_gid = getgid ();
+ buf->st_rdev = 0;
+
+ return 0;
+}
+
+
+int
+lstat (const char *path, struct stat *buf)
+{
+ int result;
+ char true_pathname[MAXPATHLEN+1];
+
+ /* Try looking for the file without resolving aliases first. */
+ if ((result = stat_noalias (path, buf)) >= 0)
+ return result;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ return stat_noalias (true_pathname, buf);
+}
+
+
+int
+stat (const char *path, struct stat *sb)
+{
+ int result;
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+
+ if ((result = stat_noalias (path, sb)) >= 0 &&
+ ! (sb->st_mode & S_IFLNK))
+ return result;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ {
+ fully_resolved_name[len] = '\0';
+ /* in fact our readlink terminates strings */
+ return lstat (fully_resolved_name, sb);
+ }
+ else
+ return lstat (true_pathname, sb);
+}
+
+
+#if __MRC__
+/* CW defines fstat in stat.mac.c while MPW does not provide this
+ function. Without the information of how to get from a file
+ descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
+ to implement this function. Fortunately, there is only one place
+ where this function is called in our configuration: in fileio.c,
+ where only the st_dev and st_ino fields are used to determine
+ whether two fildes point to different i-nodes to prevent copying
+ a file onto itself equal. What we have here probably needs
+ improvement. */
+
+int
+fstat (int fildes, struct stat *buf)
+{
+ buf->st_dev = 0;
+ buf->st_ino = fildes;
+ buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
+ return 0; /* success */
+}
+#endif /* __MRC__ */
+
+
+int
+mkdir (const char *dirname, int mode)
+{
+#pragma unused(mode)
+
+ HFileParam hfpb;
+ char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_pathname);
+ hfpb.ioNamePtr = mac_pathname;
+ hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
+ hfpb.ioDirID = 0; /* parent is the root */
+
+ errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
+ /* just return the Mac OSErr code for now */
+ return errno == noErr ? 0 : -1;
+}
+
+
+#undef rmdir
+sys_rmdir (const char *dirname)
+{
+ HFileParam hfpb;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_pathname);
+ hfpb.ioNamePtr = mac_pathname;
+ hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
+ hfpb.ioDirID = 0; /* parent is the root */
+
+ errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
+ return errno == noErr ? 0 : -1;
+}
+
+
+#ifdef __MRC__
+/* No implementation yet. */
+int
+execvp (const char *path, ...)
+{
+ return -1;
+}
+#endif /* __MRC__ */
+
+
+int
+utime (const char *path, const struct utimbuf *times)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+ CInfoPBRec cipb;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ return -1;
+
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
+ {
+ if (times)
+ cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
+ else
+ GetDateTime (&cipb.dirInfo.ioDrMdDat);
+ }
+ else
+ {
+ if (times)
+ cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
+ else
+ GetDateTime (&cipb.hFileInfo.ioFlMdDat);
+ }
+
+ errno = PBSetCatInfo (&cipb, false);
+ return errno == noErr ? 0 : -1;
+}
+
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef X_OK
+#define X_OK 1
+#endif
+#ifndef W_OK
+#define W_OK 2
+#endif
+
+/* Like stat, but test for access mode in hfpb.ioFlAttrib */
+int
+access (const char *path, int mode)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+ CInfoPBRec cipb;
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ return -1;
+
+ if (mode == F_OK) /* got this far, file exists */
+ return 0;
+
+ if (mode & X_OK)
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
+ return 0;
+ else
+ {
+ if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
+ return 0;
+ else
+ return -1;
+ }
+
+ if (mode & W_OK)
+ return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
+ /* don't allow if lock bit is on */
+
+ return -1;
+}
+
+
+#define DEV_NULL_FD 0x10000
+
+#undef open
+int
+sys_open (const char *path, int oflag)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (strcmp (path, "/dev/null") == 0)
+ return DEV_NULL_FD; /* some bogus fd to be ignored in write */
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+ else
+ {
+#ifdef __MRC__
+ int res = open (mac_pathname, oflag);
+ /* if (oflag == O_WRONLY || oflag == O_RDWR) */
+ if (oflag & O_CREAT)
+ fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ return res;
+#else /* not __MRC__ */
+ return open (mac_pathname, oflag);
+#endif /* not __MRC__ */
+ }
+}
+
+
+#undef creat
+int
+sys_creat (const char *path, mode_t mode)
+{
+ char true_pathname[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
+ return -1;
+ else
+ {
+#ifdef __MRC__
+ int result = creat (mac_pathname);
+ fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ return result;
+#else /* not __MRC__ */
+ return creat (mac_pathname, mode);
+#endif /* not __MRC__ */
+ }
+}
+
+
+#undef unlink
+int
+sys_unlink (const char *path)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return -1;
+ else
+ return unlink (mac_pathname);
+}
+
+
+#undef read
+int
+sys_read (int fildes, char *buf, int count)
+{
+ if (fildes == 0) /* this should not be used for console input */
+ return -1;
+ else
+#if __MSL__ >= 0x6000
+ return _read (fildes, buf, count);
+#else
+ return read (fildes, buf, count);
+#endif
+}
+
+
+#undef write
+int
+sys_write (int fildes, const char *buf, int count)
+{
+ if (fildes == DEV_NULL_FD)
+ return count;
+ else
+#if __MSL__ >= 0x6000
+ return _write (fildes, buf, count);
+#else
+ return write (fildes, buf, count);
+#endif
+}
+
+
+#undef rename
+int
+sys_rename (const char * old_name, const char * new_name)
+{
+ char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
+ char fully_resolved_old_name[MAXPATHLEN+1];
+ int len;
+ char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
+
+ if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_old_name[len] = '\0';
+ else
+ strcpy (fully_resolved_old_name, true_old_pathname);
+
+ if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
+ return -1;
+
+ if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
+ return 0;
+
+ if (!posix_to_mac_pathname (fully_resolved_old_name,
+ mac_old_name,
+ MAXPATHLEN+1))
+ return -1;
+
+ if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
+ return -1;
+
+ /* If a file with new_name already exists, rename deletes the old
+ file in Unix. CW version fails in these situation. So we add a
+ call to unlink here. */
+ (void) unlink (mac_new_name);
+
+ return rename (mac_old_name, mac_new_name);
+}
+
+
+#undef fopen
+extern FILE *fopen (const char *name, const char *mode);
+FILE *
+sys_fopen (const char *name, const char *mode)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ int len;
+ char mac_pathname[MAXPATHLEN+1];
+
+ if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
+ return 0;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return 0;
+ else
+ {
+#ifdef __MRC__
+ if (mode[0] == 'w' || mode[0] == 'a')
+ fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+#endif /* not __MRC__ */
+ return fopen (mac_pathname, mode);
+ }
+}
+
+
+#include <Events.h>
+
+long target_ticks = 0;
+
+#ifdef __MRC__
+__sigfun alarm_signal_func = (__sigfun) 0;
+#elif __MWERKS__
+__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
+#else /* not __MRC__ and not __MWERKS__ */
+You lose!!!
+#endif /* not __MRC__ and not __MWERKS__ */
+
+
+/* These functions simulate SIG_ALRM. The stub for function signal
+ stores the signal handler function in alarm_signal_func if a
+ SIG_ALRM is encountered. check_alarm is called in XTread_socket,
+ which emacs calls periodically. A pending alarm is represented by
+ a non-zero target_ticks value. check_alarm calls the handler
+ function pointed to by alarm_signal_func if one has been set up and
+ an alarm is pending. */
+
+void
+check_alarm ()
+{
+ if (target_ticks && TickCount () > target_ticks)
+ {
+ target_ticks = 0;
+ if (alarm_signal_func)
+ (*alarm_signal_func)(SIGALRM);
+ }
+}
+
+
+int
+select (n, rfds, wfds, efds, timeout)
+ int n;
+ SELECT_TYPE *rfds;
+ SELECT_TYPE *wfds;
+ SELECT_TYPE *efds;
+ struct timeval *timeout;
+{
+#ifdef TARGET_API_MAC_CARBON
+ return 1;
+#else /* not TARGET_API_MAC_CARBON */
+ EMACS_TIME end_time, now;
+ EventRecord e;
+
+ /* Can only handle wait for keyboard input. */
+ if (n > 1 || wfds || efds)
+ return -1;
+
+ EMACS_GET_TIME (end_time);
+ EMACS_ADD_TIME (end_time, end_time, *timeout);
+
+ do
+ {
+ /* Also return true if an event other than a keyDown has
+ occurred. This causes kbd_buffer_get_event in keyboard.c to
+ call read_avail_input which in turn calls XTread_socket to
+ poll for these events. Otherwise these never get processed
+ except but a very slow poll timer. */
+ if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
+ return 1;
+
+ /* Also check movement of the mouse. */
+ {
+ Point mouse_pos;
+ static Point old_mouse_pos = {-1, -1};
+
+ GetMouse (&mouse_pos);
+ if (!EqualPt (mouse_pos, old_mouse_pos))
+ {
+ old_mouse_pos = mouse_pos;
+ return 1;
+ }
+ }
+
+ WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1
+ tic. by T.I. */
+
+ EMACS_GET_TIME (now);
+ EMACS_SUB_TIME (now, end_time, now);
+ }
+ while (!EMACS_TIME_NEG_P (now));
+
+ return 0;
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* Called in sys_select to wait for an alarm signal to arrive. */
+
+int
+pause ()
+{
+ EventRecord e;
+ unsigned long tick;
+
+ if (!target_ticks) /* no alarm pending */
+ return -1;
+
+ if ((tick = TickCount ()) < target_ticks)
+ WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event;
+ just wait. by T.I. */
+
+ target_ticks = 0;
+ if (alarm_signal_func)
+ (*alarm_signal_func)(SIGALRM);
+
+ return 0;
+}
+
+
+int
+alarm (int seconds)
+{
+ long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
+
+ target_ticks = seconds ? TickCount () + 60 * seconds : 0;
+
+ return (remaining < 0) ? 0 : (unsigned int) remaining;
+}
+
+
+#undef signal
+#ifdef __MRC__
+extern __sigfun signal (int signal, __sigfun signal_func);
+__sigfun
+sys_signal (int signal_num, __sigfun signal_func)
+#elif __MWERKS__
+extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
+__signal_func_ptr
+sys_signal (int signal_num, __signal_func_ptr signal_func)
+#else /* not __MRC__ and not __MWERKS__ */
+ You lose!!!
+#endif /* not __MRC__ and not __MWERKS__ */
+{
+ if (signal_num != SIGALRM)
+ return signal (signal_num, signal_func);
+ else
+ {
+#ifdef __MRC__
+ __sigfun old_signal_func;
+#elif __MWERKS__
+ __signal_func_ptr old_signal_func;
+#else
+ You lose!!!
+#endif
+ old_signal_func = alarm_signal_func;
+ alarm_signal_func = signal_func;
+ return old_signal_func;
+ }
+}
+
+
+/* gettimeofday should return the amount of time (in a timeval
+ structure) since midnight today. The toolbox function Microseconds
+ returns the number of microseconds (in a UnsignedWide value) since
+ the machine was booted. Also making this complicated is WideAdd,
+ WideSubtract, etc. take wide values. */
+
+int
+gettimeofday (tp)
+ struct timeval *tp;
+{
+ static inited = 0;
+ static wide wall_clock_at_epoch, clicks_at_epoch;
+ UnsignedWide uw_microseconds;
+ wide w_microseconds;
+ time_t sys_time (time_t *);
+
+ /* If this function is called for the first time, record the number
+ of seconds since midnight and the number of microseconds since
+ boot at the time of this first call. */
+ if (!inited)
+ {
+ time_t systime;
+ inited = 1;
+ systime = sys_time (NULL);
+ /* Store microseconds since midnight in wall_clock_at_epoch. */
+ WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
+ Microseconds (&uw_microseconds);
+ /* Store microseconds since boot in clicks_at_epoch. */
+ clicks_at_epoch.hi = uw_microseconds.hi;
+ clicks_at_epoch.lo = uw_microseconds.lo;
+ }
+
+ /* Get time since boot */
+ Microseconds (&uw_microseconds);
+
+ /* Convert to time since midnight*/
+ w_microseconds.hi = uw_microseconds.hi;
+ w_microseconds.lo = uw_microseconds.lo;
+ WideSubtract (&w_microseconds, &clicks_at_epoch);
+ WideAdd (&w_microseconds, &wall_clock_at_epoch);
+ tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
+
+ return 0;
+}
+
+
+#ifdef __MRC__
+unsigned int
+sleep (unsigned int seconds)
+{
+ unsigned long time_up;
+ EventRecord e;
+
+ time_up = TickCount () + seconds * 60;
+ while (TickCount () < time_up)
+ {
+ /* Accept no event; just wait. by T.I. */
+ WaitNextEvent (0, &e, 30, NULL);
+ }
+
+ return (0);
+}
+#endif /* __MRC__ */
+
+
+/* The time functions adjust time values according to the difference
+ between the Unix and CW epoches. */
+
+#undef gmtime
+extern struct tm *gmtime (const time_t *);
+struct tm *
+sys_gmtime (const time_t *timer)
+{
+ time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
+
+ return gmtime (&unix_time);
+}
+
+
+#undef localtime
+extern struct tm *localtime (const time_t *);
+struct tm *
+sys_localtime (const time_t *timer)
+{
+#if __MSL__ >= 0x6000
+ time_t unix_time = *timer;
+#else
+ time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
+#endif
+
+ return localtime (&unix_time);
+}
+
+
+#undef ctime
+extern char *ctime (const time_t *);
+char *
+sys_ctime (const time_t *timer)
+{
+#if __MSL__ >= 0x6000
+ time_t unix_time = *timer;
+#else
+ time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
+#endif
+
+ return ctime (&unix_time);
+}
+
+
+#undef time
+extern time_t time (time_t *);
+time_t
+sys_time (time_t *timer)
+{
+#if __MSL__ >= 0x6000
+ time_t mac_time = time (NULL);
+#else
+ time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
+#endif
+
+ if (timer)
+ *timer = mac_time;
+
+ return mac_time;
+}
+
+
+/* MPW strftime broken for "%p" format */
+#ifdef __MRC__
+#undef strftime
+#include <time.h>
+size_t
+sys_strftime (char * s, size_t maxsize, const char * format,
+ const struct tm * timeptr)
+{
+ if (strcmp (format, "%p") == 0)
+ {
+ if (maxsize < 3)
+ return 0;
+ if (timeptr->tm_hour < 12)
+ {
+ strcpy (s, "AM");
+ return 2;
+ }
+ else
+ {
+ strcpy (s, "PM");
+ return 2;
+ }
+ }
+ else
+ return strftime (s, maxsize, format, timeptr);
+}
+#endif /* __MRC__ */
+
+
+/* no subprocesses, empty wait */
+
+int
+wait (int pid)
+{
+ return 0;
+}
+
+
+void
+croak (char *badfunc)
+{
+ printf ("%s not yet implemented\r\n", badfunc);
+ exit (1);
+}
+
+
+char *
+index (const char * str, int chr)
+{
+ return strchr (str, chr);
+}
+
+
+char *
+mktemp (char *template)
+{
+ int len, k;
+ static seqnum = 0;
+
+ len = strlen (template);
+ k = len - 1;
+ while (k >= 0 && template[k] == 'X')
+ k--;
+
+ k++; /* make k index of first 'X' */
+
+ if (k < len)
+ {
+ /* Zero filled, number of digits equal to the number of X's. */
+ sprintf (&template[k], "%0*d", len-k, seqnum++);
+
+ return template;
+ }
+ else
+ return 0;
+}
+
+
+/* Emulate getpwuid, getpwnam and others. */
+
+#define PASSWD_FIELD_SIZE 256
+
+static char my_passwd_name[PASSWD_FIELD_SIZE];
+static char my_passwd_dir[MAXPATHLEN+1];
+
+static struct passwd my_passwd =
+{
+ my_passwd_name,
+ my_passwd_dir,
+};
+
+
+/* Initialized by main () in macterm.c to pathname of emacs directory. */
+
+char emacs_passwd_dir[MAXPATHLEN+1];
+
+char *
+getwd (char *);
+
+void
+init_emacs_passwd_dir ()
+{
+ int found = false;
+
+ if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
+ {
+ /* Need pathname of first ancestor that begins with "emacs"
+ since Mac emacs application is somewhere in the emacs-*
+ tree. */
+ int len = strlen (emacs_passwd_dir);
+ int j = len - 1;
+ /* j points to the "/" following the directory name being
+ compared. */
+ int i = j - 1;
+ while (i >= 0 && !found)
+ {
+ while (i >= 0 && emacs_passwd_dir[i] != '/')
+ i--;
+ if (emacs_passwd_dir[i] == '/' && i+5 < len)
+ found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
+ if (found)
+ emacs_passwd_dir[j+1] = '\0';
+ else
+ {
+ j = i;
+ i = j - 1;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ /* Setting to "/" probably won't work but set it to something
+ anyway. */
+ strcpy (emacs_passwd_dir, "/");
+ strcpy (my_passwd_dir, "/");
+ }
+}
+
+
+static struct passwd emacs_passwd =
+{
+ "emacs",
+ emacs_passwd_dir,
+};
+
+static int my_passwd_inited = 0;
+
+
+static void
+init_my_passwd ()
+{
+ char **owner_name;
+
+ /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
+ directory where Emacs was started. */
+
+ owner_name = (char **) GetResource ('STR ',-16096);
+ if (owner_name)
+ {
+ HLock (owner_name);
+ BlockMove ((unsigned char *) *owner_name,
+ (unsigned char *) my_passwd_name,
+ *owner_name[0]+1);
+ HUnlock (owner_name);
+ p2cstr ((unsigned char *) my_passwd_name);
+ }
+ else
+ my_passwd_name[0] = 0;
+}
+
+
+struct passwd *
+getpwuid (uid_t uid)
+{
+ if (!my_passwd_inited)
+ {
+ init_my_passwd ();
+ my_passwd_inited = 1;
+ }
+
+ return &my_passwd;
+}
+
+
+struct passwd *
+getpwnam (const char *name)
+{
+ if (strcmp (name, "emacs") == 0)
+ return &emacs_passwd;
+
+ if (!my_passwd_inited)
+ {
+ init_my_passwd ();
+ my_passwd_inited = 1;
+ }
+
+ return &my_passwd;
+}
+
+
+/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
+ setpgrp, setpriority, and unrequest_sigio are defined to be empty
+ as in msdos.c. */
+
+
+int
+fork ()
+{
+ return -1;
+}
+
+
+int
+kill (int x, int y)
+{
+ return -1;
+}
+
+
+void
+sys_subshell ()
+{
+ error ("Can't spawn subshell");
+}
+
+
+int
+sigsetmask (int x)
+{
+ return 0;
+}
+
+
+int
+sigblock (int mask)
+{
+ return 0;
+}
+
+
+void
+request_sigio (void)
+{
+}
+
+
+void
+unrequest_sigio (void)
+{
+}
+
+
+int
+setpgrp ()
+{
+ return 0;
+}
+
+
+/* No pipes yet. */
+
+int
+pipe (int _fildes[2])
+{
+ errno = EACCES;
+ return -1;
+}
+
+
+/* Hard and symbolic links. */
+
+int
+symlink (const char *name1, const char *name2)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+
+int
+link (const char *name1, const char *name2)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+#endif /* ! MAC_OSX */
+
+/* Determine the path name of the file specified by VREFNUM, DIRID,
+ and NAME and place that in the buffer PATH of length
+ MAXPATHLEN. */
+int
+path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
+ long dir_id, ConstStr255Param name)
+{
+ Str255 dir_name;
+ CInfoPBRec cipb;
+ OSErr err;
+
+ if (strlen (name) > man_path_len)
+ return 0;
+
+ memcpy (dir_name, name, name[0]+1);
+ memcpy (path, name, name[0]+1);
+ p2cstr (path);
+
+ cipb.dirInfo.ioDrParID = dir_id;
+ cipb.dirInfo.ioNamePtr = dir_name;
+
+ do
+ {
+ cipb.dirInfo.ioVRefNum = vol_ref_num;
+ cipb.dirInfo.ioFDirIndex = -1;
+ cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
+ /* go up to parent each time */
+
+ err = PBGetCatInfo (&cipb, false);
+ if (err != noErr)
+ return 0;
+
+ p2cstr (dir_name);
+ if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
+ return 0;
+
+ strcat (dir_name, ":");
+ strcat (dir_name, path);
+ /* attach to front since we're going up directory tree */
+ strcpy (path, dir_name);
+ }
+ while (cipb.dirInfo.ioDrDirID != fsRtDirID);
+ /* stop when we see the volume's root directory */
+
+ return 1; /* success */
+}
+
+#ifndef MAC_OSX
+
+int
+readlink (const char *path, char *buf, int bufsiz)
+{
+ char mac_sym_link_name[MAXPATHLEN+1];
+ OSErr err;
+ FSSpec fsspec;
+ Boolean target_is_folder, was_aliased;
+ Str255 directory_name, mac_pathname;
+ CInfoPBRec cipb;
+
+ if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
+ return -1;
+
+ c2pstr (mac_sym_link_name);
+ err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
+ if (err != noErr)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
+ if (err != noErr || !was_aliased)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
+ fsspec.name) == 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return strlen (buf);
+}
+
+
+/* Convert a path to one with aliases fully expanded. */
+
+static int
+find_true_pathname (const char *path, char *buf, int bufsiz)
+{
+ char *q, temp[MAXPATHLEN+1];
+ const char *p;
+ int len;
+
+ if (bufsiz <= 0 || path == 0 || path[0] == '\0')
+ return -1;
+
+ buf[0] = '\0';
+
+ p = path;
+ if (*p == '/')
+ q = strchr (p + 1, '/');
+ else
+ q = strchr (p, '/');
+ len = 0; /* loop may not be entered, e.g., for "/" */
+
+ while (q)
+ {
+ strcpy (temp, buf);
+ strncat (temp, p, q - p);
+ len = readlink (temp, buf, bufsiz);
+ if (len <= -1)
+ {
+ if (strlen (temp) + 1 > bufsiz)
+ return -1;
+ strcpy (buf, temp);
+ }
+ strcat (buf, "/");
+ len++;
+ p = q + 1;
+ q = strchr(p, '/');
+ }
+
+ if (len + strlen (p) + 1 >= bufsiz)
+ return -1;
+
+ strcat (buf, p);
+ return len + strlen (p);
+}
+
+
+mode_t
+umask (mode_t numask)
+{
+ static mode_t mask = 022;
+ mode_t oldmask = mask;
+ mask = numask;
+ return oldmask;
+}
+
+
+int
+chmod (const char *path, mode_t mode)
+{
+ /* say it always succeed for now */
+ return 0;
+}
+
+
+int
+dup (int oldd)
+{
+#ifdef __MRC__
+ return fcntl (oldd, F_DUPFD, 0);
+#elif __MWERKS__
+ /* current implementation of fcntl in fcntl.mac.c simply returns old
+ descriptor */
+ return fcntl (oldd, F_DUPFD);
+#else
+You lose!!!
+#endif
+}
+
+
+/* This is from the original sysdep.c. Emulate BSD dup2. First close
+ newd if it already exists. Then, attempt to dup oldd. If not
+ successful, call dup2 recursively until we are, then close the
+ unsuccessful ones. */
+
+int
+dup2 (int oldd, int newd)
+{
+ int fd, ret;
+
+ close (newd);
+
+ fd = dup (oldd);
+ if (fd == -1)
+ return -1;
+ if (fd == newd)
+ return newd;
+ ret = dup2 (oldd, newd);
+ close (fd);
+ return ret;
+}
+
+
+/* let it fail for now */
+
+char *
+sbrk (int incr)
+{
+ return (char *) -1;
+}
+
+
+int
+fsync (int fd)
+{
+ return 0;
+}
+
+
+int
+ioctl (int d, int request, void *argp)
+{
+ return -1;
+}
+
+
+#ifdef __MRC__
+int
+isatty (int fildes)
+{
+ if (fildes >=0 && fildes <= 2)
+ return 1;
+ else
+ return 0;
+}
+
+
+int
+getgid ()
+{
+ return 100;
+}
+
+
+int
+getegid ()
+{
+ return 100;
+}
+
+
+int
+getuid ()
+{
+ return 200;
+}
+
+
+int
+geteuid ()
+{
+ return 200;
+}
+#endif /* __MRC__ */
+
+
+#ifdef __MWERKS__
+#if __MSL__ < 0x6000
+#undef getpid
+int
+getpid ()
+{
+ return 9999;
+}
+#endif
+#endif /* __MWERKS__ */
+
+#endif /* ! MAC_OSX */
+
+
+/* Return the path to the directory in which Emacs can create
+ temporary files. The MacOS "temporary items" directory cannot be
+ used because it removes the file written by a process when it
+ exits. In that sense it's more like "/dev/null" than "/tmp" (but
+ again not exactly). And of course Emacs needs to read back the
+ files written by its subprocesses. So here we write the files to a
+ directory "Emacs" in the Preferences Folder. This directory is
+ created if it does not exist. */
+
+char *
+get_temp_dir_name ()
+{
+ static char *temp_dir_name = NULL;
+ short vol_ref_num;
+ long dir_id;
+ OSErr err;
+ Str255 dir_name, full_path;
+ CInfoPBRec cpb;
+ char unix_dir_name[MAXPATHLEN+1];
+ DIR *dir;
+
+ /* Cache directory name with pointer temp_dir_name.
+ Look for it only the first time. */
+ if (!temp_dir_name)
+ {
+ err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
+ &vol_ref_num, &dir_id);
+ if (err != noErr)
+ return NULL;
+
+ if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
+ return NULL;
+
+ if (strlen (full_path) + 6 <= MAXPATHLEN)
+ strcat (full_path, "Emacs:");
+ else
+ return NULL;
+
+ if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
+ return NULL;
+
+ dir = opendir (unix_dir_name); /* check whether temp directory exists */
+ if (dir)
+ closedir (dir);
+ else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
+ return NULL;
+
+ temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
+ strcpy (temp_dir_name, unix_dir_name);
+ }
+
+ return temp_dir_name;
+}
+
+#ifndef MAC_OSX
+
+/* Allocate and construct an array of pointers to strings from a list
+ of strings stored in a 'STR#' resource. The returned pointer array
+ is stored in the style of argv and environ: if the 'STR#' resource
+ contains numString strings, an pointer array with numString+1
+ elements is returned in which the last entry contains a null
+ pointer. The pointer to the pointer array is passed by pointer in
+ parameter t. The resource ID of the 'STR#' resource is passed in
+ parameter StringListID.
+ */
+
+void
+get_string_list (char ***t, short string_list_id)
+{
+ Handle h;
+ Ptr p;
+ int i, num_strings;
+
+ h = GetResource ('STR#', string_list_id);
+ if (h)
+ {
+ HLock (h);
+ p = *h;
+ num_strings = * (short *) p;
+ p += sizeof(short);
+ *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
+ for (i = 0; i < num_strings; i++)
+ {
+ short length = *p++;
+ (*t)[i] = (char *) malloc (length + 1);
+ strncpy ((*t)[i], p, length);
+ (*t)[i][length] = '\0';
+ p += length;
+ }
+ (*t)[num_strings] = 0;
+ HUnlock (h);
+ }
+ else
+ {
+ /* Return no string in case GetResource fails. Bug fixed by
+ Ikegami Tsutomu. Caused MPW build to crash without sym -on
+ option (no sym -on implies -opt local). */
+ *t = (char **) malloc (sizeof (char *));
+ (*t)[0] = 0;
+ }
+}
+
+
+static char *
+get_path_to_system_folder ()
+{
+ short vol_ref_num;
+ long dir_id;
+ OSErr err;
+ Str255 dir_name, full_path;
+ CInfoPBRec cpb;
+ static char system_folder_unix_name[MAXPATHLEN+1];
+ DIR *dir;
+
+ err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
+ &vol_ref_num, &dir_id);
+ if (err != noErr)
+ return NULL;
+
+ if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
+ return NULL;
+
+ if (!mac_to_posix_pathname (full_path, system_folder_unix_name,
+ MAXPATHLEN+1))
+ return NULL;
+
+ return system_folder_unix_name;
+}
+
+
+char **environ;
+
+#define ENVIRON_STRING_LIST_ID 128
+
+/* Get environment variable definitions from STR# resource. */
+
+void
+init_environ ()
+{
+ int i;
+
+ get_string_list (&environ, ENVIRON_STRING_LIST_ID);
+
+ i = 0;
+ while (environ[i])
+ i++;
+
+ /* Make HOME directory the one Emacs starts up in if not specified
+ by resource. */
+ if (getenv ("HOME") == NULL)
+ {
+ environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
+ if (environ)
+ {
+ environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
+ if (environ[i])
+ {
+ strcpy (environ[i], "HOME=");
+ strcat (environ[i], my_passwd_dir);
+ }
+ environ[i+1] = 0;
+ i++;
+ }
+ }
+
+ /* Make HOME directory the one Emacs starts up in if not specified
+ by resource. */
+ if (getenv ("MAIL") == NULL)
+ {
+ environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
+ if (environ)
+ {
+ char * path_to_system_folder = get_path_to_system_folder ();
+ environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
+ if (environ[i])
+ {
+ strcpy (environ[i], "MAIL=");
+ strcat (environ[i], path_to_system_folder);
+ strcat (environ[i], "Eudora Folder/In");
+ }
+ environ[i+1] = 0;
+ }
+ }
+}
+
+
+/* Return the value of the environment variable NAME. */
+
+char *
+getenv (const char *name)
+{
+ int length = strlen(name);
+ char **e;
+
+ for (e = environ; *e != 0; e++)
+ if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
+ return &(*e)[length + 1];
+
+ if (strcmp (name, "TMPDIR") == 0)
+ return get_temp_dir_name ();
+
+ return 0;
+}
+
+
+#ifdef __MRC__
+/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
+char *sys_siglist[] =
+{
+ "Zero is not a signal!!!",
+ "Abort", /* 1 */
+ "Interactive user interrupt", /* 2 */ "?",
+ "Floating point exception", /* 4 */ "?", "?", "?",
+ "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
+ "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
+ "?", "?", "?", "?", "?", "?", "?", "?",
+ "Terminal" /* 32 */
+};
+#elif __MWERKS__
+char *sys_siglist[] =
+{
+ "Zero is not a signal!!!",
+ "Abort",
+ "Floating point exception",
+ "Illegal instruction",
+ "Interactive user interrupt",
+ "Segment violation",
+ "Terminal"
+};
+#else /* not __MRC__ and not __MWERKS__ */
+You lose!!!
+#endif /* not __MRC__ and not __MWERKS__ */
+
+
+#include <utsname.h>
+
+int
+uname (struct utsname *name)
+{
+ char **system_name;
+ system_name = GetString (-16413); /* IM - Resource Manager Reference */
+ if (system_name)
+ {
+ BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
+ p2cstr (name->nodename);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+#include <Processes.h>
+#include <EPPC.h>
+
+/* Event class of HLE sent to subprocess. */
+const OSType kEmacsSubprocessSend = 'ESND';
+
+/* Event class of HLE sent back from subprocess. */
+const OSType kEmacsSubprocessReply = 'ERPY';
+
+
+char *
+mystrchr (char *s, char c)
+{
+ while (*s && *s != c)
+ {
+ if (*s == '\\')
+ s++;
+ s++;
+ }
+
+ if (*s)
+ {
+ *s = '\0';
+ return s;
+ }
+ else
+ return NULL;
+}
+
+
+char *
+mystrtok (char *s)
+{
+ while (*s)
+ s++;
+
+ return s + 1;
+}
+
+
+void
+mystrcpy (char *to, char *from)
+{
+ while (*from)
+ {
+ if (*from == '\\')
+ from++;
+ *to++ = *from++;
+ }
+ *to = '\0';
+}
+
+
+/* Start a Mac subprocess. Arguments for it is passed in argv (null
+ terminated). The process should run with the default directory
+ "workdir", read input from "infn", and write output and error to
+ "outfn" and "errfn", resp. The Process Manager call
+ LaunchApplication is used to start the subprocess. We use high
+ level events as the mechanism to pass arguments to the subprocess
+ and to make Emacs wait for the subprocess to terminate and pass
+ back a result code. The bulk of the code here packs the arguments
+ into one message to be passed together with the high level event.
+ Emacs also sometimes starts a subprocess using a shell to perform
+ wildcard filename expansion. Since we don't really have a shell on
+ the Mac, this case is detected and the starting of the shell is
+ by-passed. We really need to add code here to do filename
+ expansion to support such functionality. */
+
+int
+run_mac_command (argv, workdir, infn, outfn, errfn)
+ unsigned char **argv;
+ const char *workdir;
+ const char *infn, *outfn, *errfn;
+{
+#ifdef TARGET_API_MAC_CARBON
+ return -1;
+#else /* not TARGET_API_MAC_CARBON */
+ char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
+ char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
+ int paramlen, argc, newargc, j, retries;
+ char **newargv, *param, *p;
+ OSErr iErr;
+ FSSpec spec;
+ LaunchParamBlockRec lpbr;
+ EventRecord send_event, reply_event;
+ RgnHandle cursor_region_handle;
+ TargetID targ;
+ unsigned long ref_con, len;
+
+ if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
+ return -1;
+ if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
+ return -1;
+ if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
+ return -1;
+ if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
+ return -1;
+
+ paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
+ + strlen (macerrfn) + 4; /* count nulls at end of strings */
+
+ argc = 0;
+ while (argv[argc])
+ argc++;
+
+ if (argc == 0)
+ return -1;
+
+ /* If a subprocess is invoked with a shell, we receive 3 arguments
+ of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
+ bins>/<command> <command args>" */
+ j = strlen (argv[0]);
+ if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
+ && argc == 3 && strcmp (argv[1], "-c") == 0)
+ {
+ char *command, *t, tempmacpathname[MAXPATHLEN+1];
+
+ /* The arguments for the command in argv[2] are separated by
+ spaces. Count them and put the count in newargc. */
+ command = (char *) alloca (strlen (argv[2])+2);
+ strcpy (command, argv[2]);
+ if (command[strlen (command) - 1] != ' ')
+ strcat (command, " ");
+
+ t = command;
+ newargc = 0;
+ t = mystrchr (t, ' ');
+ while (t)
+ {
+ newargc++;
+ t = mystrchr (t+1, ' ');
+ }
+
+ newargv = (char **) alloca (sizeof (char *) * newargc);
+
+ t = command;
+ for (j = 0; j < newargc; j++)
+ {
+ newargv[j] = (char *) alloca (strlen (t) + 1);
+ mystrcpy (newargv[j], t);
+
+ t = mystrtok (t);
+ paramlen += strlen (newargv[j]) + 1;
+ }
+
+ if (strncmp (newargv[0], "~emacs/", 7) == 0)
+ {
+ if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
+ == 0)
+ return -1;
+ }
+ else
+ { /* sometimes Emacs call "sh" without a path for the command */
+#if 0
+ char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
+ strcpy (t, "~emacs/");
+ strcat (t, newargv[0]);
+#endif /* 0 */
+ Lisp_Object path;
+ openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
+ 1);
+
+ if (NILP (path))
+ return -1;
+ if (posix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
+ MAXPATHLEN+1) == 0)
+ return -1;
+ }
+ strcpy (macappname, tempmacpathname);
+ }
+ else
+ {
+ if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
+ return -1;
+
+ newargv = (char **) alloca (sizeof (char *) * argc);
+ newargc = argc;
+ for (j = 1; j < argc; j++)
+ {
+ if (strncmp (argv[j], "~emacs/", 7) == 0)
+ {
+ char *t = strchr (argv[j], ' ');
+ if (t)
+ {
+ char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
+ strncpy (tempcmdname, argv[j], t-argv[j]);
+ tempcmdname[t-argv[j]] = '\0';
+ if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
+ MAXPATHLEN+1) == 0)
+ return -1;
+ newargv[j] = (char *) alloca (strlen (tempmaccmdname)
+ + strlen (t) + 1);
+ strcpy (newargv[j], tempmaccmdname);
+ strcat (newargv[j], t);
+ }
+ else
+ {
+ char tempmaccmdname[MAXPATHLEN+1];
+ if (posix_to_mac_pathname (argv[j], tempmaccmdname,
+ MAXPATHLEN+1) == 0)
+ return -1;
+ newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
+ strcpy (newargv[j], tempmaccmdname);
+ }
+ }
+ else
+ newargv[j] = argv[j];
+ paramlen += strlen (newargv[j]) + 1;
+ }
+ }
+
+ /* After expanding all the arguments, we now know the length of the
+ parameter block to be sent to the subprocess as a message
+ attached to the HLE. */
+ param = (char *) malloc (paramlen + 1);
+ if (!param)
+ return -1;
+
+ p = param;
+ *p++ = newargc;
+ /* first byte of message contains number of arguments for command */
+ strcpy (p, macworkdir);
+ p += strlen (macworkdir);
+ *p++ = '\0';
+ /* null terminate strings sent so it's possible to use strcpy over there */
+ strcpy (p, macinfn);
+ p += strlen (macinfn);
+ *p++ = '\0';
+ strcpy (p, macoutfn);
+ p += strlen (macoutfn);
+ *p++ = '\0';
+ strcpy (p, macerrfn);
+ p += strlen (macerrfn);
+ *p++ = '\0';
+ for (j = 1; j < newargc; j++)
+ {
+ strcpy (p, newargv[j]);
+ p += strlen (newargv[j]);
+ *p++ = '\0';
+ }
+
+ c2pstr (macappname);
+
+ iErr = FSMakeFSSpec (0, 0, macappname, &spec);
+
+ if (iErr != noErr)
+ {
+ free (param);
+ return -1;
+ }
+
+ lpbr.launchBlockID = extendedBlock;
+ lpbr.launchEPBLength = extendedBlockLen;
+ lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
+ lpbr.launchAppSpec = &spec;
+ lpbr.launchAppParameters = NULL;
+
+ iErr = LaunchApplication (&lpbr); /* call the subprocess */
+ if (iErr != noErr)
+ {
+ free (param);
+ return -1;
+ }
+
+ send_event.what = kHighLevelEvent;
+ send_event.message = kEmacsSubprocessSend;
+ /* Event ID stored in "where" unused */
+
+ retries = 3;
+ /* OS may think current subprocess has terminated if previous one
+ terminated recently. */
+ do
+ {
+ iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
+ paramlen + 1, receiverIDisPSN);
+ }
+ while (iErr == sessClosedErr && retries-- > 0);
+
+ if (iErr != noErr)
+ {
+ free (param);
+ return -1;
+ }
+
+ cursor_region_handle = NewRgn ();
+
+ /* Wait for the subprocess to finish, when it will send us a ERPY
+ high level event. */
+ while (1)
+ if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
+ cursor_region_handle)
+ && reply_event.message == kEmacsSubprocessReply)
+ break;
+
+ /* The return code is sent through the refCon */
+ iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
+ if (iErr != noErr)
+ {
+ DisposeHandle ((Handle) cursor_region_handle);
+ free (param);
+ return -1;
+ }
+
+ DisposeHandle ((Handle) cursor_region_handle);
+ free (param);
+
+ return ref_con;
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+DIR *
+opendir (const char *dirname)
+{
+ char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
+ char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
+ DIR *dirp;
+ CInfoPBRec cipb;
+ HVolumeParam vpb;
+ int len, vol_name_len;
+
+ if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
+ return 0;
+
+ len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
+ if (len > -1)
+ fully_resolved_name[len] = '\0';
+ else
+ strcpy (fully_resolved_name, true_pathname);
+
+ dirp = (DIR *) malloc (sizeof(DIR));
+ if (!dirp)
+ return 0;
+
+ /* Handle special case when dirname is "/": sets up for readir to
+ get all mount volumes. */
+ if (strcmp (fully_resolved_name, "/") == 0)
+ {
+ dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
+ dirp->current_index = 1; /* index for first volume */
+ return dirp;
+ }
+
+ /* Handle typical cases: not accessing all mounted volumes. */
+ if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
+ return 0;
+
+ /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
+ len = strlen (mac_pathname);
+ if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
+ strcat (mac_pathname, ":");
+
+ /* Extract volume name */
+ vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
+ strncpy (vol_name, mac_pathname, vol_name_len);
+ vol_name[vol_name_len] = '\0';
+ strcat (vol_name, ":");
+
+ c2pstr (mac_pathname);
+ cipb.hFileInfo.ioNamePtr = mac_pathname;
+ /* using full pathname so vRefNum and DirID ignored */
+ cipb.hFileInfo.ioVRefNum = 0;
+ cipb.hFileInfo.ioDirID = 0;
+ cipb.hFileInfo.ioFDirIndex = 0;
+ /* set to 0 to get information about specific dir or file */
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
+ return 0; /* not a directory */
+
+ dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
+ dirp->getting_volumes = 0;
+ dirp->current_index = 1; /* index for first file/directory */
+
+ c2pstr (vol_name);
+ vpb.ioNamePtr = vol_name;
+ /* using full pathname so vRefNum and DirID ignored */
+ vpb.ioVRefNum = 0;
+ vpb.ioVolIndex = -1;
+ errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ dirp->vol_ref_num = vpb.ioVRefNum;
+
+ return dirp;
+}
+
+int
+closedir (DIR *dp)
+{
+ free (dp);
+
+ return 0;
+}
+
+
+struct dirent *
+readdir (DIR *dp)
+{
+ HParamBlockRec hpblock;
+ CInfoPBRec cipb;
+ static struct dirent s_dirent;
+ static Str255 s_name;
+ int done;
+ char *p;
+
+ /* Handle the root directory containing the mounted volumes. Call
+ PBHGetVInfo specifying an index to obtain the info for a volume.
+ PBHGetVInfo returns an error when it receives an index beyond the
+ last volume, at which time we should return a nil dirent struct
+ pointer. */
+ if (dp->getting_volumes)
+ {
+ hpblock.volumeParam.ioNamePtr = s_name;
+ hpblock.volumeParam.ioVRefNum = 0;
+ hpblock.volumeParam.ioVolIndex = dp->current_index;
+
+ errno = PBHGetVInfo (&hpblock, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ p2cstr (s_name);
+ strcat (s_name, "/"); /* need "/" for stat to work correctly */
+
+ dp->current_index++;
+
+ s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
+ s_dirent.d_name = s_name;
+
+ return &s_dirent;
+ }
+ else
+ {
+ cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
+ cipb.hFileInfo.ioNamePtr = s_name;
+ /* location to receive filename returned */
+
+ /* return only visible files */
+ done = false;
+ while (!done)
+ {
+ cipb.hFileInfo.ioDirID = dp->dir_id;
+ /* directory ID found by opendir */
+ cipb.hFileInfo.ioFDirIndex = dp->current_index;
+
+ errno = PBGetCatInfo (&cipb, false);
+ if (errno != noErr)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ /* insist on an visibile entry */
+ if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
+ done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
+ else
+ done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
+
+ dp->current_index++;
+ }
+
+ p2cstr (s_name);
+
+ p = s_name;
+ while (*p)
+ {
+ if (*p == '/')
+ *p = ':';
+ p++;
+ }
+
+ s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
+ /* value unimportant: non-zero for valid file */
+ s_dirent.d_name = s_name;
+
+ return &s_dirent;
+ }
+}
+
+
+char *
+getwd (char *path)
+{
+ char mac_pathname[MAXPATHLEN+1];
+ Str255 directory_name;
+ OSErr errno;
+ CInfoPBRec cipb;
+
+ if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
+ return NULL;
+
+ if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
+ return 0;
+ else
+ return path;
+}
+
+#endif /* ! MAC_OSX */
+
+
+void
+initialize_applescript ()
+{
+ AEDesc null_desc;
+ OSAError osaerror;
+
+ /* if open fails, as_scripting_component is set to NULL. Its
+ subsequent use in OSA calls will fail with badComponentInstance
+ error. */
+ as_scripting_component = OpenDefaultComponent (kOSAComponentType,
+ kAppleScriptSubtype);
+
+ null_desc.descriptorType = typeNull;
+ null_desc.dataHandle = 0;
+ osaerror = OSAMakeContext (as_scripting_component, &null_desc,
+ kOSANullScript, &as_script_context);
+ if (osaerror)
+ as_script_context = kOSANullScript;
+ /* use default context if create fails */
+}
+
+
+void terminate_applescript()
+{
+ OSADispose (as_scripting_component, as_script_context);
+ CloseComponent (as_scripting_component);
+}
+
+
+/* Compile and execute the AppleScript SCRIPT and return the error
+ status as function value. A zero is returned if compilation and
+ execution is successful, in which case RESULT returns a pointer to
+ a string containing the resulting script value. Otherwise, the Mac
+ error code is returned and RESULT returns a pointer to an error
+ string. In both cases the caller should deallocate the storage
+ used by the string pointed to by RESULT if it is non-NULL. For
+ documentation on the MacOS scripting architecture, see Inside
+ Macintosh - Interapplication Communications: Scripting Components. */
+
+static long
+do_applescript (char *script, char **result)
+{
+ AEDesc script_desc, result_desc, error_desc;
+ OSErr error;
+ OSAError osaerror;
+ long length;
+
+ *result = 0;
+
+ error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
+ if (error)
+ return error;
+
+ osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
+ typeChar, kOSAModeNull, &result_desc);
+
+ if (osaerror == errOSAScriptError)
+ {
+ /* error executing AppleScript: retrieve error message */
+ if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
+ &error_desc))
+ {
+#if TARGET_API_MAC_CARBON
+ length = AEGetDescDataSize (&error_desc);
+ *result = (char *) xmalloc (length + 1);
+ if (*result)
+ {
+ AEGetDescData (&error_desc, *result, length);
+ *(*result + length) = '\0';
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ HLock (error_desc.dataHandle);
+ length = GetHandleSize(error_desc.dataHandle);
+ *result = (char *) xmalloc (length + 1);
+ if (*result)
+ {
+ memcpy (*result, *(error_desc.dataHandle), length);
+ *(*result + length) = '\0';
+ }
+ HUnlock (error_desc.dataHandle);
+#endif /* not TARGET_API_MAC_CARBON */
+ AEDisposeDesc (&error_desc);
+ }
+ }
+ else if (osaerror == noErr) /* success: retrieve resulting script value */
+ {
+#if TARGET_API_MAC_CARBON
+ length = AEGetDescDataSize (&result_desc);
+ *result = (char *) xmalloc (length + 1);
+ if (*result)
+ {
+ AEGetDescData (&result_desc, *result, length);
+ *(*result + length) = '\0';
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ HLock (result_desc.dataHandle);
+ length = GetHandleSize(result_desc.dataHandle);
+ *result = (char *) xmalloc (length + 1);
+ if (*result)
+ {
+ memcpy (*result, *(result_desc.dataHandle), length);
+ *(*result + length) = '\0';
+ }
+ HUnlock (result_desc.dataHandle);
+#endif /* not TARGET_API_MAC_CARBON */
+ }
+
+ AEDisposeDesc (&script_desc);
+ AEDisposeDesc (&result_desc);
+
+ return osaerror;
+}
+
+
+DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
+ doc: /* Compile and execute AppleScript SCRIPT and retrieve and return the result.
+If compilation and execution are successful, the resulting script
+value is returned as a string. Otherwise the function aborts and
+displays the error message returned by the AppleScript scripting
+component. */)
+ (script)
+ Lisp_Object script;
+{
+ char *result, *temp;
+ Lisp_Object lisp_result;
+ long status;
+
+ CHECK_STRING (script);
+
+ status = do_applescript (XSTRING (script)->data, &result);
+ if (status)
+ {
+ if (!result)
+ error ("AppleScript error %ld", status);
+ else
+ {
+ /* Unfortunately only OSADoScript in do_applescript knows how
+ how large the resulting script value or error message is
+ going to be and therefore as caller memory must be
+ deallocated here. It is necessary to free the error
+ message before calling error to avoid a memory leak. */
+ temp = (char *) alloca (strlen (result) + 1);
+ strcpy (temp, result);
+ xfree (result);
+ error (temp);
+ }
+ }
+ else
+ {
+ lisp_result = build_string (result);
+ xfree (result);
+ return lisp_result;
+ }
+}
+
+
+DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix,
+ Smac_file_name_to_posix, 1, 1, 0,
+ doc: /* Convert Macintosh filename to Posix form. */)
+ (mac_filename)
+ Lisp_Object mac_filename;
+{
+ char posix_filename[MAXPATHLEN+1];
+
+ CHECK_STRING (mac_filename);
+
+ if (mac_to_posix_pathname (XSTRING (mac_filename)->data, posix_filename,
+ MAXPATHLEN))
+ return build_string (posix_filename);
+ else
+ return Qnil;
+}
+
+
+DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac,
+ Sposix_file_name_to_mac, 1, 1, 0,
+ doc: /* Convert Posix filename to Mac form. */)
+ (posix_filename)
+ Lisp_Object posix_filename;
+{
+ char mac_filename[MAXPATHLEN+1];
+
+ CHECK_STRING (posix_filename);
+
+ if (posix_to_mac_pathname (XSTRING (posix_filename)->data, mac_filename,
+ MAXPATHLEN))
+ return build_string (mac_filename);
+ else
+ return Qnil;
+}
+
+
+/* set interprogram-paste-function to mac-paste-function in mac-win.el
+ to enable Emacs to obtain the contents of the Mac clipboard. */
+DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
+ doc: /* Return the contents of the Mac clipboard as a string. */)
+ ()
+{
+#if TARGET_API_MAC_CARBON
+ ScrapRef scrap;
+ ScrapFlavorFlags sff;
+ Size s;
+ int i;
+ char *data;
+
+ if (GetCurrentScrap (&scrap) != noErr)
+ return Qnil;
+
+ if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) != noErr)
+ return Qnil;
+
+ if (GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s) != noErr)
+ return Qnil;
+
+ if ((data = (char*) alloca (s)) == NULL)
+ return Qnil;
+
+ if (GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data) != noErr
+ || s == 0)
+ return Qnil;
+
+ /* Emacs expects clipboard contents have Unix-style eol's */
+ for (i = 0; i < s; i++)
+ if (data[i] == '\r')
+ data[i] = '\n';
+
+ return make_string (data, s);
+#else /* not TARGET_API_MAC_CARBON */
+ Lisp_Object value;
+ Handle my_handle;
+ long scrap_offset, rc, i;
+
+ my_handle = NewHandle (0); /* allocate 0-length data area */
+
+ rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
+ if (rc < 0)
+ return Qnil;
+
+ HLock (my_handle);
+
+ /* Emacs expects clipboard contents have Unix-style eol's */
+ for (i = 0; i < rc; i++)
+ if ((*my_handle)[i] == '\r')
+ (*my_handle)[i] = '\n';
+
+ value = make_string (*my_handle, rc);
+
+ HUnlock (my_handle);
+
+ DisposeHandle (my_handle);
+
+ return value;
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* set interprogram-cut-function to mac-cut-function in mac-win.el
+ to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
+DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
+ doc: /* Put the value of the string parameter to the Mac clipboard. */)
+ (value, push)
+ Lisp_Object value, push;
+{
+ char *buf;
+ int len, i;
+
+ /* fixme: ignore the push flag for now */
+
+ CHECK_STRING (value);
+
+ len = XSTRING (value)->size;
+ buf = (char *) alloca (len+1);
+ bcopy (XSTRING (value)->data, buf, len);
+ buf[len] = '\0';
+
+ /* convert to Mac-style eol's before sending to clipboard */
+ for (i = 0; i < len; i++)
+ if (buf[i] == '\n')
+ buf[i] = '\r';
+
+#if TARGET_API_MAC_CARBON
+ {
+ ScrapRef scrap;
+ ClearCurrentScrap ();
+ if (GetCurrentScrap (&scrap) != noErr)
+ error ("cannot get current scrap");
+
+ if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len,
+ buf) != noErr)
+ error ("cannot put to scrap");
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ ZeroScrap ();
+ PutScrap (len, 'TEXT', buf);
+#endif /* not TARGET_API_MAC_CARBON */
+
+ return Qnil;
+}
+
+
+DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
+ 0, 1, 0,
+ doc: /* Whether there is an owner for the given X Selection.
+The arg should be the name of the selection in question, typically one of
+the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
+(Those are literal upper-case symbol names, since that's what X expects.)
+For convenience, the symbol nil is the same as `PRIMARY',
+and t is the same as `SECONDARY'. */)
+ (selection)
+ Lisp_Object selection;
+{
+ CHECK_SYMBOL (selection);
+
+ /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
+ if the clipboard currently has valid text format contents. */
+
+ if (EQ (selection, QCLIPBOARD))
+ {
+ Lisp_Object val = Qnil;
+
+#if TARGET_API_MAC_CARBON
+ ScrapRef scrap;
+ ScrapFlavorFlags sff;
+
+ if (GetCurrentScrap (&scrap) == noErr)
+ if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr)
+ val = Qt;
+#else /* not TARGET_API_MAC_CARBON */
+ Handle my_handle;
+ long rc, scrap_offset;
+
+ my_handle = NewHandle (0);
+
+ rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
+ if (rc >= 0)
+ val = Qt;
+
+ DisposeHandle (my_handle);
+#endif /* not TARGET_API_MAC_CARBON */
+
+ return val;
+ }
+ return Qnil;
+}
+
+
+void
+syms_of_mac ()
+{
+ QCLIPBOARD = intern ("CLIPBOARD");
+ staticpro (&QCLIPBOARD);
+
+ defsubr (&Smac_paste_function);
+ defsubr (&Smac_cut_function);
+#if 0
+ defsubr (&Sx_selection_exists_p);
+#endif /* 0 */
+
+ defsubr (&Sdo_applescript);
+ defsubr (&Smac_file_name_to_posix);
+ defsubr (&Sposix_file_name_to_mac);
+}
diff --git a/src/macfns.c b/src/macfns.c
new file mode 100644
index 00000000000..a4235d7c653
--- /dev/null
+++ b/src/macfns.c
@@ -0,0 +1,10255 @@
+/* Graphical user interface functions for Mac OS.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#include <config.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <math.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "lisp.h"
+#include "charset.h"
+#include "macterm.h"
+#include "frame.h"
+#include "window.h"
+#include "buffer.h"
+#include "dispextern.h"
+#include "fontset.h"
+#include "intervals.h"
+#include "keyboard.h"
+#include "blockinput.h"
+#include "epaths.h"
+#include "termhooks.h"
+#include "coding.h"
+#include "ccl.h"
+#include "systime.h"
+
+/* #include "bitmaps/gray.xbm" */
+#define gray_width 2
+#define gray_height 2
+static unsigned char gray_bits[] = {
+ 0x01, 0x02};
+
+/*#include <commdlg.h>
+#include <shellapi.h>*/
+#include <ctype.h>
+
+#include <stdlib.h>
+#include <string.h>
+#ifndef MAC_OSX
+#include <alloca.h>
+#endif
+
+#ifdef MAC_OSX
+#undef mktime
+#undef DEBUG
+#undef Z
+#undef free
+#undef malloc
+#undef realloc
+/* Macros max and min defined in lisp.h conflict with those in
+ precompiled header Carbon.h. */
+#undef max
+#undef min
+#include <Carbon/Carbon.h>
+#undef Z
+#define Z (current_buffer->text->z)
+#undef free
+#define free unexec_free
+#undef malloc
+#define malloc unexec_malloc
+#undef realloc
+#define realloc unexec_realloc
+#undef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#undef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#else /* not MAC_OSX */
+#include <Windows.h>
+#include <Gestalt.h>
+#include <TextUtils.h>
+#endif /* not MAC_OSX */
+
+/*extern void free_frame_menubar ();
+extern double atof ();
+extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
+extern int quit_char;*/
+
+/* A definition of XColor for non-X frames. */
+#ifndef HAVE_X_WINDOWS
+typedef struct {
+ unsigned long pixel;
+ unsigned short red, green, blue;
+ char flags;
+ char pad;
+} XColor;
+#endif
+
+extern char *lispy_function_keys[];
+
+/* The gray bitmap `bitmaps/gray'. This is done because macterm.c uses
+ it, and including `bitmaps/gray' more than once is a problem when
+ config.h defines `static' as an empty replacement string. */
+
+int gray_bitmap_width = gray_width;
+int gray_bitmap_height = gray_height;
+unsigned char *gray_bitmap_bits = gray_bits;
+
+/* The name we're using in resource queries. */
+
+Lisp_Object Vx_resource_name;
+
+/* Non-zero means we're allowed to display an hourglass cursor. */
+
+int display_hourglass_p;
+
+/* The background and shape of the mouse pointer, and shape when not
+ over text or in the modeline. */
+
+Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
+Lisp_Object Vx_hourglass_pointer_shape;
+
+/* The shape when over mouse-sensitive text. */
+
+Lisp_Object Vx_sensitive_text_pointer_shape;
+
+/* If non-nil, the pointer shape to indicate that windows can be
+ dragged horizontally. */
+
+Lisp_Object Vx_window_horizontal_drag_shape;
+
+/* Color of chars displayed in cursor box. */
+
+Lisp_Object Vx_cursor_fore_pixel;
+
+/* Nonzero if using Windows. */
+
+static int mac_in_use;
+
+/* Non nil if no window manager is in use. */
+
+Lisp_Object Vx_no_window_manager;
+
+/* Search path for bitmap files. */
+
+Lisp_Object Vx_bitmap_file_path;
+
+/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
+
+Lisp_Object Vx_pixel_size_width_font_regexp;
+
+/* Evaluate this expression to rebuild the section of syms_of_macfns
+ that initializes and staticpros the symbols declared below. Note
+ that Emacs 18 has a bug that keeps C-x C-e from being able to
+ evaluate this expression.
+
+(progn
+ ;; Accumulate a list of the symbols we want to initialize from the
+ ;; declarations at the top of the file.
+ (goto-char (point-min))
+ (search-forward "/\*&&& symbols declared here &&&*\/\n")
+ (let (symbol-list)
+ (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
+ (setq symbol-list
+ (cons (buffer-substring (match-beginning 1) (match-end 1))
+ symbol-list))
+ (forward-line 1))
+ (setq symbol-list (nreverse symbol-list))
+ ;; Delete the section of syms_of_... where we initialize the symbols.
+ (search-forward "\n /\*&&& init symbols here &&&*\/\n")
+ (let ((start (point)))
+ (while (looking-at "^ Q")
+ (forward-line 2))
+ (kill-region start (point)))
+ ;; Write a new symbol initialization section.
+ (while symbol-list
+ (insert (format " %s = intern (\"" (car symbol-list)))
+ (let ((start (point)))
+ (insert (substring (car symbol-list) 1))
+ (subst-char-in-region start (point) ?_ ?-))
+ (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
+ (setq symbol-list (cdr symbol-list)))))
+
+ */
+
+/*&&& symbols declared here &&&*/
+Lisp_Object Qauto_raise;
+Lisp_Object Qauto_lower;
+Lisp_Object Qbar;
+Lisp_Object Qborder_color;
+Lisp_Object Qborder_width;
+Lisp_Object Qbox;
+Lisp_Object Qcursor_color;
+Lisp_Object Qcursor_type;
+Lisp_Object Qgeometry;
+Lisp_Object Qicon_left;
+Lisp_Object Qicon_top;
+Lisp_Object Qicon_type;
+Lisp_Object Qicon_name;
+Lisp_Object Qinternal_border_width;
+Lisp_Object Qleft;
+Lisp_Object Qright;
+Lisp_Object Qmouse_color;
+Lisp_Object Qnone;
+Lisp_Object Qparent_id;
+Lisp_Object Qscroll_bar_width;
+Lisp_Object Qsuppress_icon;
+Lisp_Object Qundefined_color;
+Lisp_Object Qvertical_scroll_bars;
+Lisp_Object Qvisibility;
+Lisp_Object Qwindow_id;
+Lisp_Object Qx_frame_parameter;
+Lisp_Object Qx_resource_name;
+Lisp_Object Quser_position;
+Lisp_Object Quser_size;
+Lisp_Object Qscreen_gamma;
+Lisp_Object Qline_spacing;
+Lisp_Object Qcenter;
+Lisp_Object Qcancel_timer;
+Lisp_Object Qhyper;
+Lisp_Object Qsuper;
+Lisp_Object Qmeta;
+Lisp_Object Qalt;
+Lisp_Object Qctrl;
+Lisp_Object Qcontrol;
+Lisp_Object Qshift;
+
+extern Lisp_Object Qtop;
+extern Lisp_Object Qdisplay;
+Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
+extern Lisp_Object Qtool_bar_lines;
+
+/* These are defined in frame.c. */
+extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
+extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
+extern Lisp_Object Qtool_bar_lines;
+
+extern Lisp_Object Vwindow_system_version;
+
+Lisp_Object Qface_set_after_frame_default;
+
+extern int mac_initialized;
+
+/* Functions in macterm.c. */
+extern void x_set_offset (struct frame *, int, int, int);
+extern void x_wm_set_icon_position (struct frame *, int, int);
+extern void x_display_cursor (struct window *, int, int, int, int, int);
+extern void x_set_window_size (struct frame *, int, int, int);
+extern void x_make_frame_visible (struct frame *);
+extern struct mac_display_info *mac_term_init (Lisp_Object, char *, char *);
+extern struct font_info *x_get_font_info (FRAME_PTR, int);
+extern struct font_info *x_load_font (struct frame *, char *, int);
+extern void x_find_ccl_program (struct font_info *);
+extern struct font_info *x_query_font (struct frame *, char *);
+extern void mac_initialize ();
+
+/* compare two strings ignoring case */
+
+static int
+stricmp (const char *s, const char *t)
+{
+ for ( ; tolower (*s) == tolower (*t); s++, t++)
+ if (*s == '\0')
+ return 0;
+ return tolower (*s) - tolower (*t);
+}
+
+/* compare two strings up to n characters, ignoring case */
+
+static int
+strnicmp (const char *s, const char *t, unsigned int n)
+{
+ for ( ; n-- > 0 && tolower (*s) == tolower (*t); s++, t++)
+ if (*s == '\0')
+ return 0;
+ return n == 0 ? 0 : tolower (*s) - tolower (*t);
+}
+
+
+/* Error if we are not running on Mac OS. */
+
+void
+check_mac ()
+{
+ if (! mac_in_use)
+ error ("Mac OS not in use or not initialized");
+}
+
+/* Nonzero if we can use mouse menus.
+ You should not call this unless HAVE_MENUS is defined. */
+
+int
+have_menus_p ()
+{
+ return mac_in_use;
+}
+
+/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
+ and checking validity for Mac. */
+
+FRAME_PTR
+check_x_frame (frame)
+ Lisp_Object frame;
+{
+ FRAME_PTR f;
+
+ if (NILP (frame))
+ frame = selected_frame;
+ CHECK_LIVE_FRAME (frame);
+ f = XFRAME (frame);
+ if (! FRAME_MAC_P (f))
+ error ("non-mac frame used");
+ return f;
+}
+
+/* Let the user specify an display with a frame.
+ nil stands for the selected frame--or, if that is not a mac frame,
+ the first display on the list. */
+
+static struct mac_display_info *
+check_x_display_info (frame)
+ Lisp_Object frame;
+{
+ if (!mac_initialized)
+ {
+ mac_initialize ();
+ mac_initialized = 1;
+ }
+
+ if (NILP (frame))
+ {
+ struct frame *sf = XFRAME (selected_frame);
+
+ if (FRAME_MAC_P (sf) && FRAME_LIVE_P (sf))
+ return FRAME_MAC_DISPLAY_INFO (sf);
+ else
+ return &one_mac_display_info;
+ }
+ else if (STRINGP (frame))
+ return x_display_info_for_name (frame);
+ else
+ {
+ FRAME_PTR f;
+
+ CHECK_LIVE_FRAME (frame);
+ f = XFRAME (frame);
+ if (! FRAME_MAC_P (f))
+ error ("non-mac frame used");
+ return FRAME_MAC_DISPLAY_INFO (f);
+ }
+}
+
+/* Return the Emacs frame-object corresponding to an mac window.
+ It could be the frame's main window or an icon window. */
+
+/* This function can be called during GC, so use GC_xxx type test macros. */
+
+struct frame *
+x_window_to_frame (dpyinfo, wdesc)
+ struct mac_display_info *dpyinfo;
+ WindowPtr wdesc;
+{
+ Lisp_Object tail, frame;
+ struct frame *f;
+
+ for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+ {
+ frame = XCAR (tail);
+ if (!GC_FRAMEP (frame))
+ continue;
+ f = XFRAME (frame);
+ if (!FRAME_W32_P (f) || FRAME_MAC_DISPLAY_INFO (f) != dpyinfo)
+ continue;
+ /*if (f->output_data.w32->hourglass_window == wdesc)
+ return f;*/
+
+ /* MAC_TODO: Check tooltips when supported. */
+ if (FRAME_MAC_WINDOW (f) == wdesc)
+ return f;
+ }
+ return 0;
+}
+
+
+
+/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
+ id, which is just an int that this section returns. Bitmaps are
+ reference counted so they can be shared among frames.
+
+ Bitmap indices are guaranteed to be > 0, so a negative number can
+ be used to indicate no bitmap.
+
+ If you use x_create_bitmap_from_data, then you must keep track of
+ the bitmaps yourself. That is, creating a bitmap from the same
+ data more than once will not be caught. */
+
+
+/* Functions to access the contents of a bitmap, given an id. */
+
+int
+x_bitmap_height (f, id)
+ FRAME_PTR f;
+ int id;
+{
+ return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height;
+}
+
+int
+x_bitmap_width (f, id)
+ FRAME_PTR f;
+ int id;
+{
+ return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width;
+}
+
+#if 0 /* MAC_TODO : not used anywhere (?) */
+int
+x_bitmap_pixmap (f, id)
+ FRAME_PTR f;
+ int id;
+{
+ return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
+}
+#endif
+
+/* Allocate a new bitmap record. Returns index of new record. */
+
+static int
+x_allocate_bitmap_record (f)
+ FRAME_PTR f;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ int i;
+
+ if (dpyinfo->bitmaps == NULL)
+ {
+ dpyinfo->bitmaps_size = 10;
+ dpyinfo->bitmaps = (struct mac_bitmap_record *)
+ xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
+ dpyinfo->bitmaps_last = 1;
+ return 1;
+ }
+
+ if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
+ return ++dpyinfo->bitmaps_last;
+
+ for (i = 0; i < dpyinfo->bitmaps_size; ++i)
+ if (dpyinfo->bitmaps[i].refcount == 0)
+ return i + 1;
+
+ dpyinfo->bitmaps_size *= 2;
+ dpyinfo->bitmaps = (struct mac_bitmap_record *)
+ xrealloc (dpyinfo->bitmaps,
+ dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
+ return ++dpyinfo->bitmaps_last;
+}
+
+/* Add one reference to the reference count of the bitmap with id
+ ID. */
+
+void
+x_reference_bitmap (f, id)
+ FRAME_PTR f;
+ int id;
+{
+ ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
+}
+
+/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at
+ BITS. */
+
+int
+x_create_bitmap_from_data (f, bits, width, height)
+ struct frame *f;
+ char *bits;
+ unsigned int width, height;
+{
+ struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ int id;
+
+ /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
+
+ id = x_allocate_bitmap_record (f);
+
+ if (width % 16 != 0)
+ return -1;
+
+ dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
+ if (! dpyinfo->bitmaps[id - 1].bitmap_data)
+ return -1;
+
+ bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
+
+ dpyinfo->bitmaps[id - 1].refcount = 1;
+ dpyinfo->bitmaps[id - 1].height = height;
+ dpyinfo->bitmaps[id - 1].width = width;
+
+ return id;
+}
+
+/* Create bitmap from file FILE for frame F. */
+
+int
+x_create_bitmap_from_file (f, file)
+ struct frame *f;
+ Lisp_Object file;
+{
+ return -1;
+#if 0 /* MAC_TODO : bitmap support */
+ struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
+ unsigned int width, height;
+ HBITMAP bitmap;
+ int xhot, yhot, result, id;
+ Lisp_Object found;
+ int fd;
+ char *filename;
+ HINSTANCE hinst;
+
+ /* Look for an existing bitmap with the same name. */
+ for (id = 0; id < dpyinfo->bitmaps_last; ++id)
+ {
+ if (dpyinfo->bitmaps[id].refcount
+ && dpyinfo->bitmaps[id].file
+ && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
+ {
+ ++dpyinfo->bitmaps[id].refcount;
+ return id + 1;
+ }
+ }
+
+ /* Search bitmap-file-path for the file, if appropriate. */
+ fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
+ if (fd < 0)
+ return -1;
+ /* LoadLibraryEx won't handle special files handled by Emacs handler. */
+ if (fd == 0)
+ return -1;
+ emacs_close (fd);
+
+ filename = (char *) XSTRING (found)->data;
+
+ hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
+
+ if (hinst == NULL)
+ return -1;
+
+
+ result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
+ filename, &width, &height, &bitmap, &xhot, &yhot);
+ if (result != BitmapSuccess)
+ return -1;
+
+ id = x_allocate_bitmap_record (f);
+ dpyinfo->bitmaps[id - 1].pixmap = bitmap;
+ dpyinfo->bitmaps[id - 1].refcount = 1;
+ dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
+ dpyinfo->bitmaps[id - 1].depth = 1;
+ dpyinfo->bitmaps[id - 1].height = height;
+ dpyinfo->bitmaps[id - 1].width = width;
+ strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
+
+ return id;
+#endif /* MAC_TODO */
+}
+
+/* Remove reference to bitmap with id number ID. */
+
+void
+x_destroy_bitmap (f, id)
+ FRAME_PTR f;
+ int id;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+
+ if (id > 0)
+ {
+ --dpyinfo->bitmaps[id - 1].refcount;
+ if (dpyinfo->bitmaps[id - 1].refcount == 0)
+ {
+ BLOCK_INPUT;
+ dpyinfo->bitmaps[id - 1].bitmap_data = NULL;
+ UNBLOCK_INPUT;
+ }
+ }
+}
+
+/* Free all the bitmaps for the display specified by DPYINFO. */
+
+static void
+x_destroy_all_bitmaps (dpyinfo)
+ struct mac_display_info *dpyinfo;
+{
+ int i;
+ for (i = 0; i < dpyinfo->bitmaps_last; i++)
+ if (dpyinfo->bitmaps[i].refcount > 0)
+ xfree (dpyinfo->bitmaps[i].bitmap_data);
+ dpyinfo->bitmaps_last = 0;
+}
+
+/* Connect the frame-parameter names for W32 frames
+ to the ways of passing the parameter values to the window system.
+
+ The name of a parameter, as a Lisp symbol,
+ has an `x-frame-parameter' property which is an integer in Lisp
+ but can be interpreted as an `enum x_frame_parm' in C. */
+
+struct x_frame_parm_table
+{
+ char *name;
+ void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
+};
+
+void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
+ Lisp_Object));
+void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
+ Lisp_Object));
+void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
+void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
+ Lisp_Object));
+void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
+ Lisp_Object));
+static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
+ Lisp_Object,
+ Lisp_Object,
+ char *, char *,
+ int));
+static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
+
+static struct x_frame_parm_table x_frame_parms[] =
+{
+ "auto-raise", x_set_autoraise,
+ "auto-lower", x_set_autolower,
+ "background-color", x_set_background_color,
+ "border-color", x_set_border_color,
+ "border-width", x_set_border_width,
+ "cursor-color", x_set_cursor_color,
+ "cursor-type", x_set_cursor_type,
+ "font", x_set_font,
+ "foreground-color", x_set_foreground_color,
+ "icon-name", x_set_icon_name,
+#if 0 /* MAC_TODO: no icons for Mac */
+ "icon-type", x_set_icon_type,
+#endif
+ "internal-border-width", x_set_internal_border_width,
+ "menu-bar-lines", x_set_menu_bar_lines,
+ "mouse-color", x_set_mouse_color,
+ "name", x_explicitly_set_name,
+ "scroll-bar-width", x_set_scroll_bar_width,
+ "title", x_set_title,
+ "unsplittable", x_set_unsplittable,
+ "vertical-scroll-bars", x_set_vertical_scroll_bars,
+ "visibility", x_set_visibility,
+ "tool-bar-lines", x_set_tool_bar_lines,
+#if 0 /* MAC_TODO: cannot set color of scroll bar on the Mac? */
+ "scroll-bar-foreground", x_set_scroll_bar_foreground,
+ "scroll-bar-background", x_set_scroll_bar_background,
+#endif
+ "screen-gamma", x_set_screen_gamma,
+ "line-spacing", x_set_line_spacing
+};
+
+/* Attach the `x-frame-parameter' properties to
+ the Lisp symbol names of parameters relevant to Mac. */
+
+void
+init_x_parm_symbols ()
+{
+ int i;
+
+ for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
+ Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
+ make_number (i));
+}
+
+/* Change the parameters of frame F as specified by ALIST.
+ If a parameter is not specially recognized, do nothing;
+ otherwise call the `x_set_...' function for that parameter. */
+
+void
+x_set_frame_parameters (f, alist)
+ FRAME_PTR f;
+ Lisp_Object alist;
+{
+ Lisp_Object tail;
+
+ /* If both of these parameters are present, it's more efficient to
+ set them both at once. So we wait until we've looked at the
+ entire list before we set them. */
+ int width, height;
+
+ /* Same here. */
+ Lisp_Object left, top;
+
+ /* Same with these. */
+ Lisp_Object icon_left, icon_top;
+
+ /* Record in these vectors all the parms specified. */
+ Lisp_Object *parms;
+ Lisp_Object *values;
+ int i, p;
+ int left_no_change = 0, top_no_change = 0;
+ int icon_left_no_change = 0, icon_top_no_change = 0;
+
+ struct gcpro gcpro1, gcpro2;
+
+ i = 0;
+ for (tail = alist; CONSP (tail); tail = Fcdr (tail))
+ i++;
+
+ parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
+ values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
+
+ /* Extract parm names and values into those vectors. */
+
+ i = 0;
+ for (tail = alist; CONSP (tail); tail = Fcdr (tail))
+ {
+ Lisp_Object elt;
+
+ elt = Fcar (tail);
+ parms[i] = Fcar (elt);
+ values[i] = Fcdr (elt);
+ i++;
+ }
+ /* TAIL and ALIST are not used again below here. */
+ alist = tail = Qnil;
+
+ GCPRO2 (*parms, *values);
+ gcpro1.nvars = i;
+ gcpro2.nvars = i;
+
+ /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
+ because their values appear in VALUES and strings are not valid. */
+ top = left = Qunbound;
+ icon_left = icon_top = Qunbound;
+
+ /* Provide default values for HEIGHT and WIDTH. */
+ if (FRAME_NEW_WIDTH (f))
+ width = FRAME_NEW_WIDTH (f);
+ else
+ width = FRAME_WIDTH (f);
+
+ if (FRAME_NEW_HEIGHT (f))
+ height = FRAME_NEW_HEIGHT (f);
+ else
+ height = FRAME_HEIGHT (f);
+
+ /* Process foreground_color and background_color before anything else.
+ They are independent of other properties, but other properties (e.g.,
+ cursor_color) are dependent upon them. */
+ for (p = 0; p < i; p++)
+ {
+ Lisp_Object prop, val;
+
+ prop = parms[p];
+ val = values[p];
+ if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
+ {
+ register Lisp_Object param_index, old_value;
+
+ param_index = Fget (prop, Qx_frame_parameter);
+ old_value = get_frame_param (f, prop);
+ store_frame_param (f, prop, val);
+ if (NATNUMP (param_index)
+ && (XFASTINT (param_index)
+ < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
+ (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
+ }
+ }
+
+ /* Now process them in reverse of specified order. */
+ for (i--; i >= 0; i--)
+ {
+ Lisp_Object prop, val;
+
+ prop = parms[i];
+ val = values[i];
+
+ if (EQ (prop, Qwidth) && NUMBERP (val))
+ width = XFASTINT (val);
+ else if (EQ (prop, Qheight) && NUMBERP (val))
+ height = XFASTINT (val);
+ else if (EQ (prop, Qtop))
+ top = val;
+ else if (EQ (prop, Qleft))
+ left = val;
+ else if (EQ (prop, Qicon_top))
+ icon_top = val;
+ else if (EQ (prop, Qicon_left))
+ icon_left = val;
+ else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
+ /* Processed above. */
+ continue;
+ else
+ {
+ register Lisp_Object param_index, old_value;
+
+ param_index = Fget (prop, Qx_frame_parameter);
+ old_value = get_frame_param (f, prop);
+ store_frame_param (f, prop, val);
+ if (NATNUMP (param_index)
+ && (XFASTINT (param_index)
+ < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
+ (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
+ }
+ }
+
+ /* Don't die if just one of these was set. */
+ if (EQ (left, Qunbound))
+ {
+ left_no_change = 1;
+ if (f->output_data.mac->left_pos < 0)
+ left = Fcons (Qplus,
+ Fcons (make_number (f->output_data.mac->left_pos),
+ Qnil));
+ else
+ XSETINT (left, f->output_data.mac->left_pos);
+ }
+ if (EQ (top, Qunbound))
+ {
+ top_no_change = 1;
+ if (f->output_data.mac->top_pos < 0)
+ top = Fcons (Qplus,
+ Fcons (make_number (f->output_data.mac->top_pos), Qnil));
+ else
+ XSETINT (top, f->output_data.mac->top_pos);
+ }
+
+ /* If one of the icon positions was not set, preserve or default it. */
+ if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
+ {
+ icon_left_no_change = 1;
+ icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
+ if (NILP (icon_left))
+ XSETINT (icon_left, 0);
+ }
+ if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
+ {
+ icon_top_no_change = 1;
+ icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
+ if (NILP (icon_top))
+ XSETINT (icon_top, 0);
+ }
+
+ /* Don't set these parameters unless they've been explicitly
+ specified. The window might be mapped or resized while we're in
+ this function, and we don't want to override that unless the lisp
+ code has asked for it.
+
+ Don't set these parameters unless they actually differ from the
+ window's current parameters; the window may not actually exist
+ yet. */
+ {
+ Lisp_Object frame;
+
+ check_frame_size (f, &height, &width);
+
+ XSETFRAME (frame, f);
+
+ if (width != FRAME_WIDTH (f)
+ || height != FRAME_HEIGHT (f)
+ || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
+ Fset_frame_size (frame, make_number (width), make_number (height));
+
+ if ((!NILP (left) || !NILP (top))
+ && ! (left_no_change && top_no_change)
+ && ! (NUMBERP (left) && XINT (left) == f->output_data.mac->left_pos
+ && NUMBERP (top) && XINT (top) == f->output_data.mac->top_pos))
+ {
+ int leftpos = 0;
+ int toppos = 0;
+
+ /* Record the signs. */
+ f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
+ if (EQ (left, Qminus))
+ f->output_data.mac->size_hint_flags |= XNegative;
+ else if (INTEGERP (left))
+ {
+ leftpos = XINT (left);
+ if (leftpos < 0)
+ f->output_data.mac->size_hint_flags |= XNegative;
+ }
+ else if (CONSP (left) && EQ (XCAR (left), Qminus)
+ && CONSP (XCDR (left))
+ && INTEGERP (XCAR (XCDR (left))))
+ {
+ leftpos = - XINT (XCAR (XCDR (left)));
+ f->output_data.mac->size_hint_flags |= XNegative;
+ }
+ else if (CONSP (left) && EQ (XCAR (left), Qplus)
+ && CONSP (XCDR (left))
+ && INTEGERP (XCAR (XCDR (left))))
+ {
+ leftpos = XINT (XCAR (XCDR (left)));
+ }
+
+ if (EQ (top, Qminus))
+ f->output_data.mac->size_hint_flags |= YNegative;
+ else if (INTEGERP (top))
+ {
+ toppos = XINT (top);
+ if (toppos < 0)
+ f->output_data.mac->size_hint_flags |= YNegative;
+ }
+ else if (CONSP (top) && EQ (XCAR (top), Qminus)
+ && CONSP (XCDR (top))
+ && INTEGERP (XCAR (XCDR (top))))
+ {
+ toppos = - XINT (XCAR (XCDR (top)));
+ f->output_data.mac->size_hint_flags |= YNegative;
+ }
+ else if (CONSP (top) && EQ (XCAR (top), Qplus)
+ && CONSP (XCDR (top))
+ && INTEGERP (XCAR (XCDR (top))))
+ {
+ toppos = XINT (XCAR (XCDR (top)));
+ }
+
+
+ /* Store the numeric value of the position. */
+ f->output_data.mac->top_pos = toppos;
+ f->output_data.mac->left_pos = leftpos;
+
+ f->output_data.mac->win_gravity = NorthWestGravity;
+
+ /* Actually set that position, and convert to absolute. */
+ x_set_offset (f, leftpos, toppos, -1);
+ }
+
+ if ((!NILP (icon_left) || !NILP (icon_top))
+ && ! (icon_left_no_change && icon_top_no_change))
+ x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
+ }
+
+ UNGCPRO;
+}
+
+/* Store the screen positions of frame F into XPTR and YPTR.
+ These are the positions of the containing window manager window,
+ not Emacs's own window. */
+
+void
+x_real_positions (f, xptr, yptr)
+ FRAME_PTR f;
+ int *xptr, *yptr;
+{
+ Point pt;
+ GrafPtr oldport;
+
+#ifdef TARGET_API_MAC_CARBON
+ {
+ Rect r;
+
+ GetWindowPortBounds (f->output_data.mac->mWP, &r);
+ SetPt (&pt, r.left, r.top);
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ SetPt (&pt,
+ f->output_data.mac->mWP->portRect.left,
+ f->output_data.mac->mWP->portRect.top);
+#endif /* not TARGET_API_MAC_CARBON */
+ GetPort (&oldport);
+ LocalToGlobal (&pt);
+ SetPort (oldport);
+
+ *xptr = pt.h;
+ *yptr = pt.v;
+}
+
+/* Insert a description of internally-recorded parameters of frame X
+ into the parameter alist *ALISTPTR that is to be given to the user.
+ Only parameters that are specific to Mac and whose values are not
+ correctly recorded in the frame's param_alist need to be considered
+ here. */
+
+void
+x_report_frame_params (f, alistptr)
+ struct frame *f;
+ Lisp_Object *alistptr;
+{
+ char buf[16];
+ Lisp_Object tem;
+
+ /* Represent negative positions (off the top or left screen edge)
+ in a way that Fmodify_frame_parameters will understand correctly. */
+ XSETINT (tem, f->output_data.mac->left_pos);
+ if (f->output_data.mac->left_pos >= 0)
+ store_in_alist (alistptr, Qleft, tem);
+ else
+ store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
+
+ XSETINT (tem, f->output_data.mac->top_pos);
+ if (f->output_data.mac->top_pos >= 0)
+ store_in_alist (alistptr, Qtop, tem);
+ else
+ store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
+
+ store_in_alist (alistptr, Qborder_width,
+ make_number (f->output_data.mac->border_width));
+ store_in_alist (alistptr, Qinternal_border_width,
+ make_number (f->output_data.mac->internal_border_width));
+ sprintf (buf, "%ld", (long) FRAME_MAC_WINDOW (f));
+ store_in_alist (alistptr, Qwindow_id,
+ build_string (buf));
+ store_in_alist (alistptr, Qicon_name, f->icon_name);
+ FRAME_SAMPLE_VISIBILITY (f);
+ store_in_alist (alistptr, Qvisibility,
+ (FRAME_VISIBLE_P (f) ? Qt
+ : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
+ store_in_alist (alistptr, Qdisplay,
+ XCAR (FRAME_MAC_DISPLAY_INFO (f)->name_list_element));
+}
+
+/* The default colors for the Mac color map */
+typedef struct colormap_t
+{
+ unsigned long color;
+ char *name;
+} colormap_t;
+
+colormap_t mac_color_map[] =
+{
+ { RGB_TO_ULONG(255, 250, 250), "snow" },
+ { RGB_TO_ULONG(248, 248, 255), "ghost white" },
+ { RGB_TO_ULONG(248, 248, 255), "GhostWhite" },
+ { RGB_TO_ULONG(245, 245, 245), "white smoke" },
+ { RGB_TO_ULONG(245, 245, 245), "WhiteSmoke" },
+ { RGB_TO_ULONG(220, 220, 220), "gainsboro" },
+ { RGB_TO_ULONG(255, 250, 240), "floral white" },
+ { RGB_TO_ULONG(255, 250, 240), "FloralWhite" },
+ { RGB_TO_ULONG(253, 245, 230), "old lace" },
+ { RGB_TO_ULONG(253, 245, 230), "OldLace" },
+ { RGB_TO_ULONG(250, 240, 230), "linen" },
+ { RGB_TO_ULONG(250, 235, 215), "antique white" },
+ { RGB_TO_ULONG(250, 235, 215), "AntiqueWhite" },
+ { RGB_TO_ULONG(255, 239, 213), "papaya whip" },
+ { RGB_TO_ULONG(255, 239, 213), "PapayaWhip" },
+ { RGB_TO_ULONG(255, 235, 205), "blanched almond" },
+ { RGB_TO_ULONG(255, 235, 205), "BlanchedAlmond" },
+ { RGB_TO_ULONG(255, 228, 196), "bisque" },
+ { RGB_TO_ULONG(255, 218, 185), "peach puff" },
+ { RGB_TO_ULONG(255, 218, 185), "PeachPuff" },
+ { RGB_TO_ULONG(255, 222, 173), "navajo white" },
+ { RGB_TO_ULONG(255, 222, 173), "NavajoWhite" },
+ { RGB_TO_ULONG(255, 228, 181), "moccasin" },
+ { RGB_TO_ULONG(255, 248, 220), "cornsilk" },
+ { RGB_TO_ULONG(255, 255, 240), "ivory" },
+ { RGB_TO_ULONG(255, 250, 205), "lemon chiffon" },
+ { RGB_TO_ULONG(255, 250, 205), "LemonChiffon" },
+ { RGB_TO_ULONG(255, 245, 238), "seashell" },
+ { RGB_TO_ULONG(240, 255, 240), "honeydew" },
+ { RGB_TO_ULONG(245, 255, 250), "mint cream" },
+ { RGB_TO_ULONG(245, 255, 250), "MintCream" },
+ { RGB_TO_ULONG(240, 255, 255), "azure" },
+ { RGB_TO_ULONG(240, 248, 255), "alice blue" },
+ { RGB_TO_ULONG(240, 248, 255), "AliceBlue" },
+ { RGB_TO_ULONG(230, 230, 250), "lavender" },
+ { RGB_TO_ULONG(255, 240, 245), "lavender blush" },
+ { RGB_TO_ULONG(255, 240, 245), "LavenderBlush" },
+ { RGB_TO_ULONG(255, 228, 225), "misty rose" },
+ { RGB_TO_ULONG(255, 228, 225), "MistyRose" },
+ { RGB_TO_ULONG(255, 255, 255), "white" },
+ { RGB_TO_ULONG(0 , 0 , 0 ), "black" },
+ { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate gray" },
+ { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGray" },
+ { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate grey" },
+ { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGrey" },
+ { RGB_TO_ULONG(105, 105, 105), "dim gray" },
+ { RGB_TO_ULONG(105, 105, 105), "DimGray" },
+ { RGB_TO_ULONG(105, 105, 105), "dim grey" },
+ { RGB_TO_ULONG(105, 105, 105), "DimGrey" },
+ { RGB_TO_ULONG(112, 128, 144), "slate gray" },
+ { RGB_TO_ULONG(112, 128, 144), "SlateGray" },
+ { RGB_TO_ULONG(112, 128, 144), "slate grey" },
+ { RGB_TO_ULONG(112, 128, 144), "SlateGrey" },
+ { RGB_TO_ULONG(119, 136, 153), "light slate gray" },
+ { RGB_TO_ULONG(119, 136, 153), "LightSlateGray" },
+ { RGB_TO_ULONG(119, 136, 153), "light slate grey" },
+ { RGB_TO_ULONG(119, 136, 153), "LightSlateGrey" },
+ { RGB_TO_ULONG(190, 190, 190), "gray" },
+ { RGB_TO_ULONG(190, 190, 190), "grey" },
+ { RGB_TO_ULONG(211, 211, 211), "light grey" },
+ { RGB_TO_ULONG(211, 211, 211), "LightGrey" },
+ { RGB_TO_ULONG(211, 211, 211), "light gray" },
+ { RGB_TO_ULONG(211, 211, 211), "LightGray" },
+ { RGB_TO_ULONG(25 , 25 , 112), "midnight blue" },
+ { RGB_TO_ULONG(25 , 25 , 112), "MidnightBlue" },
+ { RGB_TO_ULONG(0 , 0 , 128), "navy" },
+ { RGB_TO_ULONG(0 , 0 , 128), "navy blue" },
+ { RGB_TO_ULONG(0 , 0 , 128), "NavyBlue" },
+ { RGB_TO_ULONG(100, 149, 237), "cornflower blue" },
+ { RGB_TO_ULONG(100, 149, 237), "CornflowerBlue" },
+ { RGB_TO_ULONG(72 , 61 , 139), "dark slate blue" },
+ { RGB_TO_ULONG(72 , 61 , 139), "DarkSlateBlue" },
+ { RGB_TO_ULONG(106, 90 , 205), "slate blue" },
+ { RGB_TO_ULONG(106, 90 , 205), "SlateBlue" },
+ { RGB_TO_ULONG(123, 104, 238), "medium slate blue" },
+ { RGB_TO_ULONG(123, 104, 238), "MediumSlateBlue" },
+ { RGB_TO_ULONG(132, 112, 255), "light slate blue" },
+ { RGB_TO_ULONG(132, 112, 255), "LightSlateBlue" },
+ { RGB_TO_ULONG(0 , 0 , 205), "medium blue" },
+ { RGB_TO_ULONG(0 , 0 , 205), "MediumBlue" },
+ { RGB_TO_ULONG(65 , 105, 225), "royal blue" },
+ { RGB_TO_ULONG(65 , 105, 225), "RoyalBlue" },
+ { RGB_TO_ULONG(0 , 0 , 255), "blue" },
+ { RGB_TO_ULONG(30 , 144, 255), "dodger blue" },
+ { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue" },
+ { RGB_TO_ULONG(0 , 191, 255), "deep sky blue" },
+ { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue" },
+ { RGB_TO_ULONG(135, 206, 235), "sky blue" },
+ { RGB_TO_ULONG(135, 206, 235), "SkyBlue" },
+ { RGB_TO_ULONG(135, 206, 250), "light sky blue" },
+ { RGB_TO_ULONG(135, 206, 250), "LightSkyBlue" },
+ { RGB_TO_ULONG(70 , 130, 180), "steel blue" },
+ { RGB_TO_ULONG(70 , 130, 180), "SteelBlue" },
+ { RGB_TO_ULONG(176, 196, 222), "light steel blue" },
+ { RGB_TO_ULONG(176, 196, 222), "LightSteelBlue" },
+ { RGB_TO_ULONG(173, 216, 230), "light blue" },
+ { RGB_TO_ULONG(173, 216, 230), "LightBlue" },
+ { RGB_TO_ULONG(176, 224, 230), "powder blue" },
+ { RGB_TO_ULONG(176, 224, 230), "PowderBlue" },
+ { RGB_TO_ULONG(175, 238, 238), "pale turquoise" },
+ { RGB_TO_ULONG(175, 238, 238), "PaleTurquoise" },
+ { RGB_TO_ULONG(0 , 206, 209), "dark turquoise" },
+ { RGB_TO_ULONG(0 , 206, 209), "DarkTurquoise" },
+ { RGB_TO_ULONG(72 , 209, 204), "medium turquoise" },
+ { RGB_TO_ULONG(72 , 209, 204), "MediumTurquoise" },
+ { RGB_TO_ULONG(64 , 224, 208), "turquoise" },
+ { RGB_TO_ULONG(0 , 255, 255), "cyan" },
+ { RGB_TO_ULONG(224, 255, 255), "light cyan" },
+ { RGB_TO_ULONG(224, 255, 255), "LightCyan" },
+ { RGB_TO_ULONG(95 , 158, 160), "cadet blue" },
+ { RGB_TO_ULONG(95 , 158, 160), "CadetBlue" },
+ { RGB_TO_ULONG(102, 205, 170), "medium aquamarine" },
+ { RGB_TO_ULONG(102, 205, 170), "MediumAquamarine" },
+ { RGB_TO_ULONG(127, 255, 212), "aquamarine" },
+ { RGB_TO_ULONG(0 , 100, 0 ), "dark green" },
+ { RGB_TO_ULONG(0 , 100, 0 ), "DarkGreen" },
+ { RGB_TO_ULONG(85 , 107, 47 ), "dark olive green" },
+ { RGB_TO_ULONG(85 , 107, 47 ), "DarkOliveGreen" },
+ { RGB_TO_ULONG(143, 188, 143), "dark sea green" },
+ { RGB_TO_ULONG(143, 188, 143), "DarkSeaGreen" },
+ { RGB_TO_ULONG(46 , 139, 87 ), "sea green" },
+ { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen" },
+ { RGB_TO_ULONG(60 , 179, 113), "medium sea green" },
+ { RGB_TO_ULONG(60 , 179, 113), "MediumSeaGreen" },
+ { RGB_TO_ULONG(32 , 178, 170), "light sea green" },
+ { RGB_TO_ULONG(32 , 178, 170), "LightSeaGreen" },
+ { RGB_TO_ULONG(152, 251, 152), "pale green" },
+ { RGB_TO_ULONG(152, 251, 152), "PaleGreen" },
+ { RGB_TO_ULONG(0 , 255, 127), "spring green" },
+ { RGB_TO_ULONG(0 , 255, 127), "SpringGreen" },
+ { RGB_TO_ULONG(124, 252, 0 ), "lawn green" },
+ { RGB_TO_ULONG(124, 252, 0 ), "LawnGreen" },
+ { RGB_TO_ULONG(0 , 255, 0 ), "green" },
+ { RGB_TO_ULONG(127, 255, 0 ), "chartreuse" },
+ { RGB_TO_ULONG(0 , 250, 154), "medium spring green" },
+ { RGB_TO_ULONG(0 , 250, 154), "MediumSpringGreen" },
+ { RGB_TO_ULONG(173, 255, 47 ), "green yellow" },
+ { RGB_TO_ULONG(173, 255, 47 ), "GreenYellow" },
+ { RGB_TO_ULONG(50 , 205, 50 ), "lime green" },
+ { RGB_TO_ULONG(50 , 205, 50 ), "LimeGreen" },
+ { RGB_TO_ULONG(154, 205, 50 ), "yellow green" },
+ { RGB_TO_ULONG(154, 205, 50 ), "YellowGreen" },
+ { RGB_TO_ULONG(34 , 139, 34 ), "forest green" },
+ { RGB_TO_ULONG(34 , 139, 34 ), "ForestGreen" },
+ { RGB_TO_ULONG(107, 142, 35 ), "olive drab" },
+ { RGB_TO_ULONG(107, 142, 35 ), "OliveDrab" },
+ { RGB_TO_ULONG(189, 183, 107), "dark khaki" },
+ { RGB_TO_ULONG(189, 183, 107), "DarkKhaki" },
+ { RGB_TO_ULONG(240, 230, 140), "khaki" },
+ { RGB_TO_ULONG(238, 232, 170), "pale goldenrod" },
+ { RGB_TO_ULONG(238, 232, 170), "PaleGoldenrod" },
+ { RGB_TO_ULONG(250, 250, 210), "light goldenrod yellow" },
+ { RGB_TO_ULONG(250, 250, 210), "LightGoldenrodYellow" },
+ { RGB_TO_ULONG(255, 255, 224), "light yellow" },
+ { RGB_TO_ULONG(255, 255, 224), "LightYellow" },
+ { RGB_TO_ULONG(255, 255, 0 ), "yellow" },
+ { RGB_TO_ULONG(255, 215, 0 ), "gold" },
+ { RGB_TO_ULONG(238, 221, 130), "light goldenrod" },
+ { RGB_TO_ULONG(238, 221, 130), "LightGoldenrod" },
+ { RGB_TO_ULONG(218, 165, 32 ), "goldenrod" },
+ { RGB_TO_ULONG(184, 134, 11 ), "dark goldenrod" },
+ { RGB_TO_ULONG(184, 134, 11 ), "DarkGoldenrod" },
+ { RGB_TO_ULONG(188, 143, 143), "rosy brown" },
+ { RGB_TO_ULONG(188, 143, 143), "RosyBrown" },
+ { RGB_TO_ULONG(205, 92 , 92 ), "indian red" },
+ { RGB_TO_ULONG(205, 92 , 92 ), "IndianRed" },
+ { RGB_TO_ULONG(139, 69 , 19 ), "saddle brown" },
+ { RGB_TO_ULONG(139, 69 , 19 ), "SaddleBrown" },
+ { RGB_TO_ULONG(160, 82 , 45 ), "sienna" },
+ { RGB_TO_ULONG(205, 133, 63 ), "peru" },
+ { RGB_TO_ULONG(222, 184, 135), "burlywood" },
+ { RGB_TO_ULONG(245, 245, 220), "beige" },
+ { RGB_TO_ULONG(245, 222, 179), "wheat" },
+ { RGB_TO_ULONG(244, 164, 96 ), "sandy brown" },
+ { RGB_TO_ULONG(244, 164, 96 ), "SandyBrown" },
+ { RGB_TO_ULONG(210, 180, 140), "tan" },
+ { RGB_TO_ULONG(210, 105, 30 ), "chocolate" },
+ { RGB_TO_ULONG(178, 34 , 34 ), "firebrick" },
+ { RGB_TO_ULONG(165, 42 , 42 ), "brown" },
+ { RGB_TO_ULONG(233, 150, 122), "dark salmon" },
+ { RGB_TO_ULONG(233, 150, 122), "DarkSalmon" },
+ { RGB_TO_ULONG(250, 128, 114), "salmon" },
+ { RGB_TO_ULONG(255, 160, 122), "light salmon" },
+ { RGB_TO_ULONG(255, 160, 122), "LightSalmon" },
+ { RGB_TO_ULONG(255, 165, 0 ), "orange" },
+ { RGB_TO_ULONG(255, 140, 0 ), "dark orange" },
+ { RGB_TO_ULONG(255, 140, 0 ), "DarkOrange" },
+ { RGB_TO_ULONG(255, 127, 80 ), "coral" },
+ { RGB_TO_ULONG(240, 128, 128), "light coral" },
+ { RGB_TO_ULONG(240, 128, 128), "LightCoral" },
+ { RGB_TO_ULONG(255, 99 , 71 ), "tomato" },
+ { RGB_TO_ULONG(255, 69 , 0 ), "orange red" },
+ { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed" },
+ { RGB_TO_ULONG(255, 0 , 0 ), "red" },
+ { RGB_TO_ULONG(255, 105, 180), "hot pink" },
+ { RGB_TO_ULONG(255, 105, 180), "HotPink" },
+ { RGB_TO_ULONG(255, 20 , 147), "deep pink" },
+ { RGB_TO_ULONG(255, 20 , 147), "DeepPink" },
+ { RGB_TO_ULONG(255, 192, 203), "pink" },
+ { RGB_TO_ULONG(255, 182, 193), "light pink" },
+ { RGB_TO_ULONG(255, 182, 193), "LightPink" },
+ { RGB_TO_ULONG(219, 112, 147), "pale violet red" },
+ { RGB_TO_ULONG(219, 112, 147), "PaleVioletRed" },
+ { RGB_TO_ULONG(176, 48 , 96 ), "maroon" },
+ { RGB_TO_ULONG(199, 21 , 133), "medium violet red" },
+ { RGB_TO_ULONG(199, 21 , 133), "MediumVioletRed" },
+ { RGB_TO_ULONG(208, 32 , 144), "violet red" },
+ { RGB_TO_ULONG(208, 32 , 144), "VioletRed" },
+ { RGB_TO_ULONG(255, 0 , 255), "magenta" },
+ { RGB_TO_ULONG(238, 130, 238), "violet" },
+ { RGB_TO_ULONG(221, 160, 221), "plum" },
+ { RGB_TO_ULONG(218, 112, 214), "orchid" },
+ { RGB_TO_ULONG(186, 85 , 211), "medium orchid" },
+ { RGB_TO_ULONG(186, 85 , 211), "MediumOrchid" },
+ { RGB_TO_ULONG(153, 50 , 204), "dark orchid" },
+ { RGB_TO_ULONG(153, 50 , 204), "DarkOrchid" },
+ { RGB_TO_ULONG(148, 0 , 211), "dark violet" },
+ { RGB_TO_ULONG(148, 0 , 211), "DarkViolet" },
+ { RGB_TO_ULONG(138, 43 , 226), "blue violet" },
+ { RGB_TO_ULONG(138, 43 , 226), "BlueViolet" },
+ { RGB_TO_ULONG(160, 32 , 240), "purple" },
+ { RGB_TO_ULONG(147, 112, 219), "medium purple" },
+ { RGB_TO_ULONG(147, 112, 219), "MediumPurple" },
+ { RGB_TO_ULONG(216, 191, 216), "thistle" },
+ { RGB_TO_ULONG(255, 250, 250), "snow1" },
+ { RGB_TO_ULONG(238, 233, 233), "snow2" },
+ { RGB_TO_ULONG(205, 201, 201), "snow3" },
+ { RGB_TO_ULONG(139, 137, 137), "snow4" },
+ { RGB_TO_ULONG(255, 245, 238), "seashell1" },
+ { RGB_TO_ULONG(238, 229, 222), "seashell2" },
+ { RGB_TO_ULONG(205, 197, 191), "seashell3" },
+ { RGB_TO_ULONG(139, 134, 130), "seashell4" },
+ { RGB_TO_ULONG(255, 239, 219), "AntiqueWhite1" },
+ { RGB_TO_ULONG(238, 223, 204), "AntiqueWhite2" },
+ { RGB_TO_ULONG(205, 192, 176), "AntiqueWhite3" },
+ { RGB_TO_ULONG(139, 131, 120), "AntiqueWhite4" },
+ { RGB_TO_ULONG(255, 228, 196), "bisque1" },
+ { RGB_TO_ULONG(238, 213, 183), "bisque2" },
+ { RGB_TO_ULONG(205, 183, 158), "bisque3" },
+ { RGB_TO_ULONG(139, 125, 107), "bisque4" },
+ { RGB_TO_ULONG(255, 218, 185), "PeachPuff1" },
+ { RGB_TO_ULONG(238, 203, 173), "PeachPuff2" },
+ { RGB_TO_ULONG(205, 175, 149), "PeachPuff3" },
+ { RGB_TO_ULONG(139, 119, 101), "PeachPuff4" },
+ { RGB_TO_ULONG(255, 222, 173), "NavajoWhite1" },
+ { RGB_TO_ULONG(238, 207, 161), "NavajoWhite2" },
+ { RGB_TO_ULONG(205, 179, 139), "NavajoWhite3" },
+ { RGB_TO_ULONG(139, 121, 94), "NavajoWhite4" },
+ { RGB_TO_ULONG(255, 250, 205), "LemonChiffon1" },
+ { RGB_TO_ULONG(238, 233, 191), "LemonChiffon2" },
+ { RGB_TO_ULONG(205, 201, 165), "LemonChiffon3" },
+ { RGB_TO_ULONG(139, 137, 112), "LemonChiffon4" },
+ { RGB_TO_ULONG(255, 248, 220), "cornsilk1" },
+ { RGB_TO_ULONG(238, 232, 205), "cornsilk2" },
+ { RGB_TO_ULONG(205, 200, 177), "cornsilk3" },
+ { RGB_TO_ULONG(139, 136, 120), "cornsilk4" },
+ { RGB_TO_ULONG(255, 255, 240), "ivory1" },
+ { RGB_TO_ULONG(238, 238, 224), "ivory2" },
+ { RGB_TO_ULONG(205, 205, 193), "ivory3" },
+ { RGB_TO_ULONG(139, 139, 131), "ivory4" },
+ { RGB_TO_ULONG(240, 255, 240), "honeydew1" },
+ { RGB_TO_ULONG(224, 238, 224), "honeydew2" },
+ { RGB_TO_ULONG(193, 205, 193), "honeydew3" },
+ { RGB_TO_ULONG(131, 139, 131), "honeydew4" },
+ { RGB_TO_ULONG(255, 240, 245), "LavenderBlush1" },
+ { RGB_TO_ULONG(238, 224, 229), "LavenderBlush2" },
+ { RGB_TO_ULONG(205, 193, 197), "LavenderBlush3" },
+ { RGB_TO_ULONG(139, 131, 134), "LavenderBlush4" },
+ { RGB_TO_ULONG(255, 228, 225), "MistyRose1" },
+ { RGB_TO_ULONG(238, 213, 210), "MistyRose2" },
+ { RGB_TO_ULONG(205, 183, 181), "MistyRose3" },
+ { RGB_TO_ULONG(139, 125, 123), "MistyRose4" },
+ { RGB_TO_ULONG(240, 255, 255), "azure1" },
+ { RGB_TO_ULONG(224, 238, 238), "azure2" },
+ { RGB_TO_ULONG(193, 205, 205), "azure3" },
+ { RGB_TO_ULONG(131, 139, 139), "azure4" },
+ { RGB_TO_ULONG(131, 111, 255), "SlateBlue1" },
+ { RGB_TO_ULONG(122, 103, 238), "SlateBlue2" },
+ { RGB_TO_ULONG(105, 89 , 205), "SlateBlue3" },
+ { RGB_TO_ULONG(71 , 60 , 139), "SlateBlue4" },
+ { RGB_TO_ULONG(72 , 118, 255), "RoyalBlue1" },
+ { RGB_TO_ULONG(67 , 110, 238), "RoyalBlue2" },
+ { RGB_TO_ULONG(58 , 95 , 205), "RoyalBlue3" },
+ { RGB_TO_ULONG(39 , 64 , 139), "RoyalBlue4" },
+ { RGB_TO_ULONG(0 , 0 , 255), "blue1" },
+ { RGB_TO_ULONG(0 , 0 , 238), "blue2" },
+ { RGB_TO_ULONG(0 , 0 , 205), "blue3" },
+ { RGB_TO_ULONG(0 , 0 , 139), "blue4" },
+ { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue1" },
+ { RGB_TO_ULONG(28 , 134, 238), "DodgerBlue2" },
+ { RGB_TO_ULONG(24 , 116, 205), "DodgerBlue3" },
+ { RGB_TO_ULONG(16 , 78 , 139), "DodgerBlue4" },
+ { RGB_TO_ULONG(99 , 184, 255), "SteelBlue1" },
+ { RGB_TO_ULONG(92 , 172, 238), "SteelBlue2" },
+ { RGB_TO_ULONG(79 , 148, 205), "SteelBlue3" },
+ { RGB_TO_ULONG(54 , 100, 139), "SteelBlue4" },
+ { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue1" },
+ { RGB_TO_ULONG(0 , 178, 238), "DeepSkyBlue2" },
+ { RGB_TO_ULONG(0 , 154, 205), "DeepSkyBlue3" },
+ { RGB_TO_ULONG(0 , 104, 139), "DeepSkyBlue4" },
+ { RGB_TO_ULONG(135, 206, 255), "SkyBlue1" },
+ { RGB_TO_ULONG(126, 192, 238), "SkyBlue2" },
+ { RGB_TO_ULONG(108, 166, 205), "SkyBlue3" },
+ { RGB_TO_ULONG(74 , 112, 139), "SkyBlue4" },
+ { RGB_TO_ULONG(176, 226, 255), "LightSkyBlue1" },
+ { RGB_TO_ULONG(164, 211, 238), "LightSkyBlue2" },
+ { RGB_TO_ULONG(141, 182, 205), "LightSkyBlue3" },
+ { RGB_TO_ULONG(96 , 123, 139), "LightSkyBlue4" },
+ { RGB_TO_ULONG(198, 226, 255), "SlateGray1" },
+ { RGB_TO_ULONG(185, 211, 238), "SlateGray2" },
+ { RGB_TO_ULONG(159, 182, 205), "SlateGray3" },
+ { RGB_TO_ULONG(108, 123, 139), "SlateGray4" },
+ { RGB_TO_ULONG(202, 225, 255), "LightSteelBlue1" },
+ { RGB_TO_ULONG(188, 210, 238), "LightSteelBlue2" },
+ { RGB_TO_ULONG(162, 181, 205), "LightSteelBlue3" },
+ { RGB_TO_ULONG(110, 123, 139), "LightSteelBlue4" },
+ { RGB_TO_ULONG(191, 239, 255), "LightBlue1" },
+ { RGB_TO_ULONG(178, 223, 238), "LightBlue2" },
+ { RGB_TO_ULONG(154, 192, 205), "LightBlue3" },
+ { RGB_TO_ULONG(104, 131, 139), "LightBlue4" },
+ { RGB_TO_ULONG(224, 255, 255), "LightCyan1" },
+ { RGB_TO_ULONG(209, 238, 238), "LightCyan2" },
+ { RGB_TO_ULONG(180, 205, 205), "LightCyan3" },
+ { RGB_TO_ULONG(122, 139, 139), "LightCyan4" },
+ { RGB_TO_ULONG(187, 255, 255), "PaleTurquoise1" },
+ { RGB_TO_ULONG(174, 238, 238), "PaleTurquoise2" },
+ { RGB_TO_ULONG(150, 205, 205), "PaleTurquoise3" },
+ { RGB_TO_ULONG(102, 139, 139), "PaleTurquoise4" },
+ { RGB_TO_ULONG(152, 245, 255), "CadetBlue1" },
+ { RGB_TO_ULONG(142, 229, 238), "CadetBlue2" },
+ { RGB_TO_ULONG(122, 197, 205), "CadetBlue3" },
+ { RGB_TO_ULONG(83 , 134, 139), "CadetBlue4" },
+ { RGB_TO_ULONG(0 , 245, 255), "turquoise1" },
+ { RGB_TO_ULONG(0 , 229, 238), "turquoise2" },
+ { RGB_TO_ULONG(0 , 197, 205), "turquoise3" },
+ { RGB_TO_ULONG(0 , 134, 139), "turquoise4" },
+ { RGB_TO_ULONG(0 , 255, 255), "cyan1" },
+ { RGB_TO_ULONG(0 , 238, 238), "cyan2" },
+ { RGB_TO_ULONG(0 , 205, 205), "cyan3" },
+ { RGB_TO_ULONG(0 , 139, 139), "cyan4" },
+ { RGB_TO_ULONG(151, 255, 255), "DarkSlateGray1" },
+ { RGB_TO_ULONG(141, 238, 238), "DarkSlateGray2" },
+ { RGB_TO_ULONG(121, 205, 205), "DarkSlateGray3" },
+ { RGB_TO_ULONG(82 , 139, 139), "DarkSlateGray4" },
+ { RGB_TO_ULONG(127, 255, 212), "aquamarine1" },
+ { RGB_TO_ULONG(118, 238, 198), "aquamarine2" },
+ { RGB_TO_ULONG(102, 205, 170), "aquamarine3" },
+ { RGB_TO_ULONG(69 , 139, 116), "aquamarine4" },
+ { RGB_TO_ULONG(193, 255, 193), "DarkSeaGreen1" },
+ { RGB_TO_ULONG(180, 238, 180), "DarkSeaGreen2" },
+ { RGB_TO_ULONG(155, 205, 155), "DarkSeaGreen3" },
+ { RGB_TO_ULONG(105, 139, 105), "DarkSeaGreen4" },
+ { RGB_TO_ULONG(84 , 255, 159), "SeaGreen1" },
+ { RGB_TO_ULONG(78 , 238, 148), "SeaGreen2" },
+ { RGB_TO_ULONG(67 , 205, 128), "SeaGreen3" },
+ { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen4" },
+ { RGB_TO_ULONG(154, 255, 154), "PaleGreen1" },
+ { RGB_TO_ULONG(144, 238, 144), "PaleGreen2" },
+ { RGB_TO_ULONG(124, 205, 124), "PaleGreen3" },
+ { RGB_TO_ULONG(84 , 139, 84 ), "PaleGreen4" },
+ { RGB_TO_ULONG(0 , 255, 127), "SpringGreen1" },
+ { RGB_TO_ULONG(0 , 238, 118), "SpringGreen2" },
+ { RGB_TO_ULONG(0 , 205, 102), "SpringGreen3" },
+ { RGB_TO_ULONG(0 , 139, 69 ), "SpringGreen4" },
+ { RGB_TO_ULONG(0 , 255, 0 ), "green1" },
+ { RGB_TO_ULONG(0 , 238, 0 ), "green2" },
+ { RGB_TO_ULONG(0 , 205, 0 ), "green3" },
+ { RGB_TO_ULONG(0 , 139, 0 ), "green4" },
+ { RGB_TO_ULONG(127, 255, 0 ), "chartreuse1" },
+ { RGB_TO_ULONG(118, 238, 0 ), "chartreuse2" },
+ { RGB_TO_ULONG(102, 205, 0 ), "chartreuse3" },
+ { RGB_TO_ULONG(69 , 139, 0 ), "chartreuse4" },
+ { RGB_TO_ULONG(192, 255, 62 ), "OliveDrab1" },
+ { RGB_TO_ULONG(179, 238, 58 ), "OliveDrab2" },
+ { RGB_TO_ULONG(154, 205, 50 ), "OliveDrab3" },
+ { RGB_TO_ULONG(105, 139, 34 ), "OliveDrab4" },
+ { RGB_TO_ULONG(202, 255, 112), "DarkOliveGreen1" },
+ { RGB_TO_ULONG(188, 238, 104), "DarkOliveGreen2" },
+ { RGB_TO_ULONG(162, 205, 90 ), "DarkOliveGreen3" },
+ { RGB_TO_ULONG(110, 139, 61 ), "DarkOliveGreen4" },
+ { RGB_TO_ULONG(255, 246, 143), "khaki1" },
+ { RGB_TO_ULONG(238, 230, 133), "khaki2" },
+ { RGB_TO_ULONG(205, 198, 115), "khaki3" },
+ { RGB_TO_ULONG(139, 134, 78 ), "khaki4" },
+ { RGB_TO_ULONG(255, 236, 139), "LightGoldenrod1" },
+ { RGB_TO_ULONG(238, 220, 130), "LightGoldenrod2" },
+ { RGB_TO_ULONG(205, 190, 112), "LightGoldenrod3" },
+ { RGB_TO_ULONG(139, 129, 76 ), "LightGoldenrod4" },
+ { RGB_TO_ULONG(255, 255, 224), "LightYellow1" },
+ { RGB_TO_ULONG(238, 238, 209), "LightYellow2" },
+ { RGB_TO_ULONG(205, 205, 180), "LightYellow3" },
+ { RGB_TO_ULONG(139, 139, 122), "LightYellow4" },
+ { RGB_TO_ULONG(255, 255, 0 ), "yellow1" },
+ { RGB_TO_ULONG(238, 238, 0 ), "yellow2" },
+ { RGB_TO_ULONG(205, 205, 0 ), "yellow3" },
+ { RGB_TO_ULONG(139, 139, 0 ), "yellow4" },
+ { RGB_TO_ULONG(255, 215, 0 ), "gold1" },
+ { RGB_TO_ULONG(238, 201, 0 ), "gold2" },
+ { RGB_TO_ULONG(205, 173, 0 ), "gold3" },
+ { RGB_TO_ULONG(139, 117, 0 ), "gold4" },
+ { RGB_TO_ULONG(255, 193, 37 ), "goldenrod1" },
+ { RGB_TO_ULONG(238, 180, 34 ), "goldenrod2" },
+ { RGB_TO_ULONG(205, 155, 29 ), "goldenrod3" },
+ { RGB_TO_ULONG(139, 105, 20 ), "goldenrod4" },
+ { RGB_TO_ULONG(255, 185, 15 ), "DarkGoldenrod1" },
+ { RGB_TO_ULONG(238, 173, 14 ), "DarkGoldenrod2" },
+ { RGB_TO_ULONG(205, 149, 12 ), "DarkGoldenrod3" },
+ { RGB_TO_ULONG(139, 101, 8 ), "DarkGoldenrod4" },
+ { RGB_TO_ULONG(255, 193, 193), "RosyBrown1" },
+ { RGB_TO_ULONG(238, 180, 180), "RosyBrown2" },
+ { RGB_TO_ULONG(205, 155, 155), "RosyBrown3" },
+ { RGB_TO_ULONG(139, 105, 105), "RosyBrown4" },
+ { RGB_TO_ULONG(255, 106, 106), "IndianRed1" },
+ { RGB_TO_ULONG(238, 99 , 99 ), "IndianRed2" },
+ { RGB_TO_ULONG(205, 85 , 85 ), "IndianRed3" },
+ { RGB_TO_ULONG(139, 58 , 58 ), "IndianRed4" },
+ { RGB_TO_ULONG(255, 130, 71 ), "sienna1" },
+ { RGB_TO_ULONG(238, 121, 66 ), "sienna2" },
+ { RGB_TO_ULONG(205, 104, 57 ), "sienna3" },
+ { RGB_TO_ULONG(139, 71 , 38 ), "sienna4" },
+ { RGB_TO_ULONG(255, 211, 155), "burlywood1" },
+ { RGB_TO_ULONG(238, 197, 145), "burlywood2" },
+ { RGB_TO_ULONG(205, 170, 125), "burlywood3" },
+ { RGB_TO_ULONG(139, 115, 85 ), "burlywood4" },
+ { RGB_TO_ULONG(255, 231, 186), "wheat1" },
+ { RGB_TO_ULONG(238, 216, 174), "wheat2" },
+ { RGB_TO_ULONG(205, 186, 150), "wheat3" },
+ { RGB_TO_ULONG(139, 126, 102), "wheat4" },
+ { RGB_TO_ULONG(255, 165, 79 ), "tan1" },
+ { RGB_TO_ULONG(238, 154, 73 ), "tan2" },
+ { RGB_TO_ULONG(205, 133, 63 ), "tan3" },
+ { RGB_TO_ULONG(139, 90 , 43 ), "tan4" },
+ { RGB_TO_ULONG(255, 127, 36 ), "chocolate1" },
+ { RGB_TO_ULONG(238, 118, 33 ), "chocolate2" },
+ { RGB_TO_ULONG(205, 102, 29 ), "chocolate3" },
+ { RGB_TO_ULONG(139, 69 , 19 ), "chocolate4" },
+ { RGB_TO_ULONG(255, 48 , 48 ), "firebrick1" },
+ { RGB_TO_ULONG(238, 44 , 44 ), "firebrick2" },
+ { RGB_TO_ULONG(205, 38 , 38 ), "firebrick3" },
+ { RGB_TO_ULONG(139, 26 , 26 ), "firebrick4" },
+ { RGB_TO_ULONG(255, 64 , 64 ), "brown1" },
+ { RGB_TO_ULONG(238, 59 , 59 ), "brown2" },
+ { RGB_TO_ULONG(205, 51 , 51 ), "brown3" },
+ { RGB_TO_ULONG(139, 35 , 35 ), "brown4" },
+ { RGB_TO_ULONG(255, 140, 105), "salmon1" },
+ { RGB_TO_ULONG(238, 130, 98 ), "salmon2" },
+ { RGB_TO_ULONG(205, 112, 84 ), "salmon3" },
+ { RGB_TO_ULONG(139, 76 , 57 ), "salmon4" },
+ { RGB_TO_ULONG(255, 160, 122), "LightSalmon1" },
+ { RGB_TO_ULONG(238, 149, 114), "LightSalmon2" },
+ { RGB_TO_ULONG(205, 129, 98 ), "LightSalmon3" },
+ { RGB_TO_ULONG(139, 87 , 66 ), "LightSalmon4" },
+ { RGB_TO_ULONG(255, 165, 0 ), "orange1" },
+ { RGB_TO_ULONG(238, 154, 0 ), "orange2" },
+ { RGB_TO_ULONG(205, 133, 0 ), "orange3" },
+ { RGB_TO_ULONG(139, 90 , 0 ), "orange4" },
+ { RGB_TO_ULONG(255, 127, 0 ), "DarkOrange1" },
+ { RGB_TO_ULONG(238, 118, 0 ), "DarkOrange2" },
+ { RGB_TO_ULONG(205, 102, 0 ), "DarkOrange3" },
+ { RGB_TO_ULONG(139, 69 , 0 ), "DarkOrange4" },
+ { RGB_TO_ULONG(255, 114, 86 ), "coral1" },
+ { RGB_TO_ULONG(238, 106, 80 ), "coral2" },
+ { RGB_TO_ULONG(205, 91 , 69 ), "coral3" },
+ { RGB_TO_ULONG(139, 62 , 47 ), "coral4" },
+ { RGB_TO_ULONG(255, 99 , 71 ), "tomato1" },
+ { RGB_TO_ULONG(238, 92 , 66 ), "tomato2" },
+ { RGB_TO_ULONG(205, 79 , 57 ), "tomato3" },
+ { RGB_TO_ULONG(139, 54 , 38 ), "tomato4" },
+ { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed1" },
+ { RGB_TO_ULONG(238, 64 , 0 ), "OrangeRed2" },
+ { RGB_TO_ULONG(205, 55 , 0 ), "OrangeRed3" },
+ { RGB_TO_ULONG(139, 37 , 0 ), "OrangeRed4" },
+ { RGB_TO_ULONG(255, 0 , 0 ), "red1" },
+ { RGB_TO_ULONG(238, 0 , 0 ), "red2" },
+ { RGB_TO_ULONG(205, 0 , 0 ), "red3" },
+ { RGB_TO_ULONG(139, 0 , 0 ), "red4" },
+ { RGB_TO_ULONG(255, 20 , 147), "DeepPink1" },
+ { RGB_TO_ULONG(238, 18 , 137), "DeepPink2" },
+ { RGB_TO_ULONG(205, 16 , 118), "DeepPink3" },
+ { RGB_TO_ULONG(139, 10 , 80 ), "DeepPink4" },
+ { RGB_TO_ULONG(255, 110, 180), "HotPink1" },
+ { RGB_TO_ULONG(238, 106, 167), "HotPink2" },
+ { RGB_TO_ULONG(205, 96 , 144), "HotPink3" },
+ { RGB_TO_ULONG(139, 58 , 98 ), "HotPink4" },
+ { RGB_TO_ULONG(255, 181, 197), "pink1" },
+ { RGB_TO_ULONG(238, 169, 184), "pink2" },
+ { RGB_TO_ULONG(205, 145, 158), "pink3" },
+ { RGB_TO_ULONG(139, 99 , 108), "pink4" },
+ { RGB_TO_ULONG(255, 174, 185), "LightPink1" },
+ { RGB_TO_ULONG(238, 162, 173), "LightPink2" },
+ { RGB_TO_ULONG(205, 140, 149), "LightPink3" },
+ { RGB_TO_ULONG(139, 95 , 101), "LightPink4" },
+ { RGB_TO_ULONG(255, 130, 171), "PaleVioletRed1" },
+ { RGB_TO_ULONG(238, 121, 159), "PaleVioletRed2" },
+ { RGB_TO_ULONG(205, 104, 137), "PaleVioletRed3" },
+ { RGB_TO_ULONG(139, 71 , 93 ), "PaleVioletRed4" },
+ { RGB_TO_ULONG(255, 52 , 179), "maroon1" },
+ { RGB_TO_ULONG(238, 48 , 167), "maroon2" },
+ { RGB_TO_ULONG(205, 41 , 144), "maroon3" },
+ { RGB_TO_ULONG(139, 28 , 98 ), "maroon4" },
+ { RGB_TO_ULONG(255, 62 , 150), "VioletRed1" },
+ { RGB_TO_ULONG(238, 58 , 140), "VioletRed2" },
+ { RGB_TO_ULONG(205, 50 , 120), "VioletRed3" },
+ { RGB_TO_ULONG(139, 34 , 82 ), "VioletRed4" },
+ { RGB_TO_ULONG(255, 0 , 255), "magenta1" },
+ { RGB_TO_ULONG(238, 0 , 238), "magenta2" },
+ { RGB_TO_ULONG(205, 0 , 205), "magenta3" },
+ { RGB_TO_ULONG(139, 0 , 139), "magenta4" },
+ { RGB_TO_ULONG(255, 131, 250), "orchid1" },
+ { RGB_TO_ULONG(238, 122, 233), "orchid2" },
+ { RGB_TO_ULONG(205, 105, 201), "orchid3" },
+ { RGB_TO_ULONG(139, 71 , 137), "orchid4" },
+ { RGB_TO_ULONG(255, 187, 255), "plum1" },
+ { RGB_TO_ULONG(238, 174, 238), "plum2" },
+ { RGB_TO_ULONG(205, 150, 205), "plum3" },
+ { RGB_TO_ULONG(139, 102, 139), "plum4" },
+ { RGB_TO_ULONG(224, 102, 255), "MediumOrchid1" },
+ { RGB_TO_ULONG(209, 95 , 238), "MediumOrchid2" },
+ { RGB_TO_ULONG(180, 82 , 205), "MediumOrchid3" },
+ { RGB_TO_ULONG(122, 55 , 139), "MediumOrchid4" },
+ { RGB_TO_ULONG(191, 62 , 255), "DarkOrchid1" },
+ { RGB_TO_ULONG(178, 58 , 238), "DarkOrchid2" },
+ { RGB_TO_ULONG(154, 50 , 205), "DarkOrchid3" },
+ { RGB_TO_ULONG(104, 34 , 139), "DarkOrchid4" },
+ { RGB_TO_ULONG(155, 48 , 255), "purple1" },
+ { RGB_TO_ULONG(145, 44 , 238), "purple2" },
+ { RGB_TO_ULONG(125, 38 , 205), "purple3" },
+ { RGB_TO_ULONG(85 , 26 , 139), "purple4" },
+ { RGB_TO_ULONG(171, 130, 255), "MediumPurple1" },
+ { RGB_TO_ULONG(159, 121, 238), "MediumPurple2" },
+ { RGB_TO_ULONG(137, 104, 205), "MediumPurple3" },
+ { RGB_TO_ULONG(93 , 71 , 139), "MediumPurple4" },
+ { RGB_TO_ULONG(255, 225, 255), "thistle1" },
+ { RGB_TO_ULONG(238, 210, 238), "thistle2" },
+ { RGB_TO_ULONG(205, 181, 205), "thistle3" },
+ { RGB_TO_ULONG(139, 123, 139), "thistle4" },
+ { RGB_TO_ULONG(0 , 0 , 0 ), "gray0" },
+ { RGB_TO_ULONG(0 , 0 , 0 ), "grey0" },
+ { RGB_TO_ULONG(3 , 3 , 3 ), "gray1" },
+ { RGB_TO_ULONG(3 , 3 , 3 ), "grey1" },
+ { RGB_TO_ULONG(5 , 5 , 5 ), "gray2" },
+ { RGB_TO_ULONG(5 , 5 , 5 ), "grey2" },
+ { RGB_TO_ULONG(8 , 8 , 8 ), "gray3" },
+ { RGB_TO_ULONG(8 , 8 , 8 ), "grey3" },
+ { RGB_TO_ULONG(10 , 10 , 10 ), "gray4" },
+ { RGB_TO_ULONG(10 , 10 , 10 ), "grey4" },
+ { RGB_TO_ULONG(13 , 13 , 13 ), "gray5" },
+ { RGB_TO_ULONG(13 , 13 , 13 ), "grey5" },
+ { RGB_TO_ULONG(15 , 15 , 15 ), "gray6" },
+ { RGB_TO_ULONG(15 , 15 , 15 ), "grey6" },
+ { RGB_TO_ULONG(18 , 18 , 18 ), "gray7" },
+ { RGB_TO_ULONG(18 , 18 , 18 ), "grey7" },
+ { RGB_TO_ULONG(20 , 20 , 20 ), "gray8" },
+ { RGB_TO_ULONG(20 , 20 , 20 ), "grey8" },
+ { RGB_TO_ULONG(23 , 23 , 23 ), "gray9" },
+ { RGB_TO_ULONG(23 , 23 , 23 ), "grey9" },
+ { RGB_TO_ULONG(26 , 26 , 26 ), "gray10" },
+ { RGB_TO_ULONG(26 , 26 , 26 ), "grey10" },
+ { RGB_TO_ULONG(28 , 28 , 28 ), "gray11" },
+ { RGB_TO_ULONG(28 , 28 , 28 ), "grey11" },
+ { RGB_TO_ULONG(31 , 31 , 31 ), "gray12" },
+ { RGB_TO_ULONG(31 , 31 , 31 ), "grey12" },
+ { RGB_TO_ULONG(33 , 33 , 33 ), "gray13" },
+ { RGB_TO_ULONG(33 , 33 , 33 ), "grey13" },
+ { RGB_TO_ULONG(36 , 36 , 36 ), "gray14" },
+ { RGB_TO_ULONG(36 , 36 , 36 ), "grey14" },
+ { RGB_TO_ULONG(38 , 38 , 38 ), "gray15" },
+ { RGB_TO_ULONG(38 , 38 , 38 ), "grey15" },
+ { RGB_TO_ULONG(41 , 41 , 41 ), "gray16" },
+ { RGB_TO_ULONG(41 , 41 , 41 ), "grey16" },
+ { RGB_TO_ULONG(43 , 43 , 43 ), "gray17" },
+ { RGB_TO_ULONG(43 , 43 , 43 ), "grey17" },
+ { RGB_TO_ULONG(46 , 46 , 46 ), "gray18" },
+ { RGB_TO_ULONG(46 , 46 , 46 ), "grey18" },
+ { RGB_TO_ULONG(48 , 48 , 48 ), "gray19" },
+ { RGB_TO_ULONG(48 , 48 , 48 ), "grey19" },
+ { RGB_TO_ULONG(51 , 51 , 51 ), "gray20" },
+ { RGB_TO_ULONG(51 , 51 , 51 ), "grey20" },
+ { RGB_TO_ULONG(54 , 54 , 54 ), "gray21" },
+ { RGB_TO_ULONG(54 , 54 , 54 ), "grey21" },
+ { RGB_TO_ULONG(56 , 56 , 56 ), "gray22" },
+ { RGB_TO_ULONG(56 , 56 , 56 ), "grey22" },
+ { RGB_TO_ULONG(59 , 59 , 59 ), "gray23" },
+ { RGB_TO_ULONG(59 , 59 , 59 ), "grey23" },
+ { RGB_TO_ULONG(61 , 61 , 61 ), "gray24" },
+ { RGB_TO_ULONG(61 , 61 , 61 ), "grey24" },
+ { RGB_TO_ULONG(64 , 64 , 64 ), "gray25" },
+ { RGB_TO_ULONG(64 , 64 , 64 ), "grey25" },
+ { RGB_TO_ULONG(66 , 66 , 66 ), "gray26" },
+ { RGB_TO_ULONG(66 , 66 , 66 ), "grey26" },
+ { RGB_TO_ULONG(69 , 69 , 69 ), "gray27" },
+ { RGB_TO_ULONG(69 , 69 , 69 ), "grey27" },
+ { RGB_TO_ULONG(71 , 71 , 71 ), "gray28" },
+ { RGB_TO_ULONG(71 , 71 , 71 ), "grey28" },
+ { RGB_TO_ULONG(74 , 74 , 74 ), "gray29" },
+ { RGB_TO_ULONG(74 , 74 , 74 ), "grey29" },
+ { RGB_TO_ULONG(77 , 77 , 77 ), "gray30" },
+ { RGB_TO_ULONG(77 , 77 , 77 ), "grey30" },
+ { RGB_TO_ULONG(79 , 79 , 79 ), "gray31" },
+ { RGB_TO_ULONG(79 , 79 , 79 ), "grey31" },
+ { RGB_TO_ULONG(82 , 82 , 82 ), "gray32" },
+ { RGB_TO_ULONG(82 , 82 , 82 ), "grey32" },
+ { RGB_TO_ULONG(84 , 84 , 84 ), "gray33" },
+ { RGB_TO_ULONG(84 , 84 , 84 ), "grey33" },
+ { RGB_TO_ULONG(87 , 87 , 87 ), "gray34" },
+ { RGB_TO_ULONG(87 , 87 , 87 ), "grey34" },
+ { RGB_TO_ULONG(89 , 89 , 89 ), "gray35" },
+ { RGB_TO_ULONG(89 , 89 , 89 ), "grey35" },
+ { RGB_TO_ULONG(92 , 92 , 92 ), "gray36" },
+ { RGB_TO_ULONG(92 , 92 , 92 ), "grey36" },
+ { RGB_TO_ULONG(94 , 94 , 94 ), "gray37" },
+ { RGB_TO_ULONG(94 , 94 , 94 ), "grey37" },
+ { RGB_TO_ULONG(97 , 97 , 97 ), "gray38" },
+ { RGB_TO_ULONG(97 , 97 , 97 ), "grey38" },
+ { RGB_TO_ULONG(99 , 99 , 99 ), "gray39" },
+ { RGB_TO_ULONG(99 , 99 , 99 ), "grey39" },
+ { RGB_TO_ULONG(102, 102, 102), "gray40" },
+ { RGB_TO_ULONG(102, 102, 102), "grey40" },
+ { RGB_TO_ULONG(105, 105, 105), "gray41" },
+ { RGB_TO_ULONG(105, 105, 105), "grey41" },
+ { RGB_TO_ULONG(107, 107, 107), "gray42" },
+ { RGB_TO_ULONG(107, 107, 107), "grey42" },
+ { RGB_TO_ULONG(110, 110, 110), "gray43" },
+ { RGB_TO_ULONG(110, 110, 110), "grey43" },
+ { RGB_TO_ULONG(112, 112, 112), "gray44" },
+ { RGB_TO_ULONG(112, 112, 112), "grey44" },
+ { RGB_TO_ULONG(115, 115, 115), "gray45" },
+ { RGB_TO_ULONG(115, 115, 115), "grey45" },
+ { RGB_TO_ULONG(117, 117, 117), "gray46" },
+ { RGB_TO_ULONG(117, 117, 117), "grey46" },
+ { RGB_TO_ULONG(120, 120, 120), "gray47" },
+ { RGB_TO_ULONG(120, 120, 120), "grey47" },
+ { RGB_TO_ULONG(122, 122, 122), "gray48" },
+ { RGB_TO_ULONG(122, 122, 122), "grey48" },
+ { RGB_TO_ULONG(125, 125, 125), "gray49" },
+ { RGB_TO_ULONG(125, 125, 125), "grey49" },
+ { RGB_TO_ULONG(127, 127, 127), "gray50" },
+ { RGB_TO_ULONG(127, 127, 127), "grey50" },
+ { RGB_TO_ULONG(130, 130, 130), "gray51" },
+ { RGB_TO_ULONG(130, 130, 130), "grey51" },
+ { RGB_TO_ULONG(133, 133, 133), "gray52" },
+ { RGB_TO_ULONG(133, 133, 133), "grey52" },
+ { RGB_TO_ULONG(135, 135, 135), "gray53" },
+ { RGB_TO_ULONG(135, 135, 135), "grey53" },
+ { RGB_TO_ULONG(138, 138, 138), "gray54" },
+ { RGB_TO_ULONG(138, 138, 138), "grey54" },
+ { RGB_TO_ULONG(140, 140, 140), "gray55" },
+ { RGB_TO_ULONG(140, 140, 140), "grey55" },
+ { RGB_TO_ULONG(143, 143, 143), "gray56" },
+ { RGB_TO_ULONG(143, 143, 143), "grey56" },
+ { RGB_TO_ULONG(145, 145, 145), "gray57" },
+ { RGB_TO_ULONG(145, 145, 145), "grey57" },
+ { RGB_TO_ULONG(148, 148, 148), "gray58" },
+ { RGB_TO_ULONG(148, 148, 148), "grey58" },
+ { RGB_TO_ULONG(150, 150, 150), "gray59" },
+ { RGB_TO_ULONG(150, 150, 150), "grey59" },
+ { RGB_TO_ULONG(153, 153, 153), "gray60" },
+ { RGB_TO_ULONG(153, 153, 153), "grey60" },
+ { RGB_TO_ULONG(156, 156, 156), "gray61" },
+ { RGB_TO_ULONG(156, 156, 156), "grey61" },
+ { RGB_TO_ULONG(158, 158, 158), "gray62" },
+ { RGB_TO_ULONG(158, 158, 158), "grey62" },
+ { RGB_TO_ULONG(161, 161, 161), "gray63" },
+ { RGB_TO_ULONG(161, 161, 161), "grey63" },
+ { RGB_TO_ULONG(163, 163, 163), "gray64" },
+ { RGB_TO_ULONG(163, 163, 163), "grey64" },
+ { RGB_TO_ULONG(166, 166, 166), "gray65" },
+ { RGB_TO_ULONG(166, 166, 166), "grey65" },
+ { RGB_TO_ULONG(168, 168, 168), "gray66" },
+ { RGB_TO_ULONG(168, 168, 168), "grey66" },
+ { RGB_TO_ULONG(171, 171, 171), "gray67" },
+ { RGB_TO_ULONG(171, 171, 171), "grey67" },
+ { RGB_TO_ULONG(173, 173, 173), "gray68" },
+ { RGB_TO_ULONG(173, 173, 173), "grey68" },
+ { RGB_TO_ULONG(176, 176, 176), "gray69" },
+ { RGB_TO_ULONG(176, 176, 176), "grey69" },
+ { RGB_TO_ULONG(179, 179, 179), "gray70" },
+ { RGB_TO_ULONG(179, 179, 179), "grey70" },
+ { RGB_TO_ULONG(181, 181, 181), "gray71" },
+ { RGB_TO_ULONG(181, 181, 181), "grey71" },
+ { RGB_TO_ULONG(184, 184, 184), "gray72" },
+ { RGB_TO_ULONG(184, 184, 184), "grey72" },
+ { RGB_TO_ULONG(186, 186, 186), "gray73" },
+ { RGB_TO_ULONG(186, 186, 186), "grey73" },
+ { RGB_TO_ULONG(189, 189, 189), "gray74" },
+ { RGB_TO_ULONG(189, 189, 189), "grey74" },
+ { RGB_TO_ULONG(191, 191, 191), "gray75" },
+ { RGB_TO_ULONG(191, 191, 191), "grey75" },
+ { RGB_TO_ULONG(194, 194, 194), "gray76" },
+ { RGB_TO_ULONG(194, 194, 194), "grey76" },
+ { RGB_TO_ULONG(196, 196, 196), "gray77" },
+ { RGB_TO_ULONG(196, 196, 196), "grey77" },
+ { RGB_TO_ULONG(199, 199, 199), "gray78" },
+ { RGB_TO_ULONG(199, 199, 199), "grey78" },
+ { RGB_TO_ULONG(201, 201, 201), "gray79" },
+ { RGB_TO_ULONG(201, 201, 201), "grey79" },
+ { RGB_TO_ULONG(204, 204, 204), "gray80" },
+ { RGB_TO_ULONG(204, 204, 204), "grey80" },
+ { RGB_TO_ULONG(207, 207, 207), "gray81" },
+ { RGB_TO_ULONG(207, 207, 207), "grey81" },
+ { RGB_TO_ULONG(209, 209, 209), "gray82" },
+ { RGB_TO_ULONG(209, 209, 209), "grey82" },
+ { RGB_TO_ULONG(212, 212, 212), "gray83" },
+ { RGB_TO_ULONG(212, 212, 212), "grey83" },
+ { RGB_TO_ULONG(214, 214, 214), "gray84" },
+ { RGB_TO_ULONG(214, 214, 214), "grey84" },
+ { RGB_TO_ULONG(217, 217, 217), "gray85" },
+ { RGB_TO_ULONG(217, 217, 217), "grey85" },
+ { RGB_TO_ULONG(219, 219, 219), "gray86" },
+ { RGB_TO_ULONG(219, 219, 219), "grey86" },
+ { RGB_TO_ULONG(222, 222, 222), "gray87" },
+ { RGB_TO_ULONG(222, 222, 222), "grey87" },
+ { RGB_TO_ULONG(224, 224, 224), "gray88" },
+ { RGB_TO_ULONG(224, 224, 224), "grey88" },
+ { RGB_TO_ULONG(227, 227, 227), "gray89" },
+ { RGB_TO_ULONG(227, 227, 227), "grey89" },
+ { RGB_TO_ULONG(229, 229, 229), "gray90" },
+ { RGB_TO_ULONG(229, 229, 229), "grey90" },
+ { RGB_TO_ULONG(232, 232, 232), "gray91" },
+ { RGB_TO_ULONG(232, 232, 232), "grey91" },
+ { RGB_TO_ULONG(235, 235, 235), "gray92" },
+ { RGB_TO_ULONG(235, 235, 235), "grey92" },
+ { RGB_TO_ULONG(237, 237, 237), "gray93" },
+ { RGB_TO_ULONG(237, 237, 237), "grey93" },
+ { RGB_TO_ULONG(240, 240, 240), "gray94" },
+ { RGB_TO_ULONG(240, 240, 240), "grey94" },
+ { RGB_TO_ULONG(242, 242, 242), "gray95" },
+ { RGB_TO_ULONG(242, 242, 242), "grey95" },
+ { RGB_TO_ULONG(245, 245, 245), "gray96" },
+ { RGB_TO_ULONG(245, 245, 245), "grey96" },
+ { RGB_TO_ULONG(247, 247, 247), "gray97" },
+ { RGB_TO_ULONG(247, 247, 247), "grey97" },
+ { RGB_TO_ULONG(250, 250, 250), "gray98" },
+ { RGB_TO_ULONG(250, 250, 250), "grey98" },
+ { RGB_TO_ULONG(252, 252, 252), "gray99" },
+ { RGB_TO_ULONG(252, 252, 252), "grey99" },
+ { RGB_TO_ULONG(255, 255, 255), "gray100" },
+ { RGB_TO_ULONG(255, 255, 255), "grey100" },
+ { RGB_TO_ULONG(169, 169, 169), "dark grey" },
+ { RGB_TO_ULONG(169, 169, 169), "DarkGrey" },
+ { RGB_TO_ULONG(169, 169, 169), "dark gray" },
+ { RGB_TO_ULONG(169, 169, 169), "DarkGray" },
+ { RGB_TO_ULONG(0 , 0 , 139), "dark blue" },
+ { RGB_TO_ULONG(0 , 0 , 139), "DarkBlue" },
+ { RGB_TO_ULONG(0 , 139, 139), "dark cyan" },
+ { RGB_TO_ULONG(0 , 139, 139), "DarkCyan" },
+ { RGB_TO_ULONG(139, 0 , 139), "dark magenta" },
+ { RGB_TO_ULONG(139, 0 , 139), "DarkMagenta" },
+ { RGB_TO_ULONG(139, 0 , 0 ), "dark red" },
+ { RGB_TO_ULONG(139, 0 , 0 ), "DarkRed" },
+ { RGB_TO_ULONG(144, 238, 144), "light green" },
+ { RGB_TO_ULONG(144, 238, 144), "LightGreen" }
+};
+
+unsigned long
+mac_color_map_lookup (colorname)
+ char *colorname;
+{
+ Lisp_Object ret = Qnil;
+ int i;
+
+ BLOCK_INPUT;
+
+ for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++)
+ if (stricmp (colorname, mac_color_map[i].name) == 0)
+ {
+ ret = mac_color_map[i].color;
+ break;
+ }
+
+ UNBLOCK_INPUT;
+
+ return ret;
+}
+
+Lisp_Object
+x_to_mac_color (colorname)
+ char * colorname;
+{
+ register Lisp_Object tail, ret = Qnil;
+
+ BLOCK_INPUT;
+
+ if (colorname[0] == '#')
+ {
+ /* Could be an old-style RGB Device specification. */
+ char *color;
+ int size;
+ color = colorname + 1;
+
+ size = strlen(color);
+ if (size == 3 || size == 6 || size == 9 || size == 12)
+ {
+ unsigned long colorval;
+ int i, pos;
+ pos = 0;
+ size /= 3;
+ colorval = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ char *end;
+ char t;
+ unsigned long value;
+
+ /* The check for 'x' in the following conditional takes into
+ account the fact that strtol allows a "0x" in front of
+ our numbers, and we don't. */
+ if (!isxdigit(color[0]) || color[1] == 'x')
+ break;
+ t = color[size];
+ color[size] = '\0';
+ value = strtoul(color, &end, 16);
+ color[size] = t;
+ if (errno == ERANGE || end - color != size)
+ break;
+ switch (size)
+ {
+ case 1:
+ value = value * 0x10;
+ break;
+ case 2:
+ break;
+ case 3:
+ value /= 0x10;
+ break;
+ case 4:
+ value /= 0x100;
+ break;
+ }
+ colorval |= (value << pos);
+ pos += 0x8;
+ if (i == 2)
+ {
+ UNBLOCK_INPUT;
+ return (colorval);
+ }
+ color = end;
+ }
+ }
+ }
+ else if (strnicmp(colorname, "rgb:", 4) == 0)
+ {
+ char *color;
+ unsigned long colorval;
+ int i, pos;
+ pos = 0;
+
+ colorval = 0;
+ color = colorname + 4;
+ for (i = 0; i < 3; i++)
+ {
+ char *end;
+ unsigned long value;
+
+ /* The check for 'x' in the following conditional takes into
+ account the fact that strtol allows a "0x" in front of
+ our numbers, and we don't. */
+ if (!isxdigit(color[0]) || color[1] == 'x')
+ break;
+ value = strtoul(color, &end, 16);
+ if (errno == ERANGE)
+ break;
+ switch (end - color)
+ {
+ case 1:
+ value = value * 0x10 + value;
+ break;
+ case 2:
+ break;
+ case 3:
+ value /= 0x10;
+ break;
+ case 4:
+ value /= 0x100;
+ break;
+ default:
+ value = ULONG_MAX;
+ }
+ if (value == ULONG_MAX)
+ break;
+ colorval |= (value << pos);
+ pos += 0x8;
+ if (i == 2)
+ {
+ if (*end != '\0')
+ break;
+ UNBLOCK_INPUT;
+ return (colorval);
+ }
+ if (*end != '/')
+ break;
+ color = end + 1;
+ }
+ }
+ else if (strnicmp(colorname, "rgbi:", 5) == 0)
+ {
+ /* This is an RGB Intensity specification. */
+ char *color;
+ unsigned long colorval;
+ int i, pos;
+ pos = 0;
+
+ colorval = 0;
+ color = colorname + 5;
+ for (i = 0; i < 3; i++)
+ {
+ char *end;
+ double value;
+ unsigned long val;
+
+ value = strtod(color, &end);
+ if (errno == ERANGE)
+ break;
+ if (value < 0.0 || value > 1.0)
+ break;
+ val = (unsigned long)(0x100 * value);
+ /* We used 0x100 instead of 0xFF to give an continuous
+ range between 0.0 and 1.0 inclusive. The next statement
+ fixes the 1.0 case. */
+ if (val == 0x100)
+ val = 0xFF;
+ colorval |= (val << pos);
+ pos += 0x8;
+ if (i == 2)
+ {
+ if (*end != '\0')
+ break;
+ UNBLOCK_INPUT;
+ return (colorval);
+ }
+ if (*end != '/')
+ break;
+ color = end + 1;
+ }
+ }
+
+ ret = mac_color_map_lookup (colorname);
+
+ UNBLOCK_INPUT;
+ return ret;
+}
+
+/* Gamma-correct COLOR on frame F. */
+
+void
+gamma_correct (f, color)
+ struct frame *f;
+ unsigned long *color;
+{
+ if (f->gamma)
+ {
+ unsigned long red, green, blue;
+
+ red = pow (RED_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
+ green = pow (GREEN_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
+ blue = pow (BLUE_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
+ *color = RGB_TO_ULONG (red, green, blue);
+ }
+}
+
+/* Decide if color named COLOR is valid for the display associated
+ with the selected frame; if so, return the rgb values in COLOR_DEF.
+ If ALLOC is nonzero, allocate a new colormap cell. */
+
+int
+mac_defined_color (f, color, color_def, alloc)
+ FRAME_PTR f;
+ char *color;
+ XColor *color_def;
+ int alloc;
+{
+ register Lisp_Object tem;
+ unsigned long mac_color_ref;
+
+ tem = x_to_mac_color (color);
+
+ if (!NILP (tem))
+ {
+ if (f)
+ {
+ /* Apply gamma correction. */
+ mac_color_ref = XUINT (tem);
+ gamma_correct (f, &mac_color_ref);
+ XSETINT (tem, mac_color_ref);
+ }
+
+ color_def->pixel = mac_color_ref;
+ color_def->red = RED_FROM_ULONG (mac_color_ref);
+ color_def->green = GREEN_FROM_ULONG (mac_color_ref);
+ color_def->blue = BLUE_FROM_ULONG (mac_color_ref);
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/* Given a string ARG naming a color, compute a pixel value from it
+ suitable for screen F.
+ If F is not a color screen, return DEF (default) regardless of what
+ ARG says. */
+
+int
+x_decode_color (f, arg, def)
+ FRAME_PTR f;
+ Lisp_Object arg;
+ int def;
+{
+ XColor cdef;
+
+ CHECK_STRING (arg);
+
+ if (strcmp (XSTRING (arg)->data, "black") == 0)
+ return BLACK_PIX_DEFAULT (f);
+ else if (strcmp (XSTRING (arg)->data, "white") == 0)
+ return WHITE_PIX_DEFAULT (f);
+
+#if 0
+ if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes
+ * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1)
+ return def;
+#endif
+
+ if (mac_defined_color (f, XSTRING (arg)->data, &cdef, 1))
+ return cdef.pixel;
+
+ /* defined_color failed; return an ultimate default. */
+ return def;
+}
+
+/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
+ the previous value of that parameter, NEW_VALUE is the new value. */
+
+static void
+x_set_line_spacing (f, new_value, old_value)
+ struct frame *f;
+ Lisp_Object new_value, old_value;
+{
+ if (NILP (new_value))
+ f->extra_line_spacing = 0;
+ else if (NATNUMP (new_value))
+ f->extra_line_spacing = XFASTINT (new_value);
+ else
+ Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
+ Fcons (new_value, Qnil)));
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+}
+
+
+/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
+ the previous value of that parameter, NEW_VALUE is the new value. */
+
+static void
+x_set_screen_gamma (f, new_value, old_value)
+ struct frame *f;
+ Lisp_Object new_value, old_value;
+{
+ if (NILP (new_value))
+ f->gamma = 0;
+ else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
+ /* The value 0.4545 is the normal viewing gamma. */
+ f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
+ else
+ Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
+ Fcons (new_value, Qnil)));
+
+ clear_face_cache (0);
+}
+
+
+/* Functions called only from `x_set_frame_param'
+ to set individual parameters.
+
+ If FRAME_MAC_WINDOW (f) is 0,
+ the frame is being created and its window does not exist yet.
+ In that case, just record the parameter's new value
+ in the standard place; do not attempt to change the window. */
+
+void
+x_set_foreground_color (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ FRAME_FOREGROUND_PIXEL (f)
+ = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+
+ if (FRAME_MAC_WINDOW (f) != 0)
+ {
+ update_face_from_frame_parameter (f, Qforeground_color, arg);
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+ }
+}
+
+void
+x_set_background_color (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ FRAME_BACKGROUND_PIXEL (f)
+ = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
+
+ if (FRAME_MAC_WINDOW (f) != 0)
+ {
+ update_face_from_frame_parameter (f, Qbackground_color, arg);
+
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+ }
+}
+
+void
+x_set_mouse_color (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
+ int count;
+ int mask_color;
+
+ if (!EQ (Qnil, arg))
+ f->output_data.mac->mouse_pixel
+ = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+ mask_color = FRAME_BACKGROUND_PIXEL (f);
+
+ /* Don't let pointers be invisible. */
+ if (mask_color == f->output_data.mac->mouse_pixel
+ && mask_color == FRAME_BACKGROUND_PIXEL (f))
+ f->output_data.mac->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
+
+#if 0 /* MAC_TODO : cursor changes */
+ BLOCK_INPUT;
+
+ /* It's not okay to crash if the user selects a screwy cursor. */
+ count = x_catch_errors (FRAME_W32_DISPLAY (f));
+
+ if (!EQ (Qnil, Vx_pointer_shape))
+ {
+ CHECK_NUMBER (Vx_pointer_shape);
+ cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
+ }
+ else
+ cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
+ x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
+
+ if (!EQ (Qnil, Vx_nontext_pointer_shape))
+ {
+ CHECK_NUMBER (Vx_nontext_pointer_shape);
+ nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
+ XINT (Vx_nontext_pointer_shape));
+ }
+ else
+ nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
+ x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
+
+ if (!EQ (Qnil, Vx_hourglass_pointer_shape))
+ {
+ CHECK_NUMBER (Vx_hourglass_pointer_shape);
+ hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
+ XINT (Vx_hourglass_pointer_shape));
+ }
+ else
+ hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
+ x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
+
+ x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
+ if (!EQ (Qnil, Vx_mode_pointer_shape))
+ {
+ CHECK_NUMBER (Vx_mode_pointer_shape);
+ mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
+ XINT (Vx_mode_pointer_shape));
+ }
+ else
+ mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
+ x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
+
+ if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
+ {
+ CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
+ cross_cursor
+ = XCreateFontCursor (FRAME_W32_DISPLAY (f),
+ XINT (Vx_sensitive_text_pointer_shape));
+ }
+ else
+ cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
+
+ if (!NILP (Vx_window_horizontal_drag_shape))
+ {
+ CHECK_NUMBER (Vx_window_horizontal_drag_shape);
+ horizontal_drag_cursor
+ = XCreateFontCursor (FRAME_W32_DISPLAY (f),
+ XINT (Vx_window_horizontal_drag_shape));
+ }
+ else
+ horizontal_drag_cursor
+ = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_h_double_arrow);
+
+ /* Check and report errors with the above calls. */
+ x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
+ x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
+
+ {
+ XColor fore_color, back_color;
+
+ fore_color.pixel = f->output_data.w32->mouse_pixel;
+ back_color.pixel = mask_color;
+ XQueryColor (FRAME_W32_DISPLAY (f),
+ DefaultColormap (FRAME_W32_DISPLAY (f),
+ DefaultScreen (FRAME_W32_DISPLAY (f))),
+ &fore_color);
+ XQueryColor (FRAME_W32_DISPLAY (f),
+ DefaultColormap (FRAME_W32_DISPLAY (f),
+ DefaultScreen (FRAME_W32_DISPLAY (f))),
+ &back_color);
+ XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
+ &fore_color, &back_color);
+ XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
+ &fore_color, &back_color);
+ XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
+ &fore_color, &back_color);
+ XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
+ &fore_color, &back_color);
+ XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
+ &fore_color, &back_color);
+ }
+
+ if (FRAME_W32_WINDOW (f) != 0)
+ XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
+
+ if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
+ XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
+ f->output_data.w32->text_cursor = cursor;
+
+ if (nontext_cursor != f->output_data.w32->nontext_cursor
+ && f->output_data.w32->nontext_cursor != 0)
+ XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
+ f->output_data.w32->nontext_cursor = nontext_cursor;
+
+ if (hourglass_cursor != f->output_data.w32->hourglass_cursor
+ && f->output_data.w32->hourglass_cursor != 0)
+ XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
+ f->output_data.w32->hourglass_cursor = hourglass_cursor;
+
+ if (mode_cursor != f->output_data.w32->modeline_cursor
+ && f->output_data.w32->modeline_cursor != 0)
+ XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
+ f->output_data.w32->modeline_cursor = mode_cursor;
+
+ if (cross_cursor != f->output_data.w32->cross_cursor
+ && f->output_data.w32->cross_cursor != 0)
+ XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
+ f->output_data.w32->cross_cursor = cross_cursor;
+
+ XFlush (FRAME_W32_DISPLAY (f));
+ UNBLOCK_INPUT;
+
+ update_face_from_frame_parameter (f, Qmouse_color, arg);
+#endif /* MAC_TODO */
+}
+
+void
+x_set_cursor_color (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ unsigned long fore_pixel;
+
+ if (!NILP (Vx_cursor_fore_pixel))
+ fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
+ WHITE_PIX_DEFAULT (f));
+ else
+ fore_pixel = FRAME_BACKGROUND_PIXEL (f);
+ f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+
+ /* Make sure that the cursor color differs from the background color. */
+ if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
+ {
+ f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel;
+ if (f->output_data.mac->cursor_pixel == fore_pixel)
+ fore_pixel = FRAME_BACKGROUND_PIXEL (f);
+ }
+ FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
+
+#if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */
+ if (FRAME_MAC_WINDOW (f) != 0)
+ {
+ if (FRAME_VISIBLE_P (f))
+ {
+ x_display_cursor (f, 0);
+ x_display_cursor (f, 1);
+ }
+ }
+#endif
+
+ update_face_from_frame_parameter (f, Qcursor_color, arg);
+}
+
+/* Set the border-color of frame F to pixel value PIX.
+ Note that this does not fully take effect if done before
+ F has an window. */
+void
+x_set_border_pixel (f, pix)
+ struct frame *f;
+ int pix;
+{
+ f->output_data.mac->border_pixel = pix;
+
+ if (FRAME_MAC_WINDOW (f) != 0 && f->output_data.mac->border_width > 0)
+ {
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+ }
+}
+
+/* Set the border-color of frame F to value described by ARG.
+ ARG can be a string naming a color.
+ The border-color is used for the border that is drawn by the server.
+ Note that this does not fully take effect if done before
+ F has a window; it must be redone when the window is created. */
+
+void
+x_set_border_color (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ int pix;
+
+ CHECK_STRING (arg);
+ pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+ x_set_border_pixel (f, pix);
+ update_face_from_frame_parameter (f, Qborder_color, arg);
+}
+
+/* Value is the internal representation of the specified cursor type
+ ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
+ of the bar cursor. */
+
+enum text_cursor_kinds
+x_specified_cursor_type (arg, width)
+ Lisp_Object arg;
+ int *width;
+{
+ enum text_cursor_kinds type;
+
+ if (EQ (arg, Qbar))
+ {
+ type = BAR_CURSOR;
+ *width = 2;
+ }
+ else if (CONSP (arg)
+ && EQ (XCAR (arg), Qbar)
+ && INTEGERP (XCDR (arg))
+ && XINT (XCDR (arg)) >= 0)
+ {
+ type = BAR_CURSOR;
+ *width = XINT (XCDR (arg));
+ }
+ else if (NILP (arg))
+ type = NO_CURSOR;
+ else
+ /* Treat anything unknown as "box cursor".
+ It was bad to signal an error; people have trouble fixing
+ .Xdefaults with Emacs, when it has something bad in it. */
+ type = FILLED_BOX_CURSOR;
+
+ return type;
+}
+
+void
+x_set_cursor_type (f, arg, oldval)
+ FRAME_PTR f;
+ Lisp_Object arg, oldval;
+{
+ int width;
+
+ FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
+ f->output_data.mac->cursor_width = width;
+
+ /* Make sure the cursor gets redrawn. This is overkill, but how
+ often do people change cursor types? */
+ update_mode_lines++;
+}
+
+#if 0 /* MAC_TODO: really no icon for Mac */
+void
+x_set_icon_type (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ int result;
+
+ if (NILP (arg) && NILP (oldval))
+ return;
+
+ if (STRINGP (arg) && STRINGP (oldval)
+ && EQ (Fstring_equal (oldval, arg), Qt))
+ return;
+
+ if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
+ return;
+
+ BLOCK_INPUT;
+
+ result = x_bitmap_icon (f, arg);
+ if (result)
+ {
+ UNBLOCK_INPUT;
+ error ("No icon window available");
+ }
+
+ UNBLOCK_INPUT;
+}
+#endif /* MAC_TODO */
+
+/* Return non-nil if frame F wants a bitmap icon. */
+
+Lisp_Object
+x_icon_type (f)
+ FRAME_PTR f;
+{
+ Lisp_Object tem;
+
+ tem = assq_no_quit (Qicon_type, f->param_alist);
+ if (CONSP (tem))
+ return XCDR (tem);
+ else
+ return Qnil;
+}
+
+void
+x_set_icon_name (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ int result;
+
+ if (STRINGP (arg))
+ {
+ if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+ return;
+ }
+ else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
+ return;
+
+ f->icon_name = arg;
+
+#if 0 /* MAC_TODO */
+ if (f->output_data.w32->icon_bitmap != 0)
+ return;
+
+ BLOCK_INPUT;
+
+ result = x_text_icon (f,
+ (char *) XSTRING ((!NILP (f->icon_name)
+ ? f->icon_name
+ : !NILP (f->title)
+ ? f->title
+ : f->name))->data);
+
+ if (result)
+ {
+ UNBLOCK_INPUT;
+ error ("No icon window available");
+ }
+
+ /* If the window was unmapped (and its icon was mapped),
+ the new icon is not mapped, so map the window in its stead. */
+ if (FRAME_VISIBLE_P (f))
+ {
+#ifdef USE_X_TOOLKIT
+ XtPopup (f->output_data.w32->widget, XtGrabNone);
+#endif
+ XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
+ }
+
+ XFlush (FRAME_W32_DISPLAY (f));
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+}
+
+extern Lisp_Object x_new_font ();
+extern Lisp_Object x_new_fontset();
+
+void
+x_set_font (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ Lisp_Object result;
+ Lisp_Object fontset_name;
+ Lisp_Object frame;
+ int old_fontset = FRAME_FONTSET(f);
+
+ CHECK_STRING (arg);
+
+ fontset_name = Fquery_fontset (arg, Qnil);
+
+ BLOCK_INPUT;
+ result = (STRINGP (fontset_name)
+ ? x_new_fontset (f, XSTRING (fontset_name)->data)
+ : x_new_font (f, XSTRING (arg)->data));
+ UNBLOCK_INPUT;
+
+ if (EQ (result, Qnil))
+ error ("Font `%s' is not defined", XSTRING (arg)->data);
+ else if (EQ (result, Qt))
+ error ("The characters of the given font have varying widths");
+ else if (STRINGP (result))
+ {
+ if (STRINGP (fontset_name))
+ {
+ /* Fontset names are built from ASCII font names, so the
+ names may be equal despite there was a change. */
+ if (old_fontset == FRAME_FONTSET (f))
+ return;
+ }
+ else if (!NILP (Fequal (result, oldval)))
+ return;
+
+ store_frame_param (f, Qfont, result);
+ recompute_basic_faces (f);
+ }
+ else
+ abort ();
+
+ do_pending_window_change (0);
+
+ /* Don't call `face-set-after-frame-default' when faces haven't been
+ initialized yet. This is the case when called from
+ Fx_create_frame. In that case, the X widget or window doesn't
+ exist either, and we can end up in x_report_frame_params with a
+ null widget which gives a segfault. */
+ if (FRAME_FACE_CACHE (f))
+ {
+ XSETFRAME (frame, f);
+ call1 (Qface_set_after_frame_default, frame);
+ }
+}
+
+void
+x_set_border_width (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ CHECK_NUMBER (arg);
+
+ if (XINT (arg) == f->output_data.mac->border_width)
+ return;
+
+#if 0 /* MAC_TODO */
+ if (FRAME_MAC_WINDOW (f) != 0)
+ error ("Cannot change the border width of a window");
+#endif
+
+ f->output_data.mac->border_width = XINT (arg);
+}
+
+void
+x_set_internal_border_width (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ int old = f->output_data.mac->internal_border_width;
+
+ CHECK_NUMBER (arg);
+ f->output_data.mac->internal_border_width = XINT (arg);
+ if (f->output_data.mac->internal_border_width < 0)
+ f->output_data.mac->internal_border_width = 0;
+
+ if (f->output_data.mac->internal_border_width == old)
+ return;
+
+ if (FRAME_MAC_WINDOW (f) != 0)
+ {
+ x_set_window_size (f, 0, f->width, f->height);
+ SET_FRAME_GARBAGED (f);
+ do_pending_window_change (0);
+ }
+ else
+ SET_FRAME_GARBAGED (f);
+}
+
+void
+x_set_visibility (f, value, oldval)
+ struct frame *f;
+ Lisp_Object value, oldval;
+{
+ Lisp_Object frame;
+ XSETFRAME (frame, f);
+
+ if (NILP (value))
+ Fmake_frame_invisible (frame, Qt);
+ else if (EQ (value, Qicon))
+ Ficonify_frame (frame);
+ else
+ Fmake_frame_visible (frame);
+}
+
+
+/* Change window heights in windows rooted in WINDOW by N lines. */
+
+static void
+x_change_window_heights (window, n)
+ Lisp_Object window;
+ int n;
+{
+ struct window *w = XWINDOW (window);
+
+ XSETFASTINT (w->top, XFASTINT (w->top) + n);
+ XSETFASTINT (w->height, XFASTINT (w->height) - n);
+
+ if (INTEGERP (w->orig_top))
+ XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
+ if (INTEGERP (w->orig_height))
+ XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
+
+ /* Handle just the top child in a vertical split. */
+ if (!NILP (w->vchild))
+ x_change_window_heights (w->vchild, n);
+
+ /* Adjust all children in a horizontal split. */
+ for (window = w->hchild; !NILP (window); window = w->next)
+ {
+ w = XWINDOW (window);
+ x_change_window_heights (window, n);
+ }
+}
+
+void
+x_set_menu_bar_lines (f, value, oldval)
+ struct frame *f;
+ Lisp_Object value, oldval;
+{
+ int nlines;
+ int olines = FRAME_MENU_BAR_LINES (f);
+
+ /* Right now, menu bars don't work properly in minibuf-only frames;
+ most of the commands try to apply themselves to the minibuffer
+ frame itself, and get an error because you can't switch buffers
+ in or split the minibuffer window. */
+ if (FRAME_MINIBUF_ONLY_P (f))
+ return;
+
+ if (INTEGERP (value))
+ nlines = XINT (value);
+ else
+ nlines = 0;
+
+ FRAME_MENU_BAR_LINES (f) = 0;
+ if (nlines)
+ FRAME_EXTERNAL_MENU_BAR (f) = 1;
+ else
+ {
+ if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
+ free_frame_menubar (f);
+ FRAME_EXTERNAL_MENU_BAR (f) = 0;
+
+ /* Adjust the frame size so that the client (text) dimensions
+ remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
+ set correctly. */
+ x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
+ do_pending_window_change (0);
+ }
+ adjust_glyphs (f);
+}
+
+
+/* Set the number of lines used for the tool bar of frame F to VALUE.
+ VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
+ is the old number of tool bar lines. This function changes the
+ height of all windows on frame F to match the new tool bar height.
+ The frame's height doesn't change. */
+
+void
+x_set_tool_bar_lines (f, value, oldval)
+ struct frame *f;
+ Lisp_Object value, oldval;
+{
+ int delta, nlines, root_height;
+ Lisp_Object root_window;
+
+ /* Treat tool bars like menu bars. */
+ if (FRAME_MINIBUF_ONLY_P (f))
+ return;
+
+ /* Use VALUE only if an integer >= 0. */
+ if (INTEGERP (value) && XINT (value) >= 0)
+ nlines = XFASTINT (value);
+ else
+ nlines = 0;
+
+ /* Make sure we redisplay all windows in this frame. */
+ ++windows_or_buffers_changed;
+
+ delta = nlines - FRAME_TOOL_BAR_LINES (f);
+
+ /* Don't resize the tool-bar to more than we have room for. */
+ root_window = FRAME_ROOT_WINDOW (f);
+ root_height = XINT (XWINDOW (root_window)->height);
+ if (root_height - delta < 1)
+ {
+ delta = root_height - 1;
+ nlines = FRAME_TOOL_BAR_LINES (f) + delta;
+ }
+
+ FRAME_TOOL_BAR_LINES (f) = nlines;
+ x_change_window_heights (root_window, delta);
+ adjust_glyphs (f);
+
+ /* We also have to make sure that the internal border at the top of
+ the frame, below the menu bar or tool bar, is redrawn when the
+ tool bar disappears. This is so because the internal border is
+ below the tool bar if one is displayed, but is below the menu bar
+ if there isn't a tool bar. The tool bar draws into the area
+ below the menu bar. */
+ if (FRAME_MAC_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
+ {
+ updating_frame = f;
+ clear_frame ();
+ clear_current_matrices (f);
+ updating_frame = NULL;
+ }
+
+ /* If the tool bar gets smaller, the internal border below it
+ has to be cleared. It was formerly part of the display
+ of the larger tool bar, and updating windows won't clear it. */
+ if (delta < 0)
+ {
+ int height = FRAME_INTERNAL_BORDER_WIDTH (f);
+ int width = PIXEL_WIDTH (f);
+ int y = nlines * CANON_Y_UNIT (f);
+
+ BLOCK_INPUT;
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ 0, y, width, height, 0);
+ UNBLOCK_INPUT;
+
+ if (WINDOWP (f->tool_bar_window))
+ clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
+ }
+}
+
+
+/* Change the name of frame F to NAME. If NAME is nil, set F's name to
+ w32_id_name.
+
+ If EXPLICIT is non-zero, that indicates that lisp code is setting the
+ name; if NAME is a string, set F's name to NAME and set
+ F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
+
+ If EXPLICIT is zero, that indicates that Emacs redisplay code is
+ suggesting a new name, which lisp code should override; if
+ F->explicit_name is set, ignore the new name; otherwise, set it. */
+
+void
+x_set_name (f, name, explicit)
+ struct frame *f;
+ Lisp_Object name;
+ int explicit;
+{
+ /* Make sure that requests from lisp code override requests from
+ Emacs redisplay code. */
+ if (explicit)
+ {
+ /* If we're switching from explicit to implicit, we had better
+ update the mode lines and thereby update the title. */
+ if (f->explicit_name && NILP (name))
+ update_mode_lines = 1;
+
+ f->explicit_name = ! NILP (name);
+ }
+ else if (f->explicit_name)
+ return;
+
+ /* If NAME is nil, set the name to the w32_id_name. */
+ if (NILP (name))
+ {
+ /* Check for no change needed in this very common case
+ before we do any consing. */
+ if (!strcmp (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name,
+ XSTRING (f->name)->data))
+ return;
+ name = build_string (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name);
+ }
+ else
+ CHECK_STRING (name);
+
+ /* Don't change the name if it's already NAME. */
+ if (! NILP (Fstring_equal (name, f->name)))
+ return;
+
+ f->name = name;
+
+ /* For setting the frame title, the title parameter should override
+ the name parameter. */
+ if (! NILP (f->title))
+ name = f->title;
+
+ if (FRAME_MAC_WINDOW (f))
+ {
+ if (STRING_MULTIBYTE (name))
+#if 0 /* MAC_TODO: encoding title string */
+ name = ENCODE_SYSTEM (name);
+#else
+ return;
+#endif
+
+ BLOCK_INPUT;
+
+ {
+ Str255 windowTitle;
+ if (strlen (XSTRING (name)->data) < 255)
+ {
+ strcpy (windowTitle, XSTRING (name)->data);
+ c2pstr (windowTitle);
+ SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
+ }
+ }
+
+ UNBLOCK_INPUT;
+ }
+}
+
+/* This function should be called when the user's lisp code has
+ specified a name for the frame; the name will override any set by the
+ redisplay code. */
+void
+x_explicitly_set_name (f, arg, oldval)
+ FRAME_PTR f;
+ Lisp_Object arg, oldval;
+{
+ x_set_name (f, arg, 1);
+}
+
+/* This function should be called by Emacs redisplay code to set the
+ name; names set this way will never override names set by the user's
+ lisp code. */
+void
+x_implicitly_set_name (f, arg, oldval)
+ FRAME_PTR f;
+ Lisp_Object arg, oldval;
+{
+ x_set_name (f, arg, 0);
+}
+
+/* Change the title of frame F to NAME.
+ If NAME is nil, use the frame name as the title.
+
+ If EXPLICIT is non-zero, that indicates that lisp code is setting the
+ name; if NAME is a string, set F's name to NAME and set
+ F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
+
+ If EXPLICIT is zero, that indicates that Emacs redisplay code is
+ suggesting a new name, which lisp code should override; if
+ F->explicit_name is set, ignore the new name; otherwise, set it. */
+
+void
+x_set_title (f, name, old_name)
+ struct frame *f;
+ Lisp_Object name, old_name;
+{
+ /* Don't change the title if it's already NAME. */
+ if (EQ (name, f->title))
+ return;
+
+ update_mode_lines = 1;
+
+ f->title = name;
+
+ if (NILP (name))
+ name = f->name;
+
+ if (FRAME_MAC_WINDOW (f))
+ {
+ if (STRING_MULTIBYTE (name))
+#if 0 /* MAC_TODO: encoding title string */
+ name = ENCODE_SYSTEM (name);
+#else
+ return;
+#endif
+
+ BLOCK_INPUT;
+
+ {
+ Str255 windowTitle;
+ if (strlen (XSTRING (name)->data) < 255)
+ {
+ strcpy (windowTitle, XSTRING (name)->data);
+ c2pstr (windowTitle);
+ SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
+ }
+ }
+
+ UNBLOCK_INPUT;
+ }
+}
+
+void
+x_set_autoraise (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ f->auto_raise = !EQ (Qnil, arg);
+}
+
+void
+x_set_autolower (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ f->auto_lower = !EQ (Qnil, arg);
+}
+
+void
+x_set_unsplittable (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ f->no_split = !NILP (arg);
+}
+
+void
+x_set_vertical_scroll_bars (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+ || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
+ || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
+ {
+ FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
+ = (NILP (arg)
+ ? vertical_scroll_bar_none
+ : EQ (Qright, arg)
+ ? vertical_scroll_bar_right
+ : vertical_scroll_bar_left);
+
+ /* We set this parameter before creating the window for the
+ frame, so we can get the geometry right from the start.
+ However, if the window hasn't been created yet, we shouldn't
+ call x_set_window_size. */
+ if (FRAME_MAC_WINDOW (f))
+ x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
+ do_pending_window_change (0);
+ }
+}
+
+void
+x_set_scroll_bar_width (f, arg, oldval)
+ struct frame *f;
+ Lisp_Object arg, oldval;
+{
+ /* Imitate X without X Toolkit */
+
+ int wid = FONT_WIDTH (f->output_data.mac->font);
+
+ if (NILP (arg))
+ {
+#ifdef MAC_OSX
+ FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 16; /* Aqua scroll bars. */
+ FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
+ wid - 1) / wid;
+#else /* not MAC_OSX */
+ /* Make the actual width at least 14 pixels and a multiple of a
+ character width. */
+ FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
+
+ /* Use all of that space (aside from required margins) for the
+ scroll bar. */
+ FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
+#endif /* not MAC_OSX */
+ if (FRAME_MAC_WINDOW (f))
+ x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
+ do_pending_window_change (0);
+ }
+ else if (INTEGERP (arg) && XINT (arg) > 0
+ && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
+ {
+ if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
+ XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
+
+ FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
+ FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
+ if (FRAME_MAC_WINDOW (f))
+ x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
+ do_pending_window_change (0);
+ }
+ change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
+ XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
+ XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
+}
+
+/* Subroutines of creating an frame. */
+
+/* Make sure that Vx_resource_name is set to a reasonable value.
+ Fix it up, or set it to `emacs' if it is too hopeless. */
+
+static void
+validate_x_resource_name ()
+{
+ int len = 0;
+ /* Number of valid characters in the resource name. */
+ int good_count = 0;
+ /* Number of invalid characters in the resource name. */
+ int bad_count = 0;
+ Lisp_Object new;
+ int i;
+
+ if (STRINGP (Vx_resource_name))
+ {
+ unsigned char *p = XSTRING (Vx_resource_name)->data;
+ int i;
+
+ len = STRING_BYTES (XSTRING (Vx_resource_name));
+
+ /* Only letters, digits, - and _ are valid in resource names.
+ Count the valid characters and count the invalid ones. */
+ for (i = 0; i < len; i++)
+ {
+ int c = p[i];
+ if (! ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '-' || c == '_'))
+ bad_count++;
+ else
+ good_count++;
+ }
+ }
+ else
+ /* Not a string => completely invalid. */
+ bad_count = 5, good_count = 0;
+
+ /* If name is valid already, return. */
+ if (bad_count == 0)
+ return;
+
+ /* If name is entirely invalid, or nearly so, use `emacs'. */
+ if (good_count == 0
+ || (good_count == 1 && bad_count > 0))
+ {
+ Vx_resource_name = build_string ("emacs");
+ return;
+ }
+
+ /* Name is partly valid. Copy it and replace the invalid characters
+ with underscores. */
+
+ Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
+
+ for (i = 0; i < len; i++)
+ {
+ int c = XSTRING (new)->data[i];
+ if (! ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '-' || c == '_'))
+ XSTRING (new)->data[i] = '_';
+ }
+}
+
+
+#if 0 /* MAC_TODO: implement resource strings */
+extern char *x_get_string_resource ();
+
+DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
+ doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
+This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
+class, where INSTANCE is the name under which Emacs was invoked, or
+the name specified by the `-name' or `-rn' command-line arguments.
+
+The optional arguments COMPONENT and SUBCLASS add to the key and the
+class, respectively. You must specify both of them or neither.
+If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
+and the class is `Emacs.CLASS.SUBCLASS'. */)
+ (attribute, class, component, subclass)
+ Lisp_Object attribute, class, component, subclass;
+{
+ register char *value;
+ char *name_key;
+ char *class_key;
+
+ CHECK_STRING (attribute);
+ CHECK_STRING (class);
+
+ if (!NILP (component))
+ CHECK_STRING (component);
+ if (!NILP (subclass))
+ CHECK_STRING (subclass);
+ if (NILP (component) != NILP (subclass))
+ error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
+
+ validate_x_resource_name ();
+
+ /* Allocate space for the components, the dots which separate them,
+ and the final '\0'. Make them big enough for the worst case. */
+ name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
+ + (STRINGP (component)
+ ? STRING_BYTES (XSTRING (component)) : 0)
+ + STRING_BYTES (XSTRING (attribute))
+ + 3);
+
+ class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
+ + STRING_BYTES (XSTRING (class))
+ + (STRINGP (subclass)
+ ? STRING_BYTES (XSTRING (subclass)) : 0)
+ + 3);
+
+ /* Start with emacs.FRAMENAME for the name (the specific one)
+ and with `Emacs' for the class key (the general one). */
+ strcpy (name_key, XSTRING (Vx_resource_name)->data);
+ strcpy (class_key, EMACS_CLASS);
+
+ strcat (class_key, ".");
+ strcat (class_key, XSTRING (class)->data);
+
+ if (!NILP (component))
+ {
+ strcat (class_key, ".");
+ strcat (class_key, XSTRING (subclass)->data);
+
+ strcat (name_key, ".");
+ strcat (name_key, XSTRING (component)->data);
+ }
+
+ strcat (name_key, ".");
+ strcat (name_key, XSTRING (attribute)->data);
+
+ value = x_get_string_resource (Qnil,
+ name_key, class_key);
+
+ if (value != (char *) 0)
+ return build_string (value);
+ else
+ return Qnil;
+}
+
+/* Used when C code wants a resource value. */
+
+char *
+x_get_resource_string (attribute, class)
+ char *attribute, *class;
+{
+ char *name_key;
+ char *class_key;
+ struct frame *sf = SELECTED_FRAME ();
+
+ /* Allocate space for the components, the dots which separate them,
+ and the final '\0'. */
+ name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
+ + strlen (attribute) + 2);
+ class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
+ + strlen (class) + 2);
+
+ sprintf (name_key, "%s.%s",
+ XSTRING (Vinvocation_name)->data,
+ attribute);
+ sprintf (class_key, "%s.%s", EMACS_CLASS, class);
+
+ return x_get_string_resource (sf, name_key, class_key);
+}
+#endif /* MAC_TODO */
+
+/* Types we might convert a resource string into. */
+enum resource_types
+{
+ RES_TYPE_NUMBER,
+ RES_TYPE_FLOAT,
+ RES_TYPE_BOOLEAN,
+ RES_TYPE_STRING,
+ RES_TYPE_SYMBOL
+};
+
+/* Return the value of parameter PARAM.
+
+ First search ALIST, then Vdefault_frame_alist, then the X defaults
+ database, using ATTRIBUTE as the attribute name and CLASS as its class.
+
+ Convert the resource to the type specified by desired_type.
+
+ If no default is specified, return Qunbound. If you call
+ w32_get_arg, make sure you deal with Qunbound in a reasonable way,
+ and don't let it get stored in any Lisp-visible variables! */
+
+static Lisp_Object
+mac_get_arg (alist, param, attribute, class, type)
+ Lisp_Object alist, param;
+ char *attribute;
+ char *class;
+ enum resource_types type;
+{
+ register Lisp_Object tem;
+
+ tem = Fassq (param, alist);
+ if (EQ (tem, Qnil))
+ tem = Fassq (param, Vdefault_frame_alist);
+ if (EQ (tem, Qnil))
+ {
+
+#if 0 /* MAC_TODO: search resource also */
+ if (attribute)
+ {
+ tem = Fx_get_resource (build_string (attribute),
+ build_string (class),
+ Qnil, Qnil);
+
+ if (NILP (tem))
+ return Qunbound;
+
+ switch (type)
+ {
+ case RES_TYPE_NUMBER:
+ return make_number (atoi (XSTRING (tem)->data));
+
+ case RES_TYPE_FLOAT:
+ return make_float (atof (XSTRING (tem)->data));
+
+ case RES_TYPE_BOOLEAN:
+ tem = Fdowncase (tem);
+ if (!strcmp (XSTRING (tem)->data, "on")
+ || !strcmp (XSTRING (tem)->data, "true"))
+ return Qt;
+ else
+ return Qnil;
+
+ case RES_TYPE_STRING:
+ return tem;
+
+ case RES_TYPE_SYMBOL:
+ /* As a special case, we map the values `true' and `on'
+ to Qt, and `false' and `off' to Qnil. */
+ {
+ Lisp_Object lower;
+ lower = Fdowncase (tem);
+ if (!strcmp (XSTRING (lower)->data, "on")
+ || !strcmp (XSTRING (lower)->data, "true"))
+ return Qt;
+ else if (!strcmp (XSTRING (lower)->data, "off")
+ || !strcmp (XSTRING (lower)->data, "false"))
+ return Qnil;
+ else
+ return Fintern (tem, Qnil);
+ }
+
+ default:
+ abort ();
+ }
+ }
+ else
+#endif /* MAC_TODO */
+ return Qunbound;
+ }
+ return Fcdr (tem);
+}
+
+/* Record in frame F the specified or default value according to ALIST
+ of the parameter named PROP (a Lisp symbol).
+ If no value is specified for PROP, look for an X default for XPROP
+ on the frame named NAME.
+ If that is not found either, use the value DEFLT. */
+
+static Lisp_Object
+x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
+ struct frame *f;
+ Lisp_Object alist;
+ Lisp_Object prop;
+ Lisp_Object deflt;
+ char *xprop;
+ char *xclass;
+ enum resource_types type;
+{
+ Lisp_Object tem;
+
+ tem = mac_get_arg (alist, prop, xprop, xclass, type);
+ if (EQ (tem, Qunbound))
+ tem = deflt;
+ x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
+ return tem;
+}
+
+/* XParseGeometry copied from w32xfns.c */
+
+/*
+ * XParseGeometry parses strings of the form
+ * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
+ * width, height, xoffset, and yoffset are unsigned integers.
+ * Example: "=80x24+300-49"
+ * The equal sign is optional.
+ * It returns a bitmask that indicates which of the four values
+ * were actually found in the string. For each value found,
+ * the corresponding argument is updated; for each value
+ * not found, the corresponding argument is left unchanged.
+ */
+
+static int
+read_integer (string, NextString)
+ register char *string;
+ char **NextString;
+{
+ register int Result = 0;
+ int Sign = 1;
+
+ if (*string == '+')
+ string++;
+ else if (*string == '-')
+ {
+ string++;
+ Sign = -1;
+ }
+ for (; (*string >= '0') && (*string <= '9'); string++)
+ {
+ Result = (Result * 10) + (*string - '0');
+ }
+ *NextString = string;
+ if (Sign >= 0)
+ return (Result);
+ else
+ return (-Result);
+}
+
+int
+XParseGeometry (string, x, y, width, height)
+ char *string;
+ int *x, *y;
+ unsigned int *width, *height; /* RETURN */
+{
+ int mask = NoValue;
+ register char *strind;
+ unsigned int tempWidth, tempHeight;
+ int tempX, tempY;
+ char *nextCharacter;
+
+ if ((string == NULL) || (*string == '\0')) return (mask);
+ if (*string == '=')
+ string++; /* ignore possible '=' at beg of geometry spec */
+
+ strind = (char *)string;
+ if (*strind != '+' && *strind != '-' && *strind != 'x')
+ {
+ tempWidth = read_integer (strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return (0);
+ strind = nextCharacter;
+ mask |= WidthValue;
+ }
+
+ if (*strind == 'x' || *strind == 'X')
+ {
+ strind++;
+ tempHeight = read_integer (strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return (0);
+ strind = nextCharacter;
+ mask |= HeightValue;
+ }
+
+ if ((*strind == '+') || (*strind == '-'))
+ {
+ if (*strind == '-')
+ {
+ strind++;
+ tempX = -read_integer (strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return (0);
+ strind = nextCharacter;
+ mask |= XNegative;
+
+ }
+ else
+ {
+ strind++;
+ tempX = read_integer (strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return (0);
+ strind = nextCharacter;
+ }
+ mask |= XValue;
+ if ((*strind == '+') || (*strind == '-'))
+ {
+ if (*strind == '-')
+ {
+ strind++;
+ tempY = -read_integer (strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return (0);
+ strind = nextCharacter;
+ mask |= YNegative;
+
+ }
+ else
+ {
+ strind++;
+ tempY = read_integer (strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return (0);
+ strind = nextCharacter;
+ }
+ mask |= YValue;
+ }
+ }
+
+ /* If strind isn't at the end of the string the it's an invalid
+ geometry specification. */
+
+ if (*strind != '\0') return (0);
+
+ if (mask & XValue)
+ *x = tempX;
+ if (mask & YValue)
+ *y = tempY;
+ if (mask & WidthValue)
+ *width = tempWidth;
+ if (mask & HeightValue)
+ *height = tempHeight;
+ return (mask);
+}
+
+DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
+ doc: /* Parse an X-style geometry string STRING.
+Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
+The properties returned may include `top', `left', `height', and `width'.
+The value of `left' or `top' may be an integer,
+or a list (+ N) meaning N pixels relative to top/left corner,
+or a list (- N) meaning -N pixels relative to bottom/right corner. */)
+ (string)
+ Lisp_Object string;
+{
+ int geometry, x, y;
+ unsigned int width, height;
+ Lisp_Object result;
+
+ CHECK_STRING (string);
+
+ geometry = XParseGeometry ((char *) XSTRING (string)->data,
+ &x, &y, &width, &height);
+
+ result = Qnil;
+ if (geometry & XValue)
+ {
+ Lisp_Object element;
+
+ if (x >= 0 && (geometry & XNegative))
+ element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
+ else if (x < 0 && ! (geometry & XNegative))
+ element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
+ else
+ element = Fcons (Qleft, make_number (x));
+ result = Fcons (element, result);
+ }
+
+ if (geometry & YValue)
+ {
+ Lisp_Object element;
+
+ if (y >= 0 && (geometry & YNegative))
+ element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
+ else if (y < 0 && ! (geometry & YNegative))
+ element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
+ else
+ element = Fcons (Qtop, make_number (y));
+ result = Fcons (element, result);
+ }
+
+ if (geometry & WidthValue)
+ result = Fcons (Fcons (Qwidth, make_number (width)), result);
+ if (geometry & HeightValue)
+ result = Fcons (Fcons (Qheight, make_number (height)), result);
+
+ return result;
+}
+
+/* Calculate the desired size and position of this window,
+ and return the flags saying which aspects were specified.
+
+ This function does not make the coordinates positive. */
+
+#define DEFAULT_ROWS 40
+#define DEFAULT_COLS 80
+
+static int
+x_figure_window_size (f, parms)
+ struct frame *f;
+ Lisp_Object parms;
+{
+ register Lisp_Object tem0, tem1, tem2;
+ long window_prompting = 0;
+
+ /* Default values if we fall through.
+ Actually, if that happens we should get
+ window manager prompting. */
+ SET_FRAME_WIDTH (f, DEFAULT_COLS);
+ f->height = DEFAULT_ROWS;
+ /* Window managers expect that if program-specified
+ positions are not (0,0), they're intentional, not defaults. */
+ f->output_data.mac->top_pos = 0;
+ f->output_data.mac->left_pos = 0;
+
+ tem0 = mac_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
+ tem1 = mac_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
+ tem2 = mac_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
+ if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
+ {
+ if (!EQ (tem0, Qunbound))
+ {
+ CHECK_NUMBER (tem0);
+ f->height = XINT (tem0);
+ }
+ if (!EQ (tem1, Qunbound))
+ {
+ CHECK_NUMBER (tem1);
+ SET_FRAME_WIDTH (f, XINT (tem1));
+ }
+ if (!NILP (tem2) && !EQ (tem2, Qunbound))
+ window_prompting |= USSize;
+ else
+ window_prompting |= PSize;
+ }
+
+ f->output_data.mac->vertical_scroll_bar_extra
+ = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+ ? 0
+ : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
+ ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
+ : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
+
+ x_compute_fringe_widths (f, 0);
+
+ f->output_data.mac->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
+ f->output_data.mac->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
+
+ tem0 = mac_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
+ tem1 = mac_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
+ tem2 = mac_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
+ if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
+ {
+ if (EQ (tem0, Qminus))
+ {
+ f->output_data.mac->top_pos = 0;
+ window_prompting |= YNegative;
+ }
+ else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
+ && CONSP (XCDR (tem0))
+ && INTEGERP (XCAR (XCDR (tem0))))
+ {
+ f->output_data.mac->top_pos = - XINT (XCAR (XCDR (tem0)));
+ window_prompting |= YNegative;
+ }
+ else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
+ && CONSP (XCDR (tem0))
+ && INTEGERP (XCAR (XCDR (tem0))))
+ {
+ f->output_data.mac->top_pos = XINT (XCAR (XCDR (tem0)));
+ }
+ else if (EQ (tem0, Qunbound))
+ f->output_data.mac->top_pos = 0;
+ else
+ {
+ CHECK_NUMBER (tem0);
+ f->output_data.mac->top_pos = XINT (tem0);
+ if (f->output_data.mac->top_pos < 0)
+ window_prompting |= YNegative;
+ }
+
+ if (EQ (tem1, Qminus))
+ {
+ f->output_data.mac->left_pos = 0;
+ window_prompting |= XNegative;
+ }
+ else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
+ && CONSP (XCDR (tem1))
+ && INTEGERP (XCAR (XCDR (tem1))))
+ {
+ f->output_data.mac->left_pos = - XINT (XCAR (XCDR (tem1)));
+ window_prompting |= XNegative;
+ }
+ else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
+ && CONSP (XCDR (tem1))
+ && INTEGERP (XCAR (XCDR (tem1))))
+ {
+ f->output_data.mac->left_pos = XINT (XCAR (XCDR (tem1)));
+ }
+ else if (EQ (tem1, Qunbound))
+ f->output_data.mac->left_pos = 0;
+ else
+ {
+ CHECK_NUMBER (tem1);
+ f->output_data.mac->left_pos = XINT (tem1);
+ if (f->output_data.mac->left_pos < 0)
+ window_prompting |= XNegative;
+ }
+
+ if (!NILP (tem2) && ! EQ (tem2, Qunbound))
+ window_prompting |= USPosition;
+ else
+ window_prompting |= PPosition;
+ }
+
+ return window_prompting;
+}
+
+
+#if 0 /* MAC_TODO */
+/* Create and set up the Mac window for frame F. */
+
+static void
+mac_window (f, window_prompting, minibuffer_only)
+ struct frame *f;
+ long window_prompting;
+ int minibuffer_only;
+{
+ Rect r;
+
+ BLOCK_INPUT;
+
+ /* Use the resource name as the top-level window name
+ for looking up resources. Make a non-Lisp copy
+ for the window manager, so GC relocation won't bother it.
+
+ Elsewhere we specify the window name for the window manager. */
+
+ {
+ char *str = (char *) XSTRING (Vx_resource_name)->data;
+ f->namebuf = (char *) xmalloc (strlen (str) + 1);
+ strcpy (f->namebuf, str);
+ }
+
+ SetRect (&r, f->output_data.mac->left_pos, f->output_data.mac->top_pos,
+ f->output_data.mac->left_pos + PIXEL_WIDTH (f),
+ f->output_data.mac->top_pos + PIXEL_HEIGHT (f));
+ FRAME_MAC_WINDOW (f)
+ = NewCWindow (NULL, &r, "\p", 1, zoomDocProc, (WindowPtr) -1, 1, (long) f->output_data.mac);
+
+ validate_x_resource_name ();
+
+ /* x_set_name normally ignores requests to set the name if the
+ requested name is the same as the current name. This is the one
+ place where that assumption isn't correct; f->name is set, but
+ the server hasn't been told. */
+ {
+ Lisp_Object name;
+ int explicit = f->explicit_name;
+
+ f->explicit_name = 0;
+ name = f->name;
+ f->name = Qnil;
+ x_set_name (f, name, explicit);
+ }
+
+ ShowWindow (FRAME_MAC_WINDOW (f));
+
+ UNBLOCK_INPUT;
+
+ if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
+ initialize_frame_menubar (f);
+
+ if (FRAME_MAC_WINDOW (f) == 0)
+ error ("Unable to create window");
+}
+#endif /* MAC_TODO */
+
+/* Handle the icon stuff for this window. Perhaps later we might
+ want an x_set_icon_position which can be called interactively as
+ well. */
+
+static void
+x_icon (f, parms)
+ struct frame *f;
+ Lisp_Object parms;
+{
+ Lisp_Object icon_x, icon_y;
+
+ /* Set the position of the icon. Note that Windows 95 groups all
+ icons in the tray. */
+ icon_x = mac_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
+ icon_y = mac_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
+ if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
+ {
+ CHECK_NUMBER (icon_x);
+ CHECK_NUMBER (icon_y);
+ }
+ else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
+ error ("Both left and top icon corners of icon must be specified");
+
+ BLOCK_INPUT;
+
+ if (! EQ (icon_x, Qunbound))
+ x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
+
+#if 0 /* TODO */
+ /* Start up iconic or window? */
+ x_wm_set_window_state
+ (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
+ ? IconicState
+ : NormalState));
+
+ x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
+ ? f->icon_name
+ : f->name))->data);
+#endif
+
+ UNBLOCK_INPUT;
+}
+
+
+void
+x_make_gc (f)
+ struct frame *f;
+{
+ XGCValues gc_values;
+
+ BLOCK_INPUT;
+
+ /* Create the GC's of this frame.
+ Note that many default values are used. */
+
+ /* Normal video */
+ gc_values.font = f->output_data.mac->font;
+ gc_values.foreground = FRAME_FOREGROUND_PIXEL (f);
+ gc_values.background = FRAME_BACKGROUND_PIXEL (f);
+ f->output_data.mac->normal_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
+ FRAME_MAC_WINDOW (f),
+ GCFont | GCForeground | GCBackground,
+ &gc_values);
+
+ /* Reverse video style. */
+ gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
+ gc_values.background = FRAME_FOREGROUND_PIXEL (f);
+ f->output_data.mac->reverse_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
+ FRAME_MAC_WINDOW (f),
+ GCFont | GCForeground | GCBackground,
+ &gc_values);
+
+ /* Cursor has cursor-color background, background-color foreground. */
+ gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
+ gc_values.background = f->output_data.mac->cursor_pixel;
+ f->output_data.mac->cursor_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
+ FRAME_MAC_WINDOW (f),
+ GCFont | GCForeground | GCBackground,
+ &gc_values);
+
+ /* Reliefs. */
+ f->output_data.mac->white_relief.gc = 0;
+ f->output_data.mac->black_relief.gc = 0;
+
+ UNBLOCK_INPUT;
+}
+
+
+DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
+ 1, 1, 0,
+ doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
+Returns an Emacs frame object.
+ALIST is an alist of frame parameters.
+If the parameters specify that the frame should not have a minibuffer,
+and do not specify a specific minibuffer window to use,
+then `default-minibuffer-frame' must be a frame whose minibuffer can
+be shared by the new frame.
+
+This function is an internal primitive--use `make-frame' instead. */)
+ (parms)
+ Lisp_Object parms;
+{
+ struct frame *f;
+ Lisp_Object frame, tem;
+ Lisp_Object name;
+ int minibuffer_only = 0;
+ long window_prompting = 0;
+ int width, height;
+ int count = BINDING_STACK_SIZE ();
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ Lisp_Object display;
+ struct mac_display_info *dpyinfo = NULL;
+ Lisp_Object parent;
+ struct kboard *kb;
+ char x_frame_name[10];
+ static int x_frame_count = 2; /* begins at 2 because terminal frame is F1 */
+
+ check_mac ();
+
+ /* Use this general default value to start with
+ until we know if this frame has a specified name. */
+ Vx_resource_name = Vinvocation_name;
+
+ display = mac_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
+ if (EQ (display, Qunbound))
+ display = Qnil;
+ dpyinfo = check_x_display_info (display);
+#ifdef MULTI_KBOARD
+ kb = dpyinfo->kboard;
+#else
+ kb = &the_only_kboard;
+#endif
+
+ name = mac_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
+ if (!STRINGP (name)
+ && ! EQ (name, Qunbound)
+ && ! NILP (name))
+ error ("Invalid frame name--not a string or nil");
+
+ if (STRINGP (name))
+ Vx_resource_name = name;
+
+ /* See if parent window is specified. */
+ parent = mac_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
+ if (EQ (parent, Qunbound))
+ parent = Qnil;
+ if (! NILP (parent))
+ CHECK_NUMBER (parent);
+
+ /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
+ /* No need to protect DISPLAY because that's not used after passing
+ it to make_frame_without_minibuffer. */
+ frame = Qnil;
+ GCPRO4 (parms, parent, name, frame);
+ tem = mac_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
+ RES_TYPE_SYMBOL);
+ if (EQ (tem, Qnone) || NILP (tem))
+ f = make_frame_without_minibuffer (Qnil, kb, display);
+ else if (EQ (tem, Qonly))
+ {
+ f = make_minibuffer_frame ();
+ minibuffer_only = 1;
+ }
+ else if (WINDOWP (tem))
+ f = make_frame_without_minibuffer (tem, kb, display);
+ else
+ f = make_frame (1);
+
+ if (EQ (name, Qunbound) || NILP (name))
+ {
+ sprintf (x_frame_name, "F%d", x_frame_count++);
+ f->name = build_string (x_frame_name);
+ f->explicit_name = 0;
+ }
+ else
+ {
+ f->name = name;
+ f->explicit_name = 1;
+ }
+
+ XSETFRAME (frame, f);
+
+ /* Note that X Windows does support scroll bars. */
+ FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
+
+ f->output_method = output_mac;
+ f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output));
+ bzero (f->output_data.mac, sizeof (struct mac_output));
+ FRAME_FONTSET (f) = -1;
+ f->output_data.mac->scroll_bar_foreground_pixel = -1;
+ f->output_data.mac->scroll_bar_background_pixel = -1;
+
+#if 0
+ FRAME_FONTSET (f) = -1;
+#endif
+
+ f->icon_name
+ = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
+ if (! STRINGP (f->icon_name))
+ f->icon_name = Qnil;
+
+/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
+#ifdef MULTI_KBOARD
+ FRAME_KBOARD (f) = kb;
+#endif
+
+ /* Specify the parent under which to make this window. */
+
+ if (!NILP (parent))
+ {
+ f->output_data.mac->parent_desc = (Window) parent;
+ f->output_data.mac->explicit_parent = 1;
+ }
+ else
+ {
+ f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
+ f->output_data.mac->explicit_parent = 0;
+ }
+
+ /* Set the name; the functions to which we pass f expect the name to
+ be set. */
+ if (EQ (name, Qunbound) || NILP (name))
+ {
+ f->name = build_string (dpyinfo->mac_id_name);
+ f->explicit_name = 0;
+ }
+ else
+ {
+ f->name = name;
+ f->explicit_name = 1;
+ /* use the frame's title when getting resources for this frame. */
+ specbind (Qx_resource_name, name);
+ }
+
+ /* Extract the window parameters from the supplied values
+ that are needed to determine window geometry. */
+ {
+ Lisp_Object font;
+
+ font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
+
+ BLOCK_INPUT;
+ /* First, try whatever font the caller has specified. */
+ if (STRINGP (font))
+ {
+ tem = Fquery_fontset (font, Qnil);
+ if (STRINGP (tem))
+ font = x_new_fontset (f, XSTRING (tem)->data);
+ else
+ font = x_new_font (f, XSTRING (font)->data);
+ }
+ /* Try out a font which we hope has bold and italic variations. */
+ if (! STRINGP (font))
+ font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1");
+ /* If those didn't work, look for something which will at least work. */
+ if (!STRINGP (font))
+ font = x_new_font (f, "-*-monaco-*-12-*-mac-roman");
+ if (! STRINGP (font))
+ font = x_new_font (f, "-*-courier-*-10-*-mac-roman");
+ if (! STRINGP (font))
+ error ("Cannot find any usable font");
+ UNBLOCK_INPUT;
+
+ x_default_parameter (f, parms, Qfont, font,
+ "font", "Font", RES_TYPE_STRING);
+ }
+
+ x_default_parameter (f, parms, Qborder_width, make_number (0),
+ "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
+ /* This defaults to 2 in order to match xterm. We recognize either
+ internalBorderWidth or internalBorder (which is what xterm calls
+ it). */
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ {
+ Lisp_Object value;
+
+ value = mac_get_arg (parms, Qinternal_border_width,
+ "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
+ if (! EQ (value, Qunbound))
+ parms = Fcons (Fcons (Qinternal_border_width, value),
+ parms);
+ }
+ /* Default internalBorderWidth to 0 on Windows to match other programs. */
+ x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
+ "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
+ x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
+ "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
+
+ /* Also do the stuff which must be set before the window exists. */
+ x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
+ "foreground", "Foreground", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
+ "background", "Background", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
+ "pointerColor", "Foreground", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
+ "cursorColor", "Foreground", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qborder_color, build_string ("black"),
+ "borderColor", "BorderColor", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qscreen_gamma, Qnil,
+ "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
+ x_default_parameter (f, parms, Qline_spacing, Qnil,
+ "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
+ x_default_parameter (f, parms, Qleft_fringe, Qnil,
+ "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
+ x_default_parameter (f, parms, Qright_fringe, Qnil,
+ "rightFringe", "RightFringe", RES_TYPE_NUMBER);
+
+
+ /* Init faces before x_default_parameter is called for scroll-bar
+ parameters because that function calls x_set_scroll_bar_width,
+ which calls change_frame_size, which calls Fset_window_buffer,
+ which runs hooks, which call Fvertical_motion. At the end, we
+ end up in init_iterator with a null face cache, which should not
+ happen. */
+ init_frame_faces (f);
+
+ x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
+ "menuBar", "MenuBar", RES_TYPE_NUMBER);
+ x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
+ "toolBar", "ToolBar", RES_TYPE_NUMBER);
+ x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
+ "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
+ x_default_parameter (f, parms, Qtitle, Qnil,
+ "title", "Title", RES_TYPE_STRING);
+
+ f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
+ window_prompting = x_figure_window_size (f, parms);
+
+ if (window_prompting & XNegative)
+ {
+ if (window_prompting & YNegative)
+ f->output_data.mac->win_gravity = SouthEastGravity;
+ else
+ f->output_data.mac->win_gravity = NorthEastGravity;
+ }
+ else
+ {
+ if (window_prompting & YNegative)
+ f->output_data.mac->win_gravity = SouthWestGravity;
+ else
+ f->output_data.mac->win_gravity = NorthWestGravity;
+ }
+
+ f->output_data.mac->size_hint_flags = window_prompting;
+
+ tem = mac_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
+ f->no_split = minibuffer_only || EQ (tem, Qt);
+
+ /* Create the window. Add the tool-bar height to the initial frame
+ height so that the user gets a text display area of the size he
+ specified with -g or via the registry. Later changes of the
+ tool-bar height don't change the frame size. This is done so that
+ users can create tall Emacs frames without having to guess how
+ tall the tool-bar will get. */
+ f->height += FRAME_TOOL_BAR_LINES (f);
+
+ /* mac_window (f, window_prompting, minibuffer_only); */
+ make_mac_frame (f);
+
+ x_icon (f, parms);
+
+ x_make_gc (f);
+
+ /* Now consider the frame official. */
+ FRAME_MAC_DISPLAY_INFO (f)->reference_count++;
+ Vframe_list = Fcons (frame, Vframe_list);
+
+ /* We need to do this after creating the window, so that the
+ icon-creation functions can say whose icon they're describing. */
+ x_default_parameter (f, parms, Qicon_type, Qnil,
+ "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
+
+ x_default_parameter (f, parms, Qauto_raise, Qnil,
+ "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ x_default_parameter (f, parms, Qauto_lower, Qnil,
+ "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ x_default_parameter (f, parms, Qcursor_type, Qbox,
+ "cursorType", "CursorType", RES_TYPE_SYMBOL);
+ x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
+ "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
+
+ /* Dimensions, especially f->height, must be done via change_frame_size.
+ Change will not be effected unless different from the current
+ f->height. */
+ width = f->width;
+ height = f->height;
+
+ f->height = 0;
+ SET_FRAME_WIDTH (f, 0);
+ change_frame_size (f, height, width, 1, 0, 0);
+
+ /* Set up faces after all frame parameters are known. */
+ call1 (Qface_set_after_frame_default, frame);
+
+#if 0 /* MAC_TODO: when we have window manager hints */
+ /* Tell the server what size and position, etc, we want, and how
+ badly we want them. This should be done after we have the menu
+ bar so that its size can be taken into account. */
+ BLOCK_INPUT;
+ x_wm_set_size_hint (f, window_prompting, 0);
+ UNBLOCK_INPUT;
+#endif
+
+ /* Make the window appear on the frame and enable display, unless
+ the caller says not to. However, with explicit parent, Emacs
+ cannot control visibility, so don't try. */
+ if (! f->output_data.mac->explicit_parent)
+ {
+ Lisp_Object visibility;
+
+ visibility = mac_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
+ if (EQ (visibility, Qunbound))
+ visibility = Qt;
+
+#if 0 /* MAC_TODO: really no iconify on Mac */
+ if (EQ (visibility, Qicon))
+ x_iconify_frame (f);
+ else
+#endif
+ if (! NILP (visibility))
+ x_make_frame_visible (f);
+ else
+ /* Must have been Qnil. */
+ ;
+ }
+ UNGCPRO;
+
+ /* Make sure windows on this frame appear in calls to next-window
+ and similar functions. */
+ Vwindow_list = Qnil;
+
+ return unbind_to (count, frame);
+}
+
+/* FRAME is used only to get a handle on the X display. We don't pass the
+ display info directly because we're called from frame.c, which doesn't
+ know about that structure. */
+Lisp_Object
+x_get_focus_frame (frame)
+ struct frame *frame;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
+ Lisp_Object xfocus;
+ if (! dpyinfo->x_focus_frame)
+ return Qnil;
+
+ XSETFRAME (xfocus, dpyinfo->x_focus_frame);
+ return xfocus;
+}
+
+DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
+ doc: /* Internal function called by `color-defined-p', which see. */)
+ (color, frame)
+ Lisp_Object color, frame;
+{
+ XColor foo;
+ FRAME_PTR f = check_x_frame (frame);
+
+ CHECK_STRING (color);
+
+ if (mac_defined_color (f, XSTRING (color)->data, &foo, 0))
+ return Qt;
+ else
+ return Qnil;
+}
+
+DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
+ doc: /* Internal function called by `color-values', which see. */)
+ (color, frame)
+ Lisp_Object color, frame;
+{
+ XColor foo;
+ FRAME_PTR f = check_x_frame (frame);
+
+ CHECK_STRING (color);
+
+ if (mac_defined_color (f, XSTRING (color)->data, &foo, 0))
+ {
+ Lisp_Object rgb[3];
+
+ rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8)
+ | RED_FROM_ULONG (foo.pixel));
+ rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8)
+ | GREEN_FROM_ULONG (foo.pixel));
+ rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8)
+ | BLUE_FROM_ULONG (foo.pixel));
+ return Flist (3, rgb);
+ }
+ else
+ return Qnil;
+}
+
+DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
+ doc: /* Internal function called by `display-color-p', which see. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
+ return Qnil;
+
+ return Qt;
+}
+
+DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
+ 0, 1, 0,
+ doc: /* Return t if the X display supports shades of gray.
+Note that color displays do support shades of gray.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
+ return Qnil;
+
+ return Qt;
+}
+
+DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
+ 0, 1, 0,
+ doc: /* Returns the width in pixels of the X display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ return make_number (dpyinfo->width);
+}
+
+DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
+ Sx_display_pixel_height, 0, 1, 0,
+ doc: /* Returns the height in pixels of the X display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ return make_number (dpyinfo->height);
+}
+
+DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
+ 0, 1, 0,
+ doc: /* Returns the number of bitplanes of the display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
+}
+
+DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
+ 0, 1, 0,
+ doc: /* Returns the number of color cells of the display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ /* MAC_TODO: check whether this is right */
+ return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits)));
+}
+
+DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
+ Sx_server_max_request_size,
+ 0, 1, 0,
+ doc: /* Returns the maximum request size of the server of display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+ return make_number (1);
+}
+
+DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
+ doc: /* Returns the vendor ID string of the Mac OS system (Apple).
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ return build_string ("Apple Computers");
+}
+
+DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
+ doc: /* Returns the version numbers of the server of display DISPLAY.
+The value is a list of three integers: the major and minor
+version numbers, and the vendor-specific release
+number. See also the function `x-server-vendor'.
+
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ int mac_major_version, mac_minor_version;
+ SInt32 response;
+
+ if (Gestalt (gestaltSystemVersion, &response) != noErr)
+ error ("Cannot get Mac OS version");
+
+ mac_major_version = (response >> 8) & 0xf;
+ mac_minor_version = (response >> 4) & 0xf;
+
+ return Fcons (make_number (mac_major_version),
+ Fcons (make_number (mac_minor_version), Qnil));
+}
+
+DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
+ doc: /* Return the number of screens on the server of display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ return make_number (1);
+}
+
+DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
+ doc: /* Return the height in millimeters of the X display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ /* MAC_TODO: this is an approximation, and only of the main display */
+
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+ short h, v;
+
+ ScreenRes (&h, &v);
+
+ return make_number ((int) (v / 72.0 * 25.4));
+}
+
+DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
+ doc: /* Return the width in millimeters of the X display DISPLAY.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ /* MAC_TODO: this is an approximation, and only of the main display */
+
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+ short h, v;
+
+ ScreenRes (&h, &v);
+
+ return make_number ((int) (h / 72.0 * 25.4));
+}
+
+DEFUN ("x-display-backing-store", Fx_display_backing_store,
+ Sx_display_backing_store, 0, 1, 0,
+ doc: /* Returns an indication of whether display DISPLAY does backing store.
+The value may be `always', `when-mapped', or `not-useful'.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ return intern ("not-useful");
+}
+
+DEFUN ("x-display-visual-class", Fx_display_visual_class,
+ Sx_display_visual_class, 0, 1, 0,
+ doc: /* Returns the visual class of the display DISPLAY.
+The value is one of the symbols `static-gray', `gray-scale',
+`static-color', `pseudo-color', `true-color', or `direct-color'.
+
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+
+#if 0
+ switch (dpyinfo->visual->class)
+ {
+ case StaticGray: return (intern ("static-gray"));
+ case GrayScale: return (intern ("gray-scale"));
+ case StaticColor: return (intern ("static-color"));
+ case PseudoColor: return (intern ("pseudo-color"));
+ case TrueColor: return (intern ("true-color"));
+ case DirectColor: return (intern ("direct-color"));
+ default:
+ error ("Display has an unknown visual class");
+ }
+#endif /* 0 */
+
+ error ("Display has an unknown visual class");
+}
+
+DEFUN ("x-display-save-under", Fx_display_save_under,
+ Sx_display_save_under, 0, 1, 0,
+ doc: /* Returns t if the display DISPLAY supports the save-under feature.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ return Qnil;
+}
+
+int
+x_pixel_width (f)
+ register struct frame *f;
+{
+ return PIXEL_WIDTH (f);
+}
+
+int
+x_pixel_height (f)
+ register struct frame *f;
+{
+ return PIXEL_HEIGHT (f);
+}
+
+int
+x_char_width (f)
+ register struct frame *f;
+{
+ return FONT_WIDTH (f->output_data.mac->font);
+}
+
+int
+x_char_height (f)
+ register struct frame *f;
+{
+ return f->output_data.mac->line_height;
+}
+
+int
+x_screen_planes (f)
+ register struct frame *f;
+{
+ return FRAME_MAC_DISPLAY_INFO (f)->n_planes;
+}
+
+/* Return the display structure for the display named NAME.
+ Open a new connection if necessary. */
+
+struct mac_display_info *
+x_display_info_for_name (name)
+ Lisp_Object name;
+{
+ Lisp_Object names;
+ struct mac_display_info *dpyinfo;
+
+ CHECK_STRING (name);
+
+ for (dpyinfo = &one_mac_display_info, names = x_display_name_list;
+ dpyinfo;
+ dpyinfo = dpyinfo->next, names = XCDR (names))
+ {
+ Lisp_Object tem;
+ tem = Fstring_equal (XCAR (XCAR (names)), name);
+ if (!NILP (tem))
+ return dpyinfo;
+ }
+
+ /* Use this general default value to start with. */
+ Vx_resource_name = Vinvocation_name;
+
+ validate_x_resource_name ();
+
+ dpyinfo = mac_term_init (name, (unsigned char *) 0,
+ (char *) XSTRING (Vx_resource_name)->data);
+
+ if (dpyinfo == 0)
+ error ("Cannot connect to server %s", XSTRING (name)->data);
+
+ mac_in_use = 1;
+ XSETFASTINT (Vwindow_system_version, 3);
+
+ return dpyinfo;
+}
+
+#if 0 /* MAC_TODO: implement network support */
+DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
+ 1, 3, 0,
+ doc: /* Open a connection to a server.
+DISPLAY is the name of the display to connect to.
+Optional second arg XRM-STRING is a string of resources in xrdb format.
+If the optional third arg MUST-SUCCEED is non-nil,
+terminate Emacs if we can't open the connection. */)
+ (display, xrm_string, must_succeed)
+ Lisp_Object display, xrm_string, must_succeed;
+{
+ unsigned char *xrm_option;
+ struct mac_display_info *dpyinfo;
+
+ CHECK_STRING (display);
+ if (! NILP (xrm_string))
+ CHECK_STRING (xrm_string);
+
+ if (! EQ (Vwindow_system, intern ("mac")))
+ error ("Not using Mac OS");
+
+ if (! NILP (xrm_string))
+ xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
+ else
+ xrm_option = (unsigned char *) 0;
+
+ validate_x_resource_name ();
+
+ /* This is what opens the connection and sets x_current_display.
+ This also initializes many symbols, such as those used for input. */
+ dpyinfo = mac_term_init (display, xrm_option,
+ (char *) XSTRING (Vx_resource_name)->data);
+
+ if (dpyinfo == 0)
+ {
+ if (!NILP (must_succeed))
+ fatal ("Cannot connect to server %s.\n",
+ XSTRING (display)->data);
+ else
+ error ("Cannot connect to server %s", XSTRING (display)->data);
+ }
+
+ mac_in_use = 1;
+
+ XSETFASTINT (Vwindow_system_version, 3);
+ return Qnil;
+}
+
+DEFUN ("x-close-connection", Fx_close_connection,
+ Sx_close_connection, 1, 1, 0,
+ doc: /* Close the connection to DISPLAY's server.
+For DISPLAY, specify either a frame or a display name (a string).
+If DISPLAY is nil, that stands for the selected frame's display. */)
+ (display)
+ Lisp_Object display;
+{
+ struct mac_display_info *dpyinfo = check_x_display_info (display);
+ int i;
+
+ if (dpyinfo->reference_count > 0)
+ error ("Display still has frames on it");
+
+ BLOCK_INPUT;
+ /* Free the fonts in the font table. */
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ if (dpyinfo->font_table[i].name)
+ {
+ if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
+ xfree (dpyinfo->font_table[i].full_name);
+ xfree (dpyinfo->font_table[i].name);
+ x_unload_font (dpyinfo, dpyinfo->font_table[i].font);
+ }
+ x_destroy_all_bitmaps (dpyinfo);
+
+ x_delete_display (dpyinfo);
+ UNBLOCK_INPUT;
+
+ return Qnil;
+}
+#endif /* 0 */
+
+DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
+ doc: /* Return the list of display names that Emacs has connections to. */)
+ ()
+{
+ Lisp_Object tail, result;
+
+ result = Qnil;
+ for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
+ result = Fcons (XCAR (XCAR (tail)), result);
+
+ return result;
+}
+
+DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
+ doc: /* If ON is non-nil, report errors as soon as the erring request is made.
+If ON is nil, allow buffering of requests.
+This is a noop on Mac OS systems.
+The optional second argument DISPLAY specifies which display to act on.
+DISPLAY should be either a frame or a display name (a string).
+If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
+ (on, display)
+ Lisp_Object display, on;
+{
+ return Qnil;
+}
+
+
+/***********************************************************************
+ Image types
+ ***********************************************************************/
+
+/* Value is the number of elements of vector VECTOR. */
+
+#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
+
+/* List of supported image types. Use define_image_type to add new
+ types. Use lookup_image_type to find a type for a given symbol. */
+
+static struct image_type *image_types;
+
+/* The symbol `image' which is the car of the lists used to represent
+ images in Lisp. */
+
+extern Lisp_Object Qimage;
+
+/* The symbol `xbm' which is used as the type symbol for XBM images. */
+
+Lisp_Object Qxbm;
+
+/* Keywords. */
+
+extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
+extern Lisp_Object QCdata, QCtype;
+Lisp_Object QCascent, QCmargin, QCrelief;
+Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
+Lisp_Object QCindex;
+
+/* Other symbols. */
+
+Lisp_Object Qlaplace;
+
+/* Time in seconds after which images should be removed from the cache
+ if not displayed. */
+
+Lisp_Object Vimage_cache_eviction_delay;
+
+/* Function prototypes. */
+
+static void define_image_type P_ ((struct image_type *type));
+static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
+static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
+static void x_laplace P_ ((struct frame *, struct image *));
+static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
+ Lisp_Object));
+
+
+/* Define a new image type from TYPE. This adds a copy of TYPE to
+ image_types and adds the symbol *TYPE->type to Vimage_types. */
+
+static void
+define_image_type (type)
+ struct image_type *type;
+{
+ /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
+ The initialized data segment is read-only. */
+ struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
+ bcopy (type, p, sizeof *p);
+ p->next = image_types;
+ image_types = p;
+ Vimage_types = Fcons (*p->type, Vimage_types);
+}
+
+
+/* Look up image type SYMBOL, and return a pointer to its image_type
+ structure. Value is null if SYMBOL is not a known image type. */
+
+static INLINE struct image_type *
+lookup_image_type (symbol)
+ Lisp_Object symbol;
+{
+ struct image_type *type;
+
+ for (type = image_types; type; type = type->next)
+ if (EQ (symbol, *type->type))
+ break;
+
+ return type;
+}
+
+
+/* Value is non-zero if OBJECT is a valid Lisp image specification. A
+ valid image specification is a list whose car is the symbol
+ `image', and whose rest is a property list. The property list must
+ contain a value for key `:type'. That value must be the name of a
+ supported image type. The rest of the property list depends on the
+ image type. */
+
+int
+valid_image_p (object)
+ Lisp_Object object;
+{
+ int valid_p = 0;
+
+ if (CONSP (object) && EQ (XCAR (object), Qimage))
+ {
+ Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
+ struct image_type *type = lookup_image_type (symbol);
+
+ if (type)
+ valid_p = type->valid_p (object);
+ }
+
+ return valid_p;
+}
+
+
+/* Log error message with format string FORMAT and argument ARG.
+ Signaling an error, e.g. when an image cannot be loaded, is not a
+ good idea because this would interrupt redisplay, and the error
+ message display would lead to another redisplay. This function
+ therefore simply displays a message. */
+
+static void
+image_error (format, arg1, arg2)
+ char *format;
+ Lisp_Object arg1, arg2;
+{
+ add_to_log (format, arg1, arg2);
+}
+
+
+
+/***********************************************************************
+ Image specifications
+ ***********************************************************************/
+
+enum image_value_type
+{
+ IMAGE_DONT_CHECK_VALUE_TYPE,
+ IMAGE_STRING_VALUE,
+ IMAGE_SYMBOL_VALUE,
+ IMAGE_POSITIVE_INTEGER_VALUE,
+ IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
+ IMAGE_NON_NEGATIVE_INTEGER_VALUE,
+ IMAGE_ASCENT_VALUE,
+ IMAGE_INTEGER_VALUE,
+ IMAGE_FUNCTION_VALUE,
+ IMAGE_NUMBER_VALUE,
+ IMAGE_BOOL_VALUE
+};
+
+/* Structure used when parsing image specifications. */
+
+struct image_keyword
+{
+ /* Name of keyword. */
+ char *name;
+
+ /* The type of value allowed. */
+ enum image_value_type type;
+
+ /* Non-zero means key must be present. */
+ int mandatory_p;
+
+ /* Used to recognize duplicate keywords in a property list. */
+ int count;
+
+ /* The value that was found. */
+ Lisp_Object value;
+};
+
+
+static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
+ int, Lisp_Object));
+static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
+
+
+/* Parse image spec SPEC according to KEYWORDS. A valid image spec
+ has the format (image KEYWORD VALUE ...). One of the keyword/
+ value pairs must be `:type TYPE'. KEYWORDS is a vector of
+ image_keywords structures of size NKEYWORDS describing other
+ allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
+
+static int
+parse_image_spec (spec, keywords, nkeywords, type)
+ Lisp_Object spec;
+ struct image_keyword *keywords;
+ int nkeywords;
+ Lisp_Object type;
+{
+ int i;
+ Lisp_Object plist;
+
+ if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
+ return 0;
+
+ plist = XCDR (spec);
+ while (CONSP (plist))
+ {
+ Lisp_Object key, value;
+
+ /* First element of a pair must be a symbol. */
+ key = XCAR (plist);
+ plist = XCDR (plist);
+ if (!SYMBOLP (key))
+ return 0;
+
+ /* There must follow a value. */
+ if (!CONSP (plist))
+ return 0;
+ value = XCAR (plist);
+ plist = XCDR (plist);
+
+ /* Find key in KEYWORDS. Error if not found. */
+ for (i = 0; i < nkeywords; ++i)
+ if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
+ break;
+
+ if (i == nkeywords)
+ continue;
+
+ /* Record that we recognized the keyword. If a keywords
+ was found more than once, it's an error. */
+ keywords[i].value = value;
+ ++keywords[i].count;
+
+ if (keywords[i].count > 1)
+ return 0;
+
+ /* Check type of value against allowed type. */
+ switch (keywords[i].type)
+ {
+ case IMAGE_STRING_VALUE:
+ if (!STRINGP (value))
+ return 0;
+ break;
+
+ case IMAGE_SYMBOL_VALUE:
+ if (!SYMBOLP (value))
+ return 0;
+ break;
+
+ case IMAGE_POSITIVE_INTEGER_VALUE:
+ if (!INTEGERP (value) || XINT (value) <= 0)
+ return 0;
+ break;
+
+ case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
+ if (INTEGERP (value) && XINT (value) >= 0)
+ break;
+ if (CONSP (value)
+ && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
+ && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
+ break;
+ return 0;
+
+ case IMAGE_ASCENT_VALUE:
+ if (SYMBOLP (value) && EQ (value, Qcenter))
+ break;
+ else if (INTEGERP (value)
+ && XINT (value) >= 0
+ && XINT (value) <= 100)
+ break;
+ return 0;
+
+ case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
+ if (!INTEGERP (value) || XINT (value) < 0)
+ return 0;
+ break;
+
+ case IMAGE_DONT_CHECK_VALUE_TYPE:
+ break;
+
+ case IMAGE_FUNCTION_VALUE:
+ value = indirect_function (value);
+ if (SUBRP (value)
+ || COMPILEDP (value)
+ || (CONSP (value) && EQ (XCAR (value), Qlambda)))
+ break;
+ return 0;
+
+ case IMAGE_NUMBER_VALUE:
+ if (!INTEGERP (value) && !FLOATP (value))
+ return 0;
+ break;
+
+ case IMAGE_INTEGER_VALUE:
+ if (!INTEGERP (value))
+ return 0;
+ break;
+
+ case IMAGE_BOOL_VALUE:
+ if (!NILP (value) && !EQ (value, Qt))
+ return 0;
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ if (EQ (key, QCtype) && !EQ (type, value))
+ return 0;
+ }
+
+ /* Check that all mandatory fields are present. */
+ for (i = 0; i < nkeywords; ++i)
+ if (keywords[i].mandatory_p && keywords[i].count == 0)
+ return 0;
+
+ return NILP (plist);
+}
+
+
+/* Return the value of KEY in image specification SPEC. Value is nil
+ if KEY is not present in SPEC. if FOUND is not null, set *FOUND
+ to 1 if KEY was found in SPEC, set it to 0 otherwise. */
+
+static Lisp_Object
+image_spec_value (spec, key, found)
+ Lisp_Object spec, key;
+ int *found;
+{
+ Lisp_Object tail;
+
+ xassert (valid_image_p (spec));
+
+ for (tail = XCDR (spec);
+ CONSP (tail) && CONSP (XCDR (tail));
+ tail = XCDR (XCDR (tail)))
+ {
+ if (EQ (XCAR (tail), key))
+ {
+ if (found)
+ *found = 1;
+ return XCAR (XCDR (tail));
+ }
+ }
+
+ if (found)
+ *found = 0;
+ return Qnil;
+}
+
+
+
+
+/***********************************************************************
+ Image type independent image structures
+ ***********************************************************************/
+
+static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
+static void free_image P_ ((struct frame *f, struct image *img));
+
+
+/* Allocate and return a new image structure for image specification
+ SPEC. SPEC has a hash value of HASH. */
+
+static struct image *
+make_image (spec, hash)
+ Lisp_Object spec;
+ unsigned hash;
+{
+ struct image *img = (struct image *) xmalloc (sizeof *img);
+
+ xassert (valid_image_p (spec));
+ bzero (img, sizeof *img);
+ img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
+ xassert (img->type != NULL);
+ img->spec = spec;
+ img->data.lisp_val = Qnil;
+ img->ascent = DEFAULT_IMAGE_ASCENT;
+ img->hash = hash;
+ return img;
+}
+
+
+/* Free image IMG which was used on frame F, including its resources. */
+
+static void
+free_image (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ if (img)
+ {
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+
+ /* Remove IMG from the hash table of its cache. */
+ if (img->prev)
+ img->prev->next = img->next;
+ else
+ c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
+
+ if (img->next)
+ img->next->prev = img->prev;
+
+ c->images[img->id] = NULL;
+
+ /* Free resources, then free IMG. */
+ img->type->free (f, img);
+ xfree (img);
+ }
+}
+
+
+/* Prepare image IMG for display on frame F. Must be called before
+ drawing an image. */
+
+void
+prepare_image_for_display (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ EMACS_TIME t;
+
+ /* We're about to display IMG, so set its timestamp to `now'. */
+ EMACS_GET_TIME (t);
+ img->timestamp = EMACS_SECS (t);
+
+ /* If IMG doesn't have a pixmap yet, load it now, using the image
+ type dependent loader function. */
+ if (img->pixmap == 0 && !img->load_failed_p)
+ img->load_failed_p = img->type->load (f, img) == 0;
+}
+
+
+/* Value is the number of pixels for the ascent of image IMG when
+ drawn in face FACE. */
+
+int
+image_ascent (img, face)
+ struct image *img;
+ struct face *face;
+{
+ int height = img->height + img->vmargin;
+ int ascent;
+
+ if (img->ascent == CENTERED_IMAGE_ASCENT)
+ {
+ if (face->font)
+ ascent = height / 2 - (FONT_DESCENT(face->font)
+ - FONT_BASE(face->font)) / 2;
+ else
+ ascent = height / 2;
+ }
+ else
+ ascent = height * img->ascent / 100.0;
+
+ return ascent;
+}
+
+
+
+/***********************************************************************
+ Helper functions for X image types
+ ***********************************************************************/
+
+static void x_clear_image P_ ((struct frame *f, struct image *img));
+static unsigned long x_alloc_image_color P_ ((struct frame *f,
+ struct image *img,
+ Lisp_Object color_name,
+ unsigned long dflt));
+
+/* Free X resources of image IMG which is used on frame F. */
+
+static void
+x_clear_image (f, img)
+ struct frame *f;
+ struct image *img;
+{
+#if 0 /* MAC_TODO: W32 image support */
+
+ if (img->pixmap)
+ {
+ BLOCK_INPUT;
+ XFreePixmap (NULL, img->pixmap);
+ img->pixmap = 0;
+ UNBLOCK_INPUT;
+ }
+
+ if (img->ncolors)
+ {
+ int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
+
+ /* If display has an immutable color map, freeing colors is not
+ necessary and some servers don't allow it. So don't do it. */
+ if (class != StaticColor
+ && class != StaticGray
+ && class != TrueColor)
+ {
+ Colormap cmap;
+ BLOCK_INPUT;
+ cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
+ XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
+ img->ncolors, 0);
+ UNBLOCK_INPUT;
+ }
+
+ xfree (img->colors);
+ img->colors = NULL;
+ img->ncolors = 0;
+ }
+#endif /* MAC_TODO */
+}
+
+
+/* Allocate color COLOR_NAME for image IMG on frame F. If color
+ cannot be allocated, use DFLT. Add a newly allocated color to
+ IMG->colors, so that it can be freed again. Value is the pixel
+ color. */
+
+static unsigned long
+x_alloc_image_color (f, img, color_name, dflt)
+ struct frame *f;
+ struct image *img;
+ Lisp_Object color_name;
+ unsigned long dflt;
+{
+#if 0 /* MAC_TODO: allocing colors. */
+ XColor color;
+ unsigned long result;
+
+ xassert (STRINGP (color_name));
+
+ if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
+ {
+ /* This isn't called frequently so we get away with simply
+ reallocating the color vector to the needed size, here. */
+ ++img->ncolors;
+ img->colors =
+ (unsigned long *) xrealloc (img->colors,
+ img->ncolors * sizeof *img->colors);
+ img->colors[img->ncolors - 1] = color.pixel;
+ result = color.pixel;
+ }
+ else
+ result = dflt;
+ return result;
+#endif /* MAC_TODO */
+ return 0;
+}
+
+
+
+/***********************************************************************
+ Image Cache
+ ***********************************************************************/
+
+static void cache_image P_ ((struct frame *f, struct image *img));
+
+
+/* Return a new, initialized image cache that is allocated from the
+ heap. Call free_image_cache to free an image cache. */
+
+struct image_cache *
+make_image_cache ()
+{
+ struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
+ int size;
+
+ bzero (c, sizeof *c);
+ c->size = 50;
+ c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
+ size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
+ c->buckets = (struct image **) xmalloc (size);
+ bzero (c->buckets, size);
+ return c;
+}
+
+
+/* Free image cache of frame F. Be aware that X frames share images
+ caches. */
+
+void
+free_image_cache (f)
+ struct frame *f;
+{
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+ if (c)
+ {
+ int i;
+
+ /* Cache should not be referenced by any frame when freed. */
+ xassert (c->refcount == 0);
+
+ for (i = 0; i < c->used; ++i)
+ free_image (f, c->images[i]);
+ xfree (c->images);
+ xfree (c->buckets);
+ xfree (c);
+ FRAME_X_IMAGE_CACHE (f) = NULL;
+ }
+}
+
+
+/* Clear image cache of frame F. FORCE_P non-zero means free all
+ images. FORCE_P zero means clear only images that haven't been
+ displayed for some time. Should be called from time to time to
+ reduce the number of loaded images. If image-eviction-seconds is
+ non-nil, this frees images in the cache which weren't displayed for
+ at least that many seconds. */
+
+void
+clear_image_cache (f, force_p)
+ struct frame *f;
+ int force_p;
+{
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+
+ if (c && INTEGERP (Vimage_cache_eviction_delay))
+ {
+ EMACS_TIME t;
+ unsigned long old;
+ int i, any_freed_p = 0;
+
+ EMACS_GET_TIME (t);
+ old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
+
+ for (i = 0; i < c->used; ++i)
+ {
+ struct image *img = c->images[i];
+ if (img != NULL
+ && (force_p
+ || (img->timestamp > old)))
+ {
+ free_image (f, img);
+ any_freed_p = 1;
+ }
+ }
+
+ /* We may be clearing the image cache because, for example,
+ Emacs was iconified for a longer period of time. In that
+ case, current matrices may still contain references to
+ images freed above. So, clear these matrices. */
+ if (any_freed_p)
+ {
+ clear_current_matrices (f);
+ ++windows_or_buffers_changed;
+ }
+ }
+}
+
+
+DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
+ 0, 1, 0,
+ doc: /* Clear the image cache of FRAME.
+FRAME nil or omitted means use the selected frame.
+FRAME t means clear the image caches of all frames. */)
+ (frame)
+ Lisp_Object frame;
+{
+ if (EQ (frame, Qt))
+ {
+ Lisp_Object tail;
+
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_MAC_P (XFRAME (frame)))
+ clear_image_cache (XFRAME (frame), 1);
+ }
+ else
+ clear_image_cache (check_x_frame (frame), 1);
+
+ return Qnil;
+}
+
+
+/* Return the id of image with Lisp specification SPEC on frame F.
+ SPEC must be a valid Lisp image specification (see valid_image_p). */
+
+int
+lookup_image (f, spec)
+ struct frame *f;
+ Lisp_Object spec;
+{
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+ struct image *img;
+ int i;
+ unsigned hash;
+ struct gcpro gcpro1;
+ EMACS_TIME now;
+
+ /* F must be a window-system frame, and SPEC must be a valid image
+ specification. */
+ xassert (FRAME_WINDOW_P (f));
+ xassert (valid_image_p (spec));
+
+ GCPRO1 (spec);
+
+ /* Look up SPEC in the hash table of the image cache. */
+ hash = sxhash (spec, 0);
+ i = hash % IMAGE_CACHE_BUCKETS_SIZE;
+
+ for (img = c->buckets[i]; img; img = img->next)
+ if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
+ break;
+
+ /* If not found, create a new image and cache it. */
+ if (img == NULL)
+ {
+ BLOCK_INPUT;
+ img = make_image (spec, hash);
+ cache_image (f, img);
+ img->load_failed_p = img->type->load (f, img) == 0;
+ xassert (!interrupt_input_blocked);
+
+ /* If we can't load the image, and we don't have a width and
+ height, use some arbitrary width and height so that we can
+ draw a rectangle for it. */
+ if (img->load_failed_p)
+ {
+ Lisp_Object value;
+
+ value = image_spec_value (spec, QCwidth, NULL);
+ img->width = (INTEGERP (value)
+ ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
+ value = image_spec_value (spec, QCheight, NULL);
+ img->height = (INTEGERP (value)
+ ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
+ }
+ else
+ {
+ /* Handle image type independent image attributes
+ `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
+ Lisp_Object ascent, margin, relief;
+
+ ascent = image_spec_value (spec, QCascent, NULL);
+ if (INTEGERP (ascent))
+ img->ascent = XFASTINT (ascent);
+ else if (EQ (ascent, Qcenter))
+ img->ascent = CENTERED_IMAGE_ASCENT;
+
+ margin = image_spec_value (spec, QCmargin, NULL);
+ if (INTEGERP (margin) && XINT (margin) >= 0)
+ img->vmargin = img->hmargin = XFASTINT (margin);
+ else if (CONSP (margin) && INTEGERP (XCAR (margin))
+ && INTEGERP (XCDR (margin)))
+ {
+ if (XINT (XCAR (margin)) > 0)
+ img->hmargin = XFASTINT (XCAR (margin));
+ if (XINT (XCDR (margin)) > 0)
+ img->vmargin = XFASTINT (XCDR (margin));
+ }
+
+ relief = image_spec_value (spec, QCrelief, NULL);
+ if (INTEGERP (relief))
+ {
+ img->relief = XINT (relief);
+ img->hmargin += abs (img->relief);
+ img->vmargin += abs (img->relief);
+ }
+ }
+ }
+
+ /* We're using IMG, so set its timestamp to `now'. */
+ EMACS_GET_TIME (now);
+ img->timestamp = EMACS_SECS (now);
+
+ UNGCPRO;
+
+ /* Value is the image id. */
+ return img->id;
+}
+
+
+/* Cache image IMG in the image cache of frame F. */
+
+static void
+cache_image (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+ int i;
+
+ /* Find a free slot in c->images. */
+ for (i = 0; i < c->used; ++i)
+ if (c->images[i] == NULL)
+ break;
+
+ /* If no free slot found, maybe enlarge c->images. */
+ if (i == c->used && c->used == c->size)
+ {
+ c->size *= 2;
+ c->images = (struct image **) xrealloc (c->images,
+ c->size * sizeof *c->images);
+ }
+
+ /* Add IMG to c->images, and assign IMG an id. */
+ c->images[i] = img;
+ img->id = i;
+ if (i == c->used)
+ ++c->used;
+
+ /* Add IMG to the cache's hash table. */
+ i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
+ img->next = c->buckets[i];
+ if (img->next)
+ img->next->prev = img;
+ img->prev = NULL;
+ c->buckets[i] = img;
+}
+
+
+/* Call FN on every image in the image cache of frame F. Used to mark
+ Lisp Objects in the image cache. */
+
+void
+forall_images_in_image_cache (f, fn)
+ struct frame *f;
+ void (*fn) P_ ((struct image *img));
+{
+ if (FRAME_LIVE_P (f) && FRAME_MAC_P (f))
+ {
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+ if (c)
+ {
+ int i;
+ for (i = 0; i < c->used; ++i)
+ if (c->images[i])
+ fn (c->images[i]);
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ Mac support code
+ ***********************************************************************/
+
+#if 0 /* MAC_TODO: Mac specific image code. */
+
+static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
+ XImage **, Pixmap *));
+static void x_destroy_x_image P_ ((XImage *));
+static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
+
+
+/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
+ frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
+ Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
+ via xmalloc. Print error messages via image_error if an error
+ occurs. Value is non-zero if successful. */
+
+static int
+x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
+ struct frame *f;
+ int width, height, depth;
+ XImage **ximg;
+ Pixmap *pixmap;
+{
+#if 0 /* MAC_TODO: Image support for Mac */
+ Display *display = FRAME_W32_DISPLAY (f);
+ Screen *screen = FRAME_X_SCREEN (f);
+ Window window = FRAME_W32_WINDOW (f);
+
+ xassert (interrupt_input_blocked);
+
+ if (depth <= 0)
+ depth = DefaultDepthOfScreen (screen);
+ *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
+ depth, ZPixmap, 0, NULL, width, height,
+ depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
+ if (*ximg == NULL)
+ {
+ image_error ("Unable to allocate X image", Qnil, Qnil);
+ return 0;
+ }
+
+ /* Allocate image raster. */
+ (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
+
+ /* Allocate a pixmap of the same size. */
+ *pixmap = XCreatePixmap (display, window, width, height, depth);
+ if (*pixmap == 0)
+ {
+ x_destroy_x_image (*ximg);
+ *ximg = NULL;
+ image_error ("Unable to create X pixmap", Qnil, Qnil);
+ return 0;
+ }
+#endif /* MAC_TODO */
+ return 1;
+}
+
+
+/* Destroy XImage XIMG. Free XIMG->data. */
+
+static void
+x_destroy_x_image (ximg)
+ XImage *ximg;
+{
+ xassert (interrupt_input_blocked);
+ if (ximg)
+ {
+ xfree (ximg->data);
+ ximg->data = NULL;
+ XDestroyImage (ximg);
+ }
+}
+
+
+/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
+ are width and height of both the image and pixmap. */
+
+static void
+x_put_x_image (f, ximg, pixmap, width, height)
+ struct frame *f;
+ XImage *ximg;
+ Pixmap pixmap;
+{
+ GC gc;
+
+ xassert (interrupt_input_blocked);
+ gc = XCreateGC (NULL, pixmap, 0, NULL);
+ XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
+ XFreeGC (NULL, gc);
+}
+
+#endif /* MAC_TODO */
+
+
+/***********************************************************************
+ Searching files
+ ***********************************************************************/
+
+static Lisp_Object x_find_image_file P_ ((Lisp_Object));
+
+/* Find image file FILE. Look in data-directory, then
+ x-bitmap-file-path. Value is the full name of the file found, or
+ nil if not found. */
+
+static Lisp_Object
+x_find_image_file (file)
+ Lisp_Object file;
+{
+ Lisp_Object file_found, search_path;
+ struct gcpro gcpro1, gcpro2;
+ int fd;
+
+ file_found = Qnil;
+ search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
+ GCPRO2 (file_found, search_path);
+
+ /* Try to find FILE in data-directory, then x-bitmap-file-path. */
+ fd = openp (search_path, file, Qnil, &file_found, 0);
+
+ if (fd < 0)
+ file_found = Qnil;
+ else
+ close (fd);
+
+ UNGCPRO;
+ return file_found;
+}
+
+
+/***********************************************************************
+ XBM images
+ ***********************************************************************/
+
+static int xbm_load P_ ((struct frame *f, struct image *img));
+static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
+ Lisp_Object file));
+static int xbm_image_p P_ ((Lisp_Object object));
+static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
+ unsigned char **));
+
+
+/* Indices of image specification fields in xbm_format, below. */
+
+enum xbm_keyword_index
+{
+ XBM_TYPE,
+ XBM_FILE,
+ XBM_WIDTH,
+ XBM_HEIGHT,
+ XBM_DATA,
+ XBM_FOREGROUND,
+ XBM_BACKGROUND,
+ XBM_ASCENT,
+ XBM_MARGIN,
+ XBM_RELIEF,
+ XBM_ALGORITHM,
+ XBM_HEURISTIC_MASK,
+ XBM_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid XBM image specifications. */
+
+static struct image_keyword xbm_format[XBM_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
+ {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
+ {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":foreground", IMAGE_STRING_VALUE, 0},
+ {":background", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type XBM. */
+
+static struct image_type xbm_type =
+{
+ &Qxbm,
+ xbm_image_p,
+ xbm_load,
+ x_clear_image,
+ NULL
+};
+
+/* Tokens returned from xbm_scan. */
+
+enum xbm_token
+{
+ XBM_TK_IDENT = 256,
+ XBM_TK_NUMBER
+};
+
+
+/* Return non-zero if OBJECT is a valid XBM-type image specification.
+ A valid specification is a list starting with the symbol `image'
+ The rest of the list is a property list which must contain an
+ entry `:type xbm..
+
+ If the specification specifies a file to load, it must contain
+ an entry `:file FILENAME' where FILENAME is a string.
+
+ If the specification is for a bitmap loaded from memory it must
+ contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
+ WIDTH and HEIGHT are integers > 0. DATA may be:
+
+ 1. a string large enough to hold the bitmap data, i.e. it must
+ have a size >= (WIDTH + 7) / 8 * HEIGHT
+
+ 2. a bool-vector of size >= WIDTH * HEIGHT
+
+ 3. a vector of strings or bool-vectors, one for each line of the
+ bitmap.
+
+ Both the file and data forms may contain the additional entries
+ `:background COLOR' and `:foreground COLOR'. If not present,
+ foreground and background of the frame on which the image is
+ displayed, is used. */
+
+static int
+xbm_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword kw[XBM_LAST];
+
+ bcopy (xbm_format, kw, sizeof kw);
+ if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
+ return 0;
+
+ xassert (EQ (kw[XBM_TYPE].value, Qxbm));
+
+ if (kw[XBM_FILE].count)
+ {
+ if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
+ return 0;
+ }
+ else
+ {
+ Lisp_Object data;
+ int width, height;
+
+ /* Entries for `:width', `:height' and `:data' must be present. */
+ if (!kw[XBM_WIDTH].count
+ || !kw[XBM_HEIGHT].count
+ || !kw[XBM_DATA].count)
+ return 0;
+
+ data = kw[XBM_DATA].value;
+ width = XFASTINT (kw[XBM_WIDTH].value);
+ height = XFASTINT (kw[XBM_HEIGHT].value);
+
+ /* Check type of data, and width and height against contents of
+ data. */
+ if (VECTORP (data))
+ {
+ int i;
+
+ /* Number of elements of the vector must be >= height. */
+ if (XVECTOR (data)->size < height)
+ return 0;
+
+ /* Each string or bool-vector in data must be large enough
+ for one line of the image. */
+ for (i = 0; i < height; ++i)
+ {
+ Lisp_Object elt = XVECTOR (data)->contents[i];
+
+ if (STRINGP (elt))
+ {
+ if (XSTRING (elt)->size
+ < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
+ return 0;
+ }
+ else if (BOOL_VECTOR_P (elt))
+ {
+ if (XBOOL_VECTOR (elt)->size < width)
+ return 0;
+ }
+ else
+ return 0;
+ }
+ }
+ else if (STRINGP (data))
+ {
+ if (XSTRING (data)->size
+ < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
+ return 0;
+ }
+ else if (BOOL_VECTOR_P (data))
+ {
+ if (XBOOL_VECTOR (data)->size < width * height)
+ return 0;
+ }
+ else
+ return 0;
+ }
+
+ /* Baseline must be a value between 0 and 100 (a percentage). */
+ if (kw[XBM_ASCENT].count
+ && XFASTINT (kw[XBM_ASCENT].value) > 100)
+ return 0;
+
+ return 1;
+}
+
+
+/* Scan a bitmap file. FP is the stream to read from. Value is
+ either an enumerator from enum xbm_token, or a character for a
+ single-character token, or 0 at end of file. If scanning an
+ identifier, store the lexeme of the identifier in SVAL. If
+ scanning a number, store its value in *IVAL. */
+
+static int
+xbm_scan (fp, sval, ival)
+ FILE *fp;
+ char *sval;
+ int *ival;
+{
+ int c;
+
+ /* Skip white space. */
+ while ((c = fgetc (fp)) != EOF && isspace (c))
+ ;
+
+ if (c == EOF)
+ c = 0;
+ else if (isdigit (c))
+ {
+ int value = 0, digit;
+
+ if (c == '0')
+ {
+ c = fgetc (fp);
+ if (c == 'x' || c == 'X')
+ {
+ while ((c = fgetc (fp)) != EOF)
+ {
+ if (isdigit (c))
+ digit = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ digit = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ digit = c - 'A' + 10;
+ else
+ break;
+ value = 16 * value + digit;
+ }
+ }
+ else if (isdigit (c))
+ {
+ value = c - '0';
+ while ((c = fgetc (fp)) != EOF
+ && isdigit (c))
+ value = 8 * value + c - '0';
+ }
+ }
+ else
+ {
+ value = c - '0';
+ while ((c = fgetc (fp)) != EOF
+ && isdigit (c))
+ value = 10 * value + c - '0';
+ }
+
+ if (c != EOF)
+ ungetc (c, fp);
+ *ival = value;
+ c = XBM_TK_NUMBER;
+ }
+ else if (isalpha (c) || c == '_')
+ {
+ *sval++ = c;
+ while ((c = fgetc (fp)) != EOF
+ && (isalnum (c) || c == '_'))
+ *sval++ = c;
+ *sval = 0;
+ if (c != EOF)
+ ungetc (c, fp);
+ c = XBM_TK_IDENT;
+ }
+
+ return c;
+}
+
+
+/* Replacement for XReadBitmapFileData which isn't available under old
+ X versions. FILE is the name of the bitmap file to read. Set
+ *WIDTH and *HEIGHT to the width and height of the image. Return in
+ *DATA the bitmap data allocated with xmalloc. Value is non-zero if
+ successful. */
+
+static int
+xbm_read_bitmap_file_data (file, width, height, data)
+ char *file;
+ int *width, *height;
+ unsigned char **data;
+{
+ FILE *fp;
+ char buffer[BUFSIZ];
+ int padding_p = 0;
+ int v10 = 0;
+ int bytes_per_line, i, nbytes;
+ unsigned char *p;
+ int value;
+ int LA1;
+
+#define match() \
+ LA1 = xbm_scan (fp, buffer, &value)
+
+#define expect(TOKEN) \
+ if (LA1 != (TOKEN)) \
+ goto failure; \
+ else \
+ match ()
+
+#define expect_ident(IDENT) \
+ if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
+ match (); \
+ else \
+ goto failure
+
+ fp = fopen (file, "r");
+ if (fp == NULL)
+ return 0;
+
+ *width = *height = -1;
+ *data = NULL;
+ LA1 = xbm_scan (fp, buffer, &value);
+
+ /* Parse defines for width, height and hot-spots. */
+ while (LA1 == '#')
+ {
+ match ();
+ expect_ident ("define");
+ expect (XBM_TK_IDENT);
+
+ if (LA1 == XBM_TK_NUMBER);
+ {
+ char *p = strrchr (buffer, '_');
+ p = p ? p + 1 : buffer;
+ if (strcmp (p, "width") == 0)
+ *width = value;
+ else if (strcmp (p, "height") == 0)
+ *height = value;
+ }
+ expect (XBM_TK_NUMBER);
+ }
+
+ if (*width < 0 || *height < 0)
+ goto failure;
+
+ /* Parse bits. Must start with `static'. */
+ expect_ident ("static");
+ if (LA1 == XBM_TK_IDENT)
+ {
+ if (strcmp (buffer, "unsigned") == 0)
+ {
+ match ();
+ expect_ident ("char");
+ }
+ else if (strcmp (buffer, "short") == 0)
+ {
+ match ();
+ v10 = 1;
+ if (*width % 16 && *width % 16 < 9)
+ padding_p = 1;
+ }
+ else if (strcmp (buffer, "char") == 0)
+ match ();
+ else
+ goto failure;
+ }
+ else
+ goto failure;
+
+ expect (XBM_TK_IDENT);
+ expect ('[');
+ expect (']');
+ expect ('=');
+ expect ('{');
+
+ bytes_per_line = (*width + 7) / 8 + padding_p;
+ nbytes = bytes_per_line * *height;
+ p = *data = (char *) xmalloc (nbytes);
+
+ if (v10)
+ {
+
+ for (i = 0; i < nbytes; i += 2)
+ {
+ int val = value;
+ expect (XBM_TK_NUMBER);
+
+ *p++ = val;
+ if (!padding_p || ((i + 2) % bytes_per_line))
+ *p++ = value >> 8;
+
+ if (LA1 == ',' || LA1 == '}')
+ match ();
+ else
+ goto failure;
+ }
+ }
+ else
+ {
+ for (i = 0; i < nbytes; ++i)
+ {
+ int val = value;
+ expect (XBM_TK_NUMBER);
+
+ *p++ = val;
+
+ if (LA1 == ',' || LA1 == '}')
+ match ();
+ else
+ goto failure;
+ }
+ }
+
+ fclose (fp);
+ return 1;
+
+ failure:
+
+ fclose (fp);
+ if (*data)
+ {
+ xfree (*data);
+ *data = NULL;
+ }
+ return 0;
+
+#undef match
+#undef expect
+#undef expect_ident
+}
+
+
+/* Load XBM image IMG which will be displayed on frame F from file
+ SPECIFIED_FILE. Value is non-zero if successful. */
+
+static int
+xbm_load_image_from_file (f, img, specified_file)
+ struct frame *f;
+ struct image *img;
+ Lisp_Object specified_file;
+{
+ int rc;
+ unsigned char *data;
+ int success_p = 0;
+ Lisp_Object file;
+ struct gcpro gcpro1;
+
+ xassert (STRINGP (specified_file));
+ file = Qnil;
+ GCPRO1 (file);
+
+ file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
+ &img->height, &data);
+ if (rc)
+ {
+ int depth = one_mac_display_info.n_cbits;
+ unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
+ unsigned long background = FRAME_BACKGROUND_PIXEL (f);
+ Lisp_Object value;
+
+ xassert (img->width > 0 && img->height > 0);
+
+ /* Get foreground and background colors, maybe allocate colors. */
+ value = image_spec_value (img->spec, QCforeground, NULL);
+ if (!NILP (value))
+ foreground = x_alloc_image_color (f, img, value, foreground);
+
+ value = image_spec_value (img->spec, QCbackground, NULL);
+ if (!NILP (value))
+ background = x_alloc_image_color (f, img, value, background);
+
+#if 0 /* MAC_TODO : Port image display to Mac */
+ BLOCK_INPUT;
+ img->pixmap
+ = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
+ FRAME_W32_WINDOW (f),
+ data,
+ img->width, img->height,
+ foreground, background,
+ depth);
+ xfree (data);
+
+ if (img->pixmap == 0)
+ {
+ x_clear_image (f, img);
+ image_error ("Unable to create X pixmap for `%s'", file, Qnil);
+ }
+ else
+ success_p = 1;
+
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+ }
+ else
+ image_error ("Error loading XBM image `%s'", img->spec, Qnil);
+
+ UNGCPRO;
+ return success_p;
+}
+
+
+/* Fill image IMG which is used on frame F with pixmap data. Value is
+ non-zero if successful. */
+
+static int
+xbm_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ int success_p = 0;
+ Lisp_Object file_name;
+
+ xassert (xbm_image_p (img->spec));
+
+ /* If IMG->spec specifies a file name, create a non-file spec from it. */
+ file_name = image_spec_value (img->spec, QCfile, NULL);
+ if (STRINGP (file_name))
+ success_p = xbm_load_image_from_file (f, img, file_name);
+ else
+ {
+ struct image_keyword fmt[XBM_LAST];
+ Lisp_Object data;
+ int depth;
+ unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
+ unsigned long background = FRAME_BACKGROUND_PIXEL (f);
+ char *bits;
+ int parsed_p;
+
+ /* Parse the list specification. */
+ bcopy (xbm_format, fmt, sizeof fmt);
+ parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
+ xassert (parsed_p);
+
+ /* Get specified width, and height. */
+ img->width = XFASTINT (fmt[XBM_WIDTH].value);
+ img->height = XFASTINT (fmt[XBM_HEIGHT].value);
+ xassert (img->width > 0 && img->height > 0);
+
+ BLOCK_INPUT;
+
+ if (fmt[XBM_ASCENT].count)
+ img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
+
+ /* Get foreground and background colors, maybe allocate colors. */
+ if (fmt[XBM_FOREGROUND].count)
+ foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
+ foreground);
+ if (fmt[XBM_BACKGROUND].count)
+ background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
+ background);
+
+ /* Set bits to the bitmap image data. */
+ data = fmt[XBM_DATA].value;
+ if (VECTORP (data))
+ {
+ int i;
+ char *p;
+ int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
+
+ p = bits = (char *) alloca (nbytes * img->height);
+ for (i = 0; i < img->height; ++i, p += nbytes)
+ {
+ Lisp_Object line = XVECTOR (data)->contents[i];
+ if (STRINGP (line))
+ bcopy (XSTRING (line)->data, p, nbytes);
+ else
+ bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
+ }
+ }
+ else if (STRINGP (data))
+ bits = XSTRING (data)->data;
+ else
+ bits = XBOOL_VECTOR (data)->data;
+
+#if 0 /* MAC_TODO : port Mac display code */
+ /* Create the pixmap. */
+ depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
+ img->pixmap
+ = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
+ FRAME_W32_WINDOW (f),
+ bits,
+ img->width, img->height,
+ foreground, background,
+ depth);
+#endif /* MAC_TODO */
+
+ if (img->pixmap)
+ success_p = 1;
+ else
+ {
+ image_error ("Unable to create pixmap for XBM image `%s'",
+ img->spec, Qnil);
+ x_clear_image (f, img);
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+ return success_p;
+}
+
+
+
+/***********************************************************************
+ XPM images
+ ***********************************************************************/
+
+#if HAVE_XPM
+
+static int xpm_image_p P_ ((Lisp_Object object));
+static int xpm_load P_ ((struct frame *f, struct image *img));
+static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
+
+#include "X11/xpm.h"
+
+/* The symbol `xpm' identifying XPM-format images. */
+
+Lisp_Object Qxpm;
+
+/* Indices of image specification fields in xpm_format, below. */
+
+enum xpm_keyword_index
+{
+ XPM_TYPE,
+ XPM_FILE,
+ XPM_DATA,
+ XPM_ASCENT,
+ XPM_MARGIN,
+ XPM_RELIEF,
+ XPM_ALGORITHM,
+ XPM_HEURISTIC_MASK,
+ XPM_COLOR_SYMBOLS,
+ XPM_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid XPM image specifications. */
+
+static struct image_keyword xpm_format[XPM_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type XBM. */
+
+static struct image_type xpm_type =
+{
+ &Qxpm,
+ xpm_image_p,
+ xpm_load,
+ x_clear_image,
+ NULL
+};
+
+
+/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
+ for XPM images. Such a list must consist of conses whose car and
+ cdr are strings. */
+
+static int
+xpm_valid_color_symbols_p (color_symbols)
+ Lisp_Object color_symbols;
+{
+ while (CONSP (color_symbols))
+ {
+ Lisp_Object sym = XCAR (color_symbols);
+ if (!CONSP (sym)
+ || !STRINGP (XCAR (sym))
+ || !STRINGP (XCDR (sym)))
+ break;
+ color_symbols = XCDR (color_symbols);
+ }
+
+ return NILP (color_symbols);
+}
+
+
+/* Value is non-zero if OBJECT is a valid XPM image specification. */
+
+static int
+xpm_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[XPM_LAST];
+ bcopy (xpm_format, fmt, sizeof fmt);
+ return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
+ /* Either `:file' or `:data' must be present. */
+ && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
+ /* Either no `:color-symbols' or it's a list of conses
+ whose car and cdr are strings. */
+ && (fmt[XPM_COLOR_SYMBOLS].count == 0
+ || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
+ && (fmt[XPM_ASCENT].count == 0
+ || XFASTINT (fmt[XPM_ASCENT].value) < 100));
+}
+
+
+/* Load image IMG which will be displayed on frame F. Value is
+ non-zero if successful. */
+
+static int
+xpm_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ int rc, i;
+ XpmAttributes attrs;
+ Lisp_Object specified_file, color_symbols;
+
+ /* Configure the XPM lib. Use the visual of frame F. Allocate
+ close colors. Return colors allocated. */
+ bzero (&attrs, sizeof attrs);
+ attrs.visual = FRAME_X_VISUAL (f);
+ attrs.colormap = FRAME_X_COLORMAP (f);
+ attrs.valuemask |= XpmVisual;
+ attrs.valuemask |= XpmColormap;
+ attrs.valuemask |= XpmReturnAllocPixels;
+#ifdef XpmAllocCloseColors
+ attrs.alloc_close_colors = 1;
+ attrs.valuemask |= XpmAllocCloseColors;
+#else
+ attrs.closeness = 600;
+ attrs.valuemask |= XpmCloseness;
+#endif
+
+ /* If image specification contains symbolic color definitions, add
+ these to `attrs'. */
+ color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
+ if (CONSP (color_symbols))
+ {
+ Lisp_Object tail;
+ XpmColorSymbol *xpm_syms;
+ int i, size;
+
+ attrs.valuemask |= XpmColorSymbols;
+
+ /* Count number of symbols. */
+ attrs.numsymbols = 0;
+ for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
+ ++attrs.numsymbols;
+
+ /* Allocate an XpmColorSymbol array. */
+ size = attrs.numsymbols * sizeof *xpm_syms;
+ xpm_syms = (XpmColorSymbol *) alloca (size);
+ bzero (xpm_syms, size);
+ attrs.colorsymbols = xpm_syms;
+
+ /* Fill the color symbol array. */
+ for (tail = color_symbols, i = 0;
+ CONSP (tail);
+ ++i, tail = XCDR (tail))
+ {
+ Lisp_Object name = XCAR (XCAR (tail));
+ Lisp_Object color = XCDR (XCAR (tail));
+ xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
+ strcpy (xpm_syms[i].name, XSTRING (name)->data);
+ xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
+ strcpy (xpm_syms[i].value, XSTRING (color)->data);
+ }
+ }
+
+ /* Create a pixmap for the image, either from a file, or from a
+ string buffer containing data in the same format as an XPM file. */
+ BLOCK_INPUT;
+ specified_file = image_spec_value (img->spec, QCfile, NULL);
+ if (STRINGP (specified_file))
+ {
+ Lisp_Object file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
+ XSTRING (file)->data, &img->pixmap, &img->mask,
+ &attrs);
+ }
+ else
+ {
+ Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
+ rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
+ XSTRING (buffer)->data,
+ &img->pixmap, &img->mask,
+ &attrs);
+ }
+ UNBLOCK_INPUT;
+
+ if (rc == XpmSuccess)
+ {
+ /* Remember allocated colors. */
+ img->ncolors = attrs.nalloc_pixels;
+ img->colors = (unsigned long *) xmalloc (img->ncolors
+ * sizeof *img->colors);
+ for (i = 0; i < attrs.nalloc_pixels; ++i)
+ img->colors[i] = attrs.alloc_pixels[i];
+
+ img->width = attrs.width;
+ img->height = attrs.height;
+ xassert (img->width > 0 && img->height > 0);
+
+ /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
+ BLOCK_INPUT;
+ XpmFreeAttributes (&attrs);
+ UNBLOCK_INPUT;
+ }
+ else
+ {
+ switch (rc)
+ {
+ case XpmOpenFailed:
+ image_error ("Error opening XPM file (%s)", img->spec, Qnil);
+ break;
+
+ case XpmFileInvalid:
+ image_error ("Invalid XPM file (%s)", img->spec, Qnil);
+ break;
+
+ case XpmNoMemory:
+ image_error ("Out of memory (%s)", img->spec, Qnil);
+ break;
+
+ case XpmColorFailed:
+ image_error ("Color allocation error (%s)", img->spec, Qnil);
+ break;
+
+ default:
+ image_error ("Unknown error (%s)", img->spec, Qnil);
+ break;
+ }
+ }
+
+ return rc == XpmSuccess;
+}
+
+#endif /* HAVE_XPM != 0 */
+
+
+#if 0 /* MAC_TODO : Color tables on Mac. */
+/***********************************************************************
+ Color table
+ ***********************************************************************/
+
+/* An entry in the color table mapping an RGB color to a pixel color. */
+
+struct ct_color
+{
+ int r, g, b;
+ unsigned long pixel;
+
+ /* Next in color table collision list. */
+ struct ct_color *next;
+};
+
+/* The bucket vector size to use. Must be prime. */
+
+#define CT_SIZE 101
+
+/* Value is a hash of the RGB color given by R, G, and B. */
+
+#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
+
+/* The color hash table. */
+
+struct ct_color **ct_table;
+
+/* Number of entries in the color table. */
+
+int ct_colors_allocated;
+
+/* Function prototypes. */
+
+static void init_color_table P_ ((void));
+static void free_color_table P_ ((void));
+static unsigned long *colors_in_color_table P_ ((int *n));
+static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
+static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
+
+
+/* Initialize the color table. */
+
+static void
+init_color_table ()
+{
+ int size = CT_SIZE * sizeof (*ct_table);
+ ct_table = (struct ct_color **) xmalloc (size);
+ bzero (ct_table, size);
+ ct_colors_allocated = 0;
+}
+
+
+/* Free memory associated with the color table. */
+
+static void
+free_color_table ()
+{
+ int i;
+ struct ct_color *p, *next;
+
+ for (i = 0; i < CT_SIZE; ++i)
+ for (p = ct_table[i]; p; p = next)
+ {
+ next = p->next;
+ xfree (p);
+ }
+
+ xfree (ct_table);
+ ct_table = NULL;
+}
+
+
+/* Value is a pixel color for RGB color R, G, B on frame F. If an
+ entry for that color already is in the color table, return the
+ pixel color of that entry. Otherwise, allocate a new color for R,
+ G, B, and make an entry in the color table. */
+
+static unsigned long
+lookup_rgb_color (f, r, g, b)
+ struct frame *f;
+ int r, g, b;
+{
+ unsigned hash = CT_HASH_RGB (r, g, b);
+ int i = hash % CT_SIZE;
+ struct ct_color *p;
+
+ for (p = ct_table[i]; p; p = p->next)
+ if (p->r == r && p->g == g && p->b == b)
+ break;
+
+ if (p == NULL)
+ {
+ COLORREF color;
+ Colormap cmap;
+ int rc;
+
+ color = RGB_TO_ULONG (r, g, b);
+
+ ++ct_colors_allocated;
+
+ p = (struct ct_color *) xmalloc (sizeof *p);
+ p->r = r;
+ p->g = g;
+ p->b = b;
+ p->pixel = color;
+ p->next = ct_table[i];
+ ct_table[i] = p;
+ }
+
+ return p->pixel;
+}
+
+
+/* Look up pixel color PIXEL which is used on frame F in the color
+ table. If not already present, allocate it. Value is PIXEL. */
+
+static unsigned long
+lookup_pixel_color (f, pixel)
+ struct frame *f;
+ unsigned long pixel;
+{
+ int i = pixel % CT_SIZE;
+ struct ct_color *p;
+
+ for (p = ct_table[i]; p; p = p->next)
+ if (p->pixel == pixel)
+ break;
+
+ if (p == NULL)
+ {
+ XColor color;
+ Colormap cmap;
+ int rc;
+
+ BLOCK_INPUT;
+
+ cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+ color.pixel = pixel;
+ XQueryColor (NULL, cmap, &color);
+ rc = x_alloc_nearest_color (f, cmap, &color);
+ UNBLOCK_INPUT;
+
+ if (rc)
+ {
+ ++ct_colors_allocated;
+
+ p = (struct ct_color *) xmalloc (sizeof *p);
+ p->r = color.red;
+ p->g = color.green;
+ p->b = color.blue;
+ p->pixel = pixel;
+ p->next = ct_table[i];
+ ct_table[i] = p;
+ }
+ else
+ return FRAME_FOREGROUND_PIXEL (f);
+ }
+ return p->pixel;
+}
+
+
+/* Value is a vector of all pixel colors contained in the color table,
+ allocated via xmalloc. Set *N to the number of colors. */
+
+static unsigned long *
+colors_in_color_table (n)
+ int *n;
+{
+ int i, j;
+ struct ct_color *p;
+ unsigned long *colors;
+
+ if (ct_colors_allocated == 0)
+ {
+ *n = 0;
+ colors = NULL;
+ }
+ else
+ {
+ colors = (unsigned long *) xmalloc (ct_colors_allocated
+ * sizeof *colors);
+ *n = ct_colors_allocated;
+
+ for (i = j = 0; i < CT_SIZE; ++i)
+ for (p = ct_table[i]; p; p = p->next)
+ colors[j++] = p->pixel;
+ }
+
+ return colors;
+}
+
+#endif /* MAC_TODO */
+
+
+/***********************************************************************
+ Algorithms
+ ***********************************************************************/
+
+#if 0 /* MAC_TODO : Mac versions of low level algorithms */
+static void x_laplace_write_row P_ ((struct frame *, long *,
+ int, XImage *, int));
+static void x_laplace_read_row P_ ((struct frame *, Colormap,
+ XColor *, int, XImage *, int));
+
+
+/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
+ frame we operate on, CMAP is the color-map in effect, and WIDTH is
+ the width of one row in the image. */
+
+static void
+x_laplace_read_row (f, cmap, colors, width, ximg, y)
+ struct frame *f;
+ Colormap cmap;
+ XColor *colors;
+ int width;
+ XImage *ximg;
+ int y;
+{
+ int x;
+
+ for (x = 0; x < width; ++x)
+ colors[x].pixel = XGetPixel (ximg, x, y);
+
+ XQueryColors (NULL, cmap, colors, width);
+}
+
+
+/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
+ containing the pixel colors to write. F is the frame we are
+ working on. */
+
+static void
+x_laplace_write_row (f, pixels, width, ximg, y)
+ struct frame *f;
+ long *pixels;
+ int width;
+ XImage *ximg;
+ int y;
+{
+ int x;
+
+ for (x = 0; x < width; ++x)
+ XPutPixel (ximg, x, y, pixels[x]);
+}
+#endif /* MAC_TODO */
+
+/* Transform image IMG which is used on frame F with a Laplace
+ edge-detection algorithm. The result is an image that can be used
+ to draw disabled buttons, for example. */
+
+static void
+x_laplace (f, img)
+ struct frame *f;
+ struct image *img;
+{
+#if 0 /* MAC_TODO : Mac version */
+ Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+ XImage *ximg, *oimg;
+ XColor *in[3];
+ long *out;
+ Pixmap pixmap;
+ int x, y, i;
+ long pixel;
+ int in_y, out_y, rc;
+ int mv2 = 45000;
+
+ BLOCK_INPUT;
+
+ /* Get the X image IMG->pixmap. */
+ ximg = XGetImage (NULL, img->pixmap,
+ 0, 0, img->width, img->height, ~0, ZPixmap);
+
+ /* Allocate 3 input rows, and one output row of colors. */
+ for (i = 0; i < 3; ++i)
+ in[i] = (XColor *) alloca (img->width * sizeof (XColor));
+ out = (long *) alloca (img->width * sizeof (long));
+
+ /* Create an X image for output. */
+ rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
+ &oimg, &pixmap);
+
+ /* Fill first two rows. */
+ x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
+ x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
+ in_y = 2;
+
+ /* Write first row, all zeros. */
+ init_color_table ();
+ pixel = lookup_rgb_color (f, 0, 0, 0);
+ for (x = 0; x < img->width; ++x)
+ out[x] = pixel;
+ x_laplace_write_row (f, out, img->width, oimg, 0);
+ out_y = 1;
+
+ for (y = 2; y < img->height; ++y)
+ {
+ int rowa = y % 3;
+ int rowb = (y + 2) % 3;
+
+ x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
+
+ for (x = 0; x < img->width - 2; ++x)
+ {
+ int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
+ int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
+ int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
+
+ out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
+ b & 0xffff);
+ }
+
+ x_laplace_write_row (f, out, img->width, oimg, out_y++);
+ }
+
+ /* Write last line, all zeros. */
+ for (x = 0; x < img->width; ++x)
+ out[x] = pixel;
+ x_laplace_write_row (f, out, img->width, oimg, out_y);
+
+ /* Free the input image, and free resources of IMG. */
+ XDestroyImage (ximg);
+ x_clear_image (f, img);
+
+ /* Put the output image into pixmap, and destroy it. */
+ x_put_x_image (f, oimg, pixmap, img->width, img->height);
+ x_destroy_x_image (oimg);
+
+ /* Remember new pixmap and colors in IMG. */
+ img->pixmap = pixmap;
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+}
+
+
+/* Build a mask for image IMG which is used on frame F. FILE is the
+ name of an image file, for error messages. HOW determines how to
+ determine the background color of IMG. If it is a list '(R G B)',
+ with R, G, and B being integers >= 0, take that as the color of the
+ background. Otherwise, determine the background color of IMG
+ heuristically. Value is non-zero if successful. */
+
+static int
+x_build_heuristic_mask (f, img, how)
+ struct frame *f;
+ struct image *img;
+ Lisp_Object how;
+{
+#if 0 /* MAC_TODO : Mac version */
+ Display *dpy = FRAME_W32_DISPLAY (f);
+ XImage *ximg, *mask_img;
+ int x, y, rc, look_at_corners_p;
+ unsigned long bg;
+
+ BLOCK_INPUT;
+
+ /* Create an image and pixmap serving as mask. */
+ rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
+ &mask_img, &img->mask);
+ if (!rc)
+ {
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ /* Get the X image of IMG->pixmap. */
+ ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
+ ~0, ZPixmap);
+
+ /* Determine the background color of ximg. If HOW is `(R G B)'
+ take that as color. Otherwise, try to determine the color
+ heuristically. */
+ look_at_corners_p = 1;
+
+ if (CONSP (how))
+ {
+ int rgb[3], i = 0;
+
+ while (i < 3
+ && CONSP (how)
+ && NATNUMP (XCAR (how)))
+ {
+ rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
+ how = XCDR (how);
+ }
+
+ if (i == 3 && NILP (how))
+ {
+ char color_name[30];
+ XColor exact, color;
+ Colormap cmap;
+
+ sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
+
+ cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+ if (XLookupColor (dpy, cmap, color_name, &exact, &color))
+ {
+ bg = color.pixel;
+ look_at_corners_p = 0;
+ }
+ }
+ }
+
+ if (look_at_corners_p)
+ {
+ unsigned long corners[4];
+ int i, best_count;
+
+ /* Get the colors at the corners of ximg. */
+ corners[0] = XGetPixel (ximg, 0, 0);
+ corners[1] = XGetPixel (ximg, img->width - 1, 0);
+ corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
+ corners[3] = XGetPixel (ximg, 0, img->height - 1);
+
+ /* Choose the most frequently found color as background. */
+ for (i = best_count = 0; i < 4; ++i)
+ {
+ int j, n;
+
+ for (j = n = 0; j < 4; ++j)
+ if (corners[i] == corners[j])
+ ++n;
+
+ if (n > best_count)
+ bg = corners[i], best_count = n;
+ }
+ }
+
+ /* Set all bits in mask_img to 1 whose color in ximg is different
+ from the background color bg. */
+ for (y = 0; y < img->height; ++y)
+ for (x = 0; x < img->width; ++x)
+ XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
+
+ /* Put mask_img into img->mask. */
+ x_put_x_image (f, mask_img, img->mask, img->width, img->height);
+ x_destroy_x_image (mask_img);
+ XDestroyImage (ximg);
+
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+
+ return 1;
+}
+
+
+
+/***********************************************************************
+ PBM (mono, gray, color)
+ ***********************************************************************/
+#ifdef HAVE_PBM
+
+static int pbm_image_p P_ ((Lisp_Object object));
+static int pbm_load P_ ((struct frame *f, struct image *img));
+static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
+
+/* The symbol `pbm' identifying images of this type. */
+
+Lisp_Object Qpbm;
+
+/* Indices of image specification fields in gs_format, below. */
+
+enum pbm_keyword_index
+{
+ PBM_TYPE,
+ PBM_FILE,
+ PBM_DATA,
+ PBM_ASCENT,
+ PBM_MARGIN,
+ PBM_RELIEF,
+ PBM_ALGORITHM,
+ PBM_HEURISTIC_MASK,
+ PBM_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword pbm_format[PBM_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type `pbm'. */
+
+static struct image_type pbm_type =
+{
+ &Qpbm,
+ pbm_image_p,
+ pbm_load,
+ x_clear_image,
+ NULL
+};
+
+
+/* Return non-zero if OBJECT is a valid PBM image specification. */
+
+static int
+pbm_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[PBM_LAST];
+
+ bcopy (pbm_format, fmt, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
+ || (fmt[PBM_ASCENT].count
+ && XFASTINT (fmt[PBM_ASCENT].value) > 100))
+ return 0;
+
+ /* Must specify either :data or :file. */
+ return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
+}
+
+
+/* Scan a decimal number from *S and return it. Advance *S while
+ reading the number. END is the end of the string. Value is -1 at
+ end of input. */
+
+static int
+pbm_scan_number (s, end)
+ unsigned char **s, *end;
+{
+ int c, val = -1;
+
+ while (*s < end)
+ {
+ /* Skip white-space. */
+ while (*s < end && (c = *(*s)++, isspace (c)))
+ ;
+
+ if (c == '#')
+ {
+ /* Skip comment to end of line. */
+ while (*s < end && (c = *(*s)++, c != '\n'))
+ ;
+ }
+ else if (isdigit (c))
+ {
+ /* Read decimal number. */
+ val = c - '0';
+ while (*s < end && (c = *(*s)++, isdigit (c)))
+ val = 10 * val + c - '0';
+ break;
+ }
+ else
+ break;
+ }
+
+ return val;
+}
+
+
+/* Read FILE into memory. Value is a pointer to a buffer allocated
+ with xmalloc holding FILE's contents. Value is null if an error
+ occured. *SIZE is set to the size of the file. */
+
+static char *
+pbm_read_file (file, size)
+ Lisp_Object file;
+ int *size;
+{
+ FILE *fp = NULL;
+ char *buf = NULL;
+ struct stat st;
+
+ if (stat (XSTRING (file)->data, &st) == 0
+ && (fp = fopen (XSTRING (file)->data, "r")) != NULL
+ && (buf = (char *) xmalloc (st.st_size),
+ fread (buf, 1, st.st_size, fp) == st.st_size))
+ {
+ *size = st.st_size;
+ fclose (fp);
+ }
+ else
+ {
+ if (fp)
+ fclose (fp);
+ if (buf)
+ {
+ xfree (buf);
+ buf = NULL;
+ }
+ }
+
+ return buf;
+}
+
+
+/* Load PBM image IMG for use on frame F. */
+
+static int
+pbm_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ int raw_p, x, y;
+ int width, height, max_color_idx = 0;
+ XImage *ximg;
+ Lisp_Object file, specified_file;
+ enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
+ struct gcpro gcpro1;
+ unsigned char *contents = NULL;
+ unsigned char *end, *p;
+ int size;
+
+ specified_file = image_spec_value (img->spec, QCfile, NULL);
+ file = Qnil;
+ GCPRO1 (file);
+
+ if (STRINGP (specified_file))
+ {
+ file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ contents = pbm_read_file (file, &size);
+ if (contents == NULL)
+ {
+ image_error ("Error reading `%s'", file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ p = contents;
+ end = contents + size;
+ }
+ else
+ {
+ Lisp_Object data;
+ data = image_spec_value (img->spec, QCdata, NULL);
+ p = XSTRING (data)->data;
+ end = p + STRING_BYTES (XSTRING (data));
+ }
+
+ /* Check magic number. */
+ if (end - p < 2 || *p++ != 'P')
+ {
+ image_error ("Not a PBM image: `%s'", img->spec, Qnil);
+ error:
+ xfree (contents);
+ UNGCPRO;
+ return 0;
+ }
+
+ switch (*p++)
+ {
+ case '1':
+ raw_p = 0, type = PBM_MONO;
+ break;
+
+ case '2':
+ raw_p = 0, type = PBM_GRAY;
+ break;
+
+ case '3':
+ raw_p = 0, type = PBM_COLOR;
+ break;
+
+ case '4':
+ raw_p = 1, type = PBM_MONO;
+ break;
+
+ case '5':
+ raw_p = 1, type = PBM_GRAY;
+ break;
+
+ case '6':
+ raw_p = 1, type = PBM_COLOR;
+ break;
+
+ default:
+ image_error ("Not a PBM image: `%s'", img->spec, Qnil);
+ goto error;
+ }
+
+ /* Read width, height, maximum color-component. Characters
+ starting with `#' up to the end of a line are ignored. */
+ width = pbm_scan_number (&p, end);
+ height = pbm_scan_number (&p, end);
+
+ if (type != PBM_MONO)
+ {
+ max_color_idx = pbm_scan_number (&p, end);
+ if (raw_p && max_color_idx > 255)
+ max_color_idx = 255;
+ }
+
+ if (width < 0
+ || height < 0
+ || (type != PBM_MONO && max_color_idx < 0))
+ goto error;
+
+ BLOCK_INPUT;
+ if (!x_create_x_image_and_pixmap (f, width, height, 0,
+ &ximg, &img->pixmap))
+ {
+ UNBLOCK_INPUT;
+ goto error;
+ }
+
+ /* Initialize the color hash table. */
+ init_color_table ();
+
+ if (type == PBM_MONO)
+ {
+ int c = 0, g;
+
+ for (y = 0; y < height; ++y)
+ for (x = 0; x < width; ++x)
+ {
+ if (raw_p)
+ {
+ if ((x & 7) == 0)
+ c = *p++;
+ g = c & 0x80;
+ c <<= 1;
+ }
+ else
+ g = pbm_scan_number (&p, end);
+
+ XPutPixel (ximg, x, y, (g
+ ? FRAME_FOREGROUND_PIXEL (f)
+ : FRAME_BACKGROUND_PIXEL (f)));
+ }
+ }
+ else
+ {
+ for (y = 0; y < height; ++y)
+ for (x = 0; x < width; ++x)
+ {
+ int r, g, b;
+
+ if (type == PBM_GRAY)
+ r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
+ else if (raw_p)
+ {
+ r = *p++;
+ g = *p++;
+ b = *p++;
+ }
+ else
+ {
+ r = pbm_scan_number (&p, end);
+ g = pbm_scan_number (&p, end);
+ b = pbm_scan_number (&p, end);
+ }
+
+ if (r < 0 || g < 0 || b < 0)
+ {
+ xfree (ximg->data);
+ ximg->data = NULL;
+ XDestroyImage (ximg);
+ UNBLOCK_INPUT;
+ image_error ("Invalid pixel value in image `%s'",
+ img->spec, Qnil);
+ goto error;
+ }
+
+ /* RGB values are now in the range 0..max_color_idx.
+ Scale this to the range 0..0xffff supported by X. */
+ r = (double) r * 65535 / max_color_idx;
+ g = (double) g * 65535 / max_color_idx;
+ b = (double) b * 65535 / max_color_idx;
+ XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+ }
+ }
+
+ /* Store in IMG->colors the colors allocated for the image, and
+ free the color table. */
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+
+ /* Put the image into a pixmap. */
+ x_put_x_image (f, ximg, img->pixmap, width, height);
+ x_destroy_x_image (ximg);
+ UNBLOCK_INPUT;
+
+ img->width = width;
+ img->height = height;
+
+ UNGCPRO;
+ xfree (contents);
+ return 1;
+}
+#endif /* HAVE_PBM */
+
+
+/***********************************************************************
+ PNG
+ ***********************************************************************/
+
+#if HAVE_PNG
+
+#include <png.h>
+
+/* Function prototypes. */
+
+static int png_image_p P_ ((Lisp_Object object));
+static int png_load P_ ((struct frame *f, struct image *img));
+
+/* The symbol `png' identifying images of this type. */
+
+Lisp_Object Qpng;
+
+/* Indices of image specification fields in png_format, below. */
+
+enum png_keyword_index
+{
+ PNG_TYPE,
+ PNG_DATA,
+ PNG_FILE,
+ PNG_ASCENT,
+ PNG_MARGIN,
+ PNG_RELIEF,
+ PNG_ALGORITHM,
+ PNG_HEURISTIC_MASK,
+ PNG_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword png_format[PNG_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type `png'. */
+
+static struct image_type png_type =
+{
+ &Qpng,
+ png_image_p,
+ png_load,
+ x_clear_image,
+ NULL
+};
+
+
+/* Return non-zero if OBJECT is a valid PNG image specification. */
+
+static int
+png_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[PNG_LAST];
+ bcopy (png_format, fmt, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
+ || (fmt[PNG_ASCENT].count
+ && XFASTINT (fmt[PNG_ASCENT].value) > 100))
+ return 0;
+
+ /* Must specify either the :data or :file keyword. */
+ return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
+}
+
+
+/* Error and warning handlers installed when the PNG library
+ is initialized. */
+
+static void
+my_png_error (png_ptr, msg)
+ png_struct *png_ptr;
+ char *msg;
+{
+ xassert (png_ptr != NULL);
+ image_error ("PNG error: %s", build_string (msg), Qnil);
+ longjmp (png_ptr->jmpbuf, 1);
+}
+
+
+static void
+my_png_warning (png_ptr, msg)
+ png_struct *png_ptr;
+ char *msg;
+{
+ xassert (png_ptr != NULL);
+ image_error ("PNG warning: %s", build_string (msg), Qnil);
+}
+
+/* Memory source for PNG decoding. */
+
+struct png_memory_storage
+{
+ unsigned char *bytes; /* The data */
+ size_t len; /* How big is it? */
+ int index; /* Where are we? */
+};
+
+
+/* Function set as reader function when reading PNG image from memory.
+ PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
+ bytes from the input to DATA. */
+
+static void
+png_read_from_memory (png_ptr, data, length)
+ png_structp png_ptr;
+ png_bytep data;
+ png_size_t length;
+{
+ struct png_memory_storage *tbr
+ = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
+
+ if (length > tbr->len - tbr->index)
+ png_error (png_ptr, "Read error");
+
+ bcopy (tbr->bytes + tbr->index, data, length);
+ tbr->index = tbr->index + length;
+}
+
+/* Load PNG image IMG for use on frame F. Value is non-zero if
+ successful. */
+
+static int
+png_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ Lisp_Object file, specified_file;
+ Lisp_Object specified_data;
+ int x, y, i;
+ XImage *ximg, *mask_img = NULL;
+ struct gcpro gcpro1;
+ png_struct *png_ptr = NULL;
+ png_info *info_ptr = NULL, *end_info = NULL;
+ FILE *fp = NULL;
+ png_byte sig[8];
+ png_byte *pixels = NULL;
+ png_byte **rows = NULL;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+ png_byte channels;
+ png_uint_32 row_bytes;
+ int transparent_p;
+ char *gamma_str;
+ double screen_gamma, image_gamma;
+ int intent;
+ struct png_memory_storage tbr; /* Data to be read */
+
+ /* Find out what file to load. */
+ specified_file = image_spec_value (img->spec, QCfile, NULL);
+ specified_data = image_spec_value (img->spec, QCdata, NULL);
+ file = Qnil;
+ GCPRO1 (file);
+
+ if (NILP (specified_data))
+ {
+ file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Open the image file. */
+ fp = fopen (XSTRING (file)->data, "rb");
+ if (!fp)
+ {
+ image_error ("Cannot open image file `%s'", file, Qnil);
+ UNGCPRO;
+ fclose (fp);
+ return 0;
+ }
+
+ /* Check PNG signature. */
+ if (fread (sig, 1, sizeof sig, fp) != sizeof sig
+ || !png_check_sig (sig, sizeof sig))
+ {
+ image_error ("Not a PNG file:` %s'", file, Qnil);
+ UNGCPRO;
+ fclose (fp);
+ return 0;
+ }
+ }
+ else
+ {
+ /* Read from memory. */
+ tbr.bytes = XSTRING (specified_data)->data;
+ tbr.len = STRING_BYTES (XSTRING (specified_data));
+ tbr.index = 0;
+
+ /* Check PNG signature. */
+ if (tbr.len < sizeof sig
+ || !png_check_sig (tbr.bytes, sizeof sig))
+ {
+ image_error ("Not a PNG image: `%s'", img->spec, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Need to skip past the signature. */
+ tbr.bytes += sizeof (sig);
+ }
+
+ /* Initialize read and info structs for PNG lib. */
+ png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
+ my_png_error, my_png_warning);
+ if (!png_ptr)
+ {
+ if (fp) fclose (fp);
+ UNGCPRO;
+ return 0;
+ }
+
+ info_ptr = png_create_info_struct (png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct (&png_ptr, NULL, NULL);
+ if (fp) fclose (fp);
+ UNGCPRO;
+ return 0;
+ }
+
+ end_info = png_create_info_struct (png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+ if (fp) fclose (fp);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Set error jump-back. We come back here when the PNG library
+ detects an error. */
+ if (setjmp (png_ptr->jmpbuf))
+ {
+ error:
+ if (png_ptr)
+ png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
+ xfree (pixels);
+ xfree (rows);
+ if (fp) fclose (fp);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Read image info. */
+ if (!NILP (specified_data))
+ png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
+ else
+ png_init_io (png_ptr, fp);
+
+ png_set_sig_bytes (png_ptr, sizeof sig);
+ png_read_info (png_ptr, info_ptr);
+ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+
+ /* If image contains simply transparency data, we prefer to
+ construct a clipping mask. */
+ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
+ transparent_p = 1;
+ else
+ transparent_p = 0;
+
+ /* This function is easier to write if we only have to handle
+ one data format: RGB or RGBA with 8 bits per channel. Let's
+ transform other formats into that format. */
+
+ /* Strip more than 8 bits per channel. */
+ if (bit_depth == 16)
+ png_set_strip_16 (png_ptr);
+
+ /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
+ if available. */
+ png_set_expand (png_ptr);
+
+ /* Convert grayscale images to RGB. */
+ if (color_type == PNG_COLOR_TYPE_GRAY
+ || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png_ptr);
+
+ /* The value 2.2 is a guess for PC monitors from PNG example.c. */
+ gamma_str = getenv ("SCREEN_GAMMA");
+ screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
+
+ /* Tell the PNG lib to handle gamma correction for us. */
+
+#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
+ if (png_get_sRGB (png_ptr, info_ptr, &intent))
+ /* There is a special chunk in the image specifying the gamma. */
+ png_set_sRGB (png_ptr, info_ptr, intent);
+ else
+#endif
+ if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
+ /* Image contains gamma information. */
+ png_set_gamma (png_ptr, screen_gamma, image_gamma);
+ else
+ /* Use a default of 0.5 for the image gamma. */
+ png_set_gamma (png_ptr, screen_gamma, 0.5);
+
+ /* Handle alpha channel by combining the image with a background
+ color. Do this only if a real alpha channel is supplied. For
+ simple transparency, we prefer a clipping mask. */
+ if (!transparent_p)
+ {
+ png_color_16 *image_background;
+
+ if (png_get_bKGD (png_ptr, info_ptr, &image_background))
+ /* Image contains a background color with which to
+ combine the image. */
+ png_set_background (png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ {
+ /* Image does not contain a background color with which
+ to combine the image data via an alpha channel. Use
+ the frame's background instead. */
+ XColor color;
+ Colormap cmap;
+ png_color_16 frame_background;
+
+ BLOCK_INPUT;
+ cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+ color.pixel = FRAME_BACKGROUND_PIXEL (f);
+ XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
+ UNBLOCK_INPUT;
+
+ bzero (&frame_background, sizeof frame_background);
+ frame_background.red = color.red;
+ frame_background.green = color.green;
+ frame_background.blue = color.blue;
+
+ png_set_background (png_ptr, &frame_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+ }
+ }
+
+ /* Update info structure. */
+ png_read_update_info (png_ptr, info_ptr);
+
+ /* Get number of channels. Valid values are 1 for grayscale images
+ and images with a palette, 2 for grayscale images with transparency
+ information (alpha channel), 3 for RGB images, and 4 for RGB
+ images with alpha channel, i.e. RGBA. If conversions above were
+ sufficient we should only have 3 or 4 channels here. */
+ channels = png_get_channels (png_ptr, info_ptr);
+ xassert (channels == 3 || channels == 4);
+
+ /* Number of bytes needed for one row of the image. */
+ row_bytes = png_get_rowbytes (png_ptr, info_ptr);
+
+ /* Allocate memory for the image. */
+ pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
+ rows = (png_byte **) xmalloc (height * sizeof *rows);
+ for (i = 0; i < height; ++i)
+ rows[i] = pixels + i * row_bytes;
+
+ /* Read the entire image. */
+ png_read_image (png_ptr, rows);
+ png_read_end (png_ptr, info_ptr);
+ if (fp)
+ {
+ fclose (fp);
+ fp = NULL;
+ }
+
+ BLOCK_INPUT;
+
+ /* Create the X image and pixmap. */
+ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
+ &img->pixmap))
+ {
+ UNBLOCK_INPUT;
+ goto error;
+ }
+
+ /* Create an image and pixmap serving as mask if the PNG image
+ contains an alpha channel. */
+ if (channels == 4
+ && !transparent_p
+ && !x_create_x_image_and_pixmap (f, width, height, 1,
+ &mask_img, &img->mask))
+ {
+ x_destroy_x_image (ximg);
+ XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
+ img->pixmap = 0;
+ UNBLOCK_INPUT;
+ goto error;
+ }
+
+ /* Fill the X image and mask from PNG data. */
+ init_color_table ();
+
+ for (y = 0; y < height; ++y)
+ {
+ png_byte *p = rows[y];
+
+ for (x = 0; x < width; ++x)
+ {
+ unsigned r, g, b;
+
+ r = *p++ << 8;
+ g = *p++ << 8;
+ b = *p++ << 8;
+ XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+
+ /* An alpha channel, aka mask channel, associates variable
+ transparency with an image. Where other image formats
+ support binary transparency---fully transparent or fully
+ opaque---PNG allows up to 254 levels of partial transparency.
+ The PNG library implements partial transparency by combining
+ the image with a specified background color.
+
+ I'm not sure how to handle this here nicely: because the
+ background on which the image is displayed may change, for
+ real alpha channel support, it would be necessary to create
+ a new image for each possible background.
+
+ What I'm doing now is that a mask is created if we have
+ boolean transparency information. Otherwise I'm using
+ the frame's background color to combine the image with. */
+
+ if (channels == 4)
+ {
+ if (mask_img)
+ XPutPixel (mask_img, x, y, *p > 0);
+ ++p;
+ }
+ }
+ }
+
+ /* Remember colors allocated for this image. */
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+
+ /* Clean up. */
+ png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
+ xfree (rows);
+ xfree (pixels);
+
+ img->width = width;
+ img->height = height;
+
+ /* Put the image into the pixmap, then free the X image and its buffer. */
+ x_put_x_image (f, ximg, img->pixmap, width, height);
+ x_destroy_x_image (ximg);
+
+ /* Same for the mask. */
+ if (mask_img)
+ {
+ x_put_x_image (f, mask_img, img->mask, img->width, img->height);
+ x_destroy_x_image (mask_img);
+ }
+
+ UNBLOCK_INPUT;
+ UNGCPRO;
+ return 1;
+}
+
+#endif /* HAVE_PNG != 0 */
+
+
+
+/***********************************************************************
+ JPEG
+ ***********************************************************************/
+
+#if HAVE_JPEG
+
+/* Work around a warning about HAVE_STDLIB_H being redefined in
+ jconfig.h. */
+#ifdef HAVE_STDLIB_H
+#define HAVE_STDLIB_H_1
+#undef HAVE_STDLIB_H
+#endif /* HAVE_STLIB_H */
+
+#include <jpeglib.h>
+#include <jerror.h>
+#include <setjmp.h>
+
+#ifdef HAVE_STLIB_H_1
+#define HAVE_STDLIB_H 1
+#endif
+
+static int jpeg_image_p P_ ((Lisp_Object object));
+static int jpeg_load P_ ((struct frame *f, struct image *img));
+
+/* The symbol `jpeg' identifying images of this type. */
+
+Lisp_Object Qjpeg;
+
+/* Indices of image specification fields in gs_format, below. */
+
+enum jpeg_keyword_index
+{
+ JPEG_TYPE,
+ JPEG_DATA,
+ JPEG_FILE,
+ JPEG_ASCENT,
+ JPEG_MARGIN,
+ JPEG_RELIEF,
+ JPEG_ALGORITHM,
+ JPEG_HEURISTIC_MASK,
+ JPEG_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword jpeg_format[JPEG_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type `jpeg'. */
+
+static struct image_type jpeg_type =
+{
+ &Qjpeg,
+ jpeg_image_p,
+ jpeg_load,
+ x_clear_image,
+ NULL
+};
+
+
+/* Return non-zero if OBJECT is a valid JPEG image specification. */
+
+static int
+jpeg_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[JPEG_LAST];
+
+ bcopy (jpeg_format, fmt, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
+ || (fmt[JPEG_ASCENT].count
+ && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
+ return 0;
+
+ /* Must specify either the :data or :file keyword. */
+ return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
+}
+
+
+struct my_jpeg_error_mgr
+{
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+};
+
+static void
+my_error_exit (cinfo)
+ j_common_ptr cinfo;
+{
+ struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
+ longjmp (mgr->setjmp_buffer, 1);
+}
+
+/* Init source method for JPEG data source manager. Called by
+ jpeg_read_header() before any data is actually read. See
+ libjpeg.doc from the JPEG lib distribution. */
+
+static void
+our_init_source (cinfo)
+ j_decompress_ptr cinfo;
+{
+}
+
+
+/* Fill input buffer method for JPEG data source manager. Called
+ whenever more data is needed. We read the whole image in one step,
+ so this only adds a fake end of input marker at the end. */
+
+static boolean
+our_fill_input_buffer (cinfo)
+ j_decompress_ptr cinfo;
+{
+ /* Insert a fake EOI marker. */
+ struct jpeg_source_mgr *src = cinfo->src;
+ static JOCTET buffer[2];
+
+ buffer[0] = (JOCTET) 0xFF;
+ buffer[1] = (JOCTET) JPEG_EOI;
+
+ src->next_input_byte = buffer;
+ src->bytes_in_buffer = 2;
+ return TRUE;
+}
+
+
+/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
+ is the JPEG data source manager. */
+
+static void
+our_skip_input_data (cinfo, num_bytes)
+ j_decompress_ptr cinfo;
+ long num_bytes;
+{
+ struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
+
+ if (src)
+ {
+ if (num_bytes > src->bytes_in_buffer)
+ ERREXIT (cinfo, JERR_INPUT_EOF);
+
+ src->bytes_in_buffer -= num_bytes;
+ src->next_input_byte += num_bytes;
+ }
+}
+
+
+/* Method to terminate data source. Called by
+ jpeg_finish_decompress() after all data has been processed. */
+
+static void
+our_term_source (cinfo)
+ j_decompress_ptr cinfo;
+{
+}
+
+
+/* Set up the JPEG lib for reading an image from DATA which contains
+ LEN bytes. CINFO is the decompression info structure created for
+ reading the image. */
+
+static void
+jpeg_memory_src (cinfo, data, len)
+ j_decompress_ptr cinfo;
+ JOCTET *data;
+ unsigned int len;
+{
+ struct jpeg_source_mgr *src;
+
+ if (cinfo->src == NULL)
+ {
+ /* First time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof (struct jpeg_source_mgr));
+ src = (struct jpeg_source_mgr *) cinfo->src;
+ src->next_input_byte = data;
+ }
+
+ src = (struct jpeg_source_mgr *) cinfo->src;
+ src->init_source = our_init_source;
+ src->fill_input_buffer = our_fill_input_buffer;
+ src->skip_input_data = our_skip_input_data;
+ src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
+ src->term_source = our_term_source;
+ src->bytes_in_buffer = len;
+ src->next_input_byte = data;
+}
+
+
+/* Load image IMG for use on frame F. Patterned after example.c
+ from the JPEG lib. */
+
+static int
+jpeg_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ struct jpeg_decompress_struct cinfo;
+ struct my_jpeg_error_mgr mgr;
+ Lisp_Object file, specified_file;
+ Lisp_Object specified_data;
+ FILE *fp = NULL;
+ JSAMPARRAY buffer;
+ int row_stride, x, y;
+ XImage *ximg = NULL;
+ int rc;
+ unsigned long *colors;
+ int width, height;
+ struct gcpro gcpro1;
+
+ /* Open the JPEG file. */
+ specified_file = image_spec_value (img->spec, QCfile, NULL);
+ specified_data = image_spec_value (img->spec, QCdata, NULL);
+ file = Qnil;
+ GCPRO1 (file);
+
+ if (NILP (specified_data))
+ {
+ file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ fp = fopen (XSTRING (file)->data, "r");
+ if (fp == NULL)
+ {
+ image_error ("Cannot open `%s'", file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+ }
+
+ /* Customize libjpeg's error handling to call my_error_exit when an
+ error is detected. This function will perform a longjmp. */
+ mgr.pub.error_exit = my_error_exit;
+ cinfo.err = jpeg_std_error (&mgr.pub);
+
+ if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
+ {
+ if (rc == 1)
+ {
+ /* Called from my_error_exit. Display a JPEG error. */
+ char buffer[JMSG_LENGTH_MAX];
+ cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
+ image_error ("Error reading JPEG image `%s': %s", img->spec,
+ build_string (buffer));
+ }
+
+ /* Close the input file and destroy the JPEG object. */
+ if (fp)
+ fclose (fp);
+ jpeg_destroy_decompress (&cinfo);
+
+ BLOCK_INPUT;
+
+ /* If we already have an XImage, free that. */
+ x_destroy_x_image (ximg);
+
+ /* Free pixmap and colors. */
+ x_clear_image (f, img);
+
+ UNBLOCK_INPUT;
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Create the JPEG decompression object. Let it read from fp.
+ Read the JPEG image header. */
+ jpeg_create_decompress (&cinfo);
+
+ if (NILP (specified_data))
+ jpeg_stdio_src (&cinfo, fp);
+ else
+ jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
+ STRING_BYTES (XSTRING (specified_data)));
+
+ jpeg_read_header (&cinfo, TRUE);
+
+ /* Customize decompression so that color quantization will be used.
+ Start decompression. */
+ cinfo.quantize_colors = TRUE;
+ jpeg_start_decompress (&cinfo);
+ width = img->width = cinfo.output_width;
+ height = img->height = cinfo.output_height;
+
+ BLOCK_INPUT;
+
+ /* Create X image and pixmap. */
+ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
+ &img->pixmap))
+ {
+ UNBLOCK_INPUT;
+ longjmp (mgr.setjmp_buffer, 2);
+ }
+
+ /* Allocate colors. When color quantization is used,
+ cinfo.actual_number_of_colors has been set with the number of
+ colors generated, and cinfo.colormap is a two-dimensional array
+ of color indices in the range 0..cinfo.actual_number_of_colors.
+ No more than 255 colors will be generated. */
+ {
+ int i, ir, ig, ib;
+
+ if (cinfo.out_color_components > 2)
+ ir = 0, ig = 1, ib = 2;
+ else if (cinfo.out_color_components > 1)
+ ir = 0, ig = 1, ib = 0;
+ else
+ ir = 0, ig = 0, ib = 0;
+
+ /* Use the color table mechanism because it handles colors that
+ cannot be allocated nicely. Such colors will be replaced with
+ a default color, and we don't have to care about which colors
+ can be freed safely, and which can't. */
+ init_color_table ();
+ colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
+ * sizeof *colors);
+
+ for (i = 0; i < cinfo.actual_number_of_colors; ++i)
+ {
+ /* Multiply RGB values with 255 because X expects RGB values
+ in the range 0..0xffff. */
+ int r = cinfo.colormap[ir][i] << 8;
+ int g = cinfo.colormap[ig][i] << 8;
+ int b = cinfo.colormap[ib][i] << 8;
+ colors[i] = lookup_rgb_color (f, r, g, b);
+ }
+
+ /* Remember those colors actually allocated. */
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+ }
+
+ /* Read pixels. */
+ row_stride = width * cinfo.output_components;
+ buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
+ row_stride, 1);
+ for (y = 0; y < height; ++y)
+ {
+ jpeg_read_scanlines (&cinfo, buffer, 1);
+ for (x = 0; x < cinfo.output_width; ++x)
+ XPutPixel (ximg, x, y, colors[buffer[0][x]]);
+ }
+
+ /* Clean up. */
+ jpeg_finish_decompress (&cinfo);
+ jpeg_destroy_decompress (&cinfo);
+ if (fp)
+ fclose (fp);
+
+ /* Put the image into the pixmap. */
+ x_put_x_image (f, ximg, img->pixmap, width, height);
+ x_destroy_x_image (ximg);
+ UNBLOCK_INPUT;
+ UNGCPRO;
+ return 1;
+}
+
+#endif /* HAVE_JPEG */
+
+
+
+/***********************************************************************
+ TIFF
+ ***********************************************************************/
+
+#if HAVE_TIFF
+
+#include <tiffio.h>
+
+static int tiff_image_p P_ ((Lisp_Object object));
+static int tiff_load P_ ((struct frame *f, struct image *img));
+
+/* The symbol `tiff' identifying images of this type. */
+
+Lisp_Object Qtiff;
+
+/* Indices of image specification fields in tiff_format, below. */
+
+enum tiff_keyword_index
+{
+ TIFF_TYPE,
+ TIFF_DATA,
+ TIFF_FILE,
+ TIFF_ASCENT,
+ TIFF_MARGIN,
+ TIFF_RELIEF,
+ TIFF_ALGORITHM,
+ TIFF_HEURISTIC_MASK,
+ TIFF_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword tiff_format[TIFF_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type `tiff'. */
+
+static struct image_type tiff_type =
+{
+ &Qtiff,
+ tiff_image_p,
+ tiff_load,
+ x_clear_image,
+ NULL
+};
+
+
+/* Return non-zero if OBJECT is a valid TIFF image specification. */
+
+static int
+tiff_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[TIFF_LAST];
+ bcopy (tiff_format, fmt, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
+ || (fmt[TIFF_ASCENT].count
+ && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
+ return 0;
+
+ /* Must specify either the :data or :file keyword. */
+ return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
+}
+
+
+/* Reading from a memory buffer for TIFF images Based on the PNG
+ memory source, but we have to provide a lot of extra functions.
+ Blah.
+
+ We really only need to implement read and seek, but I am not
+ convinced that the TIFF library is smart enough not to destroy
+ itself if we only hand it the function pointers we need to
+ override. */
+
+typedef struct
+{
+ unsigned char *bytes;
+ size_t len;
+ int index;
+}
+tiff_memory_source;
+
+static size_t
+tiff_read_from_memory (data, buf, size)
+ thandle_t data;
+ tdata_t buf;
+ tsize_t size;
+{
+ tiff_memory_source *src = (tiff_memory_source *) data;
+
+ if (size > src->len - src->index)
+ return (size_t) -1;
+ bcopy (src->bytes + src->index, buf, size);
+ src->index += size;
+ return size;
+}
+
+static size_t
+tiff_write_from_memory (data, buf, size)
+ thandle_t data;
+ tdata_t buf;
+ tsize_t size;
+{
+ return (size_t) -1;
+}
+
+static toff_t
+tiff_seek_in_memory (data, off, whence)
+ thandle_t data;
+ toff_t off;
+ int whence;
+{
+ tiff_memory_source *src = (tiff_memory_source *) data;
+ int idx;
+
+ switch (whence)
+ {
+ case SEEK_SET: /* Go from beginning of source. */
+ idx = off;
+ break;
+
+ case SEEK_END: /* Go from end of source. */
+ idx = src->len + off;
+ break;
+
+ case SEEK_CUR: /* Go from current position. */
+ idx = src->index + off;
+ break;
+
+ default: /* Invalid `whence'. */
+ return -1;
+ }
+
+ if (idx > src->len || idx < 0)
+ return -1;
+
+ src->index = idx;
+ return src->index;
+}
+
+static int
+tiff_close_memory (data)
+ thandle_t data;
+{
+ /* NOOP */
+ return 0;
+}
+
+static int
+tiff_mmap_memory (data, pbase, psize)
+ thandle_t data;
+ tdata_t *pbase;
+ toff_t *psize;
+{
+ /* It is already _IN_ memory. */
+ return 0;
+}
+
+static void
+tiff_unmap_memory (data, base, size)
+ thandle_t data;
+ tdata_t base;
+ toff_t size;
+{
+ /* We don't need to do this. */
+}
+
+static toff_t
+tiff_size_of_memory (data)
+ thandle_t data;
+{
+ return ((tiff_memory_source *) data)->len;
+}
+
+/* Load TIFF image IMG for use on frame F. Value is non-zero if
+ successful. */
+
+static int
+tiff_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ Lisp_Object file, specified_file;
+ Lisp_Object specified_data;
+ TIFF *tiff;
+ int width, height, x, y;
+ uint32 *buf;
+ int rc;
+ XImage *ximg;
+ struct gcpro gcpro1;
+ tiff_memory_source memsrc;
+
+ specified_file = image_spec_value (img->spec, QCfile, NULL);
+ specified_data = image_spec_value (img->spec, QCdata, NULL);
+ file = Qnil;
+ GCPRO1 (file);
+
+ if (NILP (specified_data))
+ {
+ /* Read from a file */
+ file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Try to open the image file. */
+ tiff = TIFFOpen (XSTRING (file)->data, "r");
+ if (tiff == NULL)
+ {
+ image_error ("Cannot open `%s'", file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+ }
+ else
+ {
+ /* Memory source! */
+ memsrc.bytes = XSTRING (specified_data)->data;
+ memsrc.len = STRING_BYTES (XSTRING (specified_data));
+ memsrc.index = 0;
+
+ tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
+ (TIFFReadWriteProc) tiff_read_from_memory,
+ (TIFFReadWriteProc) tiff_write_from_memory,
+ tiff_seek_in_memory,
+ tiff_close_memory,
+ tiff_size_of_memory,
+ tiff_mmap_memory,
+ tiff_unmap_memory);
+
+ if (!tiff)
+ {
+ image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+ }
+
+ /* Get width and height of the image, and allocate a raster buffer
+ of width x height 32-bit values. */
+ TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
+ buf = (uint32 *) xmalloc (width * height * sizeof *buf);
+
+ rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
+ TIFFClose (tiff);
+ if (!rc)
+ {
+ image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
+ xfree (buf);
+ UNGCPRO;
+ return 0;
+ }
+
+ BLOCK_INPUT;
+
+ /* Create the X image and pixmap. */
+ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+ {
+ UNBLOCK_INPUT;
+ xfree (buf);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Initialize the color table. */
+ init_color_table ();
+
+ /* Process the pixel raster. Origin is in the lower-left corner. */
+ for (y = 0; y < height; ++y)
+ {
+ uint32 *row = buf + y * width;
+
+ for (x = 0; x < width; ++x)
+ {
+ uint32 abgr = row[x];
+ int r = TIFFGetR (abgr) << 8;
+ int g = TIFFGetG (abgr) << 8;
+ int b = TIFFGetB (abgr) << 8;
+ XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
+ }
+ }
+
+ /* Remember the colors allocated for the image. Free the color table. */
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+
+ /* Put the image into the pixmap, then free the X image and its buffer. */
+ x_put_x_image (f, ximg, img->pixmap, width, height);
+ x_destroy_x_image (ximg);
+ xfree (buf);
+ UNBLOCK_INPUT;
+
+ img->width = width;
+ img->height = height;
+
+ UNGCPRO;
+ return 1;
+}
+
+#endif /* HAVE_TIFF != 0 */
+
+
+
+/***********************************************************************
+ GIF
+ ***********************************************************************/
+
+#if HAVE_GIF
+
+#include <gif_lib.h>
+
+static int gif_image_p P_ ((Lisp_Object object));
+static int gif_load P_ ((struct frame *f, struct image *img));
+
+/* The symbol `gif' identifying images of this type. */
+
+Lisp_Object Qgif;
+
+/* Indices of image specification fields in gif_format, below. */
+
+enum gif_keyword_index
+{
+ GIF_TYPE,
+ GIF_DATA,
+ GIF_FILE,
+ GIF_ASCENT,
+ GIF_MARGIN,
+ GIF_RELIEF,
+ GIF_ALGORITHM,
+ GIF_HEURISTIC_MASK,
+ GIF_IMAGE,
+ GIF_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword gif_format[GIF_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
+};
+
+/* Structure describing the image type `gif'. */
+
+static struct image_type gif_type =
+{
+ &Qgif,
+ gif_image_p,
+ gif_load,
+ x_clear_image,
+ NULL
+};
+
+/* Return non-zero if OBJECT is a valid GIF image specification. */
+
+static int
+gif_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[GIF_LAST];
+ bcopy (gif_format, fmt, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
+ || (fmt[GIF_ASCENT].count
+ && XFASTINT (fmt[GIF_ASCENT].value) > 100))
+ return 0;
+
+ /* Must specify either the :data or :file keyword. */
+ return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
+}
+
+/* Reading a GIF image from memory
+ Based on the PNG memory stuff to a certain extent. */
+
+typedef struct
+{
+ unsigned char *bytes;
+ size_t len;
+ int index;
+}
+gif_memory_source;
+
+/* Make the current memory source available to gif_read_from_memory.
+ It's done this way because not all versions of libungif support
+ a UserData field in the GifFileType structure. */
+static gif_memory_source *current_gif_memory_src;
+
+static int
+gif_read_from_memory (file, buf, len)
+ GifFileType *file;
+ GifByteType *buf;
+ int len;
+{
+ gif_memory_source *src = current_gif_memory_src;
+
+ if (len > src->len - src->index)
+ return -1;
+
+ bcopy (src->bytes + src->index, buf, len);
+ src->index += len;
+ return len;
+}
+
+
+/* Load GIF image IMG for use on frame F. Value is non-zero if
+ successful. */
+
+static int
+gif_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ Lisp_Object file, specified_file;
+ Lisp_Object specified_data;
+ int rc, width, height, x, y, i;
+ XImage *ximg;
+ ColorMapObject *gif_color_map;
+ unsigned long pixel_colors[256];
+ GifFileType *gif;
+ struct gcpro gcpro1;
+ Lisp_Object image;
+ int ino, image_left, image_top, image_width, image_height;
+ gif_memory_source memsrc;
+ unsigned char *raster;
+
+ specified_file = image_spec_value (img->spec, QCfile, NULL);
+ specified_data = image_spec_value (img->spec, QCdata, NULL);
+ file = Qnil;
+ GCPRO1 (file);
+
+ if (NILP (specified_data))
+ {
+ file = x_find_image_file (specified_file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Open the GIF file. */
+ gif = DGifOpenFileName (XSTRING (file)->data);
+ if (gif == NULL)
+ {
+ image_error ("Cannot open `%s'", file, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+ }
+ else
+ {
+ /* Read from memory! */
+ current_gif_memory_src = &memsrc;
+ memsrc.bytes = XSTRING (specified_data)->data;
+ memsrc.len = STRING_BYTES (XSTRING (specified_data));
+ memsrc.index = 0;
+
+ gif = DGifOpen(&memsrc, gif_read_from_memory);
+ if (!gif)
+ {
+ image_error ("Cannot open memory source `%s'", img->spec, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+ }
+
+ /* Read entire contents. */
+ rc = DGifSlurp (gif);
+ if (rc == GIF_ERROR)
+ {
+ image_error ("Error reading `%s'", img->spec, Qnil);
+ DGifCloseFile (gif);
+ UNGCPRO;
+ return 0;
+ }
+
+ image = image_spec_value (img->spec, QCindex, NULL);
+ ino = INTEGERP (image) ? XFASTINT (image) : 0;
+ if (ino >= gif->ImageCount)
+ {
+ image_error ("Invalid image number `%s' in image `%s'",
+ image, img->spec);
+ DGifCloseFile (gif);
+ UNGCPRO;
+ return 0;
+ }
+
+ width = img->width = gif->SWidth;
+ height = img->height = gif->SHeight;
+
+ BLOCK_INPUT;
+
+ /* Create the X image and pixmap. */
+ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+ {
+ UNBLOCK_INPUT;
+ DGifCloseFile (gif);
+ UNGCPRO;
+ return 0;
+ }
+
+ /* Allocate colors. */
+ gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
+ if (!gif_color_map)
+ gif_color_map = gif->SColorMap;
+ init_color_table ();
+ bzero (pixel_colors, sizeof pixel_colors);
+
+ for (i = 0; i < gif_color_map->ColorCount; ++i)
+ {
+ int r = gif_color_map->Colors[i].Red << 8;
+ int g = gif_color_map->Colors[i].Green << 8;
+ int b = gif_color_map->Colors[i].Blue << 8;
+ pixel_colors[i] = lookup_rgb_color (f, r, g, b);
+ }
+
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+
+ /* Clear the part of the screen image that are not covered by
+ the image from the GIF file. Full animated GIF support
+ requires more than can be done here (see the gif89 spec,
+ disposal methods). Let's simply assume that the part
+ not covered by a sub-image is in the frame's background color. */
+ image_top = gif->SavedImages[ino].ImageDesc.Top;
+ image_left = gif->SavedImages[ino].ImageDesc.Left;
+ image_width = gif->SavedImages[ino].ImageDesc.Width;
+ image_height = gif->SavedImages[ino].ImageDesc.Height;
+
+ for (y = 0; y < image_top; ++y)
+ for (x = 0; x < width; ++x)
+ XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+
+ for (y = image_top + image_height; y < height; ++y)
+ for (x = 0; x < width; ++x)
+ XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+
+ for (y = image_top; y < image_top + image_height; ++y)
+ {
+ for (x = 0; x < image_left; ++x)
+ XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+ for (x = image_left + image_width; x < width; ++x)
+ XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+ }
+
+ /* Read the GIF image into the X image. We use a local variable
+ `raster' here because RasterBits below is a char *, and invites
+ problems with bytes >= 0x80. */
+ raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
+
+ if (gif->SavedImages[ino].ImageDesc.Interlace)
+ {
+ static int interlace_start[] = {0, 4, 2, 1};
+ static int interlace_increment[] = {8, 8, 4, 2};
+ int pass, inc;
+ int row = interlace_start[0];
+
+ pass = 0;
+
+ for (y = 0; y < image_height; y++)
+ {
+ if (row >= image_height)
+ {
+ row = interlace_start[++pass];
+ while (row >= image_height)
+ row = interlace_start[++pass];
+ }
+
+ for (x = 0; x < image_width; x++)
+ {
+ int i = raster[(y * image_width) + x];
+ XPutPixel (ximg, x + image_left, row + image_top,
+ pixel_colors[i]);
+ }
+
+ row += interlace_increment[pass];
+ }
+ }
+ else
+ {
+ for (y = 0; y < image_height; ++y)
+ for (x = 0; x < image_width; ++x)
+ {
+ int i = raster[y* image_width + x];
+ XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
+ }
+ }
+
+ DGifCloseFile (gif);
+
+ /* Put the image into the pixmap, then free the X image and its buffer. */
+ x_put_x_image (f, ximg, img->pixmap, width, height);
+ x_destroy_x_image (ximg);
+ UNBLOCK_INPUT;
+
+ UNGCPRO;
+ return 1;
+}
+
+#endif /* HAVE_GIF != 0 */
+
+
+
+/***********************************************************************
+ Ghostscript
+ ***********************************************************************/
+
+#ifdef HAVE_GHOSTSCRIPT
+static int gs_image_p P_ ((Lisp_Object object));
+static int gs_load P_ ((struct frame *f, struct image *img));
+static void gs_clear_image P_ ((struct frame *f, struct image *img));
+
+/* The symbol `postscript' identifying images of this type. */
+
+Lisp_Object Qpostscript;
+
+/* Keyword symbols. */
+
+Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
+
+/* Indices of image specification fields in gs_format, below. */
+
+enum gs_keyword_index
+{
+ GS_TYPE,
+ GS_PT_WIDTH,
+ GS_PT_HEIGHT,
+ GS_FILE,
+ GS_LOADER,
+ GS_BOUNDING_BOX,
+ GS_ASCENT,
+ GS_MARGIN,
+ GS_RELIEF,
+ GS_ALGORITHM,
+ GS_HEURISTIC_MASK,
+ GS_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword gs_format[GS_LAST] =
+{
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
+ {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
+ {":file", IMAGE_STRING_VALUE, 1},
+ {":loader", IMAGE_FUNCTION_VALUE, 0},
+ {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
+ {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
+ {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":relief", IMAGE_INTEGER_VALUE, 0},
+ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
+ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+};
+
+/* Structure describing the image type `ghostscript'. */
+
+static struct image_type gs_type =
+{
+ &Qpostscript,
+ gs_image_p,
+ gs_load,
+ gs_clear_image,
+ NULL
+};
+
+
+/* Free X resources of Ghostscript image IMG which is used on frame F. */
+
+static void
+gs_clear_image (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ /* IMG->data.ptr_val may contain a recorded colormap. */
+ xfree (img->data.ptr_val);
+ x_clear_image (f, img);
+}
+
+
+/* Return non-zero if OBJECT is a valid Ghostscript image
+ specification. */
+
+static int
+gs_image_p (object)
+ Lisp_Object object;
+{
+ struct image_keyword fmt[GS_LAST];
+ Lisp_Object tem;
+ int i;
+
+ bcopy (gs_format, fmt, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
+ || (fmt[GS_ASCENT].count
+ && XFASTINT (fmt[GS_ASCENT].value) > 100))
+ return 0;
+
+ /* Bounding box must be a list or vector containing 4 integers. */
+ tem = fmt[GS_BOUNDING_BOX].value;
+ if (CONSP (tem))
+ {
+ for (i = 0; i < 4; ++i, tem = XCDR (tem))
+ if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
+ return 0;
+ if (!NILP (tem))
+ return 0;
+ }
+ else if (VECTORP (tem))
+ {
+ if (XVECTOR (tem)->size != 4)
+ return 0;
+ for (i = 0; i < 4; ++i)
+ if (!INTEGERP (XVECTOR (tem)->contents[i]))
+ return 0;
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
+
+/* Load Ghostscript image IMG for use on frame F. Value is non-zero
+ if successful. */
+
+static int
+gs_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ char buffer[100];
+ Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
+ struct gcpro gcpro1, gcpro2;
+ Lisp_Object frame;
+ double in_width, in_height;
+ Lisp_Object pixel_colors = Qnil;
+
+ /* Compute pixel size of pixmap needed from the given size in the
+ image specification. Sizes in the specification are in pt. 1 pt
+ = 1/72 in, xdpi and ydpi are stored in the frame's X display
+ info. */
+ pt_width = image_spec_value (img->spec, QCpt_width, NULL);
+ in_width = XFASTINT (pt_width) / 72.0;
+ img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
+ pt_height = image_spec_value (img->spec, QCpt_height, NULL);
+ in_height = XFASTINT (pt_height) / 72.0;
+ img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
+
+ /* Create the pixmap. */
+ BLOCK_INPUT;
+ xassert (img->pixmap == 0);
+ img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
+ img->width, img->height,
+ DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
+ UNBLOCK_INPUT;
+
+ if (!img->pixmap)
+ {
+ image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
+ return 0;
+ }
+
+ /* Call the loader to fill the pixmap. It returns a process object
+ if successful. We do not record_unwind_protect here because
+ other places in redisplay like calling window scroll functions
+ don't either. Let the Lisp loader use `unwind-protect' instead. */
+ GCPRO2 (window_and_pixmap_id, pixel_colors);
+
+ sprintf (buffer, "%lu %lu",
+ (unsigned long) FRAME_W32_WINDOW (f),
+ (unsigned long) img->pixmap);
+ window_and_pixmap_id = build_string (buffer);
+
+ sprintf (buffer, "%lu %lu",
+ FRAME_FOREGROUND_PIXEL (f),
+ FRAME_BACKGROUND_PIXEL (f));
+ pixel_colors = build_string (buffer);
+
+ XSETFRAME (frame, f);
+ loader = image_spec_value (img->spec, QCloader, NULL);
+ if (NILP (loader))
+ loader = intern ("gs-load-image");
+
+ img->data.lisp_val = call6 (loader, frame, img->spec,
+ make_number (img->width),
+ make_number (img->height),
+ window_and_pixmap_id,
+ pixel_colors);
+ UNGCPRO;
+ return PROCESSP (img->data.lisp_val);
+}
+
+
+/* Kill the Ghostscript process that was started to fill PIXMAP on
+ frame F. Called from XTread_socket when receiving an event
+ telling Emacs that Ghostscript has finished drawing. */
+
+void
+x_kill_gs_process (pixmap, f)
+ Pixmap pixmap;
+ struct frame *f;
+{
+ struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+ int class, i;
+ struct image *img;
+
+ /* Find the image containing PIXMAP. */
+ for (i = 0; i < c->used; ++i)
+ if (c->images[i]->pixmap == pixmap)
+ break;
+
+ /* Kill the GS process. We should have found PIXMAP in the image
+ cache and its image should contain a process object. */
+ xassert (i < c->used);
+ img = c->images[i];
+ xassert (PROCESSP (img->data.lisp_val));
+ Fkill_process (img->data.lisp_val, Qnil);
+ img->data.lisp_val = Qnil;
+
+ /* On displays with a mutable colormap, figure out the colors
+ allocated for the image by looking at the pixels of an XImage for
+ img->pixmap. */
+ class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
+ if (class != StaticColor && class != StaticGray && class != TrueColor)
+ {
+ XImage *ximg;
+
+ BLOCK_INPUT;
+
+ /* Try to get an XImage for img->pixmep. */
+ ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
+ 0, 0, img->width, img->height, ~0, ZPixmap);
+ if (ximg)
+ {
+ int x, y;
+
+ /* Initialize the color table. */
+ init_color_table ();
+
+ /* For each pixel of the image, look its color up in the
+ color table. After having done so, the color table will
+ contain an entry for each color used by the image. */
+ for (y = 0; y < img->height; ++y)
+ for (x = 0; x < img->width; ++x)
+ {
+ unsigned long pixel = XGetPixel (ximg, x, y);
+ lookup_pixel_color (f, pixel);
+ }
+
+ /* Record colors in the image. Free color table and XImage. */
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+ XDestroyImage (ximg);
+
+#if 0 /* This doesn't seem to be the case. If we free the colors
+ here, we get a BadAccess later in x_clear_image when
+ freeing the colors. */
+ /* We have allocated colors once, but Ghostscript has also
+ allocated colors on behalf of us. So, to get the
+ reference counts right, free them once. */
+ if (img->ncolors)
+ {
+ Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+ XFreeColors (FRAME_W32_DISPLAY (f), cmap,
+ img->colors, img->ncolors, 0);
+ }
+#endif
+ }
+ else
+ image_error ("Cannot get X image of `%s'; colors will not be freed",
+ img->spec, Qnil);
+
+ UNBLOCK_INPUT;
+ }
+}
+
+#endif /* HAVE_GHOSTSCRIPT */
+
+
+/***********************************************************************
+ Window properties
+ ***********************************************************************/
+
+DEFUN ("x-change-window-property", Fx_change_window_property,
+ Sx_change_window_property, 2, 3, 0,
+ doc: /* Change window property PROP to VALUE on the X window of FRAME.
+PROP and VALUE must be strings. FRAME nil or omitted means use the
+selected frame. Value is VALUE. */)
+ (prop, value, frame)
+ Lisp_Object frame, prop, value;
+{
+#if 0 /* MAC_TODO : port window properties to Mac */
+ struct frame *f = check_x_frame (frame);
+ Atom prop_atom;
+
+ CHECK_STRING (prop);
+ CHECK_STRING (value);
+
+ BLOCK_INPUT;
+ prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
+ XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
+ prop_atom, XA_STRING, 8, PropModeReplace,
+ XSTRING (value)->data, XSTRING (value)->size);
+
+ /* Make sure the property is set when we return. */
+ XFlush (FRAME_W32_DISPLAY (f));
+ UNBLOCK_INPUT;
+
+#endif /* MAC_TODO */
+
+ return value;
+}
+
+
+DEFUN ("x-delete-window-property", Fx_delete_window_property,
+ Sx_delete_window_property, 1, 2, 0,
+ doc: /* Remove window property PROP from X window of FRAME.
+FRAME nil or omitted means use the selected frame. Value is PROP. */)
+ (prop, frame)
+ Lisp_Object prop, frame;
+{
+#if 0 /* MAC_TODO : port window properties to Mac */
+
+ struct frame *f = check_x_frame (frame);
+ Atom prop_atom;
+
+ CHECK_STRING (prop);
+ BLOCK_INPUT;
+ prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
+ XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
+
+ /* Make sure the property is removed when we return. */
+ XFlush (FRAME_W32_DISPLAY (f));
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+
+ return prop;
+}
+
+
+DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
+ 1, 2, 0,
+ doc: /* Value is the value of window property PROP on FRAME.
+If FRAME is nil or omitted, use the selected frame. Value is nil
+if FRAME hasn't a property with name PROP or if PROP has no string
+value. */)
+ (prop, frame)
+ Lisp_Object prop, frame;
+{
+#if 0 /* MAC_TODO : port window properties to Mac */
+
+ struct frame *f = check_x_frame (frame);
+ Atom prop_atom;
+ int rc;
+ Lisp_Object prop_value = Qnil;
+ char *tmp_data = NULL;
+ Atom actual_type;
+ int actual_format;
+ unsigned long actual_size, bytes_remaining;
+
+ CHECK_STRING (prop);
+ BLOCK_INPUT;
+ prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
+ rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
+ prop_atom, 0, 0, False, XA_STRING,
+ &actual_type, &actual_format, &actual_size,
+ &bytes_remaining, (unsigned char **) &tmp_data);
+ if (rc == Success)
+ {
+ int size = bytes_remaining;
+
+ XFree (tmp_data);
+ tmp_data = NULL;
+
+ rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
+ prop_atom, 0, bytes_remaining,
+ False, XA_STRING,
+ &actual_type, &actual_format,
+ &actual_size, &bytes_remaining,
+ (unsigned char **) &tmp_data);
+ if (rc == Success)
+ prop_value = make_string (tmp_data, size);
+
+ XFree (tmp_data);
+ }
+
+ UNBLOCK_INPUT;
+
+ return prop_value;
+
+#endif /* MAC_TODO */
+ return Qnil;
+}
+
+
+
+/***********************************************************************
+ Hourglass cursor
+ ***********************************************************************/
+
+/* If non-null, an asynchronous timer that, when it expires, displays
+ an hourglass cursor on all frames. */
+
+static struct atimer *hourglass_atimer;
+
+/* Non-zero means an hourglass cursor is currently shown. */
+
+static int hourglass_shown_p;
+
+/* Number of seconds to wait before displaying an hourglass cursor. */
+
+static Lisp_Object Vhourglass_delay;
+
+/* Default number of seconds to wait before displaying an hourglass
+ cursor. */
+
+#define DEFAULT_HOURGLASS_DELAY 1
+
+/* Function prototypes. */
+
+static void show_hourglass P_ ((struct atimer *));
+static void hide_hourglass P_ ((void));
+
+
+/* Cancel a currently active hourglass timer, and start a new one. */
+
+void
+start_hourglass ()
+{
+#if 0 /* MAC_TODO: cursor shape changes. */
+ EMACS_TIME delay;
+ int secs, usecs = 0;
+
+ cancel_hourglass ();
+
+ if (INTEGERP (Vhourglass_delay)
+ && XINT (Vhourglass_delay) > 0)
+ secs = XFASTINT (Vhourglass_delay);
+ else if (FLOATP (Vhourglass_delay)
+ && XFLOAT_DATA (Vhourglass_delay) > 0)
+ {
+ Lisp_Object tem;
+ tem = Ftruncate (Vhourglass_delay, Qnil);
+ secs = XFASTINT (tem);
+ usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
+ }
+ else
+ secs = DEFAULT_HOURGLASS_DELAY;
+
+ EMACS_SET_SECS_USECS (delay, secs, usecs);
+ hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
+ show_hourglass, NULL);
+#endif /* MAC_TODO */
+}
+
+
+/* Cancel the hourglass cursor timer if active, hide an hourglass
+ cursor if shown. */
+
+void
+cancel_hourglass ()
+{
+ if (hourglass_atimer)
+ {
+ cancel_atimer (hourglass_atimer);
+ hourglass_atimer = NULL;
+ }
+
+ if (hourglass_shown_p)
+ hide_hourglass ();
+}
+
+
+/* Timer function of hourglass_atimer. TIMER is equal to
+ hourglass_atimer.
+
+ Display an hourglass cursor on all frames by mapping the frames'
+ hourglass_window. Set the hourglass_p flag in the frames'
+ output_data.x structure to indicate that an hourglass cursor is
+ shown on the frames. */
+
+static void
+show_hourglass (timer)
+ struct atimer *timer;
+{
+#if 0 /* MAC_TODO: cursor shape changes. */
+ /* The timer implementation will cancel this timer automatically
+ after this function has run. Set hourglass_atimer to null
+ so that we know the timer doesn't have to be canceled. */
+ hourglass_atimer = NULL;
+
+ if (!hourglass_shown_p)
+ {
+ Lisp_Object rest, frame;
+
+ BLOCK_INPUT;
+
+ FOR_EACH_FRAME (rest, frame)
+ if (FRAME_W32_P (XFRAME (frame)))
+ {
+ struct frame *f = XFRAME (frame);
+
+ f->output_data.w32->hourglass_p = 1;
+
+ if (!f->output_data.w32->hourglass_window)
+ {
+ unsigned long mask = CWCursor;
+ XSetWindowAttributes attrs;
+
+ attrs.cursor = f->output_data.w32->hourglass_cursor;
+
+ f->output_data.w32->hourglass_window
+ = XCreateWindow (FRAME_X_DISPLAY (f),
+ FRAME_OUTER_WINDOW (f),
+ 0, 0, 32000, 32000, 0, 0,
+ InputOnly,
+ CopyFromParent,
+ mask, &attrs);
+ }
+
+ XMapRaised (FRAME_X_DISPLAY (f),
+ f->output_data.w32->hourglass_window);
+ XFlush (FRAME_X_DISPLAY (f));
+ }
+
+ hourglass_shown_p = 1;
+ UNBLOCK_INPUT;
+ }
+#endif /* MAC_TODO */
+}
+
+
+/* Hide the hourglass cursor on all frames, if it is currently shown. */
+
+static void
+hide_hourglass ()
+{
+#if 0 /* MAC_TODO: cursor shape changes. */
+ if (hourglass_shown_p)
+ {
+ Lisp_Object rest, frame;
+
+ BLOCK_INPUT;
+ FOR_EACH_FRAME (rest, frame)
+ {
+ struct frame *f = XFRAME (frame);
+
+ if (FRAME_W32_P (f)
+ /* Watch out for newly created frames. */
+ && f->output_data.x->hourglass_window)
+ {
+ XUnmapWindow (FRAME_X_DISPLAY (f),
+ f->output_data.x->hourglass_window);
+ /* Sync here because XTread_socket looks at the
+ hourglass_p flag that is reset to zero below. */
+ XSync (FRAME_X_DISPLAY (f), False);
+ f->output_data.x->hourglass_p = 0;
+ }
+ }
+
+ hourglass_shown_p = 0;
+ UNBLOCK_INPUT;
+ }
+#endif /* MAC_TODO */
+}
+
+
+
+/***********************************************************************
+ Tool tips
+ ***********************************************************************/
+
+static Lisp_Object x_create_tip_frame P_ ((struct mac_display_info *,
+ Lisp_Object));
+
+/* The frame of a currently visible tooltip, or null. */
+
+Lisp_Object tip_frame;
+
+/* If non-nil, a timer started that hides the last tooltip when it
+ fires. */
+
+Lisp_Object tip_timer;
+Window tip_window;
+
+/* If non-nil, a vector of 3 elements containing the last args
+ with which x-show-tip was called. See there. */
+
+Lisp_Object last_show_tip_args;
+
+/* Create a frame for a tooltip on the display described by DPYINFO.
+ PARMS is a list of frame parameters. Value is the frame. */
+
+static Lisp_Object
+x_create_tip_frame (dpyinfo, parms)
+ struct mac_display_info *dpyinfo;
+ Lisp_Object parms;
+{
+#if 0 /* MAC_TODO : Mac version */
+ struct frame *f;
+ Lisp_Object frame, tem;
+ Lisp_Object name;
+ long window_prompting = 0;
+ int width, height;
+ int count = specpdl_ptr - specpdl;
+ struct gcpro gcpro1, gcpro2, gcpro3;
+ struct kboard *kb;
+
+ check_x ();
+
+ /* Use this general default value to start with until we know if
+ this frame has a specified name. */
+ Vx_resource_name = Vinvocation_name;
+
+#ifdef MULTI_KBOARD
+ kb = dpyinfo->kboard;
+#else
+ kb = &the_only_kboard;
+#endif
+
+ /* Get the name of the frame to use for resource lookup. */
+ name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
+ if (!STRINGP (name)
+ && !EQ (name, Qunbound)
+ && !NILP (name))
+ error ("Invalid frame name--not a string or nil");
+ Vx_resource_name = name;
+
+ frame = Qnil;
+ GCPRO3 (parms, name, frame);
+ tip_frame = f = make_frame (1);
+ XSETFRAME (frame, f);
+ FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
+
+ f->output_method = output_w32;
+ f->output_data.w32 =
+ (struct w32_output *) xmalloc (sizeof (struct w32_output));
+ bzero (f->output_data.w32, sizeof (struct w32_output));
+#if 0
+ f->output_data.w32->icon_bitmap = -1;
+#endif
+ f->output_data.w32->fontset = -1;
+ f->icon_name = Qnil;
+
+#ifdef MULTI_KBOARD
+ FRAME_KBOARD (f) = kb;
+#endif
+ f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
+ f->output_data.w32->explicit_parent = 0;
+
+ /* Set the name; the functions to which we pass f expect the name to
+ be set. */
+ if (EQ (name, Qunbound) || NILP (name))
+ {
+ f->name = build_string (dpyinfo->x_id_name);
+ f->explicit_name = 0;
+ }
+ else
+ {
+ f->name = name;
+ f->explicit_name = 1;
+ /* use the frame's title when getting resources for this frame. */
+ specbind (Qx_resource_name, name);
+ }
+
+ /* Extract the window parameters from the supplied values
+ that are needed to determine window geometry. */
+ {
+ Lisp_Object font;
+
+ font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
+
+ BLOCK_INPUT;
+ /* First, try whatever font the caller has specified. */
+ if (STRINGP (font))
+ {
+ tem = Fquery_fontset (font, Qnil);
+ if (STRINGP (tem))
+ font = x_new_fontset (f, XSTRING (tem)->data);
+ else
+ font = x_new_font (f, XSTRING (font)->data);
+ }
+
+ /* Try out a font which we hope has bold and italic variations. */
+ if (!STRINGP (font))
+ font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
+ if (!STRINGP (font))
+ font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
+ if (! STRINGP (font))
+ font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
+ if (! STRINGP (font))
+ /* This was formerly the first thing tried, but it finds too many fonts
+ and takes too long. */
+ font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
+ /* If those didn't work, look for something which will at least work. */
+ if (! STRINGP (font))
+ font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
+ UNBLOCK_INPUT;
+ if (! STRINGP (font))
+ font = build_string ("fixed");
+
+ x_default_parameter (f, parms, Qfont, font,
+ "font", "Font", RES_TYPE_STRING);
+ }
+
+ x_default_parameter (f, parms, Qborder_width, make_number (2),
+ "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
+
+ /* This defaults to 2 in order to match xterm. We recognize either
+ internalBorderWidth or internalBorder (which is what xterm calls
+ it). */
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ {
+ Lisp_Object value;
+
+ value = w32_get_arg (parms, Qinternal_border_width,
+ "internalBorder", "internalBorder", RES_TYPE_NUMBER);
+ if (! EQ (value, Qunbound))
+ parms = Fcons (Fcons (Qinternal_border_width, value),
+ parms);
+ }
+
+ x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
+ "internalBorderWidth", "internalBorderWidth",
+ RES_TYPE_NUMBER);
+
+ /* Also do the stuff which must be set before the window exists. */
+ x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
+ "foreground", "Foreground", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
+ "background", "Background", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
+ "pointerColor", "Foreground", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
+ "cursorColor", "Foreground", RES_TYPE_STRING);
+ x_default_parameter (f, parms, Qborder_color, build_string ("black"),
+ "borderColor", "BorderColor", RES_TYPE_STRING);
+
+ /* Init faces before x_default_parameter is called for scroll-bar
+ parameters because that function calls x_set_scroll_bar_width,
+ which calls change_frame_size, which calls Fset_window_buffer,
+ which runs hooks, which call Fvertical_motion. At the end, we
+ end up in init_iterator with a null face cache, which should not
+ happen. */
+ init_frame_faces (f);
+
+ f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
+ window_prompting = x_figure_window_size (f, parms);
+
+ if (window_prompting & XNegative)
+ {
+ if (window_prompting & YNegative)
+ f->output_data.w32->win_gravity = SouthEastGravity;
+ else
+ f->output_data.w32->win_gravity = NorthEastGravity;
+ }
+ else
+ {
+ if (window_prompting & YNegative)
+ f->output_data.w32->win_gravity = SouthWestGravity;
+ else
+ f->output_data.w32->win_gravity = NorthWestGravity;
+ }
+
+ f->output_data.w32->size_hint_flags = window_prompting;
+ {
+ XSetWindowAttributes attrs;
+ unsigned long mask;
+
+ BLOCK_INPUT;
+ mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
+ /* Window managers looks at the override-redirect flag to
+ determine whether or net to give windows a decoration (Xlib
+ 3.2.8). */
+ attrs.override_redirect = True;
+ attrs.save_under = True;
+ attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
+ /* Arrange for getting MapNotify and UnmapNotify events. */
+ attrs.event_mask = StructureNotifyMask;
+ tip_window
+ = FRAME_W32_WINDOW (f)
+ = XCreateWindow (FRAME_W32_DISPLAY (f),
+ FRAME_W32_DISPLAY_INFO (f)->root_window,
+ /* x, y, width, height */
+ 0, 0, 1, 1,
+ /* Border. */
+ 1,
+ CopyFromParent, InputOutput, CopyFromParent,
+ mask, &attrs);
+ UNBLOCK_INPUT;
+ }
+
+ x_make_gc (f);
+
+ x_default_parameter (f, parms, Qauto_raise, Qnil,
+ "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ x_default_parameter (f, parms, Qauto_lower, Qnil,
+ "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ x_default_parameter (f, parms, Qcursor_type, Qbox,
+ "cursorType", "CursorType", RES_TYPE_SYMBOL);
+
+ /* Dimensions, especially f->height, must be done via change_frame_size.
+ Change will not be effected unless different from the current
+ f->height. */
+ width = f->width;
+ height = f->height;
+ f->height = 0;
+ SET_FRAME_WIDTH (f, 0);
+ change_frame_size (f, height, width, 1, 0, 0);
+
+ f->no_split = 1;
+
+ UNGCPRO;
+
+ /* It is now ok to make the frame official even if we get an error
+ below. And the frame needs to be on Vframe_list or making it
+ visible won't work. */
+ Vframe_list = Fcons (frame, Vframe_list);
+
+ /* Now that the frame is official, it counts as a reference to
+ its display. */
+ FRAME_W32_DISPLAY_INFO (f)->reference_count++;
+
+ return unbind_to (count, frame);
+#endif /* MAC_TODO */
+ return Qnil;
+}
+
+
+DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
+ doc : /* Show STRING in a "tooltip" window on frame FRAME.
+A tooltip window is a small window displaying a string.
+
+FRAME nil or omitted means use the selected frame.
+
+PARMS is an optional list of frame parameters which can be used to
+change the tooltip's appearance.
+
+Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
+means use the default timeout of 5 seconds.
+
+If the list of frame parameters PARAMS contains a `left' parameters,
+the tooltip is displayed at that x-position. Otherwise it is
+displayed at the mouse position, with offset DX added (default is 5 if
+DX isn't specified). Likewise for the y-position; if a `top' frame
+parameter is specified, it determines the y-position of the tooltip
+window, otherwise it is displayed at the mouse position, with offset
+DY added (default is 10). */)
+ (string, frame, parms, timeout, dx, dy)
+ Lisp_Object string, frame, parms, timeout, dx, dy;
+{
+ struct frame *f;
+ struct window *w;
+ Window root, child;
+ Lisp_Object buffer, top, left;
+ struct buffer *old_buffer;
+ struct text_pos pos;
+ int i, width, height;
+ int root_x, root_y, win_x, win_y;
+ unsigned pmask;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ int old_windows_or_buffers_changed = windows_or_buffers_changed;
+ int count = specpdl_ptr - specpdl;
+
+ specbind (Qinhibit_redisplay, Qt);
+
+ GCPRO4 (string, parms, frame, timeout);
+
+ CHECK_STRING (string);
+ f = check_x_frame (frame);
+ if (NILP (timeout))
+ timeout = make_number (5);
+ else
+ CHECK_NATNUM (timeout);
+
+ if (NILP (dx))
+ dx = make_number (5);
+ else
+ CHECK_NUMBER (dx);
+
+ if (NILP (dy))
+ dy = make_number (-10);
+ else
+ CHECK_NUMBER (dy);
+
+ if (NILP (last_show_tip_args))
+ last_show_tip_args = Fmake_vector (make_number (3), Qnil);
+
+ if (!NILP (tip_frame))
+ {
+ Lisp_Object last_string = AREF (last_show_tip_args, 0);
+ Lisp_Object last_frame = AREF (last_show_tip_args, 1);
+ Lisp_Object last_parms = AREF (last_show_tip_args, 2);
+
+ if (EQ (frame, last_frame)
+ && !NILP (Fequal (last_string, string))
+ && !NILP (Fequal (last_parms, parms)))
+ {
+ struct frame *f = XFRAME (tip_frame);
+
+ /* Only DX and DY have changed. */
+ if (!NILP (tip_timer))
+ {
+ Lisp_Object timer = tip_timer;
+ tip_timer = Qnil;
+ call1 (Qcancel_timer, timer);
+ }
+
+#if 0 /* MAC_TODO : Mac specifics */
+ BLOCK_INPUT;
+ compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
+ XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ root_x, root_y - PIXEL_HEIGHT (f));
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+ goto start_timer;
+ }
+ }
+
+ /* Hide a previous tip, if any. */
+ Fx_hide_tip ();
+
+ ASET (last_show_tip_args, 0, string);
+ ASET (last_show_tip_args, 1, frame);
+ ASET (last_show_tip_args, 2, parms);
+
+ /* Add default values to frame parameters. */
+ if (NILP (Fassq (Qname, parms)))
+ parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
+ if (NILP (Fassq (Qborder_width, parms)))
+ parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
+ if (NILP (Fassq (Qborder_color, parms)))
+ parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
+ if (NILP (Fassq (Qbackground_color, parms)))
+ parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+ parms);
+
+ /* Create a frame for the tooltip, and record it in the global
+ variable tip_frame. */
+ frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms);
+ f = XFRAME (frame);
+
+ /* Set up the frame's root window. Currently we use a size of 80
+ columns x 40 lines. If someone wants to show a larger tip, he
+ will loose. I don't think this is a realistic case. */
+ w = XWINDOW (FRAME_ROOT_WINDOW (f));
+ w->left = w->top = make_number (0);
+ w->width = make_number (80);
+ w->height = make_number (40);
+ adjust_glyphs (f);
+ w->pseudo_window_p = 1;
+
+ /* Display the tooltip text in a temporary buffer. */
+ buffer = Fget_buffer_create (build_string (" *tip*"));
+ Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
+ old_buffer = current_buffer;
+ set_buffer_internal_1 (XBUFFER (buffer));
+ Ferase_buffer ();
+ Finsert (1, &string);
+ clear_glyph_matrix (w->desired_matrix);
+ clear_glyph_matrix (w->current_matrix);
+ SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
+ try_window (FRAME_ROOT_WINDOW (f), pos);
+
+ /* Compute width and height of the tooltip. */
+ width = height = 0;
+ for (i = 0; i < w->desired_matrix->nrows; ++i)
+ {
+ struct glyph_row *row = &w->desired_matrix->rows[i];
+ struct glyph *last;
+ int row_width;
+
+ /* Stop at the first empty row at the end. */
+ if (!row->enabled_p || !row->displays_text_p)
+ break;
+
+ /* Let the row go over the full width of the frame. */
+ row->full_width_p = 1;
+
+ /* There's a glyph at the end of rows that is use to place
+ the cursor there. Don't include the width of this glyph. */
+ if (row->used[TEXT_AREA])
+ {
+ last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
+ row_width = row->pixel_width - last->pixel_width;
+ }
+ else
+ row_width = row->pixel_width;
+
+ height += row->height;
+ width = max (width, row_width);
+ }
+
+ /* Add the frame's internal border to the width and height the X
+ window should have. */
+ height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+ width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+
+ /* Move the tooltip window where the mouse pointer is. Resize and
+ show it. */
+#if 0 /* TODO : Mac specifics */
+ compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
+
+ BLOCK_INPUT;
+ XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
+ &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
+ XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
+ root_x + 5, root_y - height - 5, width, height);
+ XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
+ UNBLOCK_INPUT;
+#endif /* MAC_TODO */
+
+ /* Draw into the window. */
+ w->must_be_updated_p = 1;
+ update_single_window (w, 1);
+
+ /* Restore original current buffer. */
+ set_buffer_internal_1 (old_buffer);
+ windows_or_buffers_changed = old_windows_or_buffers_changed;
+
+ start_timer:
+ /* Let the tip disappear after timeout seconds. */
+ tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
+ intern ("x-hide-tip"));
+
+ UNGCPRO;
+ return unbind_to (count, Qnil);
+}
+
+
+DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
+ doc: /* Hide the current tooltip window, if there is any.
+Value is t is tooltip was open, nil otherwise. */)
+ ()
+{
+ int count;
+ Lisp_Object deleted, frame, timer;
+ struct gcpro gcpro1, gcpro2;
+
+ /* Return quickly if nothing to do. */
+ if (NILP (tip_timer) && NILP (tip_frame))
+ return Qnil;
+
+ frame = tip_frame;
+ timer = tip_timer;
+ GCPRO2 (frame, timer);
+ tip_frame = tip_timer = deleted = Qnil;
+
+ count = BINDING_STACK_SIZE ();
+ specbind (Qinhibit_redisplay, Qt);
+ specbind (Qinhibit_quit, Qt);
+
+ if (!NILP (timer))
+ call1 (Qcancel_timer, timer);
+
+ if (FRAMEP (frame))
+ {
+ Fdelete_frame (frame, Qnil);
+ deleted = Qt;
+ }
+
+ UNGCPRO;
+ return unbind_to (count, deleted);
+}
+
+
+
+/***********************************************************************
+ File selection dialog
+ ***********************************************************************/
+
+#if 0 /* MAC_TODO: can standard file dialog */
+extern Lisp_Object Qfile_name_history;
+
+DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
+ doc: /* Read file name, prompting with PROMPT in directory DIR.
+Use a file selection dialog.
+Select DEFAULT-FILENAME in the dialog's file selection box, if
+specified. Don't let the user enter a file name in the file
+selection dialog's entry field, if MUSTMATCH is non-nil. */)
+ (prompt, dir, default_filename, mustmatch)
+ Lisp_Object prompt, dir, default_filename, mustmatch;
+{
+ struct frame *f = SELECTED_FRAME ();
+ Lisp_Object file = Qnil;
+ int count = specpdl_ptr - specpdl;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+ char filename[MAX_PATH + 1];
+ char init_dir[MAX_PATH + 1];
+ int use_dialog_p = 1;
+
+ GCPRO5 (prompt, dir, default_filename, mustmatch, file);
+ CHECK_STRING (prompt);
+ CHECK_STRING (dir);
+
+ /* Create the dialog with PROMPT as title, using DIR as initial
+ directory and using "*" as pattern. */
+ dir = Fexpand_file_name (dir, Qnil);
+ strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
+ init_dir[MAX_PATH] = '\0';
+ unixtodos_filename (init_dir);
+
+ if (STRINGP (default_filename))
+ {
+ char *file_name_only;
+ char *full_path_name = XSTRING (default_filename)->data;
+
+ unixtodos_filename (full_path_name);
+
+ file_name_only = strrchr (full_path_name, '\\');
+ if (!file_name_only)
+ file_name_only = full_path_name;
+ else
+ {
+ file_name_only++;
+
+ /* If default_file_name is a directory, don't use the open
+ file dialog, as it does not support selecting
+ directories. */
+ if (!(*file_name_only))
+ use_dialog_p = 0;
+ }
+
+ strncpy (filename, file_name_only, MAX_PATH);
+ filename[MAX_PATH] = '\0';
+ }
+ else
+ filename[0] = '\0';
+
+ if (use_dialog_p)
+ {
+ OPENFILENAME file_details;
+ char *filename_file;
+
+ /* Prevent redisplay. */
+ specbind (Qinhibit_redisplay, Qt);
+ BLOCK_INPUT;
+
+ bzero (&file_details, sizeof (file_details));
+ file_details.lStructSize = sizeof (file_details);
+ file_details.hwndOwner = FRAME_W32_WINDOW (f);
+ file_details.lpstrFile = filename;
+ file_details.nMaxFile = sizeof (filename);
+ file_details.lpstrInitialDir = init_dir;
+ file_details.lpstrTitle = XSTRING (prompt)->data;
+ file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
+
+ if (!NILP (mustmatch))
+ file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
+
+ if (GetOpenFileName (&file_details))
+ {
+ dostounix_filename (filename);
+ file = build_string (filename);
+ }
+ else
+ file = Qnil;
+
+ UNBLOCK_INPUT;
+ file = unbind_to (count, file);
+ }
+ /* Open File dialog will not allow folders to be selected, so resort
+ to minibuffer completing reads for directories. */
+ else
+ file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
+ dir, mustmatch, dir, Qfile_name_history,
+ default_filename, Qnil);
+
+ UNGCPRO;
+
+ /* Make "Cancel" equivalent to C-g. */
+ if (NILP (file))
+ Fsignal (Qquit, Qnil);
+
+ return unbind_to (count, file);
+}
+#endif /* MAC_TODO */
+
+
+
+/***********************************************************************
+ Tests
+ ***********************************************************************/
+
+#if GLYPH_DEBUG
+
+DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
+ doc: /* Value is non-nil if SPEC is a valid image specification. */)
+ (spec)
+ Lisp_Object spec;
+{
+ return valid_image_p (spec) ? Qt : Qnil;
+}
+
+
+DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
+ (spec)
+ Lisp_Object spec;
+{
+ int id = -1;
+
+ if (valid_image_p (spec))
+ id = lookup_image (SELECTED_FRAME (), spec);
+
+ debug_print (spec);
+ return make_number (id);
+}
+
+#endif /* GLYPH_DEBUG != 0 */
+
+
+
+void
+syms_of_macfns ()
+{
+ /* Certainly running on Mac. */
+ mac_in_use = 1;
+
+ /* The section below is built by the lisp expression at the top of the file,
+ just above where these variables are declared. */
+ /*&&& init symbols here &&&*/
+ Qauto_raise = intern ("auto-raise");
+ staticpro (&Qauto_raise);
+ Qauto_lower = intern ("auto-lower");
+ staticpro (&Qauto_lower);
+ Qbar = intern ("bar");
+ staticpro (&Qbar);
+ Qborder_color = intern ("border-color");
+ staticpro (&Qborder_color);
+ Qborder_width = intern ("border-width");
+ staticpro (&Qborder_width);
+ Qbox = intern ("box");
+ staticpro (&Qbox);
+ Qcursor_color = intern ("cursor-color");
+ staticpro (&Qcursor_color);
+ Qcursor_type = intern ("cursor-type");
+ staticpro (&Qcursor_type);
+ Qgeometry = intern ("geometry");
+ staticpro (&Qgeometry);
+ Qicon_left = intern ("icon-left");
+ staticpro (&Qicon_left);
+ Qicon_top = intern ("icon-top");
+ staticpro (&Qicon_top);
+ Qicon_type = intern ("icon-type");
+ staticpro (&Qicon_type);
+ Qicon_name = intern ("icon-name");
+ staticpro (&Qicon_name);
+ Qinternal_border_width = intern ("internal-border-width");
+ staticpro (&Qinternal_border_width);
+ Qleft = intern ("left");
+ staticpro (&Qleft);
+ Qright = intern ("right");
+ staticpro (&Qright);
+ Qmouse_color = intern ("mouse-color");
+ staticpro (&Qmouse_color);
+ Qnone = intern ("none");
+ staticpro (&Qnone);
+ Qparent_id = intern ("parent-id");
+ staticpro (&Qparent_id);
+ Qscroll_bar_width = intern ("scroll-bar-width");
+ staticpro (&Qscroll_bar_width);
+ Qsuppress_icon = intern ("suppress-icon");
+ staticpro (&Qsuppress_icon);
+ Qundefined_color = intern ("undefined-color");
+ staticpro (&Qundefined_color);
+ Qvertical_scroll_bars = intern ("vertical-scroll-bars");
+ staticpro (&Qvertical_scroll_bars);
+ Qvisibility = intern ("visibility");
+ staticpro (&Qvisibility);
+ Qwindow_id = intern ("window-id");
+ staticpro (&Qwindow_id);
+ Qx_frame_parameter = intern ("x-frame-parameter");
+ staticpro (&Qx_frame_parameter);
+ Qx_resource_name = intern ("x-resource-name");
+ staticpro (&Qx_resource_name);
+ Quser_position = intern ("user-position");
+ staticpro (&Quser_position);
+ Quser_size = intern ("user-size");
+ staticpro (&Quser_size);
+ Qscreen_gamma = intern ("screen-gamma");
+ staticpro (&Qscreen_gamma);
+ Qline_spacing = intern ("line-spacing");
+ staticpro (&Qline_spacing);
+ Qcenter = intern ("center");
+ staticpro (&Qcenter);
+ /* This is the end of symbol initialization. */
+
+ Qhyper = intern ("hyper");
+ staticpro (&Qhyper);
+ Qsuper = intern ("super");
+ staticpro (&Qsuper);
+ Qmeta = intern ("meta");
+ staticpro (&Qmeta);
+ Qalt = intern ("alt");
+ staticpro (&Qalt);
+ Qctrl = intern ("ctrl");
+ staticpro (&Qctrl);
+ Qcontrol = intern ("control");
+ staticpro (&Qcontrol);
+ Qshift = intern ("shift");
+ staticpro (&Qshift);
+
+ /* Text property `display' should be nonsticky by default. */
+ Vtext_property_default_nonsticky
+ = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
+
+
+ Qlaplace = intern ("laplace");
+ staticpro (&Qlaplace);
+
+ Qface_set_after_frame_default = intern ("face-set-after-frame-default");
+ staticpro (&Qface_set_after_frame_default);
+
+ Fput (Qundefined_color, Qerror_conditions,
+ Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
+ Fput (Qundefined_color, Qerror_message,
+ build_string ("Undefined color"));
+
+ init_x_parm_symbols ();
+
+ DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
+ doc: /* List of directories to search for bitmap files for w32. */);
+ Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
+
+ DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
+ doc: /* The shape of the pointer when over text.
+Changing the value does not affect existing frames
+unless you set the mouse color. */);
+ Vx_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
+ doc: /* The name Emacs uses to look up resources; for internal use only.
+`x-get-resource' uses this as the first component of the instance name
+when requesting resource values.
+Emacs initially sets `x-resource-name' to the name under which Emacs
+was invoked, or to the value specified with the `-name' or `-rn'
+switches, if present. */);
+ Vx_resource_name = Qnil;
+
+ Vx_nontext_pointer_shape = Qnil;
+
+ Vx_mode_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
+ doc: /* The shape of the pointer when Emacs is hourglass.
+This variable takes effect when you create a new frame
+or when you set the mouse color. */);
+ Vx_hourglass_pointer_shape = Qnil;
+
+ DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
+ doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
+ display_hourglass_p = 1;
+
+ DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
+ doc: /* *Seconds to wait before displaying an hourglass pointer.
+Value must be an integer or float. */);
+ Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
+
+ DEFVAR_LISP ("x-sensitive-text-pointer-shape",
+ &Vx_sensitive_text_pointer_shape,
+ doc: /* The shape of the pointer when over mouse-sensitive text.
+This variable takes effect when you create a new frame
+or when you set the mouse color. */);
+ Vx_sensitive_text_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
+ doc: /* A string indicating the foreground color of the cursor box. */);
+ Vx_cursor_fore_pixel = Qnil;
+
+ DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
+ doc: /* Non-nil if no window manager is in use.
+Emacs doesn't try to figure this out; this is always nil
+unless you set it to something else. */);
+ /* We don't have any way to find this out, so set it to nil
+ and maybe the user would like to set it to t. */
+ Vx_no_window_manager = Qnil;
+
+ DEFVAR_LISP ("x-pixel-size-width-font-regexp",
+ &Vx_pixel_size_width_font_regexp,
+ doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
+
+Since Emacs gets width of a font matching with this regexp from
+PIXEL_SIZE field of the name, font finding mechanism gets faster for
+such a font. This is especially effective for such large fonts as
+Chinese, Japanese, and Korean. */);
+ Vx_pixel_size_width_font_regexp = Qnil;
+
+ DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
+ doc: /* Time after which cached images are removed from the cache.
+When an image has not been displayed this many seconds, remove it
+from the image cache. Value must be an integer or nil with nil
+meaning don't clear the cache. */);
+ Vimage_cache_eviction_delay = make_number (30 * 60);
+
+#if 0 /* MAC_TODO: implement get X resource */
+ defsubr (&Sx_get_resource);
+#endif
+ defsubr (&Sx_change_window_property);
+ defsubr (&Sx_delete_window_property);
+ defsubr (&Sx_window_property);
+ defsubr (&Sxw_display_color_p);
+ defsubr (&Sx_display_grayscale_p);
+ defsubr (&Sxw_color_defined_p);
+ defsubr (&Sxw_color_values);
+ defsubr (&Sx_server_max_request_size);
+ defsubr (&Sx_server_vendor);
+ defsubr (&Sx_server_version);
+ defsubr (&Sx_display_pixel_width);
+ defsubr (&Sx_display_pixel_height);
+ defsubr (&Sx_display_mm_width);
+ defsubr (&Sx_display_mm_height);
+ defsubr (&Sx_display_screens);
+ defsubr (&Sx_display_planes);
+ defsubr (&Sx_display_color_cells);
+ defsubr (&Sx_display_visual_class);
+ defsubr (&Sx_display_backing_store);
+ defsubr (&Sx_display_save_under);
+#if 0 /* MAC_TODO: implement XParseGeometry */
+ defsubr (&Sx_parse_geometry);
+#endif
+ defsubr (&Sx_create_frame);
+#if 0 /* MAC_TODO: implement network support */
+ defsubr (&Sx_open_connection);
+ defsubr (&Sx_close_connection);
+#endif
+ defsubr (&Sx_display_list);
+ defsubr (&Sx_synchronize);
+
+ /* Setting callback functions for fontset handler. */
+ get_font_info_func = x_get_font_info;
+
+#if 0 /* This function pointer doesn't seem to be used anywhere.
+ And the pointer assigned has the wrong type, anyway. */
+ list_fonts_func = x_list_fonts;
+#endif
+
+ load_font_func = x_load_font;
+ find_ccl_program_func = x_find_ccl_program;
+ query_font_func = x_query_font;
+
+ set_frame_fontset_func = x_set_font;
+ check_window_system_func = check_mac;
+
+#if 0 /* MAC_TODO: Image support for Mac Images. */
+ Qxbm = intern ("xbm");
+ staticpro (&Qxbm);
+ QCtype = intern (":type");
+ staticpro (&QCtype);
+ QCconversion = intern (":conversion");
+ staticpro (&QCconversion);
+ QCheuristic_mask = intern (":heuristic-mask");
+ staticpro (&QCheuristic_mask);
+ QCcolor_symbols = intern (":color-symbols");
+ staticpro (&QCcolor_symbols);
+ QCascent = intern (":ascent");
+ staticpro (&QCascent);
+ QCmargin = intern (":margin");
+ staticpro (&QCmargin);
+ QCrelief = intern (":relief");
+ staticpro (&QCrelief);
+ Qpostscript = intern ("postscript");
+ staticpro (&Qpostscript);
+ QCloader = intern (":loader");
+ staticpro (&QCloader);
+ QCbounding_box = intern (":bounding-box");
+ staticpro (&QCbounding_box);
+ QCpt_width = intern (":pt-width");
+ staticpro (&QCpt_width);
+ QCpt_height = intern (":pt-height");
+ staticpro (&QCpt_height);
+ QCindex = intern (":index");
+ staticpro (&QCindex);
+ Qpbm = intern ("pbm");
+ staticpro (&Qpbm);
+
+#if HAVE_XPM
+ Qxpm = intern ("xpm");
+ staticpro (&Qxpm);
+#endif
+
+#if HAVE_JPEG
+ Qjpeg = intern ("jpeg");
+ staticpro (&Qjpeg);
+#endif
+
+#if HAVE_TIFF
+ Qtiff = intern ("tiff");
+ staticpro (&Qtiff);
+#endif
+
+#if HAVE_GIF
+ Qgif = intern ("gif");
+ staticpro (&Qgif);
+#endif
+
+#if HAVE_PNG
+ Qpng = intern ("png");
+ staticpro (&Qpng);
+#endif
+
+ defsubr (&Sclear_image_cache);
+
+#if GLYPH_DEBUG
+ defsubr (&Simagep);
+ defsubr (&Slookup_image);
+#endif
+#endif /* MAC_TODO */
+
+ hourglass_atimer = NULL;
+ hourglass_shown_p = 0;
+
+ defsubr (&Sx_show_tip);
+ defsubr (&Sx_hide_tip);
+ staticpro (&tip_timer);
+ tip_timer = Qnil;
+
+#if 0 /* MAC_TODO */
+ defsubr (&Sx_file_dialog);
+#endif
+}
+
+
+void
+init_xfns ()
+{
+ image_types = NULL;
+ Vimage_types = Qnil;
+
+ define_image_type (&xbm_type);
+#if 0 /* NTEMACS_TODO : Image support for W32 */
+ define_image_type (&gs_type);
+ define_image_type (&pbm_type);
+
+#if HAVE_XPM
+ define_image_type (&xpm_type);
+#endif
+
+#if HAVE_JPEG
+ define_image_type (&jpeg_type);
+#endif
+
+#if HAVE_TIFF
+ define_image_type (&tiff_type);
+#endif
+
+#if HAVE_GIF
+ define_image_type (&gif_type);
+#endif
+
+#if HAVE_PNG
+ define_image_type (&png_type);
+#endif
+#endif /* NTEMACS_TODO */
+}
diff --git a/src/macgui.h b/src/macgui.h
new file mode 100644
index 00000000000..a6ad18fddcf
--- /dev/null
+++ b/src/macgui.h
@@ -0,0 +1,157 @@
+/* Definitions and headers for communication on the Mac OS.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#ifndef EMACS_MACGUI_H
+#define EMACS_MACGUI_H
+
+typedef int Pixmap;
+typedef int Bitmap;
+
+typedef int Display; /* fix later */
+
+typedef unsigned long Time;
+
+#if MAC_OSX
+typedef struct OpaqueWindowPtr* Window;
+#else
+#include <QuickDraw.h>
+typedef WindowPtr Window;
+#endif
+
+#define FACE_DEFAULT (~0)
+
+
+/* Emulate XCharStruct. */
+typedef struct _XCharStruct
+{
+ int rbearing;
+ int lbearing;
+ int width;
+ int ascent;
+ int descent;
+} XCharStruct;
+
+struct MacFontStruct {
+ char *fontname;
+
+ short mac_fontnum; /* font number of font used in this window */
+ int mac_fontsize; /* size of font */
+ short mac_fontface; /* plain, bold, italics, etc. */
+ short mac_scriptcode; /* Mac OS script code for font used */
+
+#if 0
+ SInt16 mFontNum; /* font number of font used in this window */
+ short mScriptCode; /* Mac OS script code for font used */
+ int mFontSize; /* size of font */
+ Style mFontFace; /* plain, bold, italics, etc. */
+ int mHeight; /* height of one line of text in pixels */
+ int mWidth; /* width of one character in pixels */
+ int mAscent;
+ int mDescent;
+ int mLeading;
+ char mTwoByte; /* true for two-byte font */
+#endif /* 0 */
+
+/* from Xlib.h */
+#if 0
+ XExtData *ext_data; /* hook for extension to hang data */
+ Font fid; /* Font id for this font */
+ unsigned direction; /* hint about the direction font is painted */
+#endif /* 0 */
+ unsigned min_char_or_byte2;/* first character */
+ unsigned max_char_or_byte2;/* last character */
+ unsigned min_byte1; /* first row that exists */
+ unsigned max_byte1; /* last row that exists */
+#if 0
+ Bool all_chars_exist; /* flag if all characters have nonzero size */
+ unsigned default_char; /* char to print for undefined character */
+ int n_properties; /* how many properties there are */
+ XFontProp *properties; /* pointer to array of additional properties */
+#endif /* 0 */
+ XCharStruct min_bounds; /* minimum bounds over all existing char */
+ XCharStruct max_bounds; /* maximum bounds over all existing char */
+ XCharStruct *per_char; /* first_char to last_char information */
+ int ascent; /* logical extent above baseline for spacing */
+ int descent; /* logical decent below baseline for spacing */
+};
+
+typedef struct MacFontStruct MacFontStruct;
+typedef struct MacFontStruct XFontStruct;
+
+
+/* Emulate X GC's by keeping color and font info in a structure. */
+typedef struct _XGCValues
+{
+ unsigned long foreground;
+ unsigned long background;
+ XFontStruct *font;
+} XGCValues;
+
+typedef XGCValues *GC;
+
+extern XGCValues *
+XCreateGC (void *, Window, unsigned long, XGCValues *);
+
+#define GCForeground 0x01
+#define GCBackground 0x02
+#define GCFont 0x03
+#define GCGraphicsExposures 0
+
+/* Bit Gravity */
+
+#define ForgetGravity 0
+#define NorthWestGravity 1
+#define NorthGravity 2
+#define NorthEastGravity 3
+#define WestGravity 4
+#define CenterGravity 5
+#define EastGravity 6
+#define SouthWestGravity 7
+#define SouthGravity 8
+#define SouthEastGravity 9
+#define StaticGravity 10
+
+#define NoValue 0x0000
+#define XValue 0x0001
+#define YValue 0x0002
+#define WidthValue 0x0004
+#define HeightValue 0x0008
+#define AllValues 0x000F
+#define XNegative 0x0010
+#define YNegative 0x0020
+
+#define USPosition (1L << 0) /* user specified x, y */
+#define USSize (1L << 1) /* user specified width, height */
+
+#define PPosition (1L << 2) /* program specified position */
+#define PSize (1L << 3) /* program specified size */
+#define PMinSize (1L << 4) /* program specified minimum size */
+#define PMaxSize (1L << 5) /* program specified maximum size */
+#define PResizeInc (1L << 6) /* program specified resize increments */
+#define PAspect (1L << 7) /* program specified min and max aspect ratios */
+#define PBaseSize (1L << 8) /* program specified base for incrementing */
+#define PWinGravity (1L << 9) /* program specified window gravity */
+
+extern int XParseGeometry ();
+
+#endif /* EMACS_MACGUI_H */
+
diff --git a/src/macmenu.c b/src/macmenu.c
new file mode 100644
index 00000000000..f9498cda67d
--- /dev/null
+++ b/src/macmenu.c
@@ -0,0 +1,2346 @@
+/* Menu support for GNU Emacs on the for Mac OS.
+ Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#include <config.h>
+#include <signal.h>
+
+#include <stdio.h>
+#include "lisp.h"
+#include "termhooks.h"
+#include "keyboard.h"
+#include "keymap.h"
+#include "frame.h"
+#include "window.h"
+#include "blockinput.h"
+#include "buffer.h"
+#include "charset.h"
+#include "coding.h"
+
+#ifdef MAC_OSX
+#undef mktime
+#undef DEBUG
+#undef Z
+#undef free
+#undef malloc
+#undef realloc
+/* Macros max and min defined in lisp.h conflict with those in
+ precompiled header Carbon.h. */
+#undef max
+#undef min
+#include <Carbon/Carbon.h>
+#undef Z
+#define Z (current_buffer->text->z)
+#undef free
+#define free unexec_free
+#undef malloc
+#define malloc unexec_malloc
+#undef realloc
+#define realloc unexec_realloc
+#undef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#undef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#else /* not MAC_OSX */
+#include <MacTypes.h>
+#include <Menus.h>
+#include <QuickDraw.h>
+#include <ToolUtils.h>
+#include <Fonts.h>
+#include <Controls.h>
+#include <Windows.h>
+#include <Events.h>
+#if defined (__MRC__) || (__MSL__ >= 0x6000)
+#include <ControlDefinitions.h>
+#endif
+#endif /* not MAC_OSX */
+
+/* This may include sys/types.h, and that somehow loses
+ if this is not done before the other system files. */
+#include "macterm.h"
+
+/* Load sys/types.h if not already loaded.
+ In some systems loading it twice is suicidal. */
+#ifndef makedev
+#include <sys/types.h>
+#endif
+
+#include "dispextern.h"
+
+#define POPUP_SUBMENU_ID 235
+#define MIN_MENU_ID 256
+#define MIN_SUBMENU_ID 1
+
+#define DIALOG_WINDOW_RESOURCE 130
+
+#define HAVE_DIALOGS 1
+
+#undef HAVE_MULTILINGUAL_MENU
+#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
+
+/******************************************************************/
+/* Definitions copied from lwlib.h */
+
+typedef void * XtPointer;
+
+enum button_type
+{
+ BUTTON_TYPE_NONE,
+ BUTTON_TYPE_TOGGLE,
+ BUTTON_TYPE_RADIO
+};
+
+/* This structure is based on the one in ../lwlib/lwlib.h, modified
+ for Mac OS. */
+typedef struct _widget_value
+{
+ /* name of widget */
+ char* name;
+ /* value (meaning depend on widget type) */
+ char* value;
+ /* keyboard equivalent. no implications for XtTranslations */
+ char* key;
+ /* Help string or nil if none.
+ GC finds this string through the frame's menu_bar_vector
+ or through menu_items. */
+ Lisp_Object help;
+ /* true if enabled */
+ Boolean enabled;
+ /* true if selected */
+ Boolean selected;
+ /* The type of a button. */
+ enum button_type button_type;
+ /* true if menu title */
+ Boolean title;
+#if 0
+ /* true if was edited (maintained by get_value) */
+ Boolean edited;
+ /* true if has changed (maintained by lw library) */
+ change_type change;
+ /* true if this widget itself has changed,
+ but not counting the other widgets found in the `next' field. */
+ change_type this_one_change;
+#endif
+ /* Contents of the sub-widgets, also selected slot for checkbox */
+ struct _widget_value* contents;
+ /* data passed to callback */
+ XtPointer call_data;
+ /* next one in the list */
+ struct _widget_value* next;
+#if 0
+ /* slot for the toolkit dependent part. Always initialize to NULL. */
+ void* toolkit_data;
+ /* tell us if we should free the toolkit data slot when freeing the
+ widget_value itself. */
+ Boolean free_toolkit_data;
+
+ /* we resource the widget_value structures; this points to the next
+ one on the free list if this one has been deallocated.
+ */
+ struct _widget_value *free_list;
+#endif
+} widget_value;
+
+/* Assumed by other routines to zero area returned. */
+#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
+ 0, (sizeof (widget_value)))
+#define free_widget_value(wv) xfree (wv)
+
+/******************************************************************/
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif /* no TRUE */
+
+Lisp_Object Vmenu_updating_frame;
+
+Lisp_Object Qdebug_on_next_call;
+
+extern Lisp_Object Qmenu_bar;
+extern Lisp_Object Qmouse_click, Qevent_kind;
+
+extern Lisp_Object QCtoggle, QCradio;
+
+extern Lisp_Object Voverriding_local_map;
+extern Lisp_Object Voverriding_local_map_menu_flag;
+
+extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
+
+extern Lisp_Object Qmenu_bar_update_hook;
+
+void set_frame_menubar ();
+
+static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+ Lisp_Object, Lisp_Object, Lisp_Object,
+ Lisp_Object, Lisp_Object));
+#ifdef HAVE_DIALOGS
+static Lisp_Object mac_dialog_show ();
+#endif
+static Lisp_Object mac_menu_show ();
+
+static void keymap_panes ();
+static void single_keymap_panes ();
+static void single_menu_item ();
+static void list_of_panes ();
+static void list_of_items ();
+
+static void fill_submenu (MenuHandle, widget_value *, int);
+static void fill_menubar (widget_value *);
+
+
+/* This holds a Lisp vector that holds the results of decoding
+ the keymaps or alist-of-alists that specify a menu.
+
+ It describes the panes and items within the panes.
+
+ Each pane is described by 3 elements in the vector:
+ t, the pane name, the pane's prefix key.
+ Then follow the pane's items, with 5 elements per item:
+ the item string, the enable flag, the item's value,
+ the definition, and the equivalent keyboard key's description string.
+
+ In some cases, multiple levels of menus may be described.
+ A single vector slot containing nil indicates the start of a submenu.
+ A single vector slot containing lambda indicates the end of a submenu.
+ The submenu follows a menu item which is the way to reach the submenu.
+
+ A single vector slot containing quote indicates that the
+ following items should appear on the right of a dialog box.
+
+ Using a Lisp vector to hold this information while we decode it
+ takes care of protecting all the data from GC. */
+
+#define MENU_ITEMS_PANE_NAME 1
+#define MENU_ITEMS_PANE_PREFIX 2
+#define MENU_ITEMS_PANE_LENGTH 3
+
+enum menu_item_idx
+{
+ MENU_ITEMS_ITEM_NAME = 0,
+ MENU_ITEMS_ITEM_ENABLE,
+ MENU_ITEMS_ITEM_VALUE,
+ MENU_ITEMS_ITEM_EQUIV_KEY,
+ MENU_ITEMS_ITEM_DEFINITION,
+ MENU_ITEMS_ITEM_TYPE,
+ MENU_ITEMS_ITEM_SELECTED,
+ MENU_ITEMS_ITEM_HELP,
+ MENU_ITEMS_ITEM_LENGTH
+};
+
+static Lisp_Object menu_items;
+
+/* Number of slots currently allocated in menu_items. */
+static int menu_items_allocated;
+
+/* This is the index in menu_items of the first empty slot. */
+static int menu_items_used;
+
+/* The number of panes currently recorded in menu_items,
+ excluding those within submenus. */
+static int menu_items_n_panes;
+
+/* Current depth within submenus. */
+static int menu_items_submenu_depth;
+
+/* Flag which when set indicates a dialog or menu has been posted by
+ Xt on behalf of one of the widget sets. */
+static int popup_activated_flag;
+
+static int next_menubar_widget_id;
+
+/* This is set nonzero after the user activates the menu bar, and set
+ to zero again after the menu bars are redisplayed by prepare_menu_bar.
+ While it is nonzero, all calls to set_frame_menubar go deep.
+
+ I don't understand why this is needed, but it does seem to be
+ needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
+
+int pending_menu_activation;
+
+/* Initialize the menu_items structure if we haven't already done so.
+ Also mark it as currently empty. */
+
+static void
+init_menu_items ()
+{
+ if (NILP (menu_items))
+ {
+ menu_items_allocated = 60;
+ menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
+ }
+
+ menu_items_used = 0;
+ menu_items_n_panes = 0;
+ menu_items_submenu_depth = 0;
+}
+
+/* Call at the end of generating the data in menu_items.
+ This fills in the number of items in the last pane. */
+
+static void
+finish_menu_items ()
+{
+}
+
+/* Call when finished using the data for the current menu
+ in menu_items. */
+
+static void
+discard_menu_items ()
+{
+ /* Free the structure if it is especially large.
+ Otherwise, hold on to it, to save time. */
+ if (menu_items_allocated > 200)
+ {
+ menu_items = Qnil;
+ menu_items_allocated = 0;
+ }
+}
+
+/* Make the menu_items vector twice as large. */
+
+static void
+grow_menu_items ()
+{
+ Lisp_Object old;
+ int old_size = menu_items_allocated;
+ old = menu_items;
+
+ menu_items_allocated *= 2;
+ menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
+ bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
+ old_size * sizeof (Lisp_Object));
+}
+
+/* Begin a submenu. */
+
+static void
+push_submenu_start ()
+{
+ if (menu_items_used + 1 > menu_items_allocated)
+ grow_menu_items ();
+
+ XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
+ menu_items_submenu_depth++;
+}
+
+/* End a submenu. */
+
+static void
+push_submenu_end ()
+{
+ if (menu_items_used + 1 > menu_items_allocated)
+ grow_menu_items ();
+
+ XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
+ menu_items_submenu_depth--;
+}
+
+/* Indicate boundary between left and right. */
+
+static void
+push_left_right_boundary ()
+{
+ if (menu_items_used + 1 > menu_items_allocated)
+ grow_menu_items ();
+
+ XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
+}
+
+/* Start a new menu pane in menu_items.
+ NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
+
+static void
+push_menu_pane (name, prefix_vec)
+ Lisp_Object name, prefix_vec;
+{
+ if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
+ grow_menu_items ();
+
+ if (menu_items_submenu_depth == 0)
+ menu_items_n_panes++;
+ XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
+ XVECTOR (menu_items)->contents[menu_items_used++] = name;
+ XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
+}
+
+/* Push one menu item into the current pane. NAME is the string to
+ display. ENABLE if non-nil means this item can be selected. KEY
+ is the key generated by choosing this item, or nil if this item
+ doesn't really have a definition. DEF is the definition of this
+ item. EQUIV is the textual description of the keyboard equivalent
+ for this item (or nil if none). TYPE is the type of this menu
+ item, one of nil, `toggle' or `radio'. */
+
+static void
+push_menu_item (name, enable, key, def, equiv, type, selected, help)
+ Lisp_Object name, enable, key, def, equiv, type, selected, help;
+{
+ if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
+ grow_menu_items ();
+
+ XVECTOR (menu_items)->contents[menu_items_used++] = name;
+ XVECTOR (menu_items)->contents[menu_items_used++] = enable;
+ XVECTOR (menu_items)->contents[menu_items_used++] = key;
+ XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
+ XVECTOR (menu_items)->contents[menu_items_used++] = def;
+ XVECTOR (menu_items)->contents[menu_items_used++] = type;
+ XVECTOR (menu_items)->contents[menu_items_used++] = selected;
+ XVECTOR (menu_items)->contents[menu_items_used++] = help;
+}
+
+/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
+ and generate menu panes for them in menu_items.
+ If NOTREAL is nonzero,
+ don't bother really computing whether an item is enabled. */
+
+static void
+keymap_panes (keymaps, nmaps, notreal)
+ Lisp_Object *keymaps;
+ int nmaps;
+ int notreal;
+{
+ int mapno;
+
+ init_menu_items ();
+
+ /* Loop over the given keymaps, making a pane for each map.
+ But don't make a pane that is empty--ignore that map instead.
+ P is the number of panes we have made so far. */
+ for (mapno = 0; mapno < nmaps; mapno++)
+ single_keymap_panes (keymaps[mapno],
+ Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
+
+ finish_menu_items ();
+}
+
+/* This is a recursive subroutine of keymap_panes.
+ It handles one keymap, KEYMAP.
+ The other arguments are passed along
+ or point to local variables of the previous function.
+ If NOTREAL is nonzero, only check for equivalent key bindings, don't
+ evaluate expressions in menu items and don't make any menu.
+
+ If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
+
+static void
+single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
+ Lisp_Object keymap;
+ Lisp_Object pane_name;
+ Lisp_Object prefix;
+ int notreal;
+ int maxdepth;
+{
+ Lisp_Object pending_maps = Qnil;
+ Lisp_Object tail, item;
+ struct gcpro gcpro1, gcpro2;
+
+ if (maxdepth <= 0)
+ return;
+
+ push_menu_pane (pane_name, prefix);
+
+ for (tail = keymap; CONSP (tail); tail = XCDR (tail))
+ {
+ GCPRO2 (keymap, pending_maps);
+ /* Look at each key binding, and if it is a menu item add it
+ to this menu. */
+ item = XCAR (tail);
+ if (CONSP (item))
+ single_menu_item (XCAR (item), XCDR (item),
+ &pending_maps, notreal, maxdepth);
+ else if (VECTORP (item))
+ {
+ /* Loop over the char values represented in the vector. */
+ int len = XVECTOR (item)->size;
+ int c;
+ for (c = 0; c < len; c++)
+ {
+ Lisp_Object character;
+ XSETFASTINT (character, c);
+ single_menu_item (character, XVECTOR (item)->contents[c],
+ &pending_maps, notreal, maxdepth);
+ }
+ }
+ UNGCPRO;
+ }
+
+ /* Process now any submenus which want to be panes at this level. */
+ while (!NILP (pending_maps))
+ {
+ Lisp_Object elt, eltcdr, string;
+ elt = Fcar (pending_maps);
+ eltcdr = XCDR (elt);
+ string = XCAR (eltcdr);
+ /* We no longer discard the @ from the beginning of the string here.
+ Instead, we do this in mac_menu_show. */
+ single_keymap_panes (Fcar (elt), string,
+ XCDR (eltcdr), notreal, maxdepth - 1);
+ pending_maps = Fcdr (pending_maps);
+ }
+}
+
+/* This is a subroutine of single_keymap_panes that handles one
+ keymap entry.
+ KEY is a key in a keymap and ITEM is its binding.
+ PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
+ separate panes.
+ If NOTREAL is nonzero, only check for equivalent key bindings, don't
+ evaluate expressions in menu items and don't make any menu.
+ If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
+
+static void
+single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
+ Lisp_Object key, item;
+ Lisp_Object *pending_maps_ptr;
+ int maxdepth, notreal;
+{
+ Lisp_Object map, item_string, enabled;
+ struct gcpro gcpro1, gcpro2;
+ int res;
+
+ /* Parse the menu item and leave the result in item_properties. */
+ GCPRO2 (key, item);
+ res = parse_menu_item (item, notreal, 0);
+ UNGCPRO;
+ if (!res)
+ return; /* Not a menu item. */
+
+ map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
+
+ if (notreal)
+ {
+ /* We don't want to make a menu, just traverse the keymaps to
+ precompute equivalent key bindings. */
+ if (!NILP (map))
+ single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
+ return;
+ }
+
+ enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
+ item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+
+ if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
+ {
+ if (!NILP (enabled))
+ /* An enabled separate pane. Remember this to handle it later. */
+ *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
+ *pending_maps_ptr);
+ return;
+ }
+
+ push_menu_item (item_string, enabled, key,
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
+
+ /* Display a submenu using the toolkit. */
+ if (! (NILP (map) || NILP (enabled)))
+ {
+ push_submenu_start ();
+ single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
+ push_submenu_end ();
+ }
+}
+
+/* Push all the panes and items of a menu described by the
+ alist-of-alists MENU.
+ This handles old-fashioned calls to x-popup-menu. */
+
+static void
+list_of_panes (menu)
+ Lisp_Object menu;
+{
+ Lisp_Object tail;
+
+ init_menu_items ();
+
+ for (tail = menu; !NILP (tail); tail = Fcdr (tail))
+ {
+ Lisp_Object elt, pane_name, pane_data;
+ elt = Fcar (tail);
+ pane_name = Fcar (elt);
+ CHECK_STRING (pane_name);
+ push_menu_pane (pane_name, Qnil);
+ pane_data = Fcdr (elt);
+ CHECK_CONS (pane_data);
+ list_of_items (pane_data);
+ }
+
+ finish_menu_items ();
+}
+
+/* Push the items in a single pane defined by the alist PANE. */
+
+static void
+list_of_items (pane)
+ Lisp_Object pane;
+{
+ Lisp_Object tail, item, item1;
+
+ for (tail = pane; !NILP (tail); tail = Fcdr (tail))
+ {
+ item = Fcar (tail);
+ if (STRINGP (item))
+ push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
+ else if (NILP (item))
+ push_left_right_boundary ();
+ else
+ {
+ CHECK_CONS (item);
+ item1 = Fcar (item);
+ CHECK_STRING (item1);
+ push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
+ }
+ }
+}
+
+DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
+ doc: /* Pop up a deck-of-cards menu and return user's selection.
+POSITION is a position specification. This is either a mouse button
+event or a list ((XOFFSET YOFFSET) WINDOW) where XOFFSET and YOFFSET
+are positions in pixels from the top left corner of WINDOW's frame
+\(WINDOW may be a frame object instead of a window). This controls the
+position of the center of the first line in the first pane of the
+menu, not the top left of the menu as a whole. If POSITION is t, it
+means to use the current mouse position.
+
+MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
+The menu items come from key bindings that have a menu string as well as
+a definition; actually, the \"definition\" in such a key binding looks like
+\(STRING . REAL-DEFINITION). To give the menu a title, put a string into
+the keymap as a top-level element.
+
+If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
+Otherwise, REAL-DEFINITION should be a valid key binding definition.
+
+You can also use a list of keymaps as MENU. Then each keymap makes a
+separate pane. When MENU is a keymap or a list of keymaps, the return
+value is a list of events.
+
+Alternatively, you can specify a menu of multiple panes with a list of
+the form (TITLE PANE1 PANE2...), where each pane is a list of
+form (TITLE ITEM1 ITEM2...).
+Each ITEM is normally a cons cell (STRING . VALUE); but a string can
+appear as an item--that makes a nonselectable line in the menu.
+With this form of menu, the return value is VALUE from the chosen item.
+
+If POSITION is nil, don't display the menu at all, just precalculate the
+cached information about equivalent key sequences. */)
+ (position, menu)
+ Lisp_Object position, menu;
+{
+ Lisp_Object keymap, tem;
+ int xpos = 0, ypos = 0;
+ Lisp_Object title;
+ char *error_name;
+ Lisp_Object selection;
+ FRAME_PTR f = NULL;
+ Lisp_Object x, y, window;
+ int keymaps = 0;
+ int for_click = 0;
+ struct gcpro gcpro1;
+
+#ifdef HAVE_MENUS
+ if (! NILP (position))
+ {
+ check_mac ();
+
+ /* Decode the first argument: find the window and the coordinates. */
+ if (EQ (position, Qt)
+ || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+ || EQ (XCAR (position), Qtool_bar))))
+ {
+ /* Use the mouse's current position. */
+ FRAME_PTR new_f = SELECTED_FRAME ();
+ Lisp_Object bar_window;
+ enum scroll_bar_part part;
+ unsigned long time;
+
+ if (mouse_position_hook)
+ (*mouse_position_hook) (&new_f, 1, &bar_window,
+ &part, &x, &y, &time);
+ if (new_f != 0)
+ XSETFRAME (window, new_f);
+ else
+ {
+ window = selected_window;
+ XSETFASTINT (x, 0);
+ XSETFASTINT (y, 0);
+ }
+ }
+ else
+ {
+ tem = Fcar (position);
+ if (CONSP (tem))
+ {
+ window = Fcar (Fcdr (position));
+ x = Fcar (tem);
+ y = Fcar (Fcdr (tem));
+ }
+ else
+ {
+ for_click = 1;
+ tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
+ window = Fcar (tem); /* POSN_WINDOW (tem) */
+ tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
+ x = Fcar (tem);
+ y = Fcdr (tem);
+ }
+ }
+
+ CHECK_NUMBER (x);
+ CHECK_NUMBER (y);
+
+ /* Decode where to put the menu. */
+
+ if (FRAMEP (window))
+ {
+ f = XFRAME (window);
+ xpos = 0;
+ ypos = 0;
+ }
+ else if (WINDOWP (window))
+ {
+ CHECK_LIVE_WINDOW (window);
+ f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+
+ xpos = (FONT_WIDTH (FRAME_FONT (f))
+ * XFASTINT (XWINDOW (window)->left));
+ ypos = (FRAME_LINE_HEIGHT (f)
+ * XFASTINT (XWINDOW (window)->top));
+ }
+ else
+ /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
+ but I don't want to make one now. */
+ CHECK_WINDOW (window);
+
+ xpos += XINT (x);
+ ypos += XINT (y);
+
+ XSETFRAME (Vmenu_updating_frame, f);
+ }
+ Vmenu_updating_frame = Qnil;
+#endif /* HAVE_MENUS */
+
+ title = Qnil;
+ GCPRO1 (title);
+
+ /* Decode the menu items from what was specified. */
+
+ keymap = get_keymap (menu, 0, 0);
+ if (CONSP (keymap))
+ {
+ /* We were given a keymap. Extract menu info from the keymap. */
+ Lisp_Object prompt;
+
+ /* Extract the detailed info to make one pane. */
+ keymap_panes (&menu, 1, NILP (position));
+
+ /* Search for a string appearing directly as an element of the keymap.
+ That string is the title of the menu. */
+ prompt = Fkeymap_prompt (keymap);
+ if (NILP (title) && !NILP (prompt))
+ title = prompt;
+
+ /* Make that be the pane title of the first pane. */
+ if (!NILP (prompt) && menu_items_n_panes >= 0)
+ XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
+
+ keymaps = 1;
+ }
+ else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
+ {
+ /* We were given a list of keymaps. */
+ int nmaps = XFASTINT (Flength (menu));
+ Lisp_Object *maps
+ = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
+ int i;
+
+ title = Qnil;
+
+ /* The first keymap that has a prompt string
+ supplies the menu title. */
+ for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
+ {
+ Lisp_Object prompt;
+
+ maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
+
+ prompt = Fkeymap_prompt (keymap);
+ if (NILP (title) && !NILP (prompt))
+ title = prompt;
+ }
+
+ /* Extract the detailed info to make one pane. */
+ keymap_panes (maps, nmaps, NILP (position));
+
+ /* Make the title be the pane title of the first pane. */
+ if (!NILP (title) && menu_items_n_panes >= 0)
+ XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
+
+ keymaps = 1;
+ }
+ else
+ {
+ /* We were given an old-fashioned menu. */
+ title = Fcar (menu);
+ CHECK_STRING (title);
+
+ list_of_panes (Fcdr (menu));
+
+ keymaps = 0;
+ }
+
+ if (NILP (position))
+ {
+ discard_menu_items ();
+ UNGCPRO;
+ return Qnil;
+ }
+
+#ifdef HAVE_MENUS
+ /* Display them in a menu. */
+ BLOCK_INPUT;
+
+ selection = mac_menu_show (f, xpos, ypos, for_click,
+ keymaps, title, &error_name);
+ UNBLOCK_INPUT;
+
+ discard_menu_items ();
+
+ UNGCPRO;
+#endif /* HAVE_MENUS */
+
+ if (error_name) error (error_name);
+ return selection;
+}
+
+#ifdef HAVE_MENUS
+
+DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
+ doc: /* Pop up a dialog box and return user's selection.
+POSITION specifies which frame to use.
+This is normally a mouse button event or a window or frame.
+If POSITION is t, it means to use the frame the mouse is on.
+The dialog box appears in the middle of the specified frame.
+
+CONTENTS specifies the alternatives to display in the dialog box.
+It is a list of the form (TITLE ITEM1 ITEM2...).
+Each ITEM is a cons cell (STRING . VALUE).
+The return value is VALUE from the chosen item.
+
+An ITEM may also be just a string--that makes a nonselectable item.
+An ITEM may also be nil--that means to put all preceding items
+on the left of the dialog box and all following items on the right.
+\(By default, approximately half appear on each side.) */)
+ (position, contents)
+ Lisp_Object position, contents;
+{
+ FRAME_PTR f = NULL;
+ Lisp_Object window;
+
+ check_mac ();
+
+ /* Decode the first argument: find the window or frame to use. */
+ if (EQ (position, Qt)
+ || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+ || EQ (XCAR (position), Qtool_bar))))
+ {
+#if 0 /* Using the frame the mouse is on may not be right. */
+ /* Use the mouse's current position. */
+ FRAME_PTR new_f = SELECTED_FRAME ();
+ Lisp_Object bar_window;
+ enum scroll_bar_part part;
+ unsigned long time;
+ Lisp_Object x, y;
+
+ (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
+
+ if (new_f != 0)
+ XSETFRAME (window, new_f);
+ else
+ window = selected_window;
+#endif
+ window = selected_window;
+ }
+ else if (CONSP (position))
+ {
+ Lisp_Object tem;
+ tem = Fcar (position);
+ if (CONSP (tem))
+ window = Fcar (Fcdr (position));
+ else
+ {
+ tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
+ window = Fcar (tem); /* POSN_WINDOW (tem) */
+ }
+ }
+ else if (WINDOWP (position) || FRAMEP (position))
+ window = position;
+ else
+ window = Qnil;
+
+ /* Decode where to put the menu. */
+
+ if (FRAMEP (window))
+ f = XFRAME (window);
+ else if (WINDOWP (window))
+ {
+ CHECK_LIVE_WINDOW (window);
+ f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+ }
+ else
+ /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
+ but I don't want to make one now. */
+ CHECK_WINDOW (window);
+
+#ifndef HAVE_DIALOGS
+ /* Display a menu with these alternatives
+ in the middle of frame F. */
+ {
+ Lisp_Object x, y, frame, newpos;
+ XSETFRAME (frame, f);
+ XSETINT (x, x_pixel_width (f) / 2);
+ XSETINT (y, x_pixel_height (f) / 2);
+ newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
+
+ return Fx_popup_menu (newpos,
+ Fcons (Fcar (contents), Fcons (contents, Qnil)));
+ }
+#else /* HAVE_DIALOGS */
+ {
+ Lisp_Object title;
+ char *error_name;
+ Lisp_Object selection;
+
+ /* Decode the dialog items from what was specified. */
+ title = Fcar (contents);
+ CHECK_STRING (title);
+
+ list_of_panes (Fcons (contents, Qnil));
+
+ /* Display them in a dialog box. */
+ BLOCK_INPUT;
+ selection = mac_dialog_show (f, 0, title, &error_name);
+ UNBLOCK_INPUT;
+
+ discard_menu_items ();
+
+ if (error_name) error (error_name);
+ return selection;
+ }
+#endif /* HAVE_DIALOGS */
+}
+
+/* Activate the menu bar of frame F.
+ This is called from keyboard.c when it gets the
+ menu_bar_activate_event out of the Emacs event queue.
+
+ To activate the menu bar, we signal to the input thread that it can
+ return from the WM_INITMENU message, allowing the normal Windows
+ processing of the menus.
+
+ But first we recompute the menu bar contents (the whole tree).
+
+ This way we can safely execute Lisp code. */
+
+void
+x_activate_menubar (f)
+ FRAME_PTR f;
+{
+ SInt32 menu_choice;
+ extern Point saved_menu_event_location;
+
+ set_frame_menubar (f, 0, 1);
+ BLOCK_INPUT;
+
+ menu_choice = MenuSelect (saved_menu_event_location);
+ do_menu_choice (menu_choice);
+
+ UNBLOCK_INPUT;
+}
+
+/* This callback is called from the menu bar pulldown menu
+ when the user makes a selection.
+ Figure out what the user chose
+ and put the appropriate events into the keyboard buffer. */
+
+void
+menubar_selection_callback (FRAME_PTR f, int client_data)
+{
+ Lisp_Object prefix, entry;
+ Lisp_Object vector;
+ Lisp_Object *subprefix_stack;
+ int submenu_depth = 0;
+ int i;
+
+ if (!f)
+ return;
+ entry = Qnil;
+ subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
+ vector = f->menu_bar_vector;
+ prefix = Qnil;
+ i = 0;
+ while (i < f->menu_bar_items_used)
+ {
+ if (EQ (XVECTOR (vector)->contents[i], Qnil))
+ {
+ subprefix_stack[submenu_depth++] = prefix;
+ prefix = entry;
+ i++;
+ }
+ else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
+ {
+ prefix = subprefix_stack[--submenu_depth];
+ i++;
+ }
+ else if (EQ (XVECTOR (vector)->contents[i], Qt))
+ {
+ prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
+ /* The EMACS_INT cast avoids a warning. There's no problem
+ as long as pointers have enough bits to hold small integers. */
+ if ((int) (EMACS_INT) client_data == i)
+ {
+ int j;
+ struct input_event buf;
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = frame;
+ kbd_buffer_store_event (&buf);
+
+ for (j = 0; j < submenu_depth; j++)
+ if (!NILP (subprefix_stack[j]))
+ {
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = subprefix_stack[j];
+ kbd_buffer_store_event (&buf);
+ }
+
+ if (!NILP (prefix))
+ {
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = prefix;
+ kbd_buffer_store_event (&buf);
+ }
+
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = entry;
+ kbd_buffer_store_event (&buf);
+
+ f->output_data.mac->menu_command_in_progress = 0;
+ f->output_data.mac->menubar_active = 0;
+ return;
+ }
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+ f->output_data.mac->menu_command_in_progress = 0;
+ f->output_data.mac->menubar_active = 0;
+}
+
+/* Allocate a widget_value, blocking input. */
+
+widget_value *
+xmalloc_widget_value ()
+{
+ widget_value *value;
+
+ BLOCK_INPUT;
+ value = malloc_widget_value ();
+ UNBLOCK_INPUT;
+
+ return value;
+}
+
+/* This recursively calls free_widget_value on the tree of widgets.
+ It must free all data that was malloc'ed for these widget_values.
+ In Emacs, many slots are pointers into the data of Lisp_Strings, and
+ must be left alone. */
+
+void
+free_menubar_widget_value_tree (wv)
+ widget_value *wv;
+{
+ if (! wv) return;
+
+ wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
+
+ if (wv->contents && (wv->contents != (widget_value*)1))
+ {
+ free_menubar_widget_value_tree (wv->contents);
+ wv->contents = (widget_value *) 0xDEADBEEF;
+ }
+ if (wv->next)
+ {
+ free_menubar_widget_value_tree (wv->next);
+ wv->next = (widget_value *) 0xDEADBEEF;
+ }
+ BLOCK_INPUT;
+ free_widget_value (wv);
+ UNBLOCK_INPUT;
+}
+
+/* Return a tree of widget_value structures for a menu bar item
+ whose event type is ITEM_KEY (with string ITEM_NAME)
+ and whose contents come from the list of keymaps MAPS. */
+
+static widget_value *
+single_submenu (item_key, item_name, maps)
+ Lisp_Object item_key, item_name, maps;
+{
+ widget_value *wv, *prev_wv, *save_wv, *first_wv;
+ int i;
+ int submenu_depth = 0;
+ Lisp_Object length;
+ int len;
+ Lisp_Object *mapvec;
+ widget_value **submenu_stack;
+ int previous_items = menu_items_used;
+ int top_level_items = 0;
+
+ length = Flength (maps);
+ len = XINT (length);
+
+ /* Convert the list MAPS into a vector MAPVEC. */
+ mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+ for (i = 0; i < len; i++)
+ {
+ mapvec[i] = Fcar (maps);
+ maps = Fcdr (maps);
+ }
+
+ menu_items_n_panes = 0;
+
+ /* Loop over the given keymaps, making a pane for each map.
+ But don't make a pane that is empty--ignore that map instead. */
+ for (i = 0; i < len; i++)
+ {
+ if (SYMBOLP (mapvec[i])
+ || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
+ {
+ /* Here we have a command at top level in the menu bar
+ as opposed to a submenu. */
+ top_level_items = 1;
+ push_menu_pane (Qnil, Qnil);
+ push_menu_item (item_name, Qt, item_key, mapvec[i],
+ Qnil, Qnil, Qnil, Qnil);
+ }
+ else
+ single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
+ }
+
+ /* Create a tree of widget_value objects
+ representing the panes and their items. */
+
+ submenu_stack
+ = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
+ wv = xmalloc_widget_value ();
+ wv->name = "menu";
+ wv->value = 0;
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
+ first_wv = wv;
+ save_wv = 0;
+ prev_wv = 0;
+
+ /* Loop over all panes and items made during this call
+ and construct a tree of widget_value objects.
+ Ignore the panes and items made by previous calls to
+ single_submenu, even though those are also in menu_items. */
+ i = previous_items;
+ while (i < menu_items_used)
+ {
+ if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
+ {
+ submenu_stack[submenu_depth++] = save_wv;
+ save_wv = prev_wv;
+ prev_wv = 0;
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
+ {
+ prev_wv = save_wv;
+ save_wv = submenu_stack[--submenu_depth];
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
+ && submenu_depth != 0)
+ i += MENU_ITEMS_PANE_LENGTH;
+ /* Ignore a nil in the item list.
+ It's meaningful only for dialog boxes. */
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+ i += 1;
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+ {
+ /* Create a new pane. */
+ Lisp_Object pane_name, prefix;
+ char *pane_string;
+
+ pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
+ prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+ {
+ pane_name = ENCODE_SYSTEM (pane_name);
+ AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
+ }
+#endif
+ pane_string = (NILP (pane_name)
+ ? "" : (char *) XSTRING (pane_name)->data);
+ /* If there is just one top-level pane, put all its items directly
+ under the top-level menu. */
+ if (menu_items_n_panes == 1)
+ pane_string = "";
+
+ /* If the pane has a meaningful name,
+ make the pane a top-level menu item
+ with its items as a submenu beneath it. */
+ if (strcmp (pane_string, ""))
+ {
+ wv = xmalloc_widget_value ();
+ if (save_wv)
+ save_wv->next = wv;
+ else
+ first_wv->contents = wv;
+ wv->name = pane_string;
+ /* Ignore the @ that means "separate pane".
+ This is a kludge, but this isn't worth more time. */
+ if (!NILP (prefix) && wv->name[0] == '@')
+ wv->name++;
+ wv->value = 0;
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
+ }
+ save_wv = wv;
+ prev_wv = 0;
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ /* Create a new item within current pane. */
+ Lisp_Object item_name, enable, descrip, def, type, selected;
+ Lisp_Object help;
+
+ item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+ enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
+ descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
+ def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
+ type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
+ selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
+ help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
+
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRING_MULTIBYTE (item_name))
+ {
+ item_name = ENCODE_SYSTEM (item_name);
+ AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
+ }
+
+ if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+ {
+ descrip = ENCODE_SYSTEM (descrip);
+ AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
+ }
+#endif /* not HAVE_MULTILINGUAL_MENU */
+
+ wv = xmalloc_widget_value ();
+ if (prev_wv)
+ prev_wv->next = wv;
+ else
+ save_wv->contents = wv;
+
+ wv->name = (char *) XSTRING (item_name)->data;
+ if (!NILP (descrip))
+ wv->key = (char *) XSTRING (descrip)->data;
+ wv->value = 0;
+ /* The EMACS_INT cast avoids a warning. There's no problem
+ as long as pointers have enough bits to hold small integers. */
+ wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
+ wv->enabled = !NILP (enable);
+
+ if (NILP (type))
+ wv->button_type = BUTTON_TYPE_NONE;
+ else if (EQ (type, QCradio))
+ wv->button_type = BUTTON_TYPE_RADIO;
+ else if (EQ (type, QCtoggle))
+ wv->button_type = BUTTON_TYPE_TOGGLE;
+ else
+ abort ();
+
+ wv->selected = !NILP (selected);
+ if (!STRINGP (help))
+ help = Qnil;
+
+ wv->help = help;
+
+ prev_wv = wv;
+
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+
+ /* If we have just one "menu item"
+ that was originally a button, return it by itself. */
+ if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
+ {
+ wv = first_wv->contents;
+ free_widget_value (first_wv);
+ return wv;
+ }
+
+ return first_wv;
+}
+
+/* Set the contents of the menubar widgets of frame F.
+ The argument FIRST_TIME is currently ignored;
+ it is set the first time this is called, from initialize_frame_menubar. */
+
+void
+set_frame_menubar (f, first_time, deep_p)
+ FRAME_PTR f;
+ int first_time;
+ int deep_p;
+{
+ int menubar_widget = f->output_data.mac->menubar_widget;
+ Lisp_Object items;
+ widget_value *wv, *first_wv, *prev_wv = 0;
+ int i;
+
+ /* We must not change the menubar when actually in use. */
+ if (f->output_data.mac->menubar_active)
+ return;
+
+ XSETFRAME (Vmenu_updating_frame, f);
+
+ if (! menubar_widget)
+ deep_p = 1;
+ else if (pending_menu_activation && !deep_p)
+ deep_p = 1;
+
+ wv = xmalloc_widget_value ();
+ wv->name = "menubar";
+ wv->value = 0;
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
+ first_wv = wv;
+
+ if (deep_p)
+ {
+ /* Make a widget-value tree representing the entire menu trees. */
+
+ struct buffer *prev = current_buffer;
+ Lisp_Object buffer;
+ int specpdl_count = specpdl_ptr - specpdl;
+ int previous_menu_items_used = f->menu_bar_items_used;
+ Lisp_Object *previous_items
+ = (Lisp_Object *) alloca (previous_menu_items_used
+ * sizeof (Lisp_Object));
+
+ /* If we are making a new widget, its contents are empty,
+ do always reinitialize them. */
+ if (! menubar_widget)
+ previous_menu_items_used = 0;
+
+ buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
+ specbind (Qinhibit_quit, Qt);
+ /* Don't let the debugger step into this code
+ because it is not reentrant. */
+ specbind (Qdebug_on_next_call, Qnil);
+
+ record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ if (NILP (Voverriding_local_map_menu_flag))
+ {
+ specbind (Qoverriding_terminal_local_map, Qnil);
+ specbind (Qoverriding_local_map, Qnil);
+ }
+
+ set_buffer_internal_1 (XBUFFER (buffer));
+
+ /* Run the Lucid hook. */
+ safe_run_hooks (Qactivate_menubar_hook);
+ /* If it has changed current-menubar from previous value,
+ really recompute the menubar from the value. */
+ if (! NILP (Vlucid_menu_bar_dirty_flag))
+ call0 (Qrecompute_lucid_menubar);
+ safe_run_hooks (Qmenu_bar_update_hook);
+ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+
+ items = FRAME_MENU_BAR_ITEMS (f);
+
+ inhibit_garbage_collection ();
+
+ /* Save the frame's previous menu bar contents data. */
+ if (previous_menu_items_used)
+ bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
+ previous_menu_items_used * sizeof (Lisp_Object));
+
+ /* Fill in the current menu bar contents. */
+ menu_items = f->menu_bar_vector;
+ menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
+ init_menu_items ();
+ for (i = 0; i < XVECTOR (items)->size; i += 4)
+ {
+ Lisp_Object key, string, maps;
+
+ key = XVECTOR (items)->contents[i];
+ string = XVECTOR (items)->contents[i + 1];
+ maps = XVECTOR (items)->contents[i + 2];
+ if (NILP (string))
+ break;
+
+ wv = single_submenu (key, string, maps);
+ if (prev_wv)
+ prev_wv->next = wv;
+ else
+ first_wv->contents = wv;
+ /* Don't set wv->name here; GC during the loop might relocate it. */
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ prev_wv = wv;
+ }
+
+ finish_menu_items ();
+
+ set_buffer_internal_1 (prev);
+ unbind_to (specpdl_count, Qnil);
+
+ /* If there has been no change in the Lisp-level contents
+ of the menu bar, skip redisplaying it. Just exit. */
+
+ for (i = 0; i < previous_menu_items_used; i++)
+ if (menu_items_used == i
+ || (!Fequal (previous_items[i], XVECTOR (menu_items)->contents[i])))
+ break;
+ if (i == menu_items_used && i == previous_menu_items_used && i != 0)
+ {
+ free_menubar_widget_value_tree (first_wv);
+ menu_items = Qnil;
+
+ return;
+ }
+
+ /* Now GC cannot happen during the lifetime of the widget_value,
+ so it's safe to store data from a Lisp_String, as long as
+ local copies are made when the actual menu is created.
+ Windows takes care of this for normal string items, but
+ not for owner-drawn items or additional item-info. */
+ wv = first_wv->contents;
+ for (i = 0; i < XVECTOR (items)->size; i += 4)
+ {
+ Lisp_Object string;
+ string = XVECTOR (items)->contents[i + 1];
+ if (NILP (string))
+ break;
+ wv->name = (char *) XSTRING (string)->data;
+ wv = wv->next;
+ }
+
+ f->menu_bar_vector = menu_items;
+ f->menu_bar_items_used = menu_items_used;
+ menu_items = Qnil;
+ }
+ else
+ {
+ /* Make a widget-value tree containing
+ just the top level menu bar strings. */
+
+ items = FRAME_MENU_BAR_ITEMS (f);
+ for (i = 0; i < XVECTOR (items)->size; i += 4)
+ {
+ Lisp_Object string;
+
+ string = XVECTOR (items)->contents[i + 1];
+ if (NILP (string))
+ break;
+
+ wv = xmalloc_widget_value ();
+ wv->name = (char *) XSTRING (string)->data;
+ wv->value = 0;
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
+ /* This prevents lwlib from assuming this
+ menu item is really supposed to be empty. */
+ /* The EMACS_INT cast avoids a warning.
+ This value just has to be different from small integers. */
+ wv->call_data = (void *) (EMACS_INT) (-1);
+
+ if (prev_wv)
+ prev_wv->next = wv;
+ else
+ first_wv->contents = wv;
+ prev_wv = wv;
+ }
+
+ /* Forget what we thought we knew about what is in the
+ detailed contents of the menu bar menus.
+ Changing the top level always destroys the contents. */
+ f->menu_bar_items_used = 0;
+ }
+
+ /* Create or update the menu bar widget. */
+
+ BLOCK_INPUT;
+
+ /* Non-null value to indicate menubar has already been "created". */
+ f->output_data.mac->menubar_widget = 1;
+
+ {
+ int i = MIN_MENU_ID;
+ MenuHandle menu = GetMenuHandle (i);
+ while (menu != NULL)
+ {
+ DeleteMenu (i);
+ DisposeMenu (menu);
+ menu = GetMenuHandle (++i);
+ }
+
+ i = MIN_SUBMENU_ID;
+ menu = GetMenuHandle (i);
+ while (menu != NULL)
+ {
+ DeleteMenu (i);
+ DisposeMenu (menu);
+ menu = GetMenuHandle (++i);
+ }
+ }
+
+ fill_menubar (first_wv->contents);
+
+ DrawMenuBar ();
+
+ free_menubar_widget_value_tree (first_wv);
+
+ UNBLOCK_INPUT;
+}
+
+/* Called from Fx_create_frame to create the initial menubar of a frame
+ before it is mapped, so that the window is mapped with the menubar already
+ there instead of us tacking it on later and thrashing the window after it
+ is visible. */
+
+void
+initialize_frame_menubar (f)
+ FRAME_PTR f;
+{
+ /* This function is called before the first chance to redisplay
+ the frame. It has to be, so the frame will have the right size. */
+ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+ set_frame_menubar (f, 1, 1);
+}
+
+/* Get rid of the menu bar of frame F, and free its storage.
+ This is used when deleting a frame, and when turning off the menu bar. */
+
+void
+free_frame_menubar (f)
+ FRAME_PTR f;
+{
+ f->output_data.mac->menubar_widget = NULL;
+}
+
+
+/* mac_menu_show actually displays a menu using the panes and items in
+ menu_items and returns the value selected from it; we assume input
+ is blocked by the caller. */
+
+/* F is the frame the menu is for.
+ X and Y are the frame-relative specified position,
+ relative to the inside upper left corner of the frame F.
+ FOR_CLICK is nonzero if this menu was invoked for a mouse click.
+ KEYMAPS is 1 if this menu was specified with keymaps;
+ in that case, we return a list containing the chosen item's value
+ and perhaps also the pane's prefix.
+ TITLE is the specified menu title.
+ ERROR is a place to store an error message string in case of failure.
+ (We return nil on failure, but the value doesn't actually matter.) */
+
+static Lisp_Object
+mac_menu_show (f, x, y, for_click, keymaps, title, error)
+ FRAME_PTR f;
+ int x;
+ int y;
+ int for_click;
+ int keymaps;
+ Lisp_Object title;
+ char **error;
+{
+ int i;
+ int menu_item_selection;
+ MenuHandle menu;
+ Point pos;
+ widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
+ widget_value **submenu_stack
+ = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
+ Lisp_Object *subprefix_stack
+ = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
+ int submenu_depth = 0;
+ int first_pane;
+
+ *error = NULL;
+
+ if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
+ {
+ *error = "Empty menu";
+ return Qnil;
+ }
+
+ /* Create a tree of widget_value objects
+ representing the panes and their items. */
+ wv = xmalloc_widget_value ();
+ wv->name = "menu";
+ wv->value = 0;
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
+ first_wv = wv;
+ first_pane = 1;
+
+ /* Loop over all panes and items, filling in the tree. */
+ i = 0;
+ while (i < menu_items_used)
+ {
+ if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
+ {
+ submenu_stack[submenu_depth++] = save_wv;
+ save_wv = prev_wv;
+ prev_wv = 0;
+ first_pane = 1;
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
+ {
+ prev_wv = save_wv;
+ save_wv = submenu_stack[--submenu_depth];
+ first_pane = 0;
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
+ && submenu_depth != 0)
+ i += MENU_ITEMS_PANE_LENGTH;
+ /* Ignore a nil in the item list.
+ It's meaningful only for dialog boxes. */
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+ i += 1;
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+ {
+ /* Create a new pane. */
+ Lisp_Object pane_name, prefix;
+ char *pane_string;
+ pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
+ prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+ {
+ pane_name = ENCODE_SYSTEM (pane_name);
+ AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
+ }
+#endif
+ pane_string = (NILP (pane_name)
+ ? "" : (char *) XSTRING (pane_name)->data);
+ /* If there is just one top-level pane, put all its items directly
+ under the top-level menu. */
+ if (menu_items_n_panes == 1)
+ pane_string = "";
+
+ /* If the pane has a meaningful name,
+ make the pane a top-level menu item
+ with its items as a submenu beneath it. */
+ if (!keymaps && strcmp (pane_string, ""))
+ {
+ wv = xmalloc_widget_value ();
+ if (save_wv)
+ save_wv->next = wv;
+ else
+ first_wv->contents = wv;
+ wv->name = pane_string;
+ if (keymaps && !NILP (prefix))
+ wv->name++;
+ wv->value = 0;
+ wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
+ save_wv = wv;
+ prev_wv = 0;
+ }
+ else if (first_pane)
+ {
+ save_wv = wv;
+ prev_wv = 0;
+ }
+ first_pane = 0;
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ /* Create a new item within current pane. */
+ Lisp_Object item_name, enable, descrip, def, type, selected, help;
+
+ item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+ enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
+ descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
+ def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
+ type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
+ selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
+ help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
+
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
+ {
+ item_name = ENCODE_SYSTEM (item_name);
+ AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
+ }
+ if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+ {
+ descrip = ENCODE_SYSTEM (descrip);
+ AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
+ }
+#endif /* not HAVE_MULTILINGUAL_MENU */
+
+ wv = xmalloc_widget_value ();
+ if (prev_wv)
+ prev_wv->next = wv;
+ else
+ save_wv->contents = wv;
+ wv->name = (char *) XSTRING (item_name)->data;
+ if (!NILP (descrip))
+ wv->key = (char *) XSTRING (descrip)->data;
+ wv->value = 0;
+ /* Use the contents index as call_data, since we are
+ restricted to 16-bits. */
+ wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
+ wv->enabled = !NILP (enable);
+
+ if (NILP (type))
+ wv->button_type = BUTTON_TYPE_NONE;
+ else if (EQ (type, QCtoggle))
+ wv->button_type = BUTTON_TYPE_TOGGLE;
+ else if (EQ (type, QCradio))
+ wv->button_type = BUTTON_TYPE_RADIO;
+ else
+ abort ();
+
+ wv->selected = !NILP (selected);
+ if (!STRINGP (help))
+ help = Qnil;
+
+ wv->help = help;
+
+ prev_wv = wv;
+
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+
+ /* Deal with the title, if it is non-nil. */
+ if (!NILP (title))
+ {
+ widget_value *wv_title = xmalloc_widget_value ();
+ widget_value *wv_sep = xmalloc_widget_value ();
+
+ /* Maybe replace this separator with a bitmap or owner-draw item
+ so that it looks better. Having two separators looks odd. */
+ wv_sep->name = "--";
+ wv_sep->next = first_wv->contents;
+ wv_sep->help = Qnil;
+
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRING_MULTIBYTE (title))
+ title = ENCODE_SYSTEM (title);
+#endif
+ wv_title->name = (char *) XSTRING (title)->data;
+ wv_title->enabled = TRUE;
+ wv_title->title = TRUE;
+ wv_title->button_type = BUTTON_TYPE_NONE;
+ wv_title->help = Qnil;
+ wv_title->next = wv_sep;
+ first_wv->contents = wv_title;
+ }
+
+ /* Actually create the menu. */
+ menu = NewMenu (POPUP_SUBMENU_ID, "\p");
+ fill_submenu (menu, first_wv->contents, 0);
+
+ /* Adjust coordinates to be root-window-relative. */
+ pos.h = x;
+ pos.v = y;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (FRAME_MAC_WINDOW (f)));
+#else
+ SetPort (FRAME_MAC_WINDOW (f));
+#endif
+
+ LocalToGlobal (&pos);
+
+ /* No selection has been chosen yet. */
+ menu_item_selection = 0;
+
+ InsertMenu (menu, -1);
+
+ /* Display the menu. */
+ menu_item_selection = LoWord (PopUpMenuSelect (menu, pos.v, pos.h, 0));
+
+ DeleteMenu (POPUP_SUBMENU_ID);
+
+#if 0
+ /* Clean up extraneous mouse events which might have been generated
+ during the call. */
+ discard_mouse_events ();
+#endif
+
+ /* Free the widget_value objects we used to specify the
+ contents. */
+ free_menubar_widget_value_tree (first_wv);
+
+ DisposeMenu (menu);
+
+ /* Find the selected item, and its pane, to return
+ the proper value. */
+ if (menu_item_selection != 0)
+ {
+ Lisp_Object prefix, entry;
+
+ prefix = entry = Qnil;
+ i = 0;
+ while (i < menu_items_used)
+ {
+ if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
+ {
+ subprefix_stack[submenu_depth++] = prefix;
+ prefix = entry;
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
+ {
+ prefix = subprefix_stack[--submenu_depth];
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+ {
+ prefix
+ = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ /* Ignore a nil in the item list.
+ It's meaningful only for dialog boxes. */
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+ i += 1;
+ else
+ {
+ entry
+ = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
+ if (menu_item_selection == i)
+ {
+ if (keymaps != 0)
+ {
+ int j;
+
+ entry = Fcons (entry, Qnil);
+ if (!NILP (prefix))
+ entry = Fcons (prefix, entry);
+ for (j = submenu_depth - 1; j >= 0; j--)
+ if (!NILP (subprefix_stack[j]))
+ entry = Fcons (subprefix_stack[j], entry);
+ }
+ return entry;
+ }
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+ }
+
+ return Qnil;
+}
+
+
+#ifdef HAVE_DIALOGS
+/* Construct native Mac OS menubar based on widget_value tree. */
+
+static int
+mac_dialog (widget_value *wv)
+{
+ char *dialog_name;
+ char *prompt;
+ char **button_labels;
+ UInt32 *ref_cons;
+ int nb_buttons;
+ int left_count;
+ int i;
+ int dialog_width;
+ Rect rect;
+ WindowPtr window_ptr;
+ ControlHandle ch;
+ int left;
+ EventRecord event_record;
+ SInt16 part_code;
+ int control_part_code;
+ Point mouse;
+
+ dialog_name = wv->name;
+ nb_buttons = dialog_name[1] - '0';
+ left_count = nb_buttons - (dialog_name[4] - '0');
+ button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
+ ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
+
+ wv = wv->contents;
+ prompt = (char *) alloca (strlen (wv->value) + 1);
+ strcpy (prompt, wv->value);
+ c2pstr (prompt);
+
+ wv = wv->next;
+ for (i = 0; i < nb_buttons; i++)
+ {
+ button_labels[i] = wv->value;
+ button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
+ strcpy (button_labels[i], wv->value);
+ c2pstr (button_labels[i]);
+ ref_cons[i] = (UInt32) wv->call_data;
+ wv = wv->next;
+ }
+
+ window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (window_ptr));
+#else
+ SetPort (window_ptr);
+#endif
+
+ TextFont (0);
+ /* Left and right margins in the dialog are 13 pixels each.*/
+ dialog_width = 14;
+ /* Calculate width of dialog box: 8 pixels on each side of the text
+ label in each button, 12 pixels between buttons. */
+ for (i = 0; i < nb_buttons; i++)
+ dialog_width += StringWidth (button_labels[i]) + 16 + 12;
+
+ if (left_count != 0 && nb_buttons - left_count != 0)
+ dialog_width += 12;
+
+ dialog_width = max (dialog_width, StringWidth (prompt) + 26);
+
+ SizeWindow (window_ptr, dialog_width, 78, 0);
+ ShowWindow (window_ptr);
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (window_ptr));
+#else
+ SetPort (window_ptr);
+#endif
+
+ TextFont (0);
+
+ MoveTo (13, 29);
+ DrawString (prompt);
+
+ left = 13;
+ for (i = 0; i < nb_buttons; i++)
+ {
+ int button_width = StringWidth (button_labels[i]) + 16;
+ SetRect (&rect, left, 45, left + button_width, 65);
+ ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
+ kControlPushButtonProc, ref_cons[i]);
+ left += button_width + 12;
+ if (i == left_count - 1)
+ left += 12;
+ }
+
+ i = 0;
+ while (!i)
+ {
+ if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
+ if (event_record.what == mouseDown)
+ {
+ part_code = FindWindow (event_record.where, &window_ptr);
+ if (part_code == inContent)
+ {
+ mouse = event_record.where;
+ GlobalToLocal (&mouse);
+ control_part_code = FindControl (mouse, window_ptr, &ch);
+ if (control_part_code == kControlButtonPart)
+ if (TrackControl (ch, mouse, NULL))
+ i = GetControlReference (ch);
+ }
+ }
+ }
+
+ DisposeWindow (window_ptr);
+
+ return i;
+}
+
+static char * button_names [] = {
+ "button1", "button2", "button3", "button4", "button5",
+ "button6", "button7", "button8", "button9", "button10" };
+
+static Lisp_Object
+mac_dialog_show (f, keymaps, title, error)
+ FRAME_PTR f;
+ int keymaps;
+ Lisp_Object title;
+ char **error;
+{
+ int i, nb_buttons=0;
+ char dialog_name[6];
+ int menu_item_selection;
+
+ widget_value *wv, *first_wv = 0, *prev_wv = 0;
+
+ /* Number of elements seen so far, before boundary. */
+ int left_count = 0;
+ /* 1 means we've seen the boundary between left-hand elts and right-hand. */
+ int boundary_seen = 0;
+
+ *error = NULL;
+
+ if (menu_items_n_panes > 1)
+ {
+ *error = "Multiple panes in dialog box";
+ return Qnil;
+ }
+
+ /* Create a tree of widget_value objects
+ representing the text label and buttons. */
+ {
+ Lisp_Object pane_name, prefix;
+ char *pane_string;
+ pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
+ prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
+ pane_string = (NILP (pane_name)
+ ? "" : (char *) XSTRING (pane_name)->data);
+ prev_wv = xmalloc_widget_value ();
+ prev_wv->value = pane_string;
+ if (keymaps && !NILP (prefix))
+ prev_wv->name++;
+ prev_wv->enabled = 1;
+ prev_wv->name = "message";
+ prev_wv->help = Qnil;
+ first_wv = prev_wv;
+
+ /* Loop over all panes and items, filling in the tree. */
+ i = MENU_ITEMS_PANE_LENGTH;
+ while (i < menu_items_used)
+ {
+
+ /* Create a new item within current pane. */
+ Lisp_Object item_name, enable, descrip, help;
+
+ item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
+ enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
+ descrip
+ = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
+ help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
+
+ if (NILP (item_name))
+ {
+ free_menubar_widget_value_tree (first_wv);
+ *error = "Submenu in dialog items";
+ return Qnil;
+ }
+ if (EQ (item_name, Qquote))
+ {
+ /* This is the boundary between left-side elts
+ and right-side elts. Stop incrementing right_count. */
+ boundary_seen = 1;
+ i++;
+ continue;
+ }
+ if (nb_buttons >= 9)
+ {
+ free_menubar_widget_value_tree (first_wv);
+ *error = "Too many dialog items";
+ return Qnil;
+ }
+
+ wv = xmalloc_widget_value ();
+ prev_wv->next = wv;
+ wv->name = (char *) button_names[nb_buttons];
+ if (!NILP (descrip))
+ wv->key = (char *) XSTRING (descrip)->data;
+ wv->value = (char *) XSTRING (item_name)->data;
+ wv->call_data = (void *) i;
+ /* menu item is identified by its index in menu_items table */
+ wv->enabled = !NILP (enable);
+ wv->help = Qnil;
+ prev_wv = wv;
+
+ if (! boundary_seen)
+ left_count++;
+
+ nb_buttons++;
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+
+ /* If the boundary was not specified,
+ by default put half on the left and half on the right. */
+ if (! boundary_seen)
+ left_count = nb_buttons - nb_buttons / 2;
+
+ wv = xmalloc_widget_value ();
+ wv->name = dialog_name;
+ wv->help = Qnil;
+
+ /* Dialog boxes use a really stupid name encoding
+ which specifies how many buttons to use
+ and how many buttons are on the right.
+ The Q means something also. */
+ dialog_name[0] = 'Q';
+ dialog_name[1] = '0' + nb_buttons;
+ dialog_name[2] = 'B';
+ dialog_name[3] = 'R';
+ /* Number of buttons to put on the right. */
+ dialog_name[4] = '0' + nb_buttons - left_count;
+ dialog_name[5] = 0;
+ wv->contents = first_wv;
+ first_wv = wv;
+ }
+
+ /* Actually create the dialog. */
+#ifdef HAVE_DIALOGS
+ menu_item_selection = mac_dialog (first_wv);
+#else
+ menu_item_selection = 0;
+#endif
+
+ /* Free the widget_value objects we used to specify the contents. */
+ free_menubar_widget_value_tree (first_wv);
+
+ /* Find the selected item, and its pane, to return the proper
+ value. */
+ if (menu_item_selection != 0)
+ {
+ Lisp_Object prefix;
+
+ prefix = Qnil;
+ i = 0;
+ while (i < menu_items_used)
+ {
+ Lisp_Object entry;
+
+ if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+ {
+ prefix
+ = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ entry
+ = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
+ if (menu_item_selection == i)
+ {
+ if (keymaps != 0)
+ {
+ entry = Fcons (entry, Qnil);
+ if (!NILP (prefix))
+ entry = Fcons (prefix, entry);
+ }
+ return entry;
+ }
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+ }
+
+ return Qnil;
+}
+#endif /* HAVE_DIALOGS */
+
+
+/* Is this item a separator? */
+static int
+name_is_separator (name)
+ char *name;
+{
+ char *start = name;
+
+ /* Check if name string consists of only dashes ('-'). */
+ while (*name == '-') name++;
+ /* Separators can also be of the form "--:TripleSuperMegaEtched"
+ or "--deep-shadow". We don't implement them yet, se we just treat
+ them like normal separators. */
+ return (*name == '\0' || start + 2 == name);
+}
+
+static void
+add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent,
+ int force_disable)
+{
+ Str255 item_name;
+ int pos, i;
+
+ if (name_is_separator (wv->name))
+ AppendMenu (menu, "\p-");
+ else
+ {
+ AppendMenu (menu, "\pX");
+
+#if TARGET_API_MAC_CARBON
+ pos = CountMenuItems (menu);
+#else
+ pos = CountMItems (menu);
+#endif
+
+ strcpy (item_name, "");
+ for (i = 0; i < indent; i++)
+ strcat (item_name, " ");
+ strcat (item_name, wv->name);
+ if (wv->key != NULL)
+ {
+ strcat (item_name, " ");
+ strcat (item_name, wv->key);
+ }
+ c2pstr (item_name);
+ SetMenuItemText (menu, pos, item_name);
+
+ if (wv->enabled && !force_disable)
+#if TARGET_API_MAC_CARBON
+ EnableMenuItem (menu, pos);
+#else
+ EnableItem (menu, pos);
+#endif
+ else
+#if TARGET_API_MAC_CARBON
+ DisableMenuItem (menu, pos);
+#else
+ DisableItem (menu, pos);
+#endif
+
+ /* Draw radio buttons and tickboxes. */
+ {
+ if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
+ wv->button_type == BUTTON_TYPE_RADIO))
+ SetItemMark (menu, pos, checkMark);
+ else
+ SetItemMark (menu, pos, noMark);
+ }
+ }
+
+ SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
+
+ if (submenu != NULL)
+ SetMenuItemHierarchicalID (menu, pos, submenu);
+}
+
+static int submenu_id;
+
+/* Construct native Mac OS menubar based on widget_value tree. */
+
+static void
+fill_submenu (MenuHandle menu, widget_value *wv, int indent)
+{
+ for ( ; wv != NULL; wv = wv->next)
+ if (wv->contents)
+ {
+ add_menu_item (menu, wv, NULL, indent, 1);
+
+ fill_submenu (menu, wv->contents, indent + 1);
+ }
+ else
+ add_menu_item (menu, wv, NULL, indent, 0);
+}
+
+
+/* Construct native Mac OS menu based on widget_value tree. */
+
+static void
+fill_menu (MenuHandle menu, widget_value *wv)
+{
+ for ( ; wv != NULL; wv = wv->next)
+ if (wv->contents)
+ {
+ MenuHandle submenu = NewMenu (submenu_id, "\pX");
+ fill_submenu (submenu, wv->contents, 0);
+ InsertMenu (submenu, -1);
+ add_menu_item (menu, wv, submenu_id, 0, 0);
+ submenu_id++;
+ }
+ else
+ add_menu_item (menu, wv, NULL, 0, 0);
+}
+
+/* Construct native Mac OS menubar based on widget_value tree. */
+
+static void
+fill_menubar (widget_value *wv)
+{
+ int id;
+
+ submenu_id = MIN_SUBMENU_ID;
+
+ for (id = MIN_MENU_ID; wv != NULL; wv = wv->next, id++)
+ {
+ MenuHandle menu;
+ Str255 title;
+
+ strcpy (title, wv->name);
+ c2pstr (title);
+ menu = NewMenu (id, title);
+
+ if (wv->contents)
+ fill_menu (menu, wv->contents);
+
+ InsertMenu (menu, 0);
+ }
+}
+
+#endif /* HAVE_MENUS */
+
+
+void
+syms_of_macmenu ()
+{
+ staticpro (&menu_items);
+ menu_items = Qnil;
+
+ Qdebug_on_next_call = intern ("debug-on-next-call");
+ staticpro (&Qdebug_on_next_call);
+
+ DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
+ doc: /* Frame for which we are updating a menu.
+The enable predicate for a menu command should check this variable. */);
+ Vmenu_updating_frame = Qnil;
+
+ defsubr (&Sx_popup_menu);
+#ifdef HAVE_MENUS
+ defsubr (&Sx_popup_dialog);
+#endif
+}
diff --git a/src/macterm.c b/src/macterm.c
new file mode 100644
index 00000000000..4e3dc93d7ce
--- /dev/null
+++ b/src/macterm.c
@@ -0,0 +1,13192 @@
+/* Implementation of GUI terminal on the Mac OS.
+ Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#include <config.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "lisp.h"
+#include "charset.h"
+#include "blockinput.h"
+
+#include "macterm.h"
+
+#ifndef MAC_OSX
+#include <alloca.h>
+#endif
+
+#ifdef MAC_OSX
+#undef mktime
+#undef DEBUG
+#undef free
+#undef malloc
+#undef realloc
+/* Macros max and min defined in lisp.h conflict with those in
+ precompiled header Carbon.h. */
+#undef max
+#undef min
+#include <Carbon/Carbon.h>
+#undef free
+#define free unexec_free
+#undef malloc
+#define malloc unexec_malloc
+#undef realloc
+#define realloc unexec_realloc
+#undef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#undef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#else /* not MAC_OSX */
+#include <Quickdraw.h>
+#include <ToolUtils.h>
+#include <Sound.h>
+#include <Events.h>
+#include <Script.h>
+#include <Resources.h>
+#include <Fonts.h>
+#include <TextUtils.h>
+#include <LowMem.h>
+#include <Controls.h>
+#if defined (__MRC__) || (__MSL__ >= 0x6000)
+#include <ControlDefinitions.h>
+#endif
+#include <Gestalt.h>
+
+#if __profile__
+#include <profiler.h>
+#endif
+#endif /* not MAC_OSX */
+
+#include "systty.h"
+#include "systime.h"
+#include "atimer.h"
+#include "keymap.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+
+#include "keyboard.h"
+#include "frame.h"
+#include "dispextern.h"
+#include "fontset.h"
+#include "termhooks.h"
+#include "termopts.h"
+#include "termchar.h"
+#include "gnu.h"
+#include "disptab.h"
+#include "buffer.h"
+#include "window.h"
+#include "intervals.h"
+#include "composite.h"
+#include "coding.h"
+
+#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
+
+
+/* Fringe bitmaps. */
+
+enum fringe_bitmap_type
+{
+ NO_FRINGE_BITMAP,
+ LEFT_TRUNCATION_BITMAP,
+ RIGHT_TRUNCATION_BITMAP,
+ OVERLAY_ARROW_BITMAP,
+ CONTINUED_LINE_BITMAP,
+ CONTINUATION_LINE_BITMAP,
+ ZV_LINE_BITMAP
+};
+
+/* Bitmap drawn to indicate lines not displaying text if
+ `indicate-empty-lines' is non-nil. */
+
+#define zv_width 8
+#define zv_height 72
+#define zv_period 3
+static unsigned char zv_bits[] = {
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
+
+/* An arrow like this: `<-'. */
+
+#define left_width 8
+#define left_height 8
+static unsigned char left_bits[] = {
+ 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
+
+/* Right truncation arrow bitmap `->'. */
+
+#define right_width 8
+#define right_height 8
+static unsigned char right_bits[] = {
+ 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
+
+/* Marker for continued lines. */
+
+#define continued_width 8
+#define continued_height 8
+static unsigned char continued_bits[] = {
+ 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
+
+/* Marker for continuation lines. */
+
+#define continuation_width 8
+#define continuation_height 8
+static unsigned char continuation_bits[] = {
+ 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
+
+/* Overlay arrow bitmap. */
+
+#if 0
+/* A bomb. */
+#define ov_width 8
+#define ov_height 8
+static unsigned char ov_bits[] = {
+ 0x0c, 0x10, 0x3c, 0x7e, 0x5e, 0x5e, 0x46, 0x3c};
+#else
+/* A triangular arrow. */
+#define ov_width 8
+#define ov_height 8
+static unsigned char ov_bits[] = {
+ 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0};
+#endif
+
+extern Lisp_Object Qhelp_echo;
+
+
+/* Non-nil means Emacs uses toolkit scroll bars. */
+
+Lisp_Object Vx_toolkit_scroll_bars;
+
+/* If a string, XTread_socket generates an event to display that string.
+ (The display is done in read_char.) */
+
+static Lisp_Object help_echo;
+static Lisp_Object help_echo_window;
+static Lisp_Object help_echo_object;
+static int help_echo_pos;
+
+/* Temporary variable for XTread_socket. */
+
+static Lisp_Object previous_help_echo;
+
+/* Non-zero means that a HELP_EVENT has been generated since Emacs
+ start. */
+
+static int any_help_event_p;
+
+/* Non-zero means autoselect window with the mouse cursor. */
+
+int x_autoselect_window_p;
+
+/* Non-zero means draw block and hollow cursor as wide as the glyph
+ under it. For example, if a block cursor is over a tab, it will be
+ drawn as wide as that tab on the display. */
+
+int x_stretch_cursor_p;
+
+/* Non-zero means make use of UNDERLINE_POSITION font properties. */
+
+int x_use_underline_position_properties;
+
+/* This is a chain of structures for all the X displays currently in
+ use. */
+
+struct x_display_info *x_display_list;
+
+/* This is a list of cons cells, each of the form (NAME
+ . FONT-LIST-CACHE), one for each element of x_display_list and in
+ the same order. NAME is the name of the frame. FONT-LIST-CACHE
+ records previous values returned by x-list-fonts. */
+
+Lisp_Object x_display_name_list;
+
+/* This is display since Mac does not support multiple ones. */
+struct mac_display_info one_mac_display_info;
+
+/* Frame being updated by update_frame. This is declared in term.c.
+ This is set by update_begin and looked at by all the XT functions.
+ It is zero while not inside an update. In that case, the XT
+ functions assume that `selected_frame' is the frame to apply to. */
+
+extern struct frame *updating_frame;
+
+extern int waiting_for_input;
+
+/* This is a frame waiting to be auto-raised, within XTread_socket. */
+
+struct frame *pending_autoraise_frame;
+
+/* Nominal cursor position -- where to draw output.
+ HPOS and VPOS are window relative glyph matrix coordinates.
+ X and Y are window relative pixel coordinates. */
+
+struct cursor_pos output_cursor;
+
+/* Non-zero means user is interacting with a toolkit scroll bar. */
+
+static int toolkit_scroll_bar_interaction;
+
+/* Mouse movement.
+
+ Formerly, we used PointerMotionHintMask (in standard_event_mask)
+ so that we would have to call XQueryPointer after each MotionNotify
+ event to ask for another such event. However, this made mouse tracking
+ slow, and there was a bug that made it eventually stop.
+
+ Simply asking for MotionNotify all the time seems to work better.
+
+ In order to avoid asking for motion events and then throwing most
+ of them away or busy-polling the server for mouse positions, we ask
+ the server for pointer motion hints. This means that we get only
+ one event per group of mouse movements. "Groups" are delimited by
+ other kinds of events (focus changes and button clicks, for
+ example), or by XQueryPointer calls; when one of these happens, we
+ get another MotionNotify event the next time the mouse moves. This
+ is at least as efficient as getting motion events when mouse
+ tracking is on, and I suspect only negligibly worse when tracking
+ is off. */
+
+/* Where the mouse was last time we reported a mouse event. */
+
+FRAME_PTR last_mouse_frame;
+static Rect last_mouse_glyph;
+static Lisp_Object last_mouse_press_frame;
+
+/* The scroll bar in which the last X motion event occurred.
+
+ If the last X motion event occurred in a scroll bar, we set this so
+ XTmouse_position can know whether to report a scroll bar motion or
+ an ordinary motion.
+
+ If the last X motion event didn't occur in a scroll bar, we set
+ this to Qnil, to tell XTmouse_position to return an ordinary motion
+ event. */
+
+static Lisp_Object last_mouse_scroll_bar;
+
+/* This is a hack. We would really prefer that XTmouse_position would
+ return the time associated with the position it returns, but there
+ doesn't seem to be any way to wrest the time-stamp from the server
+ along with the position query. So, we just keep track of the time
+ of the last movement we received, and return that in hopes that
+ it's somewhat accurate. */
+
+static Time last_mouse_movement_time;
+
+enum mouse_tracking_type {
+ mouse_tracking_none,
+ mouse_tracking_mouse_movement,
+ mouse_tracking_scroll_bar
+};
+
+enum mouse_tracking_type mouse_tracking_in_progress = mouse_tracking_none;
+
+struct scroll_bar *tracked_scroll_bar = NULL;
+
+/* Incremented by XTread_socket whenever it really tries to read
+ events. */
+
+#ifdef __STDC__
+static int volatile input_signal_count;
+#else
+static int input_signal_count;
+#endif
+
+/* Used locally within XTread_socket. */
+
+static int x_noop_count;
+
+/* Initial values of argv and argc. */
+
+extern char **initial_argv;
+extern int initial_argc;
+
+extern Lisp_Object Vcommand_line_args, Vsystem_name;
+
+/* Tells if a window manager is present or not. */
+
+extern Lisp_Object Vx_no_window_manager;
+
+extern Lisp_Object Qface, Qmouse_face;
+
+extern int errno;
+
+/* A mask of extra modifier bits to put into every keyboard char. */
+
+extern int extra_keyboard_modifiers;
+
+static Lisp_Object Qvendor_specific_keysyms;
+
+#if 0
+extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
+#endif
+
+extern Lisp_Object x_icon_type P_ ((struct frame *));
+
+
+#if __MRC__
+QDGlobals qd; /* QuickDraw global information structure. */
+#endif
+
+
+/* Enumeration for overriding/changing the face to use for drawing
+ glyphs in x_draw_glyphs. */
+
+enum draw_glyphs_face
+{
+ DRAW_NORMAL_TEXT,
+ DRAW_INVERSE_VIDEO,
+ DRAW_CURSOR,
+ DRAW_MOUSE_FACE,
+ DRAW_IMAGE_RAISED,
+ DRAW_IMAGE_SUNKEN
+};
+
+struct frame * x_window_to_frame (struct mac_display_info *, WindowPtr);
+struct mac_display_info *mac_display_info_for_display (Display *);
+static void x_update_window_end P_ ((struct window *, int, int));
+static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
+static int fast_find_position P_ ((struct window *, int, int *, int *,
+ int *, int *, Lisp_Object));
+static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
+ int *, int *, int *, int *, int));
+static void set_output_cursor P_ ((struct cursor_pos *));
+static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
+ int *, int *, int *, int));
+static void note_mode_line_highlight P_ ((struct window *, int, int));
+static void note_mouse_highlight P_ ((struct frame *, int, int));
+static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
+static void x_handle_tool_bar_click P_ ((struct frame *, EventRecord *));
+static void show_mouse_face P_ ((struct x_display_info *,
+ enum draw_glyphs_face));
+static int cursor_in_mouse_face_p P_ ((struct window *));
+static int clear_mouse_face P_ ((struct mac_display_info *));
+static int x_io_error_quitter P_ ((Display *));
+int x_catch_errors P_ ((Display *));
+void x_uncatch_errors P_ ((Display *, int));
+void x_lower_frame P_ ((struct frame *));
+void x_scroll_bar_clear P_ ((struct frame *));
+int x_had_errors_p P_ ((Display *));
+void x_wm_set_size_hint P_ ((struct frame *, long, int));
+void x_raise_frame P_ ((struct frame *));
+void x_set_window_size P_ ((struct frame *, int, int, int));
+void x_wm_set_window_state P_ ((struct frame *, int));
+void x_wm_set_icon_pixmap P_ ((struct frame *, int));
+void mac_initialize P_ ((void));
+static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
+static int x_compute_min_glyph_bounds P_ ((struct frame *));
+enum text_cursor_kinds x_specified_cursor_type P_ ((Lisp_Object, int *));
+static void x_draw_phys_cursor_glyph P_ ((struct window *,
+ struct glyph_row *,
+ enum draw_glyphs_face));
+static void x_update_end P_ ((struct frame *));
+static void XTframe_up_to_date P_ ((struct frame *));
+static void XTreassert_line_highlight P_ ((int, int));
+static void x_change_line_highlight P_ ((int, int, int, int));
+static void XTset_terminal_modes P_ ((void));
+static void XTreset_terminal_modes P_ ((void));
+static void XTcursor_to P_ ((int, int, int, int));
+static void x_write_glyphs P_ ((struct glyph *, int));
+static void x_clear_end_of_line P_ ((int));
+static void x_clear_frame P_ ((void));
+static void x_clear_cursor P_ ((struct window *));
+static void frame_highlight P_ ((struct frame *));
+static void frame_unhighlight P_ ((struct frame *));
+static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
+static void XTframe_rehighlight P_ ((struct frame *));
+static void x_frame_rehighlight P_ ((struct x_display_info *));
+static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
+static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
+static int x_intersect_rectangles P_ ((Rect *, Rect *, Rect *));
+static void expose_frame P_ ((struct frame *, int, int, int, int));
+static int expose_window_tree P_ ((struct window *, Rect *));
+static int expose_window P_ ((struct window *, Rect *));
+static void expose_area P_ ((struct window *, struct glyph_row *,
+ Rect *, enum glyph_row_area));
+static int expose_line P_ ((struct window *, struct glyph_row *,
+ Rect *));
+void x_display_cursor (struct window *, int, int, int, int, int);
+void x_update_cursor P_ ((struct frame *, int));
+static void x_update_cursor_in_window_tree P_ ((struct window *, int));
+static void x_update_window_cursor P_ ((struct window *, int));
+static void x_erase_phys_cursor P_ ((struct window *));
+void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
+static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *,
+ enum fringe_bitmap_type, int left_p));
+static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
+ GC, int));
+static int x_phys_cursor_in_rect_p P_ ((struct window *, Rect *));
+static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *));
+static void notice_overwritten_cursor P_ ((struct window *,
+ enum glyph_row_area,
+ int, int, int, int));
+static void x_flush P_ ((struct frame *f));
+static void x_update_begin P_ ((struct frame *));
+static void x_update_window_begin P_ ((struct window *));
+static void x_draw_vertical_border P_ ((struct window *));
+static void x_after_update_window_line P_ ((struct glyph_row *));
+static INLINE void take_vertical_position_into_account P_ ((struct it *));
+static void x_produce_stretch_glyph P_ ((struct it *));
+
+static void activate_scroll_bars (FRAME_PTR);
+static void deactivate_scroll_bars (FRAME_PTR);
+
+extern int image_ascent (struct image *, struct face *);
+void x_set_offset (struct frame *, int, int, int);
+int x_bitmap_icon (struct frame *, Lisp_Object);
+void x_make_frame_visible (struct frame *);
+
+extern void window_scroll (Lisp_Object, int, int, int);
+
+/* Defined in macmenu.h. */
+extern void menubar_selection_callback (FRAME_PTR, int);
+extern void set_frame_menubar (FRAME_PTR, int, int);
+
+/* X display function emulation */
+
+/* Structure borrowed from Xlib.h to represent two-byte characters in
+ dumpglyphs. */
+
+typedef struct {
+ unsigned char byte1;
+ unsigned char byte2;
+} XChar2b;
+
+static void
+XFreePixmap (display, pixmap)
+ Display *display;
+ Pixmap pixmap;
+{
+ PixMap *p = (PixMap *) pixmap;
+
+ xfree (p->baseAddr);
+ xfree (p);
+}
+
+
+/* Set foreground color for subsequent QuickDraw commands. Assume
+ graphic port has already been set. */
+
+static void
+mac_set_forecolor (unsigned long color)
+{
+ RGBColor fg_color;
+
+ fg_color.red = RED_FROM_ULONG (color) * 256;
+ fg_color.green = GREEN_FROM_ULONG (color) * 256;
+ fg_color.blue = BLUE_FROM_ULONG (color) * 256;
+
+ RGBForeColor (&fg_color);
+}
+
+
+/* Set background color for subsequent QuickDraw commands. Assume
+ graphic port has already been set. */
+
+static void
+mac_set_backcolor (unsigned long color)
+{
+ RGBColor bg_color;
+
+ bg_color.red = RED_FROM_ULONG (color) * 256;
+ bg_color.green = GREEN_FROM_ULONG (color) * 256;
+ bg_color.blue = BLUE_FROM_ULONG (color) * 256;
+
+ RGBBackColor (&bg_color);
+}
+
+/* Set foreground and background color for subsequent QuickDraw
+ commands. Assume that the graphic port has already been set. */
+
+static void
+mac_set_colors (GC gc)
+{
+ mac_set_forecolor (gc->foreground);
+ mac_set_backcolor (gc->background);
+}
+
+/* Mac version of XDrawLine. */
+
+static void
+XDrawLine (display, w, gc, x1, y1, x2, y2)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x1, y1, x2, y2;
+{
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (gc);
+
+ MoveTo (x1, y1);
+ LineTo (x2, y2);
+}
+
+/* Mac version of XClearArea. */
+
+void
+XClearArea (display, w, x, y, width, height, exposures)
+ Display *display;
+ WindowPtr w;
+ int x, y;
+ unsigned int width, height;
+ int exposures;
+{
+ struct mac_output *mwp = (mac_output *) GetWRefCon (w);
+ Rect r;
+ XGCValues xgc;
+
+ xgc.foreground = mwp->x_compatible.foreground_pixel;
+ xgc.background = mwp->x_compatible.background_pixel;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (&xgc);
+ SetRect (&r, x, y, x + width, y + height);
+
+ EraseRect (&r);
+}
+
+/* Mac version of XClearWindow. */
+
+static void
+XClearWindow (display, w)
+ Display *display;
+ WindowPtr w;
+{
+ struct mac_output *mwp = (mac_output *) GetWRefCon (w);
+ XGCValues xgc;
+
+ xgc.foreground = mwp->x_compatible.foreground_pixel;
+ xgc.background = mwp->x_compatible.background_pixel;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (&xgc);
+
+#if TARGET_API_MAC_CARBON
+ {
+ Rect r;
+
+ GetWindowPortBounds (w, &r);
+ EraseRect (&r);
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ EraseRect (&(w->portRect));
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* Mac replacement for XCopyArea. */
+
+static void
+mac_draw_bitmap (display, w, gc, x, y, bitmap)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ BitMap *bitmap;
+{
+ Rect r;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (gc);
+ SetRect (&r, x, y, x + bitmap->bounds.right, y + bitmap->bounds.bottom);
+
+#if TARGET_API_MAC_CARBON
+ {
+ PixMapHandle pmh;
+
+ LockPortBits (GetWindowPort (w));
+ pmh = GetPortPixMap (GetWindowPort (w));
+ CopyBits (bitmap, (BitMap *) *pmh, &(bitmap->bounds), &r, srcCopy, 0);
+ UnlockPortBits (GetWindowPort (w));
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ CopyBits (bitmap, &(w->portBits), &(bitmap->bounds), &r, srcCopy, 0);
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* Mac replacement for XSetClipRectangles. */
+
+static void
+mac_set_clip_rectangle (display, w, r)
+ Display *display;
+ WindowPtr w;
+ Rect *r;
+{
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ ClipRect (r);
+}
+
+
+/* Mac replacement for XSetClipMask. */
+
+static void
+mac_reset_clipping (display, w)
+ Display *display;
+ WindowPtr w;
+{
+ Rect r;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ SetRect (&r, -32767, -32767, 32767, 32767);
+ ClipRect (&r);
+}
+
+
+/* Mac replacement for XCreateBitmapFromBitmapData. */
+
+static void
+mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
+ BitMap *bitmap;
+ char *bits;
+ int w, h;
+{
+ int bytes_per_row, i, j;
+
+ bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */
+ bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
+ if (!bitmap->baseAddr)
+ abort ();
+
+ bzero (bitmap->baseAddr, bitmap->rowBytes * h);
+ for (i = 0; i < h; i++)
+ for (j = 0; j < w; j++)
+ if (BitTst (bits, i * w + j))
+ BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j);
+
+ SetRect (&(bitmap->bounds), 0, 0, w, h);
+}
+
+
+static void
+mac_free_bitmap (bitmap)
+ BitMap *bitmap;
+{
+ xfree (bitmap->baseAddr);
+}
+
+/* Mac replacement for XFillRectangle. */
+
+static void
+XFillRectangle (display, w, gc, x, y, width, height)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ unsigned int width, height;
+{
+ Rect r;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (gc);
+ SetRect (&r, x, y, x + width, y + height);
+
+ PaintRect (&r); /* using foreground color of gc */
+}
+
+
+/* Mac replacement for XDrawRectangle: dest is a window. */
+
+static void
+mac_draw_rectangle (display, w, gc, x, y, width, height)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ unsigned int width, height;
+{
+ Rect r;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (gc);
+ SetRect (&r, x, y, x + width + 1, y + height + 1);
+
+ FrameRect (&r); /* using foreground color of gc */
+}
+
+
+/* Mac replacement for XDrawRectangle: dest is a Pixmap. */
+
+static void
+mac_draw_rectangle_to_pixmap (display, p, gc, x, y, width, height)
+ Display *display;
+ Pixmap p;
+ GC gc;
+ int x, y;
+ unsigned int width, height;
+{
+#if 0 /* MAC_TODO: draw a rectangle in a PixMap */
+ Rect r;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (gc);
+ SetRect (&r, x, y, x + width, y + height);
+
+ FrameRect (&r); /* using foreground color of gc */
+#endif /* 0 */
+}
+
+
+static void
+mac_draw_string_common (display, w, gc, x, y, buf, nchars, mode,
+ bytes_per_char)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ char *buf;
+ int nchars, mode, bytes_per_char;
+{
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ mac_set_colors (gc);
+
+ TextFont (gc->font->mac_fontnum);
+ TextSize (gc->font->mac_fontsize);
+ TextFace (gc->font->mac_fontface);
+ TextMode (mode);
+
+ MoveTo (x, y);
+ DrawText (buf, 0, nchars * bytes_per_char);
+}
+
+
+/* Mac replacement for XDrawString. */
+
+static void
+XDrawString (display, w, gc, x, y, buf, nchars)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ char *buf;
+ int nchars;
+{
+ mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcOr, 1);
+}
+
+
+/* Mac replacement for XDrawString16. */
+
+static void
+XDrawString16 (display, w, gc, x, y, buf, nchars)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ XChar2b *buf;
+ int nchars;
+{
+ mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcOr,
+ 2);
+}
+
+
+/* Mac replacement for XDrawImageString. */
+
+static void
+XDrawImageString (display, w, gc, x, y, buf, nchars)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ char *buf;
+ int nchars;
+{
+ mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcCopy, 1);
+}
+
+
+/* Mac replacement for XDrawString16. */
+
+static void
+XDrawImageString16 (display, w, gc, x, y, buf, nchars)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int x, y;
+ XChar2b *buf;
+ int nchars;
+{
+ mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcCopy,
+ 2);
+}
+
+
+/* Mac replacement for XCopyArea: dest must be window. */
+
+static void
+mac_copy_area (display, src, dest, gc, src_x, src_y, width, height, dest_x,
+ dest_y)
+ Display *display;
+ Pixmap src;
+ WindowPtr dest;
+ GC gc;
+ int src_x, src_y;
+ unsigned int width, height;
+ int dest_x, dest_y;
+{
+ Rect src_r, dest_r;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (dest));
+#else
+ SetPort (dest);
+#endif
+
+ mac_set_colors (gc);
+
+ SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
+ SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
+
+#if TARGET_API_MAC_CARBON
+ {
+ PixMapHandle pmh;
+
+ LockPortBits (GetWindowPort (dest));
+ pmh = GetPortPixMap (GetWindowPort (dest));
+ CopyBits ((BitMap *) &src, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0);
+ UnlockPortBits (GetWindowPort (dest));
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ CopyBits ((BitMap *) &src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0);
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+#if 0
+/* Convert a pair of local coordinates to global (screen) coordinates.
+ Assume graphic port has been properly set. */
+static void
+local_to_global_coord (short *h, short *v)
+{
+ Point p;
+
+ p.h = *h;
+ p.v = *v;
+
+ LocalToGlobal (&p);
+
+ *h = p.h;
+ *v = p.v;
+}
+#endif
+
+/* Mac replacement for XCopyArea: used only for scrolling. */
+
+static void
+mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y)
+ Display *display;
+ WindowPtr w;
+ GC gc;
+ int src_x, src_y;
+ unsigned int width, height;
+ int dest_x, dest_y;
+{
+#if TARGET_API_MAC_CARBON
+ Rect gw_r, src_r, dest_r;
+ PixMapHandle pmh;
+
+ SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
+ SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
+
+ SetPort (GetWindowPort (w));
+ mac_set_colors (gc);
+
+ LockPortBits (GetWindowPort (w));
+ pmh = GetPortPixMap (GetWindowPort (w));
+ CopyBits ((BitMap *) *pmh, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0);
+ UnlockPortBits (GetWindowPort (w));
+#else /* not TARGET_API_MAC_CARBON */
+ Rect src_r, dest_r;
+
+ SetPort (w);
+#if 0
+ mac_set_colors (gc);
+#endif
+
+ SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
+ SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
+
+#if 0
+ /* Need to use global coordinates and screenBits since src and dest
+ areas overlap in general. */
+ local_to_global_coord (&src_r.left, &src_r.top);
+ local_to_global_coord (&src_r.right, &src_r.bottom);
+ local_to_global_coord (&dest_r.left, &dest_r.top);
+ local_to_global_coord (&dest_r.right, &dest_r.bottom);
+
+ CopyBits (&qd.screenBits, &qd.screenBits, &src_r, &dest_r, srcCopy, 0);
+#else
+ /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
+ color mapping in CopyBits. Otherwise, it will be slow. */
+ ForeColor (blackColor);
+ BackColor (whiteColor);
+ CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
+
+ mac_set_colors (gc);
+#endif
+#endif /* not TARGET_API_MAC_CARBON */
+}
+
+
+/* Mac replacement for XCopyArea: dest must be Pixmap. */
+
+static void
+mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height,
+ dest_x, dest_y)
+ Display *display;
+ Pixmap src;
+ Pixmap dest;
+ GC gc;
+ int src_x, src_y;
+ unsigned int width, height;
+ int dest_x, dest_y;
+{
+ Rect src_r, dest_r;
+ int src_right = ((PixMap *) src)->bounds.right;
+ int src_bottom = ((PixMap *) src)->bounds.bottom;
+ int w = src_right - src_x;
+ int h = src_bottom - src_y;
+
+ mac_set_colors (gc);
+
+ SetRect (&src_r, src_x, src_y, src_right, src_bottom);
+ SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h);
+
+ CopyBits ((BitMap *) &src, (BitMap *) &dest, &src_r, &dest_r, srcCopy, 0);
+}
+
+
+/* Mac replacement for XChangeGC. */
+
+static void
+XChangeGC (void * ignore, XGCValues* gc, unsigned long mask,
+ XGCValues *xgcv)
+{
+ if (mask & GCForeground)
+ gc->foreground = xgcv->foreground;
+ if (mask & GCBackground)
+ gc->background = xgcv->background;
+ if (mask & GCFont)
+ gc->font = xgcv->font;
+}
+
+
+/* Mac replacement for XCreateGC. */
+
+XGCValues *
+XCreateGC (void * ignore, Window window, unsigned long mask,
+ XGCValues *xgcv)
+{
+ XGCValues *gc = (XGCValues *) xmalloc (sizeof (XGCValues));
+ bzero (gc, sizeof (XGCValues));
+
+ XChangeGC (ignore, gc, mask, xgcv);
+
+ return gc;
+}
+
+
+/* Used in xfaces.c. */
+
+void
+XFreeGC (display, gc)
+ Display *display;
+ GC gc;
+{
+ xfree (gc);
+}
+
+
+/* Mac replacement for XGetGCValues. */
+
+static void
+XGetGCValues (void* ignore, XGCValues *gc,
+ unsigned long mask, XGCValues *xgcv)
+{
+ XChangeGC (ignore, xgcv, mask, gc);
+}
+
+
+/* Mac replacement for XSetForeground. */
+
+static void
+XSetForeground (display, gc, color)
+ Display *display;
+ GC gc;
+ unsigned long color;
+{
+ gc->foreground = color;
+}
+
+
+/* Mac replacement for XSetFont. */
+
+static void
+XSetFont (display, gc, font)
+ Display *display;
+ GC gc;
+ XFontStruct *font;
+{
+ gc->font = font;
+}
+
+
+static void
+XTextExtents16 (XFontStruct *font, XChar2b *text, int nchars,
+ int *direction,int *font_ascent,
+ int *font_descent, XCharStruct *cs)
+{
+ /* MAC_TODO: Use GetTextMetrics to do this and inline it below. */
+}
+
+
+/* x_sync is a no-op on Mac. */
+void
+x_sync (f)
+ void *f;
+{
+}
+
+
+/* Remove calls to XFlush by defining XFlush to an empty replacement.
+ Calls to XFlush should be unnecessary because the X output buffer
+ is flushed automatically as needed by calls to XPending,
+ XNextEvent, or XWindowEvent according to the XFlush man page.
+ XTread_socket calls XPending. Removing XFlush improves
+ performance. */
+
+#if TARGET_API_MAC_CARBON
+#define XFlush(DISPLAY) QDFlushPortBuffer (GetQDGlobalsThePort (), NULL)
+#else
+#define XFlush(DISPLAY) (void) 0
+#endif
+
+/* Flush display of frame F, or of all frames if F is null. */
+
+void
+x_flush (f)
+ struct frame *f;
+{
+#if TARGET_API_MAC_CARBON
+ BLOCK_INPUT;
+ if (f == NULL)
+ {
+ Lisp_Object rest, frame;
+ FOR_EACH_FRAME (rest, frame)
+ x_flush (XFRAME (frame));
+ }
+ else if (FRAME_X_P (f))
+ XFlush (FRAME_MAC_DISPLAY (f));
+ UNBLOCK_INPUT;
+#endif /* TARGET_API_MAC_CARBON */
+}
+
+
+
+/* Return the struct mac_display_info corresponding to DPY. There's
+ only one. */
+
+struct mac_display_info *
+mac_display_info_for_display (dpy)
+ Display *dpy;
+{
+ return &one_mac_display_info;
+}
+
+
+
+/***********************************************************************
+ Starting and ending an update
+ ***********************************************************************/
+
+/* Start an update of frame F. This function is installed as a hook
+ for update_begin, i.e. it is called when update_begin is called.
+ This function is called prior to calls to x_update_window_begin for
+ each window being updated. */
+
+static void
+x_update_begin (f)
+ struct frame *f;
+{
+ /* Nothing to do. */
+}
+
+
+/* Start update of window W. Set the global variable updated_window
+ to the window being updated and set output_cursor to the cursor
+ position of W. */
+
+static void
+x_update_window_begin (w)
+ struct window *w;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
+
+ updated_window = w;
+ set_output_cursor (&w->cursor);
+
+ BLOCK_INPUT;
+
+ if (f == display_info->mouse_face_mouse_frame)
+ {
+ /* Don't do highlighting for mouse motion during the update. */
+ display_info->mouse_face_defer = 1;
+
+ /* If F needs to be redrawn, simply forget about any prior mouse
+ highlighting. */
+ if (FRAME_GARBAGED_P (f))
+ display_info->mouse_face_window = Qnil;
+
+#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
+ their mouse_face_p flag set, which means that they are always
+ unequal to rows in a desired matrix which never have that
+ flag set. So, rows containing mouse-face glyphs are never
+ scrolled, and we don't have to switch the mouse highlight off
+ here to prevent it from being scrolled. */
+
+ /* Can we tell that this update does not affect the window
+ where the mouse highlight is? If so, no need to turn off.
+ Likewise, don't do anything if the frame is garbaged;
+ in that case, the frame's current matrix that we would use
+ is all wrong, and we will redisplay that line anyway. */
+ if (!NILP (display_info->mouse_face_window)
+ && w == XWINDOW (display_info->mouse_face_window))
+ {
+ int i;
+
+ for (i = 0; i < w->desired_matrix->nrows; ++i)
+ if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
+ break;
+
+ if (i < w->desired_matrix->nrows)
+ clear_mouse_face (display_info);
+ }
+#endif /* 0 */
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+/* Draw a vertical window border to the right of window W if W doesn't
+ have vertical scroll bars. */
+
+static void
+x_draw_vertical_border (w)
+ struct window *w;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ /* Redraw borders between horizontally adjacent windows. Don't
+ do it for frames with vertical scroll bars because either the
+ right scroll bar of a window, or the left scroll bar of its
+ neighbor will suffice as a border. */
+ if (!WINDOW_RIGHTMOST_P (w)
+ && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ {
+ int x0, x1, y0, y1;
+
+ window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+ x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f);
+ y1 -= 1;
+
+ XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ f->output_data.mac->normal_gc, x1, y0, x1, y1);
+ }
+}
+
+
+/* End update of window W (which is equal to updated_window).
+
+ Draw vertical borders between horizontally adjacent windows, and
+ display W's cursor if CURSOR_ON_P is non-zero.
+
+ MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
+ glyphs in mouse-face were overwritten. In that case we have to
+ make sure that the mouse-highlight is properly redrawn.
+
+ W may be a menu bar pseudo-window in case we don't have X toolkit
+ support. Such windows don't have a cursor, so don't display it
+ here. */
+
+static void
+x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
+ struct window *w;
+ int cursor_on_p, mouse_face_overwritten_p;
+{
+ struct mac_display_info *dpyinfo
+ = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
+
+ if (!w->pseudo_window_p)
+ {
+ BLOCK_INPUT;
+
+ if (cursor_on_p)
+ x_display_and_set_cursor (w, 1, output_cursor.hpos,
+ output_cursor.vpos,
+ output_cursor.x, output_cursor.y);
+
+ x_draw_vertical_border (w);
+ UNBLOCK_INPUT;
+ }
+
+ /* If a row with mouse-face was overwritten, arrange for
+ XTframe_up_to_date to redisplay the mouse highlight. */
+ if (mouse_face_overwritten_p)
+ {
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ }
+
+#if 0
+ /* Unhide the caret. This won't actually show the cursor, unless it
+ was visible before the corresponding call to HideCaret in
+ x_update_window_begin. */
+ if (w32_use_visible_system_caret)
+ SendMessage (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0);
+#endif
+
+ updated_window = NULL;
+}
+
+
+/* End update of frame F. This function is installed as a hook in
+ update_end. */
+
+static void
+x_update_end (f)
+ struct frame *f;
+{
+ /* Reset the background color of Mac OS Window to that of the frame after
+ update so that it is used by Mac Toolbox to clear the update region before
+ an update event is generated. */
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (FRAME_MAC_WINDOW (f)));
+#else
+ SetPort (FRAME_MAC_WINDOW (f));
+#endif
+
+ mac_set_backcolor (FRAME_BACKGROUND_PIXEL (f));
+
+ /* Mouse highlight may be displayed again. */
+ FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
+
+ BLOCK_INPUT;
+ XFlush (FRAME_MAC_DISPLAY (f));
+ UNBLOCK_INPUT;
+}
+
+
+/* This function is called from various places in xdisp.c whenever a
+ complete update has been performed. The global variable
+ updated_window is not available here. */
+
+static void
+XTframe_up_to_date (f)
+ struct frame *f;
+{
+ if (FRAME_X_P (f))
+ {
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+
+ if (dpyinfo->mouse_face_deferred_gc
+ || f == dpyinfo->mouse_face_mouse_frame)
+ {
+ BLOCK_INPUT;
+ if (dpyinfo->mouse_face_mouse_frame)
+ note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
+ dpyinfo->mouse_face_mouse_x,
+ dpyinfo->mouse_face_mouse_y);
+ dpyinfo->mouse_face_deferred_gc = 0;
+ UNBLOCK_INPUT;
+ }
+ }
+}
+
+
+/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
+ arrow bitmaps, or clear the fringes if no bitmaps are required
+ before DESIRED_ROW is made current. The window being updated is
+ found in updated_window. This function is called from
+ update_window_line only if it is known that there are differences
+ between bitmaps to be drawn between current row and DESIRED_ROW. */
+
+static void
+x_after_update_window_line (desired_row)
+ struct glyph_row *desired_row;
+{
+ struct window *w = updated_window;
+ struct frame *f;
+ int width, height;
+
+ xassert (w);
+
+ if (!desired_row->mode_line_p && !w->pseudo_window_p)
+ {
+ BLOCK_INPUT;
+ x_draw_row_fringe_bitmaps (w, desired_row);
+ UNBLOCK_INPUT;
+ }
+
+ /* When a window has disappeared, make sure that no rest of
+ full-width rows stays visible in the internal border. Could
+ check here if updated_window is the leftmost/rightmost window,
+ but I guess it's not worth doing since vertically split windows
+ are almost never used, internal border is rarely set, and the
+ overhead is very small. */
+ if (windows_or_buffers_changed
+ && desired_row->full_width_p
+ && (f = XFRAME (w->frame),
+ width = FRAME_INTERNAL_BORDER_WIDTH (f),
+ width != 0)
+ && (height = desired_row->visible_height,
+ height > 0))
+ {
+ int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
+ /* Internal border is drawn below the tool bar. */
+ if (WINDOWP (f->tool_bar_window)
+ && w == XWINDOW (f->tool_bar_window))
+ y -= width;
+
+ BLOCK_INPUT;
+
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ 0, y, width, height, 0);
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ f->output_data.mac->pixel_width - width, y,
+ width, height, 0);
+
+ UNBLOCK_INPUT;
+ }
+}
+
+
+/* Draw the bitmap WHICH in one of the left or right fringes of
+ window W. ROW is the glyph row for which to display the bitmap; it
+ determines the vertical position at which the bitmap has to be
+ drawn. */
+
+static void
+x_draw_fringe_bitmap (w, row, which, left_p)
+ struct window *w;
+ struct glyph_row *row;
+ enum fringe_bitmap_type which;
+ int left_p;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ Display *display = FRAME_MAC_DISPLAY (f);
+ WindowPtr window = FRAME_MAC_WINDOW (f);
+ int x, y, wd, h, dy;
+ int b1, b2;
+ unsigned char *bits;
+ BitMap bitmap;
+ XGCValues gcv;
+ GC gc = f->output_data.mac->normal_gc;
+ struct face *face;
+
+ /* Must clip because of partially visible lines. */
+ x_clip_to_row (w, row, gc, 1);
+
+ /* Convert row to frame coordinates. */
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+
+ switch (which)
+ {
+ case NO_FRINGE_BITMAP:
+ wd = 0;
+ h = 0;
+ break;
+
+ case LEFT_TRUNCATION_BITMAP:
+ wd = left_width;
+ h = left_height;
+ bits = left_bits;
+ break;
+
+ case OVERLAY_ARROW_BITMAP:
+ wd = ov_width;
+ h = ov_height;
+ bits = ov_bits;
+ break;
+
+ case RIGHT_TRUNCATION_BITMAP:
+ wd = right_width;
+ h = right_height;
+ bits = right_bits;
+ break;
+
+ case CONTINUED_LINE_BITMAP:
+ wd = continued_width;
+ h = continued_height;
+ bits = continued_bits;
+ break;
+
+ case CONTINUATION_LINE_BITMAP:
+ wd = continuation_width;
+ h = continuation_height;
+ bits = continuation_bits;
+ break;
+
+ case ZV_LINE_BITMAP:
+ wd = zv_width;
+ h = zv_height - (y % zv_period);
+ bits = zv_bits + (y % zv_period);
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* Clip bitmap if too high. */
+ if (h > row->height)
+ h = row->height;
+
+ /* Set dy to the offset in the row to start drawing the bitmap. */
+ dy = (row->height - h) / 2;
+
+ /* Draw the bitmap. */
+ face = FACE_FROM_ID (f, FRINGE_FACE_ID);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+
+ /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
+ the fringe. */
+ b1 = -1;
+ if (left_p)
+ {
+ if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f))
+ wd = FRAME_X_LEFT_FRINGE_WIDTH (f);
+ x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
+ - wd
+ - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
+ if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h)
+ {
+ /* If W has a vertical border to its left, don't draw over it. */
+ int border = ((XFASTINT (w->left) > 0
+ && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ ? 1 : 0);
+ b1 = (window_box_left (w, -1)
+ - FRAME_X_LEFT_FRINGE_WIDTH (f)
+ + border);
+ b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border);
+ }
+ }
+ else
+ {
+ if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f))
+ wd = FRAME_X_RIGHT_FRINGE_WIDTH (f);
+ x = (window_box_right (w, -1)
+ + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2);
+ /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
+ the fringe. */
+ if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h)
+ {
+ b1 = window_box_right (w, -1);
+ b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f);
+ }
+ }
+
+ if (b1 >= 0)
+ {
+ int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ XGCValues gcv;
+ gcv.foreground = face->background;
+
+#if 0 /* MAC_TODO: stipple */
+ /* In case the same realized face is used for fringes and
+ for something displayed in the text (e.g. face `region' on
+ mono-displays, the fill style may have been changed to
+ FillSolid in x_draw_glyph_string_background. */
+ if (face->stipple)
+ XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
+ else
+ XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
+#endif
+
+ XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ &gcv,
+ b1,
+ WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
+ row->y)),
+ b2,
+ row->visible_height);
+
+#if 0 /* MAC_TODO: stipple */
+ if (!face->stipple)
+ XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
+#endif
+ }
+
+ if (which == NO_FRINGE_BITMAP)
+ {
+ mac_reset_clipping (display, window);
+ return;
+ }
+
+ mac_create_bitmap_from_bitmap_data (&bitmap, bits, wd, h);
+ gcv.foreground = face->foreground;
+ gcv.background = face->background;
+
+ mac_draw_bitmap (display, window, &gcv, x, y + dy, &bitmap);
+
+ mac_free_bitmap (&bitmap);
+ mac_reset_clipping (display, window);
+}
+
+
+/* Draw fringe bitmaps for glyph row ROW on window W. Call this
+ function with input blocked. */
+
+static void
+x_draw_row_fringe_bitmaps (w, row)
+ struct window *w;
+ struct glyph_row *row;
+{
+ struct frame *f = XFRAME (w->frame);
+ enum fringe_bitmap_type bitmap;
+
+ xassert (interrupt_input_blocked);
+
+ /* If row is completely invisible, because of vscrolling, we
+ don't have to draw anything. */
+ if (row->visible_height <= 0)
+ return;
+
+ if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0)
+ {
+ /* Decide which bitmap to draw in the left fringe. */
+ if (row->overlay_arrow_p)
+ bitmap = OVERLAY_ARROW_BITMAP;
+ else if (row->truncated_on_left_p)
+ bitmap = LEFT_TRUNCATION_BITMAP;
+ else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
+ bitmap = CONTINUATION_LINE_BITMAP;
+ else if (row->indicate_empty_line_p)
+ bitmap = ZV_LINE_BITMAP;
+ else
+ bitmap = NO_FRINGE_BITMAP;
+
+ x_draw_fringe_bitmap (w, row, bitmap, 1);
+ }
+
+ if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0)
+ {
+ /* Decide which bitmap to draw in the right fringe. */
+ if (row->truncated_on_right_p)
+ bitmap = RIGHT_TRUNCATION_BITMAP;
+ else if (row->continued_p)
+ bitmap = CONTINUED_LINE_BITMAP;
+ else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0)
+ bitmap = ZV_LINE_BITMAP;
+ else
+ bitmap = NO_FRINGE_BITMAP;
+
+ x_draw_fringe_bitmap (w, row, bitmap, 0);
+ }
+}
+
+
+/* This is called when starting Emacs and when restarting after
+ suspend. When starting Emacs, no window is mapped. And nothing
+ must be done to Emacs's own window if it is suspended (though that
+ rarely happens). */
+
+static void
+XTset_terminal_modes ()
+{
+}
+
+/* This is called when exiting or suspending Emacs. Exiting will make
+ the windows go away, and suspending requires no action. */
+
+static void
+XTreset_terminal_modes ()
+{
+}
+
+
+
+/***********************************************************************
+ Output Cursor
+ ***********************************************************************/
+
+/* Set the global variable output_cursor to CURSOR. All cursor
+ positions are relative to updated_window. */
+
+static void
+set_output_cursor (cursor)
+ struct cursor_pos *cursor;
+{
+ output_cursor.hpos = cursor->hpos;
+ output_cursor.vpos = cursor->vpos;
+ output_cursor.x = cursor->x;
+ output_cursor.y = cursor->y;
+}
+
+
+/* Set a nominal cursor position.
+
+ HPOS and VPOS are column/row positions in a window glyph matrix. X
+ and Y are window text area relative pixel positions.
+
+ If this is done during an update, updated_window will contain the
+ window that is being updated and the position is the future output
+ cursor position for that window. If updated_window is null, use
+ selected_window and display the cursor at the given position. */
+
+static void
+XTcursor_to (vpos, hpos, y, x)
+ int vpos, hpos, y, x;
+{
+ struct window *w;
+
+ /* If updated_window is not set, work on selected_window. */
+ if (updated_window)
+ w = updated_window;
+ else
+ w = XWINDOW (selected_window);
+
+ /* Set the output cursor. */
+ output_cursor.hpos = hpos;
+ output_cursor.vpos = vpos;
+ output_cursor.x = x;
+ output_cursor.y = y;
+
+ /* If not called as part of an update, really display the cursor.
+ This will also set the cursor position of W. */
+ if (updated_window == NULL)
+ {
+ BLOCK_INPUT;
+ x_display_cursor (w, 1, hpos, vpos, x, y);
+ XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
+ UNBLOCK_INPUT;
+ }
+}
+
+
+
+/***********************************************************************
+ Display Iterator
+ ***********************************************************************/
+
+/* Function prototypes of this page. */
+
+static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
+ struct glyph *,
+ XChar2b *,
+ int *));
+static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
+ int, XChar2b *, int));
+static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
+static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
+static void x_append_glyph P_ ((struct it *));
+static void x_append_composite_glyph P_ ((struct it *));
+static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
+ int, int, double));
+static void x_produce_glyphs P_ ((struct it *));
+static void x_produce_image_glyph P_ ((struct it *it));
+
+
+/* Return a pointer to per-char metric information in FONT of a
+ character pointed by B which is a pointer to an XChar2b. */
+
+#define PER_CHAR_METRIC(font, b) \
+ ((font)->per_char \
+ ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
+ + (((font)->min_byte1 || (font)->max_byte1) \
+ ? (((b)->byte1 - (font)->min_byte1) \
+ * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
+ : 0)) \
+ : &((font)->max_bounds))
+
+
+/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
+ is not contained in the font. */
+
+static INLINE XCharStruct *
+x_per_char_metric (font, char2b)
+ XFontStruct *font;
+ XChar2b *char2b;
+{
+ /* The result metric information. */
+ XCharStruct *pcm = NULL;
+
+ xassert (font && char2b);
+
+ if (font->per_char != NULL)
+ {
+ if (font->min_byte1 == 0 && font->max_byte1 == 0)
+ {
+ /* min_char_or_byte2 specifies the linear character index
+ corresponding to the first element of the per_char array,
+ max_char_or_byte2 is the index of the last character. A
+ character with non-zero CHAR2B->byte1 is not in the font.
+ A character with byte2 less than min_char_or_byte2 or
+ greater max_char_or_byte2 is not in the font. */
+ if (char2b->byte1 == 0
+ && char2b->byte2 >= font->min_char_or_byte2
+ && char2b->byte2 <= font->max_char_or_byte2)
+ pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
+ }
+ else
+ {
+ /* If either min_byte1 or max_byte1 are nonzero, both
+ min_char_or_byte2 and max_char_or_byte2 are less than
+ 256, and the 2-byte character index values corresponding
+ to the per_char array element N (counting from 0) are:
+
+ byte1 = N/D + min_byte1
+ byte2 = N\D + min_char_or_byte2
+
+ where:
+
+ D = max_char_or_byte2 - min_char_or_byte2 + 1
+ / = integer division
+ \ = integer modulus */
+ if (char2b->byte1 >= font->min_byte1
+ && char2b->byte1 <= font->max_byte1
+ && char2b->byte2 >= font->min_char_or_byte2
+ && char2b->byte2 <= font->max_char_or_byte2)
+ {
+ pcm = (font->per_char
+ + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
+ * (char2b->byte1 - font->min_byte1))
+ + (char2b->byte2 - font->min_char_or_byte2));
+ }
+ }
+ }
+ else
+ {
+ /* If the per_char pointer is null, all glyphs between the first
+ and last character indexes inclusive have the same
+ information, as given by both min_bounds and max_bounds. */
+ if (char2b->byte2 >= font->min_char_or_byte2
+ && char2b->byte2 <= font->max_char_or_byte2)
+ pcm = &font->max_bounds;
+ }
+
+ return ((pcm == NULL
+ || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
+ ? NULL : pcm);
+}
+
+
+/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
+ the two-byte form of C. Encoding is returned in *CHAR2B. */
+
+static INLINE void
+x_encode_char (c, char2b, font_info)
+ int c;
+ XChar2b *char2b;
+ struct font_info *font_info;
+{
+ int charset = CHAR_CHARSET (c);
+ XFontStruct *font = font_info->font;
+
+ /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
+ This may be either a program in a special encoder language or a
+ fixed encoding. */
+ if (font_info->font_encoder)
+ {
+ /* It's a program. */
+ struct ccl_program *ccl = font_info->font_encoder;
+
+ if (CHARSET_DIMENSION (charset) == 1)
+ {
+ ccl->reg[0] = charset;
+ ccl->reg[1] = char2b->byte2;
+ }
+ else
+ {
+ ccl->reg[0] = charset;
+ ccl->reg[1] = char2b->byte1;
+ ccl->reg[2] = char2b->byte2;
+ }
+
+ ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
+
+ /* We assume that MSBs are appropriately set/reset by CCL
+ program. */
+ if (font->max_byte1 == 0) /* 1-byte font */
+ char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
+ else
+ char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
+ }
+ else if (font_info->encoding[charset])
+ {
+ /* Fixed encoding scheme. See fontset.h for the meaning of the
+ encoding numbers. */
+ int enc = font_info->encoding[charset];
+
+ if ((enc == 1 || enc == 2)
+ && CHARSET_DIMENSION (charset) == 2)
+ char2b->byte1 |= 0x80;
+
+ if (enc == 1 || enc == 3)
+ char2b->byte2 |= 0x80;
+
+ if (enc == 4)
+ {
+ int sjis1, sjis2;
+
+ ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2);
+ char2b->byte1 = sjis1;
+ char2b->byte2 = sjis2;
+ }
+ }
+}
+
+
+/* Get face and two-byte form of character C in face FACE_ID on frame
+ F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
+ means we want to display multibyte text. Value is a pointer to a
+ realized face that is ready for display. */
+
+static INLINE struct face *
+x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
+ struct frame *f;
+ int c, face_id;
+ XChar2b *char2b;
+ int multibyte_p;
+{
+ struct face *face = FACE_FROM_ID (f, face_id);
+
+ if (!multibyte_p)
+ {
+ /* Unibyte case. We don't have to encode, but we have to make
+ sure to use a face suitable for unibyte. */
+ char2b->byte1 = 0;
+ char2b->byte2 = c;
+ face_id = FACE_FOR_CHAR (f, face, c);
+ face = FACE_FROM_ID (f, face_id);
+ }
+ else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
+ {
+ /* Case of ASCII in a face known to fit ASCII. */
+ char2b->byte1 = 0;
+ char2b->byte2 = c;
+ }
+ else
+ {
+ int c1, c2, charset;
+
+ /* Split characters into bytes. If c2 is -1 afterwards, C is
+ really a one-byte character so that byte1 is zero. */
+ SPLIT_CHAR (c, charset, c1, c2);
+ if (c2 > 0)
+ char2b->byte1 = c1, char2b->byte2 = c2;
+ else
+ char2b->byte1 = 0, char2b->byte2 = c1;
+
+ /* Maybe encode the character in *CHAR2B. */
+ if (face->font != NULL)
+ {
+ struct font_info *font_info
+ = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font_info)
+ x_encode_char (c, char2b, font_info);
+ }
+ }
+
+ /* Make sure X resources of the face are allocated. */
+ xassert (face != NULL);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+
+ return face;
+}
+
+
+/* Get face and two-byte form of character glyph GLYPH on frame F.
+ The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
+ a pointer to a realized face that is ready for display. */
+
+static INLINE struct face *
+x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
+ struct frame *f;
+ struct glyph *glyph;
+ XChar2b *char2b;
+ int *two_byte_p;
+{
+ struct face *face;
+
+ xassert (glyph->type == CHAR_GLYPH);
+ face = FACE_FROM_ID (f, glyph->face_id);
+
+ if (two_byte_p)
+ *two_byte_p = 0;
+
+ if (!glyph->multibyte_p)
+ {
+ /* Unibyte case. We don't have to encode, but we have to make
+ sure to use a face suitable for unibyte. */
+ char2b->byte1 = 0;
+ char2b->byte2 = glyph->u.ch;
+ }
+ else if (glyph->u.ch < 128
+ && glyph->face_id < BASIC_FACE_ID_SENTINEL)
+ {
+ /* Case of ASCII in a face known to fit ASCII. */
+ char2b->byte1 = 0;
+ char2b->byte2 = glyph->u.ch;
+ }
+ else
+ {
+ int c1, c2, charset;
+
+ /* Split characters into bytes. If c2 is -1 afterwards, C is
+ really a one-byte character so that byte1 is zero. */
+ SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
+ if (c2 > 0)
+ char2b->byte1 = c1, char2b->byte2 = c2;
+ else
+ char2b->byte1 = 0, char2b->byte2 = c1;
+
+ /* Maybe encode the character in *CHAR2B. */
+ if (charset != CHARSET_ASCII)
+ {
+ struct font_info *font_info
+ = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font_info)
+ {
+ x_encode_char (glyph->u.ch, char2b, font_info);
+ if (two_byte_p)
+ *two_byte_p
+ = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
+ }
+ }
+ }
+
+ /* Make sure X resources of the face are allocated. */
+ xassert (face != NULL);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+ return face;
+}
+
+
+/* Store one glyph for IT->char_to_display in IT->glyph_row.
+ Called from x_produce_glyphs when IT->glyph_row is non-null. */
+
+static INLINE void
+x_append_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (it->glyph_row);
+ xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->voffset = it->voffset;
+ glyph->type = CHAR_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+ || it->phys_descent > it->descent);
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = it->glyph_not_available_p;
+ glyph->face_id = it->face_id;
+ glyph->u.ch = it->char_to_display;
+ ++it->glyph_row->used[area];
+ }
+}
+
+/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
+ Called from x_produce_glyphs when IT->glyph_row is non-null. */
+
+static INLINE void
+x_append_composite_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (it->glyph_row);
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->voffset = it->voffset;
+ glyph->type = COMPOSITE_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+ || it->phys_descent > it->descent);
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.cmp_id = it->cmp_id;
+ ++it->glyph_row->used[area];
+ }
+}
+
+
+/* Change IT->ascent and IT->height according to the setting of
+ IT->voffset. */
+
+static INLINE void
+take_vertical_position_into_account (it)
+ struct it *it;
+{
+ if (it->voffset)
+ {
+ if (it->voffset < 0)
+ /* Increase the ascent so that we can display the text higher
+ in the line. */
+ it->ascent += abs (it->voffset);
+ else
+ /* Increase the descent so that we can display the text lower
+ in the line. */
+ it->descent += it->voffset;
+ }
+}
+
+
+/* Produce glyphs/get display metrics for the image IT is loaded with.
+ See the description of struct display_iterator in dispextern.h for
+ an overview of struct display_iterator. */
+
+static void
+x_produce_image_glyph (it)
+ struct it *it;
+{
+ struct image *img;
+ struct face *face;
+
+ xassert (it->what == IT_IMAGE);
+
+ face = FACE_FROM_ID (it->f, it->face_id);
+ img = IMAGE_FROM_ID (it->f, it->image_id);
+ xassert (img);
+
+ /* Make sure X resources of the face and image are loaded. */
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ prepare_image_for_display (it->f, img);
+
+ it->ascent = it->phys_ascent = image_ascent (img, face);
+ it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
+ it->pixel_width = img->width + 2 * img->hmargin;
+
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ if (it->end_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ {
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->voffset = it->voffset;
+ glyph->type = IMAGE_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.img_id = img->id;
+ ++it->glyph_row->used[area];
+ }
+ }
+}
+
+
+/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
+ of the glyph, WIDTH and HEIGHT are the width and height of the
+ stretch. ASCENT is the percentage/100 of HEIGHT to use for the
+ ascent of the glyph (0 <= ASCENT <= 1). */
+
+static void
+x_append_stretch_glyph (it, object, width, height, ascent)
+ struct it *it;
+ Lisp_Object object;
+ int width, height;
+ double ascent;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (ascent >= 0 && ascent <= 1);
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = object;
+ glyph->pixel_width = width;
+ glyph->voffset = it->voffset;
+ glyph->type = STRETCH_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.stretch.ascent = height * ascent;
+ glyph->u.stretch.height = height;
+ ++it->glyph_row->used[area];
+ }
+}
+
+
+/* Produce a stretch glyph for iterator IT. IT->object is the value
+ of the glyph property displayed. The value must be a list
+ `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+ being recognized:
+
+ 1. `:width WIDTH' specifies that the space should be WIDTH *
+ canonical char width wide. WIDTH may be an integer or floating
+ point number.
+
+ 2. `:relative-width FACTOR' specifies that the width of the stretch
+ should be computed from the width of the first character having the
+ `glyph' property, and should be FACTOR times that width.
+
+ 3. `:align-to HPOS' specifies that the space should be wide enough
+ to reach HPOS, a value in canonical character units.
+
+ Exactly one of the above pairs must be present.
+
+ 4. `:height HEIGHT' specifies that the height of the stretch produced
+ should be HEIGHT, measured in canonical character units.
+
+ 5. `:relative-height FACTOR' specifies that the height of the
+ stretch should be FACTOR times the height of the characters having
+ the glyph property.
+
+ Either none or exactly one of 4 or 5 must be present.
+
+ 6. `:ascent ASCENT' specifies that ASCENT percent of the height
+ of the stretch should be used for the ascent of the stretch.
+ ASCENT must be in the range 0 <= ASCENT <= 100. */
+
+#define NUMVAL(X) \
+ ((INTEGERP (X) || FLOATP (X)) \
+ ? XFLOATINT (X) \
+ : - 1)
+
+
+static void
+x_produce_stretch_glyph (it)
+ struct it *it;
+{
+ /* (space :width WIDTH :height HEIGHT. */
+#if GLYPH_DEBUG
+ extern Lisp_Object Qspace;
+#endif
+ extern Lisp_Object QCwidth, QCheight, QCascent;
+ extern Lisp_Object QCrelative_width, QCrelative_height;
+ extern Lisp_Object QCalign_to;
+ Lisp_Object prop, plist;
+ double width = 0, height = 0, ascent = 0;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
+
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+ /* List should start with `space'. */
+ xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+ plist = XCDR (it->object);
+
+ /* Compute the width of the stretch. */
+ if (prop = Fplist_get (plist, QCwidth),
+ NUMVAL (prop) > 0)
+ /* Absolute width `:width WIDTH' specified and valid. */
+ width = NUMVAL (prop) * CANON_X_UNIT (it->f);
+ else if (prop = Fplist_get (plist, QCrelative_width),
+ NUMVAL (prop) > 0)
+ {
+ /* Relative width `:relative-width FACTOR' specified and valid.
+ Compute the width of the characters having the `glyph'
+ property. */
+ struct it it2;
+ unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
+
+ it2 = *it;
+ if (it->multibyte_p)
+ {
+ int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
+ - IT_BYTEPOS (*it));
+ it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
+ }
+ else
+ it2.c = *p, it2.len = 1;
+
+ it2.glyph_row = NULL;
+ it2.what = IT_CHARACTER;
+ x_produce_glyphs (&it2);
+ width = NUMVAL (prop) * it2.pixel_width;
+ }
+ else if (prop = Fplist_get (plist, QCalign_to),
+ NUMVAL (prop) > 0)
+ width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
+ else
+ /* Nothing specified -> width defaults to canonical char width. */
+ width = CANON_X_UNIT (it->f);
+
+ /* Compute height. */
+ if (prop = Fplist_get (plist, QCheight),
+ NUMVAL (prop) > 0)
+ height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
+ else if (prop = Fplist_get (plist, QCrelative_height),
+ NUMVAL (prop) > 0)
+ height = FONT_HEIGHT (font) * NUMVAL (prop);
+ else
+ height = FONT_HEIGHT (font);
+
+ /* Compute percentage of height used for ascent. If
+ `:ascent ASCENT' is present and valid, use that. Otherwise,
+ derive the ascent from the font in use. */
+ if (prop = Fplist_get (plist, QCascent),
+ NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
+ ascent = NUMVAL (prop) / 100.0;
+ else
+ ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font);
+
+ if (width <= 0)
+ width = 1;
+ if (height <= 0)
+ height = 1;
+
+ if (it->glyph_row)
+ {
+ Lisp_Object object = it->stack[it->sp - 1].string;
+ if (!STRINGP (object))
+ object = it->w->buffer;
+ x_append_stretch_glyph (it, object, width, height, ascent);
+ }
+
+ it->pixel_width = width;
+ it->ascent = it->phys_ascent = height * ascent;
+ it->descent = it->phys_descent = height - it->ascent;
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ if (it->end_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+}
+
+/* Return proper value to be used as baseline offset of font that has
+ ASCENT and DESCENT to draw characters by the font at the vertical
+ center of the line of frame F.
+
+ Here, out task is to find the value of BOFF in the following figure;
+
+ -------------------------+-----------+-
+ -+-+---------+-+ | |
+ | | | | | |
+ | | | | F_ASCENT F_HEIGHT
+ | | | ASCENT | |
+ HEIGHT | | | | |
+ | | |-|-+------+-----------|------- baseline
+ | | | | BOFF | |
+ | |---------|-+-+ | |
+ | | | DESCENT | |
+ -+-+---------+-+ F_DESCENT |
+ -------------------------+-----------+-
+
+ -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
+ BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
+ DESCENT = FONT->descent
+ HEIGHT = FONT_HEIGHT (FONT)
+ F_DESCENT = (F->output_data.x->font->descent
+ - F->output_data.x->baseline_offset)
+ F_HEIGHT = FRAME_LINE_HEIGHT (F)
+*/
+
+#define VCENTER_BASELINE_OFFSET(FONT, F) \
+ (FONT_DESCENT (FONT) \
+ + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
+ + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
+ - (FONT_DESCENT (FRAME_FONT (F)) - FRAME_BASELINE_OFFSET (F)))
+
+/* Produce glyphs/get display metrics for the display element IT is
+ loaded with. See the description of struct display_iterator in
+ dispextern.h for an overview of struct display_iterator. */
+
+static void
+x_produce_glyphs (it)
+ struct it *it;
+{
+ it->glyph_not_available_p = 0;
+
+ if (it->what == IT_CHARACTER)
+ {
+ XChar2b char2b;
+ XFontStruct *font;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XCharStruct *pcm;
+ int font_not_found_p;
+ struct font_info *font_info;
+ int boff; /* baseline offset */
+ /* We may change it->multibyte_p upon unibyte<->multibyte
+ conversion. So, save the current value now and restore it
+ later.
+
+ Note: It seems that we don't have to record multibyte_p in
+ struct glyph because the character code itself tells if or
+ not the character is multibyte. Thus, in the future, we must
+ consider eliminating the field `multibyte_p' in the struct
+ glyph.
+ */
+ int saved_multibyte_p = it->multibyte_p;
+
+ /* Maybe translate single-byte characters to multibyte, or the
+ other way. */
+ it->char_to_display = it->c;
+ if (!ASCII_BYTE_P (it->c))
+ {
+ if (unibyte_display_via_language_environment
+ && SINGLE_BYTE_CHAR_P (it->c)
+ && (it->c >= 0240
+ || !NILP (Vnonascii_translation_table)))
+ {
+ it->char_to_display = unibyte_char_to_multibyte (it->c);
+ it->multibyte_p = 1;
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+ face = FACE_FROM_ID (it->f, it->face_id);
+ }
+ else if (!SINGLE_BYTE_CHAR_P (it->c)
+ && !it->multibyte_p)
+ {
+ it->multibyte_p = 1;
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+ face = FACE_FROM_ID (it->f, it->face_id);
+ }
+ }
+
+ /* Get font to use. Encode IT->char_to_display. */
+ x_get_char_face_and_encoding (it->f, it->char_to_display,
+ it->face_id, &char2b,
+ it->multibyte_p);
+ font = face->font;
+
+ /* When no suitable font found, use the default font. */
+ font_not_found_p = font == NULL;
+ if (font_not_found_p)
+ {
+ font = FRAME_FONT (it->f);
+ boff = it->f->output_data.mac->baseline_offset;
+ font_info = NULL;
+ }
+ else
+ {
+ font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+ boff = font_info->baseline_offset;
+ if (font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ }
+
+ if (it->char_to_display >= ' '
+ && (!it->multibyte_p || it->char_to_display < 128))
+ {
+ /* Either unibyte or ASCII. */
+ int stretched_p;
+
+ it->nglyphs = 1;
+
+ pcm = x_per_char_metric (font, &char2b);
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+
+ if (pcm)
+ {
+ it->phys_ascent = pcm->ascent + boff;
+ it->phys_descent = pcm->descent - boff;
+ it->pixel_width = pcm->width;
+ }
+ else
+ {
+ it->glyph_not_available_p = 1;
+ it->phys_ascent = FONT_BASE (font) + boff;
+ it->phys_descent = FONT_DESCENT (font) - boff;
+ it->pixel_width = FONT_WIDTH (font);
+ }
+
+ /* If this is a space inside a region of text with
+ `space-width' property, change its width. */
+ stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
+ if (stretched_p)
+ it->pixel_width *= XFLOATINT (it->space_width);
+
+ /* If face has a box, add the box thickness to the character
+ height. If character has a box line to the left and/or
+ right, add the box line width to the character's width. */
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = -thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ /* If we have to actually produce glyphs, do it. */
+ if (it->glyph_row)
+ {
+ if (stretched_p)
+ {
+ /* Translate a space with a `space-width' property
+ into a stretch glyph. */
+ double ascent = (double) FONT_BASE (font)
+ / FONT_HEIGHT (font);
+ x_append_stretch_glyph (it, it->object, it->pixel_width,
+ it->ascent + it->descent, ascent);
+ }
+ else
+ x_append_glyph (it);
+
+ /* If characters with lbearing or rbearing are displayed
+ in this line, record that fact in a flag of the
+ glyph row. This is used to optimize X output code. */
+ if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ }
+ }
+ else if (it->char_to_display == '\n')
+ {
+ /* A newline has no width but we need the height of the line. */
+ it->pixel_width = 0;
+ it->nglyphs = 0;
+ it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
+ it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+
+ if (face->box != FACE_NO_BOX
+ && face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+ }
+ else if (it->char_to_display == '\t')
+ {
+ int tab_width = it->tab_width * CANON_X_UNIT (it->f);
+ int x = it->current_x + it->continuation_lines_width;
+ int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
+
+ /* If the distance from the current position to the next tab
+ stop is less than a canonical character width, use the
+ tab stop after that. */
+ if (next_tab_x - x < CANON_X_UNIT (it->f))
+ next_tab_x += tab_width;
+
+ it->pixel_width = next_tab_x - x;
+ it->nglyphs = 1;
+ it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
+ it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+
+ if (it->glyph_row)
+ {
+ double ascent = (double) it->ascent / (it->ascent + it->descent);
+ x_append_stretch_glyph (it, it->object, it->pixel_width,
+ it->ascent + it->descent, ascent);
+ }
+ }
+ else
+ {
+ /* A multi-byte character. Assume that the display width of the
+ character is the width of the character multiplied by the
+ width of the font. */
+
+ /* If we found a font, this font should give us the right
+ metrics. If we didn't find a font, use the frame's
+ default font and calculate the width of the character
+ from the charset width; this is what old redisplay code
+ did. */
+ pcm = x_per_char_metric (font, &char2b);
+ if (font_not_found_p || !pcm)
+ {
+ int charset = CHAR_CHARSET (it->char_to_display);
+
+ it->glyph_not_available_p = 1;
+ it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
+ * CHARSET_WIDTH (charset));
+ it->phys_ascent = FONT_BASE (font) + boff;
+ it->phys_descent = FONT_DESCENT (font) - boff;
+ }
+ else
+ {
+ it->pixel_width = pcm->width;
+ it->phys_ascent = pcm->ascent + boff;
+ it->phys_descent = pcm->descent - boff;
+ if (it->glyph_row
+ && (pcm->lbearing < 0
+ || pcm->rbearing > pcm->width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ }
+ it->nglyphs = 1;
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = - thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ x_append_glyph (it);
+ }
+ it->multibyte_p = saved_multibyte_p;
+ }
+ else if (it->what == IT_COMPOSITION)
+ {
+ /* Note: A composition is represented as one glyph in the
+ glyph matrix. There are no padding glyphs. */
+ XChar2b char2b;
+ XFontStruct *font;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XCharStruct *pcm;
+ int font_not_found_p;
+ struct font_info *font_info;
+ int boff; /* baseline offset */
+ struct composition *cmp = composition_table[it->cmp_id];
+
+ /* Maybe translate single-byte characters to multibyte. */
+ it->char_to_display = it->c;
+ if (unibyte_display_via_language_environment
+ && SINGLE_BYTE_CHAR_P (it->c)
+ && (it->c >= 0240
+ || (it->c >= 0200
+ && !NILP (Vnonascii_translation_table))))
+ {
+ it->char_to_display = unibyte_char_to_multibyte (it->c);
+ }
+
+ /* Get face and font to use. Encode IT->char_to_display. */
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+ face = FACE_FROM_ID (it->f, it->face_id);
+ x_get_char_face_and_encoding (it->f, it->char_to_display,
+ it->face_id, &char2b, it->multibyte_p);
+ font = face->font;
+
+ /* When no suitable font found, use the default font. */
+ font_not_found_p = font == NULL;
+ if (font_not_found_p)
+ {
+ font = FRAME_FONT (it->f);
+ boff = it->f->output_data.mac->baseline_offset;
+ font_info = NULL;
+ }
+ else
+ {
+ font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+ boff = font_info->baseline_offset;
+ if (font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ }
+
+ /* There are no padding glyphs, so there is only one glyph to
+ produce for the composition. Important is that pixel_width,
+ ascent and descent are the values of what is drawn by
+ draw_glyphs (i.e. the values of the overall glyphs composed). */
+ it->nglyphs = 1;
+
+ /* If we have not yet calculated pixel size data of glyphs of
+ the composition for the current face font, calculate them
+ now. Theoretically, we have to check all fonts for the
+ glyphs, but that requires much time and memory space. So,
+ here we check only the font of the first glyph. This leads
+ to incorrect display very rarely, and C-l (recenter) can
+ correct the display anyway. */
+ if (cmp->font != (void *) font)
+ {
+ /* Ascent and descent of the font of the first character of
+ this composition (adjusted by baseline offset). Ascent
+ and descent of overall glyphs should not be less than
+ them respectively. */
+ int font_ascent = FONT_BASE (font) + boff;
+ int font_descent = FONT_DESCENT (font) - boff;
+ /* Bounding box of the overall glyphs. */
+ int leftmost, rightmost, lowest, highest;
+ int i, width, ascent, descent;
+
+ cmp->font = (void *) font;
+
+ /* Initialize the bounding box. */
+ pcm = x_per_char_metric (font, &char2b);
+ if (pcm)
+ {
+ width = pcm->width;
+ ascent = pcm->ascent;
+ descent = pcm->descent;
+ }
+ else
+ {
+ width = FONT_WIDTH (font);
+ ascent = FONT_BASE (font);
+ descent = FONT_DESCENT (font);
+ }
+
+ rightmost = width;
+ lowest = - descent + boff;
+ highest = ascent + boff;
+ leftmost = 0;
+
+ if (font_info
+ && font_info->default_ascent
+ && CHAR_TABLE_P (Vuse_default_ascent)
+ && !NILP (Faref (Vuse_default_ascent,
+ make_number (it->char_to_display))))
+ highest = font_info->default_ascent + boff;
+
+ /* Draw the first glyph at the normal position. It may be
+ shifted to right later if some other glyphs are drawn at
+ the left. */
+ cmp->offsets[0] = 0;
+ cmp->offsets[1] = boff;
+
+ /* Set cmp->offsets for the remaining glyphs. */
+ for (i = 1; i < cmp->glyph_len; i++)
+ {
+ int left, right, btm, top;
+ int ch = COMPOSITION_GLYPH (cmp, i);
+ int face_id = FACE_FOR_CHAR (it->f, face, ch);
+
+ face = FACE_FROM_ID (it->f, face_id);
+ x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
+ it->multibyte_p);
+ font = face->font;
+ if (font == NULL)
+ {
+ font = FRAME_FONT (it->f);
+ boff = it->f->output_data.mac->baseline_offset;
+ font_info = NULL;
+ }
+ else
+ {
+ font_info
+ = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+ boff = font_info->baseline_offset;
+ if (font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ }
+
+ pcm = x_per_char_metric (font, &char2b);
+ if (pcm)
+ {
+ width = pcm->width;
+ ascent = pcm->ascent;
+ descent = pcm->descent;
+ }
+ else
+ {
+ width = FONT_WIDTH (font);
+ ascent = 1;
+ descent = 0;
+ }
+
+ if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
+ {
+ /* Relative composition with or without
+ alternate chars. */
+ left = (leftmost + rightmost - width) / 2;
+ btm = - descent + boff;
+ if (font_info && font_info->relative_compose
+ && (! CHAR_TABLE_P (Vignore_relative_composition)
+ || NILP (Faref (Vignore_relative_composition,
+ make_number (ch)))))
+ {
+
+ if (- descent >= font_info->relative_compose)
+ /* One extra pixel between two glyphs. */
+ btm = highest + 1;
+ else if (ascent <= 0)
+ /* One extra pixel between two glyphs. */
+ btm = lowest - 1 - ascent - descent;
+ }
+ }
+ else
+ {
+ /* A composition rule is specified by an integer
+ value that encodes global and new reference
+ points (GREF and NREF). GREF and NREF are
+ specified by numbers as below:
+
+ 0---1---2 -- ascent
+ | |
+ | |
+ | |
+ 9--10--11 -- center
+ | |
+ ---3---4---5--- baseline
+ | |
+ 6---7---8 -- descent
+ */
+ int rule = COMPOSITION_RULE (cmp, i);
+ int gref, nref, grefx, grefy, nrefx, nrefy;
+
+ COMPOSITION_DECODE_RULE (rule, gref, nref);
+ grefx = gref % 3, nrefx = nref % 3;
+ grefy = gref / 3, nrefy = nref / 3;
+
+ left = (leftmost
+ + grefx * (rightmost - leftmost) / 2
+ - nrefx * width / 2);
+ btm = ((grefy == 0 ? highest
+ : grefy == 1 ? 0
+ : grefy == 2 ? lowest
+ : (highest + lowest) / 2)
+ - (nrefy == 0 ? ascent + descent
+ : nrefy == 1 ? descent - boff
+ : nrefy == 2 ? 0
+ : (ascent + descent) / 2));
+ }
+
+ cmp->offsets[i * 2] = left;
+ cmp->offsets[i * 2 + 1] = btm + descent;
+
+ /* Update the bounding box of the overall glyphs. */
+ right = left + width;
+ top = btm + descent + ascent;
+ if (left < leftmost)
+ leftmost = left;
+ if (right > rightmost)
+ rightmost = right;
+ if (top > highest)
+ highest = top;
+ if (btm < lowest)
+ lowest = btm;
+ }
+
+ /* If there are glyphs whose x-offsets are negative,
+ shift all glyphs to the right and make all x-offsets
+ non-negative. */
+ if (leftmost < 0)
+ {
+ for (i = 0; i < cmp->glyph_len; i++)
+ cmp->offsets[i * 2] -= leftmost;
+ rightmost -= leftmost;
+ }
+
+ cmp->pixel_width = rightmost;
+ cmp->ascent = highest;
+ cmp->descent = - lowest;
+ if (cmp->ascent < font_ascent)
+ cmp->ascent = font_ascent;
+ if (cmp->descent < font_descent)
+ cmp->descent = font_descent;
+ }
+
+ it->pixel_width = cmp->pixel_width;
+ it->ascent = it->phys_ascent = cmp->ascent;
+ it->descent = it->phys_descent = cmp->descent;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = - thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ x_append_composite_glyph (it);
+ }
+ else if (it->what == IT_IMAGE)
+ x_produce_image_glyph (it);
+ else if (it->what == IT_STRETCH)
+ x_produce_stretch_glyph (it);
+
+ /* Accumulate dimensions. Note: can't assume that it->descent > 0
+ because this isn't true for images with `:ascent 100'. */
+ xassert (it->ascent >= 0 && it->descent >= 0);
+ if (it->area == TEXT_AREA)
+ it->current_x += it->pixel_width;
+
+ it->descent += it->extra_line_spacing;
+
+ it->max_ascent = max (it->max_ascent, it->ascent);
+ it->max_descent = max (it->max_descent, it->descent);
+ it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
+ it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
+}
+
+
+/* Estimate the pixel height of the mode or top line on frame F.
+ FACE_ID specifies what line's height to estimate. */
+
+int
+x_estimate_mode_line_height (f, face_id)
+ struct frame *f;
+ enum face_id face_id;
+{
+ int height = FONT_HEIGHT (FRAME_FONT (f));
+
+ /* This function is called so early when Emacs starts that the face
+ cache and mode line face are not yet initialized. */
+ if (FRAME_FACE_CACHE (f))
+ {
+ struct face *face = FACE_FROM_ID (f, face_id);
+ if (face)
+ {
+ if (face->font)
+ height = FONT_HEIGHT (face->font);
+ if (face->box_line_width > 0)
+ height += 2 * face->box_line_width;
+ }
+ }
+
+ return height;
+}
+
+
+/***********************************************************************
+ Glyph display
+ ***********************************************************************/
+
+/* A sequence of glyphs to be drawn in the same face.
+
+ This data structure is not really completely X specific, so it
+ could possibly, at least partially, be useful for other systems. It
+ is currently not part of the external redisplay interface because
+ it's not clear what other systems will need. */
+
+struct glyph_string
+{
+ /* X-origin of the string. */
+ int x;
+
+ /* Y-origin and y-position of the base line of this string. */
+ int y, ybase;
+
+ /* The width of the string, not including a face extension. */
+ int width;
+
+ /* The width of the string, including a face extension. */
+ int background_width;
+
+ /* The height of this string. This is the height of the line this
+ string is drawn in, and can be different from the height of the
+ font the string is drawn in. */
+ int height;
+
+ /* Number of pixels this string overwrites in front of its x-origin.
+ This number is zero if the string has an lbearing >= 0; it is
+ -lbearing, if the string has an lbearing < 0. */
+ int left_overhang;
+
+ /* Number of pixels this string overwrites past its right-most
+ nominal x-position, i.e. x + width. Zero if the string's
+ rbearing is <= its nominal width, rbearing - width otherwise. */
+ int right_overhang;
+
+ /* The frame on which the glyph string is drawn. */
+ struct frame *f;
+
+ /* The window on which the glyph string is drawn. */
+ struct window *w;
+
+ /* X display and window for convenience. */
+ Display *display;
+ Window window;
+
+ /* The glyph row for which this string was built. It determines the
+ y-origin and height of the string. */
+ struct glyph_row *row;
+
+ /* The area within row. */
+ enum glyph_row_area area;
+
+ /* Characters to be drawn, and number of characters. */
+ XChar2b *char2b;
+ int nchars;
+
+ /* A face-override for drawing cursors, mouse face and similar. */
+ enum draw_glyphs_face hl;
+
+ /* Face in which this string is to be drawn. */
+ struct face *face;
+
+ /* Font in which this string is to be drawn. */
+ XFontStruct *font;
+
+ /* Font info for this string. */
+ struct font_info *font_info;
+
+ /* Non-null means this string describes (part of) a composition.
+ All characters from char2b are drawn composed. */
+ struct composition *cmp;
+
+ /* Index of this glyph string's first character in the glyph
+ definition of CMP. If this is zero, this glyph string describes
+ the first character of a composition. */
+ int gidx;
+
+ /* 1 means this glyph strings face has to be drawn to the right end
+ of the window's drawing area. */
+ unsigned extends_to_end_of_line_p : 1;
+
+ /* 1 means the background of this string has been drawn. */
+ unsigned background_filled_p : 1;
+
+ /* 1 means glyph string must be drawn with 16-bit functions. */
+ unsigned two_byte_p : 1;
+
+ /* 1 means that the original font determined for drawing this glyph
+ string could not be loaded. The member `font' has been set to
+ the frame's default font in this case. */
+ unsigned font_not_found_p : 1;
+
+ /* 1 means that the face in which this glyph string is drawn has a
+ stipple pattern. */
+ unsigned stippled_p : 1;
+
+ /* 1 means only the foreground of this glyph string must be drawn,
+ and we should use the physical height of the line this glyph
+ string appears in as clip rect. */
+ unsigned for_overlaps_p : 1;
+
+ /* The GC to use for drawing this glyph string. */
+ GC gc;
+
+ /* A pointer to the first glyph in the string. This glyph
+ corresponds to char2b[0]. Needed to draw rectangles if
+ font_not_found_p is 1. */
+ struct glyph *first_glyph;
+
+ /* Image, if any. */
+ struct image *img;
+
+ struct glyph_string *next, *prev;
+};
+
+
+#if 0
+
+static void
+x_dump_glyph_string (s)
+ struct glyph_string *s;
+{
+ fprintf (stderr, "glyph string\n");
+ fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
+ s->x, s->y, s->width, s->height);
+ fprintf (stderr, " ybase = %d\n", s->ybase);
+ fprintf (stderr, " hl = %d\n", s->hl);
+ fprintf (stderr, " left overhang = %d, right = %d\n",
+ s->left_overhang, s->right_overhang);
+ fprintf (stderr, " nchars = %d\n", s->nchars);
+ fprintf (stderr, " extends to end of line = %d\n",
+ s->extends_to_end_of_line_p);
+ fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
+ fprintf (stderr, " bg width = %d\n", s->background_width);
+}
+
+#endif /* GLYPH_DEBUG */
+
+
+
+static void x_append_glyph_string_lists P_ ((struct glyph_string **,
+ struct glyph_string **,
+ struct glyph_string *,
+ struct glyph_string *));
+static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
+ struct glyph_string **,
+ struct glyph_string *,
+ struct glyph_string *));
+static void x_append_glyph_string P_ ((struct glyph_string **,
+ struct glyph_string **,
+ struct glyph_string *));
+static int x_left_overwritten P_ ((struct glyph_string *));
+static int x_left_overwriting P_ ((struct glyph_string *));
+static int x_right_overwritten P_ ((struct glyph_string *));
+static int x_right_overwriting P_ ((struct glyph_string *));
+static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
+ int));
+static void x_init_glyph_string P_ ((struct glyph_string *,
+ XChar2b *, struct window *,
+ struct glyph_row *,
+ enum glyph_row_area, int,
+ enum draw_glyphs_face));
+static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
+ enum glyph_row_area, int, int,
+ enum draw_glyphs_face, int));
+static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
+static void x_set_glyph_string_gc P_ ((struct glyph_string *));
+static void x_draw_glyph_string_background P_ ((struct glyph_string *,
+ int));
+static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
+static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
+static void x_draw_glyph_string_box P_ ((struct glyph_string *));
+static void x_draw_glyph_string P_ ((struct glyph_string *));
+static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
+static void x_set_cursor_gc P_ ((struct glyph_string *));
+static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
+static void x_set_mouse_face_gc P_ ((struct glyph_string *));
+static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
+ int *, int *));
+static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
+/*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
+ unsigned long *, double, int));*/
+static void x_setup_relief_color P_ ((struct frame *, struct relief *,
+ double, int, unsigned long));
+static void x_setup_relief_colors P_ ((struct glyph_string *));
+static void x_draw_image_glyph_string P_ ((struct glyph_string *));
+static void x_draw_image_relief P_ ((struct glyph_string *));
+static void x_draw_image_foreground P_ ((struct glyph_string *));
+static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
+static void x_fill_image_glyph_string P_ ((struct glyph_string *));
+static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
+ int, int, int));
+static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
+ int, int, int, int, Rect *));
+static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
+ int, int, int, Rect *));
+static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
+ enum glyph_row_area));
+static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
+ struct glyph_row *,
+ enum glyph_row_area, int, int));
+
+#if GLYPH_DEBUG
+static void x_check_font P_ ((struct frame *, XFontStruct *));
+#endif
+
+
+/* Append the list of glyph strings with head H and tail T to the list
+ with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
+
+static INLINE void
+x_append_glyph_string_lists (head, tail, h, t)
+ struct glyph_string **head, **tail;
+ struct glyph_string *h, *t;
+{
+ if (h)
+ {
+ if (*head)
+ (*tail)->next = h;
+ else
+ *head = h;
+ h->prev = *tail;
+ *tail = t;
+ }
+}
+
+
+/* Prepend the list of glyph strings with head H and tail T to the
+ list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
+ result. */
+
+static INLINE void
+x_prepend_glyph_string_lists (head, tail, h, t)
+ struct glyph_string **head, **tail;
+ struct glyph_string *h, *t;
+{
+ if (h)
+ {
+ if (*head)
+ (*head)->prev = t;
+ else
+ *tail = t;
+ t->next = *head;
+ *head = h;
+ }
+}
+
+
+/* Append glyph string S to the list with head *HEAD and tail *TAIL.
+ Set *HEAD and *TAIL to the resulting list. */
+
+static INLINE void
+x_append_glyph_string (head, tail, s)
+ struct glyph_string **head, **tail;
+ struct glyph_string *s;
+{
+ s->next = s->prev = NULL;
+ x_append_glyph_string_lists (head, tail, s, s);
+}
+
+
+/* Set S->gc to a suitable GC for drawing glyph string S in cursor
+ face. */
+
+static void
+x_set_cursor_gc (s)
+ struct glyph_string *s;
+{
+ if (s->font == FRAME_FONT (s->f)
+ && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
+ && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
+ && !s->cmp)
+ s->gc = s->f->output_data.mac->cursor_gc;
+ else
+ {
+ /* Cursor on non-default face: must merge. */
+ XGCValues xgcv;
+ unsigned long mask;
+
+ xgcv.background = s->f->output_data.mac->cursor_pixel;
+ xgcv.foreground = s->face->background;
+
+ /* If the glyph would be invisible, try a different foreground. */
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->face->foreground;
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->face->foreground;
+
+ /* Make sure the cursor is distinct from text in this face. */
+ if (xgcv.background == s->face->background
+ && xgcv.foreground == s->face->foreground)
+ {
+ xgcv.background = s->face->foreground;
+ xgcv.foreground = s->face->background;
+ }
+
+ IF_DEBUG (x_check_font (s->f, s->font));
+ xgcv.font = s->font;
+ mask = GCForeground | GCBackground | GCFont;
+
+ if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+ XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+ mask, &xgcv);
+ else
+ FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
+ = XCreateGC (s->display, s->window, mask, &xgcv);
+
+ s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+ }
+}
+
+
+/* Set up S->gc of glyph string S for drawing text in mouse face. */
+
+static void
+x_set_mouse_face_gc (s)
+ struct glyph_string *s;
+{
+ int face_id;
+ struct face *face;
+
+ /* What face has to be used last for the mouse face? */
+ face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
+ face = FACE_FROM_ID (s->f, face_id);
+ if (face == NULL)
+ face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+
+ if (s->first_glyph->type == CHAR_GLYPH)
+ face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
+ else
+ face_id = FACE_FOR_CHAR (s->f, face, 0);
+ s->face = FACE_FROM_ID (s->f, face_id);
+ PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+
+ /* If font in this face is same as S->font, use it. */
+ if (s->font == s->face->font)
+ s->gc = s->face->gc;
+ else
+ {
+ /* Otherwise construct scratch_cursor_gc with values from FACE
+ but font FONT. */
+ XGCValues xgcv;
+ unsigned long mask;
+
+ xgcv.background = s->face->background;
+ xgcv.foreground = s->face->foreground;
+ IF_DEBUG (x_check_font (s->f, s->font));
+ xgcv.font = s->font;
+ mask = GCForeground | GCBackground | GCFont;
+
+ if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+ XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+ mask, &xgcv);
+ else
+ FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
+ = XCreateGC (s->display, s->window, mask, &xgcv);
+
+ s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+ }
+
+ xassert (s->gc != 0);
+}
+
+
+/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
+ Faces to use in the mode line have already been computed when the
+ matrix was built, so there isn't much to do, here. */
+
+static INLINE void
+x_set_mode_line_face_gc (s)
+ struct glyph_string *s;
+{
+ s->gc = s->face->gc;
+}
+
+
+/* Set S->gc of glyph string S for drawing that glyph string. Set
+ S->stippled_p to a non-zero value if the face of S has a stipple
+ pattern. */
+
+static INLINE void
+x_set_glyph_string_gc (s)
+ struct glyph_string *s;
+{
+ PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+
+ if (s->hl == DRAW_NORMAL_TEXT)
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_INVERSE_VIDEO)
+ {
+ x_set_mode_line_face_gc (s);
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_CURSOR)
+ {
+ x_set_cursor_gc (s);
+ s->stippled_p = 0;
+ }
+ else if (s->hl == DRAW_MOUSE_FACE)
+ {
+ x_set_mouse_face_gc (s);
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+
+ /* GC must have been set. */
+ xassert (s->gc != 0);
+}
+
+
+/* Return in *R the clipping rectangle for glyph string S. */
+
+static void
+x_get_glyph_string_clip_rect (s, r)
+ struct glyph_string *s;
+ Rect *r;
+{
+ int r_height, r_width;
+
+ if (s->row->full_width_p)
+ {
+ /* Draw full-width. X coordinates are relative to S->w->left. */
+ int canon_x = CANON_X_UNIT (s->f);
+
+ r->left = WINDOW_LEFT_MARGIN (s->w) * canon_x;
+ r_width = XFASTINT (s->w->width) * canon_x;
+
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
+ {
+ int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
+ r->left -= width;
+ }
+
+ r->left += FRAME_INTERNAL_BORDER_WIDTH (s->f);
+
+ /* Unless displaying a mode or menu bar line, which are always
+ fully visible, clip to the visible part of the row. */
+ if (s->w->pseudo_window_p)
+ r_height = s->row->visible_height;
+ else
+ r_height = s->height;
+ }
+ else
+ {
+ /* This is a text line that may be partially visible. */
+ r->left = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
+ r_width = window_box_width (s->w, s->area);
+ r_height = s->row->visible_height;
+ }
+
+ /* If S draws overlapping rows, it's sufficient to use the top and
+ bottom of the window for clipping because this glyph string
+ intentionally draws over other lines. */
+ if (s->for_overlaps_p)
+ {
+ r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+ r_height = window_text_bottom_y (s->w) - r->top;
+ }
+ else
+ {
+ /* Don't use S->y for clipping because it doesn't take partially
+ visible lines into account. For example, it can be negative for
+ partially visible lines at the top of a window. */
+ if (!s->row->full_width_p
+ && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
+ r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+ else
+ r->top = max (0, s->row->y);
+
+ /* If drawing a tool-bar window, draw it over the internal border
+ at the top of the window. */
+ if (s->w == XWINDOW (s->f->tool_bar_window))
+ r->top -= s->f->output_data.mac->internal_border_width;
+ }
+
+ r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top);
+
+ r->bottom = r->top + r_height;
+ r->right = r->left + r_width;
+}
+
+
+/* Set clipping for output of glyph string S. S may be part of a mode
+ line or menu if we don't have X toolkit support. */
+
+static INLINE void
+x_set_glyph_string_clipping (s)
+ struct glyph_string *s;
+{
+ Rect r;
+ x_get_glyph_string_clip_rect (s, &r);
+ mac_set_clip_rectangle (s->display, s->window, &r);
+}
+
+
+/* Compute left and right overhang of glyph string S. If S is a glyph
+ string for a composition, assume overhangs don't exist. */
+
+static INLINE void
+x_compute_glyph_string_overhangs (s)
+ struct glyph_string *s;
+{
+ if (s->cmp == NULL
+ && s->first_glyph->type == CHAR_GLYPH)
+ {
+ XCharStruct cs;
+ int direction, font_ascent, font_descent;
+ XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
+ &font_ascent, &font_descent, &cs);
+ s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
+ s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
+ }
+}
+
+
+/* Compute overhangs and x-positions for glyph string S and its
+ predecessors, or successors. X is the starting x-position for S.
+ BACKWARD_P non-zero means process predecessors. */
+
+static void
+x_compute_overhangs_and_x (s, x, backward_p)
+ struct glyph_string *s;
+ int x;
+ int backward_p;
+{
+ if (backward_p)
+ {
+ while (s)
+ {
+ x_compute_glyph_string_overhangs (s);
+ x -= s->width;
+ s->x = x;
+ s = s->prev;
+ }
+ }
+ else
+ {
+ while (s)
+ {
+ x_compute_glyph_string_overhangs (s);
+ s->x = x;
+ x += s->width;
+ s = s->next;
+ }
+ }
+}
+
+
+/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
+ frame F. Overhangs of glyphs other than type CHAR_GLYPH are
+ assumed to be zero. */
+
+void
+x_get_glyph_overhangs (glyph, f, left, right)
+ struct glyph *glyph;
+ struct frame *f;
+ int *left, *right;
+{
+ *left = *right = 0;
+
+ if (glyph->type == CHAR_GLYPH)
+ {
+ XFontStruct *font;
+ struct face *face;
+ struct font_info *font_info;
+ XChar2b char2b;
+ XCharStruct *pcm;
+
+ face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
+ font = face->font;
+ font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font
+ && (pcm = x_per_char_metric (font, &char2b)))
+ {
+ if (pcm->rbearing > pcm->width)
+ *right = pcm->rbearing - pcm->width;
+ if (pcm->lbearing < 0)
+ *left = -pcm->lbearing;
+ }
+ }
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+ is overwritten by S because of S's left overhang. Value is -1
+ if no glyphs are overwritten. */
+
+static int
+x_left_overwritten (s)
+ struct glyph_string *s;
+{
+ int k;
+
+ if (s->left_overhang)
+ {
+ int x = 0, i;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = s->first_glyph - glyphs;
+
+ for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
+ x -= glyphs[i].pixel_width;
+
+ k = i + 1;
+ }
+ else
+ k = -1;
+
+ return k;
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+ is overwriting S because of its right overhang. Value is -1 if no
+ glyph in front of S overwrites S. */
+
+static int
+x_left_overwriting (s)
+ struct glyph_string *s;
+{
+ int i, k, x;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = s->first_glyph - glyphs;
+
+ k = -1;
+ x = 0;
+ for (i = first - 1; i >= 0; --i)
+ {
+ int left, right;
+ x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+ if (x + right > 0)
+ k = i;
+ x -= glyphs[i].pixel_width;
+ }
+
+ return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that is
+ not overwritten by S because of S's right overhang. Value is -1 if
+ no such glyph is found. */
+
+static int
+x_right_overwritten (s)
+ struct glyph_string *s;
+{
+ int k = -1;
+
+ if (s->right_overhang)
+ {
+ int x = 0, i;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+ int end = s->row->used[s->area];
+
+ for (i = first; i < end && s->right_overhang > x; ++i)
+ x += glyphs[i].pixel_width;
+
+ k = i;
+ }
+
+ return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that
+ overwrites S because of its left overhang. Value is negative
+ if no such glyph is found. */
+
+static int
+x_right_overwriting (s)
+ struct glyph_string *s;
+{
+ int i, k, x;
+ int end = s->row->used[s->area];
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+
+ k = -1;
+ x = 0;
+ for (i = first; i < end; ++i)
+ {
+ int left, right;
+ x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+ if (x - left < 0)
+ k = i;
+ x += glyphs[i].pixel_width;
+ }
+
+ return k;
+}
+
+
+/* Fill rectangle X, Y, W, H with background color of glyph string S. */
+
+static INLINE void
+x_clear_glyph_string_rect (s, x, y, w, h)
+ struct glyph_string *s;
+ int x, y, w, h;
+{
+ XGCValues xgcv;
+
+ xgcv.foreground = s->gc->background;
+ XFillRectangle (s->display, s->window, &xgcv, x, y, w, h);
+}
+
+
+/* Draw the background of glyph_string S. If S->background_filled_p
+ is non-zero don't draw it. FORCE_P non-zero means draw the
+ background even if it wouldn't be drawn normally. This is used
+ when a string preceding S draws into the background of S, or S
+ contains the first component of a composition. */
+
+static void
+x_draw_glyph_string_background (s, force_p)
+ struct glyph_string *s;
+ int force_p;
+{
+ /* Nothing to do if background has already been drawn or if it
+ shouldn't be drawn in the first place. */
+ if (!s->background_filled_p)
+ {
+ int box_line_width = max (s->face->box_line_width, 0);
+
+#if 0 /* MAC_TODO: stipple */
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, s->gc, s->x,
+ s->y + box_line_width,
+ s->background_width,
+ s->height - 2 * box_line_width);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ s->background_filled_p = 1;
+ }
+ else
+#endif
+ if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
+ || s->font_not_found_p
+ || s->extends_to_end_of_line_p
+ || force_p)
+ {
+ x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
+ s->background_width,
+ s->height - 2 * box_line_width);
+ s->background_filled_p = 1;
+ }
+ }
+}
+
+
+/* Draw the foreground of glyph string S. */
+
+static void
+x_draw_glyph_string_foreground (s)
+ struct glyph_string *s;
+{
+ int i, x;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* Draw characters of S as rectangles if S's font could not be
+ loaded. */
+ if (s->font_not_found_p)
+ {
+ for (i = 0; i < s->nchars; ++i)
+ {
+ struct glyph *g = s->first_glyph + i;
+ mac_draw_rectangle (s->display, s->window,
+ s->gc, x, s->y, g->pixel_width - 1,
+ s->height - 1);
+ x += g->pixel_width;
+ }
+ }
+ else
+ {
+ char *char1b = (char *) s->char2b;
+ int boff = s->font_info->baseline_offset;
+
+ if (s->font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
+
+ /* If we can use 8-bit functions, condense S->char2b. */
+ if (!s->two_byte_p)
+ for (i = 0; i < s->nchars; ++i)
+ char1b[i] = s->char2b[i].byte2;
+
+ /* Draw text with XDrawString if background has already been
+ filled. Otherwise, use XDrawImageString. (Note that
+ XDrawImageString is usually faster than XDrawString.) Always
+ use XDrawImageString when drawing the cursor so that there is
+ no chance that characters under a box cursor are invisible. */
+ if (s->for_overlaps_p
+ || (s->background_filled_p && s->hl != DRAW_CURSOR))
+ {
+ /* Draw characters with 16-bit or 8-bit functions. */
+ if (s->two_byte_p)
+ XDrawString16 (s->display, s->window, s->gc, x,
+ s->ybase - boff, s->char2b, s->nchars);
+ else
+ XDrawString (s->display, s->window, s->gc, x,
+ s->ybase - boff, char1b, s->nchars);
+ }
+ else
+ {
+ if (s->two_byte_p)
+ XDrawImageString16 (s->display, s->window, s->gc, x,
+ s->ybase - boff, s->char2b, s->nchars);
+ else
+ XDrawImageString (s->display, s->window, s->gc, x,
+ s->ybase - boff, char1b, s->nchars);
+ }
+ }
+}
+
+/* Draw the foreground of composite glyph string S. */
+
+static void
+x_draw_composite_glyph_string_foreground (s)
+ struct glyph_string *s;
+{
+ int i, x;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* S is a glyph string for a composition. S->gidx is the index of
+ the first character drawn for glyphs of this composition.
+ S->gidx == 0 means we are drawing the very first character of
+ this composition. */
+
+ /* Draw a rectangle for the composition if the font for the very
+ first character of the composition could not be loaded. */
+ if (s->font_not_found_p)
+ {
+ if (s->gidx == 0)
+ mac_draw_rectangle (s->display, s->window, s->gc, x, s->y,
+ s->width - 1, s->height - 1);
+ }
+ else
+ {
+ for (i = 0; i < s->nchars; i++, ++s->gidx)
+ XDrawString16 (s->display, s->window, s->gc,
+ x + s->cmp->offsets[s->gidx * 2],
+ s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
+ s->char2b + i, 1);
+ }
+}
+
+
+#ifdef USE_X_TOOLKIT
+
+static struct frame *x_frame_of_widget P_ ((Widget));
+
+
+/* Return the frame on which widget WIDGET is used.. Abort if frame
+ cannot be determined. */
+
+static struct frame *
+x_frame_of_widget (widget)
+ Widget widget;
+{
+ struct x_display_info *dpyinfo;
+ Lisp_Object tail;
+ struct frame *f;
+
+ dpyinfo = x_display_info_for_display (XtDisplay (widget));
+
+ /* Find the top-level shell of the widget. Note that this function
+ can be called when the widget is not yet realized, so XtWindow
+ (widget) == 0. That's the reason we can't simply use
+ x_any_window_to_frame. */
+ while (!XtIsTopLevelShell (widget))
+ widget = XtParent (widget);
+
+ /* Look for a frame with that top-level widget. Allocate the color
+ on that frame to get the right gamma correction value. */
+ for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+ if (GC_FRAMEP (XCAR (tail))
+ && (f = XFRAME (XCAR (tail)),
+ (f->output_data.nothing != 1
+ && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
+ && f->output_data.x->widget == widget)
+ return f;
+
+ abort ();
+}
+
+
+/* Allocate the color COLOR->pixel on the screen and display of
+ widget WIDGET in colormap CMAP. If an exact match cannot be
+ allocated, try the nearest color available. Value is non-zero
+ if successful. This is called from lwlib. */
+
+int
+x_alloc_nearest_color_for_widget (widget, cmap, color)
+ Widget widget;
+ Colormap cmap;
+ XColor *color;
+{
+ struct frame *f = x_frame_of_widget (widget);
+ return x_alloc_nearest_color (f, cmap, color);
+}
+
+
+#endif /* USE_X_TOOLKIT */
+
+#if 0 /* MAC_TODO */
+
+/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
+ CMAP. If an exact match can't be allocated, try the nearest color
+ available. Value is non-zero if successful. Set *COLOR to the
+ color allocated. */
+
+int
+x_alloc_nearest_color (f, cmap, color)
+ struct frame *f;
+ Colormap cmap;
+ XColor *color;
+{
+ Display *display = FRAME_X_DISPLAY (f);
+ Screen *screen = FRAME_X_SCREEN (f);
+ int rc;
+
+ gamma_correct (f, color);
+ rc = XAllocColor (display, cmap, color);
+ if (rc == 0)
+ {
+ /* If we got to this point, the colormap is full, so we're going
+ to try to get the next closest color. The algorithm used is
+ a least-squares matching, which is what X uses for closest
+ color matching with StaticColor visuals. */
+ int nearest, i;
+ unsigned long nearest_delta = ~0;
+ int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
+ XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
+
+ for (i = 0; i < ncells; ++i)
+ cells[i].pixel = i;
+ XQueryColors (display, cmap, cells, ncells);
+
+ for (nearest = i = 0; i < ncells; ++i)
+ {
+ long dred = (color->red >> 8) - (cells[i].red >> 8);
+ long dgreen = (color->green >> 8) - (cells[i].green >> 8);
+ long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
+ unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
+
+ if (delta < nearest_delta)
+ {
+ nearest = i;
+ nearest_delta = delta;
+ }
+ }
+
+ color->red = cells[nearest].red;
+ color->green = cells[nearest].green;
+ color->blue = cells[nearest].blue;
+ rc = XAllocColor (display, cmap, color);
+ }
+
+#ifdef DEBUG_X_COLORS
+ if (rc)
+ register_color (color->pixel);
+#endif /* DEBUG_X_COLORS */
+
+ return rc;
+}
+
+
+/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
+ It's necessary to do this instead of just using PIXEL directly to
+ get color reference counts right. */
+
+unsigned long
+x_copy_color (f, pixel)
+ struct frame *f;
+ unsigned long pixel;
+{
+ XColor color;
+
+ color.pixel = pixel;
+ BLOCK_INPUT;
+ XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
+ XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
+ UNBLOCK_INPUT;
+#ifdef DEBUG_X_COLORS
+ register_color (pixel);
+#endif
+ return color.pixel;
+}
+
+
+/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
+ It's necessary to do this instead of just using PIXEL directly to
+ get color reference counts right. */
+
+unsigned long
+x_copy_dpy_color (dpy, cmap, pixel)
+ Display *dpy;
+ Colormap cmap;
+ unsigned long pixel;
+{
+ XColor color;
+
+ color.pixel = pixel;
+ BLOCK_INPUT;
+ XQueryColor (dpy, cmap, &color);
+ XAllocColor (dpy, cmap, &color);
+ UNBLOCK_INPUT;
+#ifdef DEBUG_X_COLORS
+ register_color (pixel);
+#endif
+ return color.pixel;
+}
+
+#endif /* MAC_TODO */
+
+/* Allocate a color which is lighter or darker than *COLOR by FACTOR
+ or DELTA. Try a color with RGB values multiplied by FACTOR first.
+ If this produces the same color as COLOR, try a color where all RGB
+ values have DELTA added. Return the allocated color in *COLOR.
+ DISPLAY is the X display, CMAP is the colormap to operate on.
+ Value is non-zero if successful. */
+
+static int
+mac_alloc_lighter_color (f, color, factor, delta)
+ struct frame *f;
+ unsigned long *color;
+ double factor;
+ int delta;
+{
+ unsigned long new;
+
+ /* Change RGB values by specified FACTOR. Avoid overflow! */
+ xassert (factor >= 0);
+ new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
+ min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
+ min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
+ if (new == *color)
+ new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
+ max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
+ max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
+
+ /* MAC_TODO: Map to palette and retry with delta if same? */
+ /* MAC_TODO: Free colors (if using palette)? */
+
+ if (new == *color)
+ return 0;
+
+ *color = new;
+
+ return 1;
+}
+
+
+/* Set up the foreground color for drawing relief lines of glyph
+ string S. RELIEF is a pointer to a struct relief containing the GC
+ with which lines will be drawn. Use a color that is FACTOR or
+ DELTA lighter or darker than the relief's background which is found
+ in S->f->output_data.x->relief_background. If such a color cannot
+ be allocated, use DEFAULT_PIXEL, instead. */
+
+static void
+x_setup_relief_color (f, relief, factor, delta, default_pixel)
+ struct frame *f;
+ struct relief *relief;
+ double factor;
+ int delta;
+ unsigned long default_pixel;
+{
+ XGCValues xgcv;
+ struct mac_output *di = f->output_data.mac;
+ unsigned long mask = GCForeground;
+ unsigned long pixel;
+ unsigned long background = di->relief_background;
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+
+ /* MAC_TODO: Free colors (if using palette)? */
+
+ /* Allocate new color. */
+ xgcv.foreground = default_pixel;
+ pixel = background;
+ if (mac_alloc_lighter_color (f, &pixel, factor, delta))
+ {
+ relief->allocated_p = 1;
+ xgcv.foreground = relief->pixel = pixel;
+ }
+
+ if (relief->gc == 0)
+ {
+#if 0 /* MAC_TODO: stipple */
+ xgcv.stipple = dpyinfo->gray;
+ mask |= GCStipple;
+#endif
+ relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
+ }
+ else
+ XChangeGC (NULL, relief->gc, mask, &xgcv);
+}
+
+
+/* Set up colors for the relief lines around glyph string S. */
+
+static void
+x_setup_relief_colors (s)
+ struct glyph_string *s;
+{
+ struct mac_output *di = s->f->output_data.mac;
+ unsigned long color;
+
+ if (s->face->use_box_color_for_shadows_p)
+ color = s->face->box_color;
+ else
+ {
+ XGCValues xgcv;
+
+ /* Get the background color of the face. */
+ XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
+ color = xgcv.background;
+ }
+
+ if (di->white_relief.gc == 0
+ || color != di->relief_background)
+ {
+ di->relief_background = color;
+ x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
+ WHITE_PIX_DEFAULT (s->f));
+ x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
+ BLACK_PIX_DEFAULT (s->f));
+ }
+}
+
+
+/* Draw a relief on frame F inside the rectangle given by LEFT_X,
+ TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
+ to draw, it must be >= 0. RAISED_P non-zero means draw a raised
+ relief. LEFT_P non-zero means draw a relief on the left side of
+ the rectangle. RIGHT_P non-zero means draw a relief on the right
+ side of the rectangle. CLIP_RECT is the clipping rectangle to use
+ when drawing. */
+
+static void
+x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
+ raised_p, left_p, right_p, clip_rect)
+ struct frame *f;
+ int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
+ Rect *clip_rect;
+{
+ int i;
+ GC gc;
+
+ if (raised_p)
+ gc = f->output_data.mac->white_relief.gc;
+ else
+ gc = f->output_data.mac->black_relief.gc;
+ mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect);
+
+ /* Top. */
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
+ left_x + i * left_p, top_y + i,
+ right_x + 1 - i * right_p, top_y + i);
+
+ /* Left. */
+ if (left_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
+ left_x + i, top_y + i, left_x + i, bottom_y - i);
+
+ mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
+ if (raised_p)
+ gc = f->output_data.mac->black_relief.gc;
+ else
+ gc = f->output_data.mac->white_relief.gc;
+ mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ clip_rect);
+
+ /* Bottom. */
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
+ left_x + i * left_p, bottom_y - i,
+ right_x + 1 - i * right_p, bottom_y - i);
+
+ /* Right. */
+ if (right_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
+ right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
+
+ mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
+}
+
+
+/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
+ RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
+ draw, it must be >= 0. LEFT_P non-zero means draw a line on the
+ left side of the rectangle. RIGHT_P non-zero means draw a line
+ on the right side of the rectangle. CLIP_RECT is the clipping
+ rectangle to use when drawing. */
+
+static void
+x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+ left_p, right_p, clip_rect)
+ struct glyph_string *s;
+ int left_x, top_y, right_x, bottom_y, left_p, right_p;
+ Rect *clip_rect;
+{
+ XGCValues xgcv;
+
+ xgcv.foreground = s->face->box_color;
+ mac_set_clip_rectangle (s->display, s->window, clip_rect);
+
+ /* Top. */
+ XFillRectangle (s->display, s->window, &xgcv,
+ left_x, top_y, right_x - left_x, width);
+
+ /* Left. */
+ if (left_p)
+ XFillRectangle (s->display, s->window, &xgcv,
+ left_x, top_y, width, bottom_y - top_y);
+
+ /* Bottom. */
+ XFillRectangle (s->display, s->window, &xgcv,
+ left_x, bottom_y - width, right_x - left_x, width);
+
+ /* Right. */
+ if (right_p)
+ XFillRectangle (s->display, s->window, &xgcv,
+ right_x - width, top_y, width, bottom_y - top_y);
+
+ mac_reset_clipping (s->display, s->window);
+}
+
+
+/* Draw a box around glyph string S. */
+
+static void
+x_draw_glyph_string_box (s)
+ struct glyph_string *s;
+{
+ int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
+ int left_p, right_p;
+ struct glyph *last_glyph;
+ Rect clip_rect;
+
+ last_x = window_box_right (s->w, s->area);
+ if (s->row->full_width_p
+ && !s->w->pseudo_window_p)
+ {
+ last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
+ last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
+ }
+
+ /* The glyph that may have a right box line. */
+ last_glyph = (s->cmp || s->img
+ ? s->first_glyph
+ : s->first_glyph + s->nchars - 1);
+
+ width = abs (s->face->box_line_width);
+ raised_p = s->face->box == FACE_RAISED_BOX;
+ left_x = s->x;
+ right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
+ ? last_x - 1
+ : min (last_x, s->x + s->background_width) - 1));
+ top_y = s->y;
+ bottom_y = top_y + s->height - 1;
+
+ left_p = (s->first_glyph->left_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->prev == NULL
+ || s->prev->hl != s->hl)));
+ right_p = (last_glyph->right_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->next == NULL
+ || s->next->hl != s->hl)));
+
+ x_get_glyph_string_clip_rect (s, &clip_rect);
+
+ if (s->face->box == FACE_SIMPLE_BOX)
+ x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+ left_p, right_p, &clip_rect);
+ else
+ {
+ x_setup_relief_colors (s);
+ x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
+ width, raised_p, left_p, right_p, &clip_rect);
+ }
+}
+
+
+/* Draw foreground of image glyph string S. */
+
+static void
+x_draw_image_foreground (s)
+ struct glyph_string *s;
+{
+ int x;
+ int y = s->ybase - image_ascent (s->img, s->face);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ x += s->img->hmargin;
+ y += s->img->vmargin;
+
+ if (s->img->pixmap)
+ {
+#if 0 /* MAC_TODO: image mask */
+ if (s->img->mask)
+ {
+ /* We can't set both a clip mask and use XSetClipRectangles
+ because the latter also sets a clip mask. We also can't
+ trust on the shape extension to be available
+ (XShapeCombineRegion). So, compute the rectangle to draw
+ manually. */
+ unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+ | GCFunction);
+ XGCValues xgcv;
+ XRectangle clip_rect, image_rect, r;
+
+ xgcv.clip_mask = s->img->mask;
+ xgcv.clip_x_origin = x;
+ xgcv.clip_y_origin = y;
+ xgcv.function = GXcopy;
+ XChangeGC (s->display, s->gc, mask, &xgcv);
+
+ x_get_glyph_string_clip_rect (s, &clip_rect);
+ image_rect.x = x;
+ image_rect.y = y;
+ image_rect.width = s->img->width;
+ image_rect.height = s->img->height;
+ if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
+ XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+ }
+ else
+#endif /* MAC_TODO */
+ {
+ mac_copy_area (s->display, s->img->pixmap, s->window, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+ if (s->hl == DRAW_CURSOR)
+ mac_draw_rectangle (s->display, s->window, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+ }
+ }
+ else
+ /* Draw a rectangle if image could not be loaded. */
+ mac_draw_rectangle (s->display, s->window, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+}
+
+
+
+/* Draw a relief around the image glyph string S. */
+
+static void
+x_draw_image_relief (s)
+ struct glyph_string *s;
+{
+ int x0, y0, x1, y1, thick, raised_p;
+ Rect r;
+ int x;
+ int y = s->ybase - image_ascent (s->img, s->face);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ x += s->img->hmargin;
+ y += s->img->vmargin;
+
+ if (s->hl == DRAW_IMAGE_SUNKEN
+ || s->hl == DRAW_IMAGE_RAISED)
+ {
+ thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
+ raised_p = s->hl == DRAW_IMAGE_RAISED;
+ }
+ else
+ {
+ thick = abs (s->img->relief);
+ raised_p = s->img->relief > 0;
+ }
+
+ x0 = x - thick;
+ y0 = y - thick;
+ x1 = x + s->img->width + thick - 1;
+ y1 = y + s->img->height + thick - 1;
+
+ x_setup_relief_colors (s);
+ x_get_glyph_string_clip_rect (s, &r);
+ x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
+}
+
+
+/* Draw the foreground of image glyph string S to PIXMAP. */
+
+static void
+x_draw_image_foreground_1 (s, pixmap)
+ struct glyph_string *s;
+ Pixmap pixmap;
+{
+ int x;
+ int y = s->ybase - s->y - image_ascent (s->img, s->face);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = abs (s->face->box_line_width);
+ else
+ x = 0;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ x += s->img->hmargin;
+ y += s->img->vmargin;
+
+ if (s->img->pixmap)
+ {
+#if 0 /* MAC_TODO: image mask */
+ if (s->img->mask)
+ {
+ /* We can't set both a clip mask and use XSetClipRectangles
+ because the latter also sets a clip mask. We also can't
+ trust on the shape extension to be available
+ (XShapeCombineRegion). So, compute the rectangle to draw
+ manually. */
+ unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+ | GCFunction);
+ XGCValues xgcv;
+
+ xgcv.clip_mask = s->img->mask;
+ xgcv.clip_x_origin = x;
+ xgcv.clip_y_origin = y;
+ xgcv.function = GXcopy;
+ XChangeGC (s->display, s->gc, mask, &xgcv);
+
+ XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+ XSetClipMask (s->display, s->gc, None);
+ }
+ else
+#endif /* MAC_TODO */
+ {
+ mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+ if (s->hl == DRAW_CURSOR)
+ mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+ }
+ }
+ else
+ /* Draw a rectangle if image could not be loaded. */
+ mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+}
+
+
+/* Draw part of the background of glyph string S. X, Y, W, and H
+ give the rectangle to draw. */
+
+static void
+x_draw_glyph_string_bg_rect (s, x, y, w, h)
+ struct glyph_string *s;
+ int x, y, w, h;
+{
+#if 0 /* MAC_TODO: stipple */
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ }
+ else
+#endif /* MAC_TODO */
+ x_clear_glyph_string_rect (s, x, y, w, h);
+}
+
+
+/* Draw image glyph string S.
+
+ s->y
+ s->x +-------------------------
+ | s->face->box
+ |
+ | +-------------------------
+ | | s->img->vmargin
+ | |
+ | | +-------------------
+ | | | the image
+
+ */
+
+static void
+x_draw_image_glyph_string (s)
+ struct glyph_string *s;
+{
+ int x, y;
+ int box_line_hwidth = abs (s->face->box_line_width);
+ int box_line_vwidth = max (s->face->box_line_width, 0);
+ int height;
+ Pixmap pixmap = 0;
+
+ height = s->height - 2 * box_line_vwidth;
+
+ /* Fill background with face under the image. Do it only if row is
+ taller than image or if image has a clip mask to reduce
+ flickering. */
+ s->stippled_p = s->face->stipple != 0;
+ if (height > s->img->height
+ || s->img->hmargin
+ || s->img->vmargin
+#if 0 /* TODO: image mask */
+ || s->img->mask
+#endif
+ || s->img->pixmap == 0
+ || s->width != s->background_width)
+ {
+ if (box_line_hwidth && s->first_glyph->left_box_line_p)
+ x = s->x + box_line_hwidth;
+ else
+ x = s->x;
+
+ y = s->y + box_line_vwidth;
+#if 0 /* TODO: image mask */
+ if (s->img->mask)
+ {
+ /* Create a pixmap as large as the glyph string. Fill it
+ with the background color. Copy the image to it, using
+ its mask. Copy the temporary pixmap to the display. */
+ Screen *screen = FRAME_X_SCREEN (s->f);
+ int depth = DefaultDepthOfScreen (screen);
+
+ /* Create a pixmap as large as the glyph string. */
+ pixmap = XCreatePixmap (s->display, s->window,
+ s->background_width,
+ s->height, depth);
+
+ /* Don't clip in the following because we're working on the
+ pixmap. */
+ XSetClipMask (s->display, s->gc, None);
+
+ /* Fill the pixmap with the background color/stipple. */
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, pixmap, s->gc,
+ 0, 0, s->background_width, s->height);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ }
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
+ &xgcv);
+ XSetForeground (s->display, s->gc, xgcv.background);
+ XFillRectangle (s->display, pixmap, s->gc,
+ 0, 0, s->background_width, s->height);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+ else
+#endif
+ x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
+
+ s->background_filled_p = 1;
+ }
+
+ /* Draw the foreground. */
+ if (pixmap != 0)
+ {
+ x_draw_image_foreground_1 (s, pixmap);
+ x_set_glyph_string_clipping (s);
+ mac_copy_area (s->display, pixmap, s->window, s->gc,
+ 0, 0, s->background_width, s->height, s->x, s->y);
+ mac_reset_clipping (s->display, s->window);
+ XFreePixmap (s->display, pixmap);
+ }
+ else
+ x_draw_image_foreground (s);
+
+ /* If we must draw a relief around the image, do it. */
+ if (s->img->relief
+ || s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ x_draw_image_relief (s);
+}
+
+
+/* Draw stretch glyph string S. */
+
+static void
+x_draw_stretch_glyph_string (s)
+ struct glyph_string *s;
+{
+ xassert (s->first_glyph->type == STRETCH_GLYPH);
+ s->stippled_p = s->face->stipple != 0;
+
+ if (s->hl == DRAW_CURSOR
+ && !x_stretch_cursor_p)
+ {
+ /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
+ as wide as the stretch glyph. */
+ int width = min (CANON_X_UNIT (s->f), s->background_width);
+
+ /* Draw cursor. */
+ x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
+
+ /* Clear rest using the GC of the original non-cursor face. */
+ if (width < s->background_width)
+ {
+ GC gc = s->face->gc;
+ int x = s->x + width, y = s->y;
+ int w = s->background_width - width, h = s->height;
+ Rect r;
+
+ if (s->row->mouse_face_p
+ && cursor_in_mouse_face_p (s->w))
+ {
+ x_set_mouse_face_gc (s);
+ gc = s->gc;
+ }
+ else
+ gc = s->face->gc;
+
+ x_get_glyph_string_clip_rect (s, &r);
+ mac_set_clip_rectangle (s->display, s->window, &r);
+
+#if 0 /* MAC_TODO: stipple */
+ if (s->face->stipple)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, gc, x, y, w, h);
+ XSetFillStyle (s->display, gc, FillSolid);
+ }
+ else
+#endif /* MAC_TODO */
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
+ XSetForeground (s->display, gc, xgcv.background);
+ XFillRectangle (s->display, s->window, gc, x, y, w, h);
+ XSetForeground (s->display, gc, xgcv.foreground);
+ }
+
+ mac_reset_clipping (s->display, s->window);
+ }
+ }
+ else if (!s->background_filled_p)
+ x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
+ s->height);
+
+ s->background_filled_p = 1;
+}
+
+
+/* Draw glyph string S. */
+
+static void
+x_draw_glyph_string (s)
+ struct glyph_string *s;
+{
+ int relief_drawn_p = 0;
+
+ /* If S draws into the background of its successor, draw the
+ background of the successor first so that S can draw into it.
+ This makes S->next use XDrawString instead of XDrawImageString. */
+ if (s->next && s->right_overhang && !s->for_overlaps_p)
+ {
+ xassert (s->next->img == NULL);
+ x_set_glyph_string_gc (s->next);
+ x_set_glyph_string_clipping (s->next);
+ x_draw_glyph_string_background (s->next, 1);
+
+ }
+
+ /* Set up S->gc, set clipping and draw S. */
+ x_set_glyph_string_gc (s);
+
+ /* Draw relief (if any) in advance for char/composition so that the
+ glyph string can be drawn over it. */
+ if (!s->for_overlaps_p
+ && s->face->box != FACE_NO_BOX
+ && (s->first_glyph->type == CHAR_GLYPH
+ || s->first_glyph->type == COMPOSITE_GLYPH))
+
+ {
+ x_set_glyph_string_clipping (s);
+ x_draw_glyph_string_background (s, 1);
+ x_draw_glyph_string_box (s);
+ x_set_glyph_string_clipping (s);
+ relief_drawn_p = 1;
+ }
+ else
+ x_set_glyph_string_clipping (s);
+
+ switch (s->first_glyph->type)
+ {
+ case IMAGE_GLYPH:
+ x_draw_image_glyph_string (s);
+ break;
+
+ case STRETCH_GLYPH:
+ x_draw_stretch_glyph_string (s);
+ break;
+
+ case CHAR_GLYPH:
+ if (s->for_overlaps_p)
+ s->background_filled_p = 1;
+ else
+ x_draw_glyph_string_background (s, 0);
+ x_draw_glyph_string_foreground (s);
+ break;
+
+ case COMPOSITE_GLYPH:
+ if (s->for_overlaps_p || s->gidx > 0)
+ s->background_filled_p = 1;
+ else
+ x_draw_glyph_string_background (s, 1);
+ x_draw_composite_glyph_string_foreground (s);
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (!s->for_overlaps_p)
+ {
+ /* Draw underline. */
+ if (s->face->underline_p)
+ {
+ unsigned long h = 1;
+ unsigned long dy = s->height - h;
+
+ if (s->face->underline_defaulted_p)
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->underline_color);
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+
+ /* Draw overline. */
+ if (s->face->overline_p)
+ {
+ unsigned long dy = 0, h = 1;
+
+ if (s->face->overline_color_defaulted_p)
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->overline_color);
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+
+ /* Draw strike-through. */
+ if (s->face->strike_through_p)
+ {
+ unsigned long h = 1;
+ unsigned long dy = (s->height - h) / 2;
+
+ if (s->face->strike_through_color_defaulted_p)
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->strike_through_color);
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+
+ /* Draw relief. */
+ if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
+ x_draw_glyph_string_box (s);
+ }
+
+ /* Reset clipping. */
+ mac_reset_clipping (s->display, s->window);
+}
+
+
+static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
+ struct face **, int));
+
+
+/* Fill glyph string S with composition components specified by S->cmp.
+
+ FACES is an array of faces for all components of this composition.
+ S->gidx is the index of the first component for S.
+ OVERLAPS_P non-zero means S should draw the foreground only, and
+ use its physical height for clipping.
+
+ Value is the index of a component not in S. */
+
+static int
+x_fill_composite_glyph_string (s, faces, overlaps_p)
+ struct glyph_string *s;
+ struct face **faces;
+ int overlaps_p;
+{
+ int i;
+
+ xassert (s);
+
+ s->for_overlaps_p = overlaps_p;
+
+ s->face = faces[s->gidx];
+ s->font = s->face->font;
+ s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+
+ /* For all glyphs of this composition, starting at the offset
+ S->gidx, until we reach the end of the definition or encounter a
+ glyph that requires the different face, add it to S. */
+ ++s->nchars;
+ for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
+ ++s->nchars;
+
+ /* All glyph strings for the same composition has the same width,
+ i.e. the width set for the first component of the composition. */
+
+ s->width = s->first_glyph->pixel_width;
+
+ /* If the specified font could not be loaded, use the frame's
+ default font, but record the fact that we couldn't load it in
+ the glyph string so that we can draw rectangles for the
+ characters of the glyph string. */
+ if (s->font == NULL)
+ {
+ s->font_not_found_p = 1;
+ s->font = FRAME_FONT (s->f);
+ }
+
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += s->first_glyph->voffset;
+
+ xassert (s->face && s->face->gc);
+
+ /* This glyph string must always be drawn with 16-bit functions. */
+ s->two_byte_p = 1;
+
+ return s->gidx + s->nchars;
+}
+
+
+/* Fill glyph string S from a sequence of character glyphs.
+
+ FACE_ID is the face id of the string. START is the index of the
+ first glyph to consider, END is the index of the last + 1.
+ OVERLAPS_P non-zero means S should draw the foreground only, and
+ use its physical height for clipping.
+
+ Value is the index of the first glyph not in S. */
+
+static int
+x_fill_glyph_string (s, face_id, start, end, overlaps_p)
+ struct glyph_string *s;
+ int face_id;
+ int start, end, overlaps_p;
+{
+ struct glyph *glyph, *last;
+ int voffset;
+ int glyph_not_available_p;
+
+ xassert (s->f == XFRAME (s->w->frame));
+ xassert (s->nchars == 0);
+ xassert (start >= 0 && end > start);
+
+ s->for_overlaps_p = overlaps_p;
+ glyph = s->row->glyphs[s->area] + start;
+ last = s->row->glyphs[s->area] + end;
+ voffset = glyph->voffset;
+
+ glyph_not_available_p = glyph->glyph_not_available_p;
+
+ while (glyph < last
+ && glyph->type == CHAR_GLYPH
+ && glyph->voffset == voffset
+ /* Same face id implies same font, nowadays. */
+ && glyph->face_id == face_id
+ && glyph->glyph_not_available_p == glyph_not_available_p)
+ {
+ int two_byte_p;
+
+ s->face = x_get_glyph_face_and_encoding (s->f, glyph,
+ s->char2b + s->nchars,
+ &two_byte_p);
+ s->two_byte_p = two_byte_p;
+ ++s->nchars;
+ xassert (s->nchars <= end - start);
+ s->width += glyph->pixel_width;
+ ++glyph;
+ }
+
+ s->font = s->face->font;
+ s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+
+ /* If the specified font could not be loaded, use the frame's font,
+ but record the fact that we couldn't load it in
+ S->font_not_found_p so that we can draw rectangles for the
+ characters of the glyph string. */
+ if (s->font == NULL || glyph_not_available_p)
+ {
+ s->font_not_found_p = 1;
+ s->font = FRAME_FONT (s->f);
+ }
+
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += voffset;
+
+ xassert (s->face && s->face->gc);
+ return glyph - s->row->glyphs[s->area];
+}
+
+
+/* Fill glyph string S from image glyph S->first_glyph. */
+
+static void
+x_fill_image_glyph_string (s)
+ struct glyph_string *s;
+{
+ xassert (s->first_glyph->type == IMAGE_GLYPH);
+ s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
+ xassert (s->img);
+ s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ s->font = s->face->font;
+ s->width = s->first_glyph->pixel_width;
+
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += s->first_glyph->voffset;
+}
+
+
+/* Fill glyph string S from a sequence of stretch glyphs.
+
+ ROW is the glyph row in which the glyphs are found, AREA is the
+ area within the row. START is the index of the first glyph to
+ consider, END is the index of the last + 1.
+
+ Value is the index of the first glyph not in S. */
+
+static int
+x_fill_stretch_glyph_string (s, row, area, start, end)
+ struct glyph_string *s;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ int start, end;
+{
+ struct glyph *glyph, *last;
+ int voffset, face_id;
+
+ xassert (s->first_glyph->type == STRETCH_GLYPH);
+
+ glyph = s->row->glyphs[s->area] + start;
+ last = s->row->glyphs[s->area] + end;
+ face_id = glyph->face_id;
+ s->face = FACE_FROM_ID (s->f, face_id);
+ s->font = s->face->font;
+ s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+ s->width = glyph->pixel_width;
+ voffset = glyph->voffset;
+
+ for (++glyph;
+ (glyph < last
+ && glyph->type == STRETCH_GLYPH
+ && glyph->voffset == voffset
+ && glyph->face_id == face_id);
+ ++glyph)
+ s->width += glyph->pixel_width;
+
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += voffset;
+
+ xassert (s->face);
+ return glyph - s->row->glyphs[s->area];
+}
+
+
+/* Initialize glyph string S. CHAR2B is a suitably allocated vector
+ of XChar2b structures for S; it can't be allocated in
+ x_init_glyph_string because it must be allocated via `alloca'. W
+ is the window on which S is drawn. ROW and AREA are the glyph row
+ and area within the row from which S is constructed. START is the
+ index of the first glyph structure covered by S. HL is a
+ face-override for drawing S. */
+
+static void
+x_init_glyph_string (s, char2b, w, row, area, start, hl)
+ struct glyph_string *s;
+ XChar2b *char2b;
+ struct window *w;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ int start;
+ enum draw_glyphs_face hl;
+{
+ bzero (s, sizeof *s);
+ s->w = w;
+ s->f = XFRAME (w->frame);
+ s->display = FRAME_MAC_DISPLAY (s->f);
+ s->window = FRAME_MAC_WINDOW (s->f);
+ s->char2b = char2b;
+ s->hl = hl;
+ s->row = row;
+ s->area = area;
+ s->first_glyph = row->glyphs[area] + start;
+ s->height = row->height;
+ s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+
+ /* Display the internal border below the tool-bar window. */
+ if (s->w == XWINDOW (s->f->tool_bar_window))
+ s->y -= s->f->output_data.mac->internal_border_width;
+
+ s->ybase = s->y + row->ascent;
+}
+
+
+/* Set background width of glyph string S. START is the index of the
+ first glyph following S. LAST_X is the right-most x-position + 1
+ in the drawing area. */
+
+static INLINE void
+x_set_glyph_string_background_width (s, start, last_x)
+ struct glyph_string *s;
+ int start;
+ int last_x;
+{
+ /* If the face of this glyph string has to be drawn to the end of
+ the drawing area, set S->extends_to_end_of_line_p. */
+ struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
+
+ if (start == s->row->used[s->area]
+ && s->area == TEXT_AREA
+ && ((s->hl == DRAW_NORMAL_TEXT
+ && (s->row->fill_line_p
+ || s->face->background != default_face->background
+ || s->face->stipple != default_face->stipple
+ || s->row->mouse_face_p))
+ || s->hl == DRAW_MOUSE_FACE
+ || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
+ && s->row->fill_line_p)))
+ s->extends_to_end_of_line_p = 1;
+
+ /* If S extends its face to the end of the line, set its
+ background_width to the distance to the right edge of the drawing
+ area. */
+ if (s->extends_to_end_of_line_p)
+ s->background_width = last_x - s->x + 1;
+ else
+ s->background_width = s->width;
+}
+
+
+/* Add a glyph string for a stretch glyph to the list of strings
+ between HEAD and TAIL. START is the index of the stretch glyph in
+ row area AREA of glyph row ROW. END is the index of the last glyph
+ in that glyph row area. X is the current output position assigned
+ to the new glyph string constructed. HL overrides that face of the
+ glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
+ is the right-most x-position of the drawing area. */
+
+/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
+ and below -- keep them on one line. */
+#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
+ START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
+ x_append_glyph_string (&HEAD, &TAIL, s); \
+ s->x = (X); \
+ } \
+ while (0)
+
+
+/* Add a glyph string for an image glyph to the list of strings
+ between HEAD and TAIL. START is the index of the image glyph in
+ row area AREA of glyph row ROW. END is the index of the last glyph
+ in that glyph row area. X is the current output position assigned
+ to the new glyph string constructed. HL overrides that face of the
+ glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
+ is the right-most x-position of the drawing area. */
+
+#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
+ x_fill_image_glyph_string (s); \
+ x_append_glyph_string (&HEAD, &TAIL, s); \
+ ++START; \
+ s->x = (X); \
+ } \
+ while (0)
+
+
+/* Add a glyph string for a sequence of character glyphs to the list
+ of strings between HEAD and TAIL. START is the index of the first
+ glyph in row area AREA of glyph row ROW that is part of the new
+ glyph string. END is the index of the last glyph in that glyph row
+ area. X is the current output position assigned to the new glyph
+ string constructed. HL overrides that face of the glyph; e.g. it
+ is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
+ right-most x-position of the drawing area. */
+
+#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
+ do \
+ { \
+ int c, face_id; \
+ XChar2b *char2b; \
+ \
+ c = (ROW)->glyphs[AREA][START].u.ch; \
+ face_id = (ROW)->glyphs[AREA][START].face_id; \
+ \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
+ x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
+ x_append_glyph_string (&HEAD, &TAIL, s); \
+ s->x = (X); \
+ START = x_fill_glyph_string (s, face_id, START, END, \
+ OVERLAPS_P); \
+ } \
+ while (0)
+
+
+/* Add a glyph string for a composite sequence to the list of strings
+ between HEAD and TAIL. START is the index of the first glyph in
+ row area AREA of glyph row ROW that is part of the new glyph
+ string. END is the index of the last glyph in that glyph row area.
+ X is the current output position assigned to the new glyph string
+ constructed. HL overrides that face of the glyph; e.g. it is
+ DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
+ x-position of the drawing area. */
+
+#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
+ do { \
+ int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
+ int face_id = (ROW)->glyphs[AREA][START].face_id; \
+ struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
+ struct composition *cmp = composition_table[cmp_id]; \
+ int glyph_len = cmp->glyph_len; \
+ XChar2b *char2b; \
+ struct face **faces; \
+ struct glyph_string *first_s = NULL; \
+ int n; \
+ \
+ base_face = base_face->ascii_face; \
+ char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
+ faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
+ /* At first, fill in `char2b' and `faces'. */ \
+ for (n = 0; n < glyph_len; n++) \
+ { \
+ int c = COMPOSITION_GLYPH (cmp, n); \
+ int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
+ faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
+ x_get_char_face_and_encoding (XFRAME (w->frame), c, \
+ this_face_id, char2b + n, 1); \
+ } \
+ \
+ /* Make glyph_strings for each glyph sequence that is drawable by \
+ the same face, and append them to HEAD/TAIL. */ \
+ for (n = 0; n < cmp->glyph_len;) \
+ { \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
+ x_append_glyph_string (&(HEAD), &(TAIL), s); \
+ s->cmp = cmp; \
+ s->gidx = n; \
+ s->x = (X); \
+ \
+ if (n == 0) \
+ first_s = s; \
+ \
+ n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
+ } \
+ \
+ ++START; \
+ s = first_s; \
+ } while (0)
+
+
+/* Build a list of glyph strings between HEAD and TAIL for the glyphs
+ of AREA of glyph row ROW on window W between indices START and END.
+ HL overrides the face for drawing glyph strings, e.g. it is
+ DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
+ x-positions of the drawing area.
+
+ This is an ugly monster macro construct because we must use alloca
+ to allocate glyph strings (because x_draw_glyphs can be called
+ asynchronously). */
+
+#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
+ do \
+ { \
+ HEAD = TAIL = NULL; \
+ while (START < END) \
+ { \
+ struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
+ switch (first_glyph->type) \
+ { \
+ case CHAR_GLYPH: \
+ BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
+ TAIL, HL, X, LAST_X, \
+ OVERLAPS_P); \
+ break; \
+ \
+ case COMPOSITE_GLYPH: \
+ BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
+ HEAD, TAIL, HL, X, LAST_X,\
+ OVERLAPS_P); \
+ break; \
+ \
+ case STRETCH_GLYPH: \
+ BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
+ HEAD, TAIL, HL, X, LAST_X); \
+ break; \
+ \
+ case IMAGE_GLYPH: \
+ BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
+ TAIL, HL, X, LAST_X); \
+ break; \
+ \
+ default: \
+ abort (); \
+ } \
+ \
+ x_set_glyph_string_background_width (s, START, LAST_X); \
+ (X) += s->width; \
+ } \
+ } \
+ while (0)
+
+
+/* Draw glyphs between START and END in AREA of ROW on window W,
+ starting at x-position X. X is relative to AREA in W. HL is a
+ face-override with the following meaning:
+
+ DRAW_NORMAL_TEXT draw normally
+ DRAW_CURSOR draw in cursor face
+ DRAW_MOUSE_FACE draw in mouse face.
+ DRAW_INVERSE_VIDEO draw in mode line face
+ DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
+ DRAW_IMAGE_RAISED draw an image with a raised relief around it
+
+ If OVERLAPS_P is non-zero, draw only the foreground of characters
+ and clip to the physical height of ROW.
+
+ Value is the x-position reached, relative to AREA of W. */
+
+static int
+x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
+ struct window *w;
+ int x;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ int start, end;
+ enum draw_glyphs_face hl;
+ int overlaps_p;
+{
+ struct glyph_string *head, *tail;
+ struct glyph_string *s;
+ int last_x, area_width;
+ int x_reached;
+ int i, j;
+
+ /* Let's rather be paranoid than getting a SEGV. */
+ end = min (end, row->used[area]);
+ start = max (0, start);
+ start = min (end, start);
+
+ /* Translate X to frame coordinates. Set last_x to the right
+ end of the drawing area. */
+ if (row->full_width_p)
+ {
+ /* X is relative to the left edge of W, without scroll bars
+ or fringes. */
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
+
+ x += window_left_x;
+ area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
+ last_x = window_left_x + area_width;
+
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ {
+ int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+ last_x += width;
+ else
+ x -= width;
+ }
+
+ x += FRAME_INTERNAL_BORDER_WIDTH (f);
+ last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
+ }
+ else
+ {
+ x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
+ area_width = window_box_width (w, area);
+ last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
+ }
+
+ /* Build a doubly-linked list of glyph_string structures between
+ head and tail from what we have to draw. Note that the macro
+ BUILD_GLYPH_STRINGS will modify its start parameter. That's
+ the reason we use a separate variable `i'. */
+ i = start;
+ BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
+ overlaps_p);
+ if (tail)
+ x_reached = tail->x + tail->background_width;
+ else
+ x_reached = x;
+
+ /* If there are any glyphs with lbearing < 0 or rbearing > width in
+ the row, redraw some glyphs in front or following the glyph
+ strings built above. */
+ if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
+ {
+ int dummy_x = 0;
+ struct glyph_string *h, *t;
+
+ /* Compute overhangs for all glyph strings. */
+ for (s = head; s; s = s->next)
+ x_compute_glyph_string_overhangs (s);
+
+ /* Prepend glyph strings for glyphs in front of the first glyph
+ string that are overwritten because of the first glyph
+ string's left overhang. The background of all strings
+ prepended must be drawn because the first glyph string
+ draws over it. */
+ i = x_left_overwritten (head);
+ if (i >= 0)
+ {
+ j = i;
+ BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
+ DRAW_NORMAL_TEXT, dummy_x, last_x,
+ overlaps_p);
+ start = i;
+ x_compute_overhangs_and_x (t, head->x, 1);
+ x_prepend_glyph_string_lists (&head, &tail, h, t);
+ }
+
+ /* Prepend glyph strings for glyphs in front of the first glyph
+ string that overwrite that glyph string because of their
+ right overhang. For these strings, only the foreground must
+ be drawn, because it draws over the glyph string at `head'.
+ The background must not be drawn because this would overwrite
+ right overhangs of preceding glyphs for which no glyph
+ strings exist. */
+ i = x_left_overwriting (head);
+ if (i >= 0)
+ {
+ BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
+ DRAW_NORMAL_TEXT, dummy_x, last_x,
+ overlaps_p);
+ for (s = h; s; s = s->next)
+ s->background_filled_p = 1;
+ x_compute_overhangs_and_x (t, head->x, 1);
+ x_prepend_glyph_string_lists (&head, &tail, h, t);
+ }
+
+ /* Append glyphs strings for glyphs following the last glyph
+ string tail that are overwritten by tail. The background of
+ these strings has to be drawn because tail's foreground draws
+ over it. */
+ i = x_right_overwritten (tail);
+ if (i >= 0)
+ {
+ BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
+ DRAW_NORMAL_TEXT, x, last_x,
+ overlaps_p);
+ x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
+ x_append_glyph_string_lists (&head, &tail, h, t);
+ }
+
+ /* Append glyph strings for glyphs following the last glyph
+ string tail that overwrite tail. The foreground of such
+ glyphs has to be drawn because it writes into the background
+ of tail. The background must not be drawn because it could
+ paint over the foreground of following glyphs. */
+ i = x_right_overwriting (tail);
+ if (i >= 0)
+ {
+ BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
+ DRAW_NORMAL_TEXT, x, last_x,
+ overlaps_p);
+ for (s = h; s; s = s->next)
+ s->background_filled_p = 1;
+ x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
+ x_append_glyph_string_lists (&head, &tail, h, t);
+ }
+ }
+
+ /* Draw all strings. */
+ for (s = head; s; s = s->next)
+ x_draw_glyph_string (s);
+
+ if (area == TEXT_AREA
+ && !row->full_width_p
+ /* When drawing overlapping rows, only the glyph strings'
+ foreground is drawn, which doesn't erase a cursor
+ completely. */
+ && !overlaps_p)
+ {
+ int x0 = head ? head->x : x;
+ int x1 = tail ? tail->x + tail->background_width : x;
+
+ x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
+ x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
+
+ if (!row->full_width_p && XFASTINT (w->left_margin_width) != 0)
+ {
+ int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
+ x0 -= left_area_width;
+ x1 -= left_area_width;
+ }
+
+ notice_overwritten_cursor (w, area, x0, x1,
+ row->y, MATRIX_ROW_BOTTOM_Y (row));
+ }
+
+ /* Value is the x-position up to which drawn, relative to AREA of W.
+ This doesn't include parts drawn because of overhangs. */
+ x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
+ if (!row->full_width_p)
+ {
+ if (area > LEFT_MARGIN_AREA)
+ x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
+ if (area > TEXT_AREA)
+ x_reached -= window_box_width (w, TEXT_AREA);
+ }
+
+ return x_reached;
+}
+
+
+/* Fix the display of area AREA of overlapping row ROW in window W. */
+
+static void
+x_fix_overlapping_area (w, row, area)
+ struct window *w;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+{
+ int i, x;
+
+ BLOCK_INPUT;
+
+ if (area == LEFT_MARGIN_AREA)
+ x = 0;
+ else if (area == TEXT_AREA)
+ x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
+ else
+ x = (window_box_width (w, LEFT_MARGIN_AREA)
+ + window_box_width (w, TEXT_AREA));
+
+ for (i = 0; i < row->used[area];)
+ {
+ if (row->glyphs[area][i].overlaps_vertically_p)
+ {
+ int start = i, start_x = x;
+
+ do
+ {
+ x += row->glyphs[area][i].pixel_width;
+ ++i;
+ }
+ while (i < row->used[area]
+ && row->glyphs[area][i].overlaps_vertically_p);
+
+ x_draw_glyphs (w, start_x, row, area, start, i,
+ DRAW_NORMAL_TEXT, 1);
+ }
+ else
+ {
+ x += row->glyphs[area][i].pixel_width;
+ ++i;
+ }
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+/* Output LEN glyphs starting at START at the nominal cursor position.
+ Advance the nominal cursor over the text. The global variable
+ updated_window contains the window being updated, updated_row is
+ the glyph row being updated, and updated_area is the area of that
+ row being updated. */
+
+static void
+x_write_glyphs (start, len)
+ struct glyph *start;
+ int len;
+{
+ int x, hpos;
+
+ xassert (updated_window && updated_row);
+ BLOCK_INPUT;
+
+ /* Write glyphs. */
+
+ hpos = start - updated_row->glyphs[updated_area];
+ x = x_draw_glyphs (updated_window, output_cursor.x,
+ updated_row, updated_area,
+ hpos, hpos + len,
+ DRAW_NORMAL_TEXT, 0);
+
+ UNBLOCK_INPUT;
+
+ /* Advance the output cursor. */
+ output_cursor.hpos += len;
+ output_cursor.x = x;
+}
+
+
+/* Insert LEN glyphs from START at the nominal cursor position. */
+
+static void
+x_insert_glyphs (start, len)
+ struct glyph *start;
+ register int len;
+{
+ struct frame *f;
+ struct window *w;
+ int line_height, shift_by_width, shifted_region_width;
+ struct glyph_row *row;
+ struct glyph *glyph;
+ int frame_x, frame_y, hpos;
+
+ xassert (updated_window && updated_row);
+ BLOCK_INPUT;
+ w = updated_window;
+ f = XFRAME (WINDOW_FRAME (w));
+
+ /* Get the height of the line we are in. */
+ row = updated_row;
+ line_height = row->height;
+
+ /* Get the width of the glyphs to insert. */
+ shift_by_width = 0;
+ for (glyph = start; glyph < start + len; ++glyph)
+ shift_by_width += glyph->pixel_width;
+
+ /* Get the width of the region to shift right. */
+ shifted_region_width = (window_box_width (w, updated_area)
+ - output_cursor.x
+ - shift_by_width);
+
+ /* Shift right. */
+ frame_x = window_box_left (w, updated_area) + output_cursor.x;
+ frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
+
+ mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ f->output_data.mac->normal_gc,
+ frame_x, frame_y,
+ shifted_region_width, line_height,
+ frame_x + shift_by_width, frame_y);
+
+ /* Write the glyphs. */
+ hpos = start - row->glyphs[updated_area];
+ x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
+ DRAW_NORMAL_TEXT, 0);
+
+ /* Advance the output cursor. */
+ output_cursor.hpos += len;
+ output_cursor.x += shift_by_width;
+ UNBLOCK_INPUT;
+}
+
+
+/* Delete N glyphs at the nominal cursor position. Not implemented
+ for X frames. */
+
+static void
+x_delete_glyphs (n)
+ register int n;
+{
+ abort ();
+}
+
+
+/* Erase the current text line from the nominal cursor position
+ (inclusive) to pixel column TO_X (exclusive). The idea is that
+ everything from TO_X onward is already erased.
+
+ TO_X is a pixel position relative to updated_area of
+ updated_window. TO_X == -1 means clear to the end of this area. */
+
+static void
+x_clear_end_of_line (to_x)
+ int to_x;
+{
+ struct frame *f;
+ struct window *w = updated_window;
+ int max_x, min_y, max_y;
+ int from_x, from_y, to_y;
+
+ xassert (updated_window && updated_row);
+ f = XFRAME (w->frame);
+
+ if (updated_row->full_width_p)
+ {
+ max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+ && !w->pseudo_window_p)
+ max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
+ }
+ else
+ max_x = window_box_width (w, updated_area);
+ max_y = window_text_bottom_y (w);
+
+ /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
+ of window. For TO_X > 0, truncate to end of drawing area. */
+ if (to_x == 0)
+ return;
+ else if (to_x < 0)
+ to_x = max_x;
+ else
+ to_x = min (to_x, max_x);
+
+ to_y = min (max_y, output_cursor.y + updated_row->height);
+
+ /* Notice if the cursor will be cleared by this operation. */
+ if (!updated_row->full_width_p)
+ notice_overwritten_cursor (w, updated_area,
+ output_cursor.x, -1,
+ updated_row->y,
+ MATRIX_ROW_BOTTOM_Y (updated_row));
+
+ from_x = output_cursor.x;
+
+ /* Translate to frame coordinates. */
+ if (updated_row->full_width_p)
+ {
+ from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
+ to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
+ }
+ else
+ {
+ from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
+ to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
+ }
+
+ min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
+ to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
+
+ /* Prevent inadvertently clearing to end of the X window. */
+ if (to_x > from_x && to_y > from_y)
+ {
+ BLOCK_INPUT;
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ from_x, from_y, to_x - from_x, to_y - from_y,
+ 0);
+ UNBLOCK_INPUT;
+ }
+}
+
+
+/* Clear entire frame. If updating_frame is non-null, clear that
+ frame. Otherwise clear the selected frame. */
+
+static void
+x_clear_frame ()
+{
+ struct frame *f;
+
+ if (updating_frame)
+ f = updating_frame;
+ else
+ f = SELECTED_FRAME ();
+
+ /* Clearing the frame will erase any cursor, so mark them all as no
+ longer visible. */
+ mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
+ output_cursor.hpos = output_cursor.vpos = 0;
+ output_cursor.x = -1;
+
+ /* We don't set the output cursor here because there will always
+ follow an explicit cursor_to. */
+ BLOCK_INPUT;
+ XClearWindow (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
+
+#if 0 /* Clearing frame on Mac OS clears scroll bars. */
+ /* We have to clear the scroll bars, too. If we have changed
+ colors or something like that, then they should be notified. */
+ x_scroll_bar_clear (f);
+#endif
+
+ XFlush (FRAME_MAC_DISPLAY (f));
+ UNBLOCK_INPUT;
+}
+
+
+
+/* Invert the middle quarter of the frame for .15 sec. */
+
+/* We use the select system call to do the waiting, so we have to make
+ sure it's available. If it isn't, we just won't do visual bells. */
+
+#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
+
+/* Subtract the `struct timeval' values X and Y, storing the result in
+ *RESULT. Return 1 if the difference is negative, otherwise 0. */
+
+static int
+timeval_subtract (result, x, y)
+ struct timeval *result, x, y;
+{
+ /* Perform the carry for the later subtraction by updating y. This
+ is safer because on some systems the tv_sec member is unsigned. */
+ if (x.tv_usec < y.tv_usec)
+ {
+ int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
+ y.tv_usec -= 1000000 * nsec;
+ y.tv_sec += nsec;
+ }
+
+ if (x.tv_usec - y.tv_usec > 1000000)
+ {
+ int nsec = (y.tv_usec - x.tv_usec) / 1000000;
+ y.tv_usec += 1000000 * nsec;
+ y.tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait. tv_usec is certainly
+ positive. */
+ result->tv_sec = x.tv_sec - y.tv_sec;
+ result->tv_usec = x.tv_usec - y.tv_usec;
+
+ /* Return indication of whether the result should be considered
+ negative. */
+ return x.tv_sec < y.tv_sec;
+}
+
+void
+XTflash (f)
+ struct frame *f;
+{
+ BLOCK_INPUT;
+
+ FlashMenuBar (0);
+
+ {
+ struct timeval wakeup;
+
+ EMACS_GET_TIME (wakeup);
+
+ /* Compute time to wait until, propagating carry from usecs. */
+ wakeup.tv_usec += 150000;
+ wakeup.tv_sec += (wakeup.tv_usec / 1000000);
+ wakeup.tv_usec %= 1000000;
+
+ /* Keep waiting until past the time wakeup. */
+ while (1)
+ {
+ struct timeval timeout;
+
+ EMACS_GET_TIME (timeout);
+
+ /* In effect, timeout = wakeup - timeout.
+ Break if result would be negative. */
+ if (timeval_subtract (&timeout, wakeup, timeout))
+ break;
+
+ /* Try to wait that long--but we might wake up sooner. */
+ select (0, NULL, NULL, NULL, &timeout);
+ }
+ }
+
+ FlashMenuBar (0);
+
+ UNBLOCK_INPUT;
+}
+
+#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
+
+
+/* Make audible bell. */
+
+void
+XTring_bell ()
+{
+ struct frame *f = SELECTED_FRAME ();
+
+#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
+ if (visible_bell)
+ XTflash (f);
+ else
+#endif
+ {
+ BLOCK_INPUT;
+ SysBeep (1);
+ XFlush (FRAME_MAC_DISPLAY (f));
+ UNBLOCK_INPUT;
+ }
+}
+
+
+
+/* Specify how many text lines, from the top of the window,
+ should be affected by insert-lines and delete-lines operations.
+ This, and those operations, are used only within an update
+ that is bounded by calls to x_update_begin and x_update_end. */
+
+void
+XTset_terminal_window (n)
+ register int n;
+{
+ /* This function intentionally left blank. */
+}
+
+
+
+/***********************************************************************
+ Line Dance
+ ***********************************************************************/
+
+/* Perform an insert-lines or delete-lines operation, inserting N
+ lines or deleting -N lines at vertical position VPOS. */
+
+static void
+x_ins_del_lines (vpos, n)
+ int vpos, n;
+{
+ abort ();
+}
+
+
+/* Scroll part of the display as described by RUN. */
+
+static void
+x_scroll_run (w, run)
+ struct window *w;
+ struct run *run;
+{
+ struct frame *f = XFRAME (w->frame);
+ int x, y, width, height, from_y, to_y, bottom_y;
+
+ /* Get frame-relative bounding box of the text display area of W,
+ without mode lines. Include in this box the left and right
+ fringes of W. */
+ window_box (w, -1, &x, &y, &width, &height);
+ width += FRAME_X_FRINGE_WIDTH (f);
+ x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
+
+ from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
+ to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
+ bottom_y = y + height;
+
+ if (to_y < from_y)
+ {
+ /* Scrolling up. Make sure we don't copy part of the mode
+ line at the bottom. */
+ if (from_y + run->height > bottom_y)
+ height = bottom_y - from_y;
+ else
+ height = run->height;
+ }
+ else
+ {
+ /* Scolling down. Make sure we don't copy over the mode line.
+ at the bottom. */
+ if (to_y + run->height > bottom_y)
+ height = bottom_y - to_y;
+ else
+ height = run->height;
+ }
+
+ BLOCK_INPUT;
+
+ /* Cursor off. Will be switched on again in x_update_window_end. */
+ updated_window = w;
+ x_clear_cursor (w);
+
+ mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ f->output_data.mac->normal_gc,
+ x, from_y,
+ width, height,
+ x, to_y);
+
+ UNBLOCK_INPUT;
+}
+
+
+
+/***********************************************************************
+ Exposure Events
+ ***********************************************************************/
+
+/* Redisplay an exposed area of frame F. X and Y are the upper-left
+ corner of the exposed rectangle. W and H are width and height of
+ the exposed area. All are pixel values. W or H zero means redraw
+ the entire frame. */
+
+static void
+expose_frame (f, x, y, w, h)
+ struct frame *f;
+ int x, y, w, h;
+{
+ Rect r;
+ int mouse_face_overwritten_p = 0;
+
+ TRACE ((stderr, "expose_frame "));
+
+ /* No need to redraw if frame will be redrawn soon. */
+ if (FRAME_GARBAGED_P (f))
+ {
+ TRACE ((stderr, " garbaged\n"));
+ return;
+ }
+
+ /* MAC_TODO: this is a kludge, but if scroll bars are not activated
+ or deactivated here, for unknown reasons, activated scroll bars
+ are shown in deactivated frames in some instances. */
+ if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
+ activate_scroll_bars (f);
+ else
+ deactivate_scroll_bars (f);
+
+ /* If basic faces haven't been realized yet, there is no point in
+ trying to redraw anything. This can happen when we get an expose
+ event while Emacs is starting, e.g. by moving another window. */
+ if (FRAME_FACE_CACHE (f) == NULL
+ || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
+ {
+ TRACE ((stderr, " no faces\n"));
+ return;
+ }
+
+ if (w == 0 || h == 0)
+ {
+ r.left = r.top = 0;
+ r.right = CANON_X_UNIT (f) * f->width;
+ r.bottom = CANON_Y_UNIT (f) * f->height;
+ }
+ else
+ {
+ r.left = x;
+ r.top = y;
+ r.right = x + w;
+ r.bottom = y + h;
+ }
+
+ TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom));
+ mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
+
+ if (WINDOWP (f->tool_bar_window))
+ mouse_face_overwritten_p
+ |= expose_window (XWINDOW (f->tool_bar_window), &r);
+
+ /* Some window managers support a focus-follows-mouse style with
+ delayed raising of frames. Imagine a partially obscured frame,
+ and moving the mouse into partially obscured mouse-face on that
+ frame. The visible part of the mouse-face will be highlighted,
+ then the WM raises the obscured frame. With at least one WM, KDE
+ 2.1, Emacs is not getting any event for the raising of the frame
+ (even tried with SubstructureRedirectMask), only Expose events.
+ These expose events will draw text normally, i.e. not
+ highlighted. Which means we must redo the highlight here.
+ Subsume it under ``we love X''. --gerd 2001-08-15 */
+ /* Included in Windows version because Windows most likely does not
+ do the right thing if any third party tool offers
+ focus-follows-mouse with delayed raise. --jason 2001-10-12 */
+ if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
+ {
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ if (f == dpyinfo->mouse_face_mouse_frame)
+ {
+ int x = dpyinfo->mouse_face_mouse_x;
+ int y = dpyinfo->mouse_face_mouse_y;
+ clear_mouse_face (dpyinfo);
+ note_mouse_highlight (f, x, y);
+ }
+ }
+}
+
+
+/* Redraw (parts) of all windows in the window tree rooted at W that
+ intersect R. R contains frame pixel coordinates. */
+
+static int
+expose_window_tree (w, r)
+ struct window *w;
+ Rect *r;
+{
+ struct frame *f = XFRAME (w->frame);
+ int mouse_face_overwritten_p = 0;
+
+ while (w && !FRAME_GARBAGED_P (f))
+ {
+ if (!NILP (w->hchild))
+ mouse_face_overwritten_p
+ |= expose_window_tree (XWINDOW (w->hchild), r);
+ else if (!NILP (w->vchild))
+ mouse_face_overwritten_p
+ |= expose_window_tree (XWINDOW (w->vchild), r);
+ else
+ mouse_face_overwritten_p |= expose_window (w, r);
+
+ w = NILP (w->next) ? NULL : XWINDOW (w->next);
+ }
+
+ return mouse_face_overwritten_p;
+}
+
+
+/* Redraw the part of glyph row area AREA of glyph row ROW on window W
+ which intersects rectangle R. R is in window-relative coordinates. */
+
+static void
+expose_area (w, row, r, area)
+ struct window *w;
+ struct glyph_row *row;
+ Rect *r;
+ enum glyph_row_area area;
+{
+ struct glyph *first = row->glyphs[area];
+ struct glyph *end = row->glyphs[area] + row->used[area];
+ struct glyph *last;
+ int first_x, start_x, x;
+
+ if (area == TEXT_AREA && row->fill_line_p)
+ /* If row extends face to end of line write the whole line. */
+ x_draw_glyphs (w, 0, row, area,
+ 0, row->used[area],
+ DRAW_NORMAL_TEXT, 0);
+ else
+ {
+ /* Set START_X to the window-relative start position for drawing glyphs of
+ AREA. The first glyph of the text area can be partially visible.
+ The first glyphs of other areas cannot. */
+ if (area == LEFT_MARGIN_AREA)
+ start_x = 0;
+ else if (area == TEXT_AREA)
+ start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
+ else
+ start_x = (window_box_width (w, LEFT_MARGIN_AREA)
+ + window_box_width (w, TEXT_AREA));
+ x = start_x;
+
+ /* Find the first glyph that must be redrawn. */
+ while (first < end
+ && x + first->pixel_width < r->left)
+ {
+ x += first->pixel_width;
+ ++first;
+ }
+
+ /* Find the last one. */
+ last = first;
+ first_x = x;
+ while (last < end
+ && x < r->right)
+ {
+ x += last->pixel_width;
+ ++last;
+ }
+
+ /* Repaint. */
+ if (last > first)
+ x_draw_glyphs (w, first_x - start_x, row, area,
+ first - row->glyphs[area],
+ last - row->glyphs[area],
+ DRAW_NORMAL_TEXT, 0);
+ }
+}
+
+
+/* Redraw the parts of the glyph row ROW on window W intersecting
+ rectangle R. R is in window-relative coordinates. Value is
+ non-zero if mouse face was overwritten. */
+
+static int
+expose_line (w, row, r)
+ struct window *w;
+ struct glyph_row *row;
+ Rect *r;
+{
+ xassert (row->enabled_p);
+
+ if (row->mode_line_p || w->pseudo_window_p)
+ x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
+ DRAW_NORMAL_TEXT, 0);
+ else
+ {
+ if (row->used[LEFT_MARGIN_AREA])
+ expose_area (w, row, r, LEFT_MARGIN_AREA);
+ if (row->used[TEXT_AREA])
+ expose_area (w, row, r, TEXT_AREA);
+ if (row->used[RIGHT_MARGIN_AREA])
+ expose_area (w, row, r, RIGHT_MARGIN_AREA);
+ x_draw_row_fringe_bitmaps (w, row);
+ }
+
+ return row->mouse_face_p;
+}
+
+
+/* Return non-zero if W's cursor intersects rectangle R. */
+
+static int
+x_phys_cursor_in_rect_p (w, r)
+ struct window *w;
+ Rect *r;
+{
+ Rect cr, result;
+ struct glyph *cursor_glyph;
+
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph)
+ {
+ cr.left = w->phys_cursor.x;
+ cr.top = w->phys_cursor.y;
+ cr.right = cr.left + cursor_glyph->pixel_width;
+ cr.bottom = cr.top + w->phys_cursor_height;
+ return x_intersect_rectangles (&cr, r, &result);
+ }
+ else
+ return 0;
+}
+
+
+/* Redraw the part of window W intersection rectagle FR. Pixel
+ coordinates in FR are frame relative. Call this function with
+ input blocked. Value is non-zero if the exposure overwrites
+ mouse-face. */
+
+static int
+expose_window (w, fr)
+ struct window *w;
+ Rect *fr;
+{
+ struct frame *f = XFRAME (w->frame);
+ Rect wr, r;
+ int mouse_face_overwritten_p = 0;
+
+ /* If window is not yet fully initialized, do nothing. This can
+ happen when toolkit scroll bars are used and a window is split.
+ Reconfiguring the scroll bar will generate an expose for a newly
+ created window. */
+ if (w->current_matrix == NULL)
+ return 0;
+
+ /* When we're currently updating the window, display and current
+ matrix usually don't agree. Arrange for a thorough display
+ later. */
+ if (w == updated_window)
+ {
+ SET_FRAME_GARBAGED (f);
+ return 0;
+ }
+
+ /* Frame-relative pixel rectangle of W. */
+ wr.left = XFASTINT (w->left) * CANON_X_UNIT (f);
+ wr.top = XFASTINT (w->top) * CANON_Y_UNIT (f);
+ wr.right = wr.left + XFASTINT (w->width) * CANON_X_UNIT (f);
+ wr.bottom = wr.top + XFASTINT (w->height) * CANON_Y_UNIT (f);
+
+ if (x_intersect_rectangles (fr, &wr, &r))
+ {
+ int yb = window_text_bottom_y (w);
+ struct glyph_row *row;
+ int cursor_cleared_p;
+
+ TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
+ r.left, r.top, r.right, r.bottom));
+
+ /* Convert to window coordinates. */
+ r.left = FRAME_TO_WINDOW_PIXEL_X (w, r.left);
+ r.right = FRAME_TO_WINDOW_PIXEL_X (w, r.right);
+ r.top = FRAME_TO_WINDOW_PIXEL_Y (w, r.top);
+ r.bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r.bottom);
+
+ /* Turn off the cursor. */
+ if (!w->pseudo_window_p
+ && x_phys_cursor_in_rect_p (w, &r))
+ {
+ x_clear_cursor (w);
+ cursor_cleared_p = 1;
+ }
+ else
+ cursor_cleared_p = 0;
+
+ /* Find the first row intersecting the rectangle R. */
+ for (row = w->current_matrix->rows;
+ row->enabled_p;
+ ++row)
+ {
+ int y0 = row->y;
+ int y1 = MATRIX_ROW_BOTTOM_Y (row);
+
+ if ((y0 >= r.top && y0 < r.bottom)
+ || (y1 > r.top && y1 < r.bottom)
+ || (r.top >= y0 && r.top < y1)
+ || (r.bottom > y0 && r.bottom < y1))
+ {
+ if (expose_line (w, row, &r))
+ mouse_face_overwritten_p = 1;
+ }
+
+ if (y1 >= yb)
+ break;
+ }
+
+ /* Display the mode line if there is one. */
+ if (WINDOW_WANTS_MODELINE_P (w)
+ && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
+ row->enabled_p)
+ && row->y < r.bottom)
+ {
+ if (expose_line (w, row, &r))
+ mouse_face_overwritten_p = 1;
+ }
+
+ if (!w->pseudo_window_p)
+ {
+ /* Draw border between windows. */
+ x_draw_vertical_border (w);
+
+ /* Turn the cursor on again. */
+ if (cursor_cleared_p)
+ x_update_window_cursor (w, 1);
+ }
+ }
+
+ /* Display scroll bar for this window. */
+ if (!NILP (w->vertical_scroll_bar))
+ {
+ ControlHandle ch
+ = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar));
+
+ Draw1Control (ch);
+ }
+
+ return mouse_face_overwritten_p;
+}
+
+static int
+x_intersect_rectangles (r1, r2, result)
+ Rect *r1, *r2, *result;
+{
+ Rect *left, *right;
+ Rect *upper, *lower;
+ int intersection_p = 0;
+
+ /* Rerrange so that R1 is the left-most rectangle. */
+ if (r1->left < r2->left)
+ left = r1, right = r2;
+ else
+ left = r2, right = r1;
+
+ /* X0 of the intersection is right.x0, if this is inside R1,
+ otherwise there is no intersection. */
+ if (right->left <= left->right)
+ {
+ result->left = right->left;
+
+ /* The right end of the intersection is the minimum of the
+ the right ends of left and right. */
+ result->right = min (left->right, right->right);
+
+ /* Same game for Y. */
+ if (r1->top < r2->top)
+ upper = r1, lower = r2;
+ else
+ upper = r2, lower = r1;
+
+ /* The upper end of the intersection is lower.y0, if this is inside
+ of upper. Otherwise, there is no intersection. */
+ if (lower->top <= upper->bottom)
+ {
+ result->top = lower->top;
+
+ /* The lower end of the intersection is the minimum of the lower
+ ends of upper and lower. */
+ result->bottom = min (lower->bottom, upper->bottom);
+ intersection_p = 1;
+ }
+ }
+
+ return intersection_p;
+}
+
+
+
+
+
+static void
+frame_highlight (f)
+ struct frame *f;
+{
+ x_update_cursor (f, 1);
+}
+
+static void
+frame_unhighlight (f)
+ struct frame *f;
+{
+ x_update_cursor (f, 1);
+}
+
+/* The focus has changed. Update the frames as necessary to reflect
+ the new situation. Note that we can't change the selected frame
+ here, because the Lisp code we are interrupting might become confused.
+ Each event gets marked with the frame in which it occurred, so the
+ Lisp code can tell when the switch took place by examining the events. */
+
+static void
+x_new_focus_frame (dpyinfo, frame)
+ struct x_display_info *dpyinfo;
+ struct frame *frame;
+{
+ struct frame *old_focus = dpyinfo->x_focus_frame;
+
+ if (frame != dpyinfo->x_focus_frame)
+ {
+ /* Set this before calling other routines, so that they see
+ the correct value of x_focus_frame. */
+ dpyinfo->x_focus_frame = frame;
+
+ if (old_focus && old_focus->auto_lower)
+ x_lower_frame (old_focus);
+
+#if 0
+ selected_frame = frame;
+ XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
+ selected_frame);
+ Fselect_window (selected_frame->selected_window);
+ choose_minibuf_frame ();
+#endif /* ! 0 */
+
+ if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
+ pending_autoraise_frame = dpyinfo->x_focus_frame;
+ else
+ pending_autoraise_frame = 0;
+ }
+
+ x_frame_rehighlight (dpyinfo);
+}
+
+/* Handle an event saying the mouse has moved out of an Emacs frame. */
+
+void
+x_mouse_leave (dpyinfo)
+ struct x_display_info *dpyinfo;
+{
+ x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
+}
+
+/* The focus has changed, or we have redirected a frame's focus to
+ another frame (this happens when a frame uses a surrogate
+ mini-buffer frame). Shift the highlight as appropriate.
+
+ The FRAME argument doesn't necessarily have anything to do with which
+ frame is being highlighted or un-highlighted; we only use it to find
+ the appropriate X display info. */
+
+static void
+XTframe_rehighlight (frame)
+ struct frame *frame;
+{
+ x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
+}
+
+static void
+x_frame_rehighlight (dpyinfo)
+ struct x_display_info *dpyinfo;
+{
+ struct frame *old_highlight = dpyinfo->x_highlight_frame;
+
+ if (dpyinfo->x_focus_frame)
+ {
+ dpyinfo->x_highlight_frame
+ = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
+ ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
+ : dpyinfo->x_focus_frame);
+ if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
+ {
+ FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
+ dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
+ }
+ }
+ else
+ dpyinfo->x_highlight_frame = 0;
+
+ if (dpyinfo->x_highlight_frame != old_highlight)
+ {
+ if (old_highlight)
+ frame_unhighlight (old_highlight);
+ if (dpyinfo->x_highlight_frame)
+ frame_highlight (dpyinfo->x_highlight_frame);
+ }
+}
+
+
+
+/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
+
+#if 0 /* MAC_TODO */
+/* Initialize mode_switch_bit and modifier_meaning. */
+static void
+x_find_modifier_meanings (dpyinfo)
+ struct x_display_info *dpyinfo;
+{
+ int min_code, max_code;
+ KeySym *syms;
+ int syms_per_code;
+ XModifierKeymap *mods;
+
+ dpyinfo->meta_mod_mask = 0;
+ dpyinfo->shift_lock_mask = 0;
+ dpyinfo->alt_mod_mask = 0;
+ dpyinfo->super_mod_mask = 0;
+ dpyinfo->hyper_mod_mask = 0;
+
+#ifdef HAVE_X11R4
+ XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
+#else
+ min_code = dpyinfo->display->min_keycode;
+ max_code = dpyinfo->display->max_keycode;
+#endif
+
+ syms = XGetKeyboardMapping (dpyinfo->display,
+ min_code, max_code - min_code + 1,
+ &syms_per_code);
+ mods = XGetModifierMapping (dpyinfo->display);
+
+ /* Scan the modifier table to see which modifier bits the Meta and
+ Alt keysyms are on. */
+ {
+ int row, col; /* The row and column in the modifier table. */
+
+ for (row = 3; row < 8; row++)
+ for (col = 0; col < mods->max_keypermod; col++)
+ {
+ KeyCode code
+ = mods->modifiermap[(row * mods->max_keypermod) + col];
+
+ /* Zeroes are used for filler. Skip them. */
+ if (code == 0)
+ continue;
+
+ /* Are any of this keycode's keysyms a meta key? */
+ {
+ int code_col;
+
+ for (code_col = 0; code_col < syms_per_code; code_col++)
+ {
+ int sym = syms[((code - min_code) * syms_per_code) + code_col];
+
+ switch (sym)
+ {
+ case XK_Meta_L:
+ case XK_Meta_R:
+ dpyinfo->meta_mod_mask |= (1 << row);
+ break;
+
+ case XK_Alt_L:
+ case XK_Alt_R:
+ dpyinfo->alt_mod_mask |= (1 << row);
+ break;
+
+ case XK_Hyper_L:
+ case XK_Hyper_R:
+ dpyinfo->hyper_mod_mask |= (1 << row);
+ break;
+
+ case XK_Super_L:
+ case XK_Super_R:
+ dpyinfo->super_mod_mask |= (1 << row);
+ break;
+
+ case XK_Shift_Lock:
+ /* Ignore this if it's not on the lock modifier. */
+ if ((1 << row) == LockMask)
+ dpyinfo->shift_lock_mask = LockMask;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
+ if (! dpyinfo->meta_mod_mask)
+ {
+ dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
+ dpyinfo->alt_mod_mask = 0;
+ }
+
+ /* If some keys are both alt and meta,
+ make them just meta, not alt. */
+ if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
+ {
+ dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
+ }
+
+ XFree ((char *) syms);
+ XFreeModifiermap (mods);
+}
+
+#endif /* MAC_TODO */
+
+/* Convert between the modifier bits X uses and the modifier bits
+ Emacs uses. */
+
+static unsigned int
+x_mac_to_emacs_modifiers (dpyinfo, state)
+ struct x_display_info *dpyinfo;
+ unsigned short state;
+{
+ return (((state & shiftKey) ? shift_modifier : 0)
+ | ((state & controlKey) ? ctrl_modifier : 0)
+ | ((state & cmdKey) ? meta_modifier : 0)
+ | ((state & optionKey) ? alt_modifier : 0));
+}
+
+#if 0 /* MAC_TODO */
+static unsigned short
+x_emacs_to_x_modifiers (dpyinfo, state)
+ struct x_display_info *dpyinfo;
+ unsigned int state;
+{
+ return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
+ | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
+ | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
+ | ((state & shift_modifier) ? ShiftMask : 0)
+ | ((state & ctrl_modifier) ? ControlMask : 0)
+ | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
+}
+#endif /* MAC_TODO */
+
+/* Convert a keysym to its name. */
+
+char *
+x_get_keysym_name (keysym)
+ int keysym;
+{
+ char *value;
+
+ BLOCK_INPUT;
+#if 0
+ value = XKeysymToString (keysym);
+#else
+ value = 0;
+#endif
+ UNBLOCK_INPUT;
+
+ return value;
+}
+
+
+
+/* Mouse clicks and mouse movement. Rah. */
+
+/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
+ co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
+ glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
+ not force the value into range. */
+
+void
+pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
+ FRAME_PTR f;
+ register int pix_x, pix_y;
+ register int *x, *y;
+ Rect *bounds;
+ int noclip;
+{
+ /* Support tty mode: if Vwindow_system is nil, behave correctly. */
+ if (NILP (Vwindow_system))
+ {
+ *x = pix_x;
+ *y = pix_y;
+ return;
+ }
+
+ /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
+ even for negative values. */
+ if (pix_x < 0)
+ pix_x -= FONT_WIDTH (FRAME_FONT (f)) - 1;
+ if (pix_y < 0)
+ pix_y -= (f)->output_data.mac->line_height - 1;
+
+ pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
+ pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
+
+ if (bounds)
+ {
+ bounds->left = CHAR_TO_PIXEL_COL (f, pix_x);
+ bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y);
+ bounds->right = bounds->left + FONT_WIDTH (FRAME_FONT (f)) - 1;
+ bounds->bottom = bounds->top + f->output_data.mac->line_height - 1;
+ }
+
+ if (!noclip)
+ {
+ if (pix_x < 0)
+ pix_x = 0;
+ else if (pix_x > FRAME_WINDOW_WIDTH (f))
+ pix_x = FRAME_WINDOW_WIDTH (f);
+
+ if (pix_y < 0)
+ pix_y = 0;
+ else if (pix_y > f->height)
+ pix_y = f->height;
+ }
+
+ *x = pix_x;
+ *y = pix_y;
+}
+
+
+/* Given HPOS/VPOS in the current matrix of W, return corresponding
+ frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
+ can't tell the positions because W's display is not up to date,
+ return 0. */
+
+int
+glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
+ struct window *w;
+ int hpos, vpos;
+ int *frame_x, *frame_y;
+{
+ int success_p;
+
+ xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
+ xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
+
+ if (display_completed)
+ {
+ struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
+ struct glyph *glyph = row->glyphs[TEXT_AREA];
+ struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
+
+ *frame_y = row->y;
+ *frame_x = row->x;
+ while (glyph < end)
+ {
+ *frame_x += glyph->pixel_width;
+ ++glyph;
+ }
+
+ success_p = 1;
+ }
+ else
+ {
+ *frame_y = *frame_x = 0;
+ success_p = 0;
+ }
+
+ *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
+ *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
+ return success_p;
+}
+
+
+/* Prepare a mouse-event in *RESULT for placement in the input queue.
+
+ If the event is a button press, then note that we have grabbed
+ the mouse. */
+
+static Lisp_Object
+construct_mouse_click (result, event, f)
+ struct input_event *result;
+ EventRecord *event;
+ struct frame *f;
+{
+ Point mouseLoc;
+
+ result->kind = mouse_click;
+ result->code = 0; /* only one mouse button */
+ result->timestamp = event->when;
+ result->modifiers = event->what == mouseDown ? down_modifier : up_modifier;
+
+ mouseLoc = event->where;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (FRAME_MAC_WINDOW (f)));
+#else
+ SetPort (FRAME_MAC_WINDOW (f));
+#endif
+
+ GlobalToLocal (&mouseLoc);
+ XSETINT (result->x, mouseLoc.h);
+ XSETINT (result->y, mouseLoc.v);
+
+ XSETFRAME (result->frame_or_window, f);
+
+ result->arg = Qnil;
+ return Qnil;
+}
+
+
+/* Function to report a mouse movement to the mainstream Emacs code.
+ The input handler calls this.
+
+ We have received a mouse movement event, which is given in *event.
+ If the mouse is over a different glyph than it was last time, tell
+ the mainstream emacs code by setting mouse_moved. If not, ask for
+ another motion event, so we can check again the next time it moves. */
+
+static Point last_mouse_motion_position;
+static Lisp_Object last_mouse_motion_frame;
+
+static void
+note_mouse_movement (frame, pos)
+ FRAME_PTR frame;
+ Point *pos;
+{
+#if TARGET_API_MAC_CARBON
+ Rect r;
+#endif
+
+ last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
+ last_mouse_motion_position = *pos;
+ XSETFRAME (last_mouse_motion_frame, frame);
+
+#if TARGET_API_MAC_CARBON
+ if (!PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r)))
+#else
+ if (!PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect))
+#endif
+ {
+ frame->mouse_moved = 1;
+ last_mouse_scroll_bar = Qnil;
+ note_mouse_highlight (frame, -1, -1);
+ }
+ /* Has the mouse moved off the glyph it was on at the last sighting? */
+ else if (pos->h < last_mouse_glyph.left
+ || pos->h >= last_mouse_glyph.right
+ || pos->v < last_mouse_glyph.top
+ || pos->v >= last_mouse_glyph.bottom)
+ {
+ frame->mouse_moved = 1;
+ last_mouse_scroll_bar = Qnil;
+ note_mouse_highlight (frame, pos->h, pos->v);
+ }
+}
+
+/* This is used for debugging, to turn off note_mouse_highlight. */
+
+int disable_mouse_highlight;
+
+
+
+/************************************************************************
+ Mouse Face
+ ************************************************************************/
+
+/* Find the glyph under window-relative coordinates X/Y in window W.
+ Consider only glyphs from buffer text, i.e. no glyphs from overlay
+ strings. Return in *HPOS and *VPOS the row and column number of
+ the glyph found. Return in *AREA the glyph area containing X.
+ Value is a pointer to the glyph found or null if X/Y is not on
+ text, or we can't tell because W's current matrix is not up to
+ date. */
+
+static struct glyph *
+x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
+ struct window *w;
+ int x, y;
+ int *hpos, *vpos, *area;
+ int buffer_only_p;
+{
+ struct glyph *glyph, *end;
+ struct glyph_row *row = NULL;
+ int x0, i, left_area_width;
+
+ /* Find row containing Y. Give up if some row is not enabled. */
+ for (i = 0; i < w->current_matrix->nrows; ++i)
+ {
+ row = MATRIX_ROW (w->current_matrix, i);
+ if (!row->enabled_p)
+ return NULL;
+ if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
+ break;
+ }
+
+ *vpos = i;
+ *hpos = 0;
+
+ /* Give up if Y is not in the window. */
+ if (i == w->current_matrix->nrows)
+ return NULL;
+
+ /* Get the glyph area containing X. */
+ if (w->pseudo_window_p)
+ {
+ *area = TEXT_AREA;
+ x0 = 0;
+ }
+ else
+ {
+ left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
+ if (x < left_area_width)
+ {
+ *area = LEFT_MARGIN_AREA;
+ x0 = 0;
+ }
+ else if (x < left_area_width + window_box_width (w, TEXT_AREA))
+ {
+ *area = TEXT_AREA;
+ x0 = row->x + left_area_width;
+ }
+ else
+ {
+ *area = RIGHT_MARGIN_AREA;
+ x0 = left_area_width + window_box_width (w, TEXT_AREA);
+ }
+ }
+
+ /* Find glyph containing X. */
+ glyph = row->glyphs[*area];
+ end = glyph + row->used[*area];
+ while (glyph < end)
+ {
+ if (x < x0 + glyph->pixel_width)
+ {
+ if (w->pseudo_window_p)
+ break;
+ else if (!buffer_only_p || BUFFERP (glyph->object))
+ break;
+ }
+
+ x0 += glyph->pixel_width;
+ ++glyph;
+ }
+
+ if (glyph == end)
+ return NULL;
+
+ *hpos = glyph - row->glyphs[*area];
+ return glyph;
+}
+
+
+/* Convert frame-relative x/y to coordinates relative to window W.
+ Takes pseudo-windows into account. */
+
+static void
+frame_to_window_pixel_xy (w, x, y)
+ struct window *w;
+ int *x, *y;
+{
+ if (w->pseudo_window_p)
+ {
+ /* A pseudo-window is always full-width, and starts at the
+ left edge of the frame, plus a frame border. */
+ struct frame *f = XFRAME (w->frame);
+ *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
+ *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+ }
+ else
+ {
+ *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
+ *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+ }
+}
+
+
+/* Take proper action when mouse has moved to the mode or header line of
+ window W, x-position X. MODE_LINE_P non-zero means mouse is on the
+ mode line. X is relative to the start of the text display area of
+ W, so the width of fringes and scroll bars must be subtracted
+ to get a position relative to the start of the mode line. */
+
+static void
+note_mode_line_highlight (w, x, mode_line_p)
+ struct window *w;
+ int x, mode_line_p;
+{
+ struct frame *f = XFRAME (w->frame);
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ struct Cursor *cursor = dpyinfo->vertical_scroll_bar_cursor;
+ struct glyph_row *row;
+
+ if (mode_line_p)
+ row = MATRIX_MODE_LINE_ROW (w->current_matrix);
+ else
+ row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
+
+ if (row->enabled_p)
+ {
+ struct glyph *glyph, *end;
+ Lisp_Object help, map;
+ int x0;
+
+ /* Find the glyph under X. */
+ glyph = row->glyphs[TEXT_AREA];
+ end = glyph + row->used[TEXT_AREA];
+ x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
+ + FRAME_X_LEFT_FRINGE_WIDTH (f));
+
+ while (glyph < end
+ && x >= x0 + glyph->pixel_width)
+ {
+ x0 += glyph->pixel_width;
+ ++glyph;
+ }
+
+ if (glyph < end
+ && STRINGP (glyph->object)
+ && XSTRING (glyph->object)->intervals
+ && glyph->charpos >= 0
+ && glyph->charpos < XSTRING (glyph->object)->size)
+ {
+ /* If we're on a string with `help-echo' text property,
+ arrange for the help to be displayed. This is done by
+ setting the global variable help_echo to the help string. */
+ help = Fget_text_property (make_number (glyph->charpos),
+ Qhelp_echo, glyph->object);
+ if (!NILP (help))
+ {
+ help_echo = help;
+ XSETWINDOW (help_echo_window, w);
+ help_echo_object = glyph->object;
+ help_echo_pos = glyph->charpos;
+ }
+
+ /* Change the mouse pointer according to what is under X/Y. */
+ map = Fget_text_property (make_number (glyph->charpos),
+ Qlocal_map, glyph->object);
+ if (KEYMAPP (map))
+ cursor = f->output_data.mac->nontext_cursor;
+ else
+ {
+ map = Fget_text_property (make_number (glyph->charpos),
+ Qkeymap, glyph->object);
+ if (KEYMAPP (map))
+ cursor = f->output_data.mac->nontext_cursor;
+ }
+ }
+ }
+
+#if 0 /* MAC_TODO: mouse cursor */
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
+#endif
+}
+
+
+/* Take proper action when the mouse has moved to position X, Y on
+ frame F as regards highlighting characters that have mouse-face
+ properties. Also de-highlighting chars where the mouse was before.
+ X and Y can be negative or out of range. */
+
+static void
+note_mouse_highlight (f, x, y)
+ struct frame *f;
+ int x, y;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ int portion;
+ Lisp_Object window;
+ struct window *w;
+ struct buffer *b;
+
+#if 0
+ /* When a menu is active, don't highlight because this looks odd. */
+ if (popup_activated ())
+ return;
+#endif
+
+ if (NILP (Vmouse_highlight)
+ || !f->glyphs_initialized_p)
+ return;
+
+ dpyinfo->mouse_face_mouse_x = x;
+ dpyinfo->mouse_face_mouse_y = y;
+ dpyinfo->mouse_face_mouse_frame = f;
+
+ if (dpyinfo->mouse_face_defer)
+ return;
+
+ if (gc_in_progress)
+ {
+ dpyinfo->mouse_face_deferred_gc = 1;
+ return;
+ }
+
+ /* Which window is that in? */
+ window = window_from_coordinates (f, x, y, &portion, 1);
+
+ /* If we were displaying active text in another window, clear that. */
+ if (! EQ (window, dpyinfo->mouse_face_window))
+ clear_mouse_face (dpyinfo);
+
+ /* Not on a window -> return. */
+ if (!WINDOWP (window))
+ return;
+
+ /* Reset help_echo. It will get recomputed below. */
+ help_echo = Qnil;
+
+ /* Convert to window-relative pixel coordinates. */
+ w = XWINDOW (window);
+ frame_to_window_pixel_xy (w, &x, &y);
+
+ /* Handle tool-bar window differently since it doesn't display a
+ buffer. */
+ if (EQ (window, f->tool_bar_window))
+ {
+ note_tool_bar_highlight (f, x, y);
+ return;
+ }
+
+ /* Mouse is on the mode or header line? */
+ if (portion == 1 || portion == 3)
+ {
+ note_mode_line_highlight (w, x, portion == 1);
+ return;
+ }
+#if 0 /* TODO: mouse cursor */
+ if (portion == 2)
+ cursor = f->output_data.x->horizontal_drag_cursor;
+ else
+ cursor = f->output_data.x->text_cursor;
+#endif
+ /* Are we in a window whose display is up to date?
+ And verify the buffer's text has not changed. */
+ b = XBUFFER (w->buffer);
+ if (/* Within text portion of the window. */
+ portion == 0
+ && EQ (w->window_end_valid, w->buffer)
+ && XFASTINT (w->last_modified) == BUF_MODIFF (b)
+ && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
+ {
+ int hpos, vpos, pos, i, area;
+ struct glyph *glyph;
+ Lisp_Object object;
+ Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
+ Lisp_Object *overlay_vec = NULL;
+ int len, noverlays;
+ struct buffer *obuf;
+ int obegv, ozv, same_region;
+
+ /* Find the glyph under X/Y. */
+ glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
+
+ /* Clear mouse face if X/Y not over text. */
+ if (glyph == NULL
+ || area != TEXT_AREA
+ || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
+ {
+ clear_mouse_face (dpyinfo);
+ /* TODO: mouse cursor */
+ goto set_cursor;
+ }
+
+ pos = glyph->charpos;
+ object = glyph->object;
+ if (!STRINGP (object) && !BUFFERP (object))
+ goto set_cursor;
+
+ /* If we get an out-of-range value, return now; avoid an error. */
+ if (BUFFERP (object) && pos > BUF_Z (b))
+ goto set_cursor;
+
+ /* Make the window's buffer temporarily current for
+ overlays_at and compute_char_face. */
+ obuf = current_buffer;
+ current_buffer = b;
+ obegv = BEGV;
+ ozv = ZV;
+ BEGV = BEG;
+ ZV = Z;
+
+ /* Is this char mouse-active or does it have help-echo? */
+ position = make_number (pos);
+
+ if (BUFFERP (object))
+ {
+ /* Put all the overlays we want in a vector in overlay_vec.
+ Store the length in len. If there are more than 10, make
+ enough space for all, and try again. */
+ len = 10;
+ overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+ noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
+ if (noverlays > len)
+ {
+ len = noverlays;
+ overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+ noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
+ }
+
+ /* Sort overlays into increasing priority order. */
+ noverlays = sort_overlays (overlay_vec, noverlays, w);
+ }
+ else
+ noverlays = 0;
+
+ same_region = (EQ (window, dpyinfo->mouse_face_window)
+ && vpos >= dpyinfo->mouse_face_beg_row
+ && vpos <= dpyinfo->mouse_face_end_row
+ && (vpos > dpyinfo->mouse_face_beg_row
+ || hpos >= dpyinfo->mouse_face_beg_col)
+ && (vpos < dpyinfo->mouse_face_end_row
+ || hpos < dpyinfo->mouse_face_end_col
+ || dpyinfo->mouse_face_past_end));
+
+ /* TODO: if (same_region)
+ mouse cursor */
+
+ /* Check mouse-face highlighting. */
+ if (! same_region
+ /* If there exists an overlay with mouse-face overlapping
+ the one we are currently highlighting, we have to
+ check if we enter the overlapping overlay, and then
+ highlight that. */
+ || (OVERLAYP (dpyinfo->mouse_face_overlay)
+ && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
+ {
+ /* Find the highest priority overlay that has a mouse-face
+ property. */
+ overlay = Qnil;
+ for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
+ {
+ mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
+ if (!NILP (mouse_face))
+ overlay = overlay_vec[i];
+ }
+
+ /* If we're actually highlighting the same overlay as
+ before, there's no need to do that again. */
+ if (!NILP (overlay)
+ && EQ (overlay, dpyinfo->mouse_face_overlay))
+ goto check_help_echo;
+
+ dpyinfo->mouse_face_overlay = overlay;
+
+ /* Clear the display of the old active region, if any. */
+ clear_mouse_face (dpyinfo);
+ /* TODO: mouse cursor changes. */
+
+ /* If no overlay applies, get a text property. */
+ if (NILP (overlay))
+ mouse_face = Fget_text_property (position, Qmouse_face, object);
+
+ /* Handle the overlay case. */
+ if (!NILP (overlay))
+ {
+ /* Find the range of text around this char that
+ should be active. */
+ Lisp_Object before, after;
+ int ignore;
+
+ before = Foverlay_start (overlay);
+ after = Foverlay_end (overlay);
+ /* Record this as the current active region. */
+ fast_find_position (w, XFASTINT (before),
+ &dpyinfo->mouse_face_beg_col,
+ &dpyinfo->mouse_face_beg_row,
+ &dpyinfo->mouse_face_beg_x,
+ &dpyinfo->mouse_face_beg_y, Qnil);
+
+ dpyinfo->mouse_face_past_end
+ = !fast_find_position (w, XFASTINT (after),
+ &dpyinfo->mouse_face_end_col,
+ &dpyinfo->mouse_face_end_row,
+ &dpyinfo->mouse_face_end_x,
+ &dpyinfo->mouse_face_end_y, Qnil);
+ dpyinfo->mouse_face_window = window;
+
+ dpyinfo->mouse_face_face_id
+ = face_at_buffer_position (w, pos, 0, 0,
+ &ignore, pos + 1, 1);
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ /* TODO: mouse cursor changes. */
+ }
+ /* Handle the text property case. */
+ else if (! NILP (mouse_face) && BUFFERP (object))
+ {
+ /* Find the range of text around this char that
+ should be active. */
+ Lisp_Object before, after, beginning, end;
+ int ignore;
+
+ beginning = Fmarker_position (w->start);
+ end = make_number (BUF_Z (XBUFFER (object))
+ - XFASTINT (w->window_end_pos));
+ before
+ = Fprevious_single_property_change (make_number (pos + 1),
+ Qmouse_face,
+ object, beginning);
+ after
+ = Fnext_single_property_change (position, Qmouse_face,
+ object, end);
+
+ /* Record this as the current active region. */
+ fast_find_position (w, XFASTINT (before),
+ &dpyinfo->mouse_face_beg_col,
+ &dpyinfo->mouse_face_beg_row,
+ &dpyinfo->mouse_face_beg_x,
+ &dpyinfo->mouse_face_beg_y, Qnil);
+ dpyinfo->mouse_face_past_end
+ = !fast_find_position (w, XFASTINT (after),
+ &dpyinfo->mouse_face_end_col,
+ &dpyinfo->mouse_face_end_row,
+ &dpyinfo->mouse_face_end_x,
+ &dpyinfo->mouse_face_end_y, Qnil);
+ dpyinfo->mouse_face_window = window;
+
+ if (BUFFERP (object))
+ dpyinfo->mouse_face_face_id
+ = face_at_buffer_position (w, pos, 0, 0,
+ &ignore, pos + 1, 1);
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ /* TODO: mouse cursor changes. */
+ }
+ else if (!NILP (mouse_face) && STRINGP (object))
+ {
+ Lisp_Object b, e;
+ int ignore;
+
+ b = Fprevious_single_property_change (make_number (pos + 1),
+ Qmouse_face,
+ object, Qnil);
+ e = Fnext_single_property_change (position, Qmouse_face,
+ object, Qnil);
+ if (NILP (b))
+ b = make_number (0);
+ if (NILP (e))
+ e = make_number (XSTRING (object)->size - 1);
+ fast_find_string_pos (w, XINT (b), object,
+ &dpyinfo->mouse_face_beg_col,
+ &dpyinfo->mouse_face_beg_row,
+ &dpyinfo->mouse_face_beg_x,
+ &dpyinfo->mouse_face_beg_y, 0);
+ fast_find_string_pos (w, XINT (e), object,
+ &dpyinfo->mouse_face_end_col,
+ &dpyinfo->mouse_face_end_row,
+ &dpyinfo->mouse_face_end_x,
+ &dpyinfo->mouse_face_end_y, 1);
+ dpyinfo->mouse_face_past_end = 0;
+ dpyinfo->mouse_face_window = window;
+ dpyinfo->mouse_face_face_id
+ = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
+ glyph->face_id, 1);
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ /* TODO: mouse cursor changes. */
+ }
+ else if (STRINGP (object) && NILP (mouse_face))
+ {
+ /* A string which doesn't have mouse-face, but
+ the text ``under'' it might have. */
+ struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
+ int start = MATRIX_ROW_START_CHARPOS (r);
+
+ pos = string_buffer_position (w, object, start);
+ if (pos > 0)
+ mouse_face = get_char_property_and_overlay (make_number (pos),
+ Qmouse_face,
+ w->buffer,
+ &overlay);
+ if (!NILP (mouse_face) && !NILP (overlay))
+ {
+ Lisp_Object before = Foverlay_start (overlay);
+ Lisp_Object after = Foverlay_end (overlay);
+ int ignore;
+
+ /* Note that we might not be able to find position
+ BEFORE in the glyph matrix if the overlay is
+ entirely covered by a `display' property. In
+ this case, we overshoot. So let's stop in
+ the glyph matrix before glyphs for OBJECT. */
+ fast_find_position (w, XFASTINT (before),
+ &dpyinfo->mouse_face_beg_col,
+ &dpyinfo->mouse_face_beg_row,
+ &dpyinfo->mouse_face_beg_x,
+ &dpyinfo->mouse_face_beg_y,
+ object);
+
+ dpyinfo->mouse_face_past_end
+ = !fast_find_position (w, XFASTINT (after),
+ &dpyinfo->mouse_face_end_col,
+ &dpyinfo->mouse_face_end_row,
+ &dpyinfo->mouse_face_end_x,
+ &dpyinfo->mouse_face_end_y,
+ Qnil);
+ dpyinfo->mouse_face_window = window;
+ dpyinfo->mouse_face_face_id
+ = face_at_buffer_position (w, pos, 0, 0,
+ &ignore, pos + 1, 1);
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ /* TODO: mouse cursor changes. */
+ }
+ }
+ }
+
+ check_help_echo:
+
+ /* Look for a `help-echo' property. */
+ {
+ Lisp_Object help, overlay;
+
+ /* Check overlays first. */
+ help = overlay = Qnil;
+ for (i = noverlays - 1; i >= 0 && NILP (help); --i)
+ {
+ overlay = overlay_vec[i];
+ help = Foverlay_get (overlay, Qhelp_echo);
+ }
+
+ if (!NILP (help))
+ {
+ help_echo = help;
+ help_echo_window = window;
+ help_echo_object = overlay;
+ help_echo_pos = pos;
+ }
+ else
+ {
+ Lisp_Object object = glyph->object;
+ int charpos = glyph->charpos;
+
+ /* Try text properties. */
+ if (STRINGP (object)
+ && charpos >= 0
+ && charpos < XSTRING (object)->size)
+ {
+ help = Fget_text_property (make_number (charpos),
+ Qhelp_echo, object);
+ if (NILP (help))
+ {
+ /* If the string itself doesn't specify a help-echo,
+ see if the buffer text ``under'' it does. */
+ struct glyph_row *r
+ = MATRIX_ROW (w->current_matrix, vpos);
+ int start = MATRIX_ROW_START_CHARPOS (r);
+ int pos = string_buffer_position (w, object, start);
+ if (pos > 0)
+ {
+ help = Fget_char_property (make_number (pos),
+ Qhelp_echo, w->buffer);
+ if (!NILP (help))
+ {
+ charpos = pos;
+ object = w->buffer;
+ }
+ }
+ }
+ }
+ else if (BUFFERP (object)
+ && charpos >= BEGV
+ && charpos < ZV)
+ help = Fget_text_property (make_number (charpos), Qhelp_echo,
+ object);
+
+ if (!NILP (help))
+ {
+ help_echo = help;
+ help_echo_window = window;
+ help_echo_object = object;
+ help_echo_pos = charpos;
+ }
+ }
+ }
+
+ BEGV = obegv;
+ ZV = ozv;
+ current_buffer = obuf;
+ }
+
+ set_cursor:
+ /* TODO: mouse cursor changes. */
+ ;
+}
+
+static void
+redo_mouse_highlight ()
+{
+ if (!NILP (last_mouse_motion_frame)
+ && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
+ note_mouse_highlight (XFRAME (last_mouse_motion_frame),
+ last_mouse_motion_position.h,
+ last_mouse_motion_position.v);
+}
+
+
+
+/***********************************************************************
+ Tool-bars
+ ***********************************************************************/
+
+static int x_tool_bar_item P_ ((struct frame *, int, int,
+ struct glyph **, int *, int *, int *));
+
+/* Tool-bar item index of the item on which a mouse button was pressed
+ or -1. */
+
+static int last_tool_bar_item;
+
+
+/* Get information about the tool-bar item at position X/Y on frame F.
+ Return in *GLYPH a pointer to the glyph of the tool-bar item in
+ the current matrix of the tool-bar window of F, or NULL if not
+ on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
+ item in F->current_tool_bar_items. Value is
+
+ -1 if X/Y is not on a tool-bar item
+ 0 if X/Y is on the same item that was highlighted before.
+ 1 otherwise. */
+
+static int
+x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
+ struct frame *f;
+ int x, y;
+ struct glyph **glyph;
+ int *hpos, *vpos, *prop_idx;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ struct window *w = XWINDOW (f->tool_bar_window);
+ int area;
+
+ /* Find the glyph under X/Y. */
+ *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
+ if (*glyph == NULL)
+ return -1;
+
+ /* Get the start of this tool-bar item's properties in
+ f->current_tool_bar_items. */
+ if (!tool_bar_item_info (f, *glyph, prop_idx))
+ return -1;
+
+ /* Is mouse on the highlighted item? */
+ if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
+ && *vpos >= dpyinfo->mouse_face_beg_row
+ && *vpos <= dpyinfo->mouse_face_end_row
+ && (*vpos > dpyinfo->mouse_face_beg_row
+ || *hpos >= dpyinfo->mouse_face_beg_col)
+ && (*vpos < dpyinfo->mouse_face_end_row
+ || *hpos < dpyinfo->mouse_face_end_col
+ || dpyinfo->mouse_face_past_end))
+ return 0;
+
+ return 1;
+}
+
+
+/* Handle mouse button event on the tool-bar of frame F, at
+ frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
+ or ButtonRelase. */
+
+static void
+x_handle_tool_bar_click (f, button_event)
+ struct frame *f;
+ EventRecord *button_event;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ struct window *w = XWINDOW (f->tool_bar_window);
+ int hpos, vpos, prop_idx;
+ struct glyph *glyph;
+ Lisp_Object enabled_p;
+ int x = button_event->where.h;
+ int y = button_event->where.v;
+
+ /* If not on the highlighted tool-bar item, return. */
+ frame_to_window_pixel_xy (w, &x, &y);
+ if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
+ return;
+
+ /* If item is disabled, do nothing. */
+ enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+ if (NILP (enabled_p))
+ return;
+
+ if (button_event->what == mouseDown)
+ {
+ /* Show item in pressed state. */
+ show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
+ dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
+ last_tool_bar_item = prop_idx;
+ }
+ else
+ {
+ Lisp_Object key, frame;
+ struct input_event event;
+
+ /* Show item in released state. */
+ show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
+ dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
+
+ key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
+
+ XSETFRAME (frame, f);
+ event.kind = TOOL_BAR_EVENT;
+ event.frame_or_window = frame;
+ event.arg = frame;
+ kbd_buffer_store_event (&event);
+
+ event.kind = TOOL_BAR_EVENT;
+ event.frame_or_window = frame;
+ event.arg = key;
+ event.modifiers = x_mac_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+ button_event->modifiers);
+ kbd_buffer_store_event (&event);
+ last_tool_bar_item = -1;
+ }
+}
+
+
+/* Possibly highlight a tool-bar item on frame F when mouse moves to
+ tool-bar window-relative coordinates X/Y. Called from
+ note_mouse_highlight. */
+
+static void
+note_tool_bar_highlight (f, x, y)
+ struct frame *f;
+ int x, y;
+{
+ Lisp_Object window = f->tool_bar_window;
+ struct window *w = XWINDOW (window);
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ int hpos, vpos;
+ struct glyph *glyph;
+ struct glyph_row *row;
+ int i;
+ Lisp_Object enabled_p;
+ int prop_idx;
+ enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
+ int mouse_down_p, rc;
+
+ /* Function note_mouse_highlight is called with negative x(y
+ values when mouse moves outside of the frame. */
+ if (x <= 0 || y <= 0)
+ {
+ clear_mouse_face (dpyinfo);
+ return;
+ }
+
+ rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
+ if (rc < 0)
+ {
+ /* Not on tool-bar item. */
+ clear_mouse_face (dpyinfo);
+ return;
+ }
+ else if (rc == 0)
+ /* On same tool-bar item as before. */
+ goto set_help_echo;
+
+ clear_mouse_face (dpyinfo);
+
+ /* Mouse is down, but on different tool-bar item? */
+ mouse_down_p = (dpyinfo->grabbed
+ && f == last_mouse_frame
+ && FRAME_LIVE_P (f));
+ if (mouse_down_p
+ && last_tool_bar_item != prop_idx)
+ return;
+
+ dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
+ draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
+
+ /* If tool-bar item is not enabled, don't highlight it. */
+ enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+ if (!NILP (enabled_p))
+ {
+ /* Compute the x-position of the glyph. In front and past the
+ image is a space. We include this is the highlighted area. */
+ row = MATRIX_ROW (w->current_matrix, vpos);
+ for (i = x = 0; i < hpos; ++i)
+ x += row->glyphs[TEXT_AREA][i].pixel_width;
+
+ /* Record this as the current active region. */
+ dpyinfo->mouse_face_beg_col = hpos;
+ dpyinfo->mouse_face_beg_row = vpos;
+ dpyinfo->mouse_face_beg_x = x;
+ dpyinfo->mouse_face_beg_y = row->y;
+ dpyinfo->mouse_face_past_end = 0;
+
+ dpyinfo->mouse_face_end_col = hpos + 1;
+ dpyinfo->mouse_face_end_row = vpos;
+ dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
+ dpyinfo->mouse_face_end_y = row->y;
+ dpyinfo->mouse_face_window = window;
+ dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, draw);
+ dpyinfo->mouse_face_image_state = draw;
+ }
+
+ set_help_echo:
+
+ /* Set help_echo to a help string.to display for this tool-bar item.
+ XTread_socket does the rest. */
+ help_echo_object = help_echo_window = Qnil;
+ help_echo_pos = -1;
+ help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
+ if (NILP (help_echo))
+ help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
+}
+
+
+
+/* Find the glyph matrix position of buffer position CHARPOS in window
+ *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
+ current glyphs must be up to date. If CHARPOS is above window
+ start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
+ of last line in W. In the row containing CHARPOS, stop before glyphs
+ having STOP as object. */
+
+#if 0 /* This is a version of fast_find_position that's more correct
+ in the presence of hscrolling, for example. I didn't install
+ it right away because the problem fixed is minor, it failed
+ in 20.x as well, and I think it's too risky to install
+ so near the release of 21.1. 2001-09-25 gerd. */
+
+static int
+fast_find_position (w, charpos, hpos, vpos, x, y, stop)
+ struct window *w;
+ int charpos;
+ int *hpos, *vpos, *x, *y;
+ Lisp_Object stop;
+{
+ struct glyph_row *row, *first;
+ struct glyph *glyph, *end;
+ int i, past_end = 0;
+
+ first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ row = row_containing_pos (w, charpos, first, NULL, 0);
+ if (row == NULL)
+ {
+ if (charpos < MATRIX_ROW_START_CHARPOS (first))
+ {
+ *x = *y = *hpos = *vpos = 0;
+ return 0;
+ }
+ else
+ {
+ row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+ past_end = 1;
+ }
+ }
+
+ *x = row->x;
+ *y = row->y;
+ *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+
+ glyph = row->glyphs[TEXT_AREA];
+ end = glyph + row->used[TEXT_AREA];
+
+ /* Skip over glyphs not having an object at the start of the row.
+ These are special glyphs like truncation marks on terminal
+ frames. */
+ if (row->displays_text_p)
+ while (glyph < end
+ && INTEGERP (glyph->object)
+ && !EQ (stop, glyph->object)
+ && glyph->charpos < 0)
+ {
+ *x += glyph->pixel_width;
+ ++glyph;
+ }
+
+ while (glyph < end
+ && !INTEGERP (glyph->object)
+ && !EQ (stop, glyph->object)
+ && (!BUFFERP (glyph->object)
+ || glyph->charpos < charpos))
+ {
+ *x += glyph->pixel_width;
+ ++glyph;
+ }
+
+ *hpos = glyph - row->glyphs[TEXT_AREA];
+ return past_end;
+}
+
+#else /* not 0 */
+
+static int
+fast_find_position (w, pos, hpos, vpos, x, y, stop)
+ struct window *w;
+ int pos;
+ int *hpos, *vpos, *x, *y;
+ Lisp_Object stop;
+{
+ int i;
+ int lastcol;
+ int maybe_next_line_p = 0;
+ int line_start_position;
+ int yb = window_text_bottom_y (w);
+ struct glyph_row *row, *best_row;
+ int row_vpos, best_row_vpos;
+ int current_x;
+
+ row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+
+ while (row->y < yb)
+ {
+ if (row->used[TEXT_AREA])
+ line_start_position = row->glyphs[TEXT_AREA]->charpos;
+ else
+ line_start_position = 0;
+
+ if (line_start_position > pos)
+ break;
+ /* If the position sought is the end of the buffer,
+ don't include the blank lines at the bottom of the window. */
+ else if (line_start_position == pos
+ && pos == BUF_ZV (XBUFFER (w->buffer)))
+ {
+ maybe_next_line_p = 1;
+ break;
+ }
+ else if (line_start_position > 0)
+ {
+ best_row = row;
+ best_row_vpos = row_vpos;
+ }
+
+ if (row->y + row->height >= yb)
+ break;
+
+ ++row;
+ ++row_vpos;
+ }
+
+ /* Find the right column within BEST_ROW. */
+ lastcol = 0;
+ current_x = best_row->x;
+ for (i = 0; i < best_row->used[TEXT_AREA]; i++)
+ {
+ struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
+ int charpos = glyph->charpos;
+
+ if (BUFFERP (glyph->object))
+ {
+ if (charpos == pos)
+ {
+ *hpos = i;
+ *vpos = best_row_vpos;
+ *x = current_x;
+ *y = best_row->y;
+ return 1;
+ }
+ else if (charpos > pos)
+ break;
+ }
+ else if (EQ (glyph->object, stop))
+ break;
+
+ if (charpos > 0)
+ lastcol = i;
+ current_x += glyph->pixel_width;
+ }
+
+ /* If we're looking for the end of the buffer,
+ and we didn't find it in the line we scanned,
+ use the start of the following line. */
+ if (maybe_next_line_p)
+ {
+ ++best_row;
+ ++best_row_vpos;
+ lastcol = 0;
+ current_x = best_row->x;
+ }
+
+ *vpos = best_row_vpos;
+ *hpos = lastcol + 1;
+ *x = current_x;
+ *y = best_row->y;
+ return 0;
+}
+
+#endif /* not 0 */
+
+
+/* Find the position of the glyph for position POS in OBJECT in
+ window W's current matrix, and return in *X/*Y the pixel
+ coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
+
+ RIGHT_P non-zero means return the position of the right edge of the
+ glyph, RIGHT_P zero means return the left edge position.
+
+ If no glyph for POS exists in the matrix, return the position of
+ the glyph with the next smaller position that is in the matrix, if
+ RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
+ exists in the matrix, return the position of the glyph with the
+ next larger position in OBJECT.
+
+ Value is non-zero if a glyph was found. */
+
+static int
+fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
+ struct window *w;
+ int pos;
+ Lisp_Object object;
+ int *hpos, *vpos, *x, *y;
+ int right_p;
+{
+ int yb = window_text_bottom_y (w);
+ struct glyph_row *r;
+ struct glyph *best_glyph = NULL;
+ struct glyph_row *best_row = NULL;
+ int best_x = 0;
+
+ for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ r->enabled_p && r->y < yb;
+ ++r)
+ {
+ struct glyph *g = r->glyphs[TEXT_AREA];
+ struct glyph *e = g + r->used[TEXT_AREA];
+ int gx;
+
+ for (gx = r->x; g < e; gx += g->pixel_width, ++g)
+ if (EQ (g->object, object))
+ {
+ if (g->charpos == pos)
+ {
+ best_glyph = g;
+ best_x = gx;
+ best_row = r;
+ goto found;
+ }
+ else if (best_glyph == NULL
+ || ((abs (g->charpos - pos)
+ < abs (best_glyph->charpos - pos))
+ && (right_p
+ ? g->charpos < pos
+ : g->charpos > pos)))
+ {
+ best_glyph = g;
+ best_x = gx;
+ best_row = r;
+ }
+ }
+ }
+
+ found:
+
+ if (best_glyph)
+ {
+ *x = best_x;
+ *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
+
+ if (right_p)
+ {
+ *x += best_glyph->pixel_width;
+ ++*hpos;
+ }
+
+ *y = best_row->y;
+ *vpos = best_row - w->current_matrix->rows;
+ }
+
+ return best_glyph != NULL;
+}
+
+
+/* Display the active region described by mouse_face_*
+ in its mouse-face if HL > 0, in its normal face if HL = 0. */
+
+static void
+show_mouse_face (dpyinfo, draw)
+ struct mac_display_info *dpyinfo;
+ enum draw_glyphs_face draw;
+{
+ struct window *w = XWINDOW (dpyinfo->mouse_face_window);
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ if (/* If window is in the process of being destroyed, don't bother
+ to do anything. */
+ w->current_matrix != NULL
+ /* Don't update mouse highlight if hidden */
+ && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
+ /* Recognize when we are called to operate on rows that don't exist
+ anymore. This can happen when a window is split. */
+ && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
+ {
+ int phys_cursor_on_p = w->phys_cursor_on_p;
+ struct glyph_row *row, *first, *last;
+
+ first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
+ last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
+
+ for (row = first; row <= last && row->enabled_p; ++row)
+ {
+ int start_hpos, end_hpos, start_x;
+
+ /* For all but the first row, the highlight starts at column 0. */
+ if (row == first)
+ {
+ start_hpos = dpyinfo->mouse_face_beg_col;
+ start_x = dpyinfo->mouse_face_beg_x;
+ }
+ else
+ {
+ start_hpos = 0;
+ start_x = 0;
+ }
+
+ if (row == last)
+ end_hpos = dpyinfo->mouse_face_end_col;
+ else
+ end_hpos = row->used[TEXT_AREA];
+
+ if (end_hpos > start_hpos)
+ {
+ x_draw_glyphs (w, start_x, row, TEXT_AREA,
+ start_hpos, end_hpos, draw, 0);
+
+ row->mouse_face_p
+ = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
+ }
+ }
+
+ /* When we've written over the cursor, arrange for it to
+ be displayed again. */
+ if (phys_cursor_on_p && !w->phys_cursor_on_p)
+ x_display_cursor (w, 1,
+ w->phys_cursor.hpos, w->phys_cursor.vpos,
+ w->phys_cursor.x, w->phys_cursor.y);
+ }
+
+#if 0 /* MAC_TODO: mouse cursor */
+ /* Change the mouse cursor. */
+ if (draw == DRAW_NORMAL_TEXT)
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->text_cursor);
+ else if (draw == DRAW_MOUSE_FACE)
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->cross_cursor);
+ else
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->nontext_cursor);
+#endif
+}
+
+/* Clear out the mouse-highlighted active region.
+ Redraw it un-highlighted first. */
+
+static int
+clear_mouse_face (dpyinfo)
+ struct mac_display_info *dpyinfo;
+{
+ int cleared = 0;
+
+ if (! NILP (dpyinfo->mouse_face_window))
+ {
+ show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
+ cleared = 1;
+ }
+
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ dpyinfo->mouse_face_overlay = Qnil;
+ return cleared;
+}
+
+
+/* Clear any mouse-face on window W. This function is part of the
+ redisplay interface, and is called from try_window_id and similar
+ functions to ensure the mouse-highlight is off. */
+
+static void
+x_clear_mouse_face (w)
+ struct window *w;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
+ Lisp_Object window;
+
+ BLOCK_INPUT;
+ XSETWINDOW (window, w);
+ if (EQ (window, dpyinfo->mouse_face_window))
+ clear_mouse_face (dpyinfo);
+ UNBLOCK_INPUT;
+}
+
+
+/* Just discard the mouse face information for frame F, if any.
+ This is used when the size of F is changed. */
+
+void
+cancel_mouse_face (f)
+ FRAME_PTR f;
+{
+ Lisp_Object window;
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+
+ window = dpyinfo->mouse_face_window;
+ if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
+ {
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ }
+}
+
+static struct scroll_bar *x_window_to_scroll_bar ();
+static void x_scroll_bar_report_motion ();
+static void x_check_fullscreen P_ ((struct frame *));
+static void x_check_fullscreen_move P_ ((struct frame *));
+static int glyph_rect P_ ((struct frame *f, int, int, Rect *));
+
+
+/* Try to determine frame pixel position and size of the glyph under
+ frame pixel coordinates X/Y on frame F . Return the position and
+ size in *RECT. Value is non-zero if we could compute these
+ values. */
+
+static int
+glyph_rect (f, x, y, rect)
+ struct frame *f;
+ int x, y;
+ Rect *rect;
+{
+ Lisp_Object window;
+ int part;
+
+ window = window_from_coordinates (f, x, y, &part, 0);
+ if (!NILP (window))
+ {
+ struct window *w = XWINDOW (window);
+ struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ struct glyph_row *end = r + w->current_matrix->nrows - 1;
+
+ frame_to_window_pixel_xy (w, &x, &y);
+
+ for (; r < end && r->enabled_p; ++r)
+ if (r->y <= y && r->y + r->height > y)
+ {
+ /* Found the row at y. */
+ struct glyph *g = r->glyphs[TEXT_AREA];
+ struct glyph *end = g + r->used[TEXT_AREA];
+ int gx;
+
+ rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
+ rect->bottom = rect->top + r->height;
+
+ if (x < r->x)
+ {
+ /* x is to the left of the first glyph in the row. */
+ rect->left = XINT (w->left);
+ rect->right = WINDOW_TO_FRAME_PIXEL_X (w, r->x);
+ return 1;
+ }
+
+ for (gx = r->x; g < end; gx += g->pixel_width, ++g)
+ if (gx <= x && gx + g->pixel_width > x)
+ {
+ /* x is on a glyph. */
+ rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx);
+ rect->right = rect->left + g->pixel_width;
+ return 1;
+ }
+
+ /* x is to the right of the last glyph in the row. */
+ rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx);
+ rect->right = XINT (w->left) + XINT (w->width);
+ return 1;
+ }
+ }
+
+ /* The y is not on any row. */
+ return 0;
+}
+
+/* Record the position of the mouse in last_mouse_glyph. */
+static void
+remember_mouse_glyph (f1, gx, gy)
+ struct frame * f1;
+ int gx, gy;
+{
+ if (!glyph_rect (f1, gx, gy, &last_mouse_glyph))
+ {
+ int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
+ int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
+
+ /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
+ round down even for negative values. */
+ if (gx < 0)
+ gx -= width - 1;
+ if (gy < 0)
+ gy -= height - 1;
+#if 0
+ /* This was the original code from XTmouse_position, but it seems
+ to give the position of the glyph diagonally next to the one
+ the mouse is over. */
+ gx = (gx + width - 1) / width * width;
+ gy = (gy + height - 1) / height * height;
+#else
+ gx = gx / width * width;
+ gy = gy / height * height;
+#endif
+
+ last_mouse_glyph.left = gx;
+ last_mouse_glyph.top = gy;
+ last_mouse_glyph.right = gx + width;
+ last_mouse_glyph.bottom = gy + height;
+ }
+}
+
+/* Return the current position of the mouse.
+ *fp should be a frame which indicates which display to ask about.
+
+ If the mouse movement started in a scroll bar, set *fp, *bar_window,
+ and *part to the frame, window, and scroll bar part that the mouse
+ is over. Set *x and *y to the portion and whole of the mouse's
+ position on the scroll bar.
+
+ If the mouse movement started elsewhere, set *fp to the frame the
+ mouse is on, *bar_window to nil, and *x and *y to the character cell
+ the mouse is over.
+
+ Set *time to the server time-stamp for the time at which the mouse
+ was at this position.
+
+ Don't store anything if we don't have a valid set of values to report.
+
+ This clears the mouse_moved flag, so we can wait for the next mouse
+ movement. */
+
+static void
+XTmouse_position (fp, insist, bar_window, part, x, y, time)
+ FRAME_PTR *fp;
+ int insist;
+ Lisp_Object *bar_window;
+ enum scroll_bar_part *part;
+ Lisp_Object *x, *y;
+ unsigned long *time;
+{
+ Point mouse_pos;
+ int ignore1, ignore2;
+ WindowPtr wp = FrontWindow ();
+ struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
+ Lisp_Object frame, tail;
+
+ BLOCK_INPUT;
+
+ if (! NILP (last_mouse_scroll_bar) && insist == 0)
+ x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
+ else
+ {
+ /* Clear the mouse-moved flag for every frame on this display. */
+ FOR_EACH_FRAME (tail, frame)
+ XFRAME (frame)->mouse_moved = 0;
+
+ last_mouse_scroll_bar = Qnil;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (wp));
+#else
+ SetPort (wp);
+#endif
+
+ GetMouse (&mouse_pos);
+
+ pixel_to_glyph_coords (f, mouse_pos.h, mouse_pos.v, &ignore1, &ignore2,
+ &last_mouse_glyph, insist);
+
+ *bar_window = Qnil;
+ *part = scroll_bar_handle;
+ *fp = f;
+ XSETINT (*x, mouse_pos.h);
+ XSETINT (*y, mouse_pos.v);
+ *time = last_mouse_movement_time;
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+/************************************************************************
+ Scroll bars, general
+ ************************************************************************/
+
+/* Create a scroll bar and return the scroll bar vector for it. W is
+ the Emacs window on which to create the scroll bar. TOP, LEFT,
+ WIDTH and HEIGHT are the pixel coordinates and dimensions of the
+ scroll bar. */
+
+static struct scroll_bar *
+x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
+ struct window *w;
+ int top, left, width, height, disp_top, disp_height;
+{
+ struct frame *f = XFRAME (w->frame);
+ struct scroll_bar *bar
+ = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
+ Rect r;
+ ControlHandle ch;
+
+ BLOCK_INPUT;
+
+ r.left = left;
+ r.top = disp_top;
+ r.right = left + width;
+ r.bottom = disp_top + disp_height;
+
+#ifdef TARGET_API_MAC_CARBON
+ ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0,
+ kControlScrollBarProc, 0L);
+#else
+ ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0, scrollBarProc,
+ 0L);
+#endif
+ SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch);
+ SetControlReference (ch, (long) bar);
+
+ XSETWINDOW (bar->window, w);
+ XSETINT (bar->top, top);
+ XSETINT (bar->left, left);
+ XSETINT (bar->width, width);
+ XSETINT (bar->height, height);
+ XSETINT (bar->start, 0);
+ XSETINT (bar->end, 0);
+ bar->dragging = Qnil;
+
+ /* Add bar to its frame's list of scroll bars. */
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
+ if (!NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+
+ UNBLOCK_INPUT;
+ return bar;
+}
+
+
+/* Draw BAR's handle in the proper position.
+
+ If the handle is already drawn from START to END, don't bother
+ redrawing it, unless REBUILD is non-zero; in that case, always
+ redraw it. (REBUILD is handy for drawing the handle after expose
+ events.)
+
+ Normally, we want to constrain the start and end of the handle to
+ fit inside its rectangle, but if the user is dragging the scroll
+ bar handle, we want to let them drag it down all the way, so that
+ the bar's top is as far down as it goes; otherwise, there's no way
+ to move to the very end of the buffer. */
+
+static void
+x_scroll_bar_set_handle (bar, start, end, rebuild)
+ struct scroll_bar *bar;
+ int start, end;
+ int rebuild;
+{
+ int dragging = ! NILP (bar->dragging);
+ ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+ int length = end - start;
+
+ /* If the display is already accurate, do nothing. */
+ if (! rebuild
+ && start == XINT (bar->start)
+ && end == XINT (bar->end))
+ return;
+
+ BLOCK_INPUT;
+
+ /* Make sure the values are reasonable, and try to preserve the
+ distance between start and end. */
+ if (start < 0)
+ start = 0;
+ else if (start > top_range)
+ start = top_range;
+ end = start + length;
+
+ if (end < start)
+ end = start;
+ else if (end > top_range && ! dragging)
+ end = top_range;
+
+ /* Store the adjusted setting in the scroll bar. */
+ XSETINT (bar->start, start);
+ XSETINT (bar->end, end);
+
+ /* Clip the end position, just for display. */
+ if (end > top_range)
+ end = top_range;
+
+ /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
+ top positions, to make sure the handle is always at least that
+ many pixels tall. */
+ end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
+
+ SetControlMinimum (ch, 0);
+ /* Don't inadvertently activate deactivated scroll bars */
+ if (GetControlMaximum (ch) != -1)
+ SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
+ - (end - start));
+ SetControlValue (ch, start);
+#if TARGET_API_MAC_CARBON
+ SetControlViewSize (ch, end - start);
+#endif
+
+ UNBLOCK_INPUT;
+}
+
+
+/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
+ nil. */
+
+static void
+x_scroll_bar_remove (bar)
+ struct scroll_bar *bar;
+{
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+
+ BLOCK_INPUT;
+
+ /* Destroy the Mac scroll bar control */
+ DisposeControl (SCROLL_BAR_CONTROL_HANDLE (bar));
+
+ /* Disassociate this scroll bar from its window. */
+ XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
+
+ UNBLOCK_INPUT;
+}
+
+/* Set the handle of the vertical scroll bar for WINDOW to indicate
+ that we are displaying PORTION characters out of a total of WHOLE
+ characters, starting at POSITION. If WINDOW has no scroll bar,
+ create one. */
+static void
+XTset_vertical_scroll_bar (w, portion, whole, position)
+ struct window *w;
+ int portion, whole, position;
+{
+ struct frame *f = XFRAME (w->frame);
+ struct scroll_bar *bar;
+ int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
+ int window_x, window_y, window_width, window_height;
+
+ /* Get window dimensions. */
+ window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+ top = window_y;
+#ifdef MAC_OSX
+ width = 16;
+#else
+ width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
+#endif
+ height = window_height;
+
+ /* Compute the left edge of the scroll bar area. */
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+ left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
+ else
+ left = XFASTINT (w->left);
+ left *= CANON_X_UNIT (f);
+ left += FRAME_INTERNAL_BORDER_WIDTH (f);
+
+ /* Compute the width of the scroll bar which might be less than
+ the width of the area reserved for the scroll bar. */
+ if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
+ sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
+ else
+ sb_width = width;
+
+ /* Compute the left edge of the scroll bar. */
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+ sb_left = left + width - sb_width - (width - sb_width) / 2;
+ else
+ sb_left = left + (width - sb_width) / 2;
+
+ /* Adjustments according to Inside Macintosh to make it look nice */
+ disp_top = top;
+ disp_height = height;
+ if (disp_top == 0)
+ {
+ disp_top = -1;
+ disp_height++;
+ }
+ else if (disp_top == PIXEL_HEIGHT (f) - 16)
+ {
+ disp_top++;
+ disp_height--;
+ }
+
+ if (sb_left + sb_width == PIXEL_WIDTH (f))
+ sb_left++;
+
+ /* Does the scroll bar exist yet? */
+ if (NILP (w->vertical_scroll_bar))
+ {
+ BLOCK_INPUT;
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ left, top, width, height, 0);
+ UNBLOCK_INPUT;
+ bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
+ disp_height);
+ XSETVECTOR (w->vertical_scroll_bar, bar);
+ }
+ else
+ {
+ /* It may just need to be moved and resized. */
+ ControlHandle ch;
+
+ bar = XSCROLL_BAR (w->vertical_scroll_bar);
+ ch = SCROLL_BAR_CONTROL_HANDLE (bar);
+
+ BLOCK_INPUT;
+
+ /* If already correctly positioned, do nothing. */
+ if (XINT (bar->left) == sb_left
+ && XINT (bar->top) == top
+ && XINT (bar->width) == sb_width
+ && XINT (bar->height) == height)
+ Draw1Control (ch);
+ else
+ {
+ /* Clear areas not covered by the scroll bar because it's not as
+ wide as the area reserved for it . This makes sure a
+ previous mode line display is cleared after C-x 2 C-x 1, for
+ example. */
+ int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ left, top, area_width, height, 0);
+
+#if 0
+ if (sb_left + sb_width >= PIXEL_WIDTH (f))
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ sb_left - 1, top, 1, height, 0);
+#endif
+
+ HideControl (ch);
+ MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
+ SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+ disp_height);
+ ShowControl (ch);
+
+ /* Remember new settings. */
+ XSETINT (bar->left, sb_left);
+ XSETINT (bar->top, top);
+ XSETINT (bar->width, sb_width);
+ XSETINT (bar->height, height);
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+ /* Set the scroll bar's current state, unless we're currently being
+ dragged. */
+ if (NILP (bar->dragging))
+ {
+ int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
+
+ if (whole == 0)
+ x_scroll_bar_set_handle (bar, 0, top_range, 0);
+ else
+ {
+ int start = ((double) position * top_range) / whole;
+ int end = ((double) (position + portion) * top_range) / whole;
+ x_scroll_bar_set_handle (bar, start, end, 0);
+ }
+ }
+}
+
+
+/* The following three hooks are used when we're doing a thorough
+ redisplay of the frame. We don't explicitly know which scroll bars
+ are going to be deleted, because keeping track of when windows go
+ away is a real pain - "Can you say set-window-configuration, boys
+ and girls?" Instead, we just assert at the beginning of redisplay
+ that *all* scroll bars are to be removed, and then save a scroll bar
+ from the fiery pit when we actually redisplay its window. */
+
+/* Arrange for all scroll bars on FRAME to be removed at the next call
+ to `*judge_scroll_bars_hook'. A scroll bar may be spared if
+ `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
+
+static void
+XTcondemn_scroll_bars (frame)
+ FRAME_PTR frame;
+{
+ /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
+ while (! NILP (FRAME_SCROLL_BARS (frame)))
+ {
+ Lisp_Object bar;
+ bar = FRAME_SCROLL_BARS (frame);
+ FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
+ XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
+ XSCROLL_BAR (bar)->prev = Qnil;
+ if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
+ XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
+ FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
+ }
+}
+
+
+/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
+ Note that WINDOW isn't necessarily condemned at all. */
+
+static void
+XTredeem_scroll_bar (window)
+ struct window *window;
+{
+ struct scroll_bar *bar;
+
+ /* We can't redeem this window's scroll bar if it doesn't have one. */
+ if (NILP (window->vertical_scroll_bar))
+ abort ();
+
+ bar = XSCROLL_BAR (window->vertical_scroll_bar);
+
+ /* Unlink it from the condemned list. */
+ {
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
+
+ if (NILP (bar->prev))
+ {
+ /* If the prev pointer is nil, it must be the first in one of
+ the lists. */
+ if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
+ /* It's not condemned. Everything's fine. */
+ return;
+ else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+ window->vertical_scroll_bar))
+ FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
+ else
+ /* If its prev pointer is nil, it must be at the front of
+ one or the other! */
+ abort ();
+ }
+ else
+ XSCROLL_BAR (bar->prev)->next = bar->next;
+
+ if (! NILP (bar->next))
+ XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
+ if (! NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+ }
+}
+
+/* Remove all scroll bars on FRAME that haven't been saved since the
+ last call to `*condemn_scroll_bars_hook'. */
+
+static void
+XTjudge_scroll_bars (f)
+ FRAME_PTR f;
+{
+ Lisp_Object bar, next;
+
+ bar = FRAME_CONDEMNED_SCROLL_BARS (f);
+
+ /* Clear out the condemned list now so we won't try to process any
+ more events on the hapless scroll bars. */
+ FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
+
+ for (; ! NILP (bar); bar = next)
+ {
+ struct scroll_bar *b = XSCROLL_BAR (bar);
+
+ x_scroll_bar_remove (b);
+
+ next = b->next;
+ b->next = b->prev = Qnil;
+ }
+
+ /* Now there should be no references to the condemned scroll bars,
+ and they should get garbage-collected. */
+}
+
+
+static void
+activate_scroll_bars (frame)
+ FRAME_PTR frame;
+{
+ Lisp_Object bar;
+ ControlHandle ch;
+
+ bar = FRAME_SCROLL_BARS (frame);
+ while (! NILP (bar))
+ {
+ ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar));
+#ifdef TARGET_API_MAC_CARBON
+ ActivateControl (ch);
+#else
+ SetControlMaximum (ch,
+ VERTICAL_SCROLL_BAR_TOP_RANGE (frame,
+ XINT (XSCROLL_BAR (bar)
+ ->height)) - 1);
+#endif
+ bar = XSCROLL_BAR (bar)->next;
+ }
+}
+
+
+static void
+deactivate_scroll_bars (frame)
+ FRAME_PTR frame;
+{
+ Lisp_Object bar;
+ ControlHandle ch;
+
+ bar = FRAME_SCROLL_BARS (frame);
+ while (! NILP (bar))
+ {
+ ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar));
+#ifdef TARGET_API_MAC_CARBON
+ DeactivateControl (ch);
+#else
+ SetControlMaximum (ch, XINT (-1));
+#endif
+ bar = XSCROLL_BAR (bar)->next;
+ }
+}
+
+/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
+ is set to something other than no_event, it is enqueued.
+
+ This may be called from a signal handler, so we have to ignore GC
+ mark bits. */
+
+static void
+x_scroll_bar_handle_click (bar, part_code, er, bufp)
+ struct scroll_bar *bar;
+ int part_code;
+ EventRecord *er;
+ struct input_event *bufp;
+{
+ if (! GC_WINDOWP (bar->window))
+ abort ();
+
+ bufp->kind = scroll_bar_click;
+ bufp->frame_or_window = bar->window;
+ bufp->arg = Qnil;
+
+ bar->dragging = Qnil;
+
+ switch (part_code)
+ {
+ case kControlUpButtonPart:
+ bufp->part = scroll_bar_up_arrow;
+ break;
+ case kControlDownButtonPart:
+ bufp->part = scroll_bar_down_arrow;
+ break;
+ case kControlPageUpPart:
+ bufp->part = scroll_bar_above_handle;
+ break;
+ case kControlPageDownPart:
+ bufp->part = scroll_bar_below_handle;
+ break;
+#ifdef TARGET_API_MAC_CARBON
+ default:
+#else
+ case kControlIndicatorPart:
+#endif
+ if (er->what == mouseDown)
+ bar->dragging = make_number (0);
+ XSETVECTOR (last_mouse_scroll_bar, bar);
+ bufp->part = scroll_bar_handle;
+ break;
+ }
+}
+
+
+/* Handle some mouse motion while someone is dragging the scroll bar.
+
+ This may be called from a signal handler, so we have to ignore GC
+ mark bits. */
+
+static void
+x_scroll_bar_note_movement (bar, y_pos, t)
+ struct scroll_bar *bar;
+ int y_pos;
+ Time t;
+{
+ FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
+
+ last_mouse_movement_time = t;
+
+ f->mouse_moved = 1;
+ XSETVECTOR (last_mouse_scroll_bar, bar);
+
+ /* If we're dragging the bar, display it. */
+ if (! GC_NILP (bar->dragging))
+ {
+ /* Where should the handle be now? */
+ int new_start = y_pos - 24;
+
+ if (new_start != XINT (bar->start))
+ {
+ int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
+
+ x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+ }
+ }
+}
+
+
+/* Return information to the user about the current position of the
+ mouse on the scroll bar. */
+
+static void
+x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
+ FRAME_PTR *fp;
+ Lisp_Object *bar_window;
+ enum scroll_bar_part *part;
+ Lisp_Object *x, *y;
+ unsigned long *time;
+{
+ struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
+ WindowPtr wp = FrontWindow ();
+ Point mouse_pos;
+ struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
+ int win_y, top_range;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (wp));
+#else
+ SetPort (wp);
+#endif
+
+ GetMouse (&mouse_pos);
+
+ win_y = mouse_pos.v - XINT (bar->top);
+ top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+
+ win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
+
+ win_y -= 24;
+
+ if (! NILP (bar->dragging))
+ win_y -= XINT (bar->dragging);
+
+ if (win_y < 0)
+ win_y = 0;
+ if (win_y > top_range)
+ win_y = top_range;
+
+ *fp = f;
+ *bar_window = bar->window;
+
+ if (! NILP (bar->dragging))
+ *part = scroll_bar_handle;
+ else if (win_y < XINT (bar->start))
+ *part = scroll_bar_above_handle;
+ else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
+ *part = scroll_bar_handle;
+ else
+ *part = scroll_bar_below_handle;
+
+ XSETINT (*x, win_y);
+ XSETINT (*y, top_range);
+
+ f->mouse_moved = 0;
+ last_mouse_scroll_bar = Qnil;
+
+ *time = last_mouse_movement_time;
+}
+
+/***********************************************************************
+ Text Cursor
+ ***********************************************************************/
+
+/* Notice if the text cursor of window W has been overwritten by a
+ drawing operation that outputs glyphs starting at START_X and
+ ending at END_X in the line given by output_cursor.vpos.
+ Coordinates are area-relative. END_X < 0 means all the rest
+ of the line after START_X has been written. */
+
+static void
+notice_overwritten_cursor (w, area, x0, x1, y0, y1)
+ struct window *w;
+ enum glyph_row_area area;
+ int x0, x1, y0, y1;
+{
+ if (area == TEXT_AREA
+ && w->phys_cursor_on_p
+ && y0 <= w->phys_cursor.y
+ && y1 >= w->phys_cursor.y + w->phys_cursor_height
+ && x0 <= w->phys_cursor.x
+ && (x1 < 0 || x1 > w->phys_cursor.x))
+ w->phys_cursor_on_p = 0;
+}
+
+
+/* Set clipping for output in glyph row ROW. W is the window in which
+ we operate. GC is the graphics context to set clipping in.
+ WHOLE_LINE_P non-zero means include the areas used for truncation
+ mark display and alike in the clipping rectangle.
+
+ ROW may be a text row or, e.g., a mode line. Text rows must be
+ clipped to the interior of the window dedicated to text display,
+ mode lines must be clipped to the whole window. */
+
+static void
+x_clip_to_row (w, row, gc, whole_line_p)
+ struct window *w;
+ struct glyph_row *row;
+ GC gc;
+ int whole_line_p;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ Rect clip_rect;
+ int window_x, window_y, window_width, window_height;
+
+ window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+
+ clip_rect.left = WINDOW_TO_FRAME_PIXEL_X (w, 0);
+ clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ clip_rect.top = max (clip_rect.top, window_y);
+ clip_rect.right = clip_rect.left + window_width;
+ clip_rect.bottom = clip_rect.top + row->visible_height;
+
+ /* If clipping to the whole line, including trunc marks, extend
+ the rectangle to the left and increase its width. */
+ if (whole_line_p)
+ {
+ clip_rect.left -= FRAME_X_LEFT_FRINGE_WIDTH (f);
+ clip_rect.right += FRAME_X_FRINGE_WIDTH (f);
+ }
+
+ mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), &clip_rect);
+}
+
+
+/* Draw a hollow box cursor on window W in glyph row ROW. */
+
+static void
+x_draw_hollow_cursor (w, row)
+ struct window *w;
+ struct glyph_row *row;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ Display *dpy = FRAME_MAC_DISPLAY (f);
+ int x, y, wd, h;
+ XGCValues xgcv;
+ struct glyph *cursor_glyph;
+ GC gc;
+
+ /* Compute frame-relative coordinates from window-relative
+ coordinates. */
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
+ + row->ascent - w->phys_cursor_ascent);
+ h = row->height - 1;
+
+ /* Get the glyph the cursor is on. If we can't tell because
+ the current matrix is invalid or such, give up. */
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ return;
+
+ /* Compute the width of the rectangle to draw. If on a stretch
+ glyph, and `x-stretch-block-cursor' is nil, don't draw a
+ rectangle as wide as the glyph, but use a canonical character
+ width instead. */
+ wd = cursor_glyph->pixel_width - 1;
+ if (cursor_glyph->type == STRETCH_GLYPH
+ && !x_stretch_cursor_p)
+ wd = min (CANON_X_UNIT (f), wd);
+
+ /* The foreground of cursor_gc is typically the same as the normal
+ background color, which can cause the cursor box to be invisible. */
+ xgcv.foreground = f->output_data.mac->cursor_pixel;
+ if (dpyinfo->scratch_cursor_gc)
+ XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
+ else
+ dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
+ GCForeground, &xgcv);
+ gc = dpyinfo->scratch_cursor_gc;
+
+ /* Set clipping, draw the rectangle, and reset clipping again. */
+ x_clip_to_row (w, row, gc, 0);
+ mac_draw_rectangle (dpy, FRAME_MAC_WINDOW (f), gc, x, y, wd, h);
+ mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f));
+}
+
+
+/* Draw a bar cursor on window W in glyph row ROW.
+
+ Implementation note: One would like to draw a bar cursor with an
+ angle equal to the one given by the font property XA_ITALIC_ANGLE.
+ Unfortunately, I didn't find a font yet that has this property set.
+ --gerd. */
+
+static void
+x_draw_bar_cursor (w, row, width)
+ struct window *w;
+ struct glyph_row *row;
+ int width;
+{
+ /* If cursor hpos is out of bounds, don't draw garbage. This can
+ happen in mini-buffer windows when switching between echo area
+ glyphs and mini-buffer. */
+ if (w->phys_cursor.hpos < row->used[TEXT_AREA])
+ {
+ struct frame *f = XFRAME (w->frame);
+ struct glyph *cursor_glyph;
+ GC gc;
+ int x;
+ unsigned long mask;
+ XGCValues xgcv;
+ Display *dpy;
+ Window window;
+
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ return;
+
+ xgcv.background = f->output_data.mac->cursor_pixel;
+ xgcv.foreground = f->output_data.mac->cursor_pixel;
+ mask = GCForeground | GCBackground;
+ dpy = FRAME_MAC_DISPLAY (f);
+ window = FRAME_MAC_WINDOW (f);
+ gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
+
+ if (gc)
+ XChangeGC (dpy, gc, mask, &xgcv);
+ else
+ {
+ gc = XCreateGC (dpy, window, mask, &xgcv);
+ FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
+ }
+
+ if (width < 0)
+ width = f->output_data.mac->cursor_width;
+
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ x_clip_to_row (w, row, gc, 0);
+ XFillRectangle (dpy, window, gc,
+ x,
+ WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
+ min (cursor_glyph->pixel_width, width),
+ row->height);
+ mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f));
+ }
+}
+
+
+/* Clear the cursor of window W to background color, and mark the
+ cursor as not shown. This is used when the text where the cursor
+ is is about to be rewritten. */
+
+static void
+x_clear_cursor (w)
+ struct window *w;
+{
+ if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
+ x_update_window_cursor (w, 0);
+}
+
+
+/* Draw the cursor glyph of window W in glyph row ROW. See the
+ comment of x_draw_glyphs for the meaning of HL. */
+
+static void
+x_draw_phys_cursor_glyph (w, row, hl)
+ struct window *w;
+ struct glyph_row *row;
+ enum draw_glyphs_face hl;
+{
+ /* If cursor hpos is out of bounds, don't draw garbage. This can
+ happen in mini-buffer windows when switching between echo area
+ glyphs and mini-buffer. */
+ if (w->phys_cursor.hpos < row->used[TEXT_AREA])
+ {
+ int on_p = w->phys_cursor_on_p;
+ x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
+ w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
+ hl, 0);
+ w->phys_cursor_on_p = on_p;
+
+ /* When we erase the cursor, and ROW is overlapped by other
+ rows, make sure that these overlapping parts of other rows
+ are redrawn. */
+ if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
+ {
+ if (row > w->current_matrix->rows
+ && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
+ x_fix_overlapping_area (w, row - 1, TEXT_AREA);
+
+ if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
+ && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
+ x_fix_overlapping_area (w, row + 1, TEXT_AREA);
+ }
+ }
+}
+
+
+/* Erase the image of a cursor of window W from the screen. */
+
+static void
+x_erase_phys_cursor (w)
+ struct window *w;
+{
+ struct frame *f = XFRAME (w->frame);
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ int hpos = w->phys_cursor.hpos;
+ int vpos = w->phys_cursor.vpos;
+ int mouse_face_here_p = 0;
+ struct glyph_matrix *active_glyphs = w->current_matrix;
+ struct glyph_row *cursor_row;
+ struct glyph *cursor_glyph;
+ enum draw_glyphs_face hl;
+
+ /* No cursor displayed or row invalidated => nothing to do on the
+ screen. */
+ if (w->phys_cursor_type == NO_CURSOR)
+ goto mark_cursor_off;
+
+ /* VPOS >= active_glyphs->nrows means that window has been resized.
+ Don't bother to erase the cursor. */
+ if (vpos >= active_glyphs->nrows)
+ goto mark_cursor_off;
+
+ /* If row containing cursor is marked invalid, there is nothing we
+ can do. */
+ cursor_row = MATRIX_ROW (active_glyphs, vpos);
+ if (!cursor_row->enabled_p)
+ goto mark_cursor_off;
+
+ /* If row is completely invisible, don't attempt to delete a cursor which
+ isn't there. This may happen if cursor is at top of window, and
+ we switch to a buffer with a header line in that window. */
+ if (cursor_row->visible_height <= 0)
+ goto mark_cursor_off;
+
+ /* This can happen when the new row is shorter than the old one.
+ In this case, either x_draw_glyphs or clear_end_of_line
+ should have cleared the cursor. Note that we wouldn't be
+ able to erase the cursor in this case because we don't have a
+ cursor glyph at hand. */
+ if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
+ goto mark_cursor_off;
+
+ /* If the cursor is in the mouse face area, redisplay that when
+ we clear the cursor. */
+ if (! NILP (dpyinfo->mouse_face_window)
+ && w == XWINDOW (dpyinfo->mouse_face_window)
+ && (vpos > dpyinfo->mouse_face_beg_row
+ || (vpos == dpyinfo->mouse_face_beg_row
+ && hpos >= dpyinfo->mouse_face_beg_col))
+ && (vpos < dpyinfo->mouse_face_end_row
+ || (vpos == dpyinfo->mouse_face_end_row
+ && hpos < dpyinfo->mouse_face_end_col))
+ /* Don't redraw the cursor's spot in mouse face if it is at the
+ end of a line (on a newline). The cursor appears there, but
+ mouse highlighting does not. */
+ && cursor_row->used[TEXT_AREA] > hpos)
+ mouse_face_here_p = 1;
+
+ /* Maybe clear the display under the cursor. */
+ if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
+ {
+ int x;
+ int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ goto mark_cursor_off;
+
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
+
+ XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
+ x,
+ WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
+ cursor_row->y)),
+ cursor_glyph->pixel_width,
+ cursor_row->visible_height,
+ 0);
+ }
+
+ /* Erase the cursor by redrawing the character underneath it. */
+ if (mouse_face_here_p)
+ hl = DRAW_MOUSE_FACE;
+ else
+ hl = DRAW_NORMAL_TEXT;
+ x_draw_phys_cursor_glyph (w, cursor_row, hl);
+
+ mark_cursor_off:
+ w->phys_cursor_on_p = 0;
+ w->phys_cursor_type = NO_CURSOR;
+}
+
+
+/* Non-zero if physical cursor of window W is within mouse face. */
+
+static int
+cursor_in_mouse_face_p (w)
+ struct window *w;
+{
+ struct mac_display_info *dpyinfo
+ = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
+ int in_mouse_face = 0;
+
+ if (WINDOWP (dpyinfo->mouse_face_window)
+ && XWINDOW (dpyinfo->mouse_face_window) == w)
+ {
+ int hpos = w->phys_cursor.hpos;
+ int vpos = w->phys_cursor.vpos;
+
+ if (vpos >= dpyinfo->mouse_face_beg_row
+ && vpos <= dpyinfo->mouse_face_end_row
+ && (vpos > dpyinfo->mouse_face_beg_row
+ || hpos >= dpyinfo->mouse_face_beg_col)
+ && (vpos < dpyinfo->mouse_face_end_row
+ || hpos < dpyinfo->mouse_face_end_col
+ || dpyinfo->mouse_face_past_end))
+ in_mouse_face = 1;
+ }
+
+ return in_mouse_face;
+}
+
+
+/* Display or clear cursor of window W. If ON is zero, clear the
+ cursor. If it is non-zero, display the cursor. If ON is nonzero,
+ where to put the cursor is specified by HPOS, VPOS, X and Y. */
+
+void
+x_display_and_set_cursor (w, on, hpos, vpos, x, y)
+ struct window *w;
+ int on, hpos, vpos, x, y;
+{
+ struct frame *f = XFRAME (w->frame);
+ int new_cursor_type;
+ int new_cursor_width;
+ struct glyph_matrix *current_glyphs;
+ struct glyph_row *glyph_row;
+ struct glyph *glyph;
+ int cursor_non_selected;
+ int active_cursor = 1;
+
+ /* This is pointless on invisible frames, and dangerous on garbaged
+ windows and frames; in the latter case, the frame or window may
+ be in the midst of changing its size, and x and y may be off the
+ window. */
+ if (! FRAME_VISIBLE_P (f)
+ || FRAME_GARBAGED_P (f)
+ || vpos >= w->current_matrix->nrows
+ || hpos >= w->current_matrix->matrix_w)
+ return;
+
+ /* If cursor is off and we want it off, return quickly. */
+ if (!on && !w->phys_cursor_on_p)
+ return;
+
+ current_glyphs = w->current_matrix;
+ glyph_row = MATRIX_ROW (current_glyphs, vpos);
+ glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+
+ /* If cursor row is not enabled, we don't really know where to
+ display the cursor. */
+ if (!glyph_row->enabled_p)
+ {
+ w->phys_cursor_on_p = 0;
+ return;
+ }
+
+ xassert (interrupt_input_blocked);
+
+ /* Set new_cursor_type to the cursor we want to be displayed. In a
+ mini-buffer window, we want the cursor only to appear if we are
+ reading input from this window. For the selected window, we want
+ the cursor type given by the frame parameter. If explicitly
+ marked off, draw no cursor. In all other cases, we want a hollow
+ box cursor. */
+ cursor_non_selected
+ = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
+ w->buffer));
+ new_cursor_width = -1;
+ if (cursor_in_echo_area
+ && FRAME_HAS_MINIBUF_P (f)
+ && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
+ {
+ if (w == XWINDOW (echo_area_window))
+ new_cursor_type = FRAME_DESIRED_CURSOR (f);
+ else
+ {
+ if (cursor_non_selected)
+ new_cursor_type = HOLLOW_BOX_CURSOR;
+ else
+ new_cursor_type = NO_CURSOR;
+ active_cursor = 0;
+ }
+ }
+ else
+ {
+ if (f != FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame
+ || w != XWINDOW (f->selected_window))
+ {
+ active_cursor = 0;
+
+ if (MINI_WINDOW_P (w)
+ || !cursor_non_selected
+ || NILP (XBUFFER (w->buffer)->cursor_type))
+ new_cursor_type = NO_CURSOR;
+ else
+ new_cursor_type = HOLLOW_BOX_CURSOR;
+ }
+ else
+ {
+ struct buffer *b = XBUFFER (w->buffer);
+
+ if (EQ (b->cursor_type, Qt))
+ new_cursor_type = FRAME_DESIRED_CURSOR (f);
+ else
+ new_cursor_type = x_specified_cursor_type (b->cursor_type,
+ &new_cursor_width);
+ if (w->cursor_off_p)
+ {
+ if (new_cursor_type == FILLED_BOX_CURSOR)
+ new_cursor_type = HOLLOW_BOX_CURSOR;
+ else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1)
+ new_cursor_width = 1;
+ else
+ new_cursor_type = NO_CURSOR;
+ }
+ }
+ }
+
+ /* If cursor is currently being shown and we don't want it to be or
+ it is in the wrong place, or the cursor type is not what we want,
+ erase it. */
+ if (w->phys_cursor_on_p
+ && (!on
+ || w->phys_cursor.x != x
+ || w->phys_cursor.y != y
+ || new_cursor_type != w->phys_cursor_type
+ || (new_cursor_type == BAR_CURSOR
+ && new_cursor_width != w->phys_cursor_width)))
+ x_erase_phys_cursor (w);
+
+ /* If the cursor is now invisible and we want it to be visible,
+ display it. */
+ if (on && !w->phys_cursor_on_p)
+ {
+ w->phys_cursor_ascent = glyph_row->ascent;
+ w->phys_cursor_height = glyph_row->height;
+
+ /* Set phys_cursor_.* before x_draw_.* is called because some
+ of them may need the information. */
+ w->phys_cursor.x = x;
+ w->phys_cursor.y = glyph_row->y;
+ w->phys_cursor.hpos = hpos;
+ w->phys_cursor.vpos = vpos;
+ w->phys_cursor_type = new_cursor_type;
+ w->phys_cursor_width = new_cursor_width;
+ w->phys_cursor_on_p = 1;
+
+ switch (new_cursor_type)
+ {
+ case HOLLOW_BOX_CURSOR:
+ x_draw_hollow_cursor (w, glyph_row);
+ break;
+
+ case FILLED_BOX_CURSOR:
+ x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ break;
+
+ case BAR_CURSOR:
+ x_draw_bar_cursor (w, glyph_row, new_cursor_width);
+ break;
+
+ case NO_CURSOR:
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
+
+
+/* Display the cursor on window W, or clear it. X and Y are window
+ relative pixel coordinates. HPOS and VPOS are glyph matrix
+ positions. If W is not the selected window, display a hollow
+ cursor. ON non-zero means display the cursor at X, Y which
+ correspond to HPOS, VPOS, otherwise it is cleared. */
+
+void
+x_display_cursor (w, on, hpos, vpos, x, y)
+ struct window *w;
+ int on, hpos, vpos, x, y;
+{
+ BLOCK_INPUT;
+ x_display_and_set_cursor (w, on, hpos, vpos, x, y);
+ UNBLOCK_INPUT;
+}
+
+
+/* Display the cursor on window W, or clear it, according to ON_P.
+ Don't change the cursor's position. */
+
+void
+x_update_cursor (f, on_p)
+ struct frame *f;
+ int on_p;
+{
+ x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
+}
+
+
+/* Call x_update_window_cursor with parameter ON_P on all leaf windows
+ in the window tree rooted at W. */
+
+static void
+x_update_cursor_in_window_tree (w, on_p)
+ struct window *w;
+ int on_p;
+{
+ while (w)
+ {
+ if (!NILP (w->hchild))
+ x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
+ else if (!NILP (w->vchild))
+ x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
+ else
+ x_update_window_cursor (w, on_p);
+
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+}
+
+
+/* Switch the display of W's cursor on or off, according to the value
+ of ON. */
+
+static void
+x_update_window_cursor (w, on)
+ struct window *w;
+ int on;
+{
+ /* Don't update cursor in windows whose frame is in the process
+ of being deleted. */
+ if (w->current_matrix)
+ {
+ BLOCK_INPUT;
+ x_display_and_set_cursor (w, on, w->phys_cursor.hpos,
+ w->phys_cursor.vpos, w->phys_cursor.x,
+ w->phys_cursor.y);
+ UNBLOCK_INPUT;
+ }
+}
+
+
+
+
+/* Icons. */
+
+#if 0 /* MAC_TODO: no icon support yet. */
+int
+x_bitmap_icon (f, icon)
+ struct frame *f;
+ Lisp_Object icon;
+{
+ HANDLE hicon;
+
+ if (FRAME_W32_WINDOW (f) == 0)
+ return 1;
+
+ if (NILP (icon))
+ hicon = LoadIcon (hinst, EMACS_CLASS);
+ else if (STRINGP (icon))
+ hicon = LoadImage (NULL, (LPCTSTR) XSTRING (icon)->data, IMAGE_ICON, 0, 0,
+ LR_DEFAULTSIZE | LR_LOADFROMFILE);
+ else if (SYMBOLP (icon))
+ {
+ LPCTSTR name;
+
+ if (EQ (icon, intern ("application")))
+ name = (LPCTSTR) IDI_APPLICATION;
+ else if (EQ (icon, intern ("hand")))
+ name = (LPCTSTR) IDI_HAND;
+ else if (EQ (icon, intern ("question")))
+ name = (LPCTSTR) IDI_QUESTION;
+ else if (EQ (icon, intern ("exclamation")))
+ name = (LPCTSTR) IDI_EXCLAMATION;
+ else if (EQ (icon, intern ("asterisk")))
+ name = (LPCTSTR) IDI_ASTERISK;
+ else if (EQ (icon, intern ("winlogo")))
+ name = (LPCTSTR) IDI_WINLOGO;
+ else
+ return 1;
+
+ hicon = LoadIcon (NULL, name);
+ }
+ else
+ return 1;
+
+ if (hicon == NULL)
+ return 1;
+
+ PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
+ (LPARAM) hicon);
+
+ return 0;
+}
+#endif /* MAC_TODO */
+
+/************************************************************************
+ Handling X errors
+ ************************************************************************/
+
+/* Display Error Handling functions not used on W32. Listing them here
+ helps diff stay in step when comparing w32term.c with xterm.c.
+
+x_error_catcher (display, error)
+x_catch_errors (dpy)
+x_catch_errors_unwind (old_val)
+x_check_errors (dpy, format)
+x_had_errors_p (dpy)
+x_clear_errors (dpy)
+x_uncatch_errors (dpy, count)
+x_trace_wire ()
+x_connection_signal (signalnum)
+x_connection_closed (dpy, error_message)
+x_error_quitter (display, error)
+x_error_handler (display, error)
+x_io_error_quitter (display)
+
+ */
+
+
+/* Changing the font of the frame. */
+
+/* Give frame F the font named FONTNAME as its default font, and
+ return the full name of that font. FONTNAME may be a wildcard
+ pattern; in that case, we choose some font that fits the pattern.
+ The return value shows which font we chose. */
+
+Lisp_Object
+x_new_font (f, fontname)
+ struct frame *f;
+ register char *fontname;
+{
+ struct font_info *fontp
+ = FS_LOAD_FONT (f, 0, fontname, -1);
+
+ if (!fontp)
+ return Qnil;
+
+ FRAME_FONT (f) = (XFontStruct *) (fontp->font);
+ FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
+ FRAME_FONTSET (f) = -1;
+
+ /* Compute the scroll bar width in character columns. */
+ if (f->scroll_bar_pixel_width > 0)
+ {
+ int wid = FONT_WIDTH (FRAME_FONT (f));
+ f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
+ }
+ else
+ {
+ int wid = FONT_WIDTH (FRAME_FONT (f));
+ f->scroll_bar_cols = (14 + wid - 1) / wid;
+ }
+
+ /* Now make the frame display the given font. */
+ if (FRAME_MAC_WINDOW (f) != 0)
+ {
+ frame_update_line_height (f);
+ if (NILP (tip_frame) || XFRAME (tip_frame) != f)
+ x_set_window_size (f, 0, f->width, f->height);
+ }
+ else
+ /* If we are setting a new frame's font for the first time,
+ there are no faces yet, so this font's height is the line height. */
+ f->output_data.mac->line_height = FONT_HEIGHT (FRAME_FONT (f));
+
+ return build_string (fontp->full_name);
+}
+
+/* Give frame F the fontset named FONTSETNAME as its default font, and
+ return the full name of that fontset. FONTSETNAME may be a wildcard
+ pattern; in that case, we choose some fontset that fits the pattern.
+ The return value shows which fontset we chose. */
+
+Lisp_Object
+x_new_fontset (f, fontsetname)
+ struct frame *f;
+ char *fontsetname;
+{
+ int fontset = fs_query_fontset (build_string (fontsetname), 0);
+ Lisp_Object result;
+
+ if (fontset < 0)
+ return Qnil;
+
+ if (FRAME_FONTSET (f) == fontset)
+ /* This fontset is already set in frame F. There's nothing more
+ to do. */
+ return fontset_name (fontset);
+
+ result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
+
+ if (!STRINGP (result))
+ /* Can't load ASCII font. */
+ return Qnil;
+
+ /* Since x_new_font doesn't update any fontset information, do it now. */
+ FRAME_FONTSET(f) = fontset;
+
+ return build_string (fontsetname);
+}
+
+/* Compute actual fringe widths */
+
+void
+x_compute_fringe_widths (f, redraw)
+ struct frame *f;
+ int redraw;
+{
+ int o_left = f->output_data.mac->left_fringe_width;
+ int o_right = f->output_data.mac->right_fringe_width;
+ int o_cols = f->output_data.mac->fringe_cols;
+
+ Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
+ Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
+ int left_fringe_width, right_fringe_width;
+
+ if (!NILP (left_fringe))
+ left_fringe = Fcdr (left_fringe);
+ if (!NILP (right_fringe))
+ right_fringe = Fcdr (right_fringe);
+
+ left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
+ XINT (left_fringe));
+ right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
+ XINT (right_fringe));
+
+ if (left_fringe_width || right_fringe_width)
+ {
+ int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
+ int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
+ int conf_wid = left_wid + right_wid;
+ int font_wid = FONT_WIDTH (f->output_data.mac->font);
+ int cols = (left_wid + right_wid + font_wid-1) / font_wid;
+ int real_wid = cols * font_wid;
+ if (left_wid && right_wid)
+ {
+ if (left_fringe_width < 0)
+ {
+ /* Left fringe width is fixed, adjust right fringe if necessary */
+ f->output_data.mac->left_fringe_width = left_wid;
+ f->output_data.mac->right_fringe_width = real_wid - left_wid;
+ }
+ else if (right_fringe_width < 0)
+ {
+ /* Right fringe width is fixed, adjust left fringe if necessary */
+ f->output_data.mac->left_fringe_width = real_wid - right_wid;
+ f->output_data.mac->right_fringe_width = right_wid;
+ }
+ else
+ {
+ /* Adjust both fringes with an equal amount.
+ Note that we are doing integer arithmetic here, so don't
+ lose a pixel if the total width is an odd number. */
+ int fill = real_wid - conf_wid;
+ f->output_data.mac->left_fringe_width = left_wid + fill/2;
+ f->output_data.mac->right_fringe_width = right_wid + fill - fill/2;
+ }
+ }
+ else if (left_fringe_width)
+ {
+ f->output_data.mac->left_fringe_width = real_wid;
+ f->output_data.mac->right_fringe_width = 0;
+ }
+ else
+ {
+ f->output_data.mac->left_fringe_width = 0;
+ f->output_data.mac->right_fringe_width = real_wid;
+ }
+ f->output_data.mac->fringe_cols = cols;
+ f->output_data.mac->fringes_extra = real_wid;
+ }
+ else
+ {
+ f->output_data.mac->left_fringe_width = 0;
+ f->output_data.mac->right_fringe_width = 0;
+ f->output_data.mac->fringe_cols = 0;
+ f->output_data.mac->fringes_extra = 0;
+ }
+
+ if (redraw && FRAME_VISIBLE_P (f))
+ if (o_left != f->output_data.mac->left_fringe_width ||
+ o_right != f->output_data.mac->right_fringe_width ||
+ o_cols != f->output_data.mac->fringe_cols)
+ redraw_frame (f);
+}
+
+/***********************************************************************
+ TODO: W32 Input Methods
+ ***********************************************************************/
+/* Listing missing functions from xterm.c helps diff stay in step.
+
+xim_destroy_callback (xim, client_data, call_data)
+xim_open_dpy (dpyinfo, resource_name)
+struct xim_inst_t
+xim_instantiate_callback (display, client_data, call_data)
+xim_initialize (dpyinfo, resource_name)
+xim_close_dpy (dpyinfo)
+
+ */
+
+
+/* Calculate the absolute position in frame F
+ from its current recorded position values and gravity. */
+
+void
+x_calc_absolute_position (f)
+ struct frame *f;
+{
+ Point pt;
+ int flags = f->output_data.mac->size_hint_flags;
+
+ pt.h = pt.v = 0;
+
+ /* Find the position of the outside upper-left corner of
+ the inner window, with respect to the outer window. */
+ if (f->output_data.mac->parent_desc != FRAME_MAC_DISPLAY_INFO (f)->root_window)
+ {
+ GrafPtr savePort;
+ GetPort (&savePort);
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (FRAME_MAC_WINDOW (f)));
+#else
+ SetPort (FRAME_MAC_WINDOW (f));
+#endif
+
+#if TARGET_API_MAC_CARBON
+ {
+ Rect r;
+
+ GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r);
+ SetPt(&pt, r.left, r.top);
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ SetPt(&pt, FRAME_MAC_WINDOW (f)->portRect.left, FRAME_MAC_WINDOW (f)->portRect.top);
+#endif /* not TARGET_API_MAC_CARBON */
+ LocalToGlobal (&pt);
+ SetPort (savePort);
+ }
+
+ /* Treat negative positions as relative to the leftmost bottommost
+ position that fits on the screen. */
+ if (flags & XNegative)
+ f->output_data.mac->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
+ - 2 * f->output_data.mac->border_width - pt.h
+ - PIXEL_WIDTH (f)
+ + f->output_data.mac->left_pos);
+ /* NTEMACS_TODO: Subtract menubar height? */
+ if (flags & YNegative)
+ f->output_data.mac->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
+ - 2 * f->output_data.mac->border_width - pt.v
+ - PIXEL_HEIGHT (f)
+ + f->output_data.mac->top_pos);
+ /* The left_pos and top_pos
+ are now relative to the top and left screen edges,
+ so the flags should correspond. */
+ f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
+}
+
+/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
+ to really change the position, and 0 when calling from
+ x_make_frame_visible (in that case, XOFF and YOFF are the current
+ position values). It is -1 when calling from x_set_frame_parameters,
+ which means, do adjust for borders but don't change the gravity. */
+
+void
+x_set_offset (f, xoff, yoff, change_gravity)
+ struct frame *f;
+ register int xoff, yoff;
+ int change_gravity;
+{
+ int modified_top, modified_left;
+
+ if (change_gravity > 0)
+ {
+ f->output_data.mac->top_pos = yoff;
+ f->output_data.mac->left_pos = xoff;
+ f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
+ if (xoff < 0)
+ f->output_data.mac->size_hint_flags |= XNegative;
+ if (yoff < 0)
+ f->output_data.mac->size_hint_flags |= YNegative;
+ f->output_data.mac->win_gravity = NorthWestGravity;
+ }
+ x_calc_absolute_position (f);
+
+ BLOCK_INPUT;
+ x_wm_set_size_hint (f, (long) 0, 0);
+
+ modified_left = f->output_data.mac->left_pos;
+ modified_top = f->output_data.mac->top_pos;
+
+ MoveWindow (f->output_data.mac->mWP, modified_left + 6,
+ modified_top + 42, false);
+
+ UNBLOCK_INPUT;
+}
+
+/* Call this to change the size of frame F's x-window.
+ If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
+ for this size change and subsequent size changes.
+ Otherwise we leave the window gravity unchanged. */
+
+void
+x_set_window_size (f, change_gravity, cols, rows)
+ struct frame *f;
+ int change_gravity;
+ int cols, rows;
+{
+ int pixelwidth, pixelheight;
+
+ BLOCK_INPUT;
+
+ check_frame_size (f, &rows, &cols);
+ f->output_data.mac->vertical_scroll_bar_extra
+ = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+ ? 0
+ : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
+
+ x_compute_fringe_widths (f, 0);
+
+ pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
+ pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
+
+ f->output_data.mac->win_gravity = NorthWestGravity;
+ x_wm_set_size_hint (f, (long) 0, 0);
+
+ SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
+
+ /* Now, strictly speaking, we can't be sure that this is accurate,
+ but the window manager will get around to dealing with the size
+ change request eventually, and we'll hear how it went when the
+ ConfigureNotify event gets here.
+
+ We could just not bother storing any of this information here,
+ and let the ConfigureNotify event set everything up, but that
+ might be kind of confusing to the Lisp code, since size changes
+ wouldn't be reported in the frame parameters until some random
+ point in the future when the ConfigureNotify event arrives.
+
+ We pass 1 for DELAY since we can't run Lisp code inside of
+ a BLOCK_INPUT. */
+ change_frame_size (f, rows, cols, 0, 1, 0);
+ PIXEL_WIDTH (f) = pixelwidth;
+ PIXEL_HEIGHT (f) = pixelheight;
+
+ /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
+ receive in the ConfigureNotify event; if we get what we asked
+ for, then the event won't cause the screen to become garbaged, so
+ we have to make sure to do it here. */
+ SET_FRAME_GARBAGED (f);
+
+ XFlush (FRAME_X_DISPLAY (f));
+
+ /* If cursor was outside the new size, mark it as off. */
+ mark_window_cursors_off (XWINDOW (f->root_window));
+
+ /* Clear out any recollection of where the mouse highlighting was,
+ since it might be in a place that's outside the new frame size.
+ Actually checking whether it is outside is a pain in the neck,
+ so don't try--just let the highlighting be done afresh with new size. */
+ cancel_mouse_face (f);
+
+ UNBLOCK_INPUT;
+}
+
+/* Mouse warping. */
+
+void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
+
+void
+x_set_mouse_position (f, x, y)
+ struct frame *f;
+ int x, y;
+{
+ int pix_x, pix_y;
+
+ pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.mac->font) / 2;
+ pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.mac->line_height / 2;
+
+ if (pix_x < 0) pix_x = 0;
+ if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
+
+ if (pix_y < 0) pix_y = 0;
+ if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
+
+ x_set_mouse_pixel_position (f, pix_x, pix_y);
+}
+
+void
+x_set_mouse_pixel_position (f, pix_x, pix_y)
+ struct frame *f;
+ int pix_x, pix_y;
+{
+#if 0 /* MAC_TODO: CursorDeviceMoveTo is non-Carbon */
+ BLOCK_INPUT;
+
+ XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
+ 0, 0, 0, 0, pix_x, pix_y);
+ UNBLOCK_INPUT;
+#endif
+}
+
+
+/* focus shifting, raising and lowering. */
+
+void
+x_focus_on_frame (f)
+ struct frame *f;
+{
+#if 0 /* This proves to be unpleasant. */
+ x_raise_frame (f);
+#endif
+#if 0
+ /* I don't think that the ICCCM allows programs to do things like this
+ without the interaction of the window manager. Whatever you end up
+ doing with this code, do it to x_unfocus_frame too. */
+ XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ RevertToPointerRoot, CurrentTime);
+#endif /* ! 0 */
+}
+
+void
+x_unfocus_frame (f)
+ struct frame *f;
+{
+}
+
+/* Raise frame F. */
+void
+x_raise_frame (f)
+ struct frame *f;
+{
+ if (f->async_visible)
+ SelectWindow (FRAME_MAC_WINDOW (f));
+}
+
+/* Lower frame F. */
+void
+x_lower_frame (f)
+ struct frame *f;
+{
+ if (f->async_visible)
+ SendBehind (FRAME_MAC_WINDOW (f), nil);
+}
+
+static void
+XTframe_raise_lower (f, raise_flag)
+ FRAME_PTR f;
+ int raise_flag;
+{
+ if (raise_flag)
+ x_raise_frame (f);
+ else
+ x_lower_frame (f);
+}
+
+/* Change of visibility. */
+
+/* This tries to wait until the frame is really visible.
+ However, if the window manager asks the user where to position
+ the frame, this will return before the user finishes doing that.
+ The frame will not actually be visible at that time,
+ but it will become visible later when the window manager
+ finishes with it. */
+
+void
+x_make_frame_visible (f)
+ struct frame *f;
+{
+ Lisp_Object type;
+ int original_top, original_left;
+
+ BLOCK_INPUT;
+
+ if (! FRAME_VISIBLE_P (f))
+ {
+ /* We test FRAME_GARBAGED_P here to make sure we don't
+ call x_set_offset a second time
+ if we get to x_make_frame_visible a second time
+ before the window gets really visible. */
+ if (! FRAME_ICONIFIED_P (f)
+ && ! f->output_data.mac->asked_for_visible)
+ x_set_offset (f, f->output_data.mac->left_pos,
+ f->output_data.mac->top_pos, 0);
+
+ f->output_data.mac->asked_for_visible = 1;
+
+ ShowWindow (FRAME_MAC_WINDOW (f));
+ }
+
+ XFlush (FRAME_MAC_DISPLAY (f));
+
+#if 0 /* MAC_TODO */
+ /* Synchronize to ensure Emacs knows the frame is visible
+ before we do anything else. We do this loop with input not blocked
+ so that incoming events are handled. */
+ {
+ Lisp_Object frame;
+ int count;
+
+ /* This must come after we set COUNT. */
+ UNBLOCK_INPUT;
+
+ XSETFRAME (frame, f);
+
+ /* Wait until the frame is visible. Process X events until a
+ MapNotify event has been seen, or until we think we won't get a
+ MapNotify at all.. */
+ for (count = input_signal_count + 10;
+ input_signal_count < count && !FRAME_VISIBLE_P (f);)
+ {
+ /* Force processing of queued events. */
+ x_sync (f);
+
+ /* Machines that do polling rather than SIGIO have been
+ observed to go into a busy-wait here. So we'll fake an
+ alarm signal to let the handler know that there's something
+ to be read. We used to raise a real alarm, but it seems
+ that the handler isn't always enabled here. This is
+ probably a bug. */
+ if (input_polling_used ())
+ {
+ /* It could be confusing if a real alarm arrives while
+ processing the fake one. Turn it off and let the
+ handler reset it. */
+ extern void poll_for_input_1 P_ ((void));
+ int old_poll_suppress_count = poll_suppress_count;
+ poll_suppress_count = 1;
+ poll_for_input_1 ();
+ poll_suppress_count = old_poll_suppress_count;
+ }
+
+ /* See if a MapNotify event has been processed. */
+ FRAME_SAMPLE_VISIBILITY (f);
+ }
+ }
+#endif /* MAC_TODO */
+}
+
+/* Change from mapped state to withdrawn state. */
+
+/* Make the frame visible (mapped and not iconified). */
+
+void
+x_make_frame_invisible (f)
+ struct frame *f;
+{
+ /* Don't keep the highlight on an invisible frame. */
+ if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
+ FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
+
+ BLOCK_INPUT;
+
+ HideWindow (FRAME_MAC_WINDOW (f));
+
+ /* We can't distinguish this from iconification
+ just by the event that we get from the server.
+ So we can't win using the usual strategy of letting
+ FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
+ and synchronize with the server to make sure we agree. */
+ f->visible = 0;
+ FRAME_ICONIFIED_P (f) = 0;
+ f->async_visible = 0;
+ f->async_iconified = 0;
+
+ UNBLOCK_INPUT;
+}
+
+/* Change window state from mapped to iconified. */
+
+void
+x_iconify_frame (f)
+ struct frame *f;
+{
+#if 0 /* MAC_TODO: really no iconify on Mac */
+ int result;
+ Lisp_Object type;
+
+ /* Don't keep the highlight on an invisible frame. */
+ if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
+ FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
+
+ if (f->async_iconified)
+ return;
+
+ BLOCK_INPUT;
+
+ FRAME_SAMPLE_VISIBILITY (f);
+
+ type = x_icon_type (f);
+ if (!NILP (type))
+ x_bitmap_icon (f, type);
+
+#ifdef USE_X_TOOLKIT
+
+ if (! FRAME_VISIBLE_P (f))
+ {
+ if (! EQ (Vx_no_window_manager, Qt))
+ x_wm_set_window_state (f, IconicState);
+ /* This was XtPopup, but that did nothing for an iconified frame. */
+ XtMapWidget (f->output_data.x->widget);
+ /* The server won't give us any event to indicate
+ that an invisible frame was changed to an icon,
+ so we have to record it here. */
+ f->iconified = 1;
+ f->visible = 1;
+ f->async_iconified = 1;
+ f->async_visible = 0;
+ UNBLOCK_INPUT;
+ return;
+ }
+
+ result = XIconifyWindow (FRAME_X_DISPLAY (f),
+ XtWindow (f->output_data.x->widget),
+ DefaultScreen (FRAME_X_DISPLAY (f)));
+ UNBLOCK_INPUT;
+
+ if (!result)
+ error ("Can't notify window manager of iconification");
+
+ f->async_iconified = 1;
+ f->async_visible = 0;
+
+
+ BLOCK_INPUT;
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+#else /* not USE_X_TOOLKIT */
+
+ /* Make sure the X server knows where the window should be positioned,
+ in case the user deiconifies with the window manager. */
+ if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
+ x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
+
+ /* Since we don't know which revision of X we're running, we'll use both
+ the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
+
+ /* X11R4: send a ClientMessage to the window manager using the
+ WM_CHANGE_STATE type. */
+ {
+ XEvent message;
+
+ message.xclient.window = FRAME_X_WINDOW (f);
+ message.xclient.type = ClientMessage;
+ message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
+ message.xclient.format = 32;
+ message.xclient.data.l[0] = IconicState;
+
+ if (! XSendEvent (FRAME_X_DISPLAY (f),
+ DefaultRootWindow (FRAME_X_DISPLAY (f)),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &message))
+ {
+ UNBLOCK_INPUT_RESIGNAL;
+ error ("Can't notify window manager of iconification");
+ }
+ }
+
+ /* X11R3: set the initial_state field of the window manager hints to
+ IconicState. */
+ x_wm_set_window_state (f, IconicState);
+
+ if (!FRAME_VISIBLE_P (f))
+ {
+ /* If the frame was withdrawn, before, we must map it. */
+ XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ }
+
+ f->async_iconified = 1;
+ f->async_visible = 0;
+
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+#endif /* not USE_X_TOOLKIT */
+#endif /* MAC_TODO */
+}
+
+
+/* Destroy the X window of frame F. */
+
+void
+x_destroy_window (f)
+ struct frame *f;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+
+ BLOCK_INPUT;
+
+ DisposeWindow (FRAME_MAC_WINDOW (f));
+
+ free_frame_menubar (f);
+ free_frame_faces (f);
+
+ xfree (f->output_data.mac);
+ f->output_data.mac = 0;
+ if (f == dpyinfo->x_focus_frame)
+ dpyinfo->x_focus_frame = 0;
+ if (f == dpyinfo->x_focus_event_frame)
+ dpyinfo->x_focus_event_frame = 0;
+ if (f == dpyinfo->x_highlight_frame)
+ dpyinfo->x_highlight_frame = 0;
+
+ dpyinfo->reference_count--;
+
+ if (f == dpyinfo->mouse_face_mouse_frame)
+ {
+ dpyinfo->mouse_face_beg_row
+ = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row
+ = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ dpyinfo->mouse_face_deferred_gc = 0;
+ dpyinfo->mouse_face_mouse_frame = 0;
+ }
+
+ UNBLOCK_INPUT;
+}
+
+/* Setting window manager hints. */
+
+/* Set the normal size hints for the window manager, for frame F.
+ FLAGS is the flags word to use--or 0 meaning preserve the flags
+ that the window now has.
+ If USER_POSITION is nonzero, we set the USPosition
+ flag (this is useful when FLAGS is 0). */
+void
+x_wm_set_size_hint (f, flags, user_position)
+ struct frame *f;
+ long flags;
+ int user_position;
+{
+#if 0 /* MAC_TODO: connect this to the Appearance Manager */
+ XSizeHints size_hints;
+
+#ifdef USE_X_TOOLKIT
+ Arg al[2];
+ int ac = 0;
+ Dimension widget_width, widget_height;
+ Window window = XtWindow (f->output_data.x->widget);
+#else /* not USE_X_TOOLKIT */
+ Window window = FRAME_X_WINDOW (f);
+#endif /* not USE_X_TOOLKIT */
+
+ /* Setting PMaxSize caused various problems. */
+ size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
+
+ size_hints.x = f->output_data.x->left_pos;
+ size_hints.y = f->output_data.x->top_pos;
+
+#ifdef USE_X_TOOLKIT
+ XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
+ XtSetArg (al[ac], XtNheight, &widget_height); ac++;
+ XtGetValues (f->output_data.x->widget, al, ac);
+ size_hints.height = widget_height;
+ size_hints.width = widget_width;
+#else /* not USE_X_TOOLKIT */
+ size_hints.height = PIXEL_HEIGHT (f);
+ size_hints.width = PIXEL_WIDTH (f);
+#endif /* not USE_X_TOOLKIT */
+
+ size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
+ size_hints.height_inc = f->output_data.x->line_height;
+ size_hints.max_width
+ = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
+ size_hints.max_height
+ = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
+
+ /* Calculate the base and minimum sizes.
+
+ (When we use the X toolkit, we don't do it here.
+ Instead we copy the values that the widgets are using, below.) */
+#ifndef USE_X_TOOLKIT
+ {
+ int base_width, base_height;
+ int min_rows = 0, min_cols = 0;
+
+ base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
+ base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
+
+ check_frame_size (f, &min_rows, &min_cols);
+
+ /* The window manager uses the base width hints to calculate the
+ current number of rows and columns in the frame while
+ resizing; min_width and min_height aren't useful for this
+ purpose, since they might not give the dimensions for a
+ zero-row, zero-column frame.
+
+ We use the base_width and base_height members if we have
+ them; otherwise, we set the min_width and min_height members
+ to the size for a zero x zero frame. */
+
+#ifdef HAVE_X11R4
+ size_hints.flags |= PBaseSize;
+ size_hints.base_width = base_width;
+ size_hints.base_height = base_height;
+ size_hints.min_width = base_width + min_cols * size_hints.width_inc;
+ size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+#else
+ size_hints.min_width = base_width;
+ size_hints.min_height = base_height;
+#endif
+ }
+
+ /* If we don't need the old flags, we don't need the old hint at all. */
+ if (flags)
+ {
+ size_hints.flags |= flags;
+ goto no_read;
+ }
+#endif /* not USE_X_TOOLKIT */
+
+ {
+ XSizeHints hints; /* Sometimes I hate X Windows... */
+ long supplied_return;
+ int value;
+
+#ifdef HAVE_X11R4
+ value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
+ &supplied_return);
+#else
+ value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
+#endif
+
+#ifdef USE_X_TOOLKIT
+ size_hints.base_height = hints.base_height;
+ size_hints.base_width = hints.base_width;
+ size_hints.min_height = hints.min_height;
+ size_hints.min_width = hints.min_width;
+#endif
+
+ if (flags)
+ size_hints.flags |= flags;
+ else
+ {
+ if (value == 0)
+ hints.flags = 0;
+ if (hints.flags & PSize)
+ size_hints.flags |= PSize;
+ if (hints.flags & PPosition)
+ size_hints.flags |= PPosition;
+ if (hints.flags & USPosition)
+ size_hints.flags |= USPosition;
+ if (hints.flags & USSize)
+ size_hints.flags |= USSize;
+ }
+ }
+
+#ifndef USE_X_TOOLKIT
+ no_read:
+#endif
+
+#ifdef PWinGravity
+ size_hints.win_gravity = f->output_data.x->win_gravity;
+ size_hints.flags |= PWinGravity;
+
+ if (user_position)
+ {
+ size_hints.flags &= ~ PPosition;
+ size_hints.flags |= USPosition;
+ }
+#endif /* PWinGravity */
+
+#ifdef HAVE_X11R4
+ XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
+#else
+ XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
+#endif
+#endif /* MAC_TODO */
+}
+
+#if 0 /* MAC_TODO: hide application instead of iconify? */
+/* Used for IconicState or NormalState */
+
+void
+x_wm_set_window_state (f, state)
+ struct frame *f;
+ int state;
+{
+#ifdef USE_X_TOOLKIT
+ Arg al[1];
+
+ XtSetArg (al[0], XtNinitialState, state);
+ XtSetValues (f->output_data.x->widget, al, 1);
+#else /* not USE_X_TOOLKIT */
+ Window window = FRAME_X_WINDOW (f);
+
+ f->output_data.x->wm_hints.flags |= StateHint;
+ f->output_data.x->wm_hints.initial_state = state;
+
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+#endif /* not USE_X_TOOLKIT */
+}
+
+void
+x_wm_set_icon_pixmap (f, pixmap_id)
+ struct frame *f;
+ int pixmap_id;
+{
+ Pixmap icon_pixmap;
+
+#ifndef USE_X_TOOLKIT
+ Window window = FRAME_X_WINDOW (f);
+#endif
+
+ if (pixmap_id > 0)
+ {
+ icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
+ f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
+ }
+ else
+ {
+ /* It seems there is no way to turn off use of an icon pixmap.
+ The following line does it, only if no icon has yet been created,
+ for some window managers. But with mwm it crashes.
+ Some people say it should clear the IconPixmapHint bit in this case,
+ but that doesn't work, and the X consortium said it isn't the
+ right thing at all. Since there is no way to win,
+ best to explicitly give up. */
+#if 0
+ f->output_data.x->wm_hints.icon_pixmap = None;
+#else
+ return;
+#endif
+ }
+
+#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
+
+ {
+ Arg al[1];
+ XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
+ XtSetValues (f->output_data.x->widget, al, 1);
+ }
+
+#else /* not USE_X_TOOLKIT */
+
+ f->output_data.x->wm_hints.flags |= IconPixmapHint;
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+
+#endif /* not USE_X_TOOLKIT */
+}
+
+#endif /* MAC_TODO */
+
+void
+x_wm_set_icon_position (f, icon_x, icon_y)
+ struct frame *f;
+ int icon_x, icon_y;
+{
+#if 0 /* MAC_TODO: no icons on Mac */
+#ifdef USE_X_TOOLKIT
+ Window window = XtWindow (f->output_data.x->widget);
+#else
+ Window window = FRAME_X_WINDOW (f);
+#endif
+
+ f->output_data.x->wm_hints.flags |= IconPositionHint;
+ f->output_data.x->wm_hints.icon_x = icon_x;
+ f->output_data.x->wm_hints.icon_y = icon_y;
+
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+#endif /* MAC_TODO */
+}
+
+
+/***********************************************************************
+ Fonts
+ ***********************************************************************/
+
+/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
+
+struct font_info *
+x_get_font_info (f, font_idx)
+ FRAME_PTR f;
+ int font_idx;
+{
+ return (FRAME_MAC_FONT_TABLE (f) + font_idx);
+}
+
+/* the global font name table */
+char **font_name_table = NULL;
+int font_name_table_size = 0;
+int font_name_count = 0;
+
+/* compare two strings ignoring case */
+static int
+stricmp (const char *s, const char *t)
+{
+ for ( ; tolower (*s) == tolower (*t); s++, t++)
+ if (*s == '\0')
+ return 0;
+ return tolower (*s) - tolower (*t);
+}
+
+/* compare two strings ignoring case and handling wildcard */
+static int
+wildstrieq (char *s1, char *s2)
+{
+ if (strcmp (s1, "*") == 0 || strcmp (s2, "*") == 0)
+ return true;
+
+ return stricmp (s1, s2) == 0;
+}
+
+/* Assume parameter 1 is fully qualified, no wildcards. */
+static int
+mac_font_pattern_match (fontname, pattern)
+ char * fontname;
+ char * pattern;
+{
+ char *regex = (char *) alloca (strlen (pattern) * 2 + 3);
+ char *font_name_copy = (char *) alloca (strlen (fontname) + 1);
+ char *ptr;
+
+ /* Copy fontname so we can modify it during comparison. */
+ strcpy (font_name_copy, fontname);
+
+ ptr = regex;
+ *ptr++ = '^';
+
+ /* Turn pattern into a regexp and do a regexp match. */
+ for (; *pattern; pattern++)
+ {
+ if (*pattern == '?')
+ *ptr++ = '.';
+ else if (*pattern == '*')
+ {
+ *ptr++ = '.';
+ *ptr++ = '*';
+ }
+ else
+ *ptr++ = *pattern;
+ }
+ *ptr = '$';
+ *(ptr + 1) = '\0';
+
+ return (fast_c_string_match_ignore_case (build_string (regex),
+ font_name_copy) >= 0);
+}
+
+/* Two font specs are considered to match if their foundry, family,
+ weight, slant, and charset match. */
+static int
+mac_font_match (char *mf, char *xf)
+{
+ char m_foundry[50], m_family[50], m_weight[20], m_slant[2], m_charset[20];
+ char x_foundry[50], x_family[50], x_weight[20], x_slant[2], x_charset[20];
+
+ if (sscanf (mf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s",
+ m_foundry, m_family, m_weight, m_slant, m_charset) != 5)
+ return mac_font_pattern_match (mf, xf);
+
+ if (sscanf (xf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s",
+ x_foundry, x_family, x_weight, x_slant, x_charset) != 5)
+ return mac_font_pattern_match (mf, xf);
+
+ return (wildstrieq (m_foundry, x_foundry)
+ && wildstrieq (m_family, x_family)
+ && wildstrieq (m_weight, x_weight)
+ && wildstrieq (m_slant, x_slant)
+ && wildstrieq (m_charset, x_charset))
+ || mac_font_pattern_match (mf, xf);
+}
+
+
+static char *
+mac_to_x_fontname (char *name, int size, Style style, short scriptcode)
+{
+ char foundry[32], family[32], cs[32];
+ char xf[255], *result, *p;
+
+ if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3)
+ {
+ strcpy(foundry, "Apple");
+ strcpy(family, name);
+
+ switch (scriptcode)
+ {
+ case smTradChinese:
+ strcpy(cs, "big5-0");
+ break;
+ case smSimpChinese:
+ strcpy(cs, "gb2312.1980-0");
+ break;
+ case smJapanese:
+ strcpy(cs, "jisx0208.1983-sjis");
+ break;
+ case -smJapanese:
+ /* Each Apple Japanese font is entered into the font table
+ twice: once as a jisx0208.1983-sjis font and once as a
+ jisx0201.1976-0 font. The latter can be used to display
+ the ascii charset and katakana-jisx0201 charset. A
+ negative script code signals that the name of this latter
+ font is being built. */
+ strcpy(cs, "jisx0201.1976-0");
+ break;
+ case smKorean:
+ strcpy(cs, "ksc5601.1989-0");
+ break;
+ default:
+ strcpy(cs, "mac-roman");
+ break;
+ }
+ }
+
+ sprintf(xf, "-%s-%s-%s-%c-normal--%d-%d-75-75-m-%d-%s",
+ foundry, family, style & bold ? "bold" : "medium",
+ style & italic ? 'i' : 'r', size, size * 10, size * 10, cs);
+
+ result = (char *) xmalloc (strlen (xf) + 1);
+ strcpy (result, xf);
+ for (p = result; *p; p++)
+ *p = tolower(*p);
+ return result;
+}
+
+
+/* Convert an X font spec to the corresponding mac font name, which
+ can then be passed to GetFNum after conversion to a Pascal string.
+ For ordinary Mac fonts, this should just be their names, like
+ "monaco", "Taipei", etc. Fonts converted from the GNU intlfonts
+ collection contain their charset designation in their names, like
+ "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both types of font
+ names are handled accordingly. */
+static void
+x_font_name_to_mac_font_name (char *xf, char *mf)
+{
+ char foundry[32], family[32], weight[20], slant[2], cs[32];
+
+ strcpy (mf, "");
+
+ if (sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
+ foundry, family, weight, slant, cs) != 5 &&
+ sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
+ foundry, family, weight, slant, cs) != 5)
+ return;
+
+ if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312.1980-0") == 0
+ || strcmp (cs, "jisx0208.1983-sjis") == 0
+ || strcmp (cs, "jisx0201.1976-0") == 0
+ || strcmp (cs, "ksc5601.1989-0") == 0 || strcmp (cs, "mac-roman") == 0)
+ strcpy(mf, family);
+ else
+ sprintf(mf, "%s-%s-%s", foundry, family, cs);
+}
+
+
+/* Sets up the table font_name_table to contain the list of all
+ monospace fonts in the system the first time the table is used so
+ that the Resource Manager need not be accessed every time this
+ information is needed. */
+
+static void
+init_font_name_table ()
+{
+#if TARGET_API_MAC_CARBON
+ SInt32 sv;
+
+ if (Gestalt (gestaltSystemVersion, &sv) == noErr && sv >= 0x1000)
+ {
+ FMFontFamilyIterator ffi;
+ FMFontFamilyInstanceIterator ffii;
+ FMFontFamily ff;
+
+ /* Create a dummy instance iterator here to avoid creating and
+ destroying it in the loop. */
+ if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr)
+ return;
+ /* Create an iterator to enumerate the font families. */
+ if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi)
+ != noErr)
+ {
+ FMDisposeFontFamilyInstanceIterator (&ffii);
+ return;
+ }
+
+ while (FMGetNextFontFamily (&ffi, &ff) == noErr)
+ {
+ Str255 name;
+ FMFont font;
+ FMFontStyle style;
+ FMFontSize size;
+ SInt16 sc;
+
+ if (FMGetFontFamilyName (ff, name) != noErr)
+ break;
+ p2cstr (name);
+
+ sc = FontToScript (ff);
+
+ /* Point the instance iterator at the current font family. */
+ if (FMResetFontFamilyInstanceIterator(ff, &ffii) != noErr)
+ break;
+
+ while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size)
+ == noErr)
+ {
+ if (font_name_table_size == 0)
+ {
+ font_name_table_size = 16;
+ font_name_table = (char **)
+ xmalloc (font_name_table_size * sizeof (char *));
+ }
+ else if (font_name_count + 1 >= font_name_table_size)
+ {
+ font_name_table_size += 16;
+ font_name_table = (char **)
+ xrealloc (font_name_table,
+ font_name_table_size * sizeof (char *));
+ }
+ font_name_table[font_name_count++]
+ = mac_to_x_fontname (name, size, style, sc);
+ }
+ }
+
+ /* Dispose of the iterators. */
+ FMDisposeFontFamilyIterator (&ffi);
+ FMDisposeFontFamilyInstanceIterator (&ffii);
+ }
+ else
+ {
+#endif /* TARGET_API_MAC_CARBON */
+ GrafPtr port;
+ SInt16 fontnum, old_fontnum;
+ int num_mac_fonts = CountResources('FOND');
+ int i, j;
+ Handle font_handle, font_handle_2;
+ short id, scriptcode;
+ ResType type;
+ Str32 name;
+ struct FontAssoc *fat;
+ struct AsscEntry *assc_entry;
+
+ GetPort (&port); /* save the current font number used */
+#if TARGET_API_MAC_CARBON
+ old_fontnum = GetPortTextFont (port);
+#else
+ old_fontnum = port->txFont;
+#endif
+
+ for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */
+ {
+ font_handle = GetIndResource ('FOND', i);
+ if (!font_handle)
+ continue;
+
+ GetResInfo (font_handle, &id, &type, name);
+ GetFNum (name, &fontnum);
+ p2cstr (name);
+ if (fontnum == 0)
+ continue;
+
+ TextFont (fontnum);
+ scriptcode = FontToScript (fontnum);
+ do
+ {
+ HLock (font_handle);
+
+ if (GetResourceSizeOnDisk (font_handle)
+ >= sizeof (struct FamRec))
+ {
+ fat = (struct FontAssoc *) (*font_handle
+ + sizeof (struct FamRec));
+ assc_entry
+ = (struct AsscEntry *) (*font_handle
+ + sizeof (struct FamRec)
+ + sizeof (struct FontAssoc));
+
+ for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
+ {
+ if (font_name_table_size == 0)
+ {
+ font_name_table_size = 16;
+ font_name_table = (char **)
+ xmalloc (font_name_table_size * sizeof (char *));
+ }
+ else if (font_name_count >= font_name_table_size)
+ {
+ font_name_table_size += 16;
+ font_name_table = (char **)
+ xrealloc (font_name_table,
+ font_name_table_size * sizeof (char *));
+ }
+ font_name_table[font_name_count++]
+ = mac_to_x_fontname (name,
+ assc_entry->fontSize,
+ assc_entry->fontStyle,
+ scriptcode);
+ /* Both jisx0208.1983-sjis and
+ jisx0201.1976-sjis parts are contained in
+ Apple Japanese (SJIS) font. */
+ if (smJapanese == scriptcode)
+ {
+ font_name_table[font_name_count++]
+ = mac_to_x_fontname (name,
+ assc_entry->fontSize,
+ assc_entry->fontStyle,
+ smRoman);
+ }
+ }
+ }
+
+ HUnlock (font_handle);
+ font_handle_2 = GetNextFOND (font_handle);
+ ReleaseResource (font_handle);
+ font_handle = font_handle_2;
+ }
+ while (ResError () == noErr && font_handle);
+ }
+
+ TextFont (old_fontnum);
+#if TARGET_API_MAC_CARBON
+ }
+#endif /* TARGET_API_MAC_CARBON */
+}
+
+
+/* Return a list of at most MAXNAMES font specs matching the one in
+ PATTERN. Note that each '*' in the PATTERN matches exactly one
+ field of the font spec, unlike X in which an '*' in a font spec can
+ match a number of fields. The result is in the Mac implementation
+ all fonts must be specified by a font spec with all 13 fields
+ (although many of these can be "*'s"). */
+
+Lisp_Object
+x_list_fonts (struct frame *f,
+ Lisp_Object pattern,
+ int size,
+ int maxnames)
+{
+ char *ptnstr;
+ Lisp_Object newlist = Qnil;
+ int n_fonts = 0;
+ int i;
+ struct gcpro gcpro1, gcpro2;
+
+ if (font_name_table == NULL) /* Initialize when first used. */
+ init_font_name_table ();
+
+ ptnstr = XSTRING (pattern)->data;
+
+ GCPRO2 (pattern, newlist);
+
+ /* Scan and matching bitmap fonts. */
+ for (i = 0; i < font_name_count; i++)
+ {
+ if (mac_font_pattern_match (font_name_table[i], ptnstr))
+ {
+ newlist = Fcons (build_string (font_name_table[i]), newlist);
+
+ n_fonts++;
+ if (n_fonts >= maxnames)
+ break;
+ }
+ }
+
+ /* MAC_TODO: add code for matching outline fonts here */
+
+ UNGCPRO;
+
+ return newlist;
+}
+
+
+#if GLYPH_DEBUG
+
+/* Check that FONT is valid on frame F. It is if it can be found in F's
+ font table. */
+
+static void
+x_check_font (f, font)
+ struct frame *f;
+ XFontStruct *font;
+{
+ int i;
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+ xassert (font != NULL);
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ if (dpyinfo->font_table[i].name
+ && font == dpyinfo->font_table[i].font)
+ break;
+
+ xassert (i < dpyinfo->n_fonts);
+}
+
+#endif /* GLYPH_DEBUG != 0 */
+
+/* Set *W to the minimum width, *H to the minimum font height of FONT.
+ Note: There are (broken) X fonts out there with invalid XFontStruct
+ min_bounds contents. For example, handa@etl.go.jp reports that
+ "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
+ have font->min_bounds.width == 0. */
+
+static INLINE void
+x_font_min_bounds (font, w, h)
+ MacFontStruct *font;
+ int *w, *h;
+{
+ /*
+ * TODO: Windows does not appear to offer min bound, only
+ * average and maximum width, and maximum height.
+ */
+ *h = FONT_HEIGHT (font);
+ *w = FONT_WIDTH (font);
+}
+
+
+/* Compute the smallest character width and smallest font height over
+ all fonts available on frame F. Set the members smallest_char_width
+ and smallest_font_height in F's x_display_info structure to
+ the values computed. Value is non-zero if smallest_font_height or
+ smallest_char_width become smaller than they were before. */
+
+int
+x_compute_min_glyph_bounds (f)
+ struct frame *f;
+{
+ int i;
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ MacFontStruct *font;
+ int old_width = dpyinfo->smallest_char_width;
+ int old_height = dpyinfo->smallest_font_height;
+
+ dpyinfo->smallest_font_height = 100000;
+ dpyinfo->smallest_char_width = 100000;
+
+ for (i = 0; i < dpyinfo->n_fonts; ++i)
+ if (dpyinfo->font_table[i].name)
+ {
+ struct font_info *fontp = dpyinfo->font_table + i;
+ int w, h;
+
+ font = (MacFontStruct *) fontp->font;
+ xassert (font != (MacFontStruct *) ~0);
+ x_font_min_bounds (font, &w, &h);
+
+ dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
+ dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
+ }
+
+ xassert (dpyinfo->smallest_char_width > 0
+ && dpyinfo->smallest_font_height > 0);
+
+ return (dpyinfo->n_fonts == 1
+ || dpyinfo->smallest_char_width < old_width
+ || dpyinfo->smallest_font_height < old_height);
+}
+
+
+/* Determine whether given string is a fully-specified XLFD: all 14
+ fields are present, none is '*'. */
+
+static int
+is_fully_specified_xlfd (char *p)
+{
+ int i;
+ char *q;
+
+ if (*p != '-')
+ return 0;
+
+ for (i = 0; i < 13; i++)
+ {
+ q = strchr (p + 1, '-');
+ if (q == NULL)
+ return 0;
+ if (q - p == 2 && *(p + 1) == '*')
+ return 0;
+ p = q;
+ }
+
+ if (strchr (p + 1, '-') != NULL)
+ return 0;
+
+ if (*(p + 1) == '*' && *(p + 2) == '\0')
+ return 0;
+
+ return 1;
+}
+
+
+const int kDefaultFontSize = 9;
+
+
+/* XLoadQueryFont creates and returns an internal representation for a
+ font in a MacFontStruct struct. There is really no concept
+ corresponding to "loading" a font on the Mac. But we check its
+ existence and find the font number and all other information for it
+ and store them in the returned MacFontStruct. */
+
+static MacFontStruct *
+XLoadQueryFont (Display *dpy, char *fontname)
+{
+ int i, size, is_two_byte_font, char_width;
+ char *name;
+ GrafPtr port;
+ SInt16 old_fontnum, old_fontsize;
+ Style old_fontface;
+ Str32 mfontname;
+ SInt16 fontnum;
+ Style fontface = normal;
+ MacFontStruct *font;
+ FontInfo the_fontinfo;
+ char s_weight[7], c_slant;
+
+ if (is_fully_specified_xlfd (fontname))
+ name = fontname;
+ else
+ {
+ for (i = 0; i < font_name_count; i++)
+ if (mac_font_pattern_match (font_name_table[i], fontname))
+ break;
+
+ if (i >= font_name_count)
+ return NULL;
+
+ name = font_name_table[i];
+ }
+
+ GetPort (&port); /* save the current font number used */
+#if TARGET_API_MAC_CARBON
+ old_fontnum = GetPortTextFont (port);
+ old_fontsize = GetPortTextSize (port);
+ old_fontface = GetPortTextFace (port);
+#else
+ old_fontnum = port->txFont;
+ old_fontsize = port->txSize;
+ old_fontface = port->txFace;
+#endif
+
+ if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%d-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &size) != 1)
+ size = kDefaultFontSize;
+
+ if (sscanf (name, "-%*[^-]-%*[^-]-%6[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", s_weight) == 1)
+ if (strcmp (s_weight, "bold") == 0)
+ fontface |= bold;
+
+ if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &c_slant) == 1)
+ if (c_slant == 'i')
+ fontface |= italic;
+
+ x_font_name_to_mac_font_name (name, mfontname);
+ c2pstr (mfontname);
+ GetFNum (mfontname, &fontnum);
+ if (fontnum == 0)
+ return NULL;
+
+ font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
+
+ font->fontname = (char *) xmalloc (strlen (name) + 1);
+ bcopy (name, font->fontname, strlen (name) + 1);
+
+ font->mac_fontnum = fontnum;
+ font->mac_fontsize = size;
+ font->mac_fontface = fontface;
+ font->mac_scriptcode = FontToScript (fontnum);
+
+ /* Apple Japanese (SJIS) font is listed as both
+ "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
+ (Roman script) in init_font_name_table (). The latter should be
+ treated as a one-byte font. */
+ {
+ char cs[32];
+
+ if (sscanf (name,
+ "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
+ cs) == 1
+ && 0 == strcmp (cs, "mac-roman"))
+ font->mac_scriptcode = smRoman;
+ }
+
+ is_two_byte_font = font->mac_scriptcode == smJapanese ||
+ font->mac_scriptcode == smTradChinese ||
+ font->mac_scriptcode == smSimpChinese ||
+ font->mac_scriptcode == smKorean;
+
+ TextFont (fontnum);
+ TextSize (size);
+ TextFace (fontface);
+
+ GetFontInfo (&the_fontinfo);
+
+ font->ascent = the_fontinfo.ascent;
+ font->descent = the_fontinfo.descent;
+
+ font->min_byte1 = 0;
+ if (is_two_byte_font)
+ font->max_byte1 = 1;
+ else
+ font->max_byte1 = 0;
+ font->min_char_or_byte2 = 0x20;
+ font->max_char_or_byte2 = 0xff;
+
+ if (is_two_byte_font)
+ {
+ /* Use the width of an "ideographic space" of that font because
+ the_fontinfo.widMax returns the wrong width for some fonts. */
+ switch (font->mac_scriptcode)
+ {
+ case smJapanese:
+ char_width = StringWidth("\p\x81\x40");
+ break;
+ case smTradChinese:
+ char_width = StringWidth("\p\xa1\x40");
+ break;
+ case smSimpChinese:
+ char_width = StringWidth("\p\xa1\xa1");
+ break;
+ case smKorean:
+ char_width = StringWidth("\p\xa1\xa1");
+ break;
+ }
+ }
+ else
+ /* Do this instead of use the_fontinfo.widMax, which incorrectly
+ returns 15 for 12-point Monaco! */
+ char_width = CharWidth ('m');
+
+ font->max_bounds.rbearing = char_width;
+ font->max_bounds.lbearing = 0;
+ font->max_bounds.width = char_width;
+ font->max_bounds.ascent = the_fontinfo.ascent;
+ font->max_bounds.descent = the_fontinfo.descent;
+
+ font->min_bounds = font->max_bounds;
+
+ if (is_two_byte_font || CharWidth ('m') == CharWidth ('i'))
+ font->per_char = NULL;
+ else
+ {
+ font->per_char = (XCharStruct *)
+ xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
+ {
+ int c;
+
+ for (c = 0x20; c <= 0xff; c++)
+ {
+ font->per_char[c - 0x20] = font->max_bounds;
+ font->per_char[c - 0x20].width = CharWidth (c);
+ }
+ }
+ }
+
+ TextFont (old_fontnum); /* restore previous font number, size and face */
+ TextSize (old_fontsize);
+ TextFace (old_fontface);
+
+ return font;
+}
+
+
+/* Load font named FONTNAME of the size SIZE for frame F, and return a
+ pointer to the structure font_info while allocating it dynamically.
+ If SIZE is 0, load any size of font.
+ If loading is failed, return NULL. */
+
+struct font_info *
+x_load_font (f, fontname, size)
+ struct frame *f;
+ register char *fontname;
+ int size;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ Lisp_Object font_names;
+
+ /* Get a list of all the fonts that match this name. Once we
+ have a list of matching fonts, we compare them against the fonts
+ we already have by comparing names. */
+ font_names = x_list_fonts (f, build_string (fontname), size, 1);
+
+ if (!NILP (font_names))
+ {
+ Lisp_Object tail;
+ int i;
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ for (tail = font_names; CONSP (tail); tail = XCDR (tail))
+ if (dpyinfo->font_table[i].name
+ && (!strcmp (dpyinfo->font_table[i].name,
+ XSTRING (XCAR (tail))->data)
+ || !strcmp (dpyinfo->font_table[i].full_name,
+ XSTRING (XCAR (tail))->data)))
+ return (dpyinfo->font_table + i);
+ }
+
+ /* Load the font and add it to the table. */
+ {
+ char *full_name;
+ struct MacFontStruct *font;
+ struct font_info *fontp;
+ unsigned long value;
+ int i;
+
+ /* If we have found fonts by x_list_font, load one of them. If
+ not, we still try to load a font by the name given as FONTNAME
+ because XListFonts (called in x_list_font) of some X server has
+ a bug of not finding a font even if the font surely exists and
+ is loadable by XLoadQueryFont. */
+ if (size > 0 && !NILP (font_names))
+ fontname = (char *) XSTRING (XCAR (font_names))->data;
+
+ font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname);
+ if (!font)
+ return NULL;
+
+ /* Find a free slot in the font table. */
+ for (i = 0; i < dpyinfo->n_fonts; ++i)
+ if (dpyinfo->font_table[i].name == NULL)
+ break;
+
+ /* If no free slot found, maybe enlarge the font table. */
+ if (i == dpyinfo->n_fonts
+ && dpyinfo->n_fonts == dpyinfo->font_table_size)
+ {
+ int sz;
+ dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
+ sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
+ dpyinfo->font_table
+ = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
+ }
+
+ fontp = dpyinfo->font_table + i;
+ if (i == dpyinfo->n_fonts)
+ ++dpyinfo->n_fonts;
+
+ /* Now fill in the slots of *FONTP. */
+ BLOCK_INPUT;
+ fontp->font = font;
+ fontp->font_idx = i;
+ fontp->name = (char *) xmalloc (strlen (font->fontname) + 1);
+ bcopy (font->fontname, fontp->name, strlen (font->fontname) + 1);
+
+ fontp->full_name = fontp->name;
+
+ fontp->size = font->max_bounds.width;
+ fontp->height = FONT_HEIGHT (font);
+ {
+ /* For some font, ascent and descent in max_bounds field is
+ larger than the above value. */
+ int max_height = font->max_bounds.ascent + font->max_bounds.descent;
+ if (max_height > fontp->height)
+ fontp->height = max_height;
+ }
+
+ /* The slot `encoding' specifies how to map a character
+ code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
+ the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
+ (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
+ 2:0xA020..0xFF7F). For the moment, we don't know which charset
+ uses this font. So, we set information in fontp->encoding[1]
+ which is never used by any charset. If mapping can't be
+ decided, set FONT_ENCODING_NOT_DECIDED. */
+ if (font->mac_scriptcode == smJapanese)
+ fontp->encoding[1] = 4;
+ else
+ {
+ fontp->encoding[1]
+ = (font->max_byte1 == 0
+ /* 1-byte font */
+ ? (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 0 /* 0x20..0x7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
+ : 1) /* 0xA0..0xFF */
+ /* 2-byte font */
+ : (font->min_byte1 < 0x80
+ ? (font->max_byte1 < 0x80
+ ? (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 0 /* 0x2020..0x7F7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
+ : 3) /* 0x20A0..0x7FFF */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
+ : (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 2 /* 0xA020..0xFF7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
+ : 1))); /* 0xA0A0..0xFFFF */
+ }
+
+#if 0 /* MAC_TODO: fill these out with more reasonably values */
+ fontp->baseline_offset
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
+ ? (long) value : 0);
+ fontp->relative_compose
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
+ ? (long) value : 0);
+ fontp->default_ascent
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
+ ? (long) value : 0);
+#else
+ fontp->baseline_offset = 0;
+ fontp->relative_compose = 0;
+ fontp->default_ascent = 0;
+#endif
+
+ /* Set global flag fonts_changed_p to non-zero if the font loaded
+ has a character with a smaller width than any other character
+ before, or if the font loaded has a smalle>r height than any
+ other font loaded before. If this happens, it will make a
+ glyph matrix reallocation necessary. */
+ fonts_changed_p = x_compute_min_glyph_bounds (f);
+ UNBLOCK_INPUT;
+ return fontp;
+ }
+}
+
+
+/* Return a pointer to struct font_info of a font named FONTNAME for
+ frame F. If no such font is loaded, return NULL. */
+
+struct font_info *
+x_query_font (f, fontname)
+ struct frame *f;
+ register char *fontname;
+{
+ struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
+ int i;
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ if (dpyinfo->font_table[i].name
+ && (!strcmp (dpyinfo->font_table[i].name, fontname)
+ || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
+ return (dpyinfo->font_table + i);
+ return NULL;
+}
+
+
+/* Find a CCL program for a font specified by FONTP, and set the member
+ `encoder' of the structure. */
+
+void
+x_find_ccl_program (fontp)
+ struct font_info *fontp;
+{
+ Lisp_Object list, elt;
+
+ for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
+ {
+ elt = XCAR (list);
+ if (CONSP (elt)
+ && STRINGP (XCAR (elt))
+ && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
+ >= 0))
+ break;
+ }
+ if (! NILP (list))
+ {
+ struct ccl_program *ccl
+ = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
+
+ if (setup_ccl_program (ccl, XCDR (elt)) < 0)
+ xfree (ccl);
+ else
+ fontp->font_encoder = ccl;
+ }
+}
+
+
+
+/***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+#ifdef USE_X_TOOLKIT
+static XrmOptionDescRec emacs_options[] = {
+ {"-geometry", ".geometry", XrmoptionSepArg, NULL},
+ {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
+
+ {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
+ XrmoptionSepArg, NULL},
+ {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
+
+ {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
+ {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
+ {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
+ {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
+};
+#endif /* USE_X_TOOLKIT */
+
+static int x_initialized;
+
+#ifdef MULTI_KBOARD
+/* Test whether two display-name strings agree up to the dot that separates
+ the screen number from the server number. */
+static int
+same_x_server (name1, name2)
+ char *name1, *name2;
+{
+ int seen_colon = 0;
+ unsigned char *system_name = XSTRING (Vsystem_name)->data;
+ int system_name_length = strlen (system_name);
+ int length_until_period = 0;
+
+ while (system_name[length_until_period] != 0
+ && system_name[length_until_period] != '.')
+ length_until_period++;
+
+ /* Treat `unix' like an empty host name. */
+ if (! strncmp (name1, "unix:", 5))
+ name1 += 4;
+ if (! strncmp (name2, "unix:", 5))
+ name2 += 4;
+ /* Treat this host's name like an empty host name. */
+ if (! strncmp (name1, system_name, system_name_length)
+ && name1[system_name_length] == ':')
+ name1 += system_name_length;
+ if (! strncmp (name2, system_name, system_name_length)
+ && name2[system_name_length] == ':')
+ name2 += system_name_length;
+ /* Treat this host's domainless name like an empty host name. */
+ if (! strncmp (name1, system_name, length_until_period)
+ && name1[length_until_period] == ':')
+ name1 += length_until_period;
+ if (! strncmp (name2, system_name, length_until_period)
+ && name2[length_until_period] == ':')
+ name2 += length_until_period;
+
+ for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
+ {
+ if (*name1 == ':')
+ seen_colon++;
+ if (seen_colon && *name1 == '.')
+ return 1;
+ }
+ return (seen_colon
+ && (*name1 == '.' || *name1 == '\0')
+ && (*name2 == '.' || *name2 == '\0'));
+}
+#endif
+
+
+/* The Mac Event loop code */
+
+#ifndef MAC_OSX
+#include <Events.h>
+#include <Quickdraw.h>
+#include <Balloons.h>
+#include <Devices.h>
+#include <Fonts.h>
+#include <Gestalt.h>
+#include <Menus.h>
+#include <Processes.h>
+#include <Sound.h>
+#include <ToolUtils.h>
+#include <TextUtils.h>
+#include <Dialogs.h>
+#include <Script.h>
+#include <Types.h>
+#include <TextEncodingConverter.h>
+#include <Resources.h>
+
+#if __MWERKS__
+#include <unix.h>
+#endif
+#endif /* ! MAC_OSX */
+
+#define M_APPLE 128
+#define I_ABOUT 1
+
+#define WINDOW_RESOURCE 128
+#define TERM_WINDOW_RESOURCE 129
+
+#define DEFAULT_NUM_COLS 80
+
+#define MIN_DOC_SIZE 64
+#define MAX_DOC_SIZE 32767
+
+/* sleep time for WaitNextEvent */
+#define WNE_SLEEP_AT_SUSPEND 10
+#define WNE_SLEEP_AT_RESUME 1
+
+/* true when cannot handle any Mac OS events */
+static int handling_window_update = 0;
+
+/* the flag appl_is_suspended is used both for determining the sleep
+ time to be passed to WaitNextEvent and whether the cursor should be
+ drawn when updating the display. The cursor is turned off when
+ Emacs is suspended. Redrawing it is unnecessary and what needs to
+ be done depends on whether the cursor lies inside or outside the
+ redraw region. So we might as well skip drawing it when Emacs is
+ suspended. */
+static Boolean app_is_suspended = false;
+static long app_sleep_time = WNE_SLEEP_AT_RESUME;
+
+#define EXTRA_STACK_ALLOC (256 * 1024)
+
+#define ARGV_STRING_LIST_ID 129
+#define ABOUT_ALERT_ID 128
+#define RAM_TOO_LARGE_ALERT_ID 129
+
+Boolean terminate_flag = false;
+
+/* true if using command key as meta key */
+Lisp_Object Vmac_command_key_is_meta;
+
+/* convert input from Mac keyboard (assumed to be in Mac Roman coding)
+ to this text encoding */
+int mac_keyboard_text_encoding;
+int current_mac_keyboard_text_encoding = kTextEncodingMacRoman;
+
+/* Set in term/mac-win.el to indicate that event loop can now generate
+ drag and drop events. */
+Lisp_Object Qmac_ready_for_drag_n_drop;
+
+Lisp_Object drag_and_drop_file_list;
+
+Point saved_menu_event_location;
+
+/* Apple Events */
+static void init_required_apple_events(void);
+static pascal OSErr
+do_ae_open_application(const AppleEvent *, AppleEvent *, long);
+static pascal OSErr
+do_ae_print_documents(const AppleEvent *, AppleEvent *, long);
+static pascal OSErr do_ae_open_documents(AppleEvent *, AppleEvent *, long);
+static pascal OSErr do_ae_quit_application(AppleEvent *, AppleEvent *, long);
+
+extern void init_emacs_passwd_dir ();
+extern int emacs_main (int, char **, char **);
+extern void check_alarm ();
+
+extern void initialize_applescript();
+extern void terminate_applescript();
+
+
+static void
+do_get_menus (void)
+{
+ Handle menubar_handle;
+ MenuHandle menu_handle;
+
+ menubar_handle = GetNewMBar (128);
+ if(menubar_handle == NULL)
+ abort ();
+ SetMenuBar (menubar_handle);
+ DrawMenuBar ();
+
+ menu_handle = GetMenuHandle (M_APPLE);
+ if(menu_handle != NULL)
+ AppendResMenu (menu_handle,'DRVR');
+ else
+ abort ();
+}
+
+
+static void
+do_init_managers (void)
+{
+#if !TARGET_API_MAC_CARBON
+ InitGraf (&qd.thePort);
+ InitFonts ();
+ FlushEvents (everyEvent, 0);
+ InitWindows ();
+ InitMenus ();
+ TEInit ();
+ InitDialogs (NULL);
+#endif /* !TARGET_API_MAC_CARBON */
+ InitCursor ();
+
+#if !TARGET_API_MAC_CARBON
+ /* set up some extra stack space for use by emacs */
+ SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
+
+ /* MaxApplZone must be called for AppleScript to execute more
+ complicated scripts */
+ MaxApplZone ();
+ MoreMasters ();
+#endif /* !TARGET_API_MAC_CARBON */
+}
+
+static void
+do_check_ram_size (void)
+{
+ SInt32 physical_ram_size, logical_ram_size;
+
+ if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
+ || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
+ || physical_ram_size > 256 * 1024 * 1024
+ || logical_ram_size > 256 * 1024 * 1024)
+ {
+ StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
+ exit (1);
+ }
+}
+
+static void
+do_window_update (WindowPtr win)
+{
+ struct mac_output *mwp = (mac_output *) GetWRefCon (win);
+ struct frame *f = mwp->mFP;
+
+ if (f)
+ {
+ if (f->async_visible == 0)
+ {
+ f->async_visible = 1;
+ f->async_iconified = 0;
+ SET_FRAME_GARBAGED (f);
+
+ /* An update event is equivalent to MapNotify on X, so report
+ visibility changes properly. */
+ if (! NILP(Vframe_list) && ! NILP (XCDR (Vframe_list)))
+ /* Force a redisplay sooner or later to update the
+ frame titles in case this is the second frame. */
+ record_asynch_buffer_change ();
+ }
+ else
+ {
+ BeginUpdate (win);
+ handling_window_update = 1;
+
+ expose_frame (f, 0, 0, 0, 0);
+
+ handling_window_update = 0;
+ EndUpdate (win);
+ }
+ }
+}
+
+static int
+is_emacs_window (WindowPtr win)
+{
+ Lisp_Object tail, frame;
+
+ if (!win)
+ return 0;
+
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_MAC_P (XFRAME (frame)))
+ if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
+ return 1;
+
+ return 0;
+}
+
+static void
+do_window_activate (WindowPtr win)
+{
+ mac_output *mwp;
+ struct frame *f;
+
+ if (is_emacs_window (win))
+ {
+ mwp = (mac_output *) GetWRefCon (win);
+ f = mwp->mFP;
+
+ if (f)
+ {
+ x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f);
+ activate_scroll_bars (f);
+ }
+ }
+}
+
+static void
+do_window_deactivate (WindowPtr win)
+{
+ mac_output *mwp;
+ struct frame *f;
+
+ if (is_emacs_window (win))
+ {
+ mwp = (mac_output *) GetWRefCon (win);
+ f = mwp->mFP;
+
+ if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
+ {
+ x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0);
+ deactivate_scroll_bars (f);
+ }
+ }
+}
+
+static void
+do_app_resume ()
+{
+ WindowPtr wp;
+ mac_output *mwp;
+ struct frame *f;
+
+ wp = FrontWindow();
+ if (is_emacs_window (wp))
+ {
+ mwp = (mac_output *) GetWRefCon (wp);
+ f = mwp->mFP;
+
+ if (f)
+ {
+ x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f);
+ activate_scroll_bars (f);
+ }
+ }
+
+ app_is_suspended = false;
+ app_sleep_time = WNE_SLEEP_AT_RESUME;
+}
+
+static void
+do_app_suspend ()
+{
+ WindowPtr wp;
+ mac_output *mwp;
+ struct frame *f;
+
+ wp = FrontWindow();
+ if (is_emacs_window (wp))
+ {
+ mwp = (mac_output *) GetWRefCon (wp);
+ f = mwp->mFP;
+
+ if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
+ {
+ x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0);
+ deactivate_scroll_bars (f);
+ }
+ }
+
+ app_is_suspended = true;
+ app_sleep_time = WNE_SLEEP_AT_SUSPEND;
+}
+
+
+static void
+do_mouse_moved (Point mouse_pos)
+{
+ WindowPtr wp = FrontWindow ();
+ struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (wp));
+#else
+ SetPort (wp);
+#endif
+
+ GlobalToLocal (&mouse_pos);
+
+ note_mouse_movement (f, &mouse_pos);
+}
+
+
+static void
+do_os_event (EventRecord *erp)
+{
+ switch((erp->message >> 24) & 0x000000FF)
+ {
+ case suspendResumeMessage:
+ if((erp->message & resumeFlag) == 1)
+ do_app_resume ();
+ else
+ do_app_suspend ();
+ break;
+
+ case mouseMovedMessage:
+ do_mouse_moved (erp->where);
+ break;
+ }
+}
+
+static void
+do_events (EventRecord *erp)
+{
+ switch (erp->what)
+ {
+ case updateEvt:
+ do_window_update ((WindowPtr) erp->message);
+ break;
+
+ case osEvt:
+ do_os_event (erp);
+ break;
+
+ case activateEvt:
+ if ((erp->modifiers & activeFlag) != 0)
+ do_window_activate ((WindowPtr) erp->message);
+ else
+ do_window_deactivate ((WindowPtr) erp->message);
+ break;
+ }
+}
+
+static void
+do_apple_menu (SInt16 menu_item)
+{
+#if !TARGET_API_MAC_CARBON
+ Str255 item_name;
+ SInt16 da_driver_refnum;
+
+ if (menu_item == I_ABOUT)
+ NoteAlert (ABOUT_ALERT_ID, NULL);
+ else
+ {
+ GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name);
+ da_driver_refnum = OpenDeskAcc (item_name);
+ }
+#endif /* !TARGET_API_MAC_CARBON */
+}
+
+void
+do_menu_choice (SInt32 menu_choice)
+{
+ SInt16 menu_id, menu_item;
+
+ menu_id = HiWord (menu_choice);
+ menu_item = LoWord (menu_choice);
+
+ if (menu_id == 0)
+ return;
+
+ switch (menu_id)
+ {
+ case M_APPLE:
+ do_apple_menu (menu_item);
+ break;
+
+ default:
+ {
+ WindowPtr wp = FrontWindow ();
+ struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
+ MenuHandle menu = GetMenuHandle (menu_id);
+ if (menu)
+ {
+ UInt32 refcon;
+
+ GetMenuItemRefCon (menu, menu_item, &refcon);
+ menubar_selection_callback (f, refcon);
+ }
+ }
+ }
+
+ HiliteMenu (0);
+}
+
+
+/* Handle drags in size box. Based on code contributed by Ben
+ Mesander and IM - Window Manager A. */
+
+static void
+do_grow_window (WindowPtr w, EventRecord *e)
+{
+ long grow_size;
+ Rect limit_rect;
+ int rows, columns;
+ mac_output *mwp = (mac_output *) GetWRefCon (w);
+ struct frame *f = mwp->mFP;
+
+ SetRect(&limit_rect, MIN_DOC_SIZE, MIN_DOC_SIZE, MAX_DOC_SIZE, MAX_DOC_SIZE);
+
+ grow_size = GrowWindow (w, e->where, &limit_rect);
+
+ /* see if it really changed size */
+ if (grow_size != 0)
+ {
+ rows = PIXEL_TO_CHAR_HEIGHT (f, HiWord (grow_size));
+ columns = PIXEL_TO_CHAR_WIDTH (f, LoWord (grow_size));
+
+ x_set_window_size (f, 0, columns, rows);
+ }
+}
+
+
+/* Handle clicks in zoom box. Calculation of "standard state" based
+ on code in IM - Window Manager A and code contributed by Ben
+ Mesander. The standard state of an Emacs window is 80-characters
+ wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
+
+static void
+do_zoom_window (WindowPtr w, int zoom_in_or_out)
+{
+ GrafPtr save_port;
+ Rect zoom_rect, port_rect;
+ Point top_left;
+ int w_title_height, columns, rows, width, height, dummy, x, y;
+ mac_output *mwp = (mac_output *) GetWRefCon (w);
+ struct frame *f = mwp->mFP;
+
+ GetPort (&save_port);
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (w));
+#else
+ SetPort (w);
+#endif
+
+ /* Clear window to avoid flicker. */
+#if TARGET_API_MAC_CARBON
+ {
+ Rect r;
+ BitMap bm;
+
+ GetWindowPortBounds (w, &r);
+ EraseRect (&r);
+
+ if (zoom_in_or_out == inZoomOut)
+ {
+ /* calculate height of window's title bar (hard card it for now). */
+ w_title_height = 20 + GetMBarHeight ();
+
+ /* get maximum height of window into zoom_rect.bottom -
+ zoom_rect.top */
+ GetQDGlobalsScreenBits (&bm);
+ zoom_rect = bm.bounds;
+ zoom_rect.top += w_title_height;
+ InsetRect (&zoom_rect, 8, 4); /* not too tight */
+
+ zoom_rect.right = zoom_rect.left
+ + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
+
+ SetWindowStandardState (w, &zoom_rect);
+ }
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ EraseRect (&(w->portRect));
+ if (zoom_in_or_out == inZoomOut)
+ {
+ SetPt (&top_left, w->portRect.left, w->portRect.top);
+ LocalToGlobal (&top_left);
+
+ /* calculate height of window's title bar */
+ w_title_height = top_left.v - 1
+ - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
+
+ /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
+ zoom_rect = qd.screenBits.bounds;
+ zoom_rect.top += w_title_height;
+ InsetRect (&zoom_rect, 8, 4); /* not too tight */
+
+ zoom_rect.right = zoom_rect.left
+ + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
+
+ (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
+ = zoom_rect;
+ }
+#endif /* not TARGET_API_MAC_CARBON */
+
+ ZoomWindow (w, zoom_in_or_out, w == FrontWindow ());
+
+ /* retrieve window size and update application values */
+#if TARGET_API_MAC_CARBON
+ GetWindowPortBounds (w, &port_rect);
+#else
+ port_rect = w->portRect;
+#endif
+ rows = PIXEL_TO_CHAR_HEIGHT (f, port_rect.bottom - port_rect.top);
+ columns = PIXEL_TO_CHAR_WIDTH (f, port_rect.right - port_rect.left);
+ x_set_window_size (mwp->mFP, 0, columns, rows);
+
+ SetPort (save_port);
+}
+
+
+/* Intialize AppleEvent dispatcher table for the required events. */
+void
+init_required_apple_events ()
+{
+ OSErr err;
+ long result;
+
+ /* Make sure we have apple events before starting. */
+ err = Gestalt (gestaltAppleEventsAttr, &result);
+ if (err != noErr)
+ abort ();
+
+ if (!(result & (1 << gestaltAppleEventsPresent)))
+ abort ();
+
+#if TARGET_API_MAC_CARBON
+ err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
+ NewAEEventHandlerUPP
+ ((AEEventHandlerProcPtr) do_ae_open_application),
+ 0L, false);
+#else
+ err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
+ NewAEEventHandlerProc
+ ((AEEventHandlerProcPtr) do_ae_open_application),
+ 0L, false);
+#endif
+ if (err != noErr)
+ abort ();
+
+#if TARGET_API_MAC_CARBON
+ err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
+ NewAEEventHandlerUPP
+ ((AEEventHandlerProcPtr) do_ae_open_documents),
+ 0L, false);
+#else
+ err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
+ NewAEEventHandlerProc
+ ((AEEventHandlerProcPtr) do_ae_open_documents),
+ 0L, false);
+#endif
+ if (err != noErr)
+ abort ();
+
+#if TARGET_API_MAC_CARBON
+ err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
+ NewAEEventHandlerUPP
+ ((AEEventHandlerProcPtr) do_ae_print_documents),
+ 0L, false);
+#else
+ err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
+ NewAEEventHandlerProc
+ ((AEEventHandlerProcPtr) do_ae_print_documents),
+ 0L, false);
+#endif
+ if (err != noErr)
+ abort ();
+
+#if TARGET_API_MAC_CARBON
+ err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP
+ ((AEEventHandlerProcPtr) do_ae_quit_application),
+ 0L, false);
+#else
+ err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerProc
+ ((AEEventHandlerProcPtr) do_ae_quit_application),
+ 0L, false);
+#endif
+ if (err != noErr)
+ abort ();
+}
+
+
+/* Open Application Apple Event */
+static pascal OSErr
+do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon)
+{
+ return noErr;
+}
+
+
+/* Defined in mac.c. */
+extern int
+path_from_vol_dir_name (char *, int, short, long, char *);
+
+
+/* Called when we receive an AppleEvent with an ID of
+ "kAEOpenDocuments". This routine gets the direct parameter,
+ extracts the FSSpecs in it, and puts their names on a list. */
+static pascal OSErr
+do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
+{
+ OSErr err, err2;
+ AEDesc the_desc;
+ AEKeyword keyword;
+ DescType actual_type;
+ Size actual_size;
+
+ err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc);
+ if (err != noErr)
+ goto descriptor_error_exit;
+
+ /* Check to see that we got all of the required parameters from the
+ event descriptor. For an 'odoc' event this should just be the
+ file list. */
+ err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
+ &actual_type, (Ptr) &keyword,
+ sizeof (keyword), &actual_size);
+ /* No error means that we found some unused parameters.
+ errAEDescNotFound means that there are no more parameters. If we
+ get an error code other than that, flag it. */
+ if ((err == noErr) || (err != errAEDescNotFound))
+ {
+ err = errAEEventNotHandled;
+ goto error_exit;
+ }
+ err = noErr;
+
+ /* Got all the parameters we need. Now, go through the direct
+ object list and parse it up. */
+ {
+ long num_files_to_open;
+
+ err = AECountItems (&the_desc, &num_files_to_open);
+ if (err == noErr)
+ {
+ int i;
+
+ /* AE file list is one based so just use that for indexing here. */
+ for (i = 1; (err == noErr) && (i <= num_files_to_open); i++) {
+ FSSpec fs;
+ Str255 path_name, unix_path_name;
+
+ err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type,
+ (Ptr) &fs, sizeof (fs), &actual_size);
+ if (err != noErr) break;
+
+ if (path_from_vol_dir_name (path_name, 255, fs.vRefNum, fs.parID,
+ fs.name) &&
+ mac_to_posix_pathname (path_name, unix_path_name, 255))
+ drag_and_drop_file_list = Fcons (build_string (unix_path_name),
+ drag_and_drop_file_list);
+ }
+ }
+ }
+
+error_exit:
+ /* Nuke the coerced file list in any case */
+ err2 = AEDisposeDesc(&the_desc);
+
+descriptor_error_exit:
+ /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */
+ return err;
+}
+
+
+/* Print Document Apple Event */
+static pascal OSErr
+do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon)
+{
+ return errAEEventNotHandled;
+}
+
+
+static pascal OSErr
+do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon)
+{
+ /* FixMe: Do we need an unwind-protect or something here? And what
+ do we do about unsaved files. Currently just forces quit rather
+ than doing recursive callback to get user input. */
+
+ terminate_flag = true;
+
+ /* Fkill_emacs doesn't return. We have to return. (TI) */
+ return noErr;
+}
+
+
+#if __profile__
+void
+profiler_exit_proc ()
+{
+ ProfilerDump ("\pEmacs.prof");
+ ProfilerTerm ();
+}
+#endif
+
+/* These few functions implement Emacs as a normal Mac application
+ (almost): set up the heap and the Toolbox, handle necessary
+ system events plus a few simple menu events. They also set up
+ Emacs's access to functions defined in the rest of this file.
+ Emacs uses function hooks to perform all its terminal I/O. A
+ complete list of these functions appear in termhooks.h. For what
+ they do, read the comments there and see also w32term.c and
+ xterm.c. What's noticeably missing here is the event loop, which
+ is normally present in most Mac application. After performing the
+ necessary Mac initializations, main passes off control to
+ emacs_main (corresponding to main in emacs.c). Emacs_main calls
+ mac_read_socket (defined further below) to read input. This is
+ where WaitNextEvent is called to process Mac events. This is also
+ where check_alarm in sysdep.c is called to simulate alarm signals.
+ This makes the cursor jump back to its correct position after
+ briefly jumping to that of the matching parenthesis, print useful
+ hints and prompts in the minibuffer after the user stops typing for
+ a wait, etc. */
+
+#if !TARGET_API_MAC_CARBON
+#undef main
+int
+main (void)
+{
+#if __profile__ /* is the profiler on? */
+ if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
+ exit(1);
+#endif
+
+#if __MWERKS__
+ /* set creator and type for files created by MSL */
+ _fcreator = 'EMAx';
+ _ftype = 'TEXT';
+#endif
+
+ do_init_managers ();
+
+ do_get_menus ();
+
+ do_check_ram_size ();
+
+ init_emacs_passwd_dir ();
+
+ init_environ ();
+
+ initialize_applescript ();
+
+ init_required_apple_events ();
+
+ {
+ char **argv;
+ int argc = 0;
+
+ /* set up argv array from STR# resource */
+ get_string_list (&argv, ARGV_STRING_LIST_ID);
+ while (argv[argc])
+ argc++;
+
+ /* free up AppleScript resources on exit */
+ atexit (terminate_applescript);
+
+#if __profile__ /* is the profiler on? */
+ atexit (profiler_exit_proc);
+#endif
+
+ /* 3rd param "envp" never used in emacs_main */
+ (void) emacs_main (argc, argv, 0);
+ }
+
+ /* Never reached - real exit in Fkill_emacs */
+ return 0;
+}
+#endif
+
+/* Table for translating Mac keycode to X keysym values. Contributed
+ by Sudhir Shenoy. */
+static unsigned char keycode_to_xkeysym_table[] = {
+/* 0x00 - 0x3f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 0x40 */
+ 0, '\xae' /* kp. */, 0, '\xaa' /* kp* */,
+ 0, '\xab' /* kp+ */, 0, '\x7f' /* kp_clr */,
+ 0, 0, 0, '\xaf' /* kp/ */,
+ '\x8d' /* kp_ent */, 0, '\xad' /* kp- */, 0,
+/* 0x50 */
+ 0, '\xbd' /* kp= */, '\xb0' /* kp0 */, '\xb1' /* kp1 */,
+ '\xb2' /* kp2 */, '\xb3' /* kp3 */, '\xb4' /* kp4 */, '\xb5' /* kp5 */,
+ '\xb6' /* kp6 */, '\xb7' /* kp7 */, 0, '\xb8' /* kp8 */,
+ '\xb9' /* kp9 */, 0, 0, 0,
+/* 0x60 */
+ '\xc2' /* F5 */, '\xc3' /* F6 */, '\xc4' /* F7 */, '\xc0' /* F3 */,
+ '\xc5' /* F8 */, '\xc6' /* F9 */, 0, '\xc8' /* F11 */,
+ 0, '\xca' /* F13 */, 0, '\xcb' /* F14 */,
+ 0, '\xc7' /* F10 */, 0, '\xc9' /* F12 */,
+/* 0x70 */
+ 0, '\xcc' /* F15 */, '\x9e' /* ins */, '\x95' /* home */,
+ '\x9a' /* pgup */, '\x9f' /* del */, '\xc1' /* F4 */, '\x9c' /* end */,
+ '\xbf' /* F2 */, '\x9b' /* pgdown */, '\xbe' /* F1 */, '\x51' /* left */,
+ '\x53' /* right */, '\x54' /* down */, '\x52' /* up */, 0
+};
+
+static int
+keycode_to_xkeysym (int keyCode, int *xKeySym)
+{
+ *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f];
+ return *xKeySym != 0;
+}
+
+/* Emacs calls this whenever it wants to read an input event from the
+ user. */
+int
+XTread_socket (int sd, struct input_event *bufp, int numchars, int expected)
+{
+ int count = 0;
+ EventRecord er;
+ int the_modifiers;
+ EventMask event_mask;
+
+#if 0
+ if (interrupt_input_blocked)
+ {
+ interrupt_input_pending = 1;
+ return -1;
+ }
+#endif
+
+ interrupt_input_pending = 0;
+ BLOCK_INPUT;
+
+ /* So people can tell when we have read the available input. */
+ input_signal_count++;
+
+ if (numchars <= 0)
+ abort ();
+
+ /* Don't poll for events to process (specifically updateEvt) if
+ window update currently already in progress. A call to redisplay
+ (in do_window_update) can be preempted by another call to
+ redisplay, causing blank regions to be left on the screen and the
+ cursor to be left at strange places. */
+ if (handling_window_update)
+ {
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ if (terminate_flag)
+ Fkill_emacs (make_number (1));
+
+ /* It is necessary to set this (additional) argument slot of an
+ event to nil because keyboard.c protects incompletely processed
+ event from being garbage collected by placing them in the
+ kbd_buffer_gcpro vector. */
+ bufp->arg = Qnil;
+
+ event_mask = everyEvent;
+ if (NILP (Fboundp (Qmac_ready_for_drag_n_drop)))
+ event_mask -= highLevelEventMask;
+
+ while (WaitNextEvent (event_mask, &er, 0L, NULL) && numchars > 0)
+ switch (er.what)
+ {
+ case mouseDown:
+ case mouseUp:
+ {
+ WindowPtr window_ptr = FrontWindow ();
+ SInt16 part_code;
+
+ if (mouse_tracking_in_progress == mouse_tracking_scroll_bar
+ && er.what == mouseUp)
+ {
+ struct mac_output *mwp = (mac_output *) GetWRefCon (window_ptr);
+ Point mouse_loc = er.where;
+
+ /* Convert to local coordinates of new window. */
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (window_ptr));
+#else
+ SetPort (window_ptr);
+#endif
+
+ GlobalToLocal (&mouse_loc);
+
+ bufp->code = 0; /* only one mouse button */
+ bufp->kind = scroll_bar_click;
+ bufp->frame_or_window = tracked_scroll_bar->window;
+ bufp->part = scroll_bar_handle;
+ bufp->modifiers = up_modifier;
+ bufp->timestamp = er.when * (1000 / 60);
+ /* ticks to milliseconds */
+
+ XSETINT (bufp->x, tracked_scroll_bar->left + 2);
+ XSETINT (bufp->y, mouse_loc.v - 24);
+ tracked_scroll_bar->dragging = Qnil;
+ mouse_tracking_in_progress = mouse_tracking_none;
+ tracked_scroll_bar = NULL;
+ count++;
+ bufp++;
+ numchars--;
+ break;
+ }
+
+ part_code = FindWindow (er.where, &window_ptr);
+
+ switch (part_code)
+ {
+ case inMenuBar:
+ {
+ struct frame *f = ((mac_output *)
+ GetWRefCon (FrontWindow ()))->mFP;
+ saved_menu_event_location = er.where;
+ bufp->kind = menu_bar_activate_event;
+ XSETFRAME (bufp->frame_or_window, f);
+ count++;
+ bufp++;
+ numchars--;
+ }
+ break;
+
+ case inContent:
+ if (window_ptr != FrontWindow ())
+ SelectWindow (window_ptr);
+ else
+ {
+ SInt16 control_part_code;
+ ControlHandle ch;
+ struct mac_output *mwp = (mac_output *)
+ GetWRefCon (window_ptr);
+ Point mouse_loc = er.where;
+
+ /* convert to local coordinates of new window */
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (window_ptr));
+#else
+ SetPort (window_ptr);
+#endif
+
+ GlobalToLocal (&mouse_loc);
+#if TARGET_API_MAC_CARBON
+ ch = FindControlUnderMouse (mouse_loc, window_ptr,
+ &control_part_code);
+#else
+ control_part_code = FindControl (mouse_loc, window_ptr, &ch);
+#endif
+ bufp->code = 0; /* only one mouse button */
+ XSETINT (bufp->x, mouse_loc.h);
+ XSETINT (bufp->y, mouse_loc.v);
+ bufp->timestamp = er.when * (1000 / 60);
+ /* ticks to milliseconds */
+
+#if TARGET_API_MAC_CARBON
+ if (ch != 0)
+#else
+ if (control_part_code != 0)
+#endif
+ {
+ struct scroll_bar *bar = (struct scroll_bar *)
+ GetControlReference (ch);
+ x_scroll_bar_handle_click (bar, control_part_code, &er,
+ bufp);
+ if (er.what == mouseDown
+ && control_part_code == kControlIndicatorPart)
+ {
+ mouse_tracking_in_progress
+ = mouse_tracking_scroll_bar;
+ tracked_scroll_bar = bar;
+ }
+ else
+ {
+ mouse_tracking_in_progress = mouse_tracking_none;
+ tracked_scroll_bar = NULL;
+ }
+ }
+ else
+ {
+ bufp->kind = mouse_click;
+ XSETFRAME (bufp->frame_or_window, mwp->mFP);
+ if (er.what == mouseDown)
+ mouse_tracking_in_progress
+ = mouse_tracking_mouse_movement;
+ else
+ mouse_tracking_in_progress = mouse_tracking_none;
+ }
+
+ switch (er.what)
+ {
+ case mouseDown:
+ bufp->modifiers = down_modifier;
+ break;
+ case mouseUp:
+ bufp->modifiers = up_modifier;
+ break;
+ }
+
+ count++;
+ bufp++;
+ numchars--;
+ }
+ break;
+
+ case inDrag:
+#if TARGET_API_MAC_CARBON
+ {
+ BitMap bm;
+
+ GetQDGlobalsScreenBits (&bm);
+ DragWindow (window_ptr, er.where, &bm.bounds);
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
+#endif /* not TARGET_API_MAC_CARBON */
+ break;
+
+ case inGoAway:
+ if (TrackGoAway (window_ptr, er.where))
+ {
+ bufp->kind = delete_window_event;
+ XSETFRAME (bufp->frame_or_window,
+ ((mac_output *) GetWRefCon (window_ptr))->mFP);
+ count++;
+ bufp++;
+ numchars--;
+ }
+ break;
+
+ /* window resize handling added --ben */
+ case inGrow:
+ do_grow_window(window_ptr, &er);
+ break;
+
+ /* window zoom handling added --ben */
+ case inZoomIn:
+ case inZoomOut:
+ if (TrackBox (window_ptr, er.where, part_code))
+ do_zoom_window (window_ptr, part_code);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case updateEvt:
+ case osEvt:
+ case activateEvt:
+ do_events (&er);
+ break;
+
+ case keyDown:
+ case autoKey:
+ {
+ int keycode = (er.message & keyCodeMask) >> 8;
+ int xkeysym;
+
+ ObscureCursor ();
+
+ if (keycode == 0x33) /* delete key (charCode translated to 0x8) */
+ {
+ bufp->code = 0x7f;
+ bufp->kind = ascii_keystroke;
+ }
+ else if (keycode_to_xkeysym (keycode, &xkeysym))
+ {
+ bufp->code = 0xff00 | xkeysym;
+ bufp->kind = non_ascii_keystroke;
+ }
+ else
+ {
+ if (er.modifiers
+ & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey))
+ {
+ /* This code comes from Keyboard Resource, Appendix
+ C of IM - Text. This is necessary since shift is
+ ignored in KCHR table translation when option or
+ command is pressed. */
+ int new_modifiers = er.modifiers & 0xf600;
+ /* mask off option and command */
+ int new_keycode = keycode | new_modifiers;
+ Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
+ unsigned long some_state = 0;
+ bufp->code = KeyTranslate (kchr_ptr, new_keycode,
+ &some_state) & 0xff;
+ }
+ else
+ bufp->code = er.message & charCodeMask;
+ bufp->kind = ascii_keystroke;
+ }
+ }
+
+ /* If variable mac-convert-keyboard-input-to-latin-1 is non-nil,
+ convert non-ASCII characters typed at the Mac keyboard
+ (presumed to be in the Mac Roman encoding) to iso-latin-1
+ encoding before they are passed to Emacs. This enables the
+ Mac keyboard to be used to enter non-ASCII iso-latin-1
+ characters directly. */
+ if (mac_keyboard_text_encoding != kTextEncodingMacRoman
+ && bufp->kind == ascii_keystroke && bufp->code >= 128)
+ {
+ static TECObjectRef converter = NULL;
+ OSStatus the_err = noErr;
+ OSStatus convert_status = noErr;
+
+ if (converter == NULL)
+ {
+ the_err = TECCreateConverter (&converter,
+ kTextEncodingMacRoman,
+ mac_keyboard_text_encoding);
+ current_mac_keyboard_text_encoding
+ = mac_keyboard_text_encoding;
+ }
+ else if (mac_keyboard_text_encoding
+ != current_mac_keyboard_text_encoding)
+ {
+ /* Free the converter for the current encoding before
+ creating a new one. */
+ TECDisposeConverter (converter);
+ the_err = TECCreateConverter (&converter,
+ kTextEncodingMacRoman,
+ mac_keyboard_text_encoding);
+ current_mac_keyboard_text_encoding
+ = mac_keyboard_text_encoding;
+ }
+
+ if (the_err == noErr)
+ {
+ unsigned char ch = bufp->code;
+ ByteCount actual_input_length, actual_output_length;
+ unsigned char outch;
+
+ convert_status = TECConvertText (converter, &ch, 1,
+ &actual_input_length,
+ &outch, 1,
+ &actual_output_length);
+ if (convert_status == noErr
+ && actual_input_length == 1
+ && actual_output_length == 1)
+ bufp->code = outch;
+ }
+ }
+
+ the_modifiers = 0;
+ if (er.modifiers & shiftKey)
+ the_modifiers |= shift_modifier;
+ if (er.modifiers & controlKey)
+ the_modifiers |= ctrl_modifier;
+ /* use option or command key as meta depending on value of
+ mac-command-key-is-meta */
+ if (er.modifiers
+ & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey))
+ the_modifiers |= meta_modifier;
+ bufp->modifiers = the_modifiers;
+
+ {
+ mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
+ XSETFRAME (bufp->frame_or_window, mwp->mFP);
+ }
+
+ bufp->timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
+
+ count++;
+ bufp++;
+ numchars--;
+ break;
+
+ case kHighLevelEvent:
+ drag_and_drop_file_list = Qnil;
+
+ AEProcessAppleEvent(&er);
+
+ /* Build a drag_n_drop type event as is done in
+ constuct_drag_n_drop in w32term.c. */
+ if (!NILP (drag_and_drop_file_list))
+ {
+ struct frame *f;
+ WindowPtr wp;
+ Lisp_Object frame;
+
+ wp = FrontWindow ();
+ if (!wp)
+ f = NULL;
+ else
+ f = ((mac_output *) GetWRefCon (wp))->mFP;
+
+ bufp->kind = drag_n_drop;
+ bufp->code = 0;
+ bufp->timestamp = er.when * (1000 / 60);
+ /* ticks to milliseconds */
+ bufp->modifiers = 0;
+
+ XSETINT (bufp->x, 0);
+ XSETINT (bufp->y, 0);
+
+ XSETFRAME (frame, f);
+ bufp->frame_or_window = Fcons (frame, drag_and_drop_file_list);
+
+ /* Regardless of whether Emacs was suspended or in the
+ foreground, ask it to redraw its entire screen.
+ Otherwise parts of the screen can be left in an
+ inconsistent state. */
+ if (wp)
+#if TARGET_API_MAC_CARBON
+ {
+ Rect r;
+
+ GetWindowPortBounds (wp, &r);
+ InvalWindowRect (wp, &r);
+ }
+#else /* not TARGET_API_MAC_CARBON */
+ InvalRect (&(wp->portRect));
+#endif /* not TARGET_API_MAC_CARBON */
+
+ count++;
+ bufp++;
+ numchars--;
+ }
+
+ default:
+ break;
+ }
+
+ /* If the focus was just given to an autoraising frame,
+ raise it now. */
+ /* ??? This ought to be able to handle more than one such frame. */
+ if (pending_autoraise_frame)
+ {
+ x_raise_frame (pending_autoraise_frame);
+ pending_autoraise_frame = 0;
+ }
+
+#if !TARGET_API_MAC_CARBON
+ check_alarm (); /* simulate the handling of a SIGALRM */
+#endif
+
+ {
+ static Point old_mouse_pos = { -1, -1 };
+
+ if (app_is_suspended)
+ {
+ old_mouse_pos.h = -1;
+ old_mouse_pos.v = -1;
+ }
+ else
+ {
+ Point mouse_pos;
+ WindowPtr wp;
+ struct frame *f;
+ Lisp_Object bar;
+ struct scroll_bar *sb;
+
+ wp = FrontWindow ();
+ if (is_emacs_window (wp))
+ {
+ f = ((mac_output *) GetWRefCon (wp))->mFP;
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (wp));
+#else
+ SetPort (wp);
+#endif
+
+ GetMouse (&mouse_pos);
+
+ if (!EqualPt (mouse_pos, old_mouse_pos))
+ {
+ if (mouse_tracking_in_progress == mouse_tracking_scroll_bar
+ && tracked_scroll_bar)
+ x_scroll_bar_note_movement (tracked_scroll_bar,
+ mouse_pos.v
+ - XINT (tracked_scroll_bar->top),
+ TickCount() * (1000 / 60));
+ else
+ note_mouse_movement (f, &mouse_pos);
+
+ old_mouse_pos = mouse_pos;
+ }
+ }
+ }
+ }
+
+ UNBLOCK_INPUT;
+
+ return count;
+}
+
+
+/* Need to override CodeWarrior's input function so no conversion is
+ done on newlines Otherwise compiled functions in .elc files will be
+ read incorrectly. Defined in ...:MSL C:MSL
+ Common:Source:buffer_io.c. */
+#ifdef __MWERKS__
+void
+__convert_to_newlines (unsigned char * p, size_t * n)
+{
+#pragma unused(p,n)
+}
+
+void
+__convert_from_newlines (unsigned char * p, size_t * n)
+{
+#pragma unused(p,n)
+}
+#endif
+
+
+/* Initialize the struct pointed to by MW to represent a new COLS x
+ ROWS Macintosh window, using font with name FONTNAME and size
+ FONTSIZE. */
+void
+NewMacWindow (FRAME_PTR fp)
+{
+ mac_output *mwp;
+#if TARGET_API_MAC_CARBON
+ static int making_terminal_window = 0;
+#else
+ static int making_terminal_window = 1;
+#endif
+
+ mwp = fp->output_data.mac;
+
+ if (making_terminal_window)
+ {
+ if (!(mwp->mWP = GetNewCWindow (TERM_WINDOW_RESOURCE, NULL,
+ (WindowPtr) -1)))
+ abort ();
+ making_terminal_window = 0;
+ }
+ else
+ if (!(mwp->mWP = GetNewCWindow (WINDOW_RESOURCE, NULL, (WindowPtr) -1)))
+ abort ();
+
+
+ SetWRefCon (mwp->mWP, (long) mwp);
+ /* so that update events can find this mac_output struct */
+ mwp->mFP = fp; /* point back to emacs frame */
+
+#if TARGET_API_MAC_CARBON
+ SetPort (GetWindowPort (mwp->mWP));
+#else
+ SetPort (mwp->mWP);
+#endif
+
+ mwp->fontset = -1;
+
+ SizeWindow (mwp->mWP, mwp->pixel_width, mwp->pixel_height, false);
+ ShowWindow (mwp->mWP);
+
+}
+
+
+void make_mac_frame (struct frame *f)
+{
+ FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
+ FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
+
+ NewMacWindow(f);
+ FRAME_BACKGROUND_PIXEL (f) = 0xffffff;
+ FRAME_FOREGROUND_PIXEL (f) = 0;
+
+ f->output_data.mac->cursor_pixel = 0;
+ f->output_data.mac->border_pixel = 0x00ff00;
+ f->output_data.mac->mouse_pixel = 0xff00ff;
+ f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
+
+ f->output_data.mac->desired_cursor = FILLED_BOX_CURSOR;
+
+ f->output_data.mac->fontset = -1;
+ f->output_data.mac->scroll_bar_foreground_pixel = -1;
+ f->output_data.mac->scroll_bar_background_pixel = -1;
+ f->output_data.mac->left_pos = 4;
+ f->output_data.mac->top_pos = 4;
+ f->output_data.mac->border_width = 0;
+ f->output_data.mac->explicit_parent = 0;
+
+ f->output_data.mac->internal_border_width = 0;
+
+ f->output_method = output_mac;
+
+ f->auto_raise = 1;
+ f->auto_lower = 1;
+
+ f->new_width = 0;
+ f->new_height = 0;
+}
+
+void make_mac_terminal_frame (struct frame *f)
+{
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+
+ f->output_method = output_mac;
+ f->output_data.mac = (struct mac_output *)
+ xmalloc (sizeof (struct mac_output));
+ bzero (f->output_data.mac, sizeof (struct mac_output));
+ f->output_data.mac->fontset = -1;
+ f->output_data.mac->scroll_bar_foreground_pixel = -1;
+ f->output_data.mac->scroll_bar_background_pixel = -1;
+
+ XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
+
+ f->width = 96;
+ f->height = 4;
+
+ make_mac_frame (f);
+
+ x_make_gc (f);
+
+ /* Need to be initialized for unshow_buffer in window.c. */
+ selected_window = f->selected_window;
+
+ Fmodify_frame_parameters (frame,
+ Fcons (Fcons (Qfont,
+ build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
+ Fmodify_frame_parameters (frame,
+ Fcons (Fcons (Qforeground_color,
+ build_string ("black")), Qnil));
+ Fmodify_frame_parameters (frame,
+ Fcons (Fcons (Qbackground_color,
+ build_string ("white")), Qnil));
+}
+
+
+/***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+#ifdef USE_X_TOOLKIT
+static XrmOptionDescRec emacs_options[] = {
+ {"-geometry", ".geometry", XrmoptionSepArg, NULL},
+ {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
+
+ {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
+ XrmoptionSepArg, NULL},
+ {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
+
+ {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
+ {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
+ {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
+ {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
+};
+#endif /* USE_X_TOOLKIT */
+
+#ifdef MULTI_KBOARD
+/* Test whether two display-name strings agree up to the dot that separates
+ the screen number from the server number. */
+static int
+same_x_server (name1, name2)
+ char *name1, *name2;
+{
+ int seen_colon = 0;
+ unsigned char *system_name = XSTRING (Vsystem_name)->data;
+ int system_name_length = strlen (system_name);
+ int length_until_period = 0;
+
+ while (system_name[length_until_period] != 0
+ && system_name[length_until_period] != '.')
+ length_until_period++;
+
+ /* Treat `unix' like an empty host name. */
+ if (! strncmp (name1, "unix:", 5))
+ name1 += 4;
+ if (! strncmp (name2, "unix:", 5))
+ name2 += 4;
+ /* Treat this host's name like an empty host name. */
+ if (! strncmp (name1, system_name, system_name_length)
+ && name1[system_name_length] == ':')
+ name1 += system_name_length;
+ if (! strncmp (name2, system_name, system_name_length)
+ && name2[system_name_length] == ':')
+ name2 += system_name_length;
+ /* Treat this host's domainless name like an empty host name. */
+ if (! strncmp (name1, system_name, length_until_period)
+ && name1[length_until_period] == ':')
+ name1 += length_until_period;
+ if (! strncmp (name2, system_name, length_until_period)
+ && name2[length_until_period] == ':')
+ name2 += length_until_period;
+
+ for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
+ {
+ if (*name1 == ':')
+ seen_colon++;
+ if (seen_colon && *name1 == '.')
+ return 1;
+ }
+ return (seen_colon
+ && (*name1 == '.' || *name1 == '\0')
+ && (*name2 == '.' || *name2 == '\0'));
+}
+#endif
+
+int mac_initialized = 0;
+
+void
+mac_initialize_display_info ()
+{
+ struct mac_display_info *dpyinfo = &one_mac_display_info;
+ GDHandle main_device_handle;
+
+ bzero (dpyinfo, sizeof (*dpyinfo));
+
+ /* Put it on x_display_name_list. */
+ x_display_name_list = Fcons (Fcons (build_string ("Mac"), Qnil),
+ x_display_name_list);
+ dpyinfo->name_list_element = XCAR (x_display_name_list);
+
+#if 0
+ dpyinfo->mac_id_name
+ = (char *) xmalloc (XSTRING (Vinvocation_name)->size
+ + XSTRING (Vsystem_name)->size
+ + 2);
+ sprintf (dpyinfo->mac_id_name, "%s@%s",
+ XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
+#else
+ dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1);
+ strcpy (dpyinfo->mac_id_name, "Mac Display");
+#endif
+
+ main_device_handle = LMGetMainDevice();
+
+ dpyinfo->reference_count = 0;
+ dpyinfo->resx = 75.0;
+ dpyinfo->resy = 75.0;
+ dpyinfo->n_planes = 1;
+ dpyinfo->n_cbits = 16;
+ dpyinfo->height = (**main_device_handle).gdRect.bottom;
+ dpyinfo->width = (**main_device_handle).gdRect.right;
+ dpyinfo->grabbed = 0;
+ dpyinfo->root_window = NULL;
+
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
+ dpyinfo->mouse_face_window = Qnil;
+}
+
+struct mac_display_info *
+mac_term_init (display_name, xrm_option, resource_name)
+ Lisp_Object display_name;
+ char *xrm_option;
+ char *resource_name;
+{
+ struct mac_display_info *dpyinfo;
+ GDHandle main_device_handle;
+
+ if (!mac_initialized)
+ {
+ mac_initialize ();
+ mac_initialized = 1;
+ }
+
+ mac_initialize_display_info (display_name);
+
+ dpyinfo = &one_mac_display_info;
+
+ main_device_handle = LMGetMainDevice();
+
+ dpyinfo->height = (**main_device_handle).gdRect.bottom;
+ dpyinfo->width = (**main_device_handle).gdRect.right;
+
+ return dpyinfo;
+}
+
+/* Set up use of X before we make the first connection. */
+
+static struct redisplay_interface x_redisplay_interface =
+{
+ x_produce_glyphs,
+ x_write_glyphs,
+ x_insert_glyphs,
+ x_clear_end_of_line,
+ x_scroll_run,
+ x_after_update_window_line,
+ x_update_window_begin,
+ x_update_window_end,
+ XTcursor_to,
+ x_flush,
+ x_clear_mouse_face,
+ x_get_glyph_overhangs,
+ x_fix_overlapping_area
+};
+
+void
+mac_initialize ()
+{
+ rif = &x_redisplay_interface;
+
+ clear_frame_hook = x_clear_frame;
+ ins_del_lines_hook = x_ins_del_lines;
+ delete_glyphs_hook = x_delete_glyphs;
+ ring_bell_hook = XTring_bell;
+ reset_terminal_modes_hook = XTreset_terminal_modes;
+ set_terminal_modes_hook = XTset_terminal_modes;
+ update_begin_hook = x_update_begin;
+ update_end_hook = x_update_end;
+ set_terminal_window_hook = XTset_terminal_window;
+ read_socket_hook = XTread_socket;
+ frame_up_to_date_hook = XTframe_up_to_date;
+ mouse_position_hook = XTmouse_position;
+ frame_rehighlight_hook = XTframe_rehighlight;
+ frame_raise_lower_hook = XTframe_raise_lower;
+
+ set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
+ condemn_scroll_bars_hook = XTcondemn_scroll_bars;
+ redeem_scroll_bar_hook = XTredeem_scroll_bar;
+ judge_scroll_bars_hook = XTjudge_scroll_bars;
+
+ estimate_mode_line_height_hook = x_estimate_mode_line_height;
+
+ scroll_region_ok = 1; /* we'll scroll partial frames */
+ char_ins_del_ok = 1;
+ line_ins_del_ok = 1; /* we'll just blt 'em */
+ fast_clear_end_of_line = 1; /* X does this well */
+ memory_below_frame = 0; /* we don't remember what scrolls
+ off the bottom */
+ baud_rate = 19200;
+
+ x_noop_count = 0;
+ last_tool_bar_item = -1;
+ any_help_event_p = 0;
+
+ /* Try to use interrupt input; if we can't, then start polling. */
+ Fset_input_mode (Qt, Qnil, Qt, Qnil);
+
+#ifdef USE_X_TOOLKIT
+ XtToolkitInitialize ();
+ Xt_app_con = XtCreateApplicationContext ();
+ XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
+
+ /* Install an asynchronous timer that processes Xt timeout events
+ every 0.1s. This is necessary because some widget sets use
+ timeouts internally, for example the LessTif menu bar, or the
+ Xaw3d scroll bar. When Xt timouts aren't processed, these
+ widgets don't behave normally. */
+ {
+ EMACS_TIME interval;
+ EMACS_SET_SECS_USECS (interval, 0, 100000);
+ start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
+ }
+#endif
+
+#if USE_TOOLKIT_SCROLL_BARS
+ xaw3d_arrow_scroll = False;
+ xaw3d_pick_top = True;
+#endif
+
+#if 0
+ /* Note that there is no real way portable across R3/R4 to get the
+ original error handler. */
+ XSetErrorHandler (x_error_handler);
+ XSetIOErrorHandler (x_io_error_quitter);
+
+ /* Disable Window Change signals; they are handled by X events. */
+#ifdef SIGWINCH
+ signal (SIGWINCH, SIG_DFL);
+#endif /* ! defined (SIGWINCH) */
+
+ signal (SIGPIPE, x_connection_signal);
+#endif
+
+ mac_initialize_display_info ();
+}
+
+
+void
+syms_of_macterm ()
+{
+#if 0
+ staticpro (&x_error_message_string);
+ x_error_message_string = Qnil;
+#endif
+
+ staticpro (&x_display_name_list);
+ x_display_name_list = Qnil;
+
+ staticpro (&last_mouse_scroll_bar);
+ last_mouse_scroll_bar = Qnil;
+
+ staticpro (&Qvendor_specific_keysyms);
+ Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
+
+ staticpro (&last_mouse_press_frame);
+ last_mouse_press_frame = Qnil;
+
+ Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop");
+ staticpro (&Qmac_ready_for_drag_n_drop);
+
+ help_echo = Qnil;
+ staticpro (&help_echo);
+ help_echo_object = Qnil;
+ staticpro (&help_echo_object);
+ help_echo_window = Qnil;
+ staticpro (&help_echo_window);
+ previous_help_echo = Qnil;
+ staticpro (&previous_help_echo);
+ help_echo_pos = -1;
+
+ DEFVAR_BOOL ("x-autoselect-window", &x_autoselect_window_p,
+ doc: /* *Non-nil means autoselect window with mouse pointer. */);
+ x_autoselect_window_p = 0;
+
+ DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
+ doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
+For example, if a block cursor is over a tab, it will be drawn as
+wide as that tab on the display. */);
+ x_stretch_cursor_p = 0;
+
+#if 0 /* TODO: Setting underline position from font properties. */
+ DEFVAR_BOOL ("x-use-underline-position-properties",
+ &x_use_underline_position_properties,
+ doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
+nil means ignore them. If you encounter fonts with bogus
+UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
+to 4.1, set this to nil. */);
+ x_use_underline_position_properties = 1;
+#endif
+
+ DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
+ doc: /* If not nil, Emacs uses toolkit scroll bars. */);
+ Vx_toolkit_scroll_bars = Qt;
+
+ staticpro (&last_mouse_motion_frame);
+ last_mouse_motion_frame = Qnil;
+
+ DEFVAR_LISP ("mac-command-key-is-meta", &Vmac_command_key_is_meta,
+ doc: /* Non-nil means that the command key is used as the Emacs meta key.
+Otherwise the option key is used. */);
+ Vmac_command_key_is_meta = Qt;
+
+ DEFVAR_INT ("mac-keyboard-text-encoding", &mac_keyboard_text_encoding,
+ doc: /* One of the Text Encoding Base constant values defined in the
+Basic Text Constants section of Inside Macintosh - Text Encoding
+Conversion Manager. Its value determines the encoding characters
+typed at the Mac keyboard (presumed to be in the MacRoman encoding)
+will convert into. E.g., if it is set to kTextEncodingMacRoman (0),
+its default value, no conversion takes place. If it is set to
+kTextEncodingISOLatin1 (0x201) or kTextEncodingISOLatin2 (0x202),
+characters typed on Mac keyboard are first converted into the
+ISO Latin-1 or ISO Latin-2 encoding, respectively before being
+passed to Emacs. Together with Emacs's set-keyboard-coding-system
+command, this enables the Mac keyboard to be used to enter non-ASCII
+characters directly. */);
+ mac_keyboard_text_encoding = kTextEncodingMacRoman;
+}
diff --git a/src/macterm.h b/src/macterm.h
new file mode 100644
index 00000000000..578a6ec2a4f
--- /dev/null
+++ b/src/macterm.h
@@ -0,0 +1,670 @@
+/* Display module for Mac OS.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+#include "macgui.h"
+#include "frame.h"
+
+/* The class of this X application. */
+#define EMACS_CLASS "Emacs"
+
+#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
+
+#define RED_FROM_ULONG(color) ((color) >> 16)
+#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
+#define BLUE_FROM_ULONG(color) ((color) & 0xff)
+
+#define BLACK_PIX_DEFAULT(f) RGB_TO_ULONG(0,0,0)
+#define WHITE_PIX_DEFAULT(f) RGB_TO_ULONG(255,255,255)
+
+#define FONT_WIDTH(f) ((f)->max_bounds.width)
+#define FONT_HEIGHT(f) ((f)->ascent + (f)->descent)
+#define FONT_BASE(f) ((f)->ascent)
+#define FONT_DESCENT(f) ((f)->descent)
+
+#define FONT_MAX_WIDTH(f) FONT_WIDTH(f) /* fix later */
+
+enum text_cursor_kinds {
+ NO_CURSOR = -1,
+ FILLED_BOX_CURSOR,
+ HOLLOW_BOX_CURSOR,
+ BAR_CURSOR
+};
+
+/* Structure recording bitmaps and reference count.
+ If REFCOUNT is 0 then this record is free to be reused. */
+
+struct mac_bitmap_record
+{
+ char *bitmap_data;
+ int refcount;
+ int height, width;
+};
+
+
+/* For each display (currently only one on mac), we have a structure that
+ records information about it. */
+
+struct mac_display_info
+{
+ /* Chain of all mac_display_info structures. */
+ struct mac_display_info *next;
+
+ /* This is a cons cell of the form (NAME . FONT-LIST-CACHE).
+ The same cons cell also appears in x_display_name_list. */
+ Lisp_Object name_list_element;
+
+ /* Number of frames that are on this display. */
+ int reference_count;
+
+ /* Dots per inch of the screen. */
+ double resx, resy;
+
+ /* Number of planes on this screen. */
+ int n_planes;
+
+ /* Number of bits per pixel on this screen. */
+ int n_cbits;
+
+ /* Dimensions of this screen. */
+ int height, width;
+#if 0
+ int height_in,width_in;
+#endif
+
+ /* Mask of things that cause the mouse to be grabbed. */
+ int grabbed;
+
+#if 0
+ /* Emacs bitmap-id of the default icon bitmap for this frame.
+ Or -1 if none has been allocated yet. */
+ int icon_bitmap_id;
+
+#endif
+ /* The root window of this screen. */
+ Window root_window;
+
+ /* The cursor to use for vertical scroll bars. */
+ struct Cursor *vertical_scroll_bar_cursor;
+
+#if 0
+ /* color palette information. */
+ int has_palette;
+ struct w32_palette_entry * color_list;
+ unsigned num_colors;
+ HPALETTE palette;
+
+ /* deferred action flags checked when starting frame update. */
+ int regen_palette;
+
+ /* Keystroke that has been faked by Emacs and will be ignored when
+ received; value is reset after key is received. */
+ int faked_key;
+
+#endif
+
+ /* A table of all the fonts we have already loaded. */
+ struct font_info *font_table;
+
+ /* The current capacity of font_table. */
+ int font_table_size;
+
+ /* The number of fonts actually stored in the font table.
+ font_table[n] is used and valid iff 0 <= n < n_fonts. 0 <=
+ n_fonts <= font_table_size. and font_table[i].name != 0. */
+ int n_fonts;
+
+ /* Minimum width over all characters in all fonts in font_table. */
+ int smallest_char_width;
+
+ /* Minimum font height over all fonts in font_table. */
+ int smallest_font_height;
+
+ /* Reusable Graphics Context for drawing a cursor in a non-default face. */
+ XGCValues *scratch_cursor_gc;
+
+ /* These variables describe the range of text currently shown in its
+ mouse-face, together with the window they apply to. As long as
+ the mouse stays within this range, we need not redraw anything on
+ its account. Rows and columns are glyph matrix positions in
+ MOUSE_FACE_WINDOW. */
+ int mouse_face_beg_row, mouse_face_beg_col;
+ int mouse_face_beg_x, mouse_face_beg_y;
+ int mouse_face_end_row, mouse_face_end_col;
+ int mouse_face_end_x, mouse_face_end_y;
+ int mouse_face_past_end;
+ Lisp_Object mouse_face_window;
+ int mouse_face_face_id;
+ Lisp_Object mouse_face_overlay;
+
+ /* 1 if a mouse motion event came and we didn't handle it right away because
+ gc was in progress. */
+ int mouse_face_deferred_gc;
+
+ /* FRAME and X, Y position of mouse when last checked for
+ highlighting. X and Y can be negative or out of range for the frame. */
+ struct frame *mouse_face_mouse_frame;
+
+ int mouse_face_mouse_x, mouse_face_mouse_y;
+
+ /* Nonzero means defer mouse-motion highlighting. */
+ int mouse_face_defer;
+
+ /* Nonzero means that the mouse highlight should not be shown. */
+ int mouse_face_hidden;
+
+ int mouse_face_image_state;
+
+ char *mac_id_name;
+
+ /* Pointer to bitmap records. */
+ struct mac_bitmap_record *bitmaps;
+
+ /* Allocated size of bitmaps field. */
+ int bitmaps_size;
+
+ /* Last used bitmap index. */
+ int bitmaps_last;
+
+ /* The frame (if any) which has the window that has keyboard focus.
+ Zero if none. This is examined by Ffocus_frame in w32fns.c. Note
+ that a mere EnterNotify event can set this; if you need to know the
+ last frame specified in a FocusIn or FocusOut event, use
+ w32_focus_event_frame. */
+ struct frame *x_focus_frame;
+
+ /* The last frame mentioned in a FocusIn or FocusOut event. This is
+ separate from w32_focus_frame, because whether or not LeaveNotify
+ events cause us to lose focus depends on whether or not we have
+ received a FocusIn event for it. */
+ struct frame *x_focus_event_frame;
+
+ /* The frame which currently has the visual highlight, and should get
+ keyboard input (other sorts of input have the frame encoded in the
+ event). It points to the focus frame's selected window's
+ frame. It differs from w32_focus_frame when we're using a global
+ minibuffer. */
+ struct frame *x_highlight_frame;
+
+ /* Cache of images. */
+ struct image_cache *image_cache;
+};
+
+#define x_display_info mac_display_info
+
+/* This is a chain of structures for all the X displays currently in use. */
+extern struct x_display_info *x_display_list;
+
+/* This is a chain of structures for all the displays currently in use. */
+extern struct mac_display_info one_mac_display_info;
+
+/* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
+ one for each element of x_display_list and in the same order.
+ NAME is the name of the frame.
+ FONT-LIST-CACHE records previous values returned by x-list-fonts. */
+extern Lisp_Object x_display_name_list;
+
+/* A flag to control how to display unibyte 8-bit character. */
+extern int unibyte_display_via_language_environment;
+
+extern struct x_display_info *x_display_info_for_display P_ ((Display *));
+extern struct x_display_info *x_display_info_for_name P_ ((Lisp_Object));
+
+extern struct mac_display_info *mac_term_init ();
+
+/* When Emacs uses a tty window, tty_display in frame.c points to an
+ x_output struct . */
+struct x_output
+{
+ unsigned long background_pixel;
+ unsigned long foreground_pixel;
+};
+
+/* The collection of data describing a window on the Mac. */
+struct mac_output {
+ /* Placeholder for things accessed through output_data.x. Must
+ appear first. */
+ struct x_output x_compatible;
+
+ /* Menubar "widget" handle. */
+ int menubar_widget;
+
+ Window mWP; /* pointer to QuickDraw window */
+ FRAME_PTR mFP; /* points back to the frame struct */
+
+#if 0
+ int mNumCols; /* number of characters per column */
+ int mNumRows; /* number of characters per row */
+ int mLineHeight; /* height of one line of text in pixels */
+ int mCharWidth; /* width of one character in pixels */
+ int mHomeX; /* X pixel coordinate of lower left
+ corner of character at (0, 0) */
+ int mHomeY; /* Y pixel coordinate of lower left
+ corner of character at (0, 0) */
+ int mHighlight; /* current highlight state (0 = off). */
+ int mTermWinSize; /* num of lines from top of window
+ affected by ins_del_lines; set by
+ set_terminal_window. */
+#endif /* 0 */
+
+#if 0
+ /* stuffs used by xfaces.c */
+ struct face **param_faces;
+ int n_param_faces;
+ struct face **computed_faces;
+ int n_computed_faces;
+ int size_computed_faces;
+#endif
+
+ /* Position of the Mac window (x and y offsets in global coordinates). */
+ int left_pos;
+ int top_pos;
+
+ /* Border width of the W32 window as known by the window system. */
+ int border_width;
+
+ /* Size of the W32 window in pixels. */
+ int pixel_height, pixel_width;
+
+ /* Height of a line, in pixels. */
+ int line_height;
+
+ /* Here are the Graphics Contexts for the default font. */
+ GC normal_gc; /* Normal video */
+ GC reverse_gc; /* Reverse video */
+ GC cursor_gc; /* cursor drawing */
+
+ /* Width of the internal border. This is a line of background color
+ just inside the window's border. When the frame is selected,
+ a highlighting is displayed inside the internal border. */
+ int internal_border_width;
+
+ /* The window used for this frame.
+ May be zero while the frame object is being created
+ and the window has not yet been created. */
+ Window window_desc;
+
+ /* The window that is the parent of this window.
+ Usually this is a window that was made by the window manager,
+ but it can be the root window, and it can be explicitly specified
+ (see the explicit_parent field, below). */
+ Window parent_desc;
+
+ /* Default ASCII font of this frame. */
+ XFontStruct *font;
+
+ /* The baseline offset of the default ASCII font. */
+ int baseline_offset;
+
+ /* If a fontset is specified for this frame instead of font, this
+ value contains an ID of the fontset, else -1. */
+ int fontset;
+
+ /* Pixel values used for various purposes.
+ border_pixel may be -1 meaning use a gray tile. */
+ unsigned long cursor_pixel;
+ unsigned long border_pixel;
+ unsigned long mouse_pixel;
+ unsigned long cursor_foreground_pixel;
+
+ /* Foreground color for scroll bars. A value of -1 means use the
+ default (black for non-toolkit scroll bars). */
+ unsigned long scroll_bar_foreground_pixel;
+
+ /* Background color for scroll bars. A value of -1 means use the
+ default (background color of the frame for non-toolkit scroll
+ bars). */
+ unsigned long scroll_bar_background_pixel;
+
+ /* Descriptor for the cursor in use for this window. */
+ struct Cursor *text_cursor;
+ struct Cursor *nontext_cursor;
+ struct Cursor *modeline_cursor;
+ struct Cursor *cross_cursor;
+ struct Cursor *hourglass_cursor;
+#if 0
+ /* Window whose cursor is hourglass_cursor. This window is temporarily
+ mapped to display a hourglass-cursor. */
+ Window hourglass_window;
+
+ /* Non-zero means hourglass cursor is currently displayed. */
+ unsigned hourglass_p : 1;
+
+ /* Flag to set when the window needs to be completely repainted. */
+ int needs_exposure;
+
+#endif
+
+ /* What kind of text cursor is drawn in this window right now?
+ (If there is no cursor (phys_cursor_x < 0), then this means nothing.) */
+ enum text_cursor_kinds current_cursor;
+
+ /* What kind of text cursor should we draw in the future?
+ This should always be filled_box_cursor or bar_cursor. */
+ enum text_cursor_kinds desired_cursor;
+
+ /* Width of bar cursor (if we are using that). */
+ int cursor_width;
+
+#if 0
+ DWORD dwStyle;
+#endif
+
+ /* The size of the extra width currently allotted for vertical
+ scroll bars, in pixels. */
+ int vertical_scroll_bar_extra;
+
+ /* The extra width currently allotted for the areas in which
+ truncation marks, continuation marks, and overlay arrows are
+ displayed. */
+ int left_fringe_width, right_fringe_width;
+ int fringe_cols, fringes_extra;
+
+ /* This is the gravity value for the specified window position. */
+ int win_gravity;
+
+ /* The geometry flags for this window. */
+ int size_hint_flags;
+
+ /* This is the Emacs structure for the display this frame is on. */
+ /* struct w32_display_info *display_info; */
+
+ /* Nonzero means our parent is another application's window
+ and was explicitly specified. */
+ char explicit_parent;
+
+ /* Nonzero means tried already to make this frame visible. */
+ char asked_for_visible;
+
+ /* Nonzero means menubar is currently active. */
+ char menubar_active;
+
+ /* Nonzero means a menu command is being processed. */
+ char menu_command_in_progress;
+
+ /* Nonzero means menubar is about to become active, but should be
+ brought up to date first. */
+ volatile char pending_menu_activation;
+
+ /* Relief GCs, colors etc. */
+ struct relief
+ {
+ XGCValues *gc;
+ unsigned long pixel;
+ int allocated_p;
+ }
+ black_relief, white_relief;
+
+ /* The background for which the above relief GCs were set up.
+ They are changed only when a different background is involved. */
+ unsigned long relief_background;
+};
+
+typedef struct mac_output mac_output;
+
+/* Return the Mac window used for displaying data in frame F. */
+#define FRAME_MAC_WINDOW(f) ((f)->output_data.mac->mWP)
+
+#define FRAME_FOREGROUND_PIXEL(f) ((f)->output_data.x->foreground_pixel)
+#define FRAME_BACKGROUND_PIXEL(f) ((f)->output_data.x->background_pixel)
+
+#define FRAME_FONT(f) ((f)->output_data.mac->font)
+#define FRAME_FONTSET(f) ((f)->output_data.mac->fontset)
+
+#undef FRAME_INTERNAL_BORDER_WIDTH
+#define FRAME_INTERNAL_BORDER_WIDTH(f) \
+ ((f)->output_data.mac->internal_border_width)
+#define FRAME_LINE_HEIGHT(f) ((f)->output_data.mac->line_height)
+/* Width of the default font of frame F. Must be defined by each
+ terminal specific header. */
+#define FRAME_DEFAULT_FONT_WIDTH(F) FONT_WIDTH (FRAME_FONT (F))
+#define FRAME_BASELINE_OFFSET(f) ((f)->output_data.mac->baseline_offset)
+
+/* This gives the w32_display_info structure for the display F is on. */
+#define FRAME_MAC_DISPLAY_INFO(f) (&one_mac_display_info)
+#define FRAME_X_DISPLAY_INFO(f) (&one_mac_display_info)
+
+/* This is the `Display *' which frame F is on. */
+#define FRAME_MAC_DISPLAY(f) (0)
+
+/* This is the 'font_info *' which frame F has. */
+#define FRAME_MAC_FONT_TABLE(f) (FRAME_MAC_DISPLAY_INFO (f)->font_table)
+
+/* These two really ought to be called FRAME_PIXEL_{WIDTH,HEIGHT}. */
+#define PIXEL_WIDTH(f) ((f)->output_data.mac->pixel_width)
+#define PIXEL_HEIGHT(f) ((f)->output_data.mac->pixel_height)
+
+#define FRAME_DESIRED_CURSOR(f) ((f)->output_data.mac->desired_cursor)
+
+/* Value is the smallest width of any character in any font on frame F. */
+
+#define FRAME_SMALLEST_CHAR_WIDTH(F) \
+ FRAME_MAC_DISPLAY_INFO(F)->smallest_char_width
+
+/* Value is the smallest height of any font on frame F. */
+
+#define FRAME_SMALLEST_FONT_HEIGHT(F) \
+ FRAME_MAC_DISPLAY_INFO(F)->smallest_font_height
+
+/* Return a pointer to the image cache of frame F. */
+
+#define FRAME_X_IMAGE_CACHE(F) FRAME_MAC_DISPLAY_INFO ((F))->image_cache
+
+
+/* Total width of fringes reserved for drawing truncation bitmaps,
+ continuation bitmaps and alike. The width is in canonical char
+ units of the frame. This must currently be the case because window
+ sizes aren't pixel values. If it weren't the case, we wouldn't be
+ able to split windows horizontally nicely. */
+
+#define FRAME_X_FRINGE_COLS(F) ((F)->output_data.mac->fringe_cols)
+
+/* Total width of fringes in pixels. */
+
+#define FRAME_X_FRINGE_WIDTH(F) ((F)->output_data.mac->fringes_extra)
+
+/* Pixel-width of the left and right fringe. */
+
+#define FRAME_X_LEFT_FRINGE_WIDTH(F) ((F)->output_data.mac->left_fringe_width)
+#define FRAME_X_RIGHT_FRINGE_WIDTH(F) ((F)->output_data.mac->right_fringe_width)
+
+
+
+/* Mac-specific scroll bar stuff. */
+
+/* We represent scroll bars as lisp vectors. This allows us to place
+ references to them in windows without worrying about whether we'll
+ end up with windows referring to dead scroll bars; the garbage
+ collector will free it when its time comes.
+
+ We use struct scroll_bar as a template for accessing fields of the
+ vector. */
+
+struct scroll_bar {
+
+ /* These fields are shared by all vectors. */
+ EMACS_INT size_from_Lisp_Vector_struct;
+ struct Lisp_Vector *next_from_Lisp_Vector_struct;
+
+ /* The window we're a scroll bar for. */
+ Lisp_Object window;
+
+ /* The next and previous in the chain of scroll bars in this frame. */
+ Lisp_Object next, prev;
+
+ /* The Mac control handle of this scroll bar. Since this is a full
+ 32-bit quantity, we store it split into two 32-bit values. */
+ Lisp_Object control_handle_low, control_handle_high;
+
+ /* The position and size of the scroll bar in pixels, relative to the
+ frame. */
+ Lisp_Object top, left, width, height;
+
+ /* The starting and ending positions of the handle, relative to the
+ handle area (i.e. zero is the top position, not
+ SCROLL_BAR_TOP_BORDER). If they're equal, that means the handle
+ hasn't been drawn yet.
+
+ These are not actually the locations where the beginning and end
+ are drawn; in order to keep handles from becoming invisible when
+ editing large files, we establish a minimum height by always
+ drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
+ where they would be normally; the bottom and top are in a
+ different co-ordinate system. */
+ Lisp_Object start, end;
+
+ /* If the scroll bar handle is currently being dragged by the user,
+ this is the number of pixels from the top of the handle to the
+ place where the user grabbed it. If the handle isn't currently
+ being dragged, this is Qnil. */
+ Lisp_Object dragging;
+};
+
+/* The number of elements a vector holding a struct scroll_bar needs. */
+#define SCROLL_BAR_VEC_SIZE \
+ ((sizeof (struct scroll_bar) \
+ - sizeof (EMACS_INT) - sizeof (struct Lisp_Vector *)) \
+ / sizeof (Lisp_Object))
+
+/* Turning a lisp vector value into a pointer to a struct scroll_bar. */
+#define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
+
+
+/* Building a 32-bit C integer from two 16-bit lisp integers. */
+#define SCROLL_BAR_PACK(low, high) (XINT (high) << 16 | XINT (low))
+
+/* Setting two lisp integers to the low and high words of a 32-bit C int. */
+#define SCROLL_BAR_UNPACK(low, high, int32) \
+ (XSETINT ((low), (int32) & 0xffff), \
+ XSETINT ((high), ((int32) >> 16) & 0xffff))
+
+
+/* Extract the Mac control handle of the scroll bar from a struct
+ scroll_bar. */
+#define SCROLL_BAR_CONTROL_HANDLE(ptr) \
+ ((ControlHandle) SCROLL_BAR_PACK ((ptr)->control_handle_low, \
+ (ptr)->control_handle_high))
+
+/* Store a Mac control handle in a struct scroll_bar. */
+#define SET_SCROLL_BAR_CONTROL_HANDLE(ptr, id) \
+ (SCROLL_BAR_UNPACK ((ptr)->control_handle_low, \
+ (ptr)->control_handle_high, (int) id))
+
+/* Return the inside width of a vertical scroll bar, given the outside
+ width. */
+#define VERTICAL_SCROLL_BAR_INSIDE_WIDTH(f,width) \
+ ((width) \
+ - VERTICAL_SCROLL_BAR_LEFT_BORDER \
+ - VERTICAL_SCROLL_BAR_RIGHT_BORDER \
+ - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2)
+
+/* Return the length of the rectangle within which the top of the
+ handle must stay. This isn't equivalent to the inside height,
+ because the scroll bar handle has a minimum height.
+
+ This is the real range of motion for the scroll bar, so when we're
+ scaling buffer positions to scroll bar positions, we use this, not
+ VERTICAL_SCROLL_BAR_INSIDE_HEIGHT. */
+#define VERTICAL_SCROLL_BAR_TOP_RANGE(f,height) \
+ (VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, height) \
+ - VERTICAL_SCROLL_BAR_MIN_HANDLE - UP_AND_DOWN_ARROWS)
+
+/* Return the inside height of vertical scroll bar, given the outside
+ height. See VERTICAL_SCROLL_BAR_TOP_RANGE too. */
+#define VERTICAL_SCROLL_BAR_INSIDE_HEIGHT(f,height) \
+ ((height) - VERTICAL_SCROLL_BAR_TOP_BORDER \
+ - VERTICAL_SCROLL_BAR_BOTTOM_BORDER)
+
+
+/* Border widths for scroll bars.
+
+ Scroll bar windows don't have any borders; their border width is
+ set to zero, and we redraw borders ourselves. This makes the code
+ a bit cleaner, since we don't have to convert between outside width
+ (used when relating to the rest of the screen) and inside width
+ (used when sizing and drawing the scroll bar window itself).
+
+ The handle moves up and down/back and forth in a rectangle inset
+ from the edges of the scroll bar. These are widths by which we
+ inset the handle boundaries from the scroll bar edges. */
+#define VERTICAL_SCROLL_BAR_LEFT_BORDER (0)
+#define VERTICAL_SCROLL_BAR_RIGHT_BORDER (0)
+#define VERTICAL_SCROLL_BAR_TOP_BORDER (0)
+#define VERTICAL_SCROLL_BAR_BOTTOM_BORDER (0)
+
+/* Minimum lengths for scroll bar handles, in pixels. */
+#define VERTICAL_SCROLL_BAR_MIN_HANDLE (16)
+
+/* Combined length of up and down arrow boxes in scroll bars, in pixels. */
+#define UP_AND_DOWN_ARROWS (32)
+
+/* Trimming off a few pixels from each side prevents
+ text from glomming up against the scroll bar */
+#define VERTICAL_SCROLL_BAR_WIDTH_TRIM (0)
+
+
+/* Manipulating pixel sizes and character sizes.
+ Knowledge of which factors affect the overall size of the window should
+ be hidden in these macros, if that's possible.
+
+ Return the upper/left pixel position of the character cell on frame F
+ at ROW/COL. */
+#define CHAR_TO_PIXEL_ROW(f, row) \
+ ((f)->output_data.mac->internal_border_width \
+ + (row) * (f)->output_data.mac->line_height)
+#define CHAR_TO_PIXEL_COL(f, col) \
+ ((f)->output_data.mac->internal_border_width \
+ + (col) * FONT_WIDTH ((f)->output_data.mac->font))
+
+/* Return the pixel width/height of frame F if it has
+ WIDTH columns/HEIGHT rows. */
+#define CHAR_TO_PIXEL_WIDTH(f, width) \
+ (CHAR_TO_PIXEL_COL (f, width) \
+ + (f)->output_data.mac->vertical_scroll_bar_extra \
+ + (f)->output_data.mac->fringes_extra \
+ + (f)->output_data.mac->internal_border_width)
+#define CHAR_TO_PIXEL_HEIGHT(f, height) \
+ (CHAR_TO_PIXEL_ROW (f, height) \
+ + (f)->output_data.mac->internal_border_width)
+
+
+/* Return the row/column (zero-based) of the character cell containing
+ the pixel on FRAME at ROW/COL. */
+#define PIXEL_TO_CHAR_ROW(f, row) \
+ (((row) - (f)->output_data.mac->internal_border_width) \
+ / (f)->output_data.mac->line_height)
+#define PIXEL_TO_CHAR_COL(f, col) \
+ (((col) - (f)->output_data.mac->internal_border_width) \
+ / FONT_WIDTH ((f)->output_data.mac->font))
+
+/* How many columns/rows of text can we fit in WIDTH/HEIGHT pixels on
+ frame F? */
+#define PIXEL_TO_CHAR_WIDTH(f, width) \
+ (PIXEL_TO_CHAR_COL (f, ((width) \
+ - (f)->output_data.mac->internal_border_width \
+ - (f)->output_data.mac->fringes_extra \
+ - (f)->output_data.mac->vertical_scroll_bar_extra)))
+#define PIXEL_TO_CHAR_HEIGHT(f, height) \
+ (PIXEL_TO_CHAR_ROW (f, ((height) \
+ - (f)->output_data.mac->internal_border_width)))
+
+struct frame * check_x_frame (Lisp_Object);
+
diff --git a/src/process.c b/src/process.c
index 06e931af9b6..a62b13c3f38 100644
--- a/src/process.c
+++ b/src/process.c
@@ -137,6 +137,11 @@ extern Lisp_Object QCfamily, QCfilter;
/* Qexit is declared and initialized in eval.c. */
+/* QCfamily is defined in xfaces.c. */
+extern Lisp_Object QCfamily;
+/* QCfilter is defined in keyboard.c. */
+extern Lisp_Object QCfilter;
+
/* a process object is a network connection when its childp field is neither
Qt nor Qnil but is instead a cons cell (HOSTNAME PORTNUM). */
@@ -3750,6 +3755,14 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
SELECT_TYPE Atemp, Ctemp;
Atemp = input_wait_mask;
+#ifdef MAC_OSX
+ /* On Mac OS X, the SELECT system call always says input is
+ present (for reading) at stdin, even when none is. This
+ causes the the call to SELECT below to return 1 and
+ status_notify not to be called. As a result output of
+ subprocesses are incorrectly discarded. */
+ FD_CLR (0, &Atemp);
+#endif
Ctemp = connect_wait_mask;
EMACS_SET_SECS_USECS (timeout, 0, 0);
if ((select (max (max_process_desc, max_keyboard_desc) + 1,
diff --git a/src/s/darwin.h b/src/s/darwin.h
new file mode 100644
index 00000000000..214b55b4429
--- /dev/null
+++ b/src/s/darwin.h
@@ -0,0 +1,291 @@
+/* System description header file for Darwin (Mac OS X).
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/*
+ * Define symbols to identify the version of Unix this is.
+ * Define all the symbols that apply correctly.
+ */
+
+/* #define UNIPLUS */
+/* #define USG5 */
+/* #define USG */
+/* #define HPUX */
+/* #define UMAX */
+/* #define BSD4_1 */
+#define BSD4_2
+/* BSD4_3 and BSD4_4 are already defined in sys/param.h */
+/* #define BSD4_3 */
+/* #define BSD4_4 */
+#define BSD_SYSTEM
+/* #define VMS */
+
+/* MAC_OS is used to conditionally compile code common to both MAC_OS8
+ and MAC_OSX. */
+#ifdef MAC_OSX
+#define MAC_OS
+#endif
+
+/* SYSTEM_TYPE should indicate the kind of system you are using.
+ It sets the Lisp variable system-type. */
+
+#define SYSTEM_TYPE "darwin"
+
+/* NOMULTIPLEJOBS should be defined if your system's shell
+ does not have "job control" (the ability to stop a program,
+ run some other program, then continue the first one). */
+
+/* #define NOMULTIPLEJOBS */
+
+/* Emacs can read input using SIGIO and buffering characters itself,
+ or using CBREAK mode and making C-g cause SIGINT.
+ The choice is controlled by the variable interrupt_input.
+
+ Define INTERRUPT_INPUT to make interrupt_input = 1 the default (use SIGIO)
+
+ Emacs uses the presence or absence of the SIGIO and BROKEN_SIGIO macros
+ to indicate whether or not signal-driven I/O is possible. It uses
+ INTERRUPT_INPUT to decide whether to use it by default.
+
+ SIGIO can be used only on systems that implement it (4.2 and 4.3).
+ CBREAK mode has two disadvantages
+ 1) At least in 4.2, it is impossible to handle the Meta key properly.
+ I hear that in system V this problem does not exist.
+ 2) Control-G causes output to be discarded.
+ I do not know whether this can be fixed in system V.
+
+ Another method of doing input is planned but not implemented.
+ It would have Emacs fork off a separate process
+ to read the input and send it to the true Emacs process
+ through a pipe. */
+
+#define INTERRUPT_INPUT
+
+/* Letter to use in finding device name of first pty,
+ if system supports pty's. 'a' means it is /dev/ptya0 */
+
+#define FIRST_PTY_LETTER 'p'
+
+/*
+ * Define HAVE_TERMIOS if the system provides POSIX-style
+ * functions and macros for terminal control.
+ *
+ * Define HAVE_TERMIO if the system provides sysV-style ioctls
+ * for terminal control.
+ *
+ * Do not define both. HAVE_TERMIOS is preferred, if it is
+ * supported on your system.
+ */
+
+#define HAVE_TERMIOS
+/* #define HAVE_TERMIO */
+
+#define NO_TERMIO
+
+/*
+ * Define HAVE_PTYS if the system supports pty devices.
+ */
+
+#define HAVE_PTYS
+
+/*
+ * Define NONSYSTEM_DIR_LIBRARY to make Emacs emulate
+ * The 4.2 opendir, etc., library functions.
+ */
+
+/* #define NONSYSTEM_DIR_LIBRARY */
+
+/* Define this symbol if your system has the functions bcopy, etc. */
+
+#define BSTRING
+
+/* subprocesses should be defined if you want to
+ have code for asynchronous subprocesses
+ (as used in M-x compile and M-x shell).
+ This is generally OS dependent, and not supported
+ under most USG systems. */
+
+#define subprocesses
+
+/* If your system uses COFF (Common Object File Format) then define the
+ preprocessor symbol "COFF". */
+
+/* #define COFF */
+
+/* define MAIL_USE_FLOCK if the mailer uses flock
+ to interlock access to /usr/spool/mail/$USER.
+ The alternative is that a lock file named
+ /usr/spool/mail/$USER.lock. */
+
+#define MAIL_USE_FLOCK
+
+/* Define CLASH_DETECTION if you want lock files to be written
+ so that Emacs can tell instantly when you try to modify
+ a file that someone else has modified in his Emacs. */
+
+#define CLASH_DETECTION
+
+/* Define this if your operating system declares signal handlers to
+ have a type other than the usual. `The usual' is `void' for ANSI C
+ systems (i.e. when the __STDC__ macro is defined), and `int' for
+ pre-ANSI systems. If you're using GCC on an older system, __STDC__
+ will be defined, but the system's include files will still say that
+ signal returns int or whatever; in situations like that, define
+ this to be what the system's include files want. */
+/* #define SIGTYPE int */
+
+/* If the character used to separate elements of the executable path
+ is not ':', #define this to be the appropriate character constant. */
+/* #define SEPCHAR ':' */
+
+/* Define this if the system can use mmap for buffer text allocation. */
+/* #define USE_MMAP_FOR_BUFFERS 1 */
+
+/* ============================================================ */
+
+/* Here, add any special hacks needed
+ to make Emacs work on this system. For example,
+ you might define certain system call names that don't
+ exist on your system, or that do different things on
+ your system and must be used only through an encapsulation
+ (Which you should place, by convention, in sysdep.c). */
+
+/* Some compilers tend to put everything declared static
+ into the initialized data area, which becomes pure after dumping Emacs.
+ On these systems, you must #define static as nothing to foil this.
+ Note that emacs carefully avoids static vars inside functions. */
+
+/* #define static */
+
+/* If the system's imake configuration file defines `NeedWidePrototypes'
+ as `NO', we must define NARROWPROTO manually. Such a define is
+ generated in the Makefile generated by `xmkmf'. If we don't
+ define NARROWPROTO, we will see the wrong function prototypes
+ for X functions taking float or double parameters. */
+
+/* #define NARROWPROTO 1 */
+
+/* ============================================================ */
+
+/* After adding support for a new system, modify the large case
+ statement in the `configure' script to recognize reasonable
+ configuration names, and add a description of the system to
+ `etc/MACHINES'.
+
+ If you've just fixed a problem in an existing configuration file,
+ you should also check `etc/MACHINES' to make sure its descriptions
+ of known problems in that configuration should be updated. */
+
+
+/* Avoid the use of the name init_process (process.c) because it is
+ also the name of a Mach system call. */
+#define init_process emacs_init_process
+
+/* Fix compilation problem for regex.c. */
+#define __restrict
+
+/* Fix compilation problem for md5.c. */
+#define __attribute__(x)
+
+/* Used in dispnew.c. Copied from freebsd.h. */
+#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_p - (FILE)->_bf._base)
+
+/* Darwin provides POSIX-style getpgrp. */
+#define GETPGRP_NO_ARG
+
+/* System uses OXTABS instead of the expected TAB3. (Copied from
+ bsd386.h.) */
+#define TAB3 OXTABS
+
+/* Darwin ld insists on the use of malloc routines in the System
+ framework. */
+#define SYSTEM_MALLOC
+
+/* Define HAVE_SOCKETS if system supports 4.2-compatible sockets. */
+#define HAVE_SOCKETS
+
+/* Extra initialization calls in main for Mac OS X system type. */
+#define SYMS_SYSTEM syms_of_mac()
+
+/* Definitions for how to dump. Copied from nextstep.h. */
+
+#define UNEXEC unexmacosx.o
+
+#define START_FILES pre-crt0.o
+
+/* start_of_text isn't actually used, so make it compile without error. */
+#define TEXT_START (0)
+
+/* This seems to be right for end_of_text, but it may not be used anyway. */
+#define TEXT_END get_etext()
+
+/* This seems to be right for end_of_data, but it may not be used anyway. */
+#define DATA_END get_edata()
+
+/* Definitions for how to compile & link. */
+
+/* Indicate that we are compiling for Mac OS X and where to find Mac
+ specific headers. */
+#define C_SWITCH_SYSTEM -fpascal-strings -fno-common -DMAC_OSX -I../mac/src
+
+/* Link in the Carbon lib. The -headerpad option tells ld (see man
+ page) to leave room at the end of the header for adding load
+ commands. Needed for dumping. 0x690 is the total size of 30
+ segment load commands (at 56 each). */
+#define LD_SWITCH_SYSTEM_TEMACS -prebind -framework Carbon -lstdc++ -Xlinker -headerpad -Xlinker 690
+
+#define C_SWITCH_SYSTEM_TEMACS -Dtemacs
+
+/* Link this program just by running cc. */
+#define ORDINARY_LINK
+
+/* We don't have a g library, so override the -lg LIBS_DEBUG switch. */
+#define LIBS_DEBUG
+
+/* Adding -lm confuses the dynamic linker, so omit it. */
+#define LIB_MATH
+
+/* Tell src/Makefile.in to create files in the Mac OS X application
+ bundle mac/Emacs.app. */
+#define OTHER_FILES macosx-app
+
+
+/* Define the following so emacs symbols will not conflict with those
+ in the System framework. Otherwise -prebind will not work. */
+
+/* Do not define abort in emacs.c. */
+#define NO_ABORT
+
+/* Do not define matherr in floatfns.c. */
+#define NO_MATHERR
+
+
+/* This prevents a compilation error in xfaces.c: struct kboard * is
+ used in a function protocol the first time this type appears in the
+ file, since MULTI_KBOARD is undefined for the Mac OS X build. */
+#ifndef NOT_C_CODE
+struct kboard;
+#endif
+
+#ifdef temacs
+#define malloc unexec_malloc
+#define realloc unexec_realloc
+#define free unexec_free
+#endif
diff --git a/src/sysdep.c b/src/sysdep.c
index 75d929e54ca..c7e4aba3a82 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -48,7 +48,7 @@ extern void srandom P_ ((unsigned int));
#include "blockinput.h"
#undef NULL
-#ifdef macintosh
+#ifdef MAC_OS8
/* It is essential to include stdlib.h so that this file picks up
the correct definitions of rand, srand, and RAND_MAX.
Otherwise random numbers will not work correctly. */
@@ -58,7 +58,7 @@ extern void srandom P_ ((unsigned int));
/* Nonzero means delete a process right away if it exits (process.c). */
static int delete_exited_processes;
#endif
-#endif /* macintosh */
+#endif /* MAC_OS8 */
#ifdef WINDOWSNT
#define read sys_read
@@ -759,7 +759,7 @@ sys_suspend ()
/* Fork a subshell. */
-#ifndef macintosh
+#ifndef MAC_OS8
void
sys_subshell ()
{
@@ -895,7 +895,7 @@ sys_subshell ()
synch_process_alive = 0;
#endif /* !VMS */
}
-#endif /* !macintosh */
+#endif /* !MAC_OS8 */
static void
save_signal_handlers (saved_handlers)
@@ -1305,7 +1305,7 @@ init_sys_modes ()
{
struct emacs_tty tty;
-#ifdef macintosh
+#ifdef MAC_OS8
/* cus-start.el complains if delete-exited-processes is not defined */
#ifndef subprocesses
DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
@@ -1313,7 +1313,7 @@ init_sys_modes ()
nil means don't delete them until `list-processes' is run. */);
delete_exited_processes = 0;
#endif
-#endif /* not macintosh */
+#endif /* MAC_OS8 */
#ifdef VMS
#if 0
diff --git a/src/term.c b/src/term.c
index 66f1c54ffd9..c2bac22d60c 100644
--- a/src/term.c
+++ b/src/term.c
@@ -56,7 +56,7 @@ extern int tgetnum P_ ((char *id));
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
#endif
diff --git a/src/termcap.c b/src/termcap.c
index b87fee48e87..8918f06d244 100644
--- a/src/termcap.c
+++ b/src/termcap.c
@@ -144,6 +144,9 @@ find_capability (bp, cap)
return NULL;
}
+/* These are already defined in the System framework in Mac OS X and
+ cause prebinding to fail. */
+#ifndef MAC_OSX
int
tgetnum (cap)
char *cap;
@@ -177,6 +180,7 @@ tgetstr (cap, area)
return NULL;
return tgetst1 (ptr, area);
}
+#endif /* MAC_OSX */
#ifdef IS_EBCDIC_HOST
/* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
@@ -294,7 +298,12 @@ short ospeed;
/* If OSPEED is 0, we use this as the actual baud rate. */
int tputs_baud_rate;
#endif
+
+/* Already defined in the System framework in Mac OS X and causes
+ prebinding to fail. */
+#ifndef MAC_OSX
char PC;
+#endif /* MAC_OSX */
#ifndef emacs
/* Actual baud rate if positive;
@@ -313,6 +322,9 @@ static int speeds[] =
#endif /* not emacs */
+/* Already defined in the System framework in Mac OS X and causes
+ prebinding to fail. */
+#ifndef MAC_OSX
void
tputs (str, nlines, outfun)
register char *str;
@@ -375,6 +387,7 @@ tputs (str, nlines, outfun)
while (padcount-- > 0)
(*outfun) (PC);
}
+#endif /* MAC_OSX */
/* Finding the termcap entry in the termcap data base. */
@@ -445,6 +458,9 @@ valid_filename_p (fn)
0 if the data base is accessible but the type NAME is not defined
in it, and some other value otherwise. */
+/* Already defined in the System framework in Mac OS X and causes
+ prebinding to fail. */
+#ifndef MAC_OSX
int
tgetent (bp, name)
char *bp, *name;
@@ -603,6 +619,7 @@ tgetent (bp, name)
term_entry = bp;
return 1;
}
+#endif /* MAC_OSX */
/* Given file open on FD and buffer BUFP,
scan the file from the beginning until a line is found
diff --git a/src/tparam.c b/src/tparam.c
index 5a9809aab47..844e5f6f175 100644
--- a/src/tparam.c
+++ b/src/tparam.c
@@ -107,6 +107,9 @@ tparam (string, outstring, len, arg0, arg1, arg2, arg3)
return tparam1 (string, outstring, len, NULL, NULL, arg);
}
+/* These are already defined in the System framework in Mac OS X and
+ cause prebinding to fail. */
+#ifndef MAC_OSX
char *BC;
char *UP;
@@ -124,6 +127,7 @@ tgoto (cm, hpos, vpos)
args[1] = hpos;
return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
}
+#endif
static char *
tparam1 (string, outstring, len, up, left, argp)
diff --git a/src/unexmacosx.c b/src/unexmacosx.c
new file mode 100644
index 00000000000..da4b82b6ca9
--- /dev/null
+++ b/src/unexmacosx.c
@@ -0,0 +1,914 @@
+/* Dump Emacs in Mach-O format for use on Mac OS X.
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Contributed by Andrew Choi (akochoi@mac.com). */
+
+/* Documentation note.
+
+ Consult the following documents/files for a description of the
+ Mach-O format: the file loader.h, man pages for Mach-O and ld, old
+ NEXTSTEP documents of the Mach-O format. The tool otool dumps the
+ mach header (-h option) and the load commands (-l option) in a
+ Mach-O file. The tool nm on Mac OS X displays the symbol table in
+ a Mach-O file. For examples of unexec for the Mach-O format, see
+ the file unexnext.c in the GNU Emacs distribution, the file
+ unexdyld.c in the Darwin port of GNU Emacs 20.7, and unexdyld.c in
+ the Darwin port of XEmacs 21.1. Also the Darwin Libc source
+ contains the source code for malloc_freezedry and malloc_jumpstart.
+ Read that to see what they do. This file was written completely
+ from scratch, making use of information from the above sources. */
+
+/* The Mac OS X implementation of unexec makes use of Darwin's `zone'
+ memory allocator. All calls to malloc, realloc, and free in Emacs
+ are redirected to unexec_malloc, unexec_realloc, and unexec_free in
+ this file. When temacs is run, all memory requests are handled in
+ the zone EmacsZone. The Darwin memory allocator library calls
+ maintain the data structures to manage this zone. Dumping writes
+ its contents to data segments of the executable file. When emacs
+ is run, the loader recreates the contents of the zone in memory.
+ However since the initialization routine of the zone memory
+ allocator is run again, this `zone' can no longer be used as a
+ heap. That is why emacs uses the ordinary malloc system call to
+ allocate memory. Also, when a block of memory needs to be
+ reallocated and the new size is larger than the old one, a new
+ block must be obtained by malloc and the old contents copied to
+ it. */
+
+/* Peculiarity of the Mach-O files generated by ld in Mac OS X
+ (possible causes of future bugs if changed).
+
+ The file offset of the start of the __TEXT segment is zero. Since
+ the Mach header and load commands are located at the beginning of a
+ Mach-O file, copying the contents of the __TEXT segment from the
+ input file overwrites them in the output file. Despite this,
+ unexec works fine as written below because the segment load command
+ for __TEXT appears, and is therefore processed, before all other
+ load commands except the segment load command for __PAGEZERO, which
+ remains unchanged.
+
+ Although the file offset of the start of the __TEXT segment is
+ zero, none of the sections it contains actually start there. In
+ fact, the earliest one starts a few hundred bytes beyond the end of
+ the last load command. The linker option -headerpad controls the
+ minimum size of this padding. Its setting can be changed in
+ s/darwin.h. A value of 0x300, e.g., leaves room for about 15
+ additional load commands for the newly created __DATA segments (at
+ 56 bytes each). Unexec fails if there is not enough room for these
+ new segments.
+
+ The __TEXT segment contains the sections __text, __cstring,
+ __picsymbol_stub, and __const and the __DATA segment contains the
+ sections __data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __bss,
+ and __common. The other segments do not contain any sections.
+ These sections are copied from the input file to the output file,
+ except for __data, __bss, and __common, which are dumped from
+ memory. The types of the sections __bss and __common are changed
+ from S_ZEROFILL to S_REGULAR. Note that the number of sections and
+ their relative order in the input and output files remain
+ unchanged. Otherwise all n_sect fields in the nlist records in the
+ symbol table (specified by the LC_SYMTAB load command) will have to
+ be changed accordingly.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach-o/loader.h>
+#include <objc/malloc.h>
+
+#define VERBOSE 1
+
+/* Size of buffer used to copy data from the input file to the output
+ file in function unexec_copy. */
+#define UNEXEC_COPY_BUFSZ 1024
+
+/* Regions with memory addresses above this value are assumed to be
+ mapped to dynamically loaded libraries and will not be dumped. */
+#define VM_DATA_TOP (20 * 1024 * 1024)
+
+/* Used by malloc_freezedry and malloc_jumpstart. */
+int malloc_cookie;
+
+/* Type of an element on the list of regions to be dumped. */
+struct region_t {
+ vm_address_t address;
+ vm_size_t size;
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+
+ struct region_t *next;
+};
+
+/* Head and tail of the list of regions to be dumped. */
+struct region_t *region_list_head = 0;
+struct region_t *region_list_tail = 0;
+
+/* Pointer to array of load commands. */
+struct load_command **lca;
+
+/* Number of load commands. */
+int nlc;
+
+/* The highest VM address of segments loaded by the input file.
+ Regions with addresses beyond this are assumed to be allocated
+ dynamically and thus require dumping. */
+vm_address_t infile_lc_highest_addr = 0;
+
+/* The lowest file offset used by the all sections in the __TEXT
+ segments. This leaves room at the beginning of the file to store
+ the Mach-O header. Check this value against header size to ensure
+ the added load commands for the new __DATA segments did not
+ overwrite any of the sections in the __TEXT segment. */
+unsigned long text_seg_lowest_offset = 0x10000000;
+
+/* Mach header. */
+struct mach_header mh;
+
+/* Offset at which the next load command should be written. */
+unsigned long curr_header_offset = sizeof (struct mach_header);
+
+/* Current adjustment that needs to be made to offset values because
+ of additional data segments. */
+unsigned long delta = 0;
+
+int infd, outfd;
+
+int in_dumped_exec = 0;
+
+malloc_zone_t *emacs_zone;
+
+/* Read n bytes from infd into memory starting at address dest.
+ Return true if successful, false otherwise. */
+static int
+unexec_read (void *dest, size_t n)
+{
+ return n == read (infd, dest, n);
+}
+
+/* Write n bytes from memory starting at address src to outfd starting
+ at offset dest. Return true if successful, false otherwise. */
+static int
+unexec_write (off_t dest, const void *src, size_t count)
+{
+ if (lseek (outfd, dest, SEEK_SET) != dest)
+ return 0;
+
+ return write (outfd, src, count) == count;
+}
+
+/* Copy n bytes from starting offset src in infd to starting offset
+ dest in outfd. Return true if successful, false otherwise. */
+static int
+unexec_copy (off_t dest, off_t src, ssize_t count)
+{
+ ssize_t bytes_read;
+
+ char buf[UNEXEC_COPY_BUFSZ];
+
+ if (lseek (infd, src, SEEK_SET) != src)
+ return 0;
+
+ if (lseek (outfd, dest, SEEK_SET) != dest)
+ return 0;
+
+ while (count > 0)
+ {
+ bytes_read = read (infd, buf, UNEXEC_COPY_BUFSZ);
+ if (bytes_read <= 0)
+ return 0;
+ if (write (outfd, buf, bytes_read) != bytes_read)
+ return 0;
+ count -= bytes_read;
+ }
+
+ return 1;
+}
+
+/* Debugging and informational messages routines. */
+
+static void
+unexec_error (char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ fprintf (stderr, "unexec: ");
+ vfprintf (stderr, format, ap);
+ fprintf (stderr, "\n");
+ va_end (ap);
+ exit (1);
+}
+
+static void
+print_prot (vm_prot_t prot)
+{
+ if (prot == VM_PROT_NONE)
+ printf ("none");
+ else
+ {
+ putchar (prot & VM_PROT_READ ? 'r' : ' ');
+ putchar (prot & VM_PROT_WRITE ? 'w' : ' ');
+ putchar (prot & VM_PROT_EXECUTE ? 'x' : ' ');
+ putchar (' ');
+ }
+}
+
+static void
+print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
+ vm_prot_t max_prot)
+{
+ printf ("%#10x %#8x ", address, size);
+ print_prot (prot);
+ putchar (' ');
+ print_prot (max_prot);
+ putchar ('\n');
+}
+
+static void
+print_region_list ()
+{
+ struct region_t *r;
+
+ printf (" address size prot maxp\n");
+
+ for (r = region_list_head; r; r = r->next)
+ print_region (r->address, r->size, r->protection, r->max_protection);
+}
+
+void
+print_regions ()
+{
+ task_t target_task = mach_task_self ();
+ vm_address_t address = (vm_address_t) 0;
+ vm_size_t size;
+ struct vm_region_basic_info info;
+ mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
+ mach_port_t object_name;
+
+ printf (" address size prot maxp\n");
+
+ while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
+ (vm_region_info_t) &info, &info_count, &object_name)
+ == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
+ {
+ print_region (address, size, info.protection, info.max_protection);
+
+ if (object_name != MACH_PORT_NULL)
+ mach_port_deallocate (target_task, object_name);
+
+ address += size;
+ }
+}
+
+/* Build the list of regions that need to be dumped. Regions with
+ addresses above VM_DATA_TOP are omitted. Adjacent regions with
+ identical protection are merged. Note that non-writable regions
+ cannot be omitted because they some regions created at run time are
+ read-only. */
+static void
+build_region_list ()
+{
+ task_t target_task = mach_task_self ();
+ vm_address_t address = (vm_address_t) 0;
+ vm_size_t size;
+ struct vm_region_basic_info info;
+ mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
+ mach_port_t object_name;
+ struct region_t *r;
+
+#if VERBOSE
+ printf ("--- List of All Regions ---\n");
+ printf (" address size prot maxp\n");
+#endif
+
+ while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
+ (vm_region_info_t) &info, &info_count, &object_name)
+ == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
+ {
+ /* Done when we reach addresses of shared libraries, which are
+ loaded in high memory. */
+ if (address >= VM_DATA_TOP)
+ break;
+
+#if VERBOSE
+ print_region (address, size, info.protection, info.max_protection);
+#endif
+
+ /* If a region immediately follows the previous one (the one
+ most recently added to the list) and has identical
+ protection, merge it with the latter. Otherwise create a
+ new list element for it. */
+ if (region_list_tail
+ && info.protection == region_list_tail->protection
+ && info.max_protection == region_list_tail->max_protection
+ && region_list_tail->address + region_list_tail->size == address)
+ {
+ region_list_tail->size += size;
+ }
+ else
+ {
+ r = (struct region_t *) malloc (sizeof (struct region_t));
+
+ if (!r)
+ unexec_error ("cannot allocate region structure");
+
+ r->address = address;
+ r->size = size;
+ r->protection = info.protection;
+ r->max_protection = info.max_protection;
+
+ r->next = 0;
+ if (region_list_head == 0)
+ {
+ region_list_head = r;
+ region_list_tail = r;
+ }
+ else
+ {
+ region_list_tail->next = r;
+ region_list_tail = r;
+ }
+
+ /* Deallocate (unused) object name returned by
+ vm_region. */
+ if (object_name != MACH_PORT_NULL)
+ mach_port_deallocate (target_task, object_name);
+ }
+
+ address += size;
+ }
+
+ printf ("--- List of Regions to be Dumped ---\n");
+ print_region_list ();
+}
+
+
+#define MAX_UNEXEC_REGIONS 30
+
+int num_unexec_regions;
+vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
+
+static void
+unexec_regions_recorder (task_t task, void *rr, unsigned type,
+ vm_range_t *ranges, unsigned num)
+{
+ while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
+ {
+ unexec_regions[num_unexec_regions++] = *ranges;
+ printf ("%#8x (sz: %#8x)\n", ranges->address, ranges->size);
+ ranges++; num--;
+ }
+ if (num_unexec_regions == MAX_UNEXEC_REGIONS)
+ fprintf (stderr, "malloc_freezedry_recorder: too many regions\n");
+}
+
+static kern_return_t
+unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr)
+{
+ *ptr = (void *) address;
+ return KERN_SUCCESS;
+}
+
+void
+find_emacs_zone_regions ()
+{
+ num_unexec_regions = 0;
+
+ emacs_zone->introspect->enumerator (mach_task_self(), 0,
+ MALLOC_PTR_REGION_RANGE_TYPE
+ | MALLOC_ADMIN_REGION_RANGE_TYPE,
+ (vm_address_t) emacs_zone,
+ unexec_reader,
+ unexec_regions_recorder);
+}
+
+
+/* More informational messages routines. */
+
+static void
+print_load_command_name (int lc)
+{
+ switch (lc)
+ {
+ case LC_SEGMENT:
+ printf ("LC_SEGMENT ");
+ break;
+ case LC_LOAD_DYLINKER:
+ printf ("LC_LOAD_DYLINKER ");
+ break;
+ case LC_LOAD_DYLIB:
+ printf ("LC_LOAD_DYLIB ");
+ break;
+ case LC_SYMTAB:
+ printf ("LC_SYMTAB ");
+ break;
+ case LC_DYSYMTAB:
+ printf ("LC_DYSYMTAB ");
+ break;
+ case LC_UNIXTHREAD:
+ printf ("LC_UNIXTHREAD ");
+ break;
+ case LC_PREBOUND_DYLIB:
+ printf ("LC_PREBOUND_DYLIB");
+ break;
+ case LC_TWOLEVEL_HINTS:
+ printf ("LC_TWOLEVEL_HINTS");
+ break;
+ default:
+ printf ("unknown ");
+ }
+}
+
+static void
+print_load_command (struct load_command *lc)
+{
+ print_load_command_name (lc->cmd);
+ printf ("%8d", lc->cmdsize);
+
+ if (lc->cmd == LC_SEGMENT)
+ {
+ struct segment_command *scp;
+ struct section *sectp;
+ int j;
+
+ scp = (struct segment_command *) lc;
+ printf (" %-16.16s %#10x %#8x\n",
+ scp->segname, scp->vmaddr, scp->vmsize);
+
+ sectp = (struct section *) (scp + 1);
+ for (j = 0; j < scp->nsects; j++)
+ {
+ printf (" %-16.16s %#10x %#8x\n",
+ sectp->sectname, sectp->addr, sectp->size);
+ sectp++;
+ }
+ }
+ else
+ printf ("\n");
+}
+
+/* Read header and load commands from input file. Store the latter in
+ the global array lca. Store the total number of load commands in
+ global variable nlc. */
+static void
+read_load_commands ()
+{
+ int n, i, j;
+
+ if (!unexec_read (&mh, sizeof (struct mach_header)))
+ unexec_error ("cannot read mach-o header");
+
+ if (mh.magic != MH_MAGIC)
+ unexec_error ("input file not in Mach-O format");
+
+ if (mh.filetype != MH_EXECUTE)
+ unexec_error ("input Mach-O file is not an executable object file");
+
+#if VERBOSE
+ printf ("--- Header Information ---\n");
+ printf ("Magic = 0x%08x\n", mh.magic);
+ printf ("CPUType = %d\n", mh.cputype);
+ printf ("CPUSubType = %d\n", mh.cpusubtype);
+ printf ("FileType = 0x%x\n", mh.filetype);
+ printf ("NCmds = %d\n", mh.ncmds);
+ printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
+ printf ("Flags = 0x%08x\n", mh.flags);
+#endif
+
+ nlc = mh.ncmds;
+ lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *));
+
+ for (i = 0; i < nlc; i++)
+ {
+ struct load_command lc;
+ /* Load commands are variable-size: so read the command type and
+ size first and then read the rest. */
+ if (!unexec_read (&lc, sizeof (struct load_command)))
+ unexec_error ("cannot read load command");
+ lca[i] = (struct load_command *) malloc (lc.cmdsize);
+ memcpy (lca[i], &lc, sizeof (struct load_command));
+ if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
+ unexec_error ("cannot read content of load command");
+ if (lc.cmd == LC_SEGMENT)
+ {
+ struct segment_command *scp = (struct segment_command *) lca[i];
+
+ if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
+ infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
+
+ if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
+ {
+ struct section *sectp = (struct section *) (scp + 1);
+ int j;
+
+ for (j = 0; j < scp->nsects; j++)
+ if (sectp->offset < text_seg_lowest_offset)
+ text_seg_lowest_offset = sectp->offset;
+ }
+ }
+ }
+
+ printf ("Highest address of load commands in input file: %#8x\n",
+ infile_lc_highest_addr);
+
+ printf ("Lowest offset of all sections in __TEXT segment: %#8x\n",
+ text_seg_lowest_offset);
+
+ printf ("--- List of Load Commands in Input File ---\n");
+ printf ("# cmd cmdsize name address size\n");
+
+ for (i = 0; i < nlc; i++)
+ {
+ printf ("%1d ", i);
+ print_load_command (lca[i]);
+ }
+}
+
+/* Copy a LC_SEGMENT load command other than the __DATA segment from
+ the input file to the output file, adjusting the file offset of the
+ segment and the file offsets of sections contained in it. */
+static void
+copy_segment (struct load_command *lc)
+{
+ struct segment_command *scp = (struct segment_command *) lc;
+ unsigned long old_fileoff = scp->fileoff;
+ struct section *sectp;
+ int j;
+
+ scp->fileoff += delta;
+
+ sectp = (struct section *) (scp + 1);
+ for (j = 0; j < scp->nsects; j++)
+ {
+ sectp->offset += delta;
+ sectp++;
+ }
+
+ printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
+ scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
+ scp->filesize);
+
+ if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
+ unexec_error ("cannot copy segment from input to output file");
+ if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
+ unexec_error ("cannot write load command to header");
+
+ curr_header_offset += lc->cmdsize;
+}
+
+/* Copy a LC_SEGMENT load command for the __DATA segment in the input
+ file to the output file. We assume that only one such segment load
+ command exists in the input file and it contains the sections
+ __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
+ __dyld. The first three of these should be dumped from memory and
+ the rest should be copied from the input file. Note that the
+ sections __bss and __common contain no data in the input file
+ because their flag fields have the value S_ZEROFILL. Dumping these
+ from memory makes it necessary to adjust file offset fields in
+ subsequently dumped load commands. Then, create new __DATA segment
+ load commands for regions on the region list other than the one
+ corresponding to the __DATA segment in the input file. */
+static void
+copy_data_segment (struct load_command *lc)
+{
+ struct segment_command *scp = (struct segment_command *) lc;
+ struct section *sectp;
+ int j;
+ unsigned long header_offset, file_offset, old_file_offset;
+ struct region_t *r;
+
+ printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
+ scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
+ scp->filesize);
+
+ if (delta != 0)
+ unexec_error ("cannot handle multiple DATA segments in input file");
+
+ /* Offsets in the output file for writing the next section structure
+ and segment data block, respectively. */
+ header_offset = curr_header_offset + sizeof (struct segment_command);
+
+ sectp = (struct section *) (scp + 1);
+ for (j = 0; j < scp->nsects; j++)
+ {
+ old_file_offset = sectp->offset;
+ sectp->offset = sectp->addr - scp->vmaddr + scp->fileoff;
+ /* The __data section is dumped from memory. The __bss and
+ __common sections are also dumped from memory but their flag
+ fields require changing (from S_ZEROFILL to S_REGULAR). The
+ other three kinds of sections are just copied from the input
+ file. */
+ if (strncmp (sectp->sectname, SECT_DATA, 16) == 0)
+ {
+ if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
+ unexec_error ("cannot write section %s", SECT_DATA);
+ if (!unexec_write (header_offset, sectp, sizeof (struct section)))
+ unexec_error ("cannot write section %s's header", SECT_DATA);
+ }
+ else if (strncmp (sectp->sectname, SECT_BSS, 16) == 0
+ || strncmp (sectp->sectname, SECT_COMMON, 16) == 0)
+ {
+ sectp->flags = S_REGULAR;
+ if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
+ unexec_error ("cannot write section %s", SECT_DATA);
+ if (!unexec_write (header_offset, sectp, sizeof (struct section)))
+ unexec_error ("cannot write section %s's header", SECT_DATA);
+ }
+ else if (strncmp (sectp->sectname, "__la_symbol_ptr", 16) == 0
+ || strncmp (sectp->sectname, "__nl_symbol_ptr", 16) == 0
+ || strncmp (sectp->sectname, "__dyld", 16) == 0
+ || strncmp (sectp->sectname, "__const", 16) == 0)
+ {
+ if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
+ unexec_error ("cannot copy section %s", sectp->sectname);
+ if (!unexec_write (header_offset, sectp, sizeof (struct section)))
+ unexec_error ("cannot write section %s's header", sectp->sectname);
+ }
+ else
+ unexec_error ("unrecognized section name in __DATA segment");
+
+ printf (" section %-16.16s at %#8x - %#8x (sz: %#8x)\n",
+ sectp->sectname, sectp->offset, sectp->offset + sectp->size,
+ sectp->size);
+
+ header_offset += sizeof (struct section);
+ sectp++;
+ }
+
+ /* The new filesize of the segment is set to its vmsize because data
+ blocks for segments must start at region boundaries. Note that
+ this may leave unused locations at the end of the segment data
+ block because the total of the sizes of all sections in the
+ segment is generally smaller than vmsize. */
+ delta = scp->vmsize - scp->filesize;
+ scp->filesize = scp->vmsize;
+ if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
+ unexec_error ("cannot write header of __DATA segment");
+ curr_header_offset += lc->cmdsize;
+
+ /* Create new __DATA segment load commands for regions on the region
+ list that do not corresponding to any segment load commands in
+ the input file.
+ */
+ file_offset = scp->fileoff + scp->filesize;
+ for (j = 0; j < num_unexec_regions; j++)
+ {
+ struct segment_command sc;
+
+ sc.cmd = LC_SEGMENT;
+ sc.cmdsize = sizeof (struct segment_command);
+ strncpy (sc.segname, SEG_DATA, 16);
+ sc.vmaddr = unexec_regions[j].address;
+ sc.vmsize = unexec_regions[j].size;
+ sc.fileoff = file_offset;
+ sc.filesize = unexec_regions[j].size;
+ sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
+ sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
+ sc.nsects = 0;
+ sc.flags = 0;
+
+ printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
+ sc.segname, sc.fileoff, sc.fileoff + sc.filesize,
+ sc.filesize);
+
+ if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
+ unexec_error ("cannot write new __DATA segment");
+ delta += sc.filesize;
+ file_offset += sc.filesize;
+
+ if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
+ unexec_error ("cannot write new __DATA segment's header");
+ curr_header_offset += sc.cmdsize;
+ mh.ncmds++;
+ }
+}
+
+/* Copy a LC_SYMTAB load command from the input file to the output
+ file, adjusting the file offset fields. */
+static void
+copy_symtab (struct load_command *lc)
+{
+ struct symtab_command *stp = (struct symtab_command *) lc;
+
+ stp->symoff += delta;
+ stp->stroff += delta;
+
+ printf ("Writing LC_SYMTAB command\n");
+
+ if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
+ unexec_error ("cannot write symtab command to header");
+
+ curr_header_offset += lc->cmdsize;
+}
+
+/* Copy a LC_DYSYMTAB load command from the input file to the output
+ file, adjusting the file offset fields. */
+static void
+copy_dysymtab (struct load_command *lc)
+{
+ struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
+
+ /* If Mach-O executable is not prebound, relocation entries need
+ fixing up. This is not supported currently. */
+ if (!(mh.flags & MH_PREBOUND) && (dstp->nextrel != 0 || dstp->nlocrel != 0))
+ unexec_error ("cannot handle LC_DYSYMTAB with relocation entries");
+
+ if (dstp->nextrel > 0) {
+ dstp->extreloff += delta;
+ }
+
+ if (dstp->nlocrel > 0) {
+ dstp->locreloff += delta;
+ }
+
+ if (dstp->nindirectsyms > 0)
+ dstp->indirectsymoff += delta;
+
+ printf ("Writing LC_DYSYMTAB command\n");
+
+ if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
+ unexec_error ("cannot write symtab command to header");
+
+ curr_header_offset += lc->cmdsize;
+}
+
+/* Copy other kinds of load commands from the input file to the output
+ file, ones that do not require adjustments of file offsets. */
+static void
+copy_other (struct load_command *lc)
+{
+ printf ("Writing ");
+ print_load_command_name (lc->cmd);
+ printf (" command\n");
+
+ if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
+ unexec_error ("cannot write symtab command to header");
+
+ curr_header_offset += lc->cmdsize;
+}
+
+/* Loop through all load commands and dump them. Then write the Mach
+ header. */
+static void
+dump_it ()
+{
+ int i;
+
+ printf ("--- Load Commands written to Output File ---\n");
+
+ for (i = 0; i < nlc; i++)
+ switch (lca[i]->cmd)
+ {
+ case LC_SEGMENT:
+ {
+ struct segment_command *scp = (struct segment_command *) lca[i];
+ if (strncmp (scp->segname, SEG_DATA, 16) == 0)
+ {
+ copy_data_segment (lca[i]);
+ }
+ else
+ {
+ copy_segment (lca[i]);
+ }
+ }
+ break;
+ case LC_SYMTAB:
+ copy_symtab (lca[i]);
+ break;
+ case LC_DYSYMTAB:
+ copy_dysymtab (lca[i]);
+ break;
+ default:
+ copy_other (lca[i]);
+ break;
+ }
+
+ if (curr_header_offset > text_seg_lowest_offset)
+ unexec_error ("not enough room for load commands for new __DATA segments");
+
+ printf ("%d unused bytes follow Mach-O header\n",
+ text_seg_lowest_offset - curr_header_offset);
+
+ mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
+ if (!unexec_write (0, &mh, sizeof (struct mach_header)))
+ unexec_error ("cannot write final header contents");
+}
+
+/* Take a snapshot of Emacs and make a Mach-O format executable file
+ from it. The file names of the output and input files are outfile
+ and infile, respectively. The three other parameters are
+ ignored. */
+void
+unexec (char *outfile, char *infile, void *start_data, void *start_bss,
+ void *entry_address)
+{
+ infd = open (infile, O_RDONLY, 0);
+ if (infd < 0)
+ {
+ unexec_error ("cannot open input file `%s'", infile);
+ }
+
+ outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755);
+ if (outfd < 0)
+ {
+ close (infd);
+ unexec_error ("cannot open output file `%s'", outfile);
+ }
+
+ build_region_list ();
+ read_load_commands ();
+
+ find_emacs_zone_regions ();
+
+ in_dumped_exec = 1;
+
+ dump_it ();
+
+ close (outfd);
+}
+
+
+void
+unexec_init_emacs_zone ()
+{
+ emacs_zone = malloc_create_zone (0, 0);
+ malloc_set_zone_name (emacs_zone, "EmacsZone");
+}
+
+int
+ptr_in_unexec_regions (void *ptr)
+{
+ int i;
+
+ for (i = 0; i < num_unexec_regions; i++)
+ if ((vm_address_t) ptr - unexec_regions[i].address
+ < unexec_regions[i].size)
+ return 1;
+
+ return 0;
+}
+
+void *
+unexec_malloc (size_t size)
+{
+ if (in_dumped_exec)
+ return malloc (size);
+ else
+ return malloc_zone_malloc (emacs_zone, size);
+}
+
+void *
+unexec_realloc (void *old_ptr, size_t new_size)
+{
+ if (in_dumped_exec)
+ if (ptr_in_unexec_regions (old_ptr))
+ {
+ char *p = malloc (new_size);
+ /* 2002-04-15 T. Ikegami <ikegami@adam.uprr.pr>. The original
+ code to get size failed to reallocate read_buffer
+ (lread.c). */
+ int old_size = emacs_zone->size (emacs_zone, old_ptr);
+ int size = new_size > old_size ? old_size : new_size;
+
+ if (size)
+ memcpy (p, old_ptr, size);
+ return p;
+ }
+ else
+ return realloc (old_ptr, new_size);
+ else
+ return malloc_zone_realloc (emacs_zone, old_ptr, new_size);
+}
+
+void
+unexec_free (void *ptr)
+{
+ if (in_dumped_exec)
+ {
+ if (!ptr_in_unexec_regions (ptr))
+ free (ptr);
+ }
+ else
+ malloc_zone_free (emacs_zone, ptr);
+}
diff --git a/src/window.c b/src/window.c
index 4dc8329baf1..24a95dc53a1 100644
--- a/src/window.c
+++ b/src/window.c
@@ -44,7 +44,7 @@ Boston, MA 02111-1307, USA. */
#ifdef MSDOS
#include "msdos.h"
#endif
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
#endif
diff --git a/src/xdisp.c b/src/xdisp.c
index 4764bfb90a6..5eaf8330797 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -194,13 +194,13 @@ Boston, MA 02111-1307, USA. */
#ifdef WINDOWSNT
#include "w32term.h"
#endif
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
#endif
#define INFINITY 10000000
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
extern void set_frame_menubar P_ ((struct frame *f, int, int));
extern int pending_menu_activation;
#endif
@@ -7077,7 +7077,7 @@ echo_area_display (update_frame_p)
return 0;
/* The terminal frame is used as the first Emacs frame on the Mac OS. */
-#ifndef macintosh
+#ifndef MAC_OS8
#ifdef HAVE_WINDOW_SYSTEM
/* When Emacs starts, selected_frame may be a visible terminal
frame, even if we run under a window system. If we let this
@@ -7450,7 +7450,7 @@ update_menu_bar (f, save_match_data)
if (FRAME_WINDOW_P (f)
?
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
FRAME_EXTERNAL_MENU_BAR (f)
#else
FRAME_MENU_BAR_LINES (f) > 0
@@ -7501,9 +7501,9 @@ update_menu_bar (f, save_match_data)
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
/* Redisplay the menu bar in case we changed it. */
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
if (FRAME_WINDOW_P (f)
-#if defined (macintosh)
+#if defined (MAC_OS)
/* All frames on Mac OS share the same menubar. So only the
selected frame should be allowed to set it. */
&& f == SELECTED_FRAME ()
@@ -10647,7 +10647,7 @@ redisplay_window (window, just_this_one_p)
if (FRAME_WINDOW_P (f))
{
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f);
#else
redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
@@ -13379,7 +13379,7 @@ display_menu_bar (w)
if (FRAME_X_P (f))
return;
#endif
-#ifdef macintosh
+#ifdef MAC_OS
if (FRAME_MAC_P (f))
return;
#endif
diff --git a/src/xfaces.c b/src/xfaces.c
index 256bb3a656d..9e37f096321 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -234,32 +234,11 @@ Boston, MA 02111-1307, USA. */
#define FONT_WIDTH FONT_MAX_WIDTH
#endif /* WINDOWSNT */
-#ifdef macintosh
+#ifdef MAC_OS
#include "macterm.h"
#define x_display_info mac_display_info
#define check_x check_mac
-
-extern XGCValues *XCreateGC (void *, WindowPtr, unsigned long, XGCValues *);
-
-static INLINE GC
-x_create_gc (f, mask, xgcv)
- struct frame *f;
- unsigned long mask;
- XGCValues *xgcv;
-{
- GC gc;
- gc = XCreateGC (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), mask, xgcv);
- return gc;
-}
-
-static INLINE void
-x_free_gc (f, gc)
- struct frame *f;
- GC gc;
-{
- XFreeGC (FRAME_MAC_DISPLAY (f), gc);
-}
-#endif
+#endif /* MAC_OS */
#include "buffer.h"
#include "dispextern.h"
@@ -814,6 +793,32 @@ x_free_gc (f, gc)
#endif /* WINDOWSNT */
+#ifdef MAC_OS
+/* Mac OS emulation of GCs */
+
+extern XGCValues *XCreateGC (void *, Window, unsigned long, XGCValues *);
+
+static INLINE GC
+x_create_gc (f, mask, xgcv)
+ struct frame *f;
+ unsigned long mask;
+ XGCValues *xgcv;
+{
+ GC gc;
+ gc = XCreateGC (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), mask, xgcv);
+ return gc;
+}
+
+static INLINE void
+x_free_gc (f, gc)
+ struct frame *f;
+ GC gc;
+{
+ XFreeGC (FRAME_MAC_DISPLAY (f), gc);
+}
+
+#endif /* MAC_OS */
+
/* Like stricmp. Used to compare parts of font names which are in
ISO8859-1. */
@@ -1382,7 +1387,7 @@ defined_color (f, color_name, color_def, alloc)
else if (FRAME_W32_P (f))
return w32_defined_color (f, color_name, color_def, alloc);
#endif
-#ifdef macintosh
+#ifdef MAC_OS
else if (FRAME_MAC_P (f))
return mac_defined_color (f, color_name, color_def, alloc);
#endif
@@ -1889,7 +1894,7 @@ static struct frame *font_frame;
font height, then for weight, then for slant.' This variable can be
set via set-face-font-sort-order. */
-#ifdef macintosh
+#ifdef MAC_OS
static int font_sort_order[4] = {
XLFD_SWIDTH, XLFD_POINT_SIZE, XLFD_WEIGHT, XLFD_SLANT
};
@@ -4341,7 +4346,7 @@ DEFUN ("internal-face-x-get-resource", Finternal_face_x_get_resource,
{
Lisp_Object value = Qnil;
#ifndef WINDOWSNT
-#ifndef macintosh
+#ifndef MAC_OS
CHECK_STRING (resource);
CHECK_STRING (class);
CHECK_LIVE_FRAME (frame);
@@ -4349,7 +4354,7 @@ DEFUN ("internal-face-x-get-resource", Finternal_face_x_get_resource,
value = display_x_get_resource (FRAME_X_DISPLAY_INFO (XFRAME (frame)),
resource, class, Qnil, Qnil);
UNBLOCK_INPUT;
-#endif /* not macintosh */
+#endif /* not MAC_OS */
#endif /* not WINDOWSNT */
return value;
}
@@ -4997,7 +5002,7 @@ prepare_face_for_display (f, face)
#ifdef WINDOWSNT
xgcv.font = face->font;
#endif
-#ifdef macintosh
+#ifdef MAC_OS
xgcv.font = face->font;
#endif
mask |= GCFont;
@@ -6428,7 +6433,7 @@ realize_x_face (cache, attrs, c, base_face)
face->fontset = make_fontset_for_ascii_face (f, fontset);
face->font = NULL; /* to force realize_face to load font */
-#ifdef macintosh
+#ifdef MAC_OS
/* Load the font if it is specified in ATTRS. This fixes
changing frame font on the Mac. */
if (STRINGP (attrs[LFACE_FONT_INDEX]))