aboutsummaryrefslogtreecommitdiffstats
path: root/mac/src
diff options
context:
space:
mode:
Diffstat (limited to 'mac/src')
-rw-r--r--mac/src/Emacs.r6
-rw-r--r--mac/src/EmacsMPW.r2
-rw-r--r--mac/src/chdir.c2
-rw-r--r--mac/src/mac.c2649
-rw-r--r--mac/src/macfns.c10112
-rw-r--r--mac/src/macmenu.c2206
-rw-r--r--mac/src/macterm.c12585
7 files changed, 7 insertions, 27555 deletions
diff --git a/mac/src/Emacs.r b/mac/src/Emacs.r
index 475bce62f3c..61630858730 100644
--- a/mac/src/Emacs.r
+++ b/mac/src/Emacs.r
@@ -18,11 +18,13 @@ along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */ 19Boston, MA 02111-1307, USA. */
20 20
21/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ 21/* Contributed by Andrew Choi (akochoi@mac.com). */
22 22
23#ifndef TARGET_API_MAC_CARBON
23#include "Types.r" 24#include "Types.r"
24/* added for finder icon balloon help --ben */ 25/* added for finder icon balloon help --ben */
25#include "Balloons.r" 26#include "Balloons.r"
27#endif
26 28
27/* Define to use gnu icon */ 29/* Define to use gnu icon */
28/* #define GNU_ICON 1 */ 30/* #define GNU_ICON 1 */
@@ -55,10 +57,12 @@ resource 'hfdr' (-5696) { /*help for emacs icon*/
55 } 57 }
56}; 58};
57 59
60#ifndef TARGET_API_MAC_CARBON
58/* added for finder icon balloon help --ben */ 61/* added for finder icon balloon help --ben */
59resource 'STR ' (128) { /*help message for emacs icon*/ 62resource 'STR ' (128) { /*help message for emacs icon*/
60 "GNU Emacs\0xd1the extensible, customizable, self-documenting real-time display editor." 63 "GNU Emacs\0xd1the extensible, customizable, self-documenting real-time display editor."
61}; 64};
65#endif
62 66
63resource 'MENU' (128, preload) { 67resource 'MENU' (128, preload) {
64 128, 68 128,
diff --git a/mac/src/EmacsMPW.r b/mac/src/EmacsMPW.r
index c4ff17f9914..ad49ab3b76d 100644
--- a/mac/src/EmacsMPW.r
+++ b/mac/src/EmacsMPW.r
@@ -20,7 +20,7 @@ along with GNU Emacs; see the file COPYING. If not, write to
20the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */ 21Boston, MA 02111-1307, USA. */
22 22
23/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ 23/* Contributed by Andrew Choi (akochoi@mac.com). */
24 24
25#include "Types.r" 25#include "Types.r"
26#include "CodeFragmentTypes.r" 26#include "CodeFragmentTypes.r"
diff --git a/mac/src/chdir.c b/mac/src/chdir.c
index 5bf9354b4f5..987df2008bf 100644
--- a/mac/src/chdir.c
+++ b/mac/src/chdir.c
@@ -18,7 +18,7 @@ along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */ 19Boston, MA 02111-1307, USA. */
20 20
21/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ 21/* Contributed by Andrew Choi (akochoi@mac.com). */
22 22
23#include <string.h> 23#include <string.h>
24#include <Files.h> 24#include <Files.h>
diff --git a/mac/src/mac.c b/mac/src/mac.c
deleted file mode 100644
index 473273f13b7..00000000000
--- a/mac/src/mac.c
+++ /dev/null
@@ -1,2649 +0,0 @@
1/* Unix emulation routines for GNU Emacs on the Mac OS.
2 Copyright (C) 2000 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */
22
23#include <config.h>
24
25#include <stdio.h>
26#include <errno.h>
27#include <utime.h>
28#include <dirent.h>
29#include <sys/stat.h>
30#include <string.h>
31#include <pwd.h>
32#include <sys/param.h>
33#if __MWERKS__
34#include <unistd.h>
35#endif
36
37#include <Files.h>
38#include <MacTypes.h>
39#include <TextUtils.h>
40#include <Folders.h>
41#include <Resources.h>
42#include <Aliases.h>
43#include <FixMath.h>
44#include <Timer.h>
45#include <OSA.h>
46#include <AppleScript.h>
47
48#include "lisp.h"
49#include "process.h"
50#include "sysselect.h"
51#include "systime.h"
52
53Lisp_Object QCLIPBOARD;
54
55/* An instance of the AppleScript component. */
56static ComponentInstance as_scripting_component;
57/* The single script context used for all script executions. */
58static OSAID as_script_context;
59
60
61/* When converting from Mac to Unix pathnames, /'s in folder names are
62 converted to :'s. This function, used in copying folder names,
63 performs a strncat and converts all character a to b in the copy of
64 the string s2 appended to the end of s1. */
65
66void
67string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
68{
69 int l1 = strlen (s1);
70 int l2 = strlen (s2);
71 char *p = s1 + l1;
72 int i;
73
74 strncat (s1, s2, n);
75 for (i = 0; i < l2; i++)
76 {
77 if (*p == a)
78 *p = b;
79 p++;
80 }
81}
82
83
84/* Convert a Mac pathname to Unix form. A Mac full pathname is one
85 that does not begin with a ':' and contains at least one ':'. A Mac
86 full pathname causes an '/' to be prepended to the Unix pathname.
87 The algorithm for the rest of the pathname is as follows:
88 For each segment between two ':',
89 if it is non-null, copy as is and then add a '/' at the end,
90 otherwise, insert a "../" into the Unix pathname.
91 Returns 1 if successful; 0 if fails. */
92
93int
94mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
95{
96 const char *p, *q, *pe;
97
98 strcpy (ufn, "");
99
100 if (*mfn == '\0')
101 return 1;
102
103 p = strchr (mfn, ':');
104 if (p != 0 && p != mfn) /* full pathname */
105 strcat (ufn, "/");
106
107 p = mfn;
108 if (*p == ':')
109 p++;
110
111 pe = mfn + strlen (mfn);
112 while (p < pe)
113 {
114 q = strchr (p, ':');
115 if (q)
116 {
117 if (q == p)
118 { /* two consecutive ':' */
119 if (strlen (ufn) + 3 >= ufnbuflen)
120 return 0;
121 strcat (ufn, "../");
122 }
123 else
124 {
125 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
126 return 0;
127 string_cat_and_replace (ufn, p, q - p, '/', ':');
128 strcat (ufn, "/");
129 }
130 p = q + 1;
131 }
132 else
133 {
134 if (strlen (ufn) + (pe - p) >= ufnbuflen)
135 return 0;
136 string_cat_and_replace (ufn, p, pe - p, '/', ':');
137 /* no separator for last one */
138 p = pe;
139 }
140 }
141
142 return 1;
143}
144
145
146extern char *get_temp_dir_name ();
147
148
149/* Convert a Unix pathname to Mac form. Approximately reverse of the
150 above in algorithm. */
151
152int
153posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
154{
155 const char *p, *q, *pe;
156 char expanded_pathname[MAXPATHLEN+1];
157
158 strcpy (mfn, "");
159
160 if (*ufn == '\0')
161 return 1;
162
163 p = ufn;
164
165 /* Check for and handle volume names. Last comparison: strangely
166 somewhere "/.emacs" is passed. A temporary fix for now. */
167 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
168 {
169 if (strlen (p) + 1 > mfnbuflen)
170 return 0;
171 strcpy (mfn, p+1);
172 strcat (mfn, ":");
173 return 1;
174 }
175
176 /* expand to emacs dir found by init_emacs_passwd_dir */
177 if (strncmp (p, "~emacs/", 7) == 0)
178 {
179 struct passwd *pw = getpwnam ("emacs");
180 p += 7;
181 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
182 return 0;
183 strcpy (expanded_pathname, pw->pw_dir);
184 strcat (expanded_pathname, p);
185 p = expanded_pathname;
186 /* now p points to the pathname with emacs dir prefix */
187 }
188 else if (strncmp (p, "/tmp/", 5) == 0)
189 {
190 char *t = get_temp_dir_name ();
191 p += 5;
192 if (strlen (t) + strlen (p) > MAXPATHLEN)
193 return 0;
194 strcpy (expanded_pathname, t);
195 strcat (expanded_pathname, p);
196 p = expanded_pathname;
197 /* now p points to the pathname with emacs dir prefix */
198 }
199 else if (*p != '/') /* relative pathname */
200 strcat (mfn, ":");
201
202 if (*p == '/')
203 p++;
204
205 pe = p + strlen (p);
206 while (p < pe)
207 {
208 q = strchr (p, '/');
209 if (q)
210 {
211 if (q - p == 2 && *p == '.' && *(p+1) == '.')
212 {
213 if (strlen (mfn) + 1 >= mfnbuflen)
214 return 0;
215 strcat (mfn, ":");
216 }
217 else
218 {
219 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
220 return 0;
221 string_cat_and_replace (mfn, p, q - p, ':', '/');
222 strcat (mfn, ":");
223 }
224 p = q + 1;
225 }
226 else
227 {
228 if (strlen (mfn) + (pe - p) >= mfnbuflen)
229 return 0;
230 string_cat_and_replace (mfn, p, pe - p, ':', '/');
231 p = pe;
232 }
233 }
234
235 return 1;
236}
237
238
239/* The following functions with "sys_" prefix are stubs to Unix
240 functions that have already been implemented by CW or MPW. The
241 calls to them in Emacs source course are #define'd to call the sys_
242 versions by the header files s-mac.h. In these stubs pathnames are
243 converted between their Unix and Mac forms. */
244
245
246/* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years
247 + 17 leap days. These are for adjusting time values returned by
248 MacOS Toolbox functions. */
249
250#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
251
252#ifdef __MWERKS__
253#ifndef CODEWARRIOR_VERSION_6
254/* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not
255 a leap year! This is for adjusting time_t values returned by MSL
256 functions. */
257#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
258#else
259/* CW changes Pro 6 to following Unix! */
260#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
261#endif
262#elif __MRC__
263/* MPW library functions follow Unix (confused?). */
264#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
265#else
266You lose!!!
267#endif
268
269
270/* Define our own stat function for both MrC and CW. The reason for
271 doing this: "stat" is both the name of a struct and function name:
272 can't use the same trick like that for sys_open, sys_close, etc. to
273 redirect Emacs's calls to our own version that converts Unix style
274 filenames to Mac style filename because all sorts of compilation
275 errors will be generated if stat is #define'd to be sys_stat. */
276
277int
278stat_noalias (const char *path, struct stat *buf)
279{
280 char mac_pathname[MAXPATHLEN+1];
281 CInfoPBRec cipb;
282
283 if (posix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0)
284 return -1;
285
286 c2pstr (mac_pathname);
287 cipb.hFileInfo.ioNamePtr = mac_pathname;
288 cipb.hFileInfo.ioVRefNum = 0;
289 cipb.hFileInfo.ioDirID = 0;
290 cipb.hFileInfo.ioFDirIndex = 0;
291 /* set to 0 to get information about specific dir or file */
292
293 errno = PBGetCatInfo (&cipb, false);
294 if (errno == -43) /* -43: fnfErr defined in Errors.h */
295 errno = ENOENT;
296 if (errno != noErr)
297 return -1;
298
299 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
300 {
301 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
302
303 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
304 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
305 buf->st_ino = cipb.dirInfo.ioDrDirID;
306 buf->st_dev = cipb.dirInfo.ioVRefNum;
307 buf->st_size = cipb.dirInfo.ioDrNmFls;
308 /* size of dir = number of files and dirs */
309 buf->st_atime
310 = buf->st_mtime
311 = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
312 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
313 }
314 else
315 {
316 buf->st_mode = S_IFREG | S_IREAD;
317 if (!(cipb.hFileInfo.ioFlAttrib & 0x1))
318 buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */
319 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
320 buf->st_mode |= S_IEXEC;
321 buf->st_ino = cipb.hFileInfo.ioDirID;
322 buf->st_dev = cipb.hFileInfo.ioVRefNum;
323 buf->st_size = cipb.hFileInfo.ioFlLgLen;
324 buf->st_atime
325 = buf->st_mtime
326 = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
327 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
328 }
329
330 if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000)
331 {
332 /* identify alias files as symlinks */
333 buf->st_mode &= ~S_IFREG;
334 buf->st_mode |= S_IFLNK;
335 }
336
337 buf->st_nlink = 1;
338 buf->st_uid = getuid ();
339 buf->st_gid = getgid ();
340 buf->st_rdev = 0;
341
342 return 0;
343}
344
345
346int
347lstat (const char *path, struct stat *buf)
348{
349 int result;
350 char true_pathname[MAXPATHLEN+1];
351
352 /* Try looking for the file without resolving aliases first. */
353 if ((result = stat_noalias (path, buf)) >= 0)
354 return result;
355
356 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
357 return -1;
358
359 return stat_noalias (true_pathname, buf);
360}
361
362
363int
364stat (const char *path, struct stat *sb)
365{
366 int result;
367 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
368 int len;
369
370 if ((result = stat_noalias (path, sb)) >= 0 &&
371 ! (sb->st_mode & S_IFLNK))
372 return result;
373
374 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
375 return -1;
376
377 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
378 if (len > -1)
379 {
380 fully_resolved_name[len] = '\0';
381 /* in fact our readlink terminates strings */
382 return lstat (fully_resolved_name, sb);
383 }
384 else
385 return lstat (true_pathname, sb);
386}
387
388
389#if __MRC__
390/* CW defines fstat in stat.mac.c while MPW does not provide this
391 function. Without the information of how to get from a file
392 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
393 to implement this function. Fortunately, there is only one place
394 where this function is called in our configuration: in fileio.c,
395 where only the st_dev and st_ino fields are used to determine
396 whether two fildes point to different i-nodes to prevent copying
397 a file onto itself equal. What we have here probably needs
398 improvement. */
399
400int
401fstat (int fildes, struct stat *buf)
402{
403 buf->st_dev = 0;
404 buf->st_ino = fildes;
405 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
406 return 0; /* success */
407}
408#endif /* __MRC__ */
409
410
411/* Adapted from Think Reference code example. */
412
413int
414mkdir (const char *dirname, int mode)
415{
416#pragma unused(mode)
417
418 HFileParam hfpb;
419 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
420
421 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
422 return -1;
423
424 if (posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
425 return -1;
426
427 c2pstr (mac_pathname);
428 hfpb.ioNamePtr = mac_pathname;
429 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
430 hfpb.ioDirID = 0; /* parent is the root */
431
432 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
433 /* just return the Mac OSErr code for now */
434 return errno == noErr ? 0 : -1;
435}
436
437
438#undef rmdir
439sys_rmdir (const char *dirname)
440{
441 HFileParam hfpb;
442 char mac_pathname[MAXPATHLEN+1];
443
444 if (posix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
445 return -1;
446
447 c2pstr (mac_pathname);
448 hfpb.ioNamePtr = mac_pathname;
449 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
450 hfpb.ioDirID = 0; /* parent is the root */
451
452 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
453 return errno == noErr ? 0 : -1;
454}
455
456
457#ifdef __MRC__
458/* No implementation yet. */
459int
460execvp (const char *path, ...)
461{
462 return -1;
463}
464#endif /* __MRC__ */
465
466
467int
468utime (const char *path, const struct utimbuf *times)
469{
470 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
471 int len;
472 char mac_pathname[MAXPATHLEN+1];
473 CInfoPBRec cipb;
474
475 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
476 return -1;
477
478 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
479 if (len > -1)
480 fully_resolved_name[len] = '\0';
481 else
482 strcpy (fully_resolved_name, true_pathname);
483
484 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
485 return -1;
486
487 c2pstr (mac_pathname);
488 cipb.hFileInfo.ioNamePtr = mac_pathname;
489 cipb.hFileInfo.ioVRefNum = 0;
490 cipb.hFileInfo.ioDirID = 0;
491 cipb.hFileInfo.ioFDirIndex = 0;
492 /* set to 0 to get information about specific dir or file */
493
494 errno = PBGetCatInfo (&cipb, false);
495 if (errno != noErr)
496 return -1;
497
498 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
499 {
500 if (times)
501 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
502 else
503 GetDateTime (&cipb.dirInfo.ioDrMdDat);
504 }
505 else
506 {
507 if (times)
508 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
509 else
510 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
511 }
512
513 errno = PBSetCatInfo (&cipb, false);
514 return errno == noErr ? 0 : -1;
515}
516
517
518#ifndef F_OK
519#define F_OK 0
520#endif
521#ifndef X_OK
522#define X_OK 1
523#endif
524#ifndef W_OK
525#define W_OK 2
526#endif
527
528/* Like stat, but test for access mode in hfpb.ioFlAttrib */
529int
530access (const char *path, int mode)
531{
532 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
533 int len;
534 char mac_pathname[MAXPATHLEN+1];
535 CInfoPBRec cipb;
536
537 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
538 return -1;
539
540 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
541 if (len > -1)
542 fully_resolved_name[len] = '\0';
543 else
544 strcpy (fully_resolved_name, true_pathname);
545
546 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
547 return -1;
548
549 c2pstr (mac_pathname);
550 cipb.hFileInfo.ioNamePtr = mac_pathname;
551 cipb.hFileInfo.ioVRefNum = 0;
552 cipb.hFileInfo.ioDirID = 0;
553 cipb.hFileInfo.ioFDirIndex = 0;
554 /* set to 0 to get information about specific dir or file */
555
556 errno = PBGetCatInfo (&cipb, false);
557 if (errno != noErr)
558 return -1;
559
560 if (mode == F_OK) /* got this far, file exists */
561 return 0;
562
563 if (mode & X_OK)
564 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
565 return 0;
566 else
567 {
568 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
569 return 0;
570 else
571 return -1;
572 }
573
574 if (mode & W_OK)
575 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
576 /* don't allow if lock bit is on */
577
578 return -1;
579}
580
581
582#define DEV_NULL_FD 0x10000
583
584#undef open
585int
586sys_open (const char *path, int oflag)
587{
588 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
589 int len;
590 char mac_pathname[MAXPATHLEN+1];
591
592 if (strcmp (path, "/dev/null") == 0)
593 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
594
595 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
596 return -1;
597
598 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
599 if (len > -1)
600 fully_resolved_name[len] = '\0';
601 else
602 strcpy (fully_resolved_name, true_pathname);
603
604 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
605 return -1;
606 else
607 {
608#ifdef __MRC__
609 int res = open (mac_pathname, oflag);
610 /* if (oflag == O_WRONLY || oflag == O_RDWR) */
611 if (oflag & O_CREAT)
612 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
613 return res;
614#else
615 return open (mac_pathname, oflag);
616#endif
617 }
618}
619
620
621#undef creat
622int
623sys_creat (const char *path, mode_t mode)
624{
625 char true_pathname[MAXPATHLEN+1];
626 int len;
627 char mac_pathname[MAXPATHLEN+1];
628
629 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
630 return -1;
631
632 if (!posix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
633 return -1;
634 else
635 {
636#ifdef __MRC__
637 int result = creat (mac_pathname);
638 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
639 return result;
640#else
641 return creat (mac_pathname, mode);
642#endif
643 }
644}
645
646
647#undef unlink
648int
649sys_unlink (const char *path)
650{
651 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
652 int len;
653 char mac_pathname[MAXPATHLEN+1];
654
655 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
656 return -1;
657
658 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
659 if (len > -1)
660 fully_resolved_name[len] = '\0';
661 else
662 strcpy (fully_resolved_name, true_pathname);
663
664 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
665 return -1;
666 else
667 return unlink (mac_pathname);
668}
669
670
671#undef read
672int
673sys_read (int fildes, char *buf, int count)
674{
675 if (fildes == 0) /* this should not be used for console input */
676 return -1;
677 else
678#ifdef CODEWARRIOR_VERSION_6
679 return _read (fildes, buf, count);
680#else
681 return read (fildes, buf, count);
682#endif
683}
684
685
686#undef write
687int
688sys_write (int fildes, const char *buf, int count)
689{
690 if (fildes == DEV_NULL_FD)
691 return count;
692 else
693#ifdef CODEWARRIOR_VERSION_6
694 return _write (fildes, buf, count);
695#else
696 return write (fildes, buf, count);
697#endif
698}
699
700
701#undef rename
702int
703sys_rename (const char * old_name, const char * new_name)
704{
705 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
706 char fully_resolved_old_name[MAXPATHLEN+1];
707 int len;
708 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
709
710 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
711 return -1;
712
713 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
714 if (len > -1)
715 fully_resolved_old_name[len] = '\0';
716 else
717 strcpy (fully_resolved_old_name, true_old_pathname);
718
719 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
720 return -1;
721
722 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
723 return 0;
724
725 if (!posix_to_mac_pathname (fully_resolved_old_name,
726 mac_old_name,
727 MAXPATHLEN+1))
728 return -1;
729
730 if (!posix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
731 return -1;
732
733 /* If a file with new_name already exists, rename deletes the old
734 file in Unix. CW version fails in these situation. So we add a
735 call to unlink here. */
736 (void) unlink (mac_new_name);
737
738 return rename (mac_old_name, mac_new_name);
739}
740
741
742#undef fopen
743extern FILE *fopen (const char *name, const char *mode);
744FILE *
745sys_fopen (const char *name, const char *mode)
746{
747 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
748 int len;
749 char mac_pathname[MAXPATHLEN+1];
750
751 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
752 return 0;
753
754 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
755 if (len > -1)
756 fully_resolved_name[len] = '\0';
757 else
758 strcpy (fully_resolved_name, true_pathname);
759
760 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
761 return 0;
762 else
763 {
764#ifdef __MRC__
765 if (mode[0] == 'w' || mode[0] == 'a')
766 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
767#endif
768 return fopen (mac_pathname, mode);
769 }
770}
771
772
773#include <Events.h>
774
775long target_ticks = 0;
776
777#ifdef __MRC__
778__sigfun alarm_signal_func = (__sigfun) 0;
779#elif __MWERKS__
780__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
781#else
782You lose!!!
783#endif
784
785
786/* These functions simulate SIG_ALRM. The stub for function signal
787 stores the signal handler function in alarm_signal_func if a
788 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
789 which emacs calls periodically. A pending alarm is represented by
790 a non-zero target_ticks value. check_alarm calls the handler
791 function pointed to by alarm_signal_func if one has been set up and
792 an alarm is pending. */
793
794void
795check_alarm ()
796{
797 if (target_ticks && TickCount () > target_ticks)
798 {
799 target_ticks = 0;
800 if (alarm_signal_func)
801 (*alarm_signal_func)(SIGALRM);
802 }
803}
804
805
806int
807select(n, rfds, wfds, efds, timeout)
808 int n;
809 SELECT_TYPE *rfds;
810 SELECT_TYPE *wfds;
811 SELECT_TYPE *efds;
812 struct timeval *timeout;
813{
814 EMACS_TIME end_time, now;
815 EventRecord e;
816
817 /* Can only handle wait for keyboard input. */
818 if (n > 1 || wfds || efds)
819 return -1;
820
821 EMACS_GET_TIME (end_time);
822 EMACS_ADD_TIME (end_time, end_time, *timeout);
823
824 do
825 {
826 /* Also return true if an event other than a keyDown has
827 occurred. This causes kbd_buffer_get_event in keyboard.c to
828 call read_avail_input which in turn calls XTread_socket to
829 poll for these events. Otherwise these never get processed
830 except but a very slow poll timer. */
831 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
832 return 1;
833
834 /* Also check movement of the mouse. */
835 {
836 Point mouse_pos;
837 static Point old_mouse_pos = {-1, -1};
838
839 GetMouse (&mouse_pos);
840 if (!EqualPt (mouse_pos, old_mouse_pos))
841 {
842 old_mouse_pos = mouse_pos;
843 return 1;
844 }
845 }
846
847 WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1 tic. by T.I.*/
848
849 EMACS_GET_TIME (now);
850 EMACS_SUB_TIME (now, end_time, now);
851 }
852 while (!EMACS_TIME_NEG_P (now));
853
854 return 0;
855}
856
857
858/* Called in sys_select to wait for an alarm signal to arrive. */
859
860int
861pause ()
862{
863 EventRecord e;
864 unsigned long tick;
865
866 if (!target_ticks) /* no alarm pending */
867 return -1;
868
869 if ( (tick = TickCount ()) < target_ticks )
870 WaitNextEvent (0, &e, target_ticks - tick, NULL); /* Accept no event; just wait. by T.I.*/
871
872 target_ticks = 0;
873 if (alarm_signal_func)
874 (*alarm_signal_func)(SIGALRM);
875
876 return 0;
877}
878
879
880int
881alarm (int seconds)
882{
883 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
884
885 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
886
887 return (remaining < 0) ? 0 : (unsigned int) remaining;
888}
889
890
891#undef signal
892#ifdef __MRC__
893extern __sigfun signal (int signal, __sigfun signal_func);
894__sigfun
895sys_signal (int signal_num, __sigfun signal_func)
896#elif __MWERKS__
897extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
898__signal_func_ptr
899sys_signal (int signal_num, __signal_func_ptr signal_func)
900#else
901 You lose!!!
902#endif
903{
904 if (signal_num != SIGALRM)
905 return signal (signal_num, signal_func);
906 else
907 {
908#ifdef __MRC__
909 __sigfun old_signal_func;
910#elif __MWERKS__
911 __signal_func_ptr old_signal_func;
912#else
913 You lose!!!
914#endif
915 old_signal_func = alarm_signal_func;
916 alarm_signal_func = signal_func;
917 return old_signal_func;
918 }
919}
920
921
922/* gettimeofday should return the amount of time (in a timeval
923 structure) since midnight today. The toolbox function Microseconds
924 returns the number of microseconds (in a UnsignedWide value) since
925 the machine was booted. Also making this complicated is WideAdd,
926 WideSubtract, etc. take wide values. */
927
928int
929gettimeofday (tp)
930 struct timeval *tp;
931{
932 static inited = 0;
933 static wide wall_clock_at_epoch, clicks_at_epoch;
934 UnsignedWide uw_microseconds;
935 wide w_microseconds;
936 time_t sys_time (time_t *);
937
938 /* If this function is called for the first time, record the number
939 of seconds since midnight and the number of microseconds since
940 boot at the time of this first call. */
941 if (!inited)
942 {
943 time_t systime;
944 inited = 1;
945 systime = sys_time (NULL);
946 /* Store microseconds since midnight in wall_clock_at_epoch. */
947 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
948 Microseconds (&uw_microseconds);
949 /* Store microseconds since boot in clicks_at_epoch. */
950 clicks_at_epoch.hi = uw_microseconds.hi;
951 clicks_at_epoch.lo = uw_microseconds.lo;
952 }
953
954 /* Get time since boot */
955 Microseconds (&uw_microseconds);
956
957 /* Convert to time since midnight*/
958 w_microseconds.hi = uw_microseconds.hi;
959 w_microseconds.lo = uw_microseconds.lo;
960 WideSubtract (&w_microseconds, &clicks_at_epoch);
961 WideAdd (&w_microseconds, &wall_clock_at_epoch);
962 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
963
964 return 0;
965}
966
967
968#ifdef __MRC__
969unsigned int
970sleep (unsigned int seconds)
971{
972 unsigned long time_up;
973 EventRecord e;
974
975 time_up = TickCount () + seconds * 60;
976 while (TickCount () < time_up)
977 {
978 /* Accept no event; just wait. by T.I. */
979 WaitNextEvent (0, &e, 30, NULL);
980 }
981
982 return (0);
983}
984#endif /* __MRC__ */
985
986
987/* The time functions adjust time values according to the difference
988 between the Unix and CW epoches. */
989
990#undef gmtime
991extern struct tm *gmtime (const time_t *);
992struct tm *
993sys_gmtime (const time_t *timer)
994{
995 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
996
997 return gmtime (&unix_time);
998}
999
1000
1001#undef localtime
1002extern struct tm *localtime (const time_t *);
1003struct tm *
1004sys_localtime (const time_t *timer)
1005{
1006#ifdef CODEWARRIOR_VERSION_6
1007 time_t unix_time = *timer;
1008#else
1009 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1010#endif
1011
1012 return localtime (&unix_time);
1013}
1014
1015
1016#undef ctime
1017extern char *ctime (const time_t *);
1018char *
1019sys_ctime (const time_t *timer)
1020{
1021#ifdef CODEWARRIOR_VERSION_6
1022 time_t unix_time = *timer;
1023#else
1024 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1025#endif
1026
1027 return ctime (&unix_time);
1028}
1029
1030
1031#undef time
1032extern time_t time (time_t *);
1033time_t
1034sys_time (time_t *timer)
1035{
1036#ifdef CODEWARRIOR_VERSION_6
1037 time_t mac_time = time (NULL);
1038#else
1039 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1040#endif
1041
1042 if (timer)
1043 *timer = mac_time;
1044
1045 return mac_time;
1046}
1047
1048
1049/* MPW strftime broken for "%p" format */
1050#ifdef __MRC__
1051#undef strftime
1052#include <time.h>
1053size_t
1054sys_strftime (char * s, size_t maxsize, const char * format,
1055 const struct tm * timeptr)
1056{
1057 if (strcmp (format, "%p") == 0)
1058 {
1059 if (maxsize < 3)
1060 return 0;
1061 if (timeptr->tm_hour < 12)
1062 {
1063 strcpy (s, "AM");
1064 return 2;
1065 }
1066 else
1067 {
1068 strcpy (s, "PM");
1069 return 2;
1070 }
1071 }
1072 else
1073 return strftime (s, maxsize, format, timeptr);
1074}
1075#endif /* __MRC__ */
1076
1077
1078/* no subprocesses, empty wait */
1079
1080int
1081wait (int pid)
1082{
1083 return 0;
1084}
1085
1086
1087void
1088croak (char *badfunc)
1089{
1090 printf ("%s not yet implemented\r\n", badfunc);
1091 exit (1);
1092}
1093
1094
1095char *
1096index (const char * str, int chr)
1097{
1098 return strchr (str, chr);
1099}
1100
1101
1102char *
1103mktemp (char *template)
1104{
1105 int len, k;
1106 static seqnum = 0;
1107
1108 len = strlen (template);
1109 k = len - 1;
1110 while (k >= 0 && template[k] == 'X')
1111 k--;
1112
1113 k++; /* make k index of first 'X' */
1114
1115 if (k < len)
1116 {
1117 /* Zero filled, number of digits equal to the number of X's. */
1118 sprintf (&template[k], "%0*d", len-k, seqnum++);
1119
1120 return template;
1121 }
1122 else
1123 return 0;
1124}
1125
1126
1127/* Emulate getpwuid, getpwnam and others. */
1128
1129#define PASSWD_FIELD_SIZE 256
1130
1131static char my_passwd_name[PASSWD_FIELD_SIZE];
1132static char my_passwd_dir[MAXPATHLEN+1];
1133
1134static struct passwd my_passwd =
1135{
1136 my_passwd_name,
1137 my_passwd_dir,
1138};
1139
1140
1141/* Initialized by main () in macterm.c to pathname of emacs directory. */
1142
1143char emacs_passwd_dir[MAXPATHLEN+1];
1144
1145char *
1146getwd (char *);
1147
1148void
1149init_emacs_passwd_dir ()
1150{
1151 int found = false;
1152
1153 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1154 {
1155 /* Need pathname of first ancestor that begins with "emacs"
1156 since Mac emacs application is somewhere in the emacs-*
1157 tree. */
1158 int len = strlen (emacs_passwd_dir);
1159 int j = len - 1;
1160 /* j points to the "/" following the directory name being
1161 compared. */
1162 int i = j - 1;
1163 while (i >= 0 && !found)
1164 {
1165 while (i >= 0 && emacs_passwd_dir[i] != '/')
1166 i--;
1167 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1168 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1169 if (found)
1170 emacs_passwd_dir[j+1] = '\0';
1171 else
1172 {
1173 j = i;
1174 i = j - 1;
1175 }
1176 }
1177 }
1178
1179 if (!found)
1180 {
1181 /* Setting to "/" probably won't work but set it to something
1182 anyway. */
1183 strcpy (emacs_passwd_dir, "/");
1184 strcpy (my_passwd_dir, "/");
1185 }
1186}
1187
1188
1189static struct passwd emacs_passwd =
1190{
1191 "emacs",
1192 emacs_passwd_dir,
1193};
1194
1195static int my_passwd_inited = 0;
1196
1197
1198static void
1199init_my_passwd ()
1200{
1201 char **owner_name;
1202
1203 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1204 directory where Emacs was started. */
1205
1206 owner_name = (char **) GetResource ('STR ',-16096);
1207 if (owner_name)
1208 {
1209 HLock (owner_name);
1210 BlockMove ((unsigned char *) *owner_name,
1211 (unsigned char *) my_passwd_name,
1212 *owner_name[0]+1);
1213 HUnlock (owner_name);
1214 p2cstr ((unsigned char *) my_passwd_name);
1215 }
1216 else
1217 my_passwd_name[0] = 0;
1218}
1219
1220
1221struct passwd *
1222getpwuid (uid_t uid)
1223{
1224 if (!my_passwd_inited)
1225 {
1226 init_my_passwd ();
1227 my_passwd_inited = 1;
1228 }
1229
1230 return &my_passwd;
1231}
1232
1233
1234struct passwd *
1235getpwnam (const char *name)
1236{
1237 if (strcmp (name, "emacs") == 0)
1238 return &emacs_passwd;
1239
1240 if (!my_passwd_inited)
1241 {
1242 init_my_passwd ();
1243 my_passwd_inited = 1;
1244 }
1245
1246 return &my_passwd;
1247}
1248
1249
1250/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1251 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1252 as in msdos.c. */
1253
1254
1255int
1256fork ()
1257{
1258 return -1;
1259}
1260
1261
1262int
1263kill (int x, int y)
1264{
1265 return -1;
1266}
1267
1268
1269void
1270sys_subshell ()
1271{
1272 error ("Can't spawn subshell");
1273}
1274
1275
1276int
1277sigsetmask (int x)
1278{
1279 return 0;
1280}
1281
1282
1283int
1284sigblock (int mask)
1285{
1286 return 0;
1287}
1288
1289
1290void
1291request_sigio (void)
1292{
1293}
1294
1295
1296void
1297unrequest_sigio (void)
1298{
1299}
1300
1301
1302int
1303setpgrp ()
1304{
1305 return 0;
1306}
1307
1308
1309/* No pipes yet. */
1310
1311int
1312pipe (int _fildes[2])
1313{
1314 errno = EACCES;
1315 return -1;
1316}
1317
1318
1319/* Hard and symbolic links. */
1320
1321int
1322symlink (const char *name1, const char *name2)
1323{
1324 errno = ENOENT;
1325 return -1;
1326}
1327
1328
1329int
1330link (const char *name1, const char *name2)
1331{
1332 errno = ENOENT;
1333 return -1;
1334}
1335
1336
1337/* Determine the path name of the file specified by VREFNUM, DIRID,
1338 and NAME and place that in the buffer PATH of length
1339 MAXPATHLEN. */
1340int
1341path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1342 long dir_id, ConstStr255Param name)
1343{
1344 Str255 dir_name;
1345 CInfoPBRec cipb;
1346 OSErr err;
1347
1348 if (strlen (name) > man_path_len)
1349 return 0;
1350
1351 memcpy (dir_name, name, name[0]+1);
1352 memcpy (path, name, name[0]+1);
1353 p2cstr (path);
1354
1355 cipb.dirInfo.ioDrParID = dir_id;
1356 cipb.dirInfo.ioNamePtr = dir_name;
1357
1358 do
1359 {
1360 cipb.dirInfo.ioVRefNum = vol_ref_num;
1361 cipb.dirInfo.ioFDirIndex = -1;
1362 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1363 /* go up to parent each time */
1364
1365 err = PBGetCatInfo (&cipb, false);
1366 if (err != noErr)
1367 return 0;
1368
1369 p2cstr (dir_name);
1370 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1371 return 0;
1372
1373 strcat (dir_name, ":");
1374 strcat (dir_name, path);
1375 /* attach to front since we're going up directory tree */
1376 strcpy (path, dir_name);
1377 }
1378 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1379 /* stop when we see the volume's root directory */
1380
1381 return 1; /* success */
1382}
1383
1384
1385int
1386readlink (const char *path, char *buf, int bufsiz)
1387{
1388 char mac_sym_link_name[MAXPATHLEN+1];
1389 OSErr err;
1390 FSSpec fsspec;
1391 Boolean target_is_folder, was_aliased;
1392 Str255 directory_name, mac_pathname;
1393 CInfoPBRec cipb;
1394
1395 if (posix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1396 return -1;
1397
1398 c2pstr (mac_sym_link_name);
1399 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1400 if (err != noErr)
1401 {
1402 errno = ENOENT;
1403 return -1;
1404 }
1405
1406 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1407 if (err != noErr || !was_aliased)
1408 {
1409 errno = ENOENT;
1410 return -1;
1411 }
1412
1413 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1414 fsspec.name) == 0)
1415 {
1416 errno = ENOENT;
1417 return -1;
1418 }
1419
1420 if (mac_to_posix_pathname (mac_pathname, buf, bufsiz) == 0)
1421 {
1422 errno = ENOENT;
1423 return -1;
1424 }
1425
1426 return strlen (buf);
1427}
1428
1429
1430/* Convert a path to one with aliases fully expanded. */
1431
1432static int
1433find_true_pathname (const char *path, char *buf, int bufsiz)
1434{
1435 char *q, temp[MAXPATHLEN+1];
1436 const char *p;
1437 int len;
1438
1439 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1440 return -1;
1441
1442 buf[0] = '\0';
1443
1444 p = path;
1445 if (*p == '/')
1446 q = strchr (p + 1, '/');
1447 else
1448 q = strchr (p, '/');
1449 len = 0; /* loop may not be entered, e.g., for "/" */
1450
1451 while (q)
1452 {
1453 strcpy (temp, buf);
1454 strncat (temp, p, q - p);
1455 len = readlink (temp, buf, bufsiz);
1456 if (len <= -1)
1457 {
1458 if (strlen (temp) + 1 > bufsiz)
1459 return -1;
1460 strcpy (buf, temp);
1461 }
1462 strcat (buf, "/");
1463 len++;
1464 p = q + 1;
1465 q = strchr(p, '/');
1466 }
1467
1468 if (len + strlen (p) + 1 >= bufsiz)
1469 return -1;
1470
1471 strcat (buf, p);
1472 return len + strlen (p);
1473}
1474
1475
1476mode_t
1477umask (mode_t numask)
1478{
1479 static mode_t mask = 022;
1480 mode_t oldmask = mask;
1481 mask = numask;
1482 return oldmask;
1483}
1484
1485
1486int
1487chmod (const char *path, mode_t mode)
1488{
1489 /* say it always succeed for now */
1490 return 0;
1491}
1492
1493
1494int
1495dup (int oldd)
1496{
1497#ifdef __MRC__
1498 return fcntl (oldd, F_DUPFD, 0);
1499#elif __MWERKS__
1500 /* current implementation of fcntl in fcntl.mac.c simply returns old
1501 descriptor */
1502 return fcntl (oldd, F_DUPFD);
1503#else
1504You lose!!!
1505#endif
1506}
1507
1508
1509/* This is from the original sysdep.c. Emulate BSD dup2. First close
1510 newd if it already exists. Then, attempt to dup oldd. If not
1511 successful, call dup2 recursively until we are, then close the
1512 unsuccessful ones. */
1513
1514int
1515dup2 (int oldd, int newd)
1516{
1517 int fd, ret;
1518
1519 close (newd);
1520
1521 fd = dup (oldd);
1522 if (fd == -1)
1523 return -1;
1524 if (fd == newd)
1525 return newd;
1526 ret = dup2 (oldd, newd);
1527 close (fd);
1528 return ret;
1529}
1530
1531
1532/* let it fail for now */
1533
1534char *
1535sbrk (int incr)
1536{
1537 return (char *) -1;
1538}
1539
1540
1541int
1542fsync (int fd)
1543{
1544 return 0;
1545}
1546
1547
1548int
1549ioctl (int d, int request, void *argp)
1550{
1551 return -1;
1552}
1553
1554
1555#ifdef __MRC__
1556int
1557isatty (int fildes)
1558{
1559 if (fildes >=0 && fildes <= 2)
1560 return 1;
1561 else
1562 return 0;
1563}
1564
1565
1566int
1567getgid ()
1568{
1569 return 100;
1570}
1571
1572
1573int
1574getegid ()
1575{
1576 return 100;
1577}
1578
1579
1580int
1581getuid ()
1582{
1583 return 200;
1584}
1585
1586
1587int
1588geteuid ()
1589{
1590 return 200;
1591}
1592#endif /* __MRC__ */
1593
1594
1595#ifdef __MWERKS__
1596#ifndef CODEWARRIOR_VERSION_6
1597#undef getpid
1598int
1599getpid ()
1600{
1601 return 9999;
1602}
1603#endif
1604#endif /* __MWERKS__ */
1605
1606
1607/* Return the path to the directory in which Emacs can create
1608 temporary files. The MacOS "temporary items" directory cannot be
1609 used because it removes the file written by a process when it
1610 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1611 again not exactly). And of course Emacs needs to read back the
1612 files written by its subprocesses. So here we write the files to a
1613 directory "Emacs" in the Preferences Folder. This directory is
1614 created if it does not exist. */
1615
1616static char *
1617get_temp_dir_name ()
1618{
1619 static char *temp_dir_name = NULL;
1620 short vol_ref_num;
1621 long dir_id;
1622 OSErr err;
1623 Str255 dir_name, full_path;
1624 CInfoPBRec cpb;
1625 char unix_dir_name[MAXPATHLEN+1];
1626 DIR *dir;
1627
1628 /* Cache directory name with pointer temp_dir_name.
1629 Look for it only the first time. */
1630 if (!temp_dir_name)
1631 {
1632 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1633 &vol_ref_num, &dir_id);
1634 if (err != noErr)
1635 return NULL;
1636
1637 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1638 return NULL;
1639
1640 if (strlen (full_path) + 6 <= MAXPATHLEN)
1641 strcat (full_path, "Emacs:");
1642 else
1643 return NULL;
1644
1645 if (!mac_to_posix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1646 return NULL;
1647
1648 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1649 if (dir)
1650 closedir (dir);
1651 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1652 return NULL;
1653
1654 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1655 strcpy (temp_dir_name, unix_dir_name);
1656 }
1657
1658 return temp_dir_name;
1659}
1660
1661
1662/* Allocate and construct an array of pointers to strings from a list
1663 of strings stored in a 'STR#' resource. The returned pointer array
1664 is stored in the style of argv and environ: if the 'STR#' resource
1665 contains numString strings, an pointer array with numString+1
1666 elements is returned in which the last entry contains a null
1667 pointer. The pointer to the pointer array is passed by pointer in
1668 parameter t. The resource ID of the 'STR#' resource is passed in
1669 parameter StringListID.
1670 */
1671
1672void
1673get_string_list (char ***t, short string_list_id)
1674{
1675 Handle h;
1676 Ptr p;
1677 int i, num_strings;
1678
1679 h = GetResource ('STR#', string_list_id);
1680 if (h)
1681 {
1682 HLock (h);
1683 p = *h;
1684 num_strings = * (short *) p;
1685 p += sizeof(short);
1686 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1687 for (i = 0; i < num_strings; i++)
1688 {
1689 short length = *p++;
1690 (*t)[i] = (char *) malloc (length + 1);
1691 strncpy ((*t)[i], p, length);
1692 (*t)[i][length] = '\0';
1693 p += length;
1694 }
1695 (*t)[num_strings] = 0;
1696 HUnlock (h);
1697 }
1698 else
1699 {
1700 /* Return no string in case GetResource fails. Bug fixed by
1701 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1702 option (no sym -on implies -opt local). */
1703 *t = (char **) malloc (sizeof (char *));
1704 (*t)[0] = 0;
1705 }
1706}
1707
1708
1709static char *
1710get_path_to_system_folder ()
1711{
1712 short vol_ref_num;
1713 long dir_id;
1714 OSErr err;
1715 Str255 dir_name, full_path;
1716 CInfoPBRec cpb;
1717 static char system_folder_unix_name[MAXPATHLEN+1];
1718 DIR *dir;
1719
1720 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1721 &vol_ref_num, &dir_id);
1722 if (err != noErr)
1723 return NULL;
1724
1725 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1726 return NULL;
1727
1728 if (!mac_to_posix_pathname (full_path, system_folder_unix_name, MAXPATHLEN+1))
1729 return NULL;
1730
1731 return system_folder_unix_name;
1732}
1733
1734
1735char **environ;
1736
1737#define ENVIRON_STRING_LIST_ID 128
1738
1739/* Get environment variable definitions from STR# resource. */
1740
1741void
1742init_environ ()
1743{
1744 int i;
1745
1746 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1747
1748 i = 0;
1749 while (environ[i])
1750 i++;
1751
1752 /* Make HOME directory the one Emacs starts up in if not specified
1753 by resource. */
1754 if (getenv ("HOME") == NULL)
1755 {
1756 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1757 if (environ)
1758 {
1759 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1760 if (environ[i])
1761 {
1762 strcpy (environ[i], "HOME=");
1763 strcat (environ[i], my_passwd_dir);
1764 }
1765 environ[i+1] = 0;
1766 i++;
1767 }
1768 }
1769
1770 /* Make HOME directory the one Emacs starts up in if not specified
1771 by resource. */
1772 if (getenv ("MAIL") == NULL)
1773 {
1774 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1775 if (environ)
1776 {
1777 char * path_to_system_folder = get_path_to_system_folder ();
1778 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1779 if (environ[i])
1780 {
1781 strcpy (environ[i], "MAIL=");
1782 strcat (environ[i], path_to_system_folder);
1783 strcat (environ[i], "Eudora Folder/In");
1784 }
1785 environ[i+1] = 0;
1786 }
1787 }
1788}
1789
1790
1791/* Return the value of the environment variable NAME. */
1792
1793char *
1794getenv (const char *name)
1795{
1796 int length = strlen(name);
1797 char **e;
1798
1799 for (e = environ; *e != 0; e++)
1800 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1801 return &(*e)[length + 1];
1802
1803 if (strcmp (name, "TMPDIR") == 0)
1804 return get_temp_dir_name ();
1805
1806 return 0;
1807}
1808
1809
1810#ifdef __MRC__
1811/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1812char *sys_siglist[] =
1813{
1814 "Zero is not a signal!!!",
1815 "Abort", /* 1 */
1816 "Interactive user interrupt", /* 2 */ "?",
1817 "Floating point exception", /* 4 */ "?", "?", "?",
1818 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1819 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1820 "?", "?", "?", "?", "?", "?", "?", "?",
1821 "Terminal" /* 32 */
1822};
1823#elif __MWERKS__
1824char *sys_siglist[] =
1825{
1826 "Zero is not a signal!!!",
1827 "Abort",
1828 "Floating point exception",
1829 "Illegal instruction",
1830 "Interactive user interrupt",
1831 "Segment violation",
1832 "Terminal"
1833};
1834#else
1835You lose!!!
1836#endif
1837
1838
1839#include <utsname.h>
1840
1841int
1842uname (struct utsname *name)
1843{
1844 char **system_name;
1845 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1846 if (system_name)
1847 {
1848 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1849 p2cstr (name->nodename);
1850 return 0;
1851 }
1852 else
1853 return -1;
1854}
1855
1856
1857#include <Processes.h>
1858#include <EPPC.h>
1859
1860/* Event class of HLE sent to subprocess. */
1861const OSType kEmacsSubprocessSend = 'ESND';
1862
1863/* Event class of HLE sent back from subprocess. */
1864const OSType kEmacsSubprocessReply = 'ERPY';
1865
1866
1867char *
1868mystrchr (char *s, char c)
1869{
1870 while (*s && *s != c)
1871 {
1872 if (*s == '\\')
1873 s++;
1874 s++;
1875 }
1876
1877 if (*s)
1878 {
1879 *s = '\0';
1880 return s;
1881 }
1882 else
1883 return NULL;
1884}
1885
1886
1887char *
1888mystrtok (char *s)
1889{
1890 while (*s)
1891 s++;
1892
1893 return s + 1;
1894}
1895
1896
1897void
1898mystrcpy (char *to, char *from)
1899{
1900 while (*from)
1901 {
1902 if (*from == '\\')
1903 from++;
1904 *to++ = *from++;
1905 }
1906 *to = '\0';
1907}
1908
1909
1910/* Start a Mac subprocess. Arguments for it is passed in argv (null
1911 terminated). The process should run with the default directory
1912 "workdir", read input from "infn", and write output and error to
1913 "outfn" and "errfn", resp. The Process Manager call
1914 LaunchApplication is used to start the subprocess. We use high
1915 level events as the mechanism to pass arguments to the subprocess
1916 and to make Emacs wait for the subprocess to terminate and pass
1917 back a result code. The bulk of the code here packs the arguments
1918 into one message to be passed together with the high level event.
1919 Emacs also sometimes starts a subprocess using a shell to perform
1920 wildcard filename expansion. Since we don't really have a shell on
1921 the Mac, this case is detected and the starting of the shell is
1922 by-passed. We really need to add code here to do filename
1923 expansion to support such functionality. */
1924
1925int
1926run_mac_command (argv, workdir, infn, outfn, errfn)
1927 unsigned char **argv;
1928 const char *workdir;
1929 const char *infn, *outfn, *errfn;
1930{
1931 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1932 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1933 int paramlen, argc, newargc, j, retries;
1934 char **newargv, *param, *p;
1935 OSErr iErr;
1936 FSSpec spec;
1937 LaunchParamBlockRec lpbr;
1938 EventRecord send_event, reply_event;
1939 RgnHandle cursor_region_handle;
1940 TargetID targ;
1941 unsigned long ref_con, len;
1942
1943 if (posix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1944 return -1;
1945 if (posix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1946 return -1;
1947 if (posix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1948 return -1;
1949 if (posix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1950 return -1;
1951
1952 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
1953 + strlen (macerrfn) + 4; /* count nulls at end of strings */
1954
1955 argc = 0;
1956 while (argv[argc])
1957 argc++;
1958
1959 if (argc == 0)
1960 return -1;
1961
1962 /* If a subprocess is invoked with a shell, we receive 3 arguments
1963 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1964 bins>/<command> <command args>" */
1965 j = strlen (argv[0]);
1966 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
1967 && argc == 3 && strcmp (argv[1], "-c") == 0)
1968 {
1969 char *command, *t, tempmacpathname[MAXPATHLEN+1];
1970
1971 /* The arguments for the command in argv[2] are separated by
1972 spaces. Count them and put the count in newargc. */
1973 command = (char *) alloca (strlen (argv[2])+2);
1974 strcpy (command, argv[2]);
1975 if (command[strlen (command) - 1] != ' ')
1976 strcat (command, " ");
1977
1978 t = command;
1979 newargc = 0;
1980 t = mystrchr (t, ' ');
1981 while (t)
1982 {
1983 newargc++;
1984 t = mystrchr (t+1, ' ');
1985 }
1986
1987 newargv = (char **) alloca (sizeof (char *) * newargc);
1988
1989 t = command;
1990 for (j = 0; j < newargc; j++)
1991 {
1992 newargv[j] = (char *) alloca (strlen (t) + 1);
1993 mystrcpy (newargv[j], t);
1994
1995 t = mystrtok (t);
1996 paramlen += strlen (newargv[j]) + 1;
1997 }
1998
1999 if (strncmp (newargv[0], "~emacs/", 7) == 0)
2000 {
2001 if (posix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
2002 == 0)
2003 return -1;
2004 }
2005 else
2006 { /* sometimes Emacs call "sh" without a path for the command */
2007#if 0
2008 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
2009 strcpy (t, "~emacs/");
2010 strcat (t, newargv[0]);
2011#endif
2012 Lisp_Object path;
2013 openp (Vexec_path, build_string (newargv[0]), Vexec_suffixes, &path,
2014 1);
2015
2016 if (NILP (path))
2017 return -1;
2018 if (posix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
2019 MAXPATHLEN+1) == 0)
2020 return -1;
2021 }
2022 strcpy (macappname, tempmacpathname);
2023 }
2024 else
2025 {
2026 if (posix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2027 return -1;
2028
2029 newargv = (char **) alloca (sizeof (char *) * argc);
2030 newargc = argc;
2031 for (j = 1; j < argc; j++)
2032 {
2033 if (strncmp (argv[j], "~emacs/", 7) == 0)
2034 {
2035 char *t = strchr (argv[j], ' ');
2036 if (t)
2037 {
2038 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2039 strncpy (tempcmdname, argv[j], t-argv[j]);
2040 tempcmdname[t-argv[j]] = '\0';
2041 if (posix_to_mac_pathname (tempcmdname, tempmaccmdname,
2042 MAXPATHLEN+1) == 0)
2043 return -1;
2044 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2045 + strlen (t) + 1);
2046 strcpy (newargv[j], tempmaccmdname);
2047 strcat (newargv[j], t);
2048 }
2049 else
2050 {
2051 char tempmaccmdname[MAXPATHLEN+1];
2052 if (posix_to_mac_pathname (argv[j], tempmaccmdname,
2053 MAXPATHLEN+1) == 0)
2054 return -1;
2055 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2056 strcpy (newargv[j], tempmaccmdname);
2057 }
2058 }
2059 else
2060 newargv[j] = argv[j];
2061 paramlen += strlen (newargv[j]) + 1;
2062 }
2063 }
2064
2065 /* After expanding all the arguments, we now know the length of the
2066 parameter block to be sent to the subprocess as a message
2067 attached to the HLE. */
2068 param = (char *) malloc (paramlen + 1);
2069 if (!param)
2070 return -1;
2071
2072 p = param;
2073 *p++ = newargc;
2074 /* first byte of message contains number of arguments for command */
2075 strcpy (p, macworkdir);
2076 p += strlen (macworkdir);
2077 *p++ = '\0';
2078 /* null terminate strings sent so it's possible to use strcpy over there */
2079 strcpy (p, macinfn);
2080 p += strlen (macinfn);
2081 *p++ = '\0';
2082 strcpy (p, macoutfn);
2083 p += strlen (macoutfn);
2084 *p++ = '\0';
2085 strcpy (p, macerrfn);
2086 p += strlen (macerrfn);
2087 *p++ = '\0';
2088 for (j = 1; j < newargc; j++)
2089 {
2090 strcpy (p, newargv[j]);
2091 p += strlen (newargv[j]);
2092 *p++ = '\0';
2093 }
2094
2095 c2pstr (macappname);
2096
2097 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2098
2099 if (iErr != noErr)
2100 {
2101 free (param);
2102 return -1;
2103 }
2104
2105 lpbr.launchBlockID = extendedBlock;
2106 lpbr.launchEPBLength = extendedBlockLen;
2107 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2108 lpbr.launchAppSpec = &spec;
2109 lpbr.launchAppParameters = NULL;
2110
2111 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2112 if (iErr != noErr)
2113 {
2114 free (param);
2115 return -1;
2116 }
2117
2118 send_event.what = kHighLevelEvent;
2119 send_event.message = kEmacsSubprocessSend;
2120 /* Event ID stored in "where" unused */
2121
2122 retries = 3;
2123 /* OS may think current subprocess has terminated if previous one
2124 terminated recently. */
2125 do
2126 {
2127 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2128 paramlen + 1, receiverIDisPSN);
2129 }
2130 while (iErr == sessClosedErr && retries-- > 0);
2131
2132 if (iErr != noErr)
2133 {
2134 free (param);
2135 return -1;
2136 }
2137
2138 cursor_region_handle = NewRgn ();
2139
2140 /* Wait for the subprocess to finish, when it will send us a ERPY
2141 high level event. */
2142 while (1)
2143 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2144 cursor_region_handle)
2145 && reply_event.message == kEmacsSubprocessReply)
2146 break;
2147
2148 /* The return code is sent through the refCon */
2149 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2150 if (iErr != noErr)
2151 {
2152 DisposeHandle ((Handle) cursor_region_handle);
2153 free (param);
2154 return -1;
2155 }
2156
2157 DisposeHandle ((Handle) cursor_region_handle);
2158 free (param);
2159
2160 return ref_con;
2161}
2162
2163
2164DIR *
2165opendir (const char *dirname)
2166{
2167 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2168 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2169 DIR *dirp;
2170 CInfoPBRec cipb;
2171 HVolumeParam vpb;
2172 int len, vol_name_len;
2173
2174 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2175 return 0;
2176
2177 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2178 if (len > -1)
2179 fully_resolved_name[len] = '\0';
2180 else
2181 strcpy (fully_resolved_name, true_pathname);
2182
2183 dirp = (DIR *) malloc (sizeof(DIR));
2184 if (!dirp)
2185 return 0;
2186
2187 /* Handle special case when dirname is "/": sets up for readir to
2188 get all mount volumes. */
2189 if (strcmp (fully_resolved_name, "/") == 0)
2190 {
2191 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2192 dirp->current_index = 1; /* index for first volume */
2193 return dirp;
2194 }
2195
2196 /* Handle typical cases: not accessing all mounted volumes. */
2197 if (!posix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2198 return 0;
2199
2200 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2201 len = strlen (mac_pathname);
2202 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2203 strcat (mac_pathname, ":");
2204
2205 /* Extract volume name */
2206 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2207 strncpy (vol_name, mac_pathname, vol_name_len);
2208 vol_name[vol_name_len] = '\0';
2209 strcat (vol_name, ":");
2210
2211 c2pstr (mac_pathname);
2212 cipb.hFileInfo.ioNamePtr = mac_pathname;
2213 /* using full pathname so vRefNum and DirID ignored */
2214 cipb.hFileInfo.ioVRefNum = 0;
2215 cipb.hFileInfo.ioDirID = 0;
2216 cipb.hFileInfo.ioFDirIndex = 0;
2217 /* set to 0 to get information about specific dir or file */
2218
2219 errno = PBGetCatInfo (&cipb, false);
2220 if (errno != noErr)
2221 {
2222 errno = ENOENT;
2223 return 0;
2224 }
2225
2226 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2227 return 0; /* not a directory */
2228
2229 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2230 dirp->getting_volumes = 0;
2231 dirp->current_index = 1; /* index for first file/directory */
2232
2233 c2pstr (vol_name);
2234 vpb.ioNamePtr = vol_name;
2235 /* using full pathname so vRefNum and DirID ignored */
2236 vpb.ioVRefNum = 0;
2237 vpb.ioVolIndex = -1;
2238 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2239 if (errno != noErr)
2240 {
2241 errno = ENOENT;
2242 return 0;
2243 }
2244
2245 dirp->vol_ref_num = vpb.ioVRefNum;
2246
2247 return dirp;
2248}
2249
2250int
2251closedir (DIR *dp)
2252{
2253 free (dp);
2254
2255 return 0;
2256}
2257
2258
2259struct dirent *
2260readdir (DIR *dp)
2261{
2262 HParamBlockRec hpblock;
2263 CInfoPBRec cipb;
2264 static struct dirent s_dirent;
2265 static Str255 s_name;
2266 int done;
2267 char *p;
2268
2269 /* Handle the root directory containing the mounted volumes. Call
2270 PBHGetVInfo specifying an index to obtain the info for a volume.
2271 PBHGetVInfo returns an error when it receives an index beyond the
2272 last volume, at which time we should return a nil dirent struct
2273 pointer. */
2274 if (dp->getting_volumes)
2275 {
2276 hpblock.volumeParam.ioNamePtr = s_name;
2277 hpblock.volumeParam.ioVRefNum = 0;
2278 hpblock.volumeParam.ioVolIndex = dp->current_index;
2279
2280 errno = PBHGetVInfo (&hpblock, false);
2281 if (errno != noErr)
2282 {
2283 errno = ENOENT;
2284 return 0;
2285 }
2286
2287 p2cstr (s_name);
2288 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2289
2290 dp->current_index++;
2291
2292 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2293 s_dirent.d_name = s_name;
2294
2295 return &s_dirent;
2296 }
2297 else
2298 {
2299 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2300 cipb.hFileInfo.ioNamePtr = s_name;
2301 /* location to receive filename returned */
2302
2303 /* return only visible files */
2304 done = false;
2305 while (!done)
2306 {
2307 cipb.hFileInfo.ioDirID = dp->dir_id;
2308 /* directory ID found by opendir */
2309 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2310
2311 errno = PBGetCatInfo (&cipb, false);
2312 if (errno != noErr)
2313 {
2314 errno = ENOENT;
2315 return 0;
2316 }
2317
2318 /* insist on an visibile entry */
2319 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2320 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2321 else
2322 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2323
2324 dp->current_index++;
2325 }
2326
2327 p2cstr (s_name);
2328
2329 p = s_name;
2330 while (*p)
2331 {
2332 if (*p == '/')
2333 *p = ':';
2334 p++;
2335 }
2336
2337 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2338 /* value unimportant: non-zero for valid file */
2339 s_dirent.d_name = s_name;
2340
2341 return &s_dirent;
2342 }
2343}
2344
2345
2346char *
2347getwd (char *path)
2348{
2349 char mac_pathname[MAXPATHLEN+1];
2350 Str255 directory_name;
2351 OSErr errno;
2352 CInfoPBRec cipb;
2353
2354 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2355 return NULL;
2356
2357 if (mac_to_posix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2358 return 0;
2359 else
2360 return path;
2361}
2362
2363
2364void
2365initialize_applescript ()
2366{
2367 AEDesc null_desc;
2368 OSAError osaerror;
2369
2370 /* if open fails, as_scripting_component is set to NULL. Its
2371 subsequent use in OSA calls will fail with badComponentInstance
2372 error. */
2373 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2374 kAppleScriptSubtype);
2375
2376 null_desc.descriptorType = typeNull;
2377 null_desc.dataHandle = 0;
2378 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2379 kOSANullScript, &as_script_context);
2380 if (osaerror)
2381 as_script_context = kOSANullScript;
2382 /* use default context if create fails */
2383}
2384
2385
2386void terminate_applescript()
2387{
2388 OSADispose (as_scripting_component, as_script_context);
2389 CloseComponent (as_scripting_component);
2390}
2391
2392
2393/* Compile and execute the AppleScript SCRIPT and return the error
2394 status as function value. A zero is returned if compilation and
2395 execution is successful, in which case RESULT returns a pointer to
2396 a string containing the resulting script value. Otherwise, the Mac
2397 error code is returned and RESULT returns a pointer to an error
2398 string. In both cases the caller should deallocate the storage
2399 used by the string pointed to by RESULT if it is non-NULL. For
2400 documentation on the MacOS scripting architecture, see Inside
2401 Macintosh - Interapplication Communications: Scripting Components. */
2402
2403static long
2404do_applescript (char *script, char **result)
2405{
2406 AEDesc script_desc, result_desc, error_desc;
2407 OSErr error;
2408 OSAError osaerror;
2409 long length;
2410
2411 *result = 0;
2412
2413 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2414 if (error)
2415 return error;
2416
2417 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2418 typeChar, kOSAModeNull, &result_desc);
2419
2420 if (osaerror == errOSAScriptError)
2421 {
2422 /* error executing AppleScript: retrieve error message */
2423 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2424 &error_desc))
2425 {
2426 HLock (error_desc.dataHandle);
2427 length = GetHandleSize(error_desc.dataHandle);
2428 *result = (char *) xmalloc (length + 1);
2429 if (*result)
2430 {
2431 memcpy (*result, *(error_desc.dataHandle), length);
2432 *(*result + length) = '\0';
2433 }
2434 HUnlock (error_desc.dataHandle);
2435 AEDisposeDesc (&error_desc);
2436 }
2437 }
2438 else if (osaerror == noErr) /* success: retrieve resulting script value */
2439 {
2440 HLock (result_desc.dataHandle);
2441 length = GetHandleSize(result_desc.dataHandle);
2442 *result = (char *) xmalloc (length + 1);
2443 if (*result)
2444 {
2445 memcpy (*result, *(result_desc.dataHandle), length);
2446 *(*result + length) = '\0';
2447 }
2448 HUnlock (result_desc.dataHandle);
2449 }
2450
2451 AEDisposeDesc (&script_desc);
2452 AEDisposeDesc (&result_desc);
2453
2454 return osaerror;
2455}
2456
2457
2458DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2459 "Compile and execute AppleScript SCRIPT and retrieve and return the\n\
2460result. If compilation and execution are successful, the resulting script\n\
2461value is returned as a string. Otherwise the function aborts and\n\
2462displays the error message returned by the AppleScript scripting\n\
2463component.")
2464 (script)
2465 Lisp_Object script;
2466{
2467 char *result, *temp;
2468 Lisp_Object lisp_result;
2469 long status;
2470
2471 CHECK_STRING (script, 0);
2472
2473 status = do_applescript (XSTRING (script)->data, &result);
2474 if (status)
2475 {
2476 if (!result)
2477 error ("AppleScript error %ld", status);
2478 else
2479 {
2480 /* Unfortunately only OSADoScript in do_applescript knows how
2481 how large the resulting script value or error message is
2482 going to be and therefore as caller memory must be
2483 deallocated here. It is necessary to free the error
2484 message before calling error to avoid a memory leak. */
2485 temp = (char *) alloca (strlen (result) + 1);
2486 strcpy (temp, result);
2487 xfree (result);
2488 error (temp);
2489 }
2490 }
2491 else
2492 {
2493 lisp_result = build_string (result);
2494 xfree (result);
2495 return lisp_result;
2496 }
2497}
2498
2499
2500DEFUN ("mac-file-name-to-posix", Fmac_file_name_to_posix, Smac_file_name_to_posix, 1,
2501 1, 0,
2502 "Convert Macintosh filename to Posix form.")
2503 (mac_filename)
2504 Lisp_Object mac_filename;
2505{
2506 char posix_filename[MAXPATHLEN+1];
2507
2508 CHECK_STRING (mac_filename, 0);
2509
2510 if (mac_to_posix_pathname (XSTRING (mac_filename)->data, posix_filename,
2511 MAXPATHLEN))
2512 return build_string (posix_filename);
2513 else
2514 return Qnil;
2515}
2516
2517
2518DEFUN ("posix-file-name-to-mac", Fposix_file_name_to_mac, Sposix_file_name_to_mac, 1,
2519 1, 0,
2520 "Convert Unix filename to Mac form.")
2521 (posix_filename)
2522 Lisp_Object posix_filename;
2523{
2524 char mac_filename[MAXPATHLEN+1];
2525
2526 CHECK_STRING (posix_filename, 0);
2527
2528 if (posix_to_mac_pathname (XSTRING (posix_filename)->data, mac_filename,
2529 MAXPATHLEN))
2530 return build_string (mac_filename);
2531 else
2532 return Qnil;
2533}
2534
2535
2536/* set interprogram-paste-function to mac-paste-function in mac-win.el
2537 to enable Emacs to obtain the contents of the Mac clipboard. */
2538DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2539 "Return the contents of the Mac clipboard as a string.")
2540 ()
2541{
2542 Lisp_Object value;
2543 Handle my_handle;
2544 long scrap_offset, rc, i;
2545
2546 my_handle = NewHandle (0); /* allocate 0-length data area */
2547
2548 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2549 if (rc < 0)
2550 return Qnil;
2551
2552 HLock (my_handle);
2553
2554 /* Emacs expects clipboard contents have Unix-style eol's */
2555 for (i = 0; i < rc; i++)
2556 if ((*my_handle)[i] == '\r')
2557 (*my_handle)[i] = '\n';
2558
2559 value = make_string (*my_handle, rc);
2560
2561 HUnlock (my_handle);
2562
2563 DisposeHandle (my_handle);
2564
2565 return value;
2566}
2567
2568
2569/* set interprogram-cut-function to mac-cut-function in mac-win.el
2570 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2571DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2572 "Put the value of the string parameter to the Mac clipboard.")
2573 (value, push)
2574 Lisp_Object value, push;
2575{
2576 char *buf;
2577 int len, i;
2578
2579 /* fixme: ignore the push flag for now */
2580
2581 CHECK_STRING (value, 0);
2582
2583 len = XSTRING (value)->size;
2584 buf = (char *) alloca (len);
2585 bcopy(XSTRING (value)->data, buf, len);
2586
2587 /* convert to Mac-style eol's before sending to clipboard */
2588 for (i = 0; i < len; i++)
2589 if (buf[i] == '\n')
2590 buf[i] = '\r';
2591
2592 ZeroScrap ();
2593 PutScrap (len, 'TEXT', buf);
2594
2595 return Qnil;
2596}
2597
2598
2599DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2600 0, 1, 0,
2601 "Whether there is an owner for the given X Selection.\n\
2602The arg should be the name of the selection in question, typically one of\n\
2603the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
2604\(Those are literal upper-case symbol names, since that's what X expects.)\n\
2605For convenience, the symbol nil is the same as `PRIMARY',\n\
2606and t is the same as `SECONDARY'.")
2607 (selection)
2608 Lisp_Object selection;
2609{
2610 CHECK_SYMBOL (selection, 0);
2611
2612 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2613 if the clipboard currently has valid text format contents. */
2614
2615 if (EQ (selection, QCLIPBOARD))
2616 {
2617 Lisp_Object val = Qnil;
2618 Lisp_Object value;
2619 Handle my_handle;
2620 long rc, scrap_offset;
2621
2622 my_handle = NewHandle (0);
2623
2624 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2625 if (rc >= 0)
2626 val = Qt;
2627
2628 DisposeHandle (my_handle);
2629
2630 return val;
2631 }
2632 return Qnil;
2633}
2634
2635
2636void
2637syms_of_mac ()
2638{
2639 QCLIPBOARD = intern ("CLIPBOARD");
2640 staticpro (&QCLIPBOARD);
2641
2642 defsubr (&Smac_paste_function);
2643 defsubr (&Smac_cut_function);
2644 defsubr (&Sx_selection_exists_p);
2645
2646 defsubr (&Sdo_applescript);
2647 defsubr (&Smac_file_name_to_posix);
2648 defsubr (&Sposix_file_name_to_mac);
2649}
diff --git a/mac/src/macfns.c b/mac/src/macfns.c
deleted file mode 100644
index fc0cf27a13b..00000000000
--- a/mac/src/macfns.c
+++ /dev/null
@@ -1,10112 +0,0 @@
1/* Graphical user interface functions for Mac OS.
2 Copyright (C) 2000 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */
22
23#include <config.h>
24
25#include <signal.h>
26#include <stdio.h>
27#include <math.h>
28#include <limits.h>
29#include <errno.h>
30
31#include "lisp.h"
32#include "charset.h"
33#include "macterm.h"
34#include "frame.h"
35#include "window.h"
36#include "buffer.h"
37#include "dispextern.h"
38#include "fontset.h"
39#include "intervals.h"
40#include "keyboard.h"
41#include "blockinput.h"
42#include "epaths.h"
43#include "termhooks.h"
44#include "coding.h"
45#include "ccl.h"
46#include "systime.h"
47
48/* #include "bitmaps/gray.xbm" */
49#define gray_width 2
50#define gray_height 2
51static unsigned char gray_bits[] = {
52 0x01, 0x02};
53
54/*#include <commdlg.h>
55#include <shellapi.h>*/
56#include <ctype.h>
57
58#include <stdlib.h>
59#include <string.h>
60#include <alloca.h>
61#if 0
62#include <unistd.h>
63#endif
64
65#include <Windows.h>
66#include <Gestalt.h>
67#include <TextUtils.h>
68
69#ifndef min
70#define min(a,b) ((a) < (b) ? (a) : (b))
71#endif
72#ifndef max
73#define max(a,b) ((a) > (b) ? (a) : (b))
74#endif
75
76/*extern void free_frame_menubar ();
77extern void x_compute_fringe_widths (struct frame *, int);
78extern double atof ();
79extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
80extern int quit_char;*/
81
82/* A definition of XColor for non-X frames. */
83#ifndef HAVE_X_WINDOWS
84typedef struct {
85 unsigned long pixel;
86 unsigned short red, green, blue;
87 char flags;
88 char pad;
89} XColor;
90#endif
91
92extern char *lispy_function_keys[];
93
94/* The gray bitmap `bitmaps/gray'. This is done because macterm.c uses
95 it, and including `bitmaps/gray' more than once is a problem when
96 config.h defines `static' as an empty replacement string. */
97
98int gray_bitmap_width = gray_width;
99int gray_bitmap_height = gray_height;
100unsigned char *gray_bitmap_bits = gray_bits;
101
102/* The name we're using in resource queries. */
103
104Lisp_Object Vx_resource_name;
105
106/* Non-zero means we're allowed to display an hourglass cursor. */
107
108int display_hourglass_p;
109
110/* The background and shape of the mouse pointer, and shape when not
111 over text or in the modeline. */
112
113Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
114Lisp_Object Vx_hourglass_pointer_shape;
115
116/* The shape when over mouse-sensitive text. */
117
118Lisp_Object Vx_sensitive_text_pointer_shape;
119
120/* If non-nil, the pointer shape to indicate that windows can be
121 dragged horizontally. */
122
123Lisp_Object Vx_window_horizontal_drag_shape;
124
125/* Color of chars displayed in cursor box. */
126
127Lisp_Object Vx_cursor_fore_pixel;
128
129/* Nonzero if using Windows. */
130
131static int mac_in_use;
132
133/* Non nil if no window manager is in use. */
134
135Lisp_Object Vx_no_window_manager;
136
137/* Search path for bitmap files. */
138
139Lisp_Object Vx_bitmap_file_path;
140
141/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
142
143Lisp_Object Vx_pixel_size_width_font_regexp;
144
145/* Evaluate this expression to rebuild the section of syms_of_macfns
146 that initializes and staticpros the symbols declared below. Note
147 that Emacs 18 has a bug that keeps C-x C-e from being able to
148 evaluate this expression.
149
150(progn
151 ;; Accumulate a list of the symbols we want to initialize from the
152 ;; declarations at the top of the file.
153 (goto-char (point-min))
154 (search-forward "/\*&&& symbols declared here &&&*\/\n")
155 (let (symbol-list)
156 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
157 (setq symbol-list
158 (cons (buffer-substring (match-beginning 1) (match-end 1))
159 symbol-list))
160 (forward-line 1))
161 (setq symbol-list (nreverse symbol-list))
162 ;; Delete the section of syms_of_... where we initialize the symbols.
163 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
164 (let ((start (point)))
165 (while (looking-at "^ Q")
166 (forward-line 2))
167 (kill-region start (point)))
168 ;; Write a new symbol initialization section.
169 (while symbol-list
170 (insert (format " %s = intern (\"" (car symbol-list)))
171 (let ((start (point)))
172 (insert (substring (car symbol-list) 1))
173 (subst-char-in-region start (point) ?_ ?-))
174 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
175 (setq symbol-list (cdr symbol-list)))))
176
177 */
178
179/*&&& symbols declared here &&&*/
180Lisp_Object Qauto_raise;
181Lisp_Object Qauto_lower;
182Lisp_Object Qbar;
183Lisp_Object Qborder_color;
184Lisp_Object Qborder_width;
185Lisp_Object Qbox;
186Lisp_Object Qcursor_color;
187Lisp_Object Qcursor_type;
188Lisp_Object Qgeometry;
189Lisp_Object Qicon_left;
190Lisp_Object Qicon_top;
191Lisp_Object Qicon_type;
192Lisp_Object Qicon_name;
193Lisp_Object Qinternal_border_width;
194Lisp_Object Qleft;
195Lisp_Object Qright;
196Lisp_Object Qmouse_color;
197Lisp_Object Qnone;
198Lisp_Object Qparent_id;
199Lisp_Object Qscroll_bar_width;
200Lisp_Object Qsuppress_icon;
201Lisp_Object Qundefined_color;
202Lisp_Object Qvertical_scroll_bars;
203Lisp_Object Qvisibility;
204Lisp_Object Qwindow_id;
205Lisp_Object Qx_frame_parameter;
206Lisp_Object Qx_resource_name;
207Lisp_Object Quser_position;
208Lisp_Object Quser_size;
209Lisp_Object Qscreen_gamma;
210Lisp_Object Qline_spacing;
211Lisp_Object Qcenter;
212Lisp_Object Qcancel_timer;
213Lisp_Object Qhyper;
214Lisp_Object Qsuper;
215Lisp_Object Qmeta;
216Lisp_Object Qalt;
217Lisp_Object Qctrl;
218Lisp_Object Qcontrol;
219Lisp_Object Qshift;
220
221extern Lisp_Object Qtop;
222extern Lisp_Object Qdisplay;
223Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
224extern Lisp_Object Qtool_bar_lines;
225
226/* These are defined in frame.c. */
227extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
228extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
229extern Lisp_Object Qtool_bar_lines;
230
231extern Lisp_Object Vwindow_system_version;
232
233Lisp_Object Qface_set_after_frame_default;
234
235/* Functions in macterm.c. */
236extern void x_set_offset (struct frame *, int, int, int);
237extern void x_wm_set_icon_position (struct frame *, int, int);
238extern void x_display_cursor (struct window *, int, int, int, int, int);
239extern void x_set_window_size (struct frame *, int, int, int);
240extern void x_make_frame_visible (struct frame *);
241extern struct mac_display_info *x_term_init (Lisp_Object, char *, char *);
242extern struct font_info *x_get_font_info (FRAME_PTR, int);
243extern struct font_info *x_load_font (struct frame *, char *, int);
244extern void x_find_ccl_program (struct font_info *);
245extern struct font_info *x_query_font (struct frame *, char *);
246
247
248/* compare two strings ignoring case */
249
250static int
251stricmp (const char *s, const char *t)
252{
253 for ( ; tolower (*s) == tolower (*t); s++, t++)
254 if (*s == '\0')
255 return 0;
256 return tolower (*s) - tolower (*t);
257}
258
259/* compare two strings up to n characters, ignoring case */
260
261static int
262strnicmp (const char *s, const char *t, unsigned int n)
263{
264 for ( ; n-- > 0 && tolower (*s) == tolower (*t); s++, t++)
265 if (*s == '\0')
266 return 0;
267 return n == 0 ? 0 : tolower (*s) - tolower (*t);
268}
269
270
271/* Error if we are not running on Mac OS. */
272
273void
274check_mac ()
275{
276 if (! mac_in_use)
277 error ("Mac OS not in use or not initialized");
278}
279
280/* Nonzero if we can use mouse menus.
281 You should not call this unless HAVE_MENUS is defined. */
282
283int
284have_menus_p ()
285{
286 return mac_in_use;
287}
288
289/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
290 and checking validity for Mac. */
291
292FRAME_PTR
293check_x_frame (frame)
294 Lisp_Object frame;
295{
296 FRAME_PTR f;
297
298 if (NILP (frame))
299 frame = selected_frame;
300 CHECK_LIVE_FRAME (frame, 0);
301 f = XFRAME (frame);
302 if (! FRAME_MAC_P (f))
303 error ("non-mac frame used");
304 return f;
305}
306
307/* Let the user specify an display with a frame.
308 nil stands for the selected frame--or, if that is not a mac frame,
309 the first display on the list. */
310
311static struct mac_display_info *
312check_x_display_info (frame)
313 Lisp_Object frame;
314{
315 if (NILP (frame))
316 {
317 struct frame *sf = XFRAME (selected_frame);
318
319 if (FRAME_MAC_P (sf) && FRAME_LIVE_P (sf))
320 return FRAME_MAC_DISPLAY_INFO (sf);
321 else
322 return &one_mac_display_info;
323 }
324 else if (STRINGP (frame))
325 return x_display_info_for_name (frame);
326 else
327 {
328 FRAME_PTR f;
329
330 CHECK_LIVE_FRAME (frame, 0);
331 f = XFRAME (frame);
332 if (! FRAME_MAC_P (f))
333 error ("non-mac frame used");
334 return FRAME_MAC_DISPLAY_INFO (f);
335 }
336}
337
338/* Return the Emacs frame-object corresponding to an mac window.
339 It could be the frame's main window or an icon window. */
340
341/* This function can be called during GC, so use GC_xxx type test macros. */
342
343struct frame *
344x_window_to_frame (dpyinfo, wdesc)
345 struct mac_display_info *dpyinfo;
346 WindowPtr wdesc;
347{
348 Lisp_Object tail, frame;
349 struct frame *f;
350
351 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
352 {
353 frame = XCAR (tail);
354 if (!GC_FRAMEP (frame))
355 continue;
356 f = XFRAME (frame);
357 if (!FRAME_W32_P (f) || FRAME_MAC_DISPLAY_INFO (f) != dpyinfo)
358 continue;
359 /*if (f->output_data.w32->busy_window == wdesc)
360 return f;*/
361
362 /* MAC_TODO: Check tooltips when supported. */
363 if (FRAME_MAC_WINDOW (f) == wdesc)
364 return f;
365 }
366 return 0;
367}
368
369
370
371/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
372 id, which is just an int that this section returns. Bitmaps are
373 reference counted so they can be shared among frames.
374
375 Bitmap indices are guaranteed to be > 0, so a negative number can
376 be used to indicate no bitmap.
377
378 If you use x_create_bitmap_from_data, then you must keep track of
379 the bitmaps yourself. That is, creating a bitmap from the same
380 data more than once will not be caught. */
381
382
383/* Functions to access the contents of a bitmap, given an id. */
384
385int
386x_bitmap_height (f, id)
387 FRAME_PTR f;
388 int id;
389{
390 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height;
391}
392
393int
394x_bitmap_width (f, id)
395 FRAME_PTR f;
396 int id;
397{
398 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width;
399}
400
401#if 0 /* MAC_TODO : not used anywhere (?) */
402int
403x_bitmap_pixmap (f, id)
404 FRAME_PTR f;
405 int id;
406{
407 return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
408}
409#endif
410
411/* Allocate a new bitmap record. Returns index of new record. */
412
413static int
414x_allocate_bitmap_record (f)
415 FRAME_PTR f;
416{
417 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
418 int i;
419
420 if (dpyinfo->bitmaps == NULL)
421 {
422 dpyinfo->bitmaps_size = 10;
423 dpyinfo->bitmaps = (struct mac_bitmap_record *)
424 xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
425 dpyinfo->bitmaps_last = 1;
426 return 1;
427 }
428
429 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
430 return ++dpyinfo->bitmaps_last;
431
432 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
433 if (dpyinfo->bitmaps[i].refcount == 0)
434 return i + 1;
435
436 dpyinfo->bitmaps_size *= 2;
437 dpyinfo->bitmaps = (struct mac_bitmap_record *)
438 xrealloc (dpyinfo->bitmaps,
439 dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
440 return ++dpyinfo->bitmaps_last;
441}
442
443/* Add one reference to the reference count of the bitmap with id
444 ID. */
445
446void
447x_reference_bitmap (f, id)
448 FRAME_PTR f;
449 int id;
450{
451 ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
452}
453
454/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at
455 BITS. */
456
457int
458x_create_bitmap_from_data (f, bits, width, height)
459 struct frame *f;
460 char *bits;
461 unsigned int width, height;
462{
463 struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
464 int id;
465
466 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
467
468 id = x_allocate_bitmap_record (f);
469
470 if (width % 16 != 0)
471 return -1;
472
473 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
474 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
475 return -1;
476
477 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
478
479 dpyinfo->bitmaps[id - 1].refcount = 1;
480 dpyinfo->bitmaps[id - 1].height = height;
481 dpyinfo->bitmaps[id - 1].width = width;
482
483 return id;
484}
485
486/* Create bitmap from file FILE for frame F. */
487
488int
489x_create_bitmap_from_file (f, file)
490 struct frame *f;
491 Lisp_Object file;
492{
493 return -1;
494#if 0 /* MAC_TODO : bitmap support */
495 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
496 unsigned int width, height;
497 HBITMAP bitmap;
498 int xhot, yhot, result, id;
499 Lisp_Object found;
500 int fd;
501 char *filename;
502 HINSTANCE hinst;
503
504 /* Look for an existing bitmap with the same name. */
505 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
506 {
507 if (dpyinfo->bitmaps[id].refcount
508 && dpyinfo->bitmaps[id].file
509 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
510 {
511 ++dpyinfo->bitmaps[id].refcount;
512 return id + 1;
513 }
514 }
515
516 /* Search bitmap-file-path for the file, if appropriate. */
517 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
518 if (fd < 0)
519 return -1;
520 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
521 if (fd == 0)
522 return -1;
523 emacs_close (fd);
524
525 filename = (char *) XSTRING (found)->data;
526
527 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
528
529 if (hinst == NULL)
530 return -1;
531
532
533 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
534 filename, &width, &height, &bitmap, &xhot, &yhot);
535 if (result != BitmapSuccess)
536 return -1;
537
538 id = x_allocate_bitmap_record (f);
539 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
540 dpyinfo->bitmaps[id - 1].refcount = 1;
541 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
542 dpyinfo->bitmaps[id - 1].depth = 1;
543 dpyinfo->bitmaps[id - 1].height = height;
544 dpyinfo->bitmaps[id - 1].width = width;
545 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
546
547 return id;
548#endif /* MAC_TODO */
549}
550
551/* Remove reference to bitmap with id number ID. */
552
553void
554x_destroy_bitmap (f, id)
555 FRAME_PTR f;
556 int id;
557{
558 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
559
560 if (id > 0)
561 {
562 --dpyinfo->bitmaps[id - 1].refcount;
563 if (dpyinfo->bitmaps[id - 1].refcount == 0)
564 {
565 BLOCK_INPUT;
566 dpyinfo->bitmaps[id - 1].bitmap_data = NULL;
567 UNBLOCK_INPUT;
568 }
569 }
570}
571
572/* Free all the bitmaps for the display specified by DPYINFO. */
573
574static void
575x_destroy_all_bitmaps (dpyinfo)
576 struct mac_display_info *dpyinfo;
577{
578 int i;
579 for (i = 0; i < dpyinfo->bitmaps_last; i++)
580 if (dpyinfo->bitmaps[i].refcount > 0)
581 xfree (dpyinfo->bitmaps[i].bitmap_data);
582 dpyinfo->bitmaps_last = 0;
583}
584
585/* Connect the frame-parameter names for W32 frames
586 to the ways of passing the parameter values to the window system.
587
588 The name of a parameter, as a Lisp symbol,
589 has an `x-frame-parameter' property which is an integer in Lisp
590 but can be interpreted as an `enum x_frame_parm' in C. */
591
592struct x_frame_parm_table
593{
594 char *name;
595 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
596};
597
598void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
599static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
600void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
601void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
602void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
603void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
604void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
605void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
606void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
607void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
608static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
609void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
610void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
611 Lisp_Object));
612void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
613void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
614void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
615void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
616 Lisp_Object));
617void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
618void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
619void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
620void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
621void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
622void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
623void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
624 Lisp_Object));
625void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
626 Lisp_Object));
627static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
628 Lisp_Object,
629 Lisp_Object,
630 char *, char *,
631 int));
632static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
633
634static struct x_frame_parm_table x_frame_parms[] =
635{
636 "auto-raise", x_set_autoraise,
637 "auto-lower", x_set_autolower,
638 "background-color", x_set_background_color,
639 "border-color", x_set_border_color,
640 "border-width", x_set_border_width,
641 "cursor-color", x_set_cursor_color,
642 "cursor-type", x_set_cursor_type,
643 "font", x_set_font,
644 "foreground-color", x_set_foreground_color,
645 "icon-name", x_set_icon_name,
646#if 0 /* MAC_TODO: no icons for Mac */
647 "icon-type", x_set_icon_type,
648#endif
649 "internal-border-width", x_set_internal_border_width,
650 "menu-bar-lines", x_set_menu_bar_lines,
651 "mouse-color", x_set_mouse_color,
652 "name", x_explicitly_set_name,
653 "scroll-bar-width", x_set_scroll_bar_width,
654 "title", x_set_title,
655 "unsplittable", x_set_unsplittable,
656 "vertical-scroll-bars", x_set_vertical_scroll_bars,
657 "visibility", x_set_visibility,
658 "tool-bar-lines", x_set_tool_bar_lines,
659#if 0 /* MAC_TODO: cannot set color of scroll bar on the Mac? */
660 "scroll-bar-foreground", x_set_scroll_bar_foreground,
661 "scroll-bar-background", x_set_scroll_bar_background,
662#endif
663 "screen-gamma", x_set_screen_gamma,
664 "line-spacing", x_set_line_spacing,
665 "left-fringe", x_set_fringe_width,
666 "right-fringe", x_set_fringe_width
667};
668
669/* Attach the `x-frame-parameter' properties to
670 the Lisp symbol names of parameters relevant to Mac. */
671
672void
673init_x_parm_symbols ()
674{
675 int i;
676
677 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
678 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
679 make_number (i));
680}
681
682/* Change the parameters of frame F as specified by ALIST.
683 If a parameter is not specially recognized, do nothing;
684 otherwise call the `x_set_...' function for that parameter. */
685
686void
687x_set_frame_parameters (f, alist)
688 FRAME_PTR f;
689 Lisp_Object alist;
690{
691 Lisp_Object tail;
692
693 /* If both of these parameters are present, it's more efficient to
694 set them both at once. So we wait until we've looked at the
695 entire list before we set them. */
696 int width, height;
697
698 /* Same here. */
699 Lisp_Object left, top;
700
701 /* Same with these. */
702 Lisp_Object icon_left, icon_top;
703
704 /* Record in these vectors all the parms specified. */
705 Lisp_Object *parms;
706 Lisp_Object *values;
707 int i, p;
708 int left_no_change = 0, top_no_change = 0;
709 int icon_left_no_change = 0, icon_top_no_change = 0;
710
711 struct gcpro gcpro1, gcpro2;
712
713 i = 0;
714 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
715 i++;
716
717 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
718 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
719
720 /* Extract parm names and values into those vectors. */
721
722 i = 0;
723 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
724 {
725 Lisp_Object elt;
726
727 elt = Fcar (tail);
728 parms[i] = Fcar (elt);
729 values[i] = Fcdr (elt);
730 i++;
731 }
732 /* TAIL and ALIST are not used again below here. */
733 alist = tail = Qnil;
734
735 GCPRO2 (*parms, *values);
736 gcpro1.nvars = i;
737 gcpro2.nvars = i;
738
739 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
740 because their values appear in VALUES and strings are not valid. */
741 top = left = Qunbound;
742 icon_left = icon_top = Qunbound;
743
744 /* Provide default values for HEIGHT and WIDTH. */
745 if (FRAME_NEW_WIDTH (f))
746 width = FRAME_NEW_WIDTH (f);
747 else
748 width = FRAME_WIDTH (f);
749
750 if (FRAME_NEW_HEIGHT (f))
751 height = FRAME_NEW_HEIGHT (f);
752 else
753 height = FRAME_HEIGHT (f);
754
755 /* Process foreground_color and background_color before anything else.
756 They are independent of other properties, but other properties (e.g.,
757 cursor_color) are dependent upon them. */
758 /* Process default font as well, since fringe widths depends on it. */
759 for (p = 0; p < i; p++)
760 {
761 Lisp_Object prop, val;
762
763 prop = parms[p];
764 val = values[p];
765 if (EQ (prop, Qforeground_color)
766 || EQ (prop, Qbackground_color)
767 || EQ (prop, Qfont))
768 {
769 register Lisp_Object param_index, old_value;
770
771 param_index = Fget (prop, Qx_frame_parameter);
772 old_value = get_frame_param (f, prop);
773 store_frame_param (f, prop, val);
774 if (NATNUMP (param_index)
775 && (XFASTINT (param_index)
776 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
777 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
778 }
779 }
780
781 /* Now process them in reverse of specified order. */
782 for (i--; i >= 0; i--)
783 {
784 Lisp_Object prop, val;
785
786 prop = parms[i];
787 val = values[i];
788
789 if (EQ (prop, Qwidth) && NUMBERP (val))
790 width = XFASTINT (val);
791 else if (EQ (prop, Qheight) && NUMBERP (val))
792 height = XFASTINT (val);
793 else if (EQ (prop, Qtop))
794 top = val;
795 else if (EQ (prop, Qleft))
796 left = val;
797 else if (EQ (prop, Qicon_top))
798 icon_top = val;
799 else if (EQ (prop, Qicon_left))
800 icon_left = val;
801 else if (EQ (prop, Qforeground_color)
802 || EQ (prop, Qbackground_color)
803 || EQ (prop, Qfont))
804 /* Processed above. */
805 continue;
806 else
807 {
808 register Lisp_Object param_index, old_value;
809
810 param_index = Fget (prop, Qx_frame_parameter);
811 old_value = get_frame_param (f, prop);
812 store_frame_param (f, prop, val);
813 if (NATNUMP (param_index)
814 && (XFASTINT (param_index)
815 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
816 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
817 }
818 }
819
820 /* Don't die if just one of these was set. */
821 if (EQ (left, Qunbound))
822 {
823 left_no_change = 1;
824 if (f->output_data.mac->left_pos < 0)
825 left = Fcons (Qplus,
826 Fcons (make_number (f->output_data.mac->left_pos),
827 Qnil));
828 else
829 XSETINT (left, f->output_data.mac->left_pos);
830 }
831 if (EQ (top, Qunbound))
832 {
833 top_no_change = 1;
834 if (f->output_data.mac->top_pos < 0)
835 top = Fcons (Qplus,
836 Fcons (make_number (f->output_data.mac->top_pos), Qnil));
837 else
838 XSETINT (top, f->output_data.mac->top_pos);
839 }
840
841 /* If one of the icon positions was not set, preserve or default it. */
842 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
843 {
844 icon_left_no_change = 1;
845 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
846 if (NILP (icon_left))
847 XSETINT (icon_left, 0);
848 }
849 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
850 {
851 icon_top_no_change = 1;
852 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
853 if (NILP (icon_top))
854 XSETINT (icon_top, 0);
855 }
856
857 /* Don't set these parameters unless they've been explicitly
858 specified. The window might be mapped or resized while we're in
859 this function, and we don't want to override that unless the lisp
860 code has asked for it.
861
862 Don't set these parameters unless they actually differ from the
863 window's current parameters; the window may not actually exist
864 yet. */
865 {
866 Lisp_Object frame;
867
868 check_frame_size (f, &height, &width);
869
870 XSETFRAME (frame, f);
871
872 if (width != FRAME_WIDTH (f)
873 || height != FRAME_HEIGHT (f)
874 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
875 Fset_frame_size (frame, make_number (width), make_number (height));
876
877 if ((!NILP (left) || !NILP (top))
878 && ! (left_no_change && top_no_change)
879 && ! (NUMBERP (left) && XINT (left) == f->output_data.mac->left_pos
880 && NUMBERP (top) && XINT (top) == f->output_data.mac->top_pos))
881 {
882 int leftpos = 0;
883 int toppos = 0;
884
885 /* Record the signs. */
886 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
887 if (EQ (left, Qminus))
888 f->output_data.mac->size_hint_flags |= XNegative;
889 else if (INTEGERP (left))
890 {
891 leftpos = XINT (left);
892 if (leftpos < 0)
893 f->output_data.mac->size_hint_flags |= XNegative;
894 }
895 else if (CONSP (left) && EQ (XCAR (left), Qminus)
896 && CONSP (XCDR (left))
897 && INTEGERP (XCAR (XCDR (left))))
898 {
899 leftpos = - XINT (XCAR (XCDR (left)));
900 f->output_data.mac->size_hint_flags |= XNegative;
901 }
902 else if (CONSP (left) && EQ (XCAR (left), Qplus)
903 && CONSP (XCDR (left))
904 && INTEGERP (XCAR (XCDR (left))))
905 {
906 leftpos = XINT (XCAR (XCDR (left)));
907 }
908
909 if (EQ (top, Qminus))
910 f->output_data.mac->size_hint_flags |= YNegative;
911 else if (INTEGERP (top))
912 {
913 toppos = XINT (top);
914 if (toppos < 0)
915 f->output_data.mac->size_hint_flags |= YNegative;
916 }
917 else if (CONSP (top) && EQ (XCAR (top), Qminus)
918 && CONSP (XCDR (top))
919 && INTEGERP (XCAR (XCDR (top))))
920 {
921 toppos = - XINT (XCAR (XCDR (top)));
922 f->output_data.mac->size_hint_flags |= YNegative;
923 }
924 else if (CONSP (top) && EQ (XCAR (top), Qplus)
925 && CONSP (XCDR (top))
926 && INTEGERP (XCAR (XCDR (top))))
927 {
928 toppos = XINT (XCAR (XCDR (top)));
929 }
930
931
932 /* Store the numeric value of the position. */
933 f->output_data.mac->top_pos = toppos;
934 f->output_data.mac->left_pos = leftpos;
935
936 f->output_data.mac->win_gravity = NorthWestGravity;
937
938 /* Actually set that position, and convert to absolute. */
939 x_set_offset (f, leftpos, toppos, -1);
940 }
941
942 if ((!NILP (icon_left) || !NILP (icon_top))
943 && ! (icon_left_no_change && icon_top_no_change))
944 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
945 }
946
947 UNGCPRO;
948}
949
950/* Store the screen positions of frame F into XPTR and YPTR.
951 These are the positions of the containing window manager window,
952 not Emacs's own window. */
953
954void
955x_real_positions (f, xptr, yptr)
956 FRAME_PTR f;
957 int *xptr, *yptr;
958{
959 Point pt;
960 GrafPtr oldport;
961
962 SetPt (&pt,
963 f->output_data.mac->mWP->portRect.left,
964 f->output_data.mac->mWP->portRect.top);
965 GetPort (&oldport);
966 LocalToGlobal (&pt);
967 SetPort (oldport);
968
969 *xptr = pt.h;
970 *yptr = pt.v;
971}
972
973/* Insert a description of internally-recorded parameters of frame X
974 into the parameter alist *ALISTPTR that is to be given to the user.
975 Only parameters that are specific to Mac and whose values are not
976 correctly recorded in the frame's param_alist need to be considered
977 here. */
978
979void
980x_report_frame_params (f, alistptr)
981 struct frame *f;
982 Lisp_Object *alistptr;
983{
984 char buf[16];
985 Lisp_Object tem;
986
987 /* Represent negative positions (off the top or left screen edge)
988 in a way that Fmodify_frame_parameters will understand correctly. */
989 XSETINT (tem, f->output_data.mac->left_pos);
990 if (f->output_data.mac->left_pos >= 0)
991 store_in_alist (alistptr, Qleft, tem);
992 else
993 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
994
995 XSETINT (tem, f->output_data.mac->top_pos);
996 if (f->output_data.mac->top_pos >= 0)
997 store_in_alist (alistptr, Qtop, tem);
998 else
999 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1000
1001 store_in_alist (alistptr, Qborder_width,
1002 make_number (f->output_data.mac->border_width));
1003 store_in_alist (alistptr, Qinternal_border_width,
1004 make_number (f->output_data.mac->internal_border_width));
1005 store_in_alist (alistptr, Qleft_fringe,
1006 make_number (f->output_data.mac->left_fringe_width));
1007 store_in_alist (alistptr, Qright_fringe,
1008 make_number (f->output_data.mac->right_fringe_width));
1009 store_in_alist (alistptr, Qscroll_bar_width,
1010 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1011 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1012 : 0));
1013 sprintf (buf, "%ld", (long) FRAME_MAC_WINDOW (f));
1014 store_in_alist (alistptr, Qwindow_id,
1015 build_string (buf));
1016 store_in_alist (alistptr, Qicon_name, f->icon_name);
1017 FRAME_SAMPLE_VISIBILITY (f);
1018 store_in_alist (alistptr, Qvisibility,
1019 (FRAME_VISIBLE_P (f) ? Qt
1020 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1021 store_in_alist (alistptr, Qdisplay,
1022 XCAR (FRAME_MAC_DISPLAY_INFO (f)->name_list_element));
1023}
1024
1025/* The default colors for the Mac color map */
1026typedef struct colormap_t
1027{
1028 unsigned long color;
1029 char *name;
1030} colormap_t;
1031
1032colormap_t mac_color_map[] =
1033{
1034 { RGB_TO_ULONG(255, 250, 250), "snow" },
1035 { RGB_TO_ULONG(248, 248, 255), "ghost white" },
1036 { RGB_TO_ULONG(248, 248, 255), "GhostWhite" },
1037 { RGB_TO_ULONG(245, 245, 245), "white smoke" },
1038 { RGB_TO_ULONG(245, 245, 245), "WhiteSmoke" },
1039 { RGB_TO_ULONG(220, 220, 220), "gainsboro" },
1040 { RGB_TO_ULONG(255, 250, 240), "floral white" },
1041 { RGB_TO_ULONG(255, 250, 240), "FloralWhite" },
1042 { RGB_TO_ULONG(253, 245, 230), "old lace" },
1043 { RGB_TO_ULONG(253, 245, 230), "OldLace" },
1044 { RGB_TO_ULONG(250, 240, 230), "linen" },
1045 { RGB_TO_ULONG(250, 235, 215), "antique white" },
1046 { RGB_TO_ULONG(250, 235, 215), "AntiqueWhite" },
1047 { RGB_TO_ULONG(255, 239, 213), "papaya whip" },
1048 { RGB_TO_ULONG(255, 239, 213), "PapayaWhip" },
1049 { RGB_TO_ULONG(255, 235, 205), "blanched almond" },
1050 { RGB_TO_ULONG(255, 235, 205), "BlanchedAlmond" },
1051 { RGB_TO_ULONG(255, 228, 196), "bisque" },
1052 { RGB_TO_ULONG(255, 218, 185), "peach puff" },
1053 { RGB_TO_ULONG(255, 218, 185), "PeachPuff" },
1054 { RGB_TO_ULONG(255, 222, 173), "navajo white" },
1055 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite" },
1056 { RGB_TO_ULONG(255, 228, 181), "moccasin" },
1057 { RGB_TO_ULONG(255, 248, 220), "cornsilk" },
1058 { RGB_TO_ULONG(255, 255, 240), "ivory" },
1059 { RGB_TO_ULONG(255, 250, 205), "lemon chiffon" },
1060 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon" },
1061 { RGB_TO_ULONG(255, 245, 238), "seashell" },
1062 { RGB_TO_ULONG(240, 255, 240), "honeydew" },
1063 { RGB_TO_ULONG(245, 255, 250), "mint cream" },
1064 { RGB_TO_ULONG(245, 255, 250), "MintCream" },
1065 { RGB_TO_ULONG(240, 255, 255), "azure" },
1066 { RGB_TO_ULONG(240, 248, 255), "alice blue" },
1067 { RGB_TO_ULONG(240, 248, 255), "AliceBlue" },
1068 { RGB_TO_ULONG(230, 230, 250), "lavender" },
1069 { RGB_TO_ULONG(255, 240, 245), "lavender blush" },
1070 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush" },
1071 { RGB_TO_ULONG(255, 228, 225), "misty rose" },
1072 { RGB_TO_ULONG(255, 228, 225), "MistyRose" },
1073 { RGB_TO_ULONG(255, 255, 255), "white" },
1074 { RGB_TO_ULONG(0 , 0 , 0 ), "black" },
1075 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate gray" },
1076 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGray" },
1077 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate grey" },
1078 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGrey" },
1079 { RGB_TO_ULONG(105, 105, 105), "dim gray" },
1080 { RGB_TO_ULONG(105, 105, 105), "DimGray" },
1081 { RGB_TO_ULONG(105, 105, 105), "dim grey" },
1082 { RGB_TO_ULONG(105, 105, 105), "DimGrey" },
1083 { RGB_TO_ULONG(112, 128, 144), "slate gray" },
1084 { RGB_TO_ULONG(112, 128, 144), "SlateGray" },
1085 { RGB_TO_ULONG(112, 128, 144), "slate grey" },
1086 { RGB_TO_ULONG(112, 128, 144), "SlateGrey" },
1087 { RGB_TO_ULONG(119, 136, 153), "light slate gray" },
1088 { RGB_TO_ULONG(119, 136, 153), "LightSlateGray" },
1089 { RGB_TO_ULONG(119, 136, 153), "light slate grey" },
1090 { RGB_TO_ULONG(119, 136, 153), "LightSlateGrey" },
1091 { RGB_TO_ULONG(190, 190, 190), "gray" },
1092 { RGB_TO_ULONG(190, 190, 190), "grey" },
1093 { RGB_TO_ULONG(211, 211, 211), "light grey" },
1094 { RGB_TO_ULONG(211, 211, 211), "LightGrey" },
1095 { RGB_TO_ULONG(211, 211, 211), "light gray" },
1096 { RGB_TO_ULONG(211, 211, 211), "LightGray" },
1097 { RGB_TO_ULONG(25 , 25 , 112), "midnight blue" },
1098 { RGB_TO_ULONG(25 , 25 , 112), "MidnightBlue" },
1099 { RGB_TO_ULONG(0 , 0 , 128), "navy" },
1100 { RGB_TO_ULONG(0 , 0 , 128), "navy blue" },
1101 { RGB_TO_ULONG(0 , 0 , 128), "NavyBlue" },
1102 { RGB_TO_ULONG(100, 149, 237), "cornflower blue" },
1103 { RGB_TO_ULONG(100, 149, 237), "CornflowerBlue" },
1104 { RGB_TO_ULONG(72 , 61 , 139), "dark slate blue" },
1105 { RGB_TO_ULONG(72 , 61 , 139), "DarkSlateBlue" },
1106 { RGB_TO_ULONG(106, 90 , 205), "slate blue" },
1107 { RGB_TO_ULONG(106, 90 , 205), "SlateBlue" },
1108 { RGB_TO_ULONG(123, 104, 238), "medium slate blue" },
1109 { RGB_TO_ULONG(123, 104, 238), "MediumSlateBlue" },
1110 { RGB_TO_ULONG(132, 112, 255), "light slate blue" },
1111 { RGB_TO_ULONG(132, 112, 255), "LightSlateBlue" },
1112 { RGB_TO_ULONG(0 , 0 , 205), "medium blue" },
1113 { RGB_TO_ULONG(0 , 0 , 205), "MediumBlue" },
1114 { RGB_TO_ULONG(65 , 105, 225), "royal blue" },
1115 { RGB_TO_ULONG(65 , 105, 225), "RoyalBlue" },
1116 { RGB_TO_ULONG(0 , 0 , 255), "blue" },
1117 { RGB_TO_ULONG(30 , 144, 255), "dodger blue" },
1118 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue" },
1119 { RGB_TO_ULONG(0 , 191, 255), "deep sky blue" },
1120 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue" },
1121 { RGB_TO_ULONG(135, 206, 235), "sky blue" },
1122 { RGB_TO_ULONG(135, 206, 235), "SkyBlue" },
1123 { RGB_TO_ULONG(135, 206, 250), "light sky blue" },
1124 { RGB_TO_ULONG(135, 206, 250), "LightSkyBlue" },
1125 { RGB_TO_ULONG(70 , 130, 180), "steel blue" },
1126 { RGB_TO_ULONG(70 , 130, 180), "SteelBlue" },
1127 { RGB_TO_ULONG(176, 196, 222), "light steel blue" },
1128 { RGB_TO_ULONG(176, 196, 222), "LightSteelBlue" },
1129 { RGB_TO_ULONG(173, 216, 230), "light blue" },
1130 { RGB_TO_ULONG(173, 216, 230), "LightBlue" },
1131 { RGB_TO_ULONG(176, 224, 230), "powder blue" },
1132 { RGB_TO_ULONG(176, 224, 230), "PowderBlue" },
1133 { RGB_TO_ULONG(175, 238, 238), "pale turquoise" },
1134 { RGB_TO_ULONG(175, 238, 238), "PaleTurquoise" },
1135 { RGB_TO_ULONG(0 , 206, 209), "dark turquoise" },
1136 { RGB_TO_ULONG(0 , 206, 209), "DarkTurquoise" },
1137 { RGB_TO_ULONG(72 , 209, 204), "medium turquoise" },
1138 { RGB_TO_ULONG(72 , 209, 204), "MediumTurquoise" },
1139 { RGB_TO_ULONG(64 , 224, 208), "turquoise" },
1140 { RGB_TO_ULONG(0 , 255, 255), "cyan" },
1141 { RGB_TO_ULONG(224, 255, 255), "light cyan" },
1142 { RGB_TO_ULONG(224, 255, 255), "LightCyan" },
1143 { RGB_TO_ULONG(95 , 158, 160), "cadet blue" },
1144 { RGB_TO_ULONG(95 , 158, 160), "CadetBlue" },
1145 { RGB_TO_ULONG(102, 205, 170), "medium aquamarine" },
1146 { RGB_TO_ULONG(102, 205, 170), "MediumAquamarine" },
1147 { RGB_TO_ULONG(127, 255, 212), "aquamarine" },
1148 { RGB_TO_ULONG(0 , 100, 0 ), "dark green" },
1149 { RGB_TO_ULONG(0 , 100, 0 ), "DarkGreen" },
1150 { RGB_TO_ULONG(85 , 107, 47 ), "dark olive green" },
1151 { RGB_TO_ULONG(85 , 107, 47 ), "DarkOliveGreen" },
1152 { RGB_TO_ULONG(143, 188, 143), "dark sea green" },
1153 { RGB_TO_ULONG(143, 188, 143), "DarkSeaGreen" },
1154 { RGB_TO_ULONG(46 , 139, 87 ), "sea green" },
1155 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen" },
1156 { RGB_TO_ULONG(60 , 179, 113), "medium sea green" },
1157 { RGB_TO_ULONG(60 , 179, 113), "MediumSeaGreen" },
1158 { RGB_TO_ULONG(32 , 178, 170), "light sea green" },
1159 { RGB_TO_ULONG(32 , 178, 170), "LightSeaGreen" },
1160 { RGB_TO_ULONG(152, 251, 152), "pale green" },
1161 { RGB_TO_ULONG(152, 251, 152), "PaleGreen" },
1162 { RGB_TO_ULONG(0 , 255, 127), "spring green" },
1163 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen" },
1164 { RGB_TO_ULONG(124, 252, 0 ), "lawn green" },
1165 { RGB_TO_ULONG(124, 252, 0 ), "LawnGreen" },
1166 { RGB_TO_ULONG(0 , 255, 0 ), "green" },
1167 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse" },
1168 { RGB_TO_ULONG(0 , 250, 154), "medium spring green" },
1169 { RGB_TO_ULONG(0 , 250, 154), "MediumSpringGreen" },
1170 { RGB_TO_ULONG(173, 255, 47 ), "green yellow" },
1171 { RGB_TO_ULONG(173, 255, 47 ), "GreenYellow" },
1172 { RGB_TO_ULONG(50 , 205, 50 ), "lime green" },
1173 { RGB_TO_ULONG(50 , 205, 50 ), "LimeGreen" },
1174 { RGB_TO_ULONG(154, 205, 50 ), "yellow green" },
1175 { RGB_TO_ULONG(154, 205, 50 ), "YellowGreen" },
1176 { RGB_TO_ULONG(34 , 139, 34 ), "forest green" },
1177 { RGB_TO_ULONG(34 , 139, 34 ), "ForestGreen" },
1178 { RGB_TO_ULONG(107, 142, 35 ), "olive drab" },
1179 { RGB_TO_ULONG(107, 142, 35 ), "OliveDrab" },
1180 { RGB_TO_ULONG(189, 183, 107), "dark khaki" },
1181 { RGB_TO_ULONG(189, 183, 107), "DarkKhaki" },
1182 { RGB_TO_ULONG(240, 230, 140), "khaki" },
1183 { RGB_TO_ULONG(238, 232, 170), "pale goldenrod" },
1184 { RGB_TO_ULONG(238, 232, 170), "PaleGoldenrod" },
1185 { RGB_TO_ULONG(250, 250, 210), "light goldenrod yellow" },
1186 { RGB_TO_ULONG(250, 250, 210), "LightGoldenrodYellow" },
1187 { RGB_TO_ULONG(255, 255, 224), "light yellow" },
1188 { RGB_TO_ULONG(255, 255, 224), "LightYellow" },
1189 { RGB_TO_ULONG(255, 255, 0 ), "yellow" },
1190 { RGB_TO_ULONG(255, 215, 0 ), "gold" },
1191 { RGB_TO_ULONG(238, 221, 130), "light goldenrod" },
1192 { RGB_TO_ULONG(238, 221, 130), "LightGoldenrod" },
1193 { RGB_TO_ULONG(218, 165, 32 ), "goldenrod" },
1194 { RGB_TO_ULONG(184, 134, 11 ), "dark goldenrod" },
1195 { RGB_TO_ULONG(184, 134, 11 ), "DarkGoldenrod" },
1196 { RGB_TO_ULONG(188, 143, 143), "rosy brown" },
1197 { RGB_TO_ULONG(188, 143, 143), "RosyBrown" },
1198 { RGB_TO_ULONG(205, 92 , 92 ), "indian red" },
1199 { RGB_TO_ULONG(205, 92 , 92 ), "IndianRed" },
1200 { RGB_TO_ULONG(139, 69 , 19 ), "saddle brown" },
1201 { RGB_TO_ULONG(139, 69 , 19 ), "SaddleBrown" },
1202 { RGB_TO_ULONG(160, 82 , 45 ), "sienna" },
1203 { RGB_TO_ULONG(205, 133, 63 ), "peru" },
1204 { RGB_TO_ULONG(222, 184, 135), "burlywood" },
1205 { RGB_TO_ULONG(245, 245, 220), "beige" },
1206 { RGB_TO_ULONG(245, 222, 179), "wheat" },
1207 { RGB_TO_ULONG(244, 164, 96 ), "sandy brown" },
1208 { RGB_TO_ULONG(244, 164, 96 ), "SandyBrown" },
1209 { RGB_TO_ULONG(210, 180, 140), "tan" },
1210 { RGB_TO_ULONG(210, 105, 30 ), "chocolate" },
1211 { RGB_TO_ULONG(178, 34 , 34 ), "firebrick" },
1212 { RGB_TO_ULONG(165, 42 , 42 ), "brown" },
1213 { RGB_TO_ULONG(233, 150, 122), "dark salmon" },
1214 { RGB_TO_ULONG(233, 150, 122), "DarkSalmon" },
1215 { RGB_TO_ULONG(250, 128, 114), "salmon" },
1216 { RGB_TO_ULONG(255, 160, 122), "light salmon" },
1217 { RGB_TO_ULONG(255, 160, 122), "LightSalmon" },
1218 { RGB_TO_ULONG(255, 165, 0 ), "orange" },
1219 { RGB_TO_ULONG(255, 140, 0 ), "dark orange" },
1220 { RGB_TO_ULONG(255, 140, 0 ), "DarkOrange" },
1221 { RGB_TO_ULONG(255, 127, 80 ), "coral" },
1222 { RGB_TO_ULONG(240, 128, 128), "light coral" },
1223 { RGB_TO_ULONG(240, 128, 128), "LightCoral" },
1224 { RGB_TO_ULONG(255, 99 , 71 ), "tomato" },
1225 { RGB_TO_ULONG(255, 69 , 0 ), "orange red" },
1226 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed" },
1227 { RGB_TO_ULONG(255, 0 , 0 ), "red" },
1228 { RGB_TO_ULONG(255, 105, 180), "hot pink" },
1229 { RGB_TO_ULONG(255, 105, 180), "HotPink" },
1230 { RGB_TO_ULONG(255, 20 , 147), "deep pink" },
1231 { RGB_TO_ULONG(255, 20 , 147), "DeepPink" },
1232 { RGB_TO_ULONG(255, 192, 203), "pink" },
1233 { RGB_TO_ULONG(255, 182, 193), "light pink" },
1234 { RGB_TO_ULONG(255, 182, 193), "LightPink" },
1235 { RGB_TO_ULONG(219, 112, 147), "pale violet red" },
1236 { RGB_TO_ULONG(219, 112, 147), "PaleVioletRed" },
1237 { RGB_TO_ULONG(176, 48 , 96 ), "maroon" },
1238 { RGB_TO_ULONG(199, 21 , 133), "medium violet red" },
1239 { RGB_TO_ULONG(199, 21 , 133), "MediumVioletRed" },
1240 { RGB_TO_ULONG(208, 32 , 144), "violet red" },
1241 { RGB_TO_ULONG(208, 32 , 144), "VioletRed" },
1242 { RGB_TO_ULONG(255, 0 , 255), "magenta" },
1243 { RGB_TO_ULONG(238, 130, 238), "violet" },
1244 { RGB_TO_ULONG(221, 160, 221), "plum" },
1245 { RGB_TO_ULONG(218, 112, 214), "orchid" },
1246 { RGB_TO_ULONG(186, 85 , 211), "medium orchid" },
1247 { RGB_TO_ULONG(186, 85 , 211), "MediumOrchid" },
1248 { RGB_TO_ULONG(153, 50 , 204), "dark orchid" },
1249 { RGB_TO_ULONG(153, 50 , 204), "DarkOrchid" },
1250 { RGB_TO_ULONG(148, 0 , 211), "dark violet" },
1251 { RGB_TO_ULONG(148, 0 , 211), "DarkViolet" },
1252 { RGB_TO_ULONG(138, 43 , 226), "blue violet" },
1253 { RGB_TO_ULONG(138, 43 , 226), "BlueViolet" },
1254 { RGB_TO_ULONG(160, 32 , 240), "purple" },
1255 { RGB_TO_ULONG(147, 112, 219), "medium purple" },
1256 { RGB_TO_ULONG(147, 112, 219), "MediumPurple" },
1257 { RGB_TO_ULONG(216, 191, 216), "thistle" },
1258 { RGB_TO_ULONG(255, 250, 250), "snow1" },
1259 { RGB_TO_ULONG(238, 233, 233), "snow2" },
1260 { RGB_TO_ULONG(205, 201, 201), "snow3" },
1261 { RGB_TO_ULONG(139, 137, 137), "snow4" },
1262 { RGB_TO_ULONG(255, 245, 238), "seashell1" },
1263 { RGB_TO_ULONG(238, 229, 222), "seashell2" },
1264 { RGB_TO_ULONG(205, 197, 191), "seashell3" },
1265 { RGB_TO_ULONG(139, 134, 130), "seashell4" },
1266 { RGB_TO_ULONG(255, 239, 219), "AntiqueWhite1" },
1267 { RGB_TO_ULONG(238, 223, 204), "AntiqueWhite2" },
1268 { RGB_TO_ULONG(205, 192, 176), "AntiqueWhite3" },
1269 { RGB_TO_ULONG(139, 131, 120), "AntiqueWhite4" },
1270 { RGB_TO_ULONG(255, 228, 196), "bisque1" },
1271 { RGB_TO_ULONG(238, 213, 183), "bisque2" },
1272 { RGB_TO_ULONG(205, 183, 158), "bisque3" },
1273 { RGB_TO_ULONG(139, 125, 107), "bisque4" },
1274 { RGB_TO_ULONG(255, 218, 185), "PeachPuff1" },
1275 { RGB_TO_ULONG(238, 203, 173), "PeachPuff2" },
1276 { RGB_TO_ULONG(205, 175, 149), "PeachPuff3" },
1277 { RGB_TO_ULONG(139, 119, 101), "PeachPuff4" },
1278 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite1" },
1279 { RGB_TO_ULONG(238, 207, 161), "NavajoWhite2" },
1280 { RGB_TO_ULONG(205, 179, 139), "NavajoWhite3" },
1281 { RGB_TO_ULONG(139, 121, 94), "NavajoWhite4" },
1282 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon1" },
1283 { RGB_TO_ULONG(238, 233, 191), "LemonChiffon2" },
1284 { RGB_TO_ULONG(205, 201, 165), "LemonChiffon3" },
1285 { RGB_TO_ULONG(139, 137, 112), "LemonChiffon4" },
1286 { RGB_TO_ULONG(255, 248, 220), "cornsilk1" },
1287 { RGB_TO_ULONG(238, 232, 205), "cornsilk2" },
1288 { RGB_TO_ULONG(205, 200, 177), "cornsilk3" },
1289 { RGB_TO_ULONG(139, 136, 120), "cornsilk4" },
1290 { RGB_TO_ULONG(255, 255, 240), "ivory1" },
1291 { RGB_TO_ULONG(238, 238, 224), "ivory2" },
1292 { RGB_TO_ULONG(205, 205, 193), "ivory3" },
1293 { RGB_TO_ULONG(139, 139, 131), "ivory4" },
1294 { RGB_TO_ULONG(240, 255, 240), "honeydew1" },
1295 { RGB_TO_ULONG(224, 238, 224), "honeydew2" },
1296 { RGB_TO_ULONG(193, 205, 193), "honeydew3" },
1297 { RGB_TO_ULONG(131, 139, 131), "honeydew4" },
1298 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush1" },
1299 { RGB_TO_ULONG(238, 224, 229), "LavenderBlush2" },
1300 { RGB_TO_ULONG(205, 193, 197), "LavenderBlush3" },
1301 { RGB_TO_ULONG(139, 131, 134), "LavenderBlush4" },
1302 { RGB_TO_ULONG(255, 228, 225), "MistyRose1" },
1303 { RGB_TO_ULONG(238, 213, 210), "MistyRose2" },
1304 { RGB_TO_ULONG(205, 183, 181), "MistyRose3" },
1305 { RGB_TO_ULONG(139, 125, 123), "MistyRose4" },
1306 { RGB_TO_ULONG(240, 255, 255), "azure1" },
1307 { RGB_TO_ULONG(224, 238, 238), "azure2" },
1308 { RGB_TO_ULONG(193, 205, 205), "azure3" },
1309 { RGB_TO_ULONG(131, 139, 139), "azure4" },
1310 { RGB_TO_ULONG(131, 111, 255), "SlateBlue1" },
1311 { RGB_TO_ULONG(122, 103, 238), "SlateBlue2" },
1312 { RGB_TO_ULONG(105, 89 , 205), "SlateBlue3" },
1313 { RGB_TO_ULONG(71 , 60 , 139), "SlateBlue4" },
1314 { RGB_TO_ULONG(72 , 118, 255), "RoyalBlue1" },
1315 { RGB_TO_ULONG(67 , 110, 238), "RoyalBlue2" },
1316 { RGB_TO_ULONG(58 , 95 , 205), "RoyalBlue3" },
1317 { RGB_TO_ULONG(39 , 64 , 139), "RoyalBlue4" },
1318 { RGB_TO_ULONG(0 , 0 , 255), "blue1" },
1319 { RGB_TO_ULONG(0 , 0 , 238), "blue2" },
1320 { RGB_TO_ULONG(0 , 0 , 205), "blue3" },
1321 { RGB_TO_ULONG(0 , 0 , 139), "blue4" },
1322 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue1" },
1323 { RGB_TO_ULONG(28 , 134, 238), "DodgerBlue2" },
1324 { RGB_TO_ULONG(24 , 116, 205), "DodgerBlue3" },
1325 { RGB_TO_ULONG(16 , 78 , 139), "DodgerBlue4" },
1326 { RGB_TO_ULONG(99 , 184, 255), "SteelBlue1" },
1327 { RGB_TO_ULONG(92 , 172, 238), "SteelBlue2" },
1328 { RGB_TO_ULONG(79 , 148, 205), "SteelBlue3" },
1329 { RGB_TO_ULONG(54 , 100, 139), "SteelBlue4" },
1330 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue1" },
1331 { RGB_TO_ULONG(0 , 178, 238), "DeepSkyBlue2" },
1332 { RGB_TO_ULONG(0 , 154, 205), "DeepSkyBlue3" },
1333 { RGB_TO_ULONG(0 , 104, 139), "DeepSkyBlue4" },
1334 { RGB_TO_ULONG(135, 206, 255), "SkyBlue1" },
1335 { RGB_TO_ULONG(126, 192, 238), "SkyBlue2" },
1336 { RGB_TO_ULONG(108, 166, 205), "SkyBlue3" },
1337 { RGB_TO_ULONG(74 , 112, 139), "SkyBlue4" },
1338 { RGB_TO_ULONG(176, 226, 255), "LightSkyBlue1" },
1339 { RGB_TO_ULONG(164, 211, 238), "LightSkyBlue2" },
1340 { RGB_TO_ULONG(141, 182, 205), "LightSkyBlue3" },
1341 { RGB_TO_ULONG(96 , 123, 139), "LightSkyBlue4" },
1342 { RGB_TO_ULONG(198, 226, 255), "SlateGray1" },
1343 { RGB_TO_ULONG(185, 211, 238), "SlateGray2" },
1344 { RGB_TO_ULONG(159, 182, 205), "SlateGray3" },
1345 { RGB_TO_ULONG(108, 123, 139), "SlateGray4" },
1346 { RGB_TO_ULONG(202, 225, 255), "LightSteelBlue1" },
1347 { RGB_TO_ULONG(188, 210, 238), "LightSteelBlue2" },
1348 { RGB_TO_ULONG(162, 181, 205), "LightSteelBlue3" },
1349 { RGB_TO_ULONG(110, 123, 139), "LightSteelBlue4" },
1350 { RGB_TO_ULONG(191, 239, 255), "LightBlue1" },
1351 { RGB_TO_ULONG(178, 223, 238), "LightBlue2" },
1352 { RGB_TO_ULONG(154, 192, 205), "LightBlue3" },
1353 { RGB_TO_ULONG(104, 131, 139), "LightBlue4" },
1354 { RGB_TO_ULONG(224, 255, 255), "LightCyan1" },
1355 { RGB_TO_ULONG(209, 238, 238), "LightCyan2" },
1356 { RGB_TO_ULONG(180, 205, 205), "LightCyan3" },
1357 { RGB_TO_ULONG(122, 139, 139), "LightCyan4" },
1358 { RGB_TO_ULONG(187, 255, 255), "PaleTurquoise1" },
1359 { RGB_TO_ULONG(174, 238, 238), "PaleTurquoise2" },
1360 { RGB_TO_ULONG(150, 205, 205), "PaleTurquoise3" },
1361 { RGB_TO_ULONG(102, 139, 139), "PaleTurquoise4" },
1362 { RGB_TO_ULONG(152, 245, 255), "CadetBlue1" },
1363 { RGB_TO_ULONG(142, 229, 238), "CadetBlue2" },
1364 { RGB_TO_ULONG(122, 197, 205), "CadetBlue3" },
1365 { RGB_TO_ULONG(83 , 134, 139), "CadetBlue4" },
1366 { RGB_TO_ULONG(0 , 245, 255), "turquoise1" },
1367 { RGB_TO_ULONG(0 , 229, 238), "turquoise2" },
1368 { RGB_TO_ULONG(0 , 197, 205), "turquoise3" },
1369 { RGB_TO_ULONG(0 , 134, 139), "turquoise4" },
1370 { RGB_TO_ULONG(0 , 255, 255), "cyan1" },
1371 { RGB_TO_ULONG(0 , 238, 238), "cyan2" },
1372 { RGB_TO_ULONG(0 , 205, 205), "cyan3" },
1373 { RGB_TO_ULONG(0 , 139, 139), "cyan4" },
1374 { RGB_TO_ULONG(151, 255, 255), "DarkSlateGray1" },
1375 { RGB_TO_ULONG(141, 238, 238), "DarkSlateGray2" },
1376 { RGB_TO_ULONG(121, 205, 205), "DarkSlateGray3" },
1377 { RGB_TO_ULONG(82 , 139, 139), "DarkSlateGray4" },
1378 { RGB_TO_ULONG(127, 255, 212), "aquamarine1" },
1379 { RGB_TO_ULONG(118, 238, 198), "aquamarine2" },
1380 { RGB_TO_ULONG(102, 205, 170), "aquamarine3" },
1381 { RGB_TO_ULONG(69 , 139, 116), "aquamarine4" },
1382 { RGB_TO_ULONG(193, 255, 193), "DarkSeaGreen1" },
1383 { RGB_TO_ULONG(180, 238, 180), "DarkSeaGreen2" },
1384 { RGB_TO_ULONG(155, 205, 155), "DarkSeaGreen3" },
1385 { RGB_TO_ULONG(105, 139, 105), "DarkSeaGreen4" },
1386 { RGB_TO_ULONG(84 , 255, 159), "SeaGreen1" },
1387 { RGB_TO_ULONG(78 , 238, 148), "SeaGreen2" },
1388 { RGB_TO_ULONG(67 , 205, 128), "SeaGreen3" },
1389 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen4" },
1390 { RGB_TO_ULONG(154, 255, 154), "PaleGreen1" },
1391 { RGB_TO_ULONG(144, 238, 144), "PaleGreen2" },
1392 { RGB_TO_ULONG(124, 205, 124), "PaleGreen3" },
1393 { RGB_TO_ULONG(84 , 139, 84 ), "PaleGreen4" },
1394 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen1" },
1395 { RGB_TO_ULONG(0 , 238, 118), "SpringGreen2" },
1396 { RGB_TO_ULONG(0 , 205, 102), "SpringGreen3" },
1397 { RGB_TO_ULONG(0 , 139, 69 ), "SpringGreen4" },
1398 { RGB_TO_ULONG(0 , 255, 0 ), "green1" },
1399 { RGB_TO_ULONG(0 , 238, 0 ), "green2" },
1400 { RGB_TO_ULONG(0 , 205, 0 ), "green3" },
1401 { RGB_TO_ULONG(0 , 139, 0 ), "green4" },
1402 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse1" },
1403 { RGB_TO_ULONG(118, 238, 0 ), "chartreuse2" },
1404 { RGB_TO_ULONG(102, 205, 0 ), "chartreuse3" },
1405 { RGB_TO_ULONG(69 , 139, 0 ), "chartreuse4" },
1406 { RGB_TO_ULONG(192, 255, 62 ), "OliveDrab1" },
1407 { RGB_TO_ULONG(179, 238, 58 ), "OliveDrab2" },
1408 { RGB_TO_ULONG(154, 205, 50 ), "OliveDrab3" },
1409 { RGB_TO_ULONG(105, 139, 34 ), "OliveDrab4" },
1410 { RGB_TO_ULONG(202, 255, 112), "DarkOliveGreen1" },
1411 { RGB_TO_ULONG(188, 238, 104), "DarkOliveGreen2" },
1412 { RGB_TO_ULONG(162, 205, 90 ), "DarkOliveGreen3" },
1413 { RGB_TO_ULONG(110, 139, 61 ), "DarkOliveGreen4" },
1414 { RGB_TO_ULONG(255, 246, 143), "khaki1" },
1415 { RGB_TO_ULONG(238, 230, 133), "khaki2" },
1416 { RGB_TO_ULONG(205, 198, 115), "khaki3" },
1417 { RGB_TO_ULONG(139, 134, 78 ), "khaki4" },
1418 { RGB_TO_ULONG(255, 236, 139), "LightGoldenrod1" },
1419 { RGB_TO_ULONG(238, 220, 130), "LightGoldenrod2" },
1420 { RGB_TO_ULONG(205, 190, 112), "LightGoldenrod3" },
1421 { RGB_TO_ULONG(139, 129, 76 ), "LightGoldenrod4" },
1422 { RGB_TO_ULONG(255, 255, 224), "LightYellow1" },
1423 { RGB_TO_ULONG(238, 238, 209), "LightYellow2" },
1424 { RGB_TO_ULONG(205, 205, 180), "LightYellow3" },
1425 { RGB_TO_ULONG(139, 139, 122), "LightYellow4" },
1426 { RGB_TO_ULONG(255, 255, 0 ), "yellow1" },
1427 { RGB_TO_ULONG(238, 238, 0 ), "yellow2" },
1428 { RGB_TO_ULONG(205, 205, 0 ), "yellow3" },
1429 { RGB_TO_ULONG(139, 139, 0 ), "yellow4" },
1430 { RGB_TO_ULONG(255, 215, 0 ), "gold1" },
1431 { RGB_TO_ULONG(238, 201, 0 ), "gold2" },
1432 { RGB_TO_ULONG(205, 173, 0 ), "gold3" },
1433 { RGB_TO_ULONG(139, 117, 0 ), "gold4" },
1434 { RGB_TO_ULONG(255, 193, 37 ), "goldenrod1" },
1435 { RGB_TO_ULONG(238, 180, 34 ), "goldenrod2" },
1436 { RGB_TO_ULONG(205, 155, 29 ), "goldenrod3" },
1437 { RGB_TO_ULONG(139, 105, 20 ), "goldenrod4" },
1438 { RGB_TO_ULONG(255, 185, 15 ), "DarkGoldenrod1" },
1439 { RGB_TO_ULONG(238, 173, 14 ), "DarkGoldenrod2" },
1440 { RGB_TO_ULONG(205, 149, 12 ), "DarkGoldenrod3" },
1441 { RGB_TO_ULONG(139, 101, 8 ), "DarkGoldenrod4" },
1442 { RGB_TO_ULONG(255, 193, 193), "RosyBrown1" },
1443 { RGB_TO_ULONG(238, 180, 180), "RosyBrown2" },
1444 { RGB_TO_ULONG(205, 155, 155), "RosyBrown3" },
1445 { RGB_TO_ULONG(139, 105, 105), "RosyBrown4" },
1446 { RGB_TO_ULONG(255, 106, 106), "IndianRed1" },
1447 { RGB_TO_ULONG(238, 99 , 99 ), "IndianRed2" },
1448 { RGB_TO_ULONG(205, 85 , 85 ), "IndianRed3" },
1449 { RGB_TO_ULONG(139, 58 , 58 ), "IndianRed4" },
1450 { RGB_TO_ULONG(255, 130, 71 ), "sienna1" },
1451 { RGB_TO_ULONG(238, 121, 66 ), "sienna2" },
1452 { RGB_TO_ULONG(205, 104, 57 ), "sienna3" },
1453 { RGB_TO_ULONG(139, 71 , 38 ), "sienna4" },
1454 { RGB_TO_ULONG(255, 211, 155), "burlywood1" },
1455 { RGB_TO_ULONG(238, 197, 145), "burlywood2" },
1456 { RGB_TO_ULONG(205, 170, 125), "burlywood3" },
1457 { RGB_TO_ULONG(139, 115, 85 ), "burlywood4" },
1458 { RGB_TO_ULONG(255, 231, 186), "wheat1" },
1459 { RGB_TO_ULONG(238, 216, 174), "wheat2" },
1460 { RGB_TO_ULONG(205, 186, 150), "wheat3" },
1461 { RGB_TO_ULONG(139, 126, 102), "wheat4" },
1462 { RGB_TO_ULONG(255, 165, 79 ), "tan1" },
1463 { RGB_TO_ULONG(238, 154, 73 ), "tan2" },
1464 { RGB_TO_ULONG(205, 133, 63 ), "tan3" },
1465 { RGB_TO_ULONG(139, 90 , 43 ), "tan4" },
1466 { RGB_TO_ULONG(255, 127, 36 ), "chocolate1" },
1467 { RGB_TO_ULONG(238, 118, 33 ), "chocolate2" },
1468 { RGB_TO_ULONG(205, 102, 29 ), "chocolate3" },
1469 { RGB_TO_ULONG(139, 69 , 19 ), "chocolate4" },
1470 { RGB_TO_ULONG(255, 48 , 48 ), "firebrick1" },
1471 { RGB_TO_ULONG(238, 44 , 44 ), "firebrick2" },
1472 { RGB_TO_ULONG(205, 38 , 38 ), "firebrick3" },
1473 { RGB_TO_ULONG(139, 26 , 26 ), "firebrick4" },
1474 { RGB_TO_ULONG(255, 64 , 64 ), "brown1" },
1475 { RGB_TO_ULONG(238, 59 , 59 ), "brown2" },
1476 { RGB_TO_ULONG(205, 51 , 51 ), "brown3" },
1477 { RGB_TO_ULONG(139, 35 , 35 ), "brown4" },
1478 { RGB_TO_ULONG(255, 140, 105), "salmon1" },
1479 { RGB_TO_ULONG(238, 130, 98 ), "salmon2" },
1480 { RGB_TO_ULONG(205, 112, 84 ), "salmon3" },
1481 { RGB_TO_ULONG(139, 76 , 57 ), "salmon4" },
1482 { RGB_TO_ULONG(255, 160, 122), "LightSalmon1" },
1483 { RGB_TO_ULONG(238, 149, 114), "LightSalmon2" },
1484 { RGB_TO_ULONG(205, 129, 98 ), "LightSalmon3" },
1485 { RGB_TO_ULONG(139, 87 , 66 ), "LightSalmon4" },
1486 { RGB_TO_ULONG(255, 165, 0 ), "orange1" },
1487 { RGB_TO_ULONG(238, 154, 0 ), "orange2" },
1488 { RGB_TO_ULONG(205, 133, 0 ), "orange3" },
1489 { RGB_TO_ULONG(139, 90 , 0 ), "orange4" },
1490 { RGB_TO_ULONG(255, 127, 0 ), "DarkOrange1" },
1491 { RGB_TO_ULONG(238, 118, 0 ), "DarkOrange2" },
1492 { RGB_TO_ULONG(205, 102, 0 ), "DarkOrange3" },
1493 { RGB_TO_ULONG(139, 69 , 0 ), "DarkOrange4" },
1494 { RGB_TO_ULONG(255, 114, 86 ), "coral1" },
1495 { RGB_TO_ULONG(238, 106, 80 ), "coral2" },
1496 { RGB_TO_ULONG(205, 91 , 69 ), "coral3" },
1497 { RGB_TO_ULONG(139, 62 , 47 ), "coral4" },
1498 { RGB_TO_ULONG(255, 99 , 71 ), "tomato1" },
1499 { RGB_TO_ULONG(238, 92 , 66 ), "tomato2" },
1500 { RGB_TO_ULONG(205, 79 , 57 ), "tomato3" },
1501 { RGB_TO_ULONG(139, 54 , 38 ), "tomato4" },
1502 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed1" },
1503 { RGB_TO_ULONG(238, 64 , 0 ), "OrangeRed2" },
1504 { RGB_TO_ULONG(205, 55 , 0 ), "OrangeRed3" },
1505 { RGB_TO_ULONG(139, 37 , 0 ), "OrangeRed4" },
1506 { RGB_TO_ULONG(255, 0 , 0 ), "red1" },
1507 { RGB_TO_ULONG(238, 0 , 0 ), "red2" },
1508 { RGB_TO_ULONG(205, 0 , 0 ), "red3" },
1509 { RGB_TO_ULONG(139, 0 , 0 ), "red4" },
1510 { RGB_TO_ULONG(255, 20 , 147), "DeepPink1" },
1511 { RGB_TO_ULONG(238, 18 , 137), "DeepPink2" },
1512 { RGB_TO_ULONG(205, 16 , 118), "DeepPink3" },
1513 { RGB_TO_ULONG(139, 10 , 80 ), "DeepPink4" },
1514 { RGB_TO_ULONG(255, 110, 180), "HotPink1" },
1515 { RGB_TO_ULONG(238, 106, 167), "HotPink2" },
1516 { RGB_TO_ULONG(205, 96 , 144), "HotPink3" },
1517 { RGB_TO_ULONG(139, 58 , 98 ), "HotPink4" },
1518 { RGB_TO_ULONG(255, 181, 197), "pink1" },
1519 { RGB_TO_ULONG(238, 169, 184), "pink2" },
1520 { RGB_TO_ULONG(205, 145, 158), "pink3" },
1521 { RGB_TO_ULONG(139, 99 , 108), "pink4" },
1522 { RGB_TO_ULONG(255, 174, 185), "LightPink1" },
1523 { RGB_TO_ULONG(238, 162, 173), "LightPink2" },
1524 { RGB_TO_ULONG(205, 140, 149), "LightPink3" },
1525 { RGB_TO_ULONG(139, 95 , 101), "LightPink4" },
1526 { RGB_TO_ULONG(255, 130, 171), "PaleVioletRed1" },
1527 { RGB_TO_ULONG(238, 121, 159), "PaleVioletRed2" },
1528 { RGB_TO_ULONG(205, 104, 137), "PaleVioletRed3" },
1529 { RGB_TO_ULONG(139, 71 , 93 ), "PaleVioletRed4" },
1530 { RGB_TO_ULONG(255, 52 , 179), "maroon1" },
1531 { RGB_TO_ULONG(238, 48 , 167), "maroon2" },
1532 { RGB_TO_ULONG(205, 41 , 144), "maroon3" },
1533 { RGB_TO_ULONG(139, 28 , 98 ), "maroon4" },
1534 { RGB_TO_ULONG(255, 62 , 150), "VioletRed1" },
1535 { RGB_TO_ULONG(238, 58 , 140), "VioletRed2" },
1536 { RGB_TO_ULONG(205, 50 , 120), "VioletRed3" },
1537 { RGB_TO_ULONG(139, 34 , 82 ), "VioletRed4" },
1538 { RGB_TO_ULONG(255, 0 , 255), "magenta1" },
1539 { RGB_TO_ULONG(238, 0 , 238), "magenta2" },
1540 { RGB_TO_ULONG(205, 0 , 205), "magenta3" },
1541 { RGB_TO_ULONG(139, 0 , 139), "magenta4" },
1542 { RGB_TO_ULONG(255, 131, 250), "orchid1" },
1543 { RGB_TO_ULONG(238, 122, 233), "orchid2" },
1544 { RGB_TO_ULONG(205, 105, 201), "orchid3" },
1545 { RGB_TO_ULONG(139, 71 , 137), "orchid4" },
1546 { RGB_TO_ULONG(255, 187, 255), "plum1" },
1547 { RGB_TO_ULONG(238, 174, 238), "plum2" },
1548 { RGB_TO_ULONG(205, 150, 205), "plum3" },
1549 { RGB_TO_ULONG(139, 102, 139), "plum4" },
1550 { RGB_TO_ULONG(224, 102, 255), "MediumOrchid1" },
1551 { RGB_TO_ULONG(209, 95 , 238), "MediumOrchid2" },
1552 { RGB_TO_ULONG(180, 82 , 205), "MediumOrchid3" },
1553 { RGB_TO_ULONG(122, 55 , 139), "MediumOrchid4" },
1554 { RGB_TO_ULONG(191, 62 , 255), "DarkOrchid1" },
1555 { RGB_TO_ULONG(178, 58 , 238), "DarkOrchid2" },
1556 { RGB_TO_ULONG(154, 50 , 205), "DarkOrchid3" },
1557 { RGB_TO_ULONG(104, 34 , 139), "DarkOrchid4" },
1558 { RGB_TO_ULONG(155, 48 , 255), "purple1" },
1559 { RGB_TO_ULONG(145, 44 , 238), "purple2" },
1560 { RGB_TO_ULONG(125, 38 , 205), "purple3" },
1561 { RGB_TO_ULONG(85 , 26 , 139), "purple4" },
1562 { RGB_TO_ULONG(171, 130, 255), "MediumPurple1" },
1563 { RGB_TO_ULONG(159, 121, 238), "MediumPurple2" },
1564 { RGB_TO_ULONG(137, 104, 205), "MediumPurple3" },
1565 { RGB_TO_ULONG(93 , 71 , 139), "MediumPurple4" },
1566 { RGB_TO_ULONG(255, 225, 255), "thistle1" },
1567 { RGB_TO_ULONG(238, 210, 238), "thistle2" },
1568 { RGB_TO_ULONG(205, 181, 205), "thistle3" },
1569 { RGB_TO_ULONG(139, 123, 139), "thistle4" },
1570 { RGB_TO_ULONG(0 , 0 , 0 ), "gray0" },
1571 { RGB_TO_ULONG(0 , 0 , 0 ), "grey0" },
1572 { RGB_TO_ULONG(3 , 3 , 3 ), "gray1" },
1573 { RGB_TO_ULONG(3 , 3 , 3 ), "grey1" },
1574 { RGB_TO_ULONG(5 , 5 , 5 ), "gray2" },
1575 { RGB_TO_ULONG(5 , 5 , 5 ), "grey2" },
1576 { RGB_TO_ULONG(8 , 8 , 8 ), "gray3" },
1577 { RGB_TO_ULONG(8 , 8 , 8 ), "grey3" },
1578 { RGB_TO_ULONG(10 , 10 , 10 ), "gray4" },
1579 { RGB_TO_ULONG(10 , 10 , 10 ), "grey4" },
1580 { RGB_TO_ULONG(13 , 13 , 13 ), "gray5" },
1581 { RGB_TO_ULONG(13 , 13 , 13 ), "grey5" },
1582 { RGB_TO_ULONG(15 , 15 , 15 ), "gray6" },
1583 { RGB_TO_ULONG(15 , 15 , 15 ), "grey6" },
1584 { RGB_TO_ULONG(18 , 18 , 18 ), "gray7" },
1585 { RGB_TO_ULONG(18 , 18 , 18 ), "grey7" },
1586 { RGB_TO_ULONG(20 , 20 , 20 ), "gray8" },
1587 { RGB_TO_ULONG(20 , 20 , 20 ), "grey8" },
1588 { RGB_TO_ULONG(23 , 23 , 23 ), "gray9" },
1589 { RGB_TO_ULONG(23 , 23 , 23 ), "grey9" },
1590 { RGB_TO_ULONG(26 , 26 , 26 ), "gray10" },
1591 { RGB_TO_ULONG(26 , 26 , 26 ), "grey10" },
1592 { RGB_TO_ULONG(28 , 28 , 28 ), "gray11" },
1593 { RGB_TO_ULONG(28 , 28 , 28 ), "grey11" },
1594 { RGB_TO_ULONG(31 , 31 , 31 ), "gray12" },
1595 { RGB_TO_ULONG(31 , 31 , 31 ), "grey12" },
1596 { RGB_TO_ULONG(33 , 33 , 33 ), "gray13" },
1597 { RGB_TO_ULONG(33 , 33 , 33 ), "grey13" },
1598 { RGB_TO_ULONG(36 , 36 , 36 ), "gray14" },
1599 { RGB_TO_ULONG(36 , 36 , 36 ), "grey14" },
1600 { RGB_TO_ULONG(38 , 38 , 38 ), "gray15" },
1601 { RGB_TO_ULONG(38 , 38 , 38 ), "grey15" },
1602 { RGB_TO_ULONG(41 , 41 , 41 ), "gray16" },
1603 { RGB_TO_ULONG(41 , 41 , 41 ), "grey16" },
1604 { RGB_TO_ULONG(43 , 43 , 43 ), "gray17" },
1605 { RGB_TO_ULONG(43 , 43 , 43 ), "grey17" },
1606 { RGB_TO_ULONG(46 , 46 , 46 ), "gray18" },
1607 { RGB_TO_ULONG(46 , 46 , 46 ), "grey18" },
1608 { RGB_TO_ULONG(48 , 48 , 48 ), "gray19" },
1609 { RGB_TO_ULONG(48 , 48 , 48 ), "grey19" },
1610 { RGB_TO_ULONG(51 , 51 , 51 ), "gray20" },
1611 { RGB_TO_ULONG(51 , 51 , 51 ), "grey20" },
1612 { RGB_TO_ULONG(54 , 54 , 54 ), "gray21" },
1613 { RGB_TO_ULONG(54 , 54 , 54 ), "grey21" },
1614 { RGB_TO_ULONG(56 , 56 , 56 ), "gray22" },
1615 { RGB_TO_ULONG(56 , 56 , 56 ), "grey22" },
1616 { RGB_TO_ULONG(59 , 59 , 59 ), "gray23" },
1617 { RGB_TO_ULONG(59 , 59 , 59 ), "grey23" },
1618 { RGB_TO_ULONG(61 , 61 , 61 ), "gray24" },
1619 { RGB_TO_ULONG(61 , 61 , 61 ), "grey24" },
1620 { RGB_TO_ULONG(64 , 64 , 64 ), "gray25" },
1621 { RGB_TO_ULONG(64 , 64 , 64 ), "grey25" },
1622 { RGB_TO_ULONG(66 , 66 , 66 ), "gray26" },
1623 { RGB_TO_ULONG(66 , 66 , 66 ), "grey26" },
1624 { RGB_TO_ULONG(69 , 69 , 69 ), "gray27" },
1625 { RGB_TO_ULONG(69 , 69 , 69 ), "grey27" },
1626 { RGB_TO_ULONG(71 , 71 , 71 ), "gray28" },
1627 { RGB_TO_ULONG(71 , 71 , 71 ), "grey28" },
1628 { RGB_TO_ULONG(74 , 74 , 74 ), "gray29" },
1629 { RGB_TO_ULONG(74 , 74 , 74 ), "grey29" },
1630 { RGB_TO_ULONG(77 , 77 , 77 ), "gray30" },
1631 { RGB_TO_ULONG(77 , 77 , 77 ), "grey30" },
1632 { RGB_TO_ULONG(79 , 79 , 79 ), "gray31" },
1633 { RGB_TO_ULONG(79 , 79 , 79 ), "grey31" },
1634 { RGB_TO_ULONG(82 , 82 , 82 ), "gray32" },
1635 { RGB_TO_ULONG(82 , 82 , 82 ), "grey32" },
1636 { RGB_TO_ULONG(84 , 84 , 84 ), "gray33" },
1637 { RGB_TO_ULONG(84 , 84 , 84 ), "grey33" },
1638 { RGB_TO_ULONG(87 , 87 , 87 ), "gray34" },
1639 { RGB_TO_ULONG(87 , 87 , 87 ), "grey34" },
1640 { RGB_TO_ULONG(89 , 89 , 89 ), "gray35" },
1641 { RGB_TO_ULONG(89 , 89 , 89 ), "grey35" },
1642 { RGB_TO_ULONG(92 , 92 , 92 ), "gray36" },
1643 { RGB_TO_ULONG(92 , 92 , 92 ), "grey36" },
1644 { RGB_TO_ULONG(94 , 94 , 94 ), "gray37" },
1645 { RGB_TO_ULONG(94 , 94 , 94 ), "grey37" },
1646 { RGB_TO_ULONG(97 , 97 , 97 ), "gray38" },
1647 { RGB_TO_ULONG(97 , 97 , 97 ), "grey38" },
1648 { RGB_TO_ULONG(99 , 99 , 99 ), "gray39" },
1649 { RGB_TO_ULONG(99 , 99 , 99 ), "grey39" },
1650 { RGB_TO_ULONG(102, 102, 102), "gray40" },
1651 { RGB_TO_ULONG(102, 102, 102), "grey40" },
1652 { RGB_TO_ULONG(105, 105, 105), "gray41" },
1653 { RGB_TO_ULONG(105, 105, 105), "grey41" },
1654 { RGB_TO_ULONG(107, 107, 107), "gray42" },
1655 { RGB_TO_ULONG(107, 107, 107), "grey42" },
1656 { RGB_TO_ULONG(110, 110, 110), "gray43" },
1657 { RGB_TO_ULONG(110, 110, 110), "grey43" },
1658 { RGB_TO_ULONG(112, 112, 112), "gray44" },
1659 { RGB_TO_ULONG(112, 112, 112), "grey44" },
1660 { RGB_TO_ULONG(115, 115, 115), "gray45" },
1661 { RGB_TO_ULONG(115, 115, 115), "grey45" },
1662 { RGB_TO_ULONG(117, 117, 117), "gray46" },
1663 { RGB_TO_ULONG(117, 117, 117), "grey46" },
1664 { RGB_TO_ULONG(120, 120, 120), "gray47" },
1665 { RGB_TO_ULONG(120, 120, 120), "grey47" },
1666 { RGB_TO_ULONG(122, 122, 122), "gray48" },
1667 { RGB_TO_ULONG(122, 122, 122), "grey48" },
1668 { RGB_TO_ULONG(125, 125, 125), "gray49" },
1669 { RGB_TO_ULONG(125, 125, 125), "grey49" },
1670 { RGB_TO_ULONG(127, 127, 127), "gray50" },
1671 { RGB_TO_ULONG(127, 127, 127), "grey50" },
1672 { RGB_TO_ULONG(130, 130, 130), "gray51" },
1673 { RGB_TO_ULONG(130, 130, 130), "grey51" },
1674 { RGB_TO_ULONG(133, 133, 133), "gray52" },
1675 { RGB_TO_ULONG(133, 133, 133), "grey52" },
1676 { RGB_TO_ULONG(135, 135, 135), "gray53" },
1677 { RGB_TO_ULONG(135, 135, 135), "grey53" },
1678 { RGB_TO_ULONG(138, 138, 138), "gray54" },
1679 { RGB_TO_ULONG(138, 138, 138), "grey54" },
1680 { RGB_TO_ULONG(140, 140, 140), "gray55" },
1681 { RGB_TO_ULONG(140, 140, 140), "grey55" },
1682 { RGB_TO_ULONG(143, 143, 143), "gray56" },
1683 { RGB_TO_ULONG(143, 143, 143), "grey56" },
1684 { RGB_TO_ULONG(145, 145, 145), "gray57" },
1685 { RGB_TO_ULONG(145, 145, 145), "grey57" },
1686 { RGB_TO_ULONG(148, 148, 148), "gray58" },
1687 { RGB_TO_ULONG(148, 148, 148), "grey58" },
1688 { RGB_TO_ULONG(150, 150, 150), "gray59" },
1689 { RGB_TO_ULONG(150, 150, 150), "grey59" },
1690 { RGB_TO_ULONG(153, 153, 153), "gray60" },
1691 { RGB_TO_ULONG(153, 153, 153), "grey60" },
1692 { RGB_TO_ULONG(156, 156, 156), "gray61" },
1693 { RGB_TO_ULONG(156, 156, 156), "grey61" },
1694 { RGB_TO_ULONG(158, 158, 158), "gray62" },
1695 { RGB_TO_ULONG(158, 158, 158), "grey62" },
1696 { RGB_TO_ULONG(161, 161, 161), "gray63" },
1697 { RGB_TO_ULONG(161, 161, 161), "grey63" },
1698 { RGB_TO_ULONG(163, 163, 163), "gray64" },
1699 { RGB_TO_ULONG(163, 163, 163), "grey64" },
1700 { RGB_TO_ULONG(166, 166, 166), "gray65" },
1701 { RGB_TO_ULONG(166, 166, 166), "grey65" },
1702 { RGB_TO_ULONG(168, 168, 168), "gray66" },
1703 { RGB_TO_ULONG(168, 168, 168), "grey66" },
1704 { RGB_TO_ULONG(171, 171, 171), "gray67" },
1705 { RGB_TO_ULONG(171, 171, 171), "grey67" },
1706 { RGB_TO_ULONG(173, 173, 173), "gray68" },
1707 { RGB_TO_ULONG(173, 173, 173), "grey68" },
1708 { RGB_TO_ULONG(176, 176, 176), "gray69" },
1709 { RGB_TO_ULONG(176, 176, 176), "grey69" },
1710 { RGB_TO_ULONG(179, 179, 179), "gray70" },
1711 { RGB_TO_ULONG(179, 179, 179), "grey70" },
1712 { RGB_TO_ULONG(181, 181, 181), "gray71" },
1713 { RGB_TO_ULONG(181, 181, 181), "grey71" },
1714 { RGB_TO_ULONG(184, 184, 184), "gray72" },
1715 { RGB_TO_ULONG(184, 184, 184), "grey72" },
1716 { RGB_TO_ULONG(186, 186, 186), "gray73" },
1717 { RGB_TO_ULONG(186, 186, 186), "grey73" },
1718 { RGB_TO_ULONG(189, 189, 189), "gray74" },
1719 { RGB_TO_ULONG(189, 189, 189), "grey74" },
1720 { RGB_TO_ULONG(191, 191, 191), "gray75" },
1721 { RGB_TO_ULONG(191, 191, 191), "grey75" },
1722 { RGB_TO_ULONG(194, 194, 194), "gray76" },
1723 { RGB_TO_ULONG(194, 194, 194), "grey76" },
1724 { RGB_TO_ULONG(196, 196, 196), "gray77" },
1725 { RGB_TO_ULONG(196, 196, 196), "grey77" },
1726 { RGB_TO_ULONG(199, 199, 199), "gray78" },
1727 { RGB_TO_ULONG(199, 199, 199), "grey78" },
1728 { RGB_TO_ULONG(201, 201, 201), "gray79" },
1729 { RGB_TO_ULONG(201, 201, 201), "grey79" },
1730 { RGB_TO_ULONG(204, 204, 204), "gray80" },
1731 { RGB_TO_ULONG(204, 204, 204), "grey80" },
1732 { RGB_TO_ULONG(207, 207, 207), "gray81" },
1733 { RGB_TO_ULONG(207, 207, 207), "grey81" },
1734 { RGB_TO_ULONG(209, 209, 209), "gray82" },
1735 { RGB_TO_ULONG(209, 209, 209), "grey82" },
1736 { RGB_TO_ULONG(212, 212, 212), "gray83" },
1737 { RGB_TO_ULONG(212, 212, 212), "grey83" },
1738 { RGB_TO_ULONG(214, 214, 214), "gray84" },
1739 { RGB_TO_ULONG(214, 214, 214), "grey84" },
1740 { RGB_TO_ULONG(217, 217, 217), "gray85" },
1741 { RGB_TO_ULONG(217, 217, 217), "grey85" },
1742 { RGB_TO_ULONG(219, 219, 219), "gray86" },
1743 { RGB_TO_ULONG(219, 219, 219), "grey86" },
1744 { RGB_TO_ULONG(222, 222, 222), "gray87" },
1745 { RGB_TO_ULONG(222, 222, 222), "grey87" },
1746 { RGB_TO_ULONG(224, 224, 224), "gray88" },
1747 { RGB_TO_ULONG(224, 224, 224), "grey88" },
1748 { RGB_TO_ULONG(227, 227, 227), "gray89" },
1749 { RGB_TO_ULONG(227, 227, 227), "grey89" },
1750 { RGB_TO_ULONG(229, 229, 229), "gray90" },
1751 { RGB_TO_ULONG(229, 229, 229), "grey90" },
1752 { RGB_TO_ULONG(232, 232, 232), "gray91" },
1753 { RGB_TO_ULONG(232, 232, 232), "grey91" },
1754 { RGB_TO_ULONG(235, 235, 235), "gray92" },
1755 { RGB_TO_ULONG(235, 235, 235), "grey92" },
1756 { RGB_TO_ULONG(237, 237, 237), "gray93" },
1757 { RGB_TO_ULONG(237, 237, 237), "grey93" },
1758 { RGB_TO_ULONG(240, 240, 240), "gray94" },
1759 { RGB_TO_ULONG(240, 240, 240), "grey94" },
1760 { RGB_TO_ULONG(242, 242, 242), "gray95" },
1761 { RGB_TO_ULONG(242, 242, 242), "grey95" },
1762 { RGB_TO_ULONG(245, 245, 245), "gray96" },
1763 { RGB_TO_ULONG(245, 245, 245), "grey96" },
1764 { RGB_TO_ULONG(247, 247, 247), "gray97" },
1765 { RGB_TO_ULONG(247, 247, 247), "grey97" },
1766 { RGB_TO_ULONG(250, 250, 250), "gray98" },
1767 { RGB_TO_ULONG(250, 250, 250), "grey98" },
1768 { RGB_TO_ULONG(252, 252, 252), "gray99" },
1769 { RGB_TO_ULONG(252, 252, 252), "grey99" },
1770 { RGB_TO_ULONG(255, 255, 255), "gray100" },
1771 { RGB_TO_ULONG(255, 255, 255), "grey100" },
1772 { RGB_TO_ULONG(169, 169, 169), "dark grey" },
1773 { RGB_TO_ULONG(169, 169, 169), "DarkGrey" },
1774 { RGB_TO_ULONG(169, 169, 169), "dark gray" },
1775 { RGB_TO_ULONG(169, 169, 169), "DarkGray" },
1776 { RGB_TO_ULONG(0 , 0 , 139), "dark blue" },
1777 { RGB_TO_ULONG(0 , 0 , 139), "DarkBlue" },
1778 { RGB_TO_ULONG(0 , 139, 139), "dark cyan" },
1779 { RGB_TO_ULONG(0 , 139, 139), "DarkCyan" },
1780 { RGB_TO_ULONG(139, 0 , 139), "dark magenta" },
1781 { RGB_TO_ULONG(139, 0 , 139), "DarkMagenta" },
1782 { RGB_TO_ULONG(139, 0 , 0 ), "dark red" },
1783 { RGB_TO_ULONG(139, 0 , 0 ), "DarkRed" },
1784 { RGB_TO_ULONG(144, 238, 144), "light green" },
1785 { RGB_TO_ULONG(144, 238, 144), "LightGreen" }
1786};
1787
1788unsigned long
1789mac_color_map_lookup (colorname)
1790 char *colorname;
1791{
1792 Lisp_Object ret = Qnil;
1793 int i;
1794
1795 BLOCK_INPUT;
1796
1797 for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++)
1798 if (stricmp (colorname, mac_color_map[i].name) == 0)
1799 {
1800 ret = mac_color_map[i].color;
1801 break;
1802 }
1803
1804 UNBLOCK_INPUT;
1805
1806 return ret;
1807}
1808
1809Lisp_Object
1810x_to_mac_color (colorname)
1811 char * colorname;
1812{
1813 register Lisp_Object tail, ret = Qnil;
1814
1815 BLOCK_INPUT;
1816
1817 if (colorname[0] == '#')
1818 {
1819 /* Could be an old-style RGB Device specification. */
1820 char *color;
1821 int size;
1822 color = colorname + 1;
1823
1824 size = strlen(color);
1825 if (size == 3 || size == 6 || size == 9 || size == 12)
1826 {
1827 unsigned long colorval;
1828 int i, pos;
1829 pos = 0;
1830 size /= 3;
1831 colorval = 0;
1832
1833 for (i = 0; i < 3; i++)
1834 {
1835 char *end;
1836 char t;
1837 unsigned long value;
1838
1839 /* The check for 'x' in the following conditional takes into
1840 account the fact that strtol allows a "0x" in front of
1841 our numbers, and we don't. */
1842 if (!isxdigit(color[0]) || color[1] == 'x')
1843 break;
1844 t = color[size];
1845 color[size] = '\0';
1846 value = strtoul(color, &end, 16);
1847 color[size] = t;
1848 if (errno == ERANGE || end - color != size)
1849 break;
1850 switch (size)
1851 {
1852 case 1:
1853 value = value * 0x10;
1854 break;
1855 case 2:
1856 break;
1857 case 3:
1858 value /= 0x10;
1859 break;
1860 case 4:
1861 value /= 0x100;
1862 break;
1863 }
1864 colorval |= (value << pos);
1865 pos += 0x8;
1866 if (i == 2)
1867 {
1868 UNBLOCK_INPUT;
1869 return (colorval);
1870 }
1871 color = end;
1872 }
1873 }
1874 }
1875 else if (strnicmp(colorname, "rgb:", 4) == 0)
1876 {
1877 char *color;
1878 unsigned long colorval;
1879 int i, pos;
1880 pos = 0;
1881
1882 colorval = 0;
1883 color = colorname + 4;
1884 for (i = 0; i < 3; i++)
1885 {
1886 char *end;
1887 unsigned long value;
1888
1889 /* The check for 'x' in the following conditional takes into
1890 account the fact that strtol allows a "0x" in front of
1891 our numbers, and we don't. */
1892 if (!isxdigit(color[0]) || color[1] == 'x')
1893 break;
1894 value = strtoul(color, &end, 16);
1895 if (errno == ERANGE)
1896 break;
1897 switch (end - color)
1898 {
1899 case 1:
1900 value = value * 0x10 + value;
1901 break;
1902 case 2:
1903 break;
1904 case 3:
1905 value /= 0x10;
1906 break;
1907 case 4:
1908 value /= 0x100;
1909 break;
1910 default:
1911 value = ULONG_MAX;
1912 }
1913 if (value == ULONG_MAX)
1914 break;
1915 colorval |= (value << pos);
1916 pos += 0x8;
1917 if (i == 2)
1918 {
1919 if (*end != '\0')
1920 break;
1921 UNBLOCK_INPUT;
1922 return (colorval);
1923 }
1924 if (*end != '/')
1925 break;
1926 color = end + 1;
1927 }
1928 }
1929 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1930 {
1931 /* This is an RGB Intensity specification. */
1932 char *color;
1933 unsigned long colorval;
1934 int i, pos;
1935 pos = 0;
1936
1937 colorval = 0;
1938 color = colorname + 5;
1939 for (i = 0; i < 3; i++)
1940 {
1941 char *end;
1942 double value;
1943 unsigned long val;
1944
1945 value = strtod(color, &end);
1946 if (errno == ERANGE)
1947 break;
1948 if (value < 0.0 || value > 1.0)
1949 break;
1950 val = (unsigned long)(0x100 * value);
1951 /* We used 0x100 instead of 0xFF to give an continuous
1952 range between 0.0 and 1.0 inclusive. The next statement
1953 fixes the 1.0 case. */
1954 if (val == 0x100)
1955 val = 0xFF;
1956 colorval |= (val << pos);
1957 pos += 0x8;
1958 if (i == 2)
1959 {
1960 if (*end != '\0')
1961 break;
1962 UNBLOCK_INPUT;
1963 return (colorval);
1964 }
1965 if (*end != '/')
1966 break;
1967 color = end + 1;
1968 }
1969 }
1970
1971 ret = mac_color_map_lookup (colorname);
1972
1973 UNBLOCK_INPUT;
1974 return ret;
1975}
1976
1977/* Gamma-correct COLOR on frame F. */
1978
1979void
1980gamma_correct (f, color)
1981 struct frame *f;
1982 unsigned long *color;
1983{
1984 if (f->gamma)
1985 {
1986 unsigned long red, green, blue;
1987
1988 red = pow (RED_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
1989 green = pow (GREEN_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
1990 blue = pow (BLUE_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
1991 *color = RGB_TO_ULONG (red, green, blue);
1992 }
1993}
1994
1995/* Decide if color named COLOR is valid for the display associated
1996 with the selected frame; if so, return the rgb values in COLOR_DEF.
1997 If ALLOC is nonzero, allocate a new colormap cell. */
1998
1999int
2000mac_defined_color (f, color, color_def, alloc)
2001 FRAME_PTR f;
2002 char *color;
2003 XColor *color_def;
2004 int alloc;
2005{
2006 register Lisp_Object tem;
2007 unsigned long mac_color_ref;
2008
2009 tem = x_to_mac_color (color);
2010
2011 if (!NILP (tem))
2012 {
2013 if (f)
2014 {
2015 /* Apply gamma correction. */
2016 mac_color_ref = XUINT (tem);
2017 gamma_correct (f, &mac_color_ref);
2018 XSETINT (tem, mac_color_ref);
2019 }
2020
2021 color_def->pixel = mac_color_ref;
2022 color_def->red = RED_FROM_ULONG (mac_color_ref);
2023 color_def->green = GREEN_FROM_ULONG (mac_color_ref);
2024 color_def->blue = BLUE_FROM_ULONG (mac_color_ref);
2025
2026 return 1;
2027 }
2028 else
2029 {
2030 return 0;
2031 }
2032}
2033
2034/* Given a string ARG naming a color, compute a pixel value from it
2035 suitable for screen F.
2036 If F is not a color screen, return DEF (default) regardless of what
2037 ARG says. */
2038
2039int
2040x_decode_color (f, arg, def)
2041 FRAME_PTR f;
2042 Lisp_Object arg;
2043 int def;
2044{
2045 XColor cdef;
2046
2047 CHECK_STRING (arg, 0);
2048
2049 if (strcmp (XSTRING (arg)->data, "black") == 0)
2050 return BLACK_PIX_DEFAULT (f);
2051 else if (strcmp (XSTRING (arg)->data, "white") == 0)
2052 return WHITE_PIX_DEFAULT (f);
2053
2054#if 0
2055 if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes
2056 * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1)
2057 return def;
2058#endif
2059
2060 if (mac_defined_color (f, XSTRING (arg)->data, &cdef, 1))
2061 return cdef.pixel;
2062
2063 /* defined_color failed; return an ultimate default. */
2064 return def;
2065}
2066
2067/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2068 the previous value of that parameter, NEW_VALUE is the new value. */
2069
2070static void
2071x_set_line_spacing (f, new_value, old_value)
2072 struct frame *f;
2073 Lisp_Object new_value, old_value;
2074{
2075 if (NILP (new_value))
2076 f->extra_line_spacing = 0;
2077 else if (NATNUMP (new_value))
2078 f->extra_line_spacing = XFASTINT (new_value);
2079 else
2080 Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
2081 Fcons (new_value, Qnil)));
2082 if (FRAME_VISIBLE_P (f))
2083 redraw_frame (f);
2084}
2085
2086
2087/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2088 the previous value of that parameter, NEW_VALUE is the new value. */
2089
2090static void
2091x_set_screen_gamma (f, new_value, old_value)
2092 struct frame *f;
2093 Lisp_Object new_value, old_value;
2094{
2095 if (NILP (new_value))
2096 f->gamma = 0;
2097 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2098 /* The value 0.4545 is the normal viewing gamma. */
2099 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2100 else
2101 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
2102 Fcons (new_value, Qnil)));
2103
2104 clear_face_cache (0);
2105}
2106
2107
2108/* Functions called only from `x_set_frame_param'
2109 to set individual parameters.
2110
2111 If FRAME_MAC_WINDOW (f) is 0,
2112 the frame is being created and its window does not exist yet.
2113 In that case, just record the parameter's new value
2114 in the standard place; do not attempt to change the window. */
2115
2116void
2117x_set_foreground_color (f, arg, oldval)
2118 struct frame *f;
2119 Lisp_Object arg, oldval;
2120{
2121 FRAME_FOREGROUND_PIXEL (f)
2122 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2123
2124 if (FRAME_MAC_WINDOW (f) != 0)
2125 {
2126 update_face_from_frame_parameter (f, Qforeground_color, arg);
2127 if (FRAME_VISIBLE_P (f))
2128 redraw_frame (f);
2129 }
2130}
2131
2132void
2133x_set_background_color (f, arg, oldval)
2134 struct frame *f;
2135 Lisp_Object arg, oldval;
2136{
2137 FRAME_BACKGROUND_PIXEL (f)
2138 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2139
2140 if (FRAME_MAC_WINDOW (f) != 0)
2141 {
2142 update_face_from_frame_parameter (f, Qbackground_color, arg);
2143
2144 if (FRAME_VISIBLE_P (f))
2145 redraw_frame (f);
2146 }
2147}
2148
2149void
2150x_set_mouse_color (f, arg, oldval)
2151 struct frame *f;
2152 Lisp_Object arg, oldval;
2153{
2154 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2155 int count;
2156 int mask_color;
2157
2158 if (!EQ (Qnil, arg))
2159 f->output_data.mac->mouse_pixel
2160 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2161 mask_color = FRAME_BACKGROUND_PIXEL (f);
2162
2163 /* Don't let pointers be invisible. */
2164 if (mask_color == f->output_data.mac->mouse_pixel
2165 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2166 f->output_data.mac->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2167
2168#if 0 /* MAC_TODO : cursor changes */
2169 BLOCK_INPUT;
2170
2171 /* It's not okay to crash if the user selects a screwy cursor. */
2172 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2173
2174 if (!EQ (Qnil, Vx_pointer_shape))
2175 {
2176 CHECK_NUMBER (Vx_pointer_shape, 0);
2177 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2178 }
2179 else
2180 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2181 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2182
2183 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2184 {
2185 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
2186 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2187 XINT (Vx_nontext_pointer_shape));
2188 }
2189 else
2190 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2191 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2192
2193 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2194 {
2195 CHECK_NUMBER (Vx_hourglass_pointer_shape, 0);
2196 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2197 XINT (Vx_hourglass_pointer_shape));
2198 }
2199 else
2200 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2201 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2202
2203 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2204 if (!EQ (Qnil, Vx_mode_pointer_shape))
2205 {
2206 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
2207 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2208 XINT (Vx_mode_pointer_shape));
2209 }
2210 else
2211 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2212 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2213
2214 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2215 {
2216 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2217 cross_cursor
2218 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2219 XINT (Vx_sensitive_text_pointer_shape));
2220 }
2221 else
2222 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2223
2224 if (!NILP (Vx_window_horizontal_drag_shape))
2225 {
2226 CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
2227 horizontal_drag_cursor
2228 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2229 XINT (Vx_window_horizontal_drag_shape));
2230 }
2231 else
2232 horizontal_drag_cursor
2233 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2234
2235 /* Check and report errors with the above calls. */
2236 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2237 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2238
2239 {
2240 XColor fore_color, back_color;
2241
2242 fore_color.pixel = f->output_data.w32->mouse_pixel;
2243 back_color.pixel = mask_color;
2244 XQueryColor (FRAME_W32_DISPLAY (f),
2245 DefaultColormap (FRAME_W32_DISPLAY (f),
2246 DefaultScreen (FRAME_W32_DISPLAY (f))),
2247 &fore_color);
2248 XQueryColor (FRAME_W32_DISPLAY (f),
2249 DefaultColormap (FRAME_W32_DISPLAY (f),
2250 DefaultScreen (FRAME_W32_DISPLAY (f))),
2251 &back_color);
2252 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2253 &fore_color, &back_color);
2254 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2255 &fore_color, &back_color);
2256 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2257 &fore_color, &back_color);
2258 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2259 &fore_color, &back_color);
2260 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2261 &fore_color, &back_color);
2262 }
2263
2264 if (FRAME_W32_WINDOW (f) != 0)
2265 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2266
2267 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2268 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2269 f->output_data.w32->text_cursor = cursor;
2270
2271 if (nontext_cursor != f->output_data.w32->nontext_cursor
2272 && f->output_data.w32->nontext_cursor != 0)
2273 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2274 f->output_data.w32->nontext_cursor = nontext_cursor;
2275
2276 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2277 && f->output_data.w32->hourglass_cursor != 0)
2278 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2279 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2280
2281 if (mode_cursor != f->output_data.w32->modeline_cursor
2282 && f->output_data.w32->modeline_cursor != 0)
2283 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2284 f->output_data.w32->modeline_cursor = mode_cursor;
2285
2286 if (cross_cursor != f->output_data.w32->cross_cursor
2287 && f->output_data.w32->cross_cursor != 0)
2288 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2289 f->output_data.w32->cross_cursor = cross_cursor;
2290
2291 XFlush (FRAME_W32_DISPLAY (f));
2292 UNBLOCK_INPUT;
2293
2294 update_face_from_frame_parameter (f, Qmouse_color, arg);
2295#endif /* MAC_TODO */
2296}
2297
2298void
2299x_set_cursor_color (f, arg, oldval)
2300 struct frame *f;
2301 Lisp_Object arg, oldval;
2302{
2303 unsigned long fore_pixel;
2304
2305 if (!NILP (Vx_cursor_fore_pixel))
2306 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2307 WHITE_PIX_DEFAULT (f));
2308 else
2309 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2310 f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2311
2312 /* Make sure that the cursor color differs from the background color. */
2313 if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
2314 {
2315 f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel;
2316 if (f->output_data.mac->cursor_pixel == fore_pixel)
2317 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2318 }
2319 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2320
2321#if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */
2322 if (FRAME_MAC_WINDOW (f) != 0)
2323 {
2324 if (FRAME_VISIBLE_P (f))
2325 {
2326 x_display_cursor (f, 0);
2327 x_display_cursor (f, 1);
2328 }
2329 }
2330#endif
2331
2332 update_face_from_frame_parameter (f, Qcursor_color, arg);
2333}
2334
2335/* Set the border-color of frame F to pixel value PIX.
2336 Note that this does not fully take effect if done before
2337 F has an window. */
2338void
2339x_set_border_pixel (f, pix)
2340 struct frame *f;
2341 int pix;
2342{
2343 f->output_data.mac->border_pixel = pix;
2344
2345 if (FRAME_MAC_WINDOW (f) != 0 && f->output_data.mac->border_width > 0)
2346 {
2347 if (FRAME_VISIBLE_P (f))
2348 redraw_frame (f);
2349 }
2350}
2351
2352/* Set the border-color of frame F to value described by ARG.
2353 ARG can be a string naming a color.
2354 The border-color is used for the border that is drawn by the server.
2355 Note that this does not fully take effect if done before
2356 F has a window; it must be redone when the window is created. */
2357
2358void
2359x_set_border_color (f, arg, oldval)
2360 struct frame *f;
2361 Lisp_Object arg, oldval;
2362{
2363 int pix;
2364
2365 CHECK_STRING (arg, 0);
2366 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2367 x_set_border_pixel (f, pix);
2368 update_face_from_frame_parameter (f, Qborder_color, arg);
2369}
2370
2371/* Value is the internal representation of the specified cursor type
2372 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2373 of the bar cursor. */
2374
2375enum text_cursor_kinds
2376x_specified_cursor_type (arg, width)
2377 Lisp_Object arg;
2378 int *width;
2379{
2380 enum text_cursor_kinds type;
2381
2382 if (EQ (arg, Qbar))
2383 {
2384 type = BAR_CURSOR;
2385 *width = 2;
2386 }
2387 else if (CONSP (arg)
2388 && EQ (XCAR (arg), Qbar)
2389 && INTEGERP (XCDR (arg))
2390 && XINT (XCDR (arg)) >= 0)
2391 {
2392 type = BAR_CURSOR;
2393 *width = XINT (XCDR (arg));
2394 }
2395 else if (NILP (arg))
2396 type = NO_CURSOR;
2397 else
2398 /* Treat anything unknown as "box cursor".
2399 It was bad to signal an error; people have trouble fixing
2400 .Xdefaults with Emacs, when it has something bad in it. */
2401 type = FILLED_BOX_CURSOR;
2402
2403 return type;
2404}
2405
2406void
2407x_set_cursor_type (f, arg, oldval)
2408 FRAME_PTR f;
2409 Lisp_Object arg, oldval;
2410{
2411 int width;
2412
2413 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2414 f->output_data.mac->cursor_width = width;
2415
2416 /* Make sure the cursor gets redrawn. This is overkill, but how
2417 often do people change cursor types? */
2418 update_mode_lines++;
2419}
2420
2421#if 0 /* MAC_TODO: really no icon for Mac */
2422void
2423x_set_icon_type (f, arg, oldval)
2424 struct frame *f;
2425 Lisp_Object arg, oldval;
2426{
2427 int result;
2428
2429 if (NILP (arg) && NILP (oldval))
2430 return;
2431
2432 if (STRINGP (arg) && STRINGP (oldval)
2433 && EQ (Fstring_equal (oldval, arg), Qt))
2434 return;
2435
2436 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2437 return;
2438
2439 BLOCK_INPUT;
2440
2441 result = x_bitmap_icon (f, arg);
2442 if (result)
2443 {
2444 UNBLOCK_INPUT;
2445 error ("No icon window available");
2446 }
2447
2448 UNBLOCK_INPUT;
2449}
2450#endif
2451
2452/* Return non-nil if frame F wants a bitmap icon. */
2453
2454Lisp_Object
2455x_icon_type (f)
2456 FRAME_PTR f;
2457{
2458 Lisp_Object tem;
2459
2460 tem = assq_no_quit (Qicon_type, f->param_alist);
2461 if (CONSP (tem))
2462 return XCDR (tem);
2463 else
2464 return Qnil;
2465}
2466
2467void
2468x_set_icon_name (f, arg, oldval)
2469 struct frame *f;
2470 Lisp_Object arg, oldval;
2471{
2472 int result;
2473
2474 if (STRINGP (arg))
2475 {
2476 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2477 return;
2478 }
2479 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2480 return;
2481
2482 f->icon_name = arg;
2483
2484#if 0
2485 if (f->output_data.w32->icon_bitmap != 0)
2486 return;
2487
2488 BLOCK_INPUT;
2489
2490 result = x_text_icon (f,
2491 (char *) XSTRING ((!NILP (f->icon_name)
2492 ? f->icon_name
2493 : !NILP (f->title)
2494 ? f->title
2495 : f->name))->data);
2496
2497 if (result)
2498 {
2499 UNBLOCK_INPUT;
2500 error ("No icon window available");
2501 }
2502
2503 /* If the window was unmapped (and its icon was mapped),
2504 the new icon is not mapped, so map the window in its stead. */
2505 if (FRAME_VISIBLE_P (f))
2506 {
2507#ifdef USE_X_TOOLKIT
2508 XtPopup (f->output_data.w32->widget, XtGrabNone);
2509#endif
2510 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2511 }
2512
2513 XFlush (FRAME_W32_DISPLAY (f));
2514 UNBLOCK_INPUT;
2515#endif
2516}
2517
2518extern Lisp_Object x_new_font ();
2519extern Lisp_Object x_new_fontset();
2520
2521void
2522x_set_font (f, arg, oldval)
2523 struct frame *f;
2524 Lisp_Object arg, oldval;
2525{
2526 Lisp_Object result;
2527 Lisp_Object fontset_name;
2528 Lisp_Object frame;
2529
2530 CHECK_STRING (arg, 1);
2531
2532 fontset_name = Fquery_fontset (arg, Qnil);
2533
2534 BLOCK_INPUT;
2535 result = (STRINGP (fontset_name)
2536 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2537 : x_new_font (f, XSTRING (arg)->data));
2538 UNBLOCK_INPUT;
2539
2540 if (EQ (result, Qnil))
2541 error ("Font `%s' is not defined", XSTRING (arg)->data);
2542 else if (EQ (result, Qt))
2543 error ("The characters of the given font have varying widths");
2544 else if (STRINGP (result))
2545 {
2546 if (!NILP (Fequal (result, oldval)))
2547 return;
2548 store_frame_param (f, Qfont, result);
2549 recompute_basic_faces (f);
2550 }
2551 else
2552 abort ();
2553
2554 do_pending_window_change (0);
2555
2556 /* Don't call `face-set-after-frame-default' when faces haven't been
2557 initialized yet. This is the case when called from
2558 Fx_create_frame. In that case, the X widget or window doesn't
2559 exist either, and we can end up in x_report_frame_params with a
2560 null widget which gives a segfault. */
2561 if (FRAME_FACE_CACHE (f))
2562 {
2563 XSETFRAME (frame, f);
2564 call1 (Qface_set_after_frame_default, frame);
2565 }
2566}
2567
2568static void
2569x_set_fringe_width (f, new_value, old_value)
2570 struct frame *f;
2571 Lisp_Object new_value, old_value;
2572{
2573 x_compute_fringe_widths (f, 1);
2574}
2575
2576void
2577x_set_border_width (f, arg, oldval)
2578 struct frame *f;
2579 Lisp_Object arg, oldval;
2580{
2581 CHECK_NUMBER (arg, 0);
2582
2583 if (XINT (arg) == f->output_data.mac->border_width)
2584 return;
2585
2586#if 0
2587 if (FRAME_MAC_WINDOW (f) != 0)
2588 error ("Cannot change the border width of a window");
2589#endif
2590
2591 f->output_data.mac->border_width = XINT (arg);
2592}
2593
2594void
2595x_set_internal_border_width (f, arg, oldval)
2596 struct frame *f;
2597 Lisp_Object arg, oldval;
2598{
2599 int old = f->output_data.mac->internal_border_width;
2600
2601 CHECK_NUMBER (arg, 0);
2602 f->output_data.mac->internal_border_width = XINT (arg);
2603 if (f->output_data.mac->internal_border_width < 0)
2604 f->output_data.mac->internal_border_width = 0;
2605
2606 if (f->output_data.mac->internal_border_width == old)
2607 return;
2608
2609 if (FRAME_MAC_WINDOW (f) != 0)
2610 {
2611 x_set_window_size (f, 0, f->width, f->height);
2612 SET_FRAME_GARBAGED (f);
2613 do_pending_window_change (0);
2614 }
2615}
2616
2617void
2618x_set_visibility (f, value, oldval)
2619 struct frame *f;
2620 Lisp_Object value, oldval;
2621{
2622 Lisp_Object frame;
2623 XSETFRAME (frame, f);
2624
2625 if (NILP (value))
2626 Fmake_frame_invisible (frame, Qt);
2627 else if (EQ (value, Qicon))
2628 Ficonify_frame (frame);
2629 else
2630 Fmake_frame_visible (frame);
2631}
2632
2633
2634/* Change window heights in windows rooted in WINDOW by N lines. */
2635
2636static void
2637x_change_window_heights (window, n)
2638 Lisp_Object window;
2639 int n;
2640{
2641 struct window *w = XWINDOW (window);
2642
2643 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2644 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2645
2646 if (INTEGERP (w->orig_top))
2647 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2648 if (INTEGERP (w->orig_height))
2649 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2650
2651 /* Handle just the top child in a vertical split. */
2652 if (!NILP (w->vchild))
2653 x_change_window_heights (w->vchild, n);
2654
2655 /* Adjust all children in a horizontal split. */
2656 for (window = w->hchild; !NILP (window); window = w->next)
2657 {
2658 w = XWINDOW (window);
2659 x_change_window_heights (window, n);
2660 }
2661}
2662
2663void
2664x_set_menu_bar_lines (f, value, oldval)
2665 struct frame *f;
2666 Lisp_Object value, oldval;
2667{
2668 int nlines;
2669 int olines = FRAME_MENU_BAR_LINES (f);
2670
2671 /* Right now, menu bars don't work properly in minibuf-only frames;
2672 most of the commands try to apply themselves to the minibuffer
2673 frame itself, and get an error because you can't switch buffers
2674 in or split the minibuffer window. */
2675 if (FRAME_MINIBUF_ONLY_P (f))
2676 return;
2677
2678 if (INTEGERP (value))
2679 nlines = XINT (value);
2680 else
2681 nlines = 0;
2682
2683 FRAME_MENU_BAR_LINES (f) = 0;
2684 if (nlines)
2685 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2686 else
2687 {
2688 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2689 free_frame_menubar (f);
2690 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2691
2692 /* Adjust the frame size so that the client (text) dimensions
2693 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2694 set correctly. */
2695 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2696 do_pending_window_change (0);
2697 }
2698 adjust_glyphs (f);
2699}
2700
2701/* Set the number of lines used for the tool bar of frame F to VALUE.
2702 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2703 is the old number of tool bar lines. This function changes the
2704 height of all windows on frame F to match the new tool bar height.
2705 The frame's height doesn't change. */
2706
2707void
2708x_set_tool_bar_lines (f, value, oldval)
2709 struct frame *f;
2710 Lisp_Object value, oldval;
2711{
2712 int delta, nlines, root_height;
2713 Lisp_Object root_window;
2714
2715 /* Treat tool bars like menu bars. */
2716 if (FRAME_MINIBUF_ONLY_P (f))
2717 return;
2718
2719 /* Use VALUE only if an integer >= 0. */
2720 if (INTEGERP (value) && XINT (value) >= 0)
2721 nlines = XFASTINT (value);
2722 else
2723 nlines = 0;
2724
2725 /* Make sure we redisplay all windows in this frame. */
2726 ++windows_or_buffers_changed;
2727
2728 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2729
2730 /* Don't resize the tool-bar to more than we have room for. */
2731 root_window = FRAME_ROOT_WINDOW (f);
2732 root_height = XINT (XWINDOW (root_window)->height);
2733 if (root_height - delta < 1)
2734 {
2735 delta = root_height - 1;
2736 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2737 }
2738
2739 FRAME_TOOL_BAR_LINES (f) = nlines;
2740 x_change_window_heights (root_window, delta);
2741 adjust_glyphs (f);
2742
2743 /* We also have to make sure that the internal border at the top of
2744 the frame, below the menu bar or tool bar, is redrawn when the
2745 tool bar disappears. This is so because the internal border is
2746 below the tool bar if one is displayed, but is below the menu bar
2747 if there isn't a tool bar. The tool bar draws into the area
2748 below the menu bar. */
2749 if (FRAME_MAC_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2750 {
2751 updating_frame = f;
2752 clear_frame ();
2753 clear_current_matrices (f);
2754 updating_frame = NULL;
2755 }
2756
2757 /* If the tool bar gets smaller, the internal border below it
2758 has to be cleared. It was formerly part of the display
2759 of the larger tool bar, and updating windows won't clear it. */
2760 if (delta < 0)
2761 {
2762 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2763 int width = PIXEL_WIDTH (f);
2764 int y = nlines * CANON_Y_UNIT (f);
2765
2766 BLOCK_INPUT;
2767 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
2768 0, y, width, height, 0);
2769 UNBLOCK_INPUT;
2770 }
2771}
2772
2773
2774/* Change the name of frame F to NAME. If NAME is nil, set F's name to
2775 w32_id_name.
2776
2777 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2778 name; if NAME is a string, set F's name to NAME and set
2779 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2780
2781 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2782 suggesting a new name, which lisp code should override; if
2783 F->explicit_name is set, ignore the new name; otherwise, set it. */
2784
2785void
2786x_set_name (f, name, explicit)
2787 struct frame *f;
2788 Lisp_Object name;
2789 int explicit;
2790{
2791 /* Make sure that requests from lisp code override requests from
2792 Emacs redisplay code. */
2793 if (explicit)
2794 {
2795 /* If we're switching from explicit to implicit, we had better
2796 update the mode lines and thereby update the title. */
2797 if (f->explicit_name && NILP (name))
2798 update_mode_lines = 1;
2799
2800 f->explicit_name = ! NILP (name);
2801 }
2802 else if (f->explicit_name)
2803 return;
2804
2805 /* If NAME is nil, set the name to the w32_id_name. */
2806 if (NILP (name))
2807 {
2808 /* Check for no change needed in this very common case
2809 before we do any consing. */
2810 if (!strcmp (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name,
2811 XSTRING (f->name)->data))
2812 return;
2813 name = build_string (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name);
2814 }
2815 else
2816 CHECK_STRING (name, 0);
2817
2818 /* Don't change the name if it's already NAME. */
2819 if (! NILP (Fstring_equal (name, f->name)))
2820 return;
2821
2822 f->name = name;
2823
2824 /* For setting the frame title, the title parameter should override
2825 the name parameter. */
2826 if (! NILP (f->title))
2827 name = f->title;
2828
2829 if (FRAME_MAC_WINDOW (f))
2830 {
2831 if (STRING_MULTIBYTE (name))
2832#if 0 /* MAC_TODO: encoding title string */
2833 name = ENCODE_SYSTEM (name);
2834#else
2835 return;
2836#endif
2837
2838 BLOCK_INPUT;
2839
2840 {
2841 Str255 windowTitle;
2842 if (strlen (XSTRING (name)->data) < 255)
2843 {
2844 strcpy (windowTitle, XSTRING (name)->data);
2845 c2pstr (windowTitle);
2846 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2847 }
2848 }
2849
2850 UNBLOCK_INPUT;
2851 }
2852}
2853
2854/* This function should be called when the user's lisp code has
2855 specified a name for the frame; the name will override any set by the
2856 redisplay code. */
2857void
2858x_explicitly_set_name (f, arg, oldval)
2859 FRAME_PTR f;
2860 Lisp_Object arg, oldval;
2861{
2862 x_set_name (f, arg, 1);
2863}
2864
2865/* This function should be called by Emacs redisplay code to set the
2866 name; names set this way will never override names set by the user's
2867 lisp code. */
2868void
2869x_implicitly_set_name (f, arg, oldval)
2870 FRAME_PTR f;
2871 Lisp_Object arg, oldval;
2872{
2873 x_set_name (f, arg, 0);
2874}
2875
2876/* Change the title of frame F to NAME.
2877 If NAME is nil, use the frame name as the title.
2878
2879 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2880 name; if NAME is a string, set F's name to NAME and set
2881 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2882
2883 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2884 suggesting a new name, which lisp code should override; if
2885 F->explicit_name is set, ignore the new name; otherwise, set it. */
2886
2887void
2888x_set_title (f, name, old_name)
2889 struct frame *f;
2890 Lisp_Object name, old_name;
2891{
2892 /* Don't change the title if it's already NAME. */
2893 if (EQ (name, f->title))
2894 return;
2895
2896 update_mode_lines = 1;
2897
2898 f->title = name;
2899
2900 if (NILP (name))
2901 name = f->name;
2902
2903 if (FRAME_MAC_WINDOW (f))
2904 {
2905 if (STRING_MULTIBYTE (name))
2906#if 0 /* MAC_TODO: encoding title string */
2907 name = ENCODE_SYSTEM (name);
2908#else
2909 return;
2910#endif
2911
2912 BLOCK_INPUT;
2913
2914 {
2915 Str255 windowTitle;
2916 if (strlen (XSTRING (name)->data) < 255)
2917 {
2918 strcpy (windowTitle, XSTRING (name)->data);
2919 c2pstr (windowTitle);
2920 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2921 }
2922 }
2923
2924 UNBLOCK_INPUT;
2925 }
2926}
2927
2928void
2929x_set_autoraise (f, arg, oldval)
2930 struct frame *f;
2931 Lisp_Object arg, oldval;
2932{
2933 f->auto_raise = !EQ (Qnil, arg);
2934}
2935
2936void
2937x_set_autolower (f, arg, oldval)
2938 struct frame *f;
2939 Lisp_Object arg, oldval;
2940{
2941 f->auto_lower = !EQ (Qnil, arg);
2942}
2943
2944void
2945x_set_unsplittable (f, arg, oldval)
2946 struct frame *f;
2947 Lisp_Object arg, oldval;
2948{
2949 f->no_split = !NILP (arg);
2950}
2951
2952void
2953x_set_vertical_scroll_bars (f, arg, oldval)
2954 struct frame *f;
2955 Lisp_Object arg, oldval;
2956{
2957 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2958 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2959 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2960 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2961 {
2962 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2963 = (NILP (arg)
2964 ? vertical_scroll_bar_none
2965 : EQ (Qright, arg)
2966 ? vertical_scroll_bar_right
2967 : vertical_scroll_bar_left);
2968
2969 /* We set this parameter before creating the window for the
2970 frame, so we can get the geometry right from the start.
2971 However, if the window hasn't been created yet, we shouldn't
2972 call x_set_window_size. */
2973 if (FRAME_MAC_WINDOW (f))
2974 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2975 do_pending_window_change (0);
2976 }
2977}
2978
2979void
2980x_set_scroll_bar_width (f, arg, oldval)
2981 struct frame *f;
2982 Lisp_Object arg, oldval;
2983{
2984 /* Imitate X without X Toolkit */
2985
2986 int wid = FONT_WIDTH (f->output_data.mac->font);
2987
2988 if (NILP (arg))
2989 {
2990 /* Make the actual width at least 14 pixels and a multiple of a
2991 character width. */
2992 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
2993
2994 /* Use all of that space (aside from required margins) for the
2995 scroll bar. */
2996 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
2997
2998 if (FRAME_MAC_WINDOW (f))
2999 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
3000 do_pending_window_change (0);
3001 }
3002 else if (INTEGERP (arg) && XINT (arg) > 0
3003 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
3004 {
3005 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
3006 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
3007
3008 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
3009 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
3010 if (FRAME_MAC_WINDOW (f))
3011 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
3012 do_pending_window_change (0);
3013 }
3014 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
3015 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
3016 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
3017}
3018
3019/* Subroutines of creating an frame. */
3020
3021/* Make sure that Vx_resource_name is set to a reasonable value.
3022 Fix it up, or set it to `emacs' if it is too hopeless. */
3023
3024static void
3025validate_x_resource_name ()
3026{
3027 int len = 0;
3028 /* Number of valid characters in the resource name. */
3029 int good_count = 0;
3030 /* Number of invalid characters in the resource name. */
3031 int bad_count = 0;
3032 Lisp_Object new;
3033 int i;
3034
3035 if (STRINGP (Vx_resource_name))
3036 {
3037 unsigned char *p = XSTRING (Vx_resource_name)->data;
3038 int i;
3039
3040 len = STRING_BYTES (XSTRING (Vx_resource_name));
3041
3042 /* Only letters, digits, - and _ are valid in resource names.
3043 Count the valid characters and count the invalid ones. */
3044 for (i = 0; i < len; i++)
3045 {
3046 int c = p[i];
3047 if (! ((c >= 'a' && c <= 'z')
3048 || (c >= 'A' && c <= 'Z')
3049 || (c >= '0' && c <= '9')
3050 || c == '-' || c == '_'))
3051 bad_count++;
3052 else
3053 good_count++;
3054 }
3055 }
3056 else
3057 /* Not a string => completely invalid. */
3058 bad_count = 5, good_count = 0;
3059
3060 /* If name is valid already, return. */
3061 if (bad_count == 0)
3062 return;
3063
3064 /* If name is entirely invalid, or nearly so, use `emacs'. */
3065 if (good_count == 0
3066 || (good_count == 1 && bad_count > 0))
3067 {
3068 Vx_resource_name = build_string ("emacs");
3069 return;
3070 }
3071
3072 /* Name is partly valid. Copy it and replace the invalid characters
3073 with underscores. */
3074
3075 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3076
3077 for (i = 0; i < len; i++)
3078 {
3079 int c = XSTRING (new)->data[i];
3080 if (! ((c >= 'a' && c <= 'z')
3081 || (c >= 'A' && c <= 'Z')
3082 || (c >= '0' && c <= '9')
3083 || c == '-' || c == '_'))
3084 XSTRING (new)->data[i] = '_';
3085 }
3086}
3087
3088
3089#if 0 /* MAC_TODO: implement resource strings */
3090extern char *x_get_string_resource ();
3091
3092DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
3093 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
3094This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
3095class, where INSTANCE is the name under which Emacs was invoked, or\n\
3096the name specified by the `-name' or `-rn' command-line arguments.\n\
3097\n\
3098The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
3099class, respectively. You must specify both of them or neither.\n\
3100If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
3101and the class is `Emacs.CLASS.SUBCLASS'.")
3102 (attribute, class, component, subclass)
3103 Lisp_Object attribute, class, component, subclass;
3104{
3105 register char *value;
3106 char *name_key;
3107 char *class_key;
3108
3109 CHECK_STRING (attribute, 0);
3110 CHECK_STRING (class, 0);
3111
3112 if (!NILP (component))
3113 CHECK_STRING (component, 1);
3114 if (!NILP (subclass))
3115 CHECK_STRING (subclass, 2);
3116 if (NILP (component) != NILP (subclass))
3117 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3118
3119 validate_x_resource_name ();
3120
3121 /* Allocate space for the components, the dots which separate them,
3122 and the final '\0'. Make them big enough for the worst case. */
3123 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
3124 + (STRINGP (component)
3125 ? STRING_BYTES (XSTRING (component)) : 0)
3126 + STRING_BYTES (XSTRING (attribute))
3127 + 3);
3128
3129 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3130 + STRING_BYTES (XSTRING (class))
3131 + (STRINGP (subclass)
3132 ? STRING_BYTES (XSTRING (subclass)) : 0)
3133 + 3);
3134
3135 /* Start with emacs.FRAMENAME for the name (the specific one)
3136 and with `Emacs' for the class key (the general one). */
3137 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3138 strcpy (class_key, EMACS_CLASS);
3139
3140 strcat (class_key, ".");
3141 strcat (class_key, XSTRING (class)->data);
3142
3143 if (!NILP (component))
3144 {
3145 strcat (class_key, ".");
3146 strcat (class_key, XSTRING (subclass)->data);
3147
3148 strcat (name_key, ".");
3149 strcat (name_key, XSTRING (component)->data);
3150 }
3151
3152 strcat (name_key, ".");
3153 strcat (name_key, XSTRING (attribute)->data);
3154
3155 value = x_get_string_resource (Qnil,
3156 name_key, class_key);
3157
3158 if (value != (char *) 0)
3159 return build_string (value);
3160 else
3161 return Qnil;
3162}
3163
3164/* Used when C code wants a resource value. */
3165
3166char *
3167x_get_resource_string (attribute, class)
3168 char *attribute, *class;
3169{
3170 char *name_key;
3171 char *class_key;
3172 struct frame *sf = SELECTED_FRAME ();
3173
3174 /* Allocate space for the components, the dots which separate them,
3175 and the final '\0'. */
3176 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3177 + strlen (attribute) + 2);
3178 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3179 + strlen (class) + 2);
3180
3181 sprintf (name_key, "%s.%s",
3182 XSTRING (Vinvocation_name)->data,
3183 attribute);
3184 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3185
3186 return x_get_string_resource (sf, name_key, class_key);
3187}
3188#endif
3189
3190/* Types we might convert a resource string into. */
3191enum resource_types
3192{
3193 RES_TYPE_NUMBER,
3194 RES_TYPE_FLOAT,
3195 RES_TYPE_BOOLEAN,
3196 RES_TYPE_STRING,
3197 RES_TYPE_SYMBOL
3198};
3199
3200/* Return the value of parameter PARAM.
3201
3202 First search ALIST, then Vdefault_frame_alist, then the X defaults
3203 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3204
3205 Convert the resource to the type specified by desired_type.
3206
3207 If no default is specified, return Qunbound. If you call
3208 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3209 and don't let it get stored in any Lisp-visible variables! */
3210
3211static Lisp_Object
3212mac_get_arg (alist, param, attribute, class, type)
3213 Lisp_Object alist, param;
3214 char *attribute;
3215 char *class;
3216 enum resource_types type;
3217{
3218 register Lisp_Object tem;
3219
3220 tem = Fassq (param, alist);
3221 if (EQ (tem, Qnil))
3222 tem = Fassq (param, Vdefault_frame_alist);
3223 if (EQ (tem, Qnil))
3224 {
3225
3226#if 0 /* MAC_TODO: search resource also */
3227 if (attribute)
3228 {
3229 tem = Fx_get_resource (build_string (attribute),
3230 build_string (class),
3231 Qnil, Qnil);
3232
3233 if (NILP (tem))
3234 return Qunbound;
3235
3236 switch (type)
3237 {
3238 case RES_TYPE_NUMBER:
3239 return make_number (atoi (XSTRING (tem)->data));
3240
3241 case RES_TYPE_FLOAT:
3242 return make_float (atof (XSTRING (tem)->data));
3243
3244 case RES_TYPE_BOOLEAN:
3245 tem = Fdowncase (tem);
3246 if (!strcmp (XSTRING (tem)->data, "on")
3247 || !strcmp (XSTRING (tem)->data, "true"))
3248 return Qt;
3249 else
3250 return Qnil;
3251
3252 case RES_TYPE_STRING:
3253 return tem;
3254
3255 case RES_TYPE_SYMBOL:
3256 /* As a special case, we map the values `true' and `on'
3257 to Qt, and `false' and `off' to Qnil. */
3258 {
3259 Lisp_Object lower;
3260 lower = Fdowncase (tem);
3261 if (!strcmp (XSTRING (lower)->data, "on")
3262 || !strcmp (XSTRING (lower)->data, "true"))
3263 return Qt;
3264 else if (!strcmp (XSTRING (lower)->data, "off")
3265 || !strcmp (XSTRING (lower)->data, "false"))
3266 return Qnil;
3267 else
3268 return Fintern (tem, Qnil);
3269 }
3270
3271 default:
3272 abort ();
3273 }
3274 }
3275 else
3276#endif
3277 return Qunbound;
3278 }
3279 return Fcdr (tem);
3280}
3281
3282/* Record in frame F the specified or default value according to ALIST
3283 of the parameter named PROP (a Lisp symbol).
3284 If no value is specified for PROP, look for an X default for XPROP
3285 on the frame named NAME.
3286 If that is not found either, use the value DEFLT. */
3287
3288static Lisp_Object
3289x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3290 struct frame *f;
3291 Lisp_Object alist;
3292 Lisp_Object prop;
3293 Lisp_Object deflt;
3294 char *xprop;
3295 char *xclass;
3296 enum resource_types type;
3297{
3298 Lisp_Object tem;
3299
3300 tem = mac_get_arg (alist, prop, xprop, xclass, type);
3301 if (EQ (tem, Qunbound))
3302 tem = deflt;
3303 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3304 return tem;
3305}
3306
3307DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3308 "Parse an X-style geometry string STRING.\n\
3309Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3310The properties returned may include `top', `left', `height', and `width'.\n\
3311The value of `left' or `top' may be an integer,\n\
3312or a list (+ N) meaning N pixels relative to top/left corner,\n\
3313or a list (- N) meaning -N pixels relative to bottom/right corner.")
3314 (string)
3315 Lisp_Object string;
3316{
3317 int geometry, x, y;
3318 unsigned int width, height;
3319 Lisp_Object result;
3320
3321 CHECK_STRING (string, 0);
3322
3323 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3324 &x, &y, &width, &height);
3325
3326 result = Qnil;
3327 if (geometry & XValue)
3328 {
3329 Lisp_Object element;
3330
3331 if (x >= 0 && (geometry & XNegative))
3332 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3333 else if (x < 0 && ! (geometry & XNegative))
3334 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3335 else
3336 element = Fcons (Qleft, make_number (x));
3337 result = Fcons (element, result);
3338 }
3339
3340 if (geometry & YValue)
3341 {
3342 Lisp_Object element;
3343
3344 if (y >= 0 && (geometry & YNegative))
3345 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3346 else if (y < 0 && ! (geometry & YNegative))
3347 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3348 else
3349 element = Fcons (Qtop, make_number (y));
3350 result = Fcons (element, result);
3351 }
3352
3353 if (geometry & WidthValue)
3354 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3355 if (geometry & HeightValue)
3356 result = Fcons (Fcons (Qheight, make_number (height)), result);
3357
3358 return result;
3359}
3360
3361/* Calculate the desired size and position of this window,
3362 and return the flags saying which aspects were specified.
3363
3364 This function does not make the coordinates positive. */
3365
3366#define DEFAULT_ROWS 40
3367#define DEFAULT_COLS 80
3368
3369static int
3370x_figure_window_size (f, parms)
3371 struct frame *f;
3372 Lisp_Object parms;
3373{
3374 register Lisp_Object tem0, tem1, tem2;
3375 long window_prompting = 0;
3376
3377 /* Default values if we fall through.
3378 Actually, if that happens we should get
3379 window manager prompting. */
3380 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3381 f->height = DEFAULT_ROWS;
3382 /* Window managers expect that if program-specified
3383 positions are not (0,0), they're intentional, not defaults. */
3384 f->output_data.mac->top_pos = 0;
3385 f->output_data.mac->left_pos = 0;
3386
3387 tem0 = mac_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3388 tem1 = mac_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3389 tem2 = mac_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3390 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3391 {
3392 if (!EQ (tem0, Qunbound))
3393 {
3394 CHECK_NUMBER (tem0, 0);
3395 f->height = XINT (tem0);
3396 }
3397 if (!EQ (tem1, Qunbound))
3398 {
3399 CHECK_NUMBER (tem1, 0);
3400 SET_FRAME_WIDTH (f, XINT (tem1));
3401 }
3402 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3403 window_prompting |= USSize;
3404 else
3405 window_prompting |= PSize;
3406 }
3407
3408 f->output_data.mac->vertical_scroll_bar_extra
3409 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3410 ? 0
3411 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3412 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3413 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
3414 x_compute_fringe_widths (f, 0);
3415 f->output_data.mac->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3416 f->output_data.mac->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3417
3418 tem0 = mac_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3419 tem1 = mac_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3420 tem2 = mac_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3421 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3422 {
3423 if (EQ (tem0, Qminus))
3424 {
3425 f->output_data.mac->top_pos = 0;
3426 window_prompting |= YNegative;
3427 }
3428 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3429 && CONSP (XCDR (tem0))
3430 && INTEGERP (XCAR (XCDR (tem0))))
3431 {
3432 f->output_data.mac->top_pos = - XINT (XCAR (XCDR (tem0)));
3433 window_prompting |= YNegative;
3434 }
3435 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3436 && CONSP (XCDR (tem0))
3437 && INTEGERP (XCAR (XCDR (tem0))))
3438 {
3439 f->output_data.mac->top_pos = XINT (XCAR (XCDR (tem0)));
3440 }
3441 else if (EQ (tem0, Qunbound))
3442 f->output_data.mac->top_pos = 0;
3443 else
3444 {
3445 CHECK_NUMBER (tem0, 0);
3446 f->output_data.mac->top_pos = XINT (tem0);
3447 if (f->output_data.mac->top_pos < 0)
3448 window_prompting |= YNegative;
3449 }
3450
3451 if (EQ (tem1, Qminus))
3452 {
3453 f->output_data.mac->left_pos = 0;
3454 window_prompting |= XNegative;
3455 }
3456 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3457 && CONSP (XCDR (tem1))
3458 && INTEGERP (XCAR (XCDR (tem1))))
3459 {
3460 f->output_data.mac->left_pos = - XINT (XCAR (XCDR (tem1)));
3461 window_prompting |= XNegative;
3462 }
3463 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3464 && CONSP (XCDR (tem1))
3465 && INTEGERP (XCAR (XCDR (tem1))))
3466 {
3467 f->output_data.mac->left_pos = XINT (XCAR (XCDR (tem1)));
3468 }
3469 else if (EQ (tem1, Qunbound))
3470 f->output_data.mac->left_pos = 0;
3471 else
3472 {
3473 CHECK_NUMBER (tem1, 0);
3474 f->output_data.mac->left_pos = XINT (tem1);
3475 if (f->output_data.mac->left_pos < 0)
3476 window_prompting |= XNegative;
3477 }
3478
3479 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3480 window_prompting |= USPosition;
3481 else
3482 window_prompting |= PPosition;
3483 }
3484
3485 return window_prompting;
3486}
3487
3488
3489#if 0
3490/* Create and set up the Mac window for frame F. */
3491
3492static void
3493mac_window (f, window_prompting, minibuffer_only)
3494 struct frame *f;
3495 long window_prompting;
3496 int minibuffer_only;
3497{
3498 Rect r;
3499
3500 BLOCK_INPUT;
3501
3502 /* Use the resource name as the top-level window name
3503 for looking up resources. Make a non-Lisp copy
3504 for the window manager, so GC relocation won't bother it.
3505
3506 Elsewhere we specify the window name for the window manager. */
3507
3508 {
3509 char *str = (char *) XSTRING (Vx_resource_name)->data;
3510 f->namebuf = (char *) xmalloc (strlen (str) + 1);
3511 strcpy (f->namebuf, str);
3512 }
3513
3514 SetRect (&r, f->output_data.mac->left_pos, f->output_data.mac->top_pos,
3515 f->output_data.mac->left_pos + PIXEL_WIDTH (f),
3516 f->output_data.mac->top_pos + PIXEL_HEIGHT (f));
3517 FRAME_MAC_WINDOW (f)
3518 = NewCWindow (NULL, &r, "\p", 1, zoomDocProc, (WindowPtr) -1, 1, (long) f->output_data.mac);
3519
3520 validate_x_resource_name ();
3521
3522 /* x_set_name normally ignores requests to set the name if the
3523 requested name is the same as the current name. This is the one
3524 place where that assumption isn't correct; f->name is set, but
3525 the server hasn't been told. */
3526 {
3527 Lisp_Object name;
3528 int explicit = f->explicit_name;
3529
3530 f->explicit_name = 0;
3531 name = f->name;
3532 f->name = Qnil;
3533 x_set_name (f, name, explicit);
3534 }
3535
3536 ShowWindow (FRAME_MAC_WINDOW (f));
3537
3538 UNBLOCK_INPUT;
3539
3540 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
3541 initialize_frame_menubar (f);
3542
3543 if (FRAME_MAC_WINDOW (f) == 0)
3544 error ("Unable to create window");
3545}
3546#endif
3547
3548/* Handle the icon stuff for this window. Perhaps later we might
3549 want an x_set_icon_position which can be called interactively as
3550 well. */
3551
3552static void
3553x_icon (f, parms)
3554 struct frame *f;
3555 Lisp_Object parms;
3556{
3557 Lisp_Object icon_x, icon_y;
3558
3559 /* Set the position of the icon. Note that Windows 95 groups all
3560 icons in the tray. */
3561 icon_x = mac_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
3562 icon_y = mac_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
3563 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
3564 {
3565 CHECK_NUMBER (icon_x, 0);
3566 CHECK_NUMBER (icon_y, 0);
3567 }
3568 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
3569 error ("Both left and top icon corners of icon must be specified");
3570
3571 BLOCK_INPUT;
3572
3573 if (! EQ (icon_x, Qunbound))
3574 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
3575
3576#if 0 /* TODO */
3577 /* Start up iconic or window? */
3578 x_wm_set_window_state
3579 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
3580 ? IconicState
3581 : NormalState));
3582
3583 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
3584 ? f->icon_name
3585 : f->name))->data);
3586#endif
3587
3588 UNBLOCK_INPUT;
3589}
3590
3591
3592static void
3593x_make_gc (f)
3594 struct frame *f;
3595{
3596 XGCValues gc_values;
3597
3598 BLOCK_INPUT;
3599
3600 /* Create the GC's of this frame.
3601 Note that many default values are used. */
3602
3603 /* Normal video */
3604 gc_values.font = f->output_data.mac->font;
3605 gc_values.foreground = f->output_data.mac->foreground_pixel;
3606 gc_values.background = f->output_data.mac->background_pixel;
3607 f->output_data.mac->normal_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3608 FRAME_MAC_WINDOW (f),
3609 GCFont | GCForeground | GCBackground,
3610 &gc_values);
3611
3612 /* Reverse video style. */
3613 gc_values.foreground = f->output_data.mac->background_pixel;
3614 gc_values.background = f->output_data.mac->foreground_pixel;
3615 f->output_data.mac->reverse_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3616 FRAME_MAC_WINDOW (f),
3617 GCFont | GCForeground | GCBackground,
3618 &gc_values);
3619
3620 /* Cursor has cursor-color background, background-color foreground. */
3621 gc_values.foreground = f->output_data.mac->background_pixel;
3622 gc_values.background = f->output_data.mac->cursor_pixel;
3623 f->output_data.mac->cursor_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3624 FRAME_MAC_WINDOW (f),
3625 GCFont | GCForeground | GCBackground,
3626 &gc_values);
3627
3628 /* Reliefs. */
3629 f->output_data.mac->white_relief.gc = 0;
3630 f->output_data.mac->black_relief.gc = 0;
3631
3632 UNBLOCK_INPUT;
3633}
3634
3635
3636DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
3637 1, 1, 0,
3638 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
3639Returns an Emacs frame object.\n\
3640ALIST is an alist of frame parameters.\n\
3641If the parameters specify that the frame should not have a minibuffer,\n\
3642and do not specify a specific minibuffer window to use,\n\
3643then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
3644be shared by the new frame.\n\
3645\n\
3646This function is an internal primitive--use `make-frame' instead.")
3647 (parms)
3648 Lisp_Object parms;
3649{
3650 struct frame *f;
3651 Lisp_Object frame, tem;
3652 Lisp_Object name;
3653 int minibuffer_only = 0;
3654 long window_prompting = 0;
3655 int width, height;
3656 int count = BINDING_STACK_SIZE ();
3657 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3658 Lisp_Object display;
3659 struct mac_display_info *dpyinfo = NULL;
3660 Lisp_Object parent;
3661 struct kboard *kb;
3662 char x_frame_name[10];
3663 static int x_frame_count = 2; /* starts from 2 because terminal frame is F1 */
3664
3665 check_mac ();
3666
3667 /* Use this general default value to start with
3668 until we know if this frame has a specified name. */
3669 Vx_resource_name = Vinvocation_name;
3670
3671 display = mac_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
3672 if (EQ (display, Qunbound))
3673 display = Qnil;
3674 dpyinfo = check_x_display_info (display);
3675#ifdef MULTI_KBOARD
3676 kb = dpyinfo->kboard;
3677#else
3678 kb = &the_only_kboard;
3679#endif
3680
3681 name = mac_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
3682 if (!STRINGP (name)
3683 && ! EQ (name, Qunbound)
3684 && ! NILP (name))
3685 error ("Invalid frame name--not a string or nil");
3686
3687 if (STRINGP (name))
3688 Vx_resource_name = name;
3689
3690 /* See if parent window is specified. */
3691 parent = mac_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
3692 if (EQ (parent, Qunbound))
3693 parent = Qnil;
3694 if (! NILP (parent))
3695 CHECK_NUMBER (parent, 0);
3696
3697 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
3698 /* No need to protect DISPLAY because that's not used after passing
3699 it to make_frame_without_minibuffer. */
3700 frame = Qnil;
3701 GCPRO4 (parms, parent, name, frame);
3702 tem = mac_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
3703 if (EQ (tem, Qnone) || NILP (tem))
3704 f = make_frame_without_minibuffer (Qnil, kb, display);
3705 else if (EQ (tem, Qonly))
3706 {
3707 f = make_minibuffer_frame ();
3708 minibuffer_only = 1;
3709 }
3710 else if (WINDOWP (tem))
3711 f = make_frame_without_minibuffer (tem, kb, display);
3712 else
3713 f = make_frame (1);
3714
3715 if (EQ (name, Qunbound) || NILP (name))
3716 {
3717 sprintf (x_frame_name, "F%d", x_frame_count++);
3718 f->name = build_string (x_frame_name);
3719 f->explicit_name = 0;
3720 }
3721 else
3722 {
3723 f->name = name;
3724 f->explicit_name = 1;
3725 }
3726
3727 XSETFRAME (frame, f);
3728
3729 /* Note that X Windows does support scroll bars. */
3730 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
3731
3732 f->output_method = output_mac;
3733 f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output));
3734 bzero (f->output_data.mac, sizeof (struct mac_output));
3735 f->output_data.mac->fontset = -1;
3736 f->output_data.mac->scroll_bar_foreground_pixel = -1;
3737 f->output_data.mac->scroll_bar_background_pixel = -1;
3738
3739#if 0
3740 FRAME_FONTSET (f) = -1;
3741#endif
3742
3743 f->icon_name
3744 = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
3745 if (! STRINGP (f->icon_name))
3746 f->icon_name = Qnil;
3747
3748/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
3749#ifdef MULTI_KBOARD
3750 FRAME_KBOARD (f) = kb;
3751#endif
3752
3753 /* Specify the parent under which to make this window. */
3754
3755 if (!NILP (parent))
3756 {
3757 f->output_data.mac->parent_desc = (Window) parent;
3758 f->output_data.mac->explicit_parent = 1;
3759 }
3760 else
3761 {
3762 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3763 f->output_data.mac->explicit_parent = 0;
3764 }
3765
3766 /* Set the name; the functions to which we pass f expect the name to
3767 be set. */
3768 if (EQ (name, Qunbound) || NILP (name))
3769 {
3770 f->name = build_string (dpyinfo->mac_id_name);
3771 f->explicit_name = 0;
3772 }
3773 else
3774 {
3775 f->name = name;
3776 f->explicit_name = 1;
3777 /* use the frame's title when getting resources for this frame. */
3778 specbind (Qx_resource_name, name);
3779 }
3780
3781 /* Extract the window parameters from the supplied values
3782 that are needed to determine window geometry. */
3783 {
3784 Lisp_Object font;
3785
3786 font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
3787
3788 BLOCK_INPUT;
3789 /* First, try whatever font the caller has specified. */
3790 if (STRINGP (font))
3791 {
3792 tem = Fquery_fontset (font, Qnil);
3793 if (STRINGP (tem))
3794 font = x_new_fontset (f, XSTRING (tem)->data);
3795 else
3796 font = x_new_font (f, XSTRING (font)->data);
3797 }
3798 /* Try out a font which we hope has bold and italic variations. */
3799 if (! STRINGP (font))
3800 font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1");
3801 /* If those didn't work, look for something which will at least work. */
3802 if (!STRINGP (font))
3803 font = x_new_font (f, "-*-monaco-*-12-*-mac-roman");
3804 if (! STRINGP (font))
3805 font = x_new_font (f, "-*-courier-*-10-*-mac-roman");
3806 if (! STRINGP (font))
3807 error ("Cannot find any usable font");
3808 UNBLOCK_INPUT;
3809
3810 x_default_parameter (f, parms, Qfont, font,
3811 "font", "Font", RES_TYPE_STRING);
3812 }
3813
3814 x_default_parameter (f, parms, Qborder_width, make_number (0),
3815 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
3816 /* This defaults to 2 in order to match xterm. We recognize either
3817 internalBorderWidth or internalBorder (which is what xterm calls
3818 it). */
3819 if (NILP (Fassq (Qinternal_border_width, parms)))
3820 {
3821 Lisp_Object value;
3822
3823 value = mac_get_arg (parms, Qinternal_border_width,
3824 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
3825 if (! EQ (value, Qunbound))
3826 parms = Fcons (Fcons (Qinternal_border_width, value),
3827 parms);
3828 }
3829
3830 /* Default internalBorderWidth to 0 on Windows to match other programs. */
3831 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
3832 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
3833
3834 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
3835 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
3836
3837 /* Also do the stuff which must be set before the window exists. */
3838 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
3839 "foreground", "Foreground", RES_TYPE_STRING);
3840 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
3841 "background", "Background", RES_TYPE_STRING);
3842 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
3843 "pointerColor", "Foreground", RES_TYPE_STRING);
3844 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
3845 "cursorColor", "Foreground", RES_TYPE_STRING);
3846 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
3847 "borderColor", "BorderColor", RES_TYPE_STRING);
3848 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
3849 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
3850 x_default_parameter (f, parms, Qline_spacing, Qnil,
3851 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
3852 x_default_parameter (f, parms, Qleft_fringe, Qnil,
3853 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
3854 x_default_parameter (f, parms, Qright_fringe, Qnil,
3855 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
3856
3857 /* Init faces before x_default_parameter is called for scroll-bar
3858 parameters because that function calls x_set_scroll_bar_width,
3859 which calls change_frame_size, which calls Fset_window_buffer,
3860 which runs hooks, which call Fvertical_motion. At the end, we
3861 end up in init_iterator with a null face cache, which should not
3862 happen. */
3863 init_frame_faces (f);
3864
3865 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
3866 "menuBar", "MenuBar", RES_TYPE_NUMBER);
3867 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
3868 "toolBar", "ToolBar", RES_TYPE_NUMBER);
3869#if 0
3870 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
3871 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
3872#endif
3873 x_default_parameter (f, parms, Qtitle, Qnil,
3874 "title", "Title", RES_TYPE_STRING);
3875
3876 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3877 window_prompting = x_figure_window_size (f, parms);
3878
3879 if (window_prompting & XNegative)
3880 {
3881 if (window_prompting & YNegative)
3882 f->output_data.mac->win_gravity = SouthEastGravity;
3883 else
3884 f->output_data.mac->win_gravity = NorthEastGravity;
3885 }
3886 else
3887 {
3888 if (window_prompting & YNegative)
3889 f->output_data.mac->win_gravity = SouthWestGravity;
3890 else
3891 f->output_data.mac->win_gravity = NorthWestGravity;
3892 }
3893
3894 f->output_data.mac->size_hint_flags = window_prompting;
3895
3896 tem = mac_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
3897 f->no_split = minibuffer_only || EQ (tem, Qt);
3898
3899 /* Create the window. Add the tool-bar height to the initial frame
3900 height so that the user gets a text display area of the size he
3901 specified with -g or via the registry. Later changes of the
3902 tool-bar height don't change the frame size. This is done so that
3903 users can create tall Emacs frames without having to guess how
3904 tall the tool-bar will get. */
3905 f->height += FRAME_TOOL_BAR_LINES (f);
3906
3907 /* mac_window (f, window_prompting, minibuffer_only); */
3908 make_mac_frame (f);
3909
3910 x_icon (f, parms);
3911
3912 x_make_gc (f);
3913
3914 /* Now consider the frame official. */
3915 FRAME_MAC_DISPLAY_INFO (f)->reference_count++;
3916 Vframe_list = Fcons (frame, Vframe_list);
3917
3918 /* We need to do this after creating the window, so that the
3919 icon-creation functions can say whose icon they're describing. */
3920 x_default_parameter (f, parms, Qicon_type, Qnil,
3921 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
3922
3923 x_default_parameter (f, parms, Qauto_raise, Qnil,
3924 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
3925 x_default_parameter (f, parms, Qauto_lower, Qnil,
3926 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
3927 x_default_parameter (f, parms, Qcursor_type, Qbox,
3928 "cursorType", "CursorType", RES_TYPE_SYMBOL);
3929 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
3930 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
3931
3932 /* Dimensions, especially f->height, must be done via change_frame_size.
3933 Change will not be effected unless different from the current
3934 f->height. */
3935
3936 width = f->width;
3937 height = f->height;
3938 f->height = 0;
3939 SET_FRAME_WIDTH (f, 0);
3940 change_frame_size (f, height, width, 1, 0, 0);
3941
3942 /* Set up faces after all frame parameters are known. */
3943 call1 (Qface_set_after_frame_default, frame);
3944
3945#if 0 /* MAC_TODO: when we have window manager hints */
3946 /* Tell the server what size and position, etc, we want, and how
3947 badly we want them. This should be done after we have the menu
3948 bar so that its size can be taken into account. */
3949 BLOCK_INPUT;
3950 x_wm_set_size_hint (f, window_prompting, 0);
3951 UNBLOCK_INPUT;
3952#endif
3953
3954 /* Make the window appear on the frame and enable display, unless
3955 the caller says not to. However, with explicit parent, Emacs
3956 cannot control visibility, so don't try. */
3957 if (! f->output_data.mac->explicit_parent)
3958 {
3959 Lisp_Object visibility;
3960
3961 visibility = mac_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
3962 if (EQ (visibility, Qunbound))
3963 visibility = Qt;
3964
3965#if 0 /* MAC_TODO: really no iconify on Mac */
3966 if (EQ (visibility, Qicon))
3967 x_iconify_frame (f);
3968 else
3969#endif
3970 if (! NILP (visibility))
3971 x_make_frame_visible (f);
3972 else
3973 /* Must have been Qnil. */
3974 ;
3975 }
3976
3977 UNGCPRO;
3978 return unbind_to (count, frame);
3979}
3980
3981/* FRAME is used only to get a handle on the X display. We don't pass the
3982 display info directly because we're called from frame.c, which doesn't
3983 know about that structure. */
3984Lisp_Object
3985x_get_focus_frame (frame)
3986 struct frame *frame;
3987{
3988 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
3989 Lisp_Object xfocus;
3990 if (! dpyinfo->x_focus_frame)
3991 return Qnil;
3992
3993 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
3994 return xfocus;
3995}
3996
3997DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
3998 "Internal function called by `color-defined-p', which see.")
3999 (color, frame)
4000 Lisp_Object color, frame;
4001{
4002 XColor foo;
4003 FRAME_PTR f = check_x_frame (frame);
4004
4005 CHECK_STRING (color, 1);
4006
4007 if (mac_defined_color (f, XSTRING (color)->data, &foo, 0))
4008 return Qt;
4009 else
4010 return Qnil;
4011}
4012
4013DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
4014 "Internal function called by `color-values', which see.")
4015 (color, frame)
4016 Lisp_Object color, frame;
4017{
4018 XColor foo;
4019 FRAME_PTR f = check_x_frame (frame);
4020
4021 CHECK_STRING (color, 1);
4022
4023 if (mac_defined_color (f, XSTRING (color)->data, &foo, 0))
4024 {
4025 Lisp_Object rgb[3];
4026
4027 rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8)
4028 | RED_FROM_ULONG (foo.pixel));
4029 rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8)
4030 | GREEN_FROM_ULONG (foo.pixel));
4031 rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8)
4032 | BLUE_FROM_ULONG (foo.pixel));
4033 return Flist (3, rgb);
4034 }
4035 else
4036 return Qnil;
4037}
4038
4039DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
4040 "Internal function called by `display-color-p', which see.")
4041 (display)
4042 Lisp_Object display;
4043{
4044 struct mac_display_info *dpyinfo = check_x_display_info (display);
4045
4046 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
4047 return Qnil;
4048
4049 return Qt;
4050}
4051
4052DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
4053 0, 1, 0,
4054 "Return t if the X display supports shades of gray.\n\
4055Note that color displays do support shades of gray.\n\
4056The optional argument DISPLAY specifies which display to ask about.\n\
4057DISPLAY should be either a frame or a display name (a string).\n\
4058If omitted or nil, that stands for the selected frame's display.")
4059 (display)
4060 Lisp_Object display;
4061{
4062 struct mac_display_info *dpyinfo = check_x_display_info (display);
4063
4064 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
4065 return Qnil;
4066
4067 return Qt;
4068}
4069
4070DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
4071 0, 1, 0,
4072 "Returns the width in pixels of the X display DISPLAY.\n\
4073The optional argument DISPLAY specifies which display to ask about.\n\
4074DISPLAY should be either a frame or a display name (a string).\n\
4075If omitted or nil, that stands for the selected frame's display.")
4076 (display)
4077 Lisp_Object display;
4078{
4079 struct mac_display_info *dpyinfo = check_x_display_info (display);
4080
4081 return make_number (dpyinfo->width);
4082}
4083
4084DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
4085 Sx_display_pixel_height, 0, 1, 0,
4086 "Returns the height in pixels of the X display DISPLAY.\n\
4087The optional argument DISPLAY specifies which display to ask about.\n\
4088DISPLAY should be either a frame or a display name (a string).\n\
4089If omitted or nil, that stands for the selected frame's display.")
4090 (display)
4091 Lisp_Object display;
4092{
4093 struct mac_display_info *dpyinfo = check_x_display_info (display);
4094
4095 return make_number (dpyinfo->height);
4096}
4097
4098DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
4099 0, 1, 0,
4100 "Returns the number of bitplanes of the display DISPLAY.\n\
4101The optional argument DISPLAY specifies which display to ask about.\n\
4102DISPLAY should be either a frame or a display name (a string).\n\
4103If omitted or nil, that stands for the selected frame's display.")
4104 (display)
4105 Lisp_Object display;
4106{
4107 struct mac_display_info *dpyinfo = check_x_display_info (display);
4108
4109 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
4110}
4111
4112DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
4113 0, 1, 0,
4114 "Returns the number of color cells of the display DISPLAY.\n\
4115The optional argument DISPLAY specifies which display to ask about.\n\
4116DISPLAY should be either a frame or a display name (a string).\n\
4117If omitted or nil, that stands for the selected frame's display.")
4118 (display)
4119 Lisp_Object display;
4120{
4121 struct mac_display_info *dpyinfo = check_x_display_info (display);
4122
4123 /* MAC_TODO: check whether this is right */
4124 return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits)));
4125}
4126
4127DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4128 Sx_server_max_request_size,
4129 0, 1, 0,
4130 "Returns the maximum request size of the server of display DISPLAY.\n\
4131The optional argument DISPLAY specifies which display to ask about.\n\
4132DISPLAY should be either a frame or a display name (a string).\n\
4133If omitted or nil, that stands for the selected frame's display.")
4134 (display)
4135 Lisp_Object display;
4136{
4137 struct mac_display_info *dpyinfo = check_x_display_info (display);
4138
4139 return make_number (1);
4140}
4141
4142DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
4143 "Returns the vendor ID string of the W32 system (Microsoft).\n\
4144The optional argument DISPLAY specifies which display to ask about.\n\
4145DISPLAY should be either a frame or a display name (a string).\n\
4146If omitted or nil, that stands for the selected frame's display.")
4147 (display)
4148 Lisp_Object display;
4149{
4150 return build_string ("Apple Computers");
4151}
4152
4153DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
4154 "Returns the version numbers of the server of display DISPLAY.\n\
4155The value is a list of three integers: the major and minor\n\
4156version numbers, and the vendor-specific release\n\
4157number. See also the function `x-server-vendor'.\n\n\
4158The optional argument DISPLAY specifies which display to ask about.\n\
4159DISPLAY should be either a frame or a display name (a string).\n\
4160If omitted or nil, that stands for the selected frame's display.")
4161 (display)
4162 Lisp_Object display;
4163{
4164 int mac_major_version, mac_minor_version;
4165 SInt32 response;
4166
4167 if (Gestalt (gestaltSystemVersion, &response) != noErr)
4168 error ("Cannot get Mac OS version");
4169
4170 mac_major_version = (response >> 8) & 0xf;
4171 mac_minor_version = (response >> 4) & 0xf;
4172
4173 return Fcons (make_number (mac_major_version),
4174 Fcons (make_number (mac_minor_version), Qnil));
4175}
4176
4177DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4178 "Returns the number of screens on the server of display DISPLAY.\n\
4179The optional argument DISPLAY specifies which display to ask about.\n\
4180DISPLAY should be either a frame or a display name (a string).\n\
4181If omitted or nil, that stands for the selected frame's display.")
4182 (display)
4183 Lisp_Object display;
4184{
4185 return make_number (1);
4186}
4187
4188DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
4189 "Returns the height in millimeters of the X display DISPLAY.\n\
4190The optional argument DISPLAY specifies which display to ask about.\n\
4191DISPLAY should be either a frame or a display name (a string).\n\
4192If omitted or nil, that stands for the selected frame's display.")
4193 (display)
4194 Lisp_Object display;
4195{
4196 /* MAC_TODO: this is an approximation, and only of the main display */
4197
4198 struct mac_display_info *dpyinfo = check_x_display_info (display);
4199 short h, v;
4200
4201 ScreenRes (&h, &v);
4202
4203 return make_number ((int) (v / 72.0 * 25.4));
4204}
4205
4206DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4207 "Returns the width in millimeters of the X display DISPLAY.\n\
4208The optional argument DISPLAY specifies which display to ask about.\n\
4209DISPLAY should be either a frame or a display name (a string).\n\
4210If omitted or nil, that stands for the selected frame's display.")
4211 (display)
4212 Lisp_Object display;
4213{
4214 /* MAC_TODO: this is an approximation, and only of the main display */
4215
4216 struct mac_display_info *dpyinfo = check_x_display_info (display);
4217 short h, v;
4218
4219 ScreenRes (&h, &v);
4220
4221 return make_number ((int) (h / 72.0 * 25.4));
4222}
4223
4224DEFUN ("x-display-backing-store", Fx_display_backing_store,
4225 Sx_display_backing_store, 0, 1, 0,
4226 "Returns an indication of whether display DISPLAY does backing store.\n\
4227The value may be `always', `when-mapped', or `not-useful'.\n\
4228The optional argument DISPLAY specifies which display to ask about.\n\
4229DISPLAY should be either a frame or a display name (a string).\n\
4230If omitted or nil, that stands for the selected frame's display.")
4231 (display)
4232 Lisp_Object display;
4233{
4234 return intern ("not-useful");
4235}
4236
4237DEFUN ("x-display-visual-class", Fx_display_visual_class,
4238 Sx_display_visual_class, 0, 1, 0,
4239 "Returns the visual class of the display DISPLAY.\n\
4240The value is one of the symbols `static-gray', `gray-scale',\n\
4241`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
4242The optional argument DISPLAY specifies which display to ask about.\n\
4243DISPLAY should be either a frame or a display name (a string).\n\
4244If omitted or nil, that stands for the selected frame's display.")
4245 (display)
4246 Lisp_Object display;
4247{
4248 struct mac_display_info *dpyinfo = check_x_display_info (display);
4249
4250#if 0
4251 switch (dpyinfo->visual->class)
4252 {
4253 case StaticGray: return (intern ("static-gray"));
4254 case GrayScale: return (intern ("gray-scale"));
4255 case StaticColor: return (intern ("static-color"));
4256 case PseudoColor: return (intern ("pseudo-color"));
4257 case TrueColor: return (intern ("true-color"));
4258 case DirectColor: return (intern ("direct-color"));
4259 default:
4260 error ("Display has an unknown visual class");
4261 }
4262#endif
4263
4264 error ("Display has an unknown visual class");
4265}
4266
4267DEFUN ("x-display-save-under", Fx_display_save_under,
4268 Sx_display_save_under, 0, 1, 0,
4269 "Returns t if the display DISPLAY supports the save-under feature.\n\
4270The optional argument DISPLAY specifies which display to ask about.\n\
4271DISPLAY should be either a frame or a display name (a string).\n\
4272If omitted or nil, that stands for the selected frame's display.")
4273 (display)
4274 Lisp_Object display;
4275{
4276 return Qnil;
4277}
4278
4279int
4280x_pixel_width (f)
4281 register struct frame *f;
4282{
4283 return PIXEL_WIDTH (f);
4284}
4285
4286int
4287x_pixel_height (f)
4288 register struct frame *f;
4289{
4290 return PIXEL_HEIGHT (f);
4291}
4292
4293int
4294x_char_width (f)
4295 register struct frame *f;
4296{
4297 return FONT_WIDTH (f->output_data.mac->font);
4298}
4299
4300int
4301x_char_height (f)
4302 register struct frame *f;
4303{
4304 return f->output_data.mac->line_height;
4305}
4306
4307int
4308x_screen_planes (f)
4309 register struct frame *f;
4310{
4311 return FRAME_MAC_DISPLAY_INFO (f)->n_planes;
4312}
4313
4314/* Return the display structure for the display named NAME.
4315 Open a new connection if necessary. */
4316
4317struct mac_display_info *
4318x_display_info_for_name (name)
4319 Lisp_Object name;
4320{
4321 Lisp_Object names;
4322 struct mac_display_info *dpyinfo;
4323
4324 CHECK_STRING (name, 0);
4325
4326 for (dpyinfo = &one_mac_display_info, names = x_display_name_list;
4327 dpyinfo;
4328 dpyinfo = dpyinfo->next, names = XCDR (names))
4329 {
4330 Lisp_Object tem;
4331 tem = Fstring_equal (XCAR (XCAR (names)), name);
4332 if (!NILP (tem))
4333 return dpyinfo;
4334 }
4335
4336 /* Use this general default value to start with. */
4337 Vx_resource_name = Vinvocation_name;
4338
4339 validate_x_resource_name ();
4340
4341 dpyinfo = x_term_init (name, (unsigned char *) 0,
4342 (char *) XSTRING (Vx_resource_name)->data);
4343
4344 if (dpyinfo == 0)
4345 error ("Cannot connect to server %s", XSTRING (name)->data);
4346
4347 mac_in_use = 1;
4348 XSETFASTINT (Vwindow_system_version, 3);
4349
4350 return dpyinfo;
4351}
4352
4353#if 0 /* MAC_TODO: implement network support */
4354DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
4355 1, 3, 0, "Open a connection to a server.\n\
4356DISPLAY is the name of the display to connect to.\n\
4357Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
4358If the optional third arg MUST-SUCCEED is non-nil,\n\
4359terminate Emacs if we can't open the connection.")
4360 (display, xrm_string, must_succeed)
4361 Lisp_Object display, xrm_string, must_succeed;
4362{
4363 unsigned char *xrm_option;
4364 struct mac_display_info *dpyinfo;
4365
4366 CHECK_STRING (display, 0);
4367 if (! NILP (xrm_string))
4368 CHECK_STRING (xrm_string, 1);
4369
4370 if (! EQ (Vwindow_system, intern ("mac")))
4371 error ("Not using Mac OS");
4372
4373 if (! NILP (xrm_string))
4374 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
4375 else
4376 xrm_option = (unsigned char *) 0;
4377
4378 validate_x_resource_name ();
4379
4380 /* This is what opens the connection and sets x_current_display.
4381 This also initializes many symbols, such as those used for input. */
4382 dpyinfo = mac_term_init (display, xrm_option,
4383 (char *) XSTRING (Vx_resource_name)->data);
4384
4385 if (dpyinfo == 0)
4386 {
4387 if (!NILP (must_succeed))
4388 fatal ("Cannot connect to server %s.\n",
4389 XSTRING (display)->data);
4390 else
4391 error ("Cannot connect to server %s", XSTRING (display)->data);
4392 }
4393
4394 mac_in_use = 1;
4395
4396 XSETFASTINT (Vwindow_system_version, 3);
4397 return Qnil;
4398}
4399
4400DEFUN ("x-close-connection", Fx_close_connection,
4401 Sx_close_connection, 1, 1, 0,
4402 "Close the connection to DISPLAY's server.\n\
4403For DISPLAY, specify either a frame or a display name (a string).\n\
4404If DISPLAY is nil, that stands for the selected frame's display.")
4405 (display)
4406 Lisp_Object display;
4407{
4408 struct mac_display_info *dpyinfo = check_x_display_info (display);
4409 int i;
4410
4411 if (dpyinfo->reference_count > 0)
4412 error ("Display still has frames on it");
4413
4414 BLOCK_INPUT;
4415 /* Free the fonts in the font table. */
4416 for (i = 0; i < dpyinfo->n_fonts; i++)
4417 if (dpyinfo->font_table[i].name)
4418 {
4419 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
4420 xfree (dpyinfo->font_table[i].full_name);
4421 xfree (dpyinfo->font_table[i].name);
4422 x_unload_font (dpyinfo, dpyinfo->font_table[i].font);
4423 }
4424 x_destroy_all_bitmaps (dpyinfo);
4425
4426 x_delete_display (dpyinfo);
4427 UNBLOCK_INPUT;
4428
4429 return Qnil;
4430}
4431#endif
4432
4433DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
4434 "Return the list of display names that Emacs has connections to.")
4435 ()
4436{
4437 Lisp_Object tail, result;
4438
4439 result = Qnil;
4440 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
4441 result = Fcons (XCAR (XCAR (tail)), result);
4442
4443 return result;
4444}
4445
4446DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
4447 "If ON is non-nil, report errors as soon as the erring request is made.\n\
4448If ON is nil, allow buffering of requests.\n\
4449This is a noop on W32 systems.\n\
4450The optional second argument DISPLAY specifies which display to act on.\n\
4451DISPLAY should be either a frame or a display name (a string).\n\
4452If DISPLAY is omitted or nil, that stands for the selected frame's display.")
4453 (on, display)
4454 Lisp_Object display, on;
4455{
4456 return Qnil;
4457}
4458
4459
4460/***********************************************************************
4461 Image types
4462 ***********************************************************************/
4463
4464/* Value is the number of elements of vector VECTOR. */
4465
4466#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
4467
4468/* List of supported image types. Use define_image_type to add new
4469 types. Use lookup_image_type to find a type for a given symbol. */
4470
4471static struct image_type *image_types;
4472
4473/* The symbol `image' which is the car of the lists used to represent
4474 images in Lisp. */
4475
4476extern Lisp_Object Qimage;
4477
4478/* The symbol `xbm' which is used as the type symbol for XBM images. */
4479
4480Lisp_Object Qxbm;
4481
4482/* Keywords. */
4483
4484extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
4485extern Lisp_Object QCdata;
4486Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
4487Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4488Lisp_Object QCindex;
4489
4490/* Other symbols. */
4491
4492Lisp_Object Qlaplace;
4493
4494/* Time in seconds after which images should be removed from the cache
4495 if not displayed. */
4496
4497Lisp_Object Vimage_cache_eviction_delay;
4498
4499/* Function prototypes. */
4500
4501static void define_image_type P_ ((struct image_type *type));
4502static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
4503static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
4504static void x_laplace P_ ((struct frame *, struct image *));
4505static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
4506 Lisp_Object));
4507
4508
4509/* Define a new image type from TYPE. This adds a copy of TYPE to
4510 image_types and adds the symbol *TYPE->type to Vimage_types. */
4511
4512static void
4513define_image_type (type)
4514 struct image_type *type;
4515{
4516 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
4517 The initialized data segment is read-only. */
4518 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
4519 bcopy (type, p, sizeof *p);
4520 p->next = image_types;
4521 image_types = p;
4522 Vimage_types = Fcons (*p->type, Vimage_types);
4523}
4524
4525
4526/* Look up image type SYMBOL, and return a pointer to its image_type
4527 structure. Value is null if SYMBOL is not a known image type. */
4528
4529static INLINE struct image_type *
4530lookup_image_type (symbol)
4531 Lisp_Object symbol;
4532{
4533 struct image_type *type;
4534
4535 for (type = image_types; type; type = type->next)
4536 if (EQ (symbol, *type->type))
4537 break;
4538
4539 return type;
4540}
4541
4542
4543/* Value is non-zero if OBJECT is a valid Lisp image specification. A
4544 valid image specification is a list whose car is the symbol
4545 `image', and whose rest is a property list. The property list must
4546 contain a value for key `:type'. That value must be the name of a
4547 supported image type. The rest of the property list depends on the
4548 image type. */
4549
4550int
4551valid_image_p (object)
4552 Lisp_Object object;
4553{
4554 int valid_p = 0;
4555
4556 if (CONSP (object) && EQ (XCAR (object), Qimage))
4557 {
4558 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
4559 struct image_type *type = lookup_image_type (symbol);
4560
4561 if (type)
4562 valid_p = type->valid_p (object);
4563 }
4564
4565 return valid_p;
4566}
4567
4568
4569/* Log error message with format string FORMAT and argument ARG.
4570 Signaling an error, e.g. when an image cannot be loaded, is not a
4571 good idea because this would interrupt redisplay, and the error
4572 message display would lead to another redisplay. This function
4573 therefore simply displays a message. */
4574
4575static void
4576image_error (format, arg1, arg2)
4577 char *format;
4578 Lisp_Object arg1, arg2;
4579{
4580 add_to_log (format, arg1, arg2);
4581}
4582
4583
4584
4585/***********************************************************************
4586 Image specifications
4587 ***********************************************************************/
4588
4589enum image_value_type
4590{
4591 IMAGE_DONT_CHECK_VALUE_TYPE,
4592 IMAGE_STRING_VALUE,
4593 IMAGE_SYMBOL_VALUE,
4594 IMAGE_POSITIVE_INTEGER_VALUE,
4595 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
4596 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
4597 IMAGE_ASCENT_VALUE,
4598 IMAGE_INTEGER_VALUE,
4599 IMAGE_FUNCTION_VALUE,
4600 IMAGE_NUMBER_VALUE,
4601 IMAGE_BOOL_VALUE
4602};
4603
4604/* Structure used when parsing image specifications. */
4605
4606struct image_keyword
4607{
4608 /* Name of keyword. */
4609 char *name;
4610
4611 /* The type of value allowed. */
4612 enum image_value_type type;
4613
4614 /* Non-zero means key must be present. */
4615 int mandatory_p;
4616
4617 /* Used to recognize duplicate keywords in a property list. */
4618 int count;
4619
4620 /* The value that was found. */
4621 Lisp_Object value;
4622};
4623
4624
4625static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
4626 int, Lisp_Object));
4627static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
4628
4629
4630/* Parse image spec SPEC according to KEYWORDS. A valid image spec
4631 has the format (image KEYWORD VALUE ...). One of the keyword/
4632 value pairs must be `:type TYPE'. KEYWORDS is a vector of
4633 image_keywords structures of size NKEYWORDS describing other
4634 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
4635
4636static int
4637parse_image_spec (spec, keywords, nkeywords, type)
4638 Lisp_Object spec;
4639 struct image_keyword *keywords;
4640 int nkeywords;
4641 Lisp_Object type;
4642{
4643 int i;
4644 Lisp_Object plist;
4645
4646 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
4647 return 0;
4648
4649 plist = XCDR (spec);
4650 while (CONSP (plist))
4651 {
4652 Lisp_Object key, value;
4653
4654 /* First element of a pair must be a symbol. */
4655 key = XCAR (plist);
4656 plist = XCDR (plist);
4657 if (!SYMBOLP (key))
4658 return 0;
4659
4660 /* There must follow a value. */
4661 if (!CONSP (plist))
4662 return 0;
4663 value = XCAR (plist);
4664 plist = XCDR (plist);
4665
4666 /* Find key in KEYWORDS. Error if not found. */
4667 for (i = 0; i < nkeywords; ++i)
4668 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
4669 break;
4670
4671 if (i == nkeywords)
4672 continue;
4673
4674 /* Record that we recognized the keyword. If a keywords
4675 was found more than once, it's an error. */
4676 keywords[i].value = value;
4677 ++keywords[i].count;
4678
4679 if (keywords[i].count > 1)
4680 return 0;
4681
4682 /* Check type of value against allowed type. */
4683 switch (keywords[i].type)
4684 {
4685 case IMAGE_STRING_VALUE:
4686 if (!STRINGP (value))
4687 return 0;
4688 break;
4689
4690 case IMAGE_SYMBOL_VALUE:
4691 if (!SYMBOLP (value))
4692 return 0;
4693 break;
4694
4695 case IMAGE_POSITIVE_INTEGER_VALUE:
4696 if (!INTEGERP (value) || XINT (value) <= 0)
4697 return 0;
4698 break;
4699
4700 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
4701 if (INTEGERP (value) && XINT (value) >= 0)
4702 break;
4703 if (CONSP (value)
4704 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
4705 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
4706 break;
4707 return 0;
4708
4709 case IMAGE_ASCENT_VALUE:
4710 if (SYMBOLP (value) && EQ (value, Qcenter))
4711 break;
4712 else if (INTEGERP (value)
4713 && XINT (value) >= 0
4714 && XINT (value) <= 100)
4715 break;
4716 return 0;
4717
4718 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
4719 if (!INTEGERP (value) || XINT (value) < 0)
4720 return 0;
4721 break;
4722
4723 case IMAGE_DONT_CHECK_VALUE_TYPE:
4724 break;
4725
4726 case IMAGE_FUNCTION_VALUE:
4727 value = indirect_function (value);
4728 if (SUBRP (value)
4729 || COMPILEDP (value)
4730 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
4731 break;
4732 return 0;
4733
4734 case IMAGE_NUMBER_VALUE:
4735 if (!INTEGERP (value) && !FLOATP (value))
4736 return 0;
4737 break;
4738
4739 case IMAGE_INTEGER_VALUE:
4740 if (!INTEGERP (value))
4741 return 0;
4742 break;
4743
4744 case IMAGE_BOOL_VALUE:
4745 if (!NILP (value) && !EQ (value, Qt))
4746 return 0;
4747 break;
4748
4749 default:
4750 abort ();
4751 break;
4752 }
4753
4754 if (EQ (key, QCtype) && !EQ (type, value))
4755 return 0;
4756 }
4757
4758 /* Check that all mandatory fields are present. */
4759 for (i = 0; i < nkeywords; ++i)
4760 if (keywords[i].mandatory_p && keywords[i].count == 0)
4761 return 0;
4762
4763 return NILP (plist);
4764}
4765
4766
4767/* Return the value of KEY in image specification SPEC. Value is nil
4768 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
4769 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
4770
4771static Lisp_Object
4772image_spec_value (spec, key, found)
4773 Lisp_Object spec, key;
4774 int *found;
4775{
4776 Lisp_Object tail;
4777
4778 xassert (valid_image_p (spec));
4779
4780 for (tail = XCDR (spec);
4781 CONSP (tail) && CONSP (XCDR (tail));
4782 tail = XCDR (XCDR (tail)))
4783 {
4784 if (EQ (XCAR (tail), key))
4785 {
4786 if (found)
4787 *found = 1;
4788 return XCAR (XCDR (tail));
4789 }
4790 }
4791
4792 if (found)
4793 *found = 0;
4794 return Qnil;
4795}
4796
4797
4798
4799
4800/***********************************************************************
4801 Image type independent image structures
4802 ***********************************************************************/
4803
4804static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
4805static void free_image P_ ((struct frame *f, struct image *img));
4806
4807
4808/* Allocate and return a new image structure for image specification
4809 SPEC. SPEC has a hash value of HASH. */
4810
4811static struct image *
4812make_image (spec, hash)
4813 Lisp_Object spec;
4814 unsigned hash;
4815{
4816 struct image *img = (struct image *) xmalloc (sizeof *img);
4817
4818 xassert (valid_image_p (spec));
4819 bzero (img, sizeof *img);
4820 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
4821 xassert (img->type != NULL);
4822 img->spec = spec;
4823 img->data.lisp_val = Qnil;
4824 img->ascent = DEFAULT_IMAGE_ASCENT;
4825 img->hash = hash;
4826 return img;
4827}
4828
4829
4830/* Free image IMG which was used on frame F, including its resources. */
4831
4832static void
4833free_image (f, img)
4834 struct frame *f;
4835 struct image *img;
4836{
4837 if (img)
4838 {
4839 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4840
4841 /* Remove IMG from the hash table of its cache. */
4842 if (img->prev)
4843 img->prev->next = img->next;
4844 else
4845 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
4846
4847 if (img->next)
4848 img->next->prev = img->prev;
4849
4850 c->images[img->id] = NULL;
4851
4852 /* Free resources, then free IMG. */
4853 img->type->free (f, img);
4854 xfree (img);
4855 }
4856}
4857
4858
4859/* Prepare image IMG for display on frame F. Must be called before
4860 drawing an image. */
4861
4862void
4863prepare_image_for_display (f, img)
4864 struct frame *f;
4865 struct image *img;
4866{
4867 EMACS_TIME t;
4868
4869 /* We're about to display IMG, so set its timestamp to `now'. */
4870 EMACS_GET_TIME (t);
4871 img->timestamp = EMACS_SECS (t);
4872
4873 /* If IMG doesn't have a pixmap yet, load it now, using the image
4874 type dependent loader function. */
4875 if (img->pixmap == 0 && !img->load_failed_p)
4876 img->load_failed_p = img->type->load (f, img) == 0;
4877}
4878
4879
4880/* Value is the number of pixels for the ascent of image IMG when
4881 drawn in face FACE. */
4882
4883int
4884image_ascent (img, face)
4885 struct image *img;
4886 struct face *face;
4887{
4888 int height = img->height + img->vmargin;
4889 int ascent;
4890
4891 if (img->ascent == CENTERED_IMAGE_ASCENT)
4892 {
4893 if (face->font)
4894 ascent = height / 2 - (FONT_DESCENT(face->font)
4895 - FONT_BASE(face->font)) / 2;
4896 else
4897 ascent = height / 2;
4898 }
4899 else
4900 ascent = height * img->ascent / 100.0;
4901
4902 return ascent;
4903}
4904
4905
4906
4907/***********************************************************************
4908 Helper functions for X image types
4909 ***********************************************************************/
4910
4911static void x_clear_image P_ ((struct frame *f, struct image *img));
4912static unsigned long x_alloc_image_color P_ ((struct frame *f,
4913 struct image *img,
4914 Lisp_Object color_name,
4915 unsigned long dflt));
4916
4917/* Free X resources of image IMG which is used on frame F. */
4918
4919static void
4920x_clear_image (f, img)
4921 struct frame *f;
4922 struct image *img;
4923{
4924#if 0 /* MAC_TODO: W32 image support */
4925
4926 if (img->pixmap)
4927 {
4928 BLOCK_INPUT;
4929 XFreePixmap (NULL, img->pixmap);
4930 img->pixmap = 0;
4931 UNBLOCK_INPUT;
4932 }
4933
4934 if (img->ncolors)
4935 {
4936 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
4937
4938 /* If display has an immutable color map, freeing colors is not
4939 necessary and some servers don't allow it. So don't do it. */
4940 if (class != StaticColor
4941 && class != StaticGray
4942 && class != TrueColor)
4943 {
4944 Colormap cmap;
4945 BLOCK_INPUT;
4946 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
4947 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
4948 img->ncolors, 0);
4949 UNBLOCK_INPUT;
4950 }
4951
4952 xfree (img->colors);
4953 img->colors = NULL;
4954 img->ncolors = 0;
4955 }
4956#endif
4957}
4958
4959
4960/* Allocate color COLOR_NAME for image IMG on frame F. If color
4961 cannot be allocated, use DFLT. Add a newly allocated color to
4962 IMG->colors, so that it can be freed again. Value is the pixel
4963 color. */
4964
4965static unsigned long
4966x_alloc_image_color (f, img, color_name, dflt)
4967 struct frame *f;
4968 struct image *img;
4969 Lisp_Object color_name;
4970 unsigned long dflt;
4971{
4972#if 0 /* MAC_TODO: allocing colors. */
4973 XColor color;
4974 unsigned long result;
4975
4976 xassert (STRINGP (color_name));
4977
4978 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
4979 {
4980 /* This isn't called frequently so we get away with simply
4981 reallocating the color vector to the needed size, here. */
4982 ++img->ncolors;
4983 img->colors =
4984 (unsigned long *) xrealloc (img->colors,
4985 img->ncolors * sizeof *img->colors);
4986 img->colors[img->ncolors - 1] = color.pixel;
4987 result = color.pixel;
4988 }
4989 else
4990 result = dflt;
4991 return result;
4992#endif
4993 return 0;
4994}
4995
4996
4997
4998/***********************************************************************
4999 Image Cache
5000 ***********************************************************************/
5001
5002static void cache_image P_ ((struct frame *f, struct image *img));
5003
5004
5005/* Return a new, initialized image cache that is allocated from the
5006 heap. Call free_image_cache to free an image cache. */
5007
5008struct image_cache *
5009make_image_cache ()
5010{
5011 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
5012 int size;
5013
5014 bzero (c, sizeof *c);
5015 c->size = 50;
5016 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
5017 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
5018 c->buckets = (struct image **) xmalloc (size);
5019 bzero (c->buckets, size);
5020 return c;
5021}
5022
5023
5024/* Free image cache of frame F. Be aware that X frames share images
5025 caches. */
5026
5027void
5028free_image_cache (f)
5029 struct frame *f;
5030{
5031 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5032 if (c)
5033 {
5034 int i;
5035
5036 /* Cache should not be referenced by any frame when freed. */
5037 xassert (c->refcount == 0);
5038
5039 for (i = 0; i < c->used; ++i)
5040 free_image (f, c->images[i]);
5041 xfree (c->images);
5042 xfree (c);
5043 xfree (c->buckets);
5044 FRAME_X_IMAGE_CACHE (f) = NULL;
5045 }
5046}
5047
5048
5049/* Clear image cache of frame F. FORCE_P non-zero means free all
5050 images. FORCE_P zero means clear only images that haven't been
5051 displayed for some time. Should be called from time to time to
5052 reduce the number of loaded images. If image-eviction-seconds is
5053 non-nil, this frees images in the cache which weren't displayed for
5054 at least that many seconds. */
5055
5056void
5057clear_image_cache (f, force_p)
5058 struct frame *f;
5059 int force_p;
5060{
5061 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5062
5063 if (c && INTEGERP (Vimage_cache_eviction_delay))
5064 {
5065 EMACS_TIME t;
5066 unsigned long old;
5067 int i, any_freed_p = 0;
5068
5069 EMACS_GET_TIME (t);
5070 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
5071
5072 for (i = 0; i < c->used; ++i)
5073 {
5074 struct image *img = c->images[i];
5075 if (img != NULL
5076 && (force_p
5077 || (img->timestamp > old)))
5078 {
5079 free_image (f, img);
5080 any_freed_p = 1;
5081 }
5082 }
5083
5084 /* We may be clearing the image cache because, for example,
5085 Emacs was iconified for a longer period of time. In that
5086 case, current matrices may still contain references to
5087 images freed above. So, clear these matrices. */
5088 if (any_freed_p)
5089 {
5090 clear_current_matrices (f);
5091 ++windows_or_buffers_changed;
5092 }
5093 }
5094}
5095
5096
5097DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
5098 0, 1, 0,
5099 "Clear the image cache of FRAME.\n\
5100FRAME nil or omitted means use the selected frame.\n\
5101FRAME t means clear the image caches of all frames.")
5102 (frame)
5103 Lisp_Object frame;
5104{
5105 if (EQ (frame, Qt))
5106 {
5107 Lisp_Object tail;
5108
5109 FOR_EACH_FRAME (tail, frame)
5110 if (FRAME_MAC_P (XFRAME (frame)))
5111 clear_image_cache (XFRAME (frame), 1);
5112 }
5113 else
5114 clear_image_cache (check_x_frame (frame), 1);
5115
5116 return Qnil;
5117}
5118
5119
5120/* Return the id of image with Lisp specification SPEC on frame F.
5121 SPEC must be a valid Lisp image specification (see valid_image_p). */
5122
5123int
5124lookup_image (f, spec)
5125 struct frame *f;
5126 Lisp_Object spec;
5127{
5128 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5129 struct image *img;
5130 int i;
5131 unsigned hash;
5132 struct gcpro gcpro1;
5133 EMACS_TIME now;
5134
5135 /* F must be a window-system frame, and SPEC must be a valid image
5136 specification. */
5137 xassert (FRAME_WINDOW_P (f));
5138 xassert (valid_image_p (spec));
5139
5140 GCPRO1 (spec);
5141
5142 /* Look up SPEC in the hash table of the image cache. */
5143 hash = sxhash (spec, 0);
5144 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
5145
5146 for (img = c->buckets[i]; img; img = img->next)
5147 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
5148 break;
5149
5150 /* If not found, create a new image and cache it. */
5151 if (img == NULL)
5152 {
5153 BLOCK_INPUT;
5154 img = make_image (spec, hash);
5155 cache_image (f, img);
5156 img->load_failed_p = img->type->load (f, img) == 0;
5157
5158 /* If we can't load the image, and we don't have a width and
5159 height, use some arbitrary width and height so that we can
5160 draw a rectangle for it. */
5161 if (img->load_failed_p)
5162 {
5163 Lisp_Object value;
5164
5165 value = image_spec_value (spec, QCwidth, NULL);
5166 img->width = (INTEGERP (value)
5167 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
5168 value = image_spec_value (spec, QCheight, NULL);
5169 img->height = (INTEGERP (value)
5170 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
5171 }
5172 else
5173 {
5174 /* Handle image type independent image attributes
5175 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
5176 Lisp_Object ascent, margin, relief;
5177
5178 ascent = image_spec_value (spec, QCascent, NULL);
5179 if (INTEGERP (ascent))
5180 img->ascent = XFASTINT (ascent);
5181 else if (EQ (ascent, Qcenter))
5182 img->ascent = CENTERED_IMAGE_ASCENT;
5183
5184 margin = image_spec_value (spec, QCmargin, NULL);
5185 if (INTEGERP (margin) && XINT (margin) >= 0)
5186 img->vmargin = img->hmargin = XFASTINT (margin);
5187 else if (CONSP (margin) && INTEGERP (XCAR (margin))
5188 && INTEGERP (XCDR (margin)))
5189 {
5190 if (XINT (XCAR (margin)) > 0)
5191 img->hmargin = XFASTINT (XCAR (margin));
5192 if (XINT (XCDR (margin)) > 0)
5193 img->vmargin = XFASTINT (XCDR (margin));
5194 }
5195
5196 relief = image_spec_value (spec, QCrelief, NULL);
5197 if (INTEGERP (relief))
5198 {
5199 img->relief = XINT (relief);
5200 img->hmargin += abs (img->relief);
5201 img->vmargin += abs (img->relief);
5202 }
5203 }
5204 }
5205
5206 /* We're using IMG, so set its timestamp to `now'. */
5207 EMACS_GET_TIME (now);
5208 img->timestamp = EMACS_SECS (now);
5209
5210 UNGCPRO;
5211
5212 /* Value is the image id. */
5213 return img->id;
5214}
5215
5216
5217/* Cache image IMG in the image cache of frame F. */
5218
5219static void
5220cache_image (f, img)
5221 struct frame *f;
5222 struct image *img;
5223{
5224 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5225 int i;
5226
5227 /* Find a free slot in c->images. */
5228 for (i = 0; i < c->used; ++i)
5229 if (c->images[i] == NULL)
5230 break;
5231
5232 /* If no free slot found, maybe enlarge c->images. */
5233 if (i == c->used && c->used == c->size)
5234 {
5235 c->size *= 2;
5236 c->images = (struct image **) xrealloc (c->images,
5237 c->size * sizeof *c->images);
5238 }
5239
5240 /* Add IMG to c->images, and assign IMG an id. */
5241 c->images[i] = img;
5242 img->id = i;
5243 if (i == c->used)
5244 ++c->used;
5245
5246 /* Add IMG to the cache's hash table. */
5247 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
5248 img->next = c->buckets[i];
5249 if (img->next)
5250 img->next->prev = img;
5251 img->prev = NULL;
5252 c->buckets[i] = img;
5253}
5254
5255
5256/* Call FN on every image in the image cache of frame F. Used to mark
5257 Lisp Objects in the image cache. */
5258
5259void
5260forall_images_in_image_cache (f, fn)
5261 struct frame *f;
5262 void (*fn) P_ ((struct image *img));
5263{
5264 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f))
5265 {
5266 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5267 if (c)
5268 {
5269 int i;
5270 for (i = 0; i < c->used; ++i)
5271 if (c->images[i])
5272 fn (c->images[i]);
5273 }
5274 }
5275}
5276
5277
5278
5279/***********************************************************************
5280 Mac support code
5281 ***********************************************************************/
5282
5283#if 0 /* MAC_TODO: Mac specific image code. */
5284
5285static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
5286 XImage **, Pixmap *));
5287static void x_destroy_x_image P_ ((XImage *));
5288static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
5289
5290
5291/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
5292 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
5293 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
5294 via xmalloc. Print error messages via image_error if an error
5295 occurs. Value is non-zero if successful. */
5296
5297static int
5298x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
5299 struct frame *f;
5300 int width, height, depth;
5301 XImage **ximg;
5302 Pixmap *pixmap;
5303{
5304#if 0 /* MAC_TODO: Image support for Mac */
5305 Display *display = FRAME_W32_DISPLAY (f);
5306 Screen *screen = FRAME_X_SCREEN (f);
5307 Window window = FRAME_W32_WINDOW (f);
5308
5309 xassert (interrupt_input_blocked);
5310
5311 if (depth <= 0)
5312 depth = DefaultDepthOfScreen (screen);
5313 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
5314 depth, ZPixmap, 0, NULL, width, height,
5315 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
5316 if (*ximg == NULL)
5317 {
5318 image_error ("Unable to allocate X image", Qnil, Qnil);
5319 return 0;
5320 }
5321
5322 /* Allocate image raster. */
5323 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
5324
5325 /* Allocate a pixmap of the same size. */
5326 *pixmap = XCreatePixmap (display, window, width, height, depth);
5327 if (*pixmap == 0)
5328 {
5329 x_destroy_x_image (*ximg);
5330 *ximg = NULL;
5331 image_error ("Unable to create X pixmap", Qnil, Qnil);
5332 return 0;
5333 }
5334#endif
5335 return 1;
5336}
5337
5338
5339/* Destroy XImage XIMG. Free XIMG->data. */
5340
5341static void
5342x_destroy_x_image (ximg)
5343 XImage *ximg;
5344{
5345 xassert (interrupt_input_blocked);
5346 if (ximg)
5347 {
5348 xfree (ximg->data);
5349 ximg->data = NULL;
5350 XDestroyImage (ximg);
5351 }
5352}
5353
5354
5355/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
5356 are width and height of both the image and pixmap. */
5357
5358static void
5359x_put_x_image (f, ximg, pixmap, width, height)
5360 struct frame *f;
5361 XImage *ximg;
5362 Pixmap pixmap;
5363{
5364 GC gc;
5365
5366 xassert (interrupt_input_blocked);
5367 gc = XCreateGC (NULL, pixmap, 0, NULL);
5368 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
5369 XFreeGC (NULL, gc);
5370}
5371
5372#endif
5373
5374
5375/***********************************************************************
5376 Searching files
5377 ***********************************************************************/
5378
5379static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5380
5381/* Find image file FILE. Look in data-directory, then
5382 x-bitmap-file-path. Value is the full name of the file found, or
5383 nil if not found. */
5384
5385static Lisp_Object
5386x_find_image_file (file)
5387 Lisp_Object file;
5388{
5389 Lisp_Object file_found, search_path;
5390 struct gcpro gcpro1, gcpro2;
5391 int fd;
5392
5393 file_found = Qnil;
5394 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
5395 GCPRO2 (file_found, search_path);
5396
5397 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
5398 fd = openp (search_path, file, Qnil, &file_found, 0);
5399
5400 if (fd < 0)
5401 file_found = Qnil;
5402 else
5403 close (fd);
5404
5405 UNGCPRO;
5406 return file_found;
5407}
5408
5409
5410/***********************************************************************
5411 XBM images
5412 ***********************************************************************/
5413
5414static int xbm_load P_ ((struct frame *f, struct image *img));
5415static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
5416 Lisp_Object file));
5417static int xbm_image_p P_ ((Lisp_Object object));
5418static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
5419 unsigned char **));
5420
5421
5422/* Indices of image specification fields in xbm_format, below. */
5423
5424enum xbm_keyword_index
5425{
5426 XBM_TYPE,
5427 XBM_FILE,
5428 XBM_WIDTH,
5429 XBM_HEIGHT,
5430 XBM_DATA,
5431 XBM_FOREGROUND,
5432 XBM_BACKGROUND,
5433 XBM_ASCENT,
5434 XBM_MARGIN,
5435 XBM_RELIEF,
5436 XBM_ALGORITHM,
5437 XBM_HEURISTIC_MASK,
5438 XBM_LAST
5439};
5440
5441/* Vector of image_keyword structures describing the format
5442 of valid XBM image specifications. */
5443
5444static struct image_keyword xbm_format[XBM_LAST] =
5445{
5446 {":type", IMAGE_SYMBOL_VALUE, 1},
5447 {":file", IMAGE_STRING_VALUE, 0},
5448 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5449 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5450 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5451 {":foreground", IMAGE_STRING_VALUE, 0},
5452 {":background", IMAGE_STRING_VALUE, 0},
5453 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
5454 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5455 {":relief", IMAGE_INTEGER_VALUE, 0},
5456 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5457 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
5458};
5459
5460/* Structure describing the image type XBM. */
5461
5462static struct image_type xbm_type =
5463{
5464 &Qxbm,
5465 xbm_image_p,
5466 xbm_load,
5467 x_clear_image,
5468 NULL
5469};
5470
5471/* Tokens returned from xbm_scan. */
5472
5473enum xbm_token
5474{
5475 XBM_TK_IDENT = 256,
5476 XBM_TK_NUMBER
5477};
5478
5479
5480/* Return non-zero if OBJECT is a valid XBM-type image specification.
5481 A valid specification is a list starting with the symbol `image'
5482 The rest of the list is a property list which must contain an
5483 entry `:type xbm..
5484
5485 If the specification specifies a file to load, it must contain
5486 an entry `:file FILENAME' where FILENAME is a string.
5487
5488 If the specification is for a bitmap loaded from memory it must
5489 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
5490 WIDTH and HEIGHT are integers > 0. DATA may be:
5491
5492 1. a string large enough to hold the bitmap data, i.e. it must
5493 have a size >= (WIDTH + 7) / 8 * HEIGHT
5494
5495 2. a bool-vector of size >= WIDTH * HEIGHT
5496
5497 3. a vector of strings or bool-vectors, one for each line of the
5498 bitmap.
5499
5500 Both the file and data forms may contain the additional entries
5501 `:background COLOR' and `:foreground COLOR'. If not present,
5502 foreground and background of the frame on which the image is
5503 displayed, is used. */
5504
5505static int
5506xbm_image_p (object)
5507 Lisp_Object object;
5508{
5509 struct image_keyword kw[XBM_LAST];
5510
5511 bcopy (xbm_format, kw, sizeof kw);
5512 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
5513 return 0;
5514
5515 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
5516
5517 if (kw[XBM_FILE].count)
5518 {
5519 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
5520 return 0;
5521 }
5522 else
5523 {
5524 Lisp_Object data;
5525 int width, height;
5526
5527 /* Entries for `:width', `:height' and `:data' must be present. */
5528 if (!kw[XBM_WIDTH].count
5529 || !kw[XBM_HEIGHT].count
5530 || !kw[XBM_DATA].count)
5531 return 0;
5532
5533 data = kw[XBM_DATA].value;
5534 width = XFASTINT (kw[XBM_WIDTH].value);
5535 height = XFASTINT (kw[XBM_HEIGHT].value);
5536
5537 /* Check type of data, and width and height against contents of
5538 data. */
5539 if (VECTORP (data))
5540 {
5541 int i;
5542
5543 /* Number of elements of the vector must be >= height. */
5544 if (XVECTOR (data)->size < height)
5545 return 0;
5546
5547 /* Each string or bool-vector in data must be large enough
5548 for one line of the image. */
5549 for (i = 0; i < height; ++i)
5550 {
5551 Lisp_Object elt = XVECTOR (data)->contents[i];
5552
5553 if (STRINGP (elt))
5554 {
5555 if (XSTRING (elt)->size
5556 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
5557 return 0;
5558 }
5559 else if (BOOL_VECTOR_P (elt))
5560 {
5561 if (XBOOL_VECTOR (elt)->size < width)
5562 return 0;
5563 }
5564 else
5565 return 0;
5566 }
5567 }
5568 else if (STRINGP (data))
5569 {
5570 if (XSTRING (data)->size
5571 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
5572 return 0;
5573 }
5574 else if (BOOL_VECTOR_P (data))
5575 {
5576 if (XBOOL_VECTOR (data)->size < width * height)
5577 return 0;
5578 }
5579 else
5580 return 0;
5581 }
5582
5583 /* Baseline must be a value between 0 and 100 (a percentage). */
5584 if (kw[XBM_ASCENT].count
5585 && XFASTINT (kw[XBM_ASCENT].value) > 100)
5586 return 0;
5587
5588 return 1;
5589}
5590
5591
5592/* Scan a bitmap file. FP is the stream to read from. Value is
5593 either an enumerator from enum xbm_token, or a character for a
5594 single-character token, or 0 at end of file. If scanning an
5595 identifier, store the lexeme of the identifier in SVAL. If
5596 scanning a number, store its value in *IVAL. */
5597
5598static int
5599xbm_scan (fp, sval, ival)
5600 FILE *fp;
5601 char *sval;
5602 int *ival;
5603{
5604 int c;
5605
5606 /* Skip white space. */
5607 while ((c = fgetc (fp)) != EOF && isspace (c))
5608 ;
5609
5610 if (c == EOF)
5611 c = 0;
5612 else if (isdigit (c))
5613 {
5614 int value = 0, digit;
5615
5616 if (c == '0')
5617 {
5618 c = fgetc (fp);
5619 if (c == 'x' || c == 'X')
5620 {
5621 while ((c = fgetc (fp)) != EOF)
5622 {
5623 if (isdigit (c))
5624 digit = c - '0';
5625 else if (c >= 'a' && c <= 'f')
5626 digit = c - 'a' + 10;
5627 else if (c >= 'A' && c <= 'F')
5628 digit = c - 'A' + 10;
5629 else
5630 break;
5631 value = 16 * value + digit;
5632 }
5633 }
5634 else if (isdigit (c))
5635 {
5636 value = c - '0';
5637 while ((c = fgetc (fp)) != EOF
5638 && isdigit (c))
5639 value = 8 * value + c - '0';
5640 }
5641 }
5642 else
5643 {
5644 value = c - '0';
5645 while ((c = fgetc (fp)) != EOF
5646 && isdigit (c))
5647 value = 10 * value + c - '0';
5648 }
5649
5650 if (c != EOF)
5651 ungetc (c, fp);
5652 *ival = value;
5653 c = XBM_TK_NUMBER;
5654 }
5655 else if (isalpha (c) || c == '_')
5656 {
5657 *sval++ = c;
5658 while ((c = fgetc (fp)) != EOF
5659 && (isalnum (c) || c == '_'))
5660 *sval++ = c;
5661 *sval = 0;
5662 if (c != EOF)
5663 ungetc (c, fp);
5664 c = XBM_TK_IDENT;
5665 }
5666
5667 return c;
5668}
5669
5670
5671/* Replacement for XReadBitmapFileData which isn't available under old
5672 X versions. FILE is the name of the bitmap file to read. Set
5673 *WIDTH and *HEIGHT to the width and height of the image. Return in
5674 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
5675 successful. */
5676
5677static int
5678xbm_read_bitmap_file_data (file, width, height, data)
5679 char *file;
5680 int *width, *height;
5681 unsigned char **data;
5682{
5683 FILE *fp;
5684 char buffer[BUFSIZ];
5685 int padding_p = 0;
5686 int v10 = 0;
5687 int bytes_per_line, i, nbytes;
5688 unsigned char *p;
5689 int value;
5690 int LA1;
5691
5692#define match() \
5693 LA1 = xbm_scan (fp, buffer, &value)
5694
5695#define expect(TOKEN) \
5696 if (LA1 != (TOKEN)) \
5697 goto failure; \
5698 else \
5699 match ()
5700
5701#define expect_ident(IDENT) \
5702 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
5703 match (); \
5704 else \
5705 goto failure
5706
5707 fp = fopen (file, "r");
5708 if (fp == NULL)
5709 return 0;
5710
5711 *width = *height = -1;
5712 *data = NULL;
5713 LA1 = xbm_scan (fp, buffer, &value);
5714
5715 /* Parse defines for width, height and hot-spots. */
5716 while (LA1 == '#')
5717 {
5718 match ();
5719 expect_ident ("define");
5720 expect (XBM_TK_IDENT);
5721
5722 if (LA1 == XBM_TK_NUMBER);
5723 {
5724 char *p = strrchr (buffer, '_');
5725 p = p ? p + 1 : buffer;
5726 if (strcmp (p, "width") == 0)
5727 *width = value;
5728 else if (strcmp (p, "height") == 0)
5729 *height = value;
5730 }
5731 expect (XBM_TK_NUMBER);
5732 }
5733
5734 if (*width < 0 || *height < 0)
5735 goto failure;
5736
5737 /* Parse bits. Must start with `static'. */
5738 expect_ident ("static");
5739 if (LA1 == XBM_TK_IDENT)
5740 {
5741 if (strcmp (buffer, "unsigned") == 0)
5742 {
5743 match ();
5744 expect_ident ("char");
5745 }
5746 else if (strcmp (buffer, "short") == 0)
5747 {
5748 match ();
5749 v10 = 1;
5750 if (*width % 16 && *width % 16 < 9)
5751 padding_p = 1;
5752 }
5753 else if (strcmp (buffer, "char") == 0)
5754 match ();
5755 else
5756 goto failure;
5757 }
5758 else
5759 goto failure;
5760
5761 expect (XBM_TK_IDENT);
5762 expect ('[');
5763 expect (']');
5764 expect ('=');
5765 expect ('{');
5766
5767 bytes_per_line = (*width + 7) / 8 + padding_p;
5768 nbytes = bytes_per_line * *height;
5769 p = *data = (char *) xmalloc (nbytes);
5770
5771 if (v10)
5772 {
5773
5774 for (i = 0; i < nbytes; i += 2)
5775 {
5776 int val = value;
5777 expect (XBM_TK_NUMBER);
5778
5779 *p++ = val;
5780 if (!padding_p || ((i + 2) % bytes_per_line))
5781 *p++ = value >> 8;
5782
5783 if (LA1 == ',' || LA1 == '}')
5784 match ();
5785 else
5786 goto failure;
5787 }
5788 }
5789 else
5790 {
5791 for (i = 0; i < nbytes; ++i)
5792 {
5793 int val = value;
5794 expect (XBM_TK_NUMBER);
5795
5796 *p++ = val;
5797
5798 if (LA1 == ',' || LA1 == '}')
5799 match ();
5800 else
5801 goto failure;
5802 }
5803 }
5804
5805 fclose (fp);
5806 return 1;
5807
5808 failure:
5809
5810 fclose (fp);
5811 if (*data)
5812 {
5813 xfree (*data);
5814 *data = NULL;
5815 }
5816 return 0;
5817
5818#undef match
5819#undef expect
5820#undef expect_ident
5821}
5822
5823
5824/* Load XBM image IMG which will be displayed on frame F from file
5825 SPECIFIED_FILE. Value is non-zero if successful. */
5826
5827static int
5828xbm_load_image_from_file (f, img, specified_file)
5829 struct frame *f;
5830 struct image *img;
5831 Lisp_Object specified_file;
5832{
5833 int rc;
5834 unsigned char *data;
5835 int success_p = 0;
5836 Lisp_Object file;
5837 struct gcpro gcpro1;
5838
5839 xassert (STRINGP (specified_file));
5840 file = Qnil;
5841 GCPRO1 (file);
5842
5843 file = x_find_image_file (specified_file);
5844 if (!STRINGP (file))
5845 {
5846 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5847 UNGCPRO;
5848 return 0;
5849 }
5850
5851 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
5852 &img->height, &data);
5853 if (rc)
5854 {
5855 int depth = one_mac_display_info.n_cbits;
5856 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5857 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5858 Lisp_Object value;
5859
5860 xassert (img->width > 0 && img->height > 0);
5861
5862 /* Get foreground and background colors, maybe allocate colors. */
5863 value = image_spec_value (img->spec, QCforeground, NULL);
5864 if (!NILP (value))
5865 foreground = x_alloc_image_color (f, img, value, foreground);
5866
5867 value = image_spec_value (img->spec, QCbackground, NULL);
5868 if (!NILP (value))
5869 background = x_alloc_image_color (f, img, value, background);
5870
5871#if 0 /* MAC_TODO : Port image display to Mac */
5872 BLOCK_INPUT;
5873 img->pixmap
5874 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
5875 FRAME_W32_WINDOW (f),
5876 data,
5877 img->width, img->height,
5878 foreground, background,
5879 depth);
5880 xfree (data);
5881
5882 if (img->pixmap == 0)
5883 {
5884 x_clear_image (f, img);
5885 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
5886 }
5887 else
5888 success_p = 1;
5889
5890 UNBLOCK_INPUT;
5891#endif
5892 }
5893 else
5894 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
5895
5896 UNGCPRO;
5897 return success_p;
5898}
5899
5900
5901/* Fill image IMG which is used on frame F with pixmap data. Value is
5902 non-zero if successful. */
5903
5904static int
5905xbm_load (f, img)
5906 struct frame *f;
5907 struct image *img;
5908{
5909 int success_p = 0;
5910 Lisp_Object file_name;
5911
5912 xassert (xbm_image_p (img->spec));
5913
5914 /* If IMG->spec specifies a file name, create a non-file spec from it. */
5915 file_name = image_spec_value (img->spec, QCfile, NULL);
5916 if (STRINGP (file_name))
5917 success_p = xbm_load_image_from_file (f, img, file_name);
5918 else
5919 {
5920 struct image_keyword fmt[XBM_LAST];
5921 Lisp_Object data;
5922 int depth;
5923 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5924 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5925 char *bits;
5926 int parsed_p;
5927
5928 /* Parse the list specification. */
5929 bcopy (xbm_format, fmt, sizeof fmt);
5930 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
5931 xassert (parsed_p);
5932
5933 /* Get specified width, and height. */
5934 img->width = XFASTINT (fmt[XBM_WIDTH].value);
5935 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
5936 xassert (img->width > 0 && img->height > 0);
5937
5938 BLOCK_INPUT;
5939
5940 if (fmt[XBM_ASCENT].count)
5941 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
5942
5943 /* Get foreground and background colors, maybe allocate colors. */
5944 if (fmt[XBM_FOREGROUND].count)
5945 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
5946 foreground);
5947 if (fmt[XBM_BACKGROUND].count)
5948 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
5949 background);
5950
5951 /* Set bits to the bitmap image data. */
5952 data = fmt[XBM_DATA].value;
5953 if (VECTORP (data))
5954 {
5955 int i;
5956 char *p;
5957 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
5958
5959 p = bits = (char *) alloca (nbytes * img->height);
5960 for (i = 0; i < img->height; ++i, p += nbytes)
5961 {
5962 Lisp_Object line = XVECTOR (data)->contents[i];
5963 if (STRINGP (line))
5964 bcopy (XSTRING (line)->data, p, nbytes);
5965 else
5966 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
5967 }
5968 }
5969 else if (STRINGP (data))
5970 bits = XSTRING (data)->data;
5971 else
5972 bits = XBOOL_VECTOR (data)->data;
5973
5974#if 0 /* MAC_TODO : port Mac display code */
5975 /* Create the pixmap. */
5976 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
5977 img->pixmap
5978 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
5979 FRAME_W32_WINDOW (f),
5980 bits,
5981 img->width, img->height,
5982 foreground, background,
5983 depth);
5984#endif /* MAC_TODO */
5985
5986 if (img->pixmap)
5987 success_p = 1;
5988 else
5989 {
5990 image_error ("Unable to create pixmap for XBM image `%s'",
5991 img->spec, Qnil);
5992 x_clear_image (f, img);
5993 }
5994
5995 UNBLOCK_INPUT;
5996 }
5997
5998 return success_p;
5999}
6000
6001
6002
6003/***********************************************************************
6004 XPM images
6005 ***********************************************************************/
6006
6007#if HAVE_XPM
6008
6009static int xpm_image_p P_ ((Lisp_Object object));
6010static int xpm_load P_ ((struct frame *f, struct image *img));
6011static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
6012
6013#include "X11/xpm.h"
6014
6015/* The symbol `xpm' identifying XPM-format images. */
6016
6017Lisp_Object Qxpm;
6018
6019/* Indices of image specification fields in xpm_format, below. */
6020
6021enum xpm_keyword_index
6022{
6023 XPM_TYPE,
6024 XPM_FILE,
6025 XPM_DATA,
6026 XPM_ASCENT,
6027 XPM_MARGIN,
6028 XPM_RELIEF,
6029 XPM_ALGORITHM,
6030 XPM_HEURISTIC_MASK,
6031 XPM_COLOR_SYMBOLS,
6032 XPM_LAST
6033};
6034
6035/* Vector of image_keyword structures describing the format
6036 of valid XPM image specifications. */
6037
6038static struct image_keyword xpm_format[XPM_LAST] =
6039{
6040 {":type", IMAGE_SYMBOL_VALUE, 1},
6041 {":file", IMAGE_STRING_VALUE, 0},
6042 {":data", IMAGE_STRING_VALUE, 0},
6043 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6044 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6045 {":relief", IMAGE_INTEGER_VALUE, 0},
6046 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6047 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6048 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6049};
6050
6051/* Structure describing the image type XBM. */
6052
6053static struct image_type xpm_type =
6054{
6055 &Qxpm,
6056 xpm_image_p,
6057 xpm_load,
6058 x_clear_image,
6059 NULL
6060};
6061
6062
6063/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
6064 for XPM images. Such a list must consist of conses whose car and
6065 cdr are strings. */
6066
6067static int
6068xpm_valid_color_symbols_p (color_symbols)
6069 Lisp_Object color_symbols;
6070{
6071 while (CONSP (color_symbols))
6072 {
6073 Lisp_Object sym = XCAR (color_symbols);
6074 if (!CONSP (sym)
6075 || !STRINGP (XCAR (sym))
6076 || !STRINGP (XCDR (sym)))
6077 break;
6078 color_symbols = XCDR (color_symbols);
6079 }
6080
6081 return NILP (color_symbols);
6082}
6083
6084
6085/* Value is non-zero if OBJECT is a valid XPM image specification. */
6086
6087static int
6088xpm_image_p (object)
6089 Lisp_Object object;
6090{
6091 struct image_keyword fmt[XPM_LAST];
6092 bcopy (xpm_format, fmt, sizeof fmt);
6093 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
6094 /* Either `:file' or `:data' must be present. */
6095 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
6096 /* Either no `:color-symbols' or it's a list of conses
6097 whose car and cdr are strings. */
6098 && (fmt[XPM_COLOR_SYMBOLS].count == 0
6099 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
6100 && (fmt[XPM_ASCENT].count == 0
6101 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
6102}
6103
6104
6105/* Load image IMG which will be displayed on frame F. Value is
6106 non-zero if successful. */
6107
6108static int
6109xpm_load (f, img)
6110 struct frame *f;
6111 struct image *img;
6112{
6113 int rc, i;
6114 XpmAttributes attrs;
6115 Lisp_Object specified_file, color_symbols;
6116
6117 /* Configure the XPM lib. Use the visual of frame F. Allocate
6118 close colors. Return colors allocated. */
6119 bzero (&attrs, sizeof attrs);
6120 attrs.visual = FRAME_X_VISUAL (f);
6121 attrs.colormap = FRAME_X_COLORMAP (f);
6122 attrs.valuemask |= XpmVisual;
6123 attrs.valuemask |= XpmColormap;
6124 attrs.valuemask |= XpmReturnAllocPixels;
6125#ifdef XpmAllocCloseColors
6126 attrs.alloc_close_colors = 1;
6127 attrs.valuemask |= XpmAllocCloseColors;
6128#else
6129 attrs.closeness = 600;
6130 attrs.valuemask |= XpmCloseness;
6131#endif
6132
6133 /* If image specification contains symbolic color definitions, add
6134 these to `attrs'. */
6135 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
6136 if (CONSP (color_symbols))
6137 {
6138 Lisp_Object tail;
6139 XpmColorSymbol *xpm_syms;
6140 int i, size;
6141
6142 attrs.valuemask |= XpmColorSymbols;
6143
6144 /* Count number of symbols. */
6145 attrs.numsymbols = 0;
6146 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
6147 ++attrs.numsymbols;
6148
6149 /* Allocate an XpmColorSymbol array. */
6150 size = attrs.numsymbols * sizeof *xpm_syms;
6151 xpm_syms = (XpmColorSymbol *) alloca (size);
6152 bzero (xpm_syms, size);
6153 attrs.colorsymbols = xpm_syms;
6154
6155 /* Fill the color symbol array. */
6156 for (tail = color_symbols, i = 0;
6157 CONSP (tail);
6158 ++i, tail = XCDR (tail))
6159 {
6160 Lisp_Object name = XCAR (XCAR (tail));
6161 Lisp_Object color = XCDR (XCAR (tail));
6162 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
6163 strcpy (xpm_syms[i].name, XSTRING (name)->data);
6164 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
6165 strcpy (xpm_syms[i].value, XSTRING (color)->data);
6166 }
6167 }
6168
6169 /* Create a pixmap for the image, either from a file, or from a
6170 string buffer containing data in the same format as an XPM file. */
6171 BLOCK_INPUT;
6172 specified_file = image_spec_value (img->spec, QCfile, NULL);
6173 if (STRINGP (specified_file))
6174 {
6175 Lisp_Object file = x_find_image_file (specified_file);
6176 if (!STRINGP (file))
6177 {
6178 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6179 UNBLOCK_INPUT;
6180 return 0;
6181 }
6182
6183 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
6184 XSTRING (file)->data, &img->pixmap, &img->mask,
6185 &attrs);
6186 }
6187 else
6188 {
6189 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
6190 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
6191 XSTRING (buffer)->data,
6192 &img->pixmap, &img->mask,
6193 &attrs);
6194 }
6195 UNBLOCK_INPUT;
6196
6197 if (rc == XpmSuccess)
6198 {
6199 /* Remember allocated colors. */
6200 img->ncolors = attrs.nalloc_pixels;
6201 img->colors = (unsigned long *) xmalloc (img->ncolors
6202 * sizeof *img->colors);
6203 for (i = 0; i < attrs.nalloc_pixels; ++i)
6204 img->colors[i] = attrs.alloc_pixels[i];
6205
6206 img->width = attrs.width;
6207 img->height = attrs.height;
6208 xassert (img->width > 0 && img->height > 0);
6209
6210 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
6211 BLOCK_INPUT;
6212 XpmFreeAttributes (&attrs);
6213 UNBLOCK_INPUT;
6214 }
6215 else
6216 {
6217 switch (rc)
6218 {
6219 case XpmOpenFailed:
6220 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
6221 break;
6222
6223 case XpmFileInvalid:
6224 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
6225 break;
6226
6227 case XpmNoMemory:
6228 image_error ("Out of memory (%s)", img->spec, Qnil);
6229 break;
6230
6231 case XpmColorFailed:
6232 image_error ("Color allocation error (%s)", img->spec, Qnil);
6233 break;
6234
6235 default:
6236 image_error ("Unknown error (%s)", img->spec, Qnil);
6237 break;
6238 }
6239 }
6240
6241 return rc == XpmSuccess;
6242}
6243
6244#endif /* HAVE_XPM != 0 */
6245
6246
6247#if 0 /* MAC_TODO : Color tables on Mac. */
6248/***********************************************************************
6249 Color table
6250 ***********************************************************************/
6251
6252/* An entry in the color table mapping an RGB color to a pixel color. */
6253
6254struct ct_color
6255{
6256 int r, g, b;
6257 unsigned long pixel;
6258
6259 /* Next in color table collision list. */
6260 struct ct_color *next;
6261};
6262
6263/* The bucket vector size to use. Must be prime. */
6264
6265#define CT_SIZE 101
6266
6267/* Value is a hash of the RGB color given by R, G, and B. */
6268
6269#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
6270
6271/* The color hash table. */
6272
6273struct ct_color **ct_table;
6274
6275/* Number of entries in the color table. */
6276
6277int ct_colors_allocated;
6278
6279/* Function prototypes. */
6280
6281static void init_color_table P_ ((void));
6282static void free_color_table P_ ((void));
6283static unsigned long *colors_in_color_table P_ ((int *n));
6284static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
6285static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
6286
6287
6288/* Initialize the color table. */
6289
6290static void
6291init_color_table ()
6292{
6293 int size = CT_SIZE * sizeof (*ct_table);
6294 ct_table = (struct ct_color **) xmalloc (size);
6295 bzero (ct_table, size);
6296 ct_colors_allocated = 0;
6297}
6298
6299
6300/* Free memory associated with the color table. */
6301
6302static void
6303free_color_table ()
6304{
6305 int i;
6306 struct ct_color *p, *next;
6307
6308 for (i = 0; i < CT_SIZE; ++i)
6309 for (p = ct_table[i]; p; p = next)
6310 {
6311 next = p->next;
6312 xfree (p);
6313 }
6314
6315 xfree (ct_table);
6316 ct_table = NULL;
6317}
6318
6319
6320/* Value is a pixel color for RGB color R, G, B on frame F. If an
6321 entry for that color already is in the color table, return the
6322 pixel color of that entry. Otherwise, allocate a new color for R,
6323 G, B, and make an entry in the color table. */
6324
6325static unsigned long
6326lookup_rgb_color (f, r, g, b)
6327 struct frame *f;
6328 int r, g, b;
6329{
6330 unsigned hash = CT_HASH_RGB (r, g, b);
6331 int i = hash % CT_SIZE;
6332 struct ct_color *p;
6333
6334 for (p = ct_table[i]; p; p = p->next)
6335 if (p->r == r && p->g == g && p->b == b)
6336 break;
6337
6338 if (p == NULL)
6339 {
6340 COLORREF color;
6341 Colormap cmap;
6342 int rc;
6343
6344 color = RGB_TO_ULONG (r, g, b);
6345
6346 ++ct_colors_allocated;
6347
6348 p = (struct ct_color *) xmalloc (sizeof *p);
6349 p->r = r;
6350 p->g = g;
6351 p->b = b;
6352 p->pixel = color;
6353 p->next = ct_table[i];
6354 ct_table[i] = p;
6355 }
6356
6357 return p->pixel;
6358}
6359
6360
6361/* Look up pixel color PIXEL which is used on frame F in the color
6362 table. If not already present, allocate it. Value is PIXEL. */
6363
6364static unsigned long
6365lookup_pixel_color (f, pixel)
6366 struct frame *f;
6367 unsigned long pixel;
6368{
6369 int i = pixel % CT_SIZE;
6370 struct ct_color *p;
6371
6372 for (p = ct_table[i]; p; p = p->next)
6373 if (p->pixel == pixel)
6374 break;
6375
6376 if (p == NULL)
6377 {
6378 XColor color;
6379 Colormap cmap;
6380 int rc;
6381
6382 BLOCK_INPUT;
6383
6384 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6385 color.pixel = pixel;
6386 XQueryColor (NULL, cmap, &color);
6387 rc = x_alloc_nearest_color (f, cmap, &color);
6388 UNBLOCK_INPUT;
6389
6390 if (rc)
6391 {
6392 ++ct_colors_allocated;
6393
6394 p = (struct ct_color *) xmalloc (sizeof *p);
6395 p->r = color.red;
6396 p->g = color.green;
6397 p->b = color.blue;
6398 p->pixel = pixel;
6399 p->next = ct_table[i];
6400 ct_table[i] = p;
6401 }
6402 else
6403 return FRAME_FOREGROUND_PIXEL (f);
6404 }
6405 return p->pixel;
6406}
6407
6408
6409/* Value is a vector of all pixel colors contained in the color table,
6410 allocated via xmalloc. Set *N to the number of colors. */
6411
6412static unsigned long *
6413colors_in_color_table (n)
6414 int *n;
6415{
6416 int i, j;
6417 struct ct_color *p;
6418 unsigned long *colors;
6419
6420 if (ct_colors_allocated == 0)
6421 {
6422 *n = 0;
6423 colors = NULL;
6424 }
6425 else
6426 {
6427 colors = (unsigned long *) xmalloc (ct_colors_allocated
6428 * sizeof *colors);
6429 *n = ct_colors_allocated;
6430
6431 for (i = j = 0; i < CT_SIZE; ++i)
6432 for (p = ct_table[i]; p; p = p->next)
6433 colors[j++] = p->pixel;
6434 }
6435
6436 return colors;
6437}
6438
6439#endif /* MAC_TODO */
6440
6441
6442/***********************************************************************
6443 Algorithms
6444 ***********************************************************************/
6445
6446#if 0 /* MAC_TODO : Mac versions of low level algorithms */
6447static void x_laplace_write_row P_ ((struct frame *, long *,
6448 int, XImage *, int));
6449static void x_laplace_read_row P_ ((struct frame *, Colormap,
6450 XColor *, int, XImage *, int));
6451
6452
6453/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
6454 frame we operate on, CMAP is the color-map in effect, and WIDTH is
6455 the width of one row in the image. */
6456
6457static void
6458x_laplace_read_row (f, cmap, colors, width, ximg, y)
6459 struct frame *f;
6460 Colormap cmap;
6461 XColor *colors;
6462 int width;
6463 XImage *ximg;
6464 int y;
6465{
6466 int x;
6467
6468 for (x = 0; x < width; ++x)
6469 colors[x].pixel = XGetPixel (ximg, x, y);
6470
6471 XQueryColors (NULL, cmap, colors, width);
6472}
6473
6474
6475/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
6476 containing the pixel colors to write. F is the frame we are
6477 working on. */
6478
6479static void
6480x_laplace_write_row (f, pixels, width, ximg, y)
6481 struct frame *f;
6482 long *pixels;
6483 int width;
6484 XImage *ximg;
6485 int y;
6486{
6487 int x;
6488
6489 for (x = 0; x < width; ++x)
6490 XPutPixel (ximg, x, y, pixels[x]);
6491}
6492#endif
6493
6494/* Transform image IMG which is used on frame F with a Laplace
6495 edge-detection algorithm. The result is an image that can be used
6496 to draw disabled buttons, for example. */
6497
6498static void
6499x_laplace (f, img)
6500 struct frame *f;
6501 struct image *img;
6502{
6503#if 0 /* MAC_TODO : Mac version */
6504 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6505 XImage *ximg, *oimg;
6506 XColor *in[3];
6507 long *out;
6508 Pixmap pixmap;
6509 int x, y, i;
6510 long pixel;
6511 int in_y, out_y, rc;
6512 int mv2 = 45000;
6513
6514 BLOCK_INPUT;
6515
6516 /* Get the X image IMG->pixmap. */
6517 ximg = XGetImage (NULL, img->pixmap,
6518 0, 0, img->width, img->height, ~0, ZPixmap);
6519
6520 /* Allocate 3 input rows, and one output row of colors. */
6521 for (i = 0; i < 3; ++i)
6522 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
6523 out = (long *) alloca (img->width * sizeof (long));
6524
6525 /* Create an X image for output. */
6526 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
6527 &oimg, &pixmap);
6528
6529 /* Fill first two rows. */
6530 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
6531 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
6532 in_y = 2;
6533
6534 /* Write first row, all zeros. */
6535 init_color_table ();
6536 pixel = lookup_rgb_color (f, 0, 0, 0);
6537 for (x = 0; x < img->width; ++x)
6538 out[x] = pixel;
6539 x_laplace_write_row (f, out, img->width, oimg, 0);
6540 out_y = 1;
6541
6542 for (y = 2; y < img->height; ++y)
6543 {
6544 int rowa = y % 3;
6545 int rowb = (y + 2) % 3;
6546
6547 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
6548
6549 for (x = 0; x < img->width - 2; ++x)
6550 {
6551 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
6552 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
6553 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
6554
6555 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
6556 b & 0xffff);
6557 }
6558
6559 x_laplace_write_row (f, out, img->width, oimg, out_y++);
6560 }
6561
6562 /* Write last line, all zeros. */
6563 for (x = 0; x < img->width; ++x)
6564 out[x] = pixel;
6565 x_laplace_write_row (f, out, img->width, oimg, out_y);
6566
6567 /* Free the input image, and free resources of IMG. */
6568 XDestroyImage (ximg);
6569 x_clear_image (f, img);
6570
6571 /* Put the output image into pixmap, and destroy it. */
6572 x_put_x_image (f, oimg, pixmap, img->width, img->height);
6573 x_destroy_x_image (oimg);
6574
6575 /* Remember new pixmap and colors in IMG. */
6576 img->pixmap = pixmap;
6577 img->colors = colors_in_color_table (&img->ncolors);
6578 free_color_table ();
6579
6580 UNBLOCK_INPUT;
6581#endif /* MAC_TODO */
6582}
6583
6584
6585/* Build a mask for image IMG which is used on frame F. FILE is the
6586 name of an image file, for error messages. HOW determines how to
6587 determine the background color of IMG. If it is a list '(R G B)',
6588 with R, G, and B being integers >= 0, take that as the color of the
6589 background. Otherwise, determine the background color of IMG
6590 heuristically. Value is non-zero if successful. */
6591
6592static int
6593x_build_heuristic_mask (f, img, how)
6594 struct frame *f;
6595 struct image *img;
6596 Lisp_Object how;
6597{
6598#if 0 /* MAC_TODO : Mac version */
6599 Display *dpy = FRAME_W32_DISPLAY (f);
6600 XImage *ximg, *mask_img;
6601 int x, y, rc, look_at_corners_p;
6602 unsigned long bg;
6603
6604 BLOCK_INPUT;
6605
6606 /* Create an image and pixmap serving as mask. */
6607 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
6608 &mask_img, &img->mask);
6609 if (!rc)
6610 {
6611 UNBLOCK_INPUT;
6612 return 0;
6613 }
6614
6615 /* Get the X image of IMG->pixmap. */
6616 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
6617 ~0, ZPixmap);
6618
6619 /* Determine the background color of ximg. If HOW is `(R G B)'
6620 take that as color. Otherwise, try to determine the color
6621 heuristically. */
6622 look_at_corners_p = 1;
6623
6624 if (CONSP (how))
6625 {
6626 int rgb[3], i = 0;
6627
6628 while (i < 3
6629 && CONSP (how)
6630 && NATNUMP (XCAR (how)))
6631 {
6632 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
6633 how = XCDR (how);
6634 }
6635
6636 if (i == 3 && NILP (how))
6637 {
6638 char color_name[30];
6639 XColor exact, color;
6640 Colormap cmap;
6641
6642 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
6643
6644 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6645 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
6646 {
6647 bg = color.pixel;
6648 look_at_corners_p = 0;
6649 }
6650 }
6651 }
6652
6653 if (look_at_corners_p)
6654 {
6655 unsigned long corners[4];
6656 int i, best_count;
6657
6658 /* Get the colors at the corners of ximg. */
6659 corners[0] = XGetPixel (ximg, 0, 0);
6660 corners[1] = XGetPixel (ximg, img->width - 1, 0);
6661 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
6662 corners[3] = XGetPixel (ximg, 0, img->height - 1);
6663
6664 /* Choose the most frequently found color as background. */
6665 for (i = best_count = 0; i < 4; ++i)
6666 {
6667 int j, n;
6668
6669 for (j = n = 0; j < 4; ++j)
6670 if (corners[i] == corners[j])
6671 ++n;
6672
6673 if (n > best_count)
6674 bg = corners[i], best_count = n;
6675 }
6676 }
6677
6678 /* Set all bits in mask_img to 1 whose color in ximg is different
6679 from the background color bg. */
6680 for (y = 0; y < img->height; ++y)
6681 for (x = 0; x < img->width; ++x)
6682 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
6683
6684 /* Put mask_img into img->mask. */
6685 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6686 x_destroy_x_image (mask_img);
6687 XDestroyImage (ximg);
6688
6689 UNBLOCK_INPUT;
6690#endif /* MAC_TODO */
6691
6692 return 1;
6693}
6694
6695
6696
6697/***********************************************************************
6698 PBM (mono, gray, color)
6699 ***********************************************************************/
6700#ifdef HAVE_PBM
6701
6702static int pbm_image_p P_ ((Lisp_Object object));
6703static int pbm_load P_ ((struct frame *f, struct image *img));
6704static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
6705
6706/* The symbol `pbm' identifying images of this type. */
6707
6708Lisp_Object Qpbm;
6709
6710/* Indices of image specification fields in gs_format, below. */
6711
6712enum pbm_keyword_index
6713{
6714 PBM_TYPE,
6715 PBM_FILE,
6716 PBM_DATA,
6717 PBM_ASCENT,
6718 PBM_MARGIN,
6719 PBM_RELIEF,
6720 PBM_ALGORITHM,
6721 PBM_HEURISTIC_MASK,
6722 PBM_LAST
6723};
6724
6725/* Vector of image_keyword structures describing the format
6726 of valid user-defined image specifications. */
6727
6728static struct image_keyword pbm_format[PBM_LAST] =
6729{
6730 {":type", IMAGE_SYMBOL_VALUE, 1},
6731 {":file", IMAGE_STRING_VALUE, 0},
6732 {":data", IMAGE_STRING_VALUE, 0},
6733 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6734 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6735 {":relief", IMAGE_INTEGER_VALUE, 0},
6736 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6737 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6738};
6739
6740/* Structure describing the image type `pbm'. */
6741
6742static struct image_type pbm_type =
6743{
6744 &Qpbm,
6745 pbm_image_p,
6746 pbm_load,
6747 x_clear_image,
6748 NULL
6749};
6750
6751
6752/* Return non-zero if OBJECT is a valid PBM image specification. */
6753
6754static int
6755pbm_image_p (object)
6756 Lisp_Object object;
6757{
6758 struct image_keyword fmt[PBM_LAST];
6759
6760 bcopy (pbm_format, fmt, sizeof fmt);
6761
6762 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
6763 || (fmt[PBM_ASCENT].count
6764 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
6765 return 0;
6766
6767 /* Must specify either :data or :file. */
6768 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
6769}
6770
6771
6772/* Scan a decimal number from *S and return it. Advance *S while
6773 reading the number. END is the end of the string. Value is -1 at
6774 end of input. */
6775
6776static int
6777pbm_scan_number (s, end)
6778 unsigned char **s, *end;
6779{
6780 int c, val = -1;
6781
6782 while (*s < end)
6783 {
6784 /* Skip white-space. */
6785 while (*s < end && (c = *(*s)++, isspace (c)))
6786 ;
6787
6788 if (c == '#')
6789 {
6790 /* Skip comment to end of line. */
6791 while (*s < end && (c = *(*s)++, c != '\n'))
6792 ;
6793 }
6794 else if (isdigit (c))
6795 {
6796 /* Read decimal number. */
6797 val = c - '0';
6798 while (*s < end && (c = *(*s)++, isdigit (c)))
6799 val = 10 * val + c - '0';
6800 break;
6801 }
6802 else
6803 break;
6804 }
6805
6806 return val;
6807}
6808
6809
6810/* Read FILE into memory. Value is a pointer to a buffer allocated
6811 with xmalloc holding FILE's contents. Value is null if an error
6812 occured. *SIZE is set to the size of the file. */
6813
6814static char *
6815pbm_read_file (file, size)
6816 Lisp_Object file;
6817 int *size;
6818{
6819 FILE *fp = NULL;
6820 char *buf = NULL;
6821 struct stat st;
6822
6823 if (stat (XSTRING (file)->data, &st) == 0
6824 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
6825 && (buf = (char *) xmalloc (st.st_size),
6826 fread (buf, 1, st.st_size, fp) == st.st_size))
6827 {
6828 *size = st.st_size;
6829 fclose (fp);
6830 }
6831 else
6832 {
6833 if (fp)
6834 fclose (fp);
6835 if (buf)
6836 {
6837 xfree (buf);
6838 buf = NULL;
6839 }
6840 }
6841
6842 return buf;
6843}
6844
6845
6846/* Load PBM image IMG for use on frame F. */
6847
6848static int
6849pbm_load (f, img)
6850 struct frame *f;
6851 struct image *img;
6852{
6853 int raw_p, x, y;
6854 int width, height, max_color_idx = 0;
6855 XImage *ximg;
6856 Lisp_Object file, specified_file;
6857 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
6858 struct gcpro gcpro1;
6859 unsigned char *contents = NULL;
6860 unsigned char *end, *p;
6861 int size;
6862
6863 specified_file = image_spec_value (img->spec, QCfile, NULL);
6864 file = Qnil;
6865 GCPRO1 (file);
6866
6867 if (STRINGP (specified_file))
6868 {
6869 file = x_find_image_file (specified_file);
6870 if (!STRINGP (file))
6871 {
6872 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6873 UNGCPRO;
6874 return 0;
6875 }
6876
6877 contents = pbm_read_file (file, &size);
6878 if (contents == NULL)
6879 {
6880 image_error ("Error reading `%s'", file, Qnil);
6881 UNGCPRO;
6882 return 0;
6883 }
6884
6885 p = contents;
6886 end = contents + size;
6887 }
6888 else
6889 {
6890 Lisp_Object data;
6891 data = image_spec_value (img->spec, QCdata, NULL);
6892 p = XSTRING (data)->data;
6893 end = p + STRING_BYTES (XSTRING (data));
6894 }
6895
6896 /* Check magic number. */
6897 if (end - p < 2 || *p++ != 'P')
6898 {
6899 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
6900 error:
6901 xfree (contents);
6902 UNGCPRO;
6903 return 0;
6904 }
6905
6906 switch (*p++)
6907 {
6908 case '1':
6909 raw_p = 0, type = PBM_MONO;
6910 break;
6911
6912 case '2':
6913 raw_p = 0, type = PBM_GRAY;
6914 break;
6915
6916 case '3':
6917 raw_p = 0, type = PBM_COLOR;
6918 break;
6919
6920 case '4':
6921 raw_p = 1, type = PBM_MONO;
6922 break;
6923
6924 case '5':
6925 raw_p = 1, type = PBM_GRAY;
6926 break;
6927
6928 case '6':
6929 raw_p = 1, type = PBM_COLOR;
6930 break;
6931
6932 default:
6933 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
6934 goto error;
6935 }
6936
6937 /* Read width, height, maximum color-component. Characters
6938 starting with `#' up to the end of a line are ignored. */
6939 width = pbm_scan_number (&p, end);
6940 height = pbm_scan_number (&p, end);
6941
6942 if (type != PBM_MONO)
6943 {
6944 max_color_idx = pbm_scan_number (&p, end);
6945 if (raw_p && max_color_idx > 255)
6946 max_color_idx = 255;
6947 }
6948
6949 if (width < 0
6950 || height < 0
6951 || (type != PBM_MONO && max_color_idx < 0))
6952 goto error;
6953
6954 BLOCK_INPUT;
6955 if (!x_create_x_image_and_pixmap (f, width, height, 0,
6956 &ximg, &img->pixmap))
6957 {
6958 UNBLOCK_INPUT;
6959 goto error;
6960 }
6961
6962 /* Initialize the color hash table. */
6963 init_color_table ();
6964
6965 if (type == PBM_MONO)
6966 {
6967 int c = 0, g;
6968
6969 for (y = 0; y < height; ++y)
6970 for (x = 0; x < width; ++x)
6971 {
6972 if (raw_p)
6973 {
6974 if ((x & 7) == 0)
6975 c = *p++;
6976 g = c & 0x80;
6977 c <<= 1;
6978 }
6979 else
6980 g = pbm_scan_number (&p, end);
6981
6982 XPutPixel (ximg, x, y, (g
6983 ? FRAME_FOREGROUND_PIXEL (f)
6984 : FRAME_BACKGROUND_PIXEL (f)));
6985 }
6986 }
6987 else
6988 {
6989 for (y = 0; y < height; ++y)
6990 for (x = 0; x < width; ++x)
6991 {
6992 int r, g, b;
6993
6994 if (type == PBM_GRAY)
6995 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
6996 else if (raw_p)
6997 {
6998 r = *p++;
6999 g = *p++;
7000 b = *p++;
7001 }
7002 else
7003 {
7004 r = pbm_scan_number (&p, end);
7005 g = pbm_scan_number (&p, end);
7006 b = pbm_scan_number (&p, end);
7007 }
7008
7009 if (r < 0 || g < 0 || b < 0)
7010 {
7011 xfree (ximg->data);
7012 ximg->data = NULL;
7013 XDestroyImage (ximg);
7014 UNBLOCK_INPUT;
7015 image_error ("Invalid pixel value in image `%s'",
7016 img->spec, Qnil);
7017 goto error;
7018 }
7019
7020 /* RGB values are now in the range 0..max_color_idx.
7021 Scale this to the range 0..0xffff supported by X. */
7022 r = (double) r * 65535 / max_color_idx;
7023 g = (double) g * 65535 / max_color_idx;
7024 b = (double) b * 65535 / max_color_idx;
7025 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7026 }
7027 }
7028
7029 /* Store in IMG->colors the colors allocated for the image, and
7030 free the color table. */
7031 img->colors = colors_in_color_table (&img->ncolors);
7032 free_color_table ();
7033
7034 /* Put the image into a pixmap. */
7035 x_put_x_image (f, ximg, img->pixmap, width, height);
7036 x_destroy_x_image (ximg);
7037 UNBLOCK_INPUT;
7038
7039 img->width = width;
7040 img->height = height;
7041
7042 UNGCPRO;
7043 xfree (contents);
7044 return 1;
7045}
7046#endif /* HAVE_PBM */
7047
7048
7049/***********************************************************************
7050 PNG
7051 ***********************************************************************/
7052
7053#if HAVE_PNG
7054
7055#include <png.h>
7056
7057/* Function prototypes. */
7058
7059static int png_image_p P_ ((Lisp_Object object));
7060static int png_load P_ ((struct frame *f, struct image *img));
7061
7062/* The symbol `png' identifying images of this type. */
7063
7064Lisp_Object Qpng;
7065
7066/* Indices of image specification fields in png_format, below. */
7067
7068enum png_keyword_index
7069{
7070 PNG_TYPE,
7071 PNG_DATA,
7072 PNG_FILE,
7073 PNG_ASCENT,
7074 PNG_MARGIN,
7075 PNG_RELIEF,
7076 PNG_ALGORITHM,
7077 PNG_HEURISTIC_MASK,
7078 PNG_LAST
7079};
7080
7081/* Vector of image_keyword structures describing the format
7082 of valid user-defined image specifications. */
7083
7084static struct image_keyword png_format[PNG_LAST] =
7085{
7086 {":type", IMAGE_SYMBOL_VALUE, 1},
7087 {":data", IMAGE_STRING_VALUE, 0},
7088 {":file", IMAGE_STRING_VALUE, 0},
7089 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7090 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7091 {":relief", IMAGE_INTEGER_VALUE, 0},
7092 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7093 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7094};
7095
7096/* Structure describing the image type `png'. */
7097
7098static struct image_type png_type =
7099{
7100 &Qpng,
7101 png_image_p,
7102 png_load,
7103 x_clear_image,
7104 NULL
7105};
7106
7107
7108/* Return non-zero if OBJECT is a valid PNG image specification. */
7109
7110static int
7111png_image_p (object)
7112 Lisp_Object object;
7113{
7114 struct image_keyword fmt[PNG_LAST];
7115 bcopy (png_format, fmt, sizeof fmt);
7116
7117 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
7118 || (fmt[PNG_ASCENT].count
7119 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
7120 return 0;
7121
7122 /* Must specify either the :data or :file keyword. */
7123 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
7124}
7125
7126
7127/* Error and warning handlers installed when the PNG library
7128 is initialized. */
7129
7130static void
7131my_png_error (png_ptr, msg)
7132 png_struct *png_ptr;
7133 char *msg;
7134{
7135 xassert (png_ptr != NULL);
7136 image_error ("PNG error: %s", build_string (msg), Qnil);
7137 longjmp (png_ptr->jmpbuf, 1);
7138}
7139
7140
7141static void
7142my_png_warning (png_ptr, msg)
7143 png_struct *png_ptr;
7144 char *msg;
7145{
7146 xassert (png_ptr != NULL);
7147 image_error ("PNG warning: %s", build_string (msg), Qnil);
7148}
7149
7150/* Memory source for PNG decoding. */
7151
7152struct png_memory_storage
7153{
7154 unsigned char *bytes; /* The data */
7155 size_t len; /* How big is it? */
7156 int index; /* Where are we? */
7157};
7158
7159
7160/* Function set as reader function when reading PNG image from memory.
7161 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
7162 bytes from the input to DATA. */
7163
7164static void
7165png_read_from_memory (png_ptr, data, length)
7166 png_structp png_ptr;
7167 png_bytep data;
7168 png_size_t length;
7169{
7170 struct png_memory_storage *tbr
7171 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
7172
7173 if (length > tbr->len - tbr->index)
7174 png_error (png_ptr, "Read error");
7175
7176 bcopy (tbr->bytes + tbr->index, data, length);
7177 tbr->index = tbr->index + length;
7178}
7179
7180/* Load PNG image IMG for use on frame F. Value is non-zero if
7181 successful. */
7182
7183static int
7184png_load (f, img)
7185 struct frame *f;
7186 struct image *img;
7187{
7188 Lisp_Object file, specified_file;
7189 Lisp_Object specified_data;
7190 int x, y, i;
7191 XImage *ximg, *mask_img = NULL;
7192 struct gcpro gcpro1;
7193 png_struct *png_ptr = NULL;
7194 png_info *info_ptr = NULL, *end_info = NULL;
7195 FILE *fp = NULL;
7196 png_byte sig[8];
7197 png_byte *pixels = NULL;
7198 png_byte **rows = NULL;
7199 png_uint_32 width, height;
7200 int bit_depth, color_type, interlace_type;
7201 png_byte channels;
7202 png_uint_32 row_bytes;
7203 int transparent_p;
7204 char *gamma_str;
7205 double screen_gamma, image_gamma;
7206 int intent;
7207 struct png_memory_storage tbr; /* Data to be read */
7208
7209 /* Find out what file to load. */
7210 specified_file = image_spec_value (img->spec, QCfile, NULL);
7211 specified_data = image_spec_value (img->spec, QCdata, NULL);
7212 file = Qnil;
7213 GCPRO1 (file);
7214
7215 if (NILP (specified_data))
7216 {
7217 file = x_find_image_file (specified_file);
7218 if (!STRINGP (file))
7219 {
7220 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7221 UNGCPRO;
7222 return 0;
7223 }
7224
7225 /* Open the image file. */
7226 fp = fopen (XSTRING (file)->data, "rb");
7227 if (!fp)
7228 {
7229 image_error ("Cannot open image file `%s'", file, Qnil);
7230 UNGCPRO;
7231 fclose (fp);
7232 return 0;
7233 }
7234
7235 /* Check PNG signature. */
7236 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7237 || !png_check_sig (sig, sizeof sig))
7238 {
7239 image_error ("Not a PNG file:` %s'", file, Qnil);
7240 UNGCPRO;
7241 fclose (fp);
7242 return 0;
7243 }
7244 }
7245 else
7246 {
7247 /* Read from memory. */
7248 tbr.bytes = XSTRING (specified_data)->data;
7249 tbr.len = STRING_BYTES (XSTRING (specified_data));
7250 tbr.index = 0;
7251
7252 /* Check PNG signature. */
7253 if (tbr.len < sizeof sig
7254 || !png_check_sig (tbr.bytes, sizeof sig))
7255 {
7256 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
7257 UNGCPRO;
7258 return 0;
7259 }
7260
7261 /* Need to skip past the signature. */
7262 tbr.bytes += sizeof (sig);
7263 }
7264
7265 /* Initialize read and info structs for PNG lib. */
7266 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
7267 my_png_error, my_png_warning);
7268 if (!png_ptr)
7269 {
7270 if (fp) fclose (fp);
7271 UNGCPRO;
7272 return 0;
7273 }
7274
7275 info_ptr = png_create_info_struct (png_ptr);
7276 if (!info_ptr)
7277 {
7278 png_destroy_read_struct (&png_ptr, NULL, NULL);
7279 if (fp) fclose (fp);
7280 UNGCPRO;
7281 return 0;
7282 }
7283
7284 end_info = png_create_info_struct (png_ptr);
7285 if (!end_info)
7286 {
7287 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
7288 if (fp) fclose (fp);
7289 UNGCPRO;
7290 return 0;
7291 }
7292
7293 /* Set error jump-back. We come back here when the PNG library
7294 detects an error. */
7295 if (setjmp (png_ptr->jmpbuf))
7296 {
7297 error:
7298 if (png_ptr)
7299 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7300 xfree (pixels);
7301 xfree (rows);
7302 if (fp) fclose (fp);
7303 UNGCPRO;
7304 return 0;
7305 }
7306
7307 /* Read image info. */
7308 if (!NILP (specified_data))
7309 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
7310 else
7311 png_init_io (png_ptr, fp);
7312
7313 png_set_sig_bytes (png_ptr, sizeof sig);
7314 png_read_info (png_ptr, info_ptr);
7315 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
7316 &interlace_type, NULL, NULL);
7317
7318 /* If image contains simply transparency data, we prefer to
7319 construct a clipping mask. */
7320 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
7321 transparent_p = 1;
7322 else
7323 transparent_p = 0;
7324
7325 /* This function is easier to write if we only have to handle
7326 one data format: RGB or RGBA with 8 bits per channel. Let's
7327 transform other formats into that format. */
7328
7329 /* Strip more than 8 bits per channel. */
7330 if (bit_depth == 16)
7331 png_set_strip_16 (png_ptr);
7332
7333 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
7334 if available. */
7335 png_set_expand (png_ptr);
7336
7337 /* Convert grayscale images to RGB. */
7338 if (color_type == PNG_COLOR_TYPE_GRAY
7339 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7340 png_set_gray_to_rgb (png_ptr);
7341
7342 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
7343 gamma_str = getenv ("SCREEN_GAMMA");
7344 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
7345
7346 /* Tell the PNG lib to handle gamma correction for us. */
7347
7348#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
7349 if (png_get_sRGB (png_ptr, info_ptr, &intent))
7350 /* There is a special chunk in the image specifying the gamma. */
7351 png_set_sRGB (png_ptr, info_ptr, intent);
7352 else
7353#endif
7354 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
7355 /* Image contains gamma information. */
7356 png_set_gamma (png_ptr, screen_gamma, image_gamma);
7357 else
7358 /* Use a default of 0.5 for the image gamma. */
7359 png_set_gamma (png_ptr, screen_gamma, 0.5);
7360
7361 /* Handle alpha channel by combining the image with a background
7362 color. Do this only if a real alpha channel is supplied. For
7363 simple transparency, we prefer a clipping mask. */
7364 if (!transparent_p)
7365 {
7366 png_color_16 *image_background;
7367
7368 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
7369 /* Image contains a background color with which to
7370 combine the image. */
7371 png_set_background (png_ptr, image_background,
7372 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
7373 else
7374 {
7375 /* Image does not contain a background color with which
7376 to combine the image data via an alpha channel. Use
7377 the frame's background instead. */
7378 XColor color;
7379 Colormap cmap;
7380 png_color_16 frame_background;
7381
7382 BLOCK_INPUT;
7383 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
7384 color.pixel = FRAME_BACKGROUND_PIXEL (f);
7385 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
7386 UNBLOCK_INPUT;
7387
7388 bzero (&frame_background, sizeof frame_background);
7389 frame_background.red = color.red;
7390 frame_background.green = color.green;
7391 frame_background.blue = color.blue;
7392
7393 png_set_background (png_ptr, &frame_background,
7394 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7395 }
7396 }
7397
7398 /* Update info structure. */
7399 png_read_update_info (png_ptr, info_ptr);
7400
7401 /* Get number of channels. Valid values are 1 for grayscale images
7402 and images with a palette, 2 for grayscale images with transparency
7403 information (alpha channel), 3 for RGB images, and 4 for RGB
7404 images with alpha channel, i.e. RGBA. If conversions above were
7405 sufficient we should only have 3 or 4 channels here. */
7406 channels = png_get_channels (png_ptr, info_ptr);
7407 xassert (channels == 3 || channels == 4);
7408
7409 /* Number of bytes needed for one row of the image. */
7410 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
7411
7412 /* Allocate memory for the image. */
7413 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
7414 rows = (png_byte **) xmalloc (height * sizeof *rows);
7415 for (i = 0; i < height; ++i)
7416 rows[i] = pixels + i * row_bytes;
7417
7418 /* Read the entire image. */
7419 png_read_image (png_ptr, rows);
7420 png_read_end (png_ptr, info_ptr);
7421 if (fp)
7422 {
7423 fclose (fp);
7424 fp = NULL;
7425 }
7426
7427 BLOCK_INPUT;
7428
7429 /* Create the X image and pixmap. */
7430 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7431 &img->pixmap))
7432 {
7433 UNBLOCK_INPUT;
7434 goto error;
7435 }
7436
7437 /* Create an image and pixmap serving as mask if the PNG image
7438 contains an alpha channel. */
7439 if (channels == 4
7440 && !transparent_p
7441 && !x_create_x_image_and_pixmap (f, width, height, 1,
7442 &mask_img, &img->mask))
7443 {
7444 x_destroy_x_image (ximg);
7445 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
7446 img->pixmap = 0;
7447 UNBLOCK_INPUT;
7448 goto error;
7449 }
7450
7451 /* Fill the X image and mask from PNG data. */
7452 init_color_table ();
7453
7454 for (y = 0; y < height; ++y)
7455 {
7456 png_byte *p = rows[y];
7457
7458 for (x = 0; x < width; ++x)
7459 {
7460 unsigned r, g, b;
7461
7462 r = *p++ << 8;
7463 g = *p++ << 8;
7464 b = *p++ << 8;
7465 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7466
7467 /* An alpha channel, aka mask channel, associates variable
7468 transparency with an image. Where other image formats
7469 support binary transparency---fully transparent or fully
7470 opaque---PNG allows up to 254 levels of partial transparency.
7471 The PNG library implements partial transparency by combining
7472 the image with a specified background color.
7473
7474 I'm not sure how to handle this here nicely: because the
7475 background on which the image is displayed may change, for
7476 real alpha channel support, it would be necessary to create
7477 a new image for each possible background.
7478
7479 What I'm doing now is that a mask is created if we have
7480 boolean transparency information. Otherwise I'm using
7481 the frame's background color to combine the image with. */
7482
7483 if (channels == 4)
7484 {
7485 if (mask_img)
7486 XPutPixel (mask_img, x, y, *p > 0);
7487 ++p;
7488 }
7489 }
7490 }
7491
7492 /* Remember colors allocated for this image. */
7493 img->colors = colors_in_color_table (&img->ncolors);
7494 free_color_table ();
7495
7496 /* Clean up. */
7497 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7498 xfree (rows);
7499 xfree (pixels);
7500
7501 img->width = width;
7502 img->height = height;
7503
7504 /* Put the image into the pixmap, then free the X image and its buffer. */
7505 x_put_x_image (f, ximg, img->pixmap, width, height);
7506 x_destroy_x_image (ximg);
7507
7508 /* Same for the mask. */
7509 if (mask_img)
7510 {
7511 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7512 x_destroy_x_image (mask_img);
7513 }
7514
7515 UNBLOCK_INPUT;
7516 UNGCPRO;
7517 return 1;
7518}
7519
7520#endif /* HAVE_PNG != 0 */
7521
7522
7523
7524/***********************************************************************
7525 JPEG
7526 ***********************************************************************/
7527
7528#if HAVE_JPEG
7529
7530/* Work around a warning about HAVE_STDLIB_H being redefined in
7531 jconfig.h. */
7532#ifdef HAVE_STDLIB_H
7533#define HAVE_STDLIB_H_1
7534#undef HAVE_STDLIB_H
7535#endif /* HAVE_STLIB_H */
7536
7537#include <jpeglib.h>
7538#include <jerror.h>
7539#include <setjmp.h>
7540
7541#ifdef HAVE_STLIB_H_1
7542#define HAVE_STDLIB_H 1
7543#endif
7544
7545static int jpeg_image_p P_ ((Lisp_Object object));
7546static int jpeg_load P_ ((struct frame *f, struct image *img));
7547
7548/* The symbol `jpeg' identifying images of this type. */
7549
7550Lisp_Object Qjpeg;
7551
7552/* Indices of image specification fields in gs_format, below. */
7553
7554enum jpeg_keyword_index
7555{
7556 JPEG_TYPE,
7557 JPEG_DATA,
7558 JPEG_FILE,
7559 JPEG_ASCENT,
7560 JPEG_MARGIN,
7561 JPEG_RELIEF,
7562 JPEG_ALGORITHM,
7563 JPEG_HEURISTIC_MASK,
7564 JPEG_LAST
7565};
7566
7567/* Vector of image_keyword structures describing the format
7568 of valid user-defined image specifications. */
7569
7570static struct image_keyword jpeg_format[JPEG_LAST] =
7571{
7572 {":type", IMAGE_SYMBOL_VALUE, 1},
7573 {":data", IMAGE_STRING_VALUE, 0},
7574 {":file", IMAGE_STRING_VALUE, 0},
7575 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7576 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7577 {":relief", IMAGE_INTEGER_VALUE, 0},
7578 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7579 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7580};
7581
7582/* Structure describing the image type `jpeg'. */
7583
7584static struct image_type jpeg_type =
7585{
7586 &Qjpeg,
7587 jpeg_image_p,
7588 jpeg_load,
7589 x_clear_image,
7590 NULL
7591};
7592
7593
7594/* Return non-zero if OBJECT is a valid JPEG image specification. */
7595
7596static int
7597jpeg_image_p (object)
7598 Lisp_Object object;
7599{
7600 struct image_keyword fmt[JPEG_LAST];
7601
7602 bcopy (jpeg_format, fmt, sizeof fmt);
7603
7604 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
7605 || (fmt[JPEG_ASCENT].count
7606 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
7607 return 0;
7608
7609 /* Must specify either the :data or :file keyword. */
7610 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
7611}
7612
7613
7614struct my_jpeg_error_mgr
7615{
7616 struct jpeg_error_mgr pub;
7617 jmp_buf setjmp_buffer;
7618};
7619
7620static void
7621my_error_exit (cinfo)
7622 j_common_ptr cinfo;
7623{
7624 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
7625 longjmp (mgr->setjmp_buffer, 1);
7626}
7627
7628/* Init source method for JPEG data source manager. Called by
7629 jpeg_read_header() before any data is actually read. See
7630 libjpeg.doc from the JPEG lib distribution. */
7631
7632static void
7633our_init_source (cinfo)
7634 j_decompress_ptr cinfo;
7635{
7636}
7637
7638
7639/* Fill input buffer method for JPEG data source manager. Called
7640 whenever more data is needed. We read the whole image in one step,
7641 so this only adds a fake end of input marker at the end. */
7642
7643static boolean
7644our_fill_input_buffer (cinfo)
7645 j_decompress_ptr cinfo;
7646{
7647 /* Insert a fake EOI marker. */
7648 struct jpeg_source_mgr *src = cinfo->src;
7649 static JOCTET buffer[2];
7650
7651 buffer[0] = (JOCTET) 0xFF;
7652 buffer[1] = (JOCTET) JPEG_EOI;
7653
7654 src->next_input_byte = buffer;
7655 src->bytes_in_buffer = 2;
7656 return TRUE;
7657}
7658
7659
7660/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
7661 is the JPEG data source manager. */
7662
7663static void
7664our_skip_input_data (cinfo, num_bytes)
7665 j_decompress_ptr cinfo;
7666 long num_bytes;
7667{
7668 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
7669
7670 if (src)
7671 {
7672 if (num_bytes > src->bytes_in_buffer)
7673 ERREXIT (cinfo, JERR_INPUT_EOF);
7674
7675 src->bytes_in_buffer -= num_bytes;
7676 src->next_input_byte += num_bytes;
7677 }
7678}
7679
7680
7681/* Method to terminate data source. Called by
7682 jpeg_finish_decompress() after all data has been processed. */
7683
7684static void
7685our_term_source (cinfo)
7686 j_decompress_ptr cinfo;
7687{
7688}
7689
7690
7691/* Set up the JPEG lib for reading an image from DATA which contains
7692 LEN bytes. CINFO is the decompression info structure created for
7693 reading the image. */
7694
7695static void
7696jpeg_memory_src (cinfo, data, len)
7697 j_decompress_ptr cinfo;
7698 JOCTET *data;
7699 unsigned int len;
7700{
7701 struct jpeg_source_mgr *src;
7702
7703 if (cinfo->src == NULL)
7704 {
7705 /* First time for this JPEG object? */
7706 cinfo->src = (struct jpeg_source_mgr *)
7707 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
7708 sizeof (struct jpeg_source_mgr));
7709 src = (struct jpeg_source_mgr *) cinfo->src;
7710 src->next_input_byte = data;
7711 }
7712
7713 src = (struct jpeg_source_mgr *) cinfo->src;
7714 src->init_source = our_init_source;
7715 src->fill_input_buffer = our_fill_input_buffer;
7716 src->skip_input_data = our_skip_input_data;
7717 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
7718 src->term_source = our_term_source;
7719 src->bytes_in_buffer = len;
7720 src->next_input_byte = data;
7721}
7722
7723
7724/* Load image IMG for use on frame F. Patterned after example.c
7725 from the JPEG lib. */
7726
7727static int
7728jpeg_load (f, img)
7729 struct frame *f;
7730 struct image *img;
7731{
7732 struct jpeg_decompress_struct cinfo;
7733 struct my_jpeg_error_mgr mgr;
7734 Lisp_Object file, specified_file;
7735 Lisp_Object specified_data;
7736 FILE *fp = NULL;
7737 JSAMPARRAY buffer;
7738 int row_stride, x, y;
7739 XImage *ximg = NULL;
7740 int rc;
7741 unsigned long *colors;
7742 int width, height;
7743 struct gcpro gcpro1;
7744
7745 /* Open the JPEG file. */
7746 specified_file = image_spec_value (img->spec, QCfile, NULL);
7747 specified_data = image_spec_value (img->spec, QCdata, NULL);
7748 file = Qnil;
7749 GCPRO1 (file);
7750
7751 if (NILP (specified_data))
7752 {
7753 file = x_find_image_file (specified_file);
7754 if (!STRINGP (file))
7755 {
7756 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7757 UNGCPRO;
7758 return 0;
7759 }
7760
7761 fp = fopen (XSTRING (file)->data, "r");
7762 if (fp == NULL)
7763 {
7764 image_error ("Cannot open `%s'", file, Qnil);
7765 UNGCPRO;
7766 return 0;
7767 }
7768 }
7769
7770 /* Customize libjpeg's error handling to call my_error_exit when an
7771 error is detected. This function will perform a longjmp. */
7772 mgr.pub.error_exit = my_error_exit;
7773 cinfo.err = jpeg_std_error (&mgr.pub);
7774
7775 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
7776 {
7777 if (rc == 1)
7778 {
7779 /* Called from my_error_exit. Display a JPEG error. */
7780 char buffer[JMSG_LENGTH_MAX];
7781 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
7782 image_error ("Error reading JPEG image `%s': %s", img->spec,
7783 build_string (buffer));
7784 }
7785
7786 /* Close the input file and destroy the JPEG object. */
7787 if (fp)
7788 fclose (fp);
7789 jpeg_destroy_decompress (&cinfo);
7790
7791 BLOCK_INPUT;
7792
7793 /* If we already have an XImage, free that. */
7794 x_destroy_x_image (ximg);
7795
7796 /* Free pixmap and colors. */
7797 x_clear_image (f, img);
7798
7799 UNBLOCK_INPUT;
7800 UNGCPRO;
7801 return 0;
7802 }
7803
7804 /* Create the JPEG decompression object. Let it read from fp.
7805 Read the JPEG image header. */
7806 jpeg_create_decompress (&cinfo);
7807
7808 if (NILP (specified_data))
7809 jpeg_stdio_src (&cinfo, fp);
7810 else
7811 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
7812 STRING_BYTES (XSTRING (specified_data)));
7813
7814 jpeg_read_header (&cinfo, TRUE);
7815
7816 /* Customize decompression so that color quantization will be used.
7817 Start decompression. */
7818 cinfo.quantize_colors = TRUE;
7819 jpeg_start_decompress (&cinfo);
7820 width = img->width = cinfo.output_width;
7821 height = img->height = cinfo.output_height;
7822
7823 BLOCK_INPUT;
7824
7825 /* Create X image and pixmap. */
7826 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7827 &img->pixmap))
7828 {
7829 UNBLOCK_INPUT;
7830 longjmp (mgr.setjmp_buffer, 2);
7831 }
7832
7833 /* Allocate colors. When color quantization is used,
7834 cinfo.actual_number_of_colors has been set with the number of
7835 colors generated, and cinfo.colormap is a two-dimensional array
7836 of color indices in the range 0..cinfo.actual_number_of_colors.
7837 No more than 255 colors will be generated. */
7838 {
7839 int i, ir, ig, ib;
7840
7841 if (cinfo.out_color_components > 2)
7842 ir = 0, ig = 1, ib = 2;
7843 else if (cinfo.out_color_components > 1)
7844 ir = 0, ig = 1, ib = 0;
7845 else
7846 ir = 0, ig = 0, ib = 0;
7847
7848 /* Use the color table mechanism because it handles colors that
7849 cannot be allocated nicely. Such colors will be replaced with
7850 a default color, and we don't have to care about which colors
7851 can be freed safely, and which can't. */
7852 init_color_table ();
7853 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
7854 * sizeof *colors);
7855
7856 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
7857 {
7858 /* Multiply RGB values with 255 because X expects RGB values
7859 in the range 0..0xffff. */
7860 int r = cinfo.colormap[ir][i] << 8;
7861 int g = cinfo.colormap[ig][i] << 8;
7862 int b = cinfo.colormap[ib][i] << 8;
7863 colors[i] = lookup_rgb_color (f, r, g, b);
7864 }
7865
7866 /* Remember those colors actually allocated. */
7867 img->colors = colors_in_color_table (&img->ncolors);
7868 free_color_table ();
7869 }
7870
7871 /* Read pixels. */
7872 row_stride = width * cinfo.output_components;
7873 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
7874 row_stride, 1);
7875 for (y = 0; y < height; ++y)
7876 {
7877 jpeg_read_scanlines (&cinfo, buffer, 1);
7878 for (x = 0; x < cinfo.output_width; ++x)
7879 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
7880 }
7881
7882 /* Clean up. */
7883 jpeg_finish_decompress (&cinfo);
7884 jpeg_destroy_decompress (&cinfo);
7885 if (fp)
7886 fclose (fp);
7887
7888 /* Put the image into the pixmap. */
7889 x_put_x_image (f, ximg, img->pixmap, width, height);
7890 x_destroy_x_image (ximg);
7891 UNBLOCK_INPUT;
7892 UNGCPRO;
7893 return 1;
7894}
7895
7896#endif /* HAVE_JPEG */
7897
7898
7899
7900/***********************************************************************
7901 TIFF
7902 ***********************************************************************/
7903
7904#if HAVE_TIFF
7905
7906#include <tiffio.h>
7907
7908static int tiff_image_p P_ ((Lisp_Object object));
7909static int tiff_load P_ ((struct frame *f, struct image *img));
7910
7911/* The symbol `tiff' identifying images of this type. */
7912
7913Lisp_Object Qtiff;
7914
7915/* Indices of image specification fields in tiff_format, below. */
7916
7917enum tiff_keyword_index
7918{
7919 TIFF_TYPE,
7920 TIFF_DATA,
7921 TIFF_FILE,
7922 TIFF_ASCENT,
7923 TIFF_MARGIN,
7924 TIFF_RELIEF,
7925 TIFF_ALGORITHM,
7926 TIFF_HEURISTIC_MASK,
7927 TIFF_LAST
7928};
7929
7930/* Vector of image_keyword structures describing the format
7931 of valid user-defined image specifications. */
7932
7933static struct image_keyword tiff_format[TIFF_LAST] =
7934{
7935 {":type", IMAGE_SYMBOL_VALUE, 1},
7936 {":data", IMAGE_STRING_VALUE, 0},
7937 {":file", IMAGE_STRING_VALUE, 0},
7938 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7939 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7940 {":relief", IMAGE_INTEGER_VALUE, 0},
7941 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7942 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7943};
7944
7945/* Structure describing the image type `tiff'. */
7946
7947static struct image_type tiff_type =
7948{
7949 &Qtiff,
7950 tiff_image_p,
7951 tiff_load,
7952 x_clear_image,
7953 NULL
7954};
7955
7956
7957/* Return non-zero if OBJECT is a valid TIFF image specification. */
7958
7959static int
7960tiff_image_p (object)
7961 Lisp_Object object;
7962{
7963 struct image_keyword fmt[TIFF_LAST];
7964 bcopy (tiff_format, fmt, sizeof fmt);
7965
7966 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
7967 || (fmt[TIFF_ASCENT].count
7968 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
7969 return 0;
7970
7971 /* Must specify either the :data or :file keyword. */
7972 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
7973}
7974
7975
7976/* Reading from a memory buffer for TIFF images Based on the PNG
7977 memory source, but we have to provide a lot of extra functions.
7978 Blah.
7979
7980 We really only need to implement read and seek, but I am not
7981 convinced that the TIFF library is smart enough not to destroy
7982 itself if we only hand it the function pointers we need to
7983 override. */
7984
7985typedef struct
7986{
7987 unsigned char *bytes;
7988 size_t len;
7989 int index;
7990}
7991tiff_memory_source;
7992
7993static size_t
7994tiff_read_from_memory (data, buf, size)
7995 thandle_t data;
7996 tdata_t buf;
7997 tsize_t size;
7998{
7999 tiff_memory_source *src = (tiff_memory_source *) data;
8000
8001 if (size > src->len - src->index)
8002 return (size_t) -1;
8003 bcopy (src->bytes + src->index, buf, size);
8004 src->index += size;
8005 return size;
8006}
8007
8008static size_t
8009tiff_write_from_memory (data, buf, size)
8010 thandle_t data;
8011 tdata_t buf;
8012 tsize_t size;
8013{
8014 return (size_t) -1;
8015}
8016
8017static toff_t
8018tiff_seek_in_memory (data, off, whence)
8019 thandle_t data;
8020 toff_t off;
8021 int whence;
8022{
8023 tiff_memory_source *src = (tiff_memory_source *) data;
8024 int idx;
8025
8026 switch (whence)
8027 {
8028 case SEEK_SET: /* Go from beginning of source. */
8029 idx = off;
8030 break;
8031
8032 case SEEK_END: /* Go from end of source. */
8033 idx = src->len + off;
8034 break;
8035
8036 case SEEK_CUR: /* Go from current position. */
8037 idx = src->index + off;
8038 break;
8039
8040 default: /* Invalid `whence'. */
8041 return -1;
8042 }
8043
8044 if (idx > src->len || idx < 0)
8045 return -1;
8046
8047 src->index = idx;
8048 return src->index;
8049}
8050
8051static int
8052tiff_close_memory (data)
8053 thandle_t data;
8054{
8055 /* NOOP */
8056 return 0;
8057}
8058
8059static int
8060tiff_mmap_memory (data, pbase, psize)
8061 thandle_t data;
8062 tdata_t *pbase;
8063 toff_t *psize;
8064{
8065 /* It is already _IN_ memory. */
8066 return 0;
8067}
8068
8069static void
8070tiff_unmap_memory (data, base, size)
8071 thandle_t data;
8072 tdata_t base;
8073 toff_t size;
8074{
8075 /* We don't need to do this. */
8076}
8077
8078static toff_t
8079tiff_size_of_memory (data)
8080 thandle_t data;
8081{
8082 return ((tiff_memory_source *) data)->len;
8083}
8084
8085/* Load TIFF image IMG for use on frame F. Value is non-zero if
8086 successful. */
8087
8088static int
8089tiff_load (f, img)
8090 struct frame *f;
8091 struct image *img;
8092{
8093 Lisp_Object file, specified_file;
8094 Lisp_Object specified_data;
8095 TIFF *tiff;
8096 int width, height, x, y;
8097 uint32 *buf;
8098 int rc;
8099 XImage *ximg;
8100 struct gcpro gcpro1;
8101 tiff_memory_source memsrc;
8102
8103 specified_file = image_spec_value (img->spec, QCfile, NULL);
8104 specified_data = image_spec_value (img->spec, QCdata, NULL);
8105 file = Qnil;
8106 GCPRO1 (file);
8107
8108 if (NILP (specified_data))
8109 {
8110 /* Read from a file */
8111 file = x_find_image_file (specified_file);
8112 if (!STRINGP (file))
8113 {
8114 image_error ("Cannot find image file `%s'", file, Qnil);
8115 UNGCPRO;
8116 return 0;
8117 }
8118
8119 /* Try to open the image file. */
8120 tiff = TIFFOpen (XSTRING (file)->data, "r");
8121 if (tiff == NULL)
8122 {
8123 image_error ("Cannot open `%s'", file, Qnil);
8124 UNGCPRO;
8125 return 0;
8126 }
8127 }
8128 else
8129 {
8130 /* Memory source! */
8131 memsrc.bytes = XSTRING (specified_data)->data;
8132 memsrc.len = STRING_BYTES (XSTRING (specified_data));
8133 memsrc.index = 0;
8134
8135 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
8136 (TIFFReadWriteProc) tiff_read_from_memory,
8137 (TIFFReadWriteProc) tiff_write_from_memory,
8138 tiff_seek_in_memory,
8139 tiff_close_memory,
8140 tiff_size_of_memory,
8141 tiff_mmap_memory,
8142 tiff_unmap_memory);
8143
8144 if (!tiff)
8145 {
8146 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
8147 UNGCPRO;
8148 return 0;
8149 }
8150 }
8151
8152 /* Get width and height of the image, and allocate a raster buffer
8153 of width x height 32-bit values. */
8154 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8155 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8156 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
8157
8158 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8159 TIFFClose (tiff);
8160 if (!rc)
8161 {
8162 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
8163 xfree (buf);
8164 UNGCPRO;
8165 return 0;
8166 }
8167
8168 BLOCK_INPUT;
8169
8170 /* Create the X image and pixmap. */
8171 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8172 {
8173 UNBLOCK_INPUT;
8174 xfree (buf);
8175 UNGCPRO;
8176 return 0;
8177 }
8178
8179 /* Initialize the color table. */
8180 init_color_table ();
8181
8182 /* Process the pixel raster. Origin is in the lower-left corner. */
8183 for (y = 0; y < height; ++y)
8184 {
8185 uint32 *row = buf + y * width;
8186
8187 for (x = 0; x < width; ++x)
8188 {
8189 uint32 abgr = row[x];
8190 int r = TIFFGetR (abgr) << 8;
8191 int g = TIFFGetG (abgr) << 8;
8192 int b = TIFFGetB (abgr) << 8;
8193 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
8194 }
8195 }
8196
8197 /* Remember the colors allocated for the image. Free the color table. */
8198 img->colors = colors_in_color_table (&img->ncolors);
8199 free_color_table ();
8200
8201 /* Put the image into the pixmap, then free the X image and its buffer. */
8202 x_put_x_image (f, ximg, img->pixmap, width, height);
8203 x_destroy_x_image (ximg);
8204 xfree (buf);
8205 UNBLOCK_INPUT;
8206
8207 img->width = width;
8208 img->height = height;
8209
8210 UNGCPRO;
8211 return 1;
8212}
8213
8214#endif /* HAVE_TIFF != 0 */
8215
8216
8217
8218/***********************************************************************
8219 GIF
8220 ***********************************************************************/
8221
8222#if HAVE_GIF
8223
8224#include <gif_lib.h>
8225
8226static int gif_image_p P_ ((Lisp_Object object));
8227static int gif_load P_ ((struct frame *f, struct image *img));
8228
8229/* The symbol `gif' identifying images of this type. */
8230
8231Lisp_Object Qgif;
8232
8233/* Indices of image specification fields in gif_format, below. */
8234
8235enum gif_keyword_index
8236{
8237 GIF_TYPE,
8238 GIF_DATA,
8239 GIF_FILE,
8240 GIF_ASCENT,
8241 GIF_MARGIN,
8242 GIF_RELIEF,
8243 GIF_ALGORITHM,
8244 GIF_HEURISTIC_MASK,
8245 GIF_IMAGE,
8246 GIF_LAST
8247};
8248
8249/* Vector of image_keyword structures describing the format
8250 of valid user-defined image specifications. */
8251
8252static struct image_keyword gif_format[GIF_LAST] =
8253{
8254 {":type", IMAGE_SYMBOL_VALUE, 1},
8255 {":data", IMAGE_STRING_VALUE, 0},
8256 {":file", IMAGE_STRING_VALUE, 0},
8257 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8258 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8259 {":relief", IMAGE_INTEGER_VALUE, 0},
8260 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8261 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8262 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
8263};
8264
8265/* Structure describing the image type `gif'. */
8266
8267static struct image_type gif_type =
8268{
8269 &Qgif,
8270 gif_image_p,
8271 gif_load,
8272 x_clear_image,
8273 NULL
8274};
8275
8276/* Return non-zero if OBJECT is a valid GIF image specification. */
8277
8278static int
8279gif_image_p (object)
8280 Lisp_Object object;
8281{
8282 struct image_keyword fmt[GIF_LAST];
8283 bcopy (gif_format, fmt, sizeof fmt);
8284
8285 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
8286 || (fmt[GIF_ASCENT].count
8287 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
8288 return 0;
8289
8290 /* Must specify either the :data or :file keyword. */
8291 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
8292}
8293
8294/* Reading a GIF image from memory
8295 Based on the PNG memory stuff to a certain extent. */
8296
8297typedef struct
8298{
8299 unsigned char *bytes;
8300 size_t len;
8301 int index;
8302}
8303gif_memory_source;
8304
8305/* Make the current memory source available to gif_read_from_memory.
8306 It's done this way because not all versions of libungif support
8307 a UserData field in the GifFileType structure. */
8308static gif_memory_source *current_gif_memory_src;
8309
8310static int
8311gif_read_from_memory (file, buf, len)
8312 GifFileType *file;
8313 GifByteType *buf;
8314 int len;
8315{
8316 gif_memory_source *src = current_gif_memory_src;
8317
8318 if (len > src->len - src->index)
8319 return -1;
8320
8321 bcopy (src->bytes + src->index, buf, len);
8322 src->index += len;
8323 return len;
8324}
8325
8326
8327/* Load GIF image IMG for use on frame F. Value is non-zero if
8328 successful. */
8329
8330static int
8331gif_load (f, img)
8332 struct frame *f;
8333 struct image *img;
8334{
8335 Lisp_Object file, specified_file;
8336 Lisp_Object specified_data;
8337 int rc, width, height, x, y, i;
8338 XImage *ximg;
8339 ColorMapObject *gif_color_map;
8340 unsigned long pixel_colors[256];
8341 GifFileType *gif;
8342 struct gcpro gcpro1;
8343 Lisp_Object image;
8344 int ino, image_left, image_top, image_width, image_height;
8345 gif_memory_source memsrc;
8346 unsigned char *raster;
8347
8348 specified_file = image_spec_value (img->spec, QCfile, NULL);
8349 specified_data = image_spec_value (img->spec, QCdata, NULL);
8350 file = Qnil;
8351 GCPRO1 (file);
8352
8353 if (NILP (specified_data))
8354 {
8355 file = x_find_image_file (specified_file);
8356 if (!STRINGP (file))
8357 {
8358 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8359 UNGCPRO;
8360 return 0;
8361 }
8362
8363 /* Open the GIF file. */
8364 gif = DGifOpenFileName (XSTRING (file)->data);
8365 if (gif == NULL)
8366 {
8367 image_error ("Cannot open `%s'", file, Qnil);
8368 UNGCPRO;
8369 return 0;
8370 }
8371 }
8372 else
8373 {
8374 /* Read from memory! */
8375 current_gif_memory_src = &memsrc;
8376 memsrc.bytes = XSTRING (specified_data)->data;
8377 memsrc.len = STRING_BYTES (XSTRING (specified_data));
8378 memsrc.index = 0;
8379
8380 gif = DGifOpen(&memsrc, gif_read_from_memory);
8381 if (!gif)
8382 {
8383 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
8384 UNGCPRO;
8385 return 0;
8386 }
8387 }
8388
8389 /* Read entire contents. */
8390 rc = DGifSlurp (gif);
8391 if (rc == GIF_ERROR)
8392 {
8393 image_error ("Error reading `%s'", img->spec, Qnil);
8394 DGifCloseFile (gif);
8395 UNGCPRO;
8396 return 0;
8397 }
8398
8399 image = image_spec_value (img->spec, QCindex, NULL);
8400 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8401 if (ino >= gif->ImageCount)
8402 {
8403 image_error ("Invalid image number `%s' in image `%s'",
8404 image, img->spec);
8405 DGifCloseFile (gif);
8406 UNGCPRO;
8407 return 0;
8408 }
8409
8410 width = img->width = gif->SWidth;
8411 height = img->height = gif->SHeight;
8412
8413 BLOCK_INPUT;
8414
8415 /* Create the X image and pixmap. */
8416 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8417 {
8418 UNBLOCK_INPUT;
8419 DGifCloseFile (gif);
8420 UNGCPRO;
8421 return 0;
8422 }
8423
8424 /* Allocate colors. */
8425 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
8426 if (!gif_color_map)
8427 gif_color_map = gif->SColorMap;
8428 init_color_table ();
8429 bzero (pixel_colors, sizeof pixel_colors);
8430
8431 for (i = 0; i < gif_color_map->ColorCount; ++i)
8432 {
8433 int r = gif_color_map->Colors[i].Red << 8;
8434 int g = gif_color_map->Colors[i].Green << 8;
8435 int b = gif_color_map->Colors[i].Blue << 8;
8436 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
8437 }
8438
8439 img->colors = colors_in_color_table (&img->ncolors);
8440 free_color_table ();
8441
8442 /* Clear the part of the screen image that are not covered by
8443 the image from the GIF file. Full animated GIF support
8444 requires more than can be done here (see the gif89 spec,
8445 disposal methods). Let's simply assume that the part
8446 not covered by a sub-image is in the frame's background color. */
8447 image_top = gif->SavedImages[ino].ImageDesc.Top;
8448 image_left = gif->SavedImages[ino].ImageDesc.Left;
8449 image_width = gif->SavedImages[ino].ImageDesc.Width;
8450 image_height = gif->SavedImages[ino].ImageDesc.Height;
8451
8452 for (y = 0; y < image_top; ++y)
8453 for (x = 0; x < width; ++x)
8454 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8455
8456 for (y = image_top + image_height; y < height; ++y)
8457 for (x = 0; x < width; ++x)
8458 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8459
8460 for (y = image_top; y < image_top + image_height; ++y)
8461 {
8462 for (x = 0; x < image_left; ++x)
8463 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8464 for (x = image_left + image_width; x < width; ++x)
8465 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8466 }
8467
8468 /* Read the GIF image into the X image. We use a local variable
8469 `raster' here because RasterBits below is a char *, and invites
8470 problems with bytes >= 0x80. */
8471 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
8472
8473 if (gif->SavedImages[ino].ImageDesc.Interlace)
8474 {
8475 static int interlace_start[] = {0, 4, 2, 1};
8476 static int interlace_increment[] = {8, 8, 4, 2};
8477 int pass, inc;
8478 int row = interlace_start[0];
8479
8480 pass = 0;
8481
8482 for (y = 0; y < image_height; y++)
8483 {
8484 if (row >= image_height)
8485 {
8486 row = interlace_start[++pass];
8487 while (row >= image_height)
8488 row = interlace_start[++pass];
8489 }
8490
8491 for (x = 0; x < image_width; x++)
8492 {
8493 int i = raster[(y * image_width) + x];
8494 XPutPixel (ximg, x + image_left, row + image_top,
8495 pixel_colors[i]);
8496 }
8497
8498 row += interlace_increment[pass];
8499 }
8500 }
8501 else
8502 {
8503 for (y = 0; y < image_height; ++y)
8504 for (x = 0; x < image_width; ++x)
8505 {
8506 int i = raster[y* image_width + x];
8507 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
8508 }
8509 }
8510
8511 DGifCloseFile (gif);
8512
8513 /* Put the image into the pixmap, then free the X image and its buffer. */
8514 x_put_x_image (f, ximg, img->pixmap, width, height);
8515 x_destroy_x_image (ximg);
8516 UNBLOCK_INPUT;
8517
8518 UNGCPRO;
8519 return 1;
8520}
8521
8522#endif /* HAVE_GIF != 0 */
8523
8524
8525
8526/***********************************************************************
8527 Ghostscript
8528 ***********************************************************************/
8529
8530#ifdef HAVE_GHOSTSCRIPT
8531static int gs_image_p P_ ((Lisp_Object object));
8532static int gs_load P_ ((struct frame *f, struct image *img));
8533static void gs_clear_image P_ ((struct frame *f, struct image *img));
8534
8535/* The symbol `postscript' identifying images of this type. */
8536
8537Lisp_Object Qpostscript;
8538
8539/* Keyword symbols. */
8540
8541Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8542
8543/* Indices of image specification fields in gs_format, below. */
8544
8545enum gs_keyword_index
8546{
8547 GS_TYPE,
8548 GS_PT_WIDTH,
8549 GS_PT_HEIGHT,
8550 GS_FILE,
8551 GS_LOADER,
8552 GS_BOUNDING_BOX,
8553 GS_ASCENT,
8554 GS_MARGIN,
8555 GS_RELIEF,
8556 GS_ALGORITHM,
8557 GS_HEURISTIC_MASK,
8558 GS_LAST
8559};
8560
8561/* Vector of image_keyword structures describing the format
8562 of valid user-defined image specifications. */
8563
8564static struct image_keyword gs_format[GS_LAST] =
8565{
8566 {":type", IMAGE_SYMBOL_VALUE, 1},
8567 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8568 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8569 {":file", IMAGE_STRING_VALUE, 1},
8570 {":loader", IMAGE_FUNCTION_VALUE, 0},
8571 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8572 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8573 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8574 {":relief", IMAGE_INTEGER_VALUE, 0},
8575 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8576 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8577};
8578
8579/* Structure describing the image type `ghostscript'. */
8580
8581static struct image_type gs_type =
8582{
8583 &Qpostscript,
8584 gs_image_p,
8585 gs_load,
8586 gs_clear_image,
8587 NULL
8588};
8589
8590
8591/* Free X resources of Ghostscript image IMG which is used on frame F. */
8592
8593static void
8594gs_clear_image (f, img)
8595 struct frame *f;
8596 struct image *img;
8597{
8598 /* IMG->data.ptr_val may contain a recorded colormap. */
8599 xfree (img->data.ptr_val);
8600 x_clear_image (f, img);
8601}
8602
8603
8604/* Return non-zero if OBJECT is a valid Ghostscript image
8605 specification. */
8606
8607static int
8608gs_image_p (object)
8609 Lisp_Object object;
8610{
8611 struct image_keyword fmt[GS_LAST];
8612 Lisp_Object tem;
8613 int i;
8614
8615 bcopy (gs_format, fmt, sizeof fmt);
8616
8617 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
8618 || (fmt[GS_ASCENT].count
8619 && XFASTINT (fmt[GS_ASCENT].value) > 100))
8620 return 0;
8621
8622 /* Bounding box must be a list or vector containing 4 integers. */
8623 tem = fmt[GS_BOUNDING_BOX].value;
8624 if (CONSP (tem))
8625 {
8626 for (i = 0; i < 4; ++i, tem = XCDR (tem))
8627 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
8628 return 0;
8629 if (!NILP (tem))
8630 return 0;
8631 }
8632 else if (VECTORP (tem))
8633 {
8634 if (XVECTOR (tem)->size != 4)
8635 return 0;
8636 for (i = 0; i < 4; ++i)
8637 if (!INTEGERP (XVECTOR (tem)->contents[i]))
8638 return 0;
8639 }
8640 else
8641 return 0;
8642
8643 return 1;
8644}
8645
8646
8647/* Load Ghostscript image IMG for use on frame F. Value is non-zero
8648 if successful. */
8649
8650static int
8651gs_load (f, img)
8652 struct frame *f;
8653 struct image *img;
8654{
8655 char buffer[100];
8656 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
8657 struct gcpro gcpro1, gcpro2;
8658 Lisp_Object frame;
8659 double in_width, in_height;
8660 Lisp_Object pixel_colors = Qnil;
8661
8662 /* Compute pixel size of pixmap needed from the given size in the
8663 image specification. Sizes in the specification are in pt. 1 pt
8664 = 1/72 in, xdpi and ydpi are stored in the frame's X display
8665 info. */
8666 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
8667 in_width = XFASTINT (pt_width) / 72.0;
8668 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
8669 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
8670 in_height = XFASTINT (pt_height) / 72.0;
8671 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
8672
8673 /* Create the pixmap. */
8674 BLOCK_INPUT;
8675 xassert (img->pixmap == 0);
8676 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8677 img->width, img->height,
8678 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
8679 UNBLOCK_INPUT;
8680
8681 if (!img->pixmap)
8682 {
8683 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8684 return 0;
8685 }
8686
8687 /* Call the loader to fill the pixmap. It returns a process object
8688 if successful. We do not record_unwind_protect here because
8689 other places in redisplay like calling window scroll functions
8690 don't either. Let the Lisp loader use `unwind-protect' instead. */
8691 GCPRO2 (window_and_pixmap_id, pixel_colors);
8692
8693 sprintf (buffer, "%lu %lu",
8694 (unsigned long) FRAME_W32_WINDOW (f),
8695 (unsigned long) img->pixmap);
8696 window_and_pixmap_id = build_string (buffer);
8697
8698 sprintf (buffer, "%lu %lu",
8699 FRAME_FOREGROUND_PIXEL (f),
8700 FRAME_BACKGROUND_PIXEL (f));
8701 pixel_colors = build_string (buffer);
8702
8703 XSETFRAME (frame, f);
8704 loader = image_spec_value (img->spec, QCloader, NULL);
8705 if (NILP (loader))
8706 loader = intern ("gs-load-image");
8707
8708 img->data.lisp_val = call6 (loader, frame, img->spec,
8709 make_number (img->width),
8710 make_number (img->height),
8711 window_and_pixmap_id,
8712 pixel_colors);
8713 UNGCPRO;
8714 return PROCESSP (img->data.lisp_val);
8715}
8716
8717
8718/* Kill the Ghostscript process that was started to fill PIXMAP on
8719 frame F. Called from XTread_socket when receiving an event
8720 telling Emacs that Ghostscript has finished drawing. */
8721
8722void
8723x_kill_gs_process (pixmap, f)
8724 Pixmap pixmap;
8725 struct frame *f;
8726{
8727 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8728 int class, i;
8729 struct image *img;
8730
8731 /* Find the image containing PIXMAP. */
8732 for (i = 0; i < c->used; ++i)
8733 if (c->images[i]->pixmap == pixmap)
8734 break;
8735
8736 /* Kill the GS process. We should have found PIXMAP in the image
8737 cache and its image should contain a process object. */
8738 xassert (i < c->used);
8739 img = c->images[i];
8740 xassert (PROCESSP (img->data.lisp_val));
8741 Fkill_process (img->data.lisp_val, Qnil);
8742 img->data.lisp_val = Qnil;
8743
8744 /* On displays with a mutable colormap, figure out the colors
8745 allocated for the image by looking at the pixels of an XImage for
8746 img->pixmap. */
8747 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8748 if (class != StaticColor && class != StaticGray && class != TrueColor)
8749 {
8750 XImage *ximg;
8751
8752 BLOCK_INPUT;
8753
8754 /* Try to get an XImage for img->pixmep. */
8755 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
8756 0, 0, img->width, img->height, ~0, ZPixmap);
8757 if (ximg)
8758 {
8759 int x, y;
8760
8761 /* Initialize the color table. */
8762 init_color_table ();
8763
8764 /* For each pixel of the image, look its color up in the
8765 color table. After having done so, the color table will
8766 contain an entry for each color used by the image. */
8767 for (y = 0; y < img->height; ++y)
8768 for (x = 0; x < img->width; ++x)
8769 {
8770 unsigned long pixel = XGetPixel (ximg, x, y);
8771 lookup_pixel_color (f, pixel);
8772 }
8773
8774 /* Record colors in the image. Free color table and XImage. */
8775 img->colors = colors_in_color_table (&img->ncolors);
8776 free_color_table ();
8777 XDestroyImage (ximg);
8778
8779#if 0 /* This doesn't seem to be the case. If we free the colors
8780 here, we get a BadAccess later in x_clear_image when
8781 freeing the colors. */
8782 /* We have allocated colors once, but Ghostscript has also
8783 allocated colors on behalf of us. So, to get the
8784 reference counts right, free them once. */
8785 if (img->ncolors)
8786 {
8787 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
8788 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
8789 img->colors, img->ncolors, 0);
8790 }
8791#endif
8792 }
8793 else
8794 image_error ("Cannot get X image of `%s'; colors will not be freed",
8795 img->spec, Qnil);
8796
8797 UNBLOCK_INPUT;
8798 }
8799}
8800
8801#endif /* HAVE_GHOSTSCRIPT */
8802
8803
8804/***********************************************************************
8805 Window properties
8806 ***********************************************************************/
8807
8808DEFUN ("x-change-window-property", Fx_change_window_property,
8809 Sx_change_window_property, 2, 3, 0,
8810 "Change window property PROP to VALUE on the X window of FRAME.\n\
8811PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
8812selected frame. Value is VALUE.")
8813 (prop, value, frame)
8814 Lisp_Object frame, prop, value;
8815{
8816#if 0 /* MAC_TODO : port window properties to Mac */
8817 struct frame *f = check_x_frame (frame);
8818 Atom prop_atom;
8819
8820 CHECK_STRING (prop, 1);
8821 CHECK_STRING (value, 2);
8822
8823 BLOCK_INPUT;
8824 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
8825 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8826 prop_atom, XA_STRING, 8, PropModeReplace,
8827 XSTRING (value)->data, XSTRING (value)->size);
8828
8829 /* Make sure the property is set when we return. */
8830 XFlush (FRAME_W32_DISPLAY (f));
8831 UNBLOCK_INPUT;
8832
8833#endif /* MAC_TODO */
8834
8835 return value;
8836}
8837
8838
8839DEFUN ("x-delete-window-property", Fx_delete_window_property,
8840 Sx_delete_window_property, 1, 2, 0,
8841 "Remove window property PROP from X window of FRAME.\n\
8842FRAME nil or omitted means use the selected frame. Value is PROP.")
8843 (prop, frame)
8844 Lisp_Object prop, frame;
8845{
8846#if 0 /* MAC_TODO : port window properties to Mac */
8847
8848 struct frame *f = check_x_frame (frame);
8849 Atom prop_atom;
8850
8851 CHECK_STRING (prop, 1);
8852 BLOCK_INPUT;
8853 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
8854 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
8855
8856 /* Make sure the property is removed when we return. */
8857 XFlush (FRAME_W32_DISPLAY (f));
8858 UNBLOCK_INPUT;
8859#endif /* MAC_TODO */
8860
8861 return prop;
8862}
8863
8864
8865DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
8866 1, 2, 0,
8867 "Value is the value of window property PROP on FRAME.\n\
8868If FRAME is nil or omitted, use the selected frame. Value is nil\n\
8869if FRAME hasn't a property with name PROP or if PROP has no string\n\
8870value.")
8871 (prop, frame)
8872 Lisp_Object prop, frame;
8873{
8874#if 0 /* MAC_TODO : port window properties to Mac */
8875
8876 struct frame *f = check_x_frame (frame);
8877 Atom prop_atom;
8878 int rc;
8879 Lisp_Object prop_value = Qnil;
8880 char *tmp_data = NULL;
8881 Atom actual_type;
8882 int actual_format;
8883 unsigned long actual_size, bytes_remaining;
8884
8885 CHECK_STRING (prop, 1);
8886 BLOCK_INPUT;
8887 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
8888 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8889 prop_atom, 0, 0, False, XA_STRING,
8890 &actual_type, &actual_format, &actual_size,
8891 &bytes_remaining, (unsigned char **) &tmp_data);
8892 if (rc == Success)
8893 {
8894 int size = bytes_remaining;
8895
8896 XFree (tmp_data);
8897 tmp_data = NULL;
8898
8899 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8900 prop_atom, 0, bytes_remaining,
8901 False, XA_STRING,
8902 &actual_type, &actual_format,
8903 &actual_size, &bytes_remaining,
8904 (unsigned char **) &tmp_data);
8905 if (rc == Success)
8906 prop_value = make_string (tmp_data, size);
8907
8908 XFree (tmp_data);
8909 }
8910
8911 UNBLOCK_INPUT;
8912
8913 return prop_value;
8914
8915#endif /* MAC_TODO */
8916 return Qnil;
8917}
8918
8919
8920
8921/***********************************************************************
8922 Busy cursor
8923 ***********************************************************************/
8924
8925/* If non-null, an asynchronous timer that, when it expires, displays
8926 an hourglass cursor on all frames. */
8927
8928static struct atimer *hourglass_atimer;
8929
8930/* Non-zero means an hourglass cursor is currently shown. */
8931
8932static int hourglass_shown_p;
8933
8934/* Number of seconds to wait before displaying an hourglass cursor. */
8935
8936static Lisp_Object Vhourglass_delay;
8937
8938/* Default number of seconds to wait before displaying an hourglass
8939 cursor. */
8940
8941#define DEFAULT_HOURGLASS_DELAY 1
8942
8943/* Function prototypes. */
8944
8945static void show_hourglass P_ ((struct atimer *));
8946static void hide_hourglass P_ ((void));
8947
8948
8949/* Cancel a currently active hourglass timer, and start a new one. */
8950
8951void
8952start_hourglass ()
8953{
8954#if 0 /* TODO: cursor shape changes. */
8955 EMACS_TIME delay;
8956 int secs, usecs = 0;
8957
8958 cancel_hourglass ();
8959
8960 if (INTEGERP (Vhourglass_delay)
8961 && XINT (Vhourglass_delay) > 0)
8962 secs = XFASTINT (Vhourglass_delay);
8963 else if (FLOATP (Vhourglass_delay)
8964 && XFLOAT_DATA (Vhourglass_delay) > 0)
8965 {
8966 Lisp_Object tem;
8967 tem = Ftruncate (Vhourglass_delay, Qnil);
8968 secs = XFASTINT (tem);
8969 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
8970 }
8971 else
8972 secs = DEFAULT_HOURGLASS_DELAY;
8973
8974 EMACS_SET_SECS_USECS (delay, secs, usecs);
8975 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
8976 show_hourglass, NULL);
8977#endif
8978}
8979
8980
8981/* Cancel the hourglass cursor timer if active, hide an hourglass
8982 cursor if shown. */
8983
8984void
8985cancel_hourglass ()
8986{
8987 if (hourglass_atimer)
8988 {
8989 cancel_atimer (hourglass_atimer);
8990 hourglass_atimer = NULL;
8991 }
8992
8993 if (hourglass_shown_p)
8994 hide_hourglass ();
8995}
8996
8997
8998/* Timer function of hourglass_atimer. TIMER is equal to
8999 hourglass_atimer.
9000
9001 Display an hourglass cursor on all frames by mapping the frames'
9002 hourglass_window. Set the hourglass_p flag in the frames'
9003 output_data.x structure to indicate that an hourglass cursor is
9004 shown on the frames. */
9005
9006static void
9007show_hourglass (timer)
9008 struct atimer *timer;
9009{
9010#if 0 /* MAC_TODO: cursor shape changes. */
9011 /* The timer implementation will cancel this timer automatically
9012 after this function has run. Set hourglass_atimer to null
9013 so that we know the timer doesn't have to be canceled. */
9014 hourglass_atimer = NULL;
9015
9016 if (!hourglass_shown_p)
9017 {
9018 Lisp_Object rest, frame;
9019
9020 BLOCK_INPUT;
9021
9022 FOR_EACH_FRAME (rest, frame)
9023 if (FRAME_W32_P (XFRAME (frame)))
9024 {
9025 struct frame *f = XFRAME (frame);
9026
9027 f->output_data.w32->hourglass_p = 1;
9028
9029 if (!f->output_data.w32->hourglass_window)
9030 {
9031 unsigned long mask = CWCursor;
9032 XSetWindowAttributes attrs;
9033
9034 attrs.cursor = f->output_data.w32->hourglass_cursor;
9035
9036 f->output_data.w32->hourglass_window
9037 = XCreateWindow (FRAME_X_DISPLAY (f),
9038 FRAME_OUTER_WINDOW (f),
9039 0, 0, 32000, 32000, 0, 0,
9040 InputOnly,
9041 CopyFromParent,
9042 mask, &attrs);
9043 }
9044
9045 XMapRaised (FRAME_X_DISPLAY (f),
9046 f->output_data.w32->hourglass_window);
9047 XFlush (FRAME_X_DISPLAY (f));
9048 }
9049
9050 hourglass_shown_p = 1;
9051 UNBLOCK_INPUT;
9052 }
9053#endif
9054}
9055
9056
9057/* Hide the hourglass cursor on all frames, if it is currently shown. */
9058
9059static void
9060hide_hourglass ()
9061{
9062#if 0 /* TODO: cursor shape changes. */
9063 if (hourglass_shown_p)
9064 {
9065 Lisp_Object rest, frame;
9066
9067 BLOCK_INPUT;
9068 FOR_EACH_FRAME (rest, frame)
9069 {
9070 struct frame *f = XFRAME (frame);
9071
9072 if (FRAME_W32_P (f)
9073 /* Watch out for newly created frames. */
9074 && f->output_data.x->hourglass_window)
9075 {
9076 XUnmapWindow (FRAME_X_DISPLAY (f),
9077 f->output_data.x->hourglass_window);
9078 /* Sync here because XTread_socket looks at the
9079 hourglass_p flag that is reset to zero below. */
9080 XSync (FRAME_X_DISPLAY (f), False);
9081 f->output_data.x->hourglass_p = 0;
9082 }
9083 }
9084
9085 hourglass_shown_p = 0;
9086 UNBLOCK_INPUT;
9087 }
9088#endif
9089}
9090
9091
9092
9093/***********************************************************************
9094 Tool tips
9095 ***********************************************************************/
9096
9097static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
9098 Lisp_Object));
9099
9100/* The frame of a currently visible tooltip, or null. */
9101
9102Lisp_Object tip_frame;
9103
9104/* If non-nil, a timer started that hides the last tooltip when it
9105 fires. */
9106
9107Lisp_Object tip_timer;
9108Window tip_window;
9109
9110/* Create a frame for a tooltip on the display described by DPYINFO.
9111 PARMS is a list of frame parameters. Value is the frame. */
9112
9113static Lisp_Object
9114x_create_tip_frame (dpyinfo, parms)
9115 struct w32_display_info *dpyinfo;
9116 Lisp_Object parms;
9117{
9118#if 0 /* MAC_TODO : Mac version */
9119 struct frame *f;
9120 Lisp_Object frame, tem;
9121 Lisp_Object name;
9122 long window_prompting = 0;
9123 int width, height;
9124 int count = specpdl_ptr - specpdl;
9125 struct gcpro gcpro1, gcpro2, gcpro3;
9126 struct kboard *kb;
9127
9128 check_x ();
9129
9130 /* Use this general default value to start with until we know if
9131 this frame has a specified name. */
9132 Vx_resource_name = Vinvocation_name;
9133
9134#ifdef MULTI_KBOARD
9135 kb = dpyinfo->kboard;
9136#else
9137 kb = &the_only_kboard;
9138#endif
9139
9140 /* Get the name of the frame to use for resource lookup. */
9141 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
9142 if (!STRINGP (name)
9143 && !EQ (name, Qunbound)
9144 && !NILP (name))
9145 error ("Invalid frame name--not a string or nil");
9146 Vx_resource_name = name;
9147
9148 frame = Qnil;
9149 GCPRO3 (parms, name, frame);
9150 tip_frame = f = make_frame (1);
9151 XSETFRAME (frame, f);
9152 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
9153
9154 f->output_method = output_w32;
9155 f->output_data.w32 =
9156 (struct w32_output *) xmalloc (sizeof (struct w32_output));
9157 bzero (f->output_data.w32, sizeof (struct w32_output));
9158#if 0
9159 f->output_data.w32->icon_bitmap = -1;
9160#endif
9161 f->output_data.w32->fontset = -1;
9162 f->icon_name = Qnil;
9163
9164#ifdef MULTI_KBOARD
9165 FRAME_KBOARD (f) = kb;
9166#endif
9167 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9168 f->output_data.w32->explicit_parent = 0;
9169
9170 /* Set the name; the functions to which we pass f expect the name to
9171 be set. */
9172 if (EQ (name, Qunbound) || NILP (name))
9173 {
9174 f->name = build_string (dpyinfo->x_id_name);
9175 f->explicit_name = 0;
9176 }
9177 else
9178 {
9179 f->name = name;
9180 f->explicit_name = 1;
9181 /* use the frame's title when getting resources for this frame. */
9182 specbind (Qx_resource_name, name);
9183 }
9184
9185 /* Extract the window parameters from the supplied values
9186 that are needed to determine window geometry. */
9187 {
9188 Lisp_Object font;
9189
9190 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
9191
9192 BLOCK_INPUT;
9193 /* First, try whatever font the caller has specified. */
9194 if (STRINGP (font))
9195 {
9196 tem = Fquery_fontset (font, Qnil);
9197 if (STRINGP (tem))
9198 font = x_new_fontset (f, XSTRING (tem)->data);
9199 else
9200 font = x_new_font (f, XSTRING (font)->data);
9201 }
9202
9203 /* Try out a font which we hope has bold and italic variations. */
9204 if (!STRINGP (font))
9205 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
9206 if (!STRINGP (font))
9207 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9208 if (! STRINGP (font))
9209 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9210 if (! STRINGP (font))
9211 /* This was formerly the first thing tried, but it finds too many fonts
9212 and takes too long. */
9213 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
9214 /* If those didn't work, look for something which will at least work. */
9215 if (! STRINGP (font))
9216 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
9217 UNBLOCK_INPUT;
9218 if (! STRINGP (font))
9219 font = build_string ("fixed");
9220
9221 x_default_parameter (f, parms, Qfont, font,
9222 "font", "Font", RES_TYPE_STRING);
9223 }
9224
9225 x_default_parameter (f, parms, Qborder_width, make_number (2),
9226 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
9227
9228 /* This defaults to 2 in order to match xterm. We recognize either
9229 internalBorderWidth or internalBorder (which is what xterm calls
9230 it). */
9231 if (NILP (Fassq (Qinternal_border_width, parms)))
9232 {
9233 Lisp_Object value;
9234
9235 value = w32_get_arg (parms, Qinternal_border_width,
9236 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
9237 if (! EQ (value, Qunbound))
9238 parms = Fcons (Fcons (Qinternal_border_width, value),
9239 parms);
9240 }
9241
9242 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
9243 "internalBorderWidth", "internalBorderWidth",
9244 RES_TYPE_NUMBER);
9245
9246 /* Also do the stuff which must be set before the window exists. */
9247 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
9248 "foreground", "Foreground", RES_TYPE_STRING);
9249 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
9250 "background", "Background", RES_TYPE_STRING);
9251 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
9252 "pointerColor", "Foreground", RES_TYPE_STRING);
9253 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
9254 "cursorColor", "Foreground", RES_TYPE_STRING);
9255 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
9256 "borderColor", "BorderColor", RES_TYPE_STRING);
9257
9258 /* Init faces before x_default_parameter is called for scroll-bar
9259 parameters because that function calls x_set_scroll_bar_width,
9260 which calls change_frame_size, which calls Fset_window_buffer,
9261 which runs hooks, which call Fvertical_motion. At the end, we
9262 end up in init_iterator with a null face cache, which should not
9263 happen. */
9264 init_frame_faces (f);
9265
9266 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9267 window_prompting = x_figure_window_size (f, parms);
9268
9269 if (window_prompting & XNegative)
9270 {
9271 if (window_prompting & YNegative)
9272 f->output_data.w32->win_gravity = SouthEastGravity;
9273 else
9274 f->output_data.w32->win_gravity = NorthEastGravity;
9275 }
9276 else
9277 {
9278 if (window_prompting & YNegative)
9279 f->output_data.w32->win_gravity = SouthWestGravity;
9280 else
9281 f->output_data.w32->win_gravity = NorthWestGravity;
9282 }
9283
9284 f->output_data.w32->size_hint_flags = window_prompting;
9285 {
9286 XSetWindowAttributes attrs;
9287 unsigned long mask;
9288
9289 BLOCK_INPUT;
9290 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
9291 /* Window managers looks at the override-redirect flag to
9292 determine whether or net to give windows a decoration (Xlib
9293 3.2.8). */
9294 attrs.override_redirect = True;
9295 attrs.save_under = True;
9296 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
9297 /* Arrange for getting MapNotify and UnmapNotify events. */
9298 attrs.event_mask = StructureNotifyMask;
9299 tip_window
9300 = FRAME_W32_WINDOW (f)
9301 = XCreateWindow (FRAME_W32_DISPLAY (f),
9302 FRAME_W32_DISPLAY_INFO (f)->root_window,
9303 /* x, y, width, height */
9304 0, 0, 1, 1,
9305 /* Border. */
9306 1,
9307 CopyFromParent, InputOutput, CopyFromParent,
9308 mask, &attrs);
9309 UNBLOCK_INPUT;
9310 }
9311
9312 x_make_gc (f);
9313
9314 x_default_parameter (f, parms, Qauto_raise, Qnil,
9315 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9316 x_default_parameter (f, parms, Qauto_lower, Qnil,
9317 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9318 x_default_parameter (f, parms, Qcursor_type, Qbox,
9319 "cursorType", "CursorType", RES_TYPE_SYMBOL);
9320
9321 /* Dimensions, especially f->height, must be done via change_frame_size.
9322 Change will not be effected unless different from the current
9323 f->height. */
9324 width = f->width;
9325 height = f->height;
9326 f->height = 0;
9327 SET_FRAME_WIDTH (f, 0);
9328 change_frame_size (f, height, width, 1, 0, 0);
9329
9330 f->no_split = 1;
9331
9332 UNGCPRO;
9333
9334 /* It is now ok to make the frame official even if we get an error
9335 below. And the frame needs to be on Vframe_list or making it
9336 visible won't work. */
9337 Vframe_list = Fcons (frame, Vframe_list);
9338
9339 /* Now that the frame is official, it counts as a reference to
9340 its display. */
9341 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
9342
9343 return unbind_to (count, frame);
9344#endif /* MAC_TODO */
9345 return Qnil;
9346}
9347
9348#ifdef TODO /* Tooltip support not complete. */
9349DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
9350 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
9351A tooltip window is a small window displaying a string.\n\
9352\n\
9353FRAME nil or omitted means use the selected frame.\n\
9354\n\
9355PARMS is an optional list of frame parameters which can be\n\
9356used to change the tooltip's appearance.\n\
9357\n\
9358Automatically hide the tooltip after TIMEOUT seconds.\n\
9359TIMEOUT nil means use the default timeout of 5 seconds.\n\
9360\n\
9361If the list of frame parameters PARAMS contains a `left' parameters,\n\
9362the tooltip is displayed at that x-position. Otherwise it is\n\
9363displayed at the mouse position, with offset DX added (default is 5 if\n\
9364DX isn't specified). Likewise for the y-position; if a `top' frame\n\
9365parameter is specified, it determines the y-position of the tooltip\n\
9366window, otherwise it is displayed at the mouse position, with offset\n\
9367DY added (default is 10).")
9368 (string, frame, parms, timeout, dx, dy)
9369 Lisp_Object string, frame, parms, timeout, dx, dy;
9370{
9371 struct frame *f;
9372 struct window *w;
9373 Window root, child;
9374 Lisp_Object buffer, top, left;
9375 struct buffer *old_buffer;
9376 struct text_pos pos;
9377 int i, width, height;
9378 int root_x, root_y, win_x, win_y;
9379 unsigned pmask;
9380 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
9381 int old_windows_or_buffers_changed = windows_or_buffers_changed;
9382 int count = specpdl_ptr - specpdl;
9383
9384 specbind (Qinhibit_redisplay, Qt);
9385
9386 GCPRO4 (string, parms, frame, timeout);
9387
9388 CHECK_STRING (string, 0);
9389 f = check_x_frame (frame);
9390 if (NILP (timeout))
9391 timeout = make_number (5);
9392 else
9393 CHECK_NATNUM (timeout, 2);
9394
9395 if (NILP (dx))
9396 dx = make_number (5);
9397 else
9398 CHECK_NUMBER (dx, 5);
9399
9400 if (NILP (dy))
9401 dy = make_number (-10);
9402 else
9403 CHECK_NUMBER (dy, 6);
9404
9405 if (NILP (last_show_tip_args))
9406 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
9407
9408 if (!NILP (tip_frame))
9409 {
9410 Lisp_Object last_string = AREF (last_show_tip_args, 0);
9411 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
9412 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
9413
9414 if (EQ (frame, last_frame)
9415 && !NILP (Fequal (last_string, string))
9416 && !NILP (Fequal (last_parms, parms)))
9417 {
9418 struct frame *f = XFRAME (tip_frame);
9419
9420 /* Only DX and DY have changed. */
9421 if (!NILP (tip_timer))
9422 {
9423 Lisp_Object timer = tip_timer;
9424 tip_timer = Qnil;
9425 call1 (Qcancel_timer, timer);
9426 }
9427
9428 BLOCK_INPUT;
9429 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
9430 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9431 root_x, root_y - PIXEL_HEIGHT (f));
9432 UNBLOCK_INPUT;
9433 goto start_timer;
9434 }
9435 }
9436
9437 /* Hide a previous tip, if any. */
9438 Fx_hide_tip ();
9439
9440 ASET (last_show_tip_args, 0, string);
9441 ASET (last_show_tip_args, 1, frame);
9442 ASET (last_show_tip_args, 2, parms);
9443
9444 /* Add default values to frame parameters. */
9445 if (NILP (Fassq (Qname, parms)))
9446 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
9447 if (NILP (Fassq (Qinternal_border_width, parms)))
9448 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
9449 if (NILP (Fassq (Qborder_width, parms)))
9450 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
9451 if (NILP (Fassq (Qborder_color, parms)))
9452 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
9453 if (NILP (Fassq (Qbackground_color, parms)))
9454 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
9455 parms);
9456
9457 /* Create a frame for the tooltip, and record it in the global
9458 variable tip_frame. */
9459 frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms);
9460 f = XFRAME (frame);
9461
9462 /* Set up the frame's root window. Currently we use a size of 80
9463 columns x 40 lines. If someone wants to show a larger tip, he
9464 will loose. I don't think this is a realistic case. */
9465 w = XWINDOW (FRAME_ROOT_WINDOW (f));
9466 w->left = w->top = make_number (0);
9467 w->width = make_number (80);
9468 w->height = make_number (40);
9469 adjust_glyphs (f);
9470 w->pseudo_window_p = 1;
9471
9472 /* Display the tooltip text in a temporary buffer. */
9473 buffer = Fget_buffer_create (build_string (" *tip*"));
9474 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
9475 old_buffer = current_buffer;
9476 set_buffer_internal_1 (XBUFFER (buffer));
9477 Ferase_buffer ();
9478 Finsert (1, &string);
9479 clear_glyph_matrix (w->desired_matrix);
9480 clear_glyph_matrix (w->current_matrix);
9481 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
9482 try_window (FRAME_ROOT_WINDOW (f), pos);
9483
9484 /* Compute width and height of the tooltip. */
9485 width = height = 0;
9486 for (i = 0; i < w->desired_matrix->nrows; ++i)
9487 {
9488 struct glyph_row *row = &w->desired_matrix->rows[i];
9489 struct glyph *last;
9490 int row_width;
9491
9492 /* Stop at the first empty row at the end. */
9493 if (!row->enabled_p || !row->displays_text_p)
9494 break;
9495
9496 /* Let the row go over the full width of the frame. */
9497 row->full_width_p = 1;
9498
9499 /* There's a glyph at the end of rows that is use to place
9500 the cursor there. Don't include the width of this glyph. */
9501 if (row->used[TEXT_AREA])
9502 {
9503 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
9504 row_width = row->pixel_width - last->pixel_width;
9505 }
9506 else
9507 row_width = row->pixel_width;
9508
9509 height += row->height;
9510 width = max (width, row_width);
9511 }
9512
9513 /* Add the frame's internal border to the width and height the X
9514 window should have. */
9515 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9516 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9517
9518 /* Move the tooltip window where the mouse pointer is. Resize and
9519 show it. */
9520 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
9521
9522#if 0 /* TODO : Mac specifics */
9523 BLOCK_INPUT;
9524 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9525 root_x, root_y - height, width, height);
9526 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
9527 UNBLOCK_INPUT;
9528#endif /* TODO */
9529
9530 /* Draw into the window. */
9531 w->must_be_updated_p = 1;
9532 update_single_window (w, 1);
9533
9534 /* Restore original current buffer. */
9535 set_buffer_internal_1 (old_buffer);
9536 windows_or_buffers_changed = old_windows_or_buffers_changed;
9537
9538 start_timer:
9539 /* Let the tip disappear after timeout seconds. */
9540 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
9541 intern ("x-hide-tip"));
9542
9543 UNGCPRO;
9544 return unbind_to (count, Qnil);
9545}
9546
9547
9548DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
9549 "Hide the current tooltip window, if there is any.\n\
9550Value is t is tooltip was open, nil otherwise.")
9551 ()
9552{
9553 int count;
9554 Lisp_Object deleted, frame, timer;
9555 struct gcpro gcpro1, gcpro2;
9556
9557 /* Return quickly if nothing to do. */
9558 if (NILP (tip_timer) && NILP (tip_frame))
9559 return Qnil;
9560
9561 frame = tip_frame;
9562 timer = tip_timer;
9563 GCPRO2 (frame, timer);
9564 tip_frame = tip_timer = deleted = Qnil;
9565
9566 count = BINDING_STACK_SIZE ();
9567 specbind (Qinhibit_redisplay, Qt);
9568 specbind (Qinhibit_quit, Qt);
9569
9570 if (!NILP (timer))
9571 call1 (Qcancel_timer, timer);
9572
9573 if (FRAMEP (frame))
9574 {
9575 Fdelete_frame (frame, Qnil);
9576 deleted = Qt;
9577 }
9578
9579 UNGCPRO;
9580 return unbind_to (count, deleted);
9581}
9582#endif
9583
9584
9585
9586/***********************************************************************
9587 File selection dialog
9588 ***********************************************************************/
9589
9590#if 0 /* MAC_TODO: can standard file dialog */
9591extern Lisp_Object Qfile_name_history;
9592
9593DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
9594 "Read file name, prompting with PROMPT in directory DIR.\n\
9595Use a file selection dialog.\n\
9596Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
9597specified. Don't let the user enter a file name in the file\n\
9598selection dialog's entry field, if MUSTMATCH is non-nil.")
9599 (prompt, dir, default_filename, mustmatch)
9600 Lisp_Object prompt, dir, default_filename, mustmatch;
9601{
9602 struct frame *f = SELECTED_FRAME ();
9603 Lisp_Object file = Qnil;
9604 int count = specpdl_ptr - specpdl;
9605 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
9606 char filename[MAX_PATH + 1];
9607 char init_dir[MAX_PATH + 1];
9608 int use_dialog_p = 1;
9609
9610 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
9611 CHECK_STRING (prompt, 0);
9612 CHECK_STRING (dir, 1);
9613
9614 /* Create the dialog with PROMPT as title, using DIR as initial
9615 directory and using "*" as pattern. */
9616 dir = Fexpand_file_name (dir, Qnil);
9617 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
9618 init_dir[MAX_PATH] = '\0';
9619 unixtodos_filename (init_dir);
9620
9621 if (STRINGP (default_filename))
9622 {
9623 char *file_name_only;
9624 char *full_path_name = XSTRING (default_filename)->data;
9625
9626 unixtodos_filename (full_path_name);
9627
9628 file_name_only = strrchr (full_path_name, '\\');
9629 if (!file_name_only)
9630 file_name_only = full_path_name;
9631 else
9632 {
9633 file_name_only++;
9634
9635 /* If default_file_name is a directory, don't use the open
9636 file dialog, as it does not support selecting
9637 directories. */
9638 if (!(*file_name_only))
9639 use_dialog_p = 0;
9640 }
9641
9642 strncpy (filename, file_name_only, MAX_PATH);
9643 filename[MAX_PATH] = '\0';
9644 }
9645 else
9646 filename[0] = '\0';
9647
9648 if (use_dialog_p)
9649 {
9650 OPENFILENAME file_details;
9651 char *filename_file;
9652
9653 /* Prevent redisplay. */
9654 specbind (Qinhibit_redisplay, Qt);
9655 BLOCK_INPUT;
9656
9657 bzero (&file_details, sizeof (file_details));
9658 file_details.lStructSize = sizeof (file_details);
9659 file_details.hwndOwner = FRAME_W32_WINDOW (f);
9660 file_details.lpstrFile = filename;
9661 file_details.nMaxFile = sizeof (filename);
9662 file_details.lpstrInitialDir = init_dir;
9663 file_details.lpstrTitle = XSTRING (prompt)->data;
9664 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
9665
9666 if (!NILP (mustmatch))
9667 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
9668
9669 if (GetOpenFileName (&file_details))
9670 {
9671 dostounix_filename (filename);
9672 file = build_string (filename);
9673 }
9674 else
9675 file = Qnil;
9676
9677 UNBLOCK_INPUT;
9678 file = unbind_to (count, file);
9679 }
9680 /* Open File dialog will not allow folders to be selected, so resort
9681 to minibuffer completing reads for directories. */
9682 else
9683 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
9684 dir, mustmatch, dir, Qfile_name_history,
9685 default_filename, Qnil);
9686
9687 UNGCPRO;
9688
9689 /* Make "Cancel" equivalent to C-g. */
9690 if (NILP (file))
9691 Fsignal (Qquit, Qnil);
9692
9693 return unbind_to (count, file);
9694}
9695#endif
9696
9697
9698
9699/***********************************************************************
9700 Tests
9701 ***********************************************************************/
9702
9703#if GLYPH_DEBUG
9704
9705DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
9706 "Value is non-nil if SPEC is a valid image specification.")
9707 (spec)
9708 Lisp_Object spec;
9709{
9710 return valid_image_p (spec) ? Qt : Qnil;
9711}
9712
9713
9714DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
9715 (spec)
9716 Lisp_Object spec;
9717{
9718 int id = -1;
9719
9720 if (valid_image_p (spec))
9721 id = lookup_image (SELECTED_FRAME (), spec);
9722
9723 debug_print (spec);
9724 return make_number (id);
9725}
9726
9727#endif /* GLYPH_DEBUG != 0 */
9728
9729
9730
9731void
9732syms_of_macfns ()
9733{
9734 /* Certainly running on Mac. */
9735 mac_in_use = 1;
9736
9737 /* The section below is built by the lisp expression at the top of the file,
9738 just above where these variables are declared. */
9739 /*&&& init symbols here &&&*/
9740 Qauto_raise = intern ("auto-raise");
9741 staticpro (&Qauto_raise);
9742 Qauto_lower = intern ("auto-lower");
9743 staticpro (&Qauto_lower);
9744 Qbar = intern ("bar");
9745 staticpro (&Qbar);
9746 Qborder_color = intern ("border-color");
9747 staticpro (&Qborder_color);
9748 Qborder_width = intern ("border-width");
9749 staticpro (&Qborder_width);
9750 Qbox = intern ("box");
9751 staticpro (&Qbox);
9752 Qcursor_color = intern ("cursor-color");
9753 staticpro (&Qcursor_color);
9754 Qcursor_type = intern ("cursor-type");
9755 staticpro (&Qcursor_type);
9756 Qgeometry = intern ("geometry");
9757 staticpro (&Qgeometry);
9758 Qicon_left = intern ("icon-left");
9759 staticpro (&Qicon_left);
9760 Qicon_top = intern ("icon-top");
9761 staticpro (&Qicon_top);
9762 Qicon_type = intern ("icon-type");
9763 staticpro (&Qicon_type);
9764 Qicon_name = intern ("icon-name");
9765 staticpro (&Qicon_name);
9766 Qinternal_border_width = intern ("internal-border-width");
9767 staticpro (&Qinternal_border_width);
9768 Qleft = intern ("left");
9769 staticpro (&Qleft);
9770 Qright = intern ("right");
9771 staticpro (&Qright);
9772 Qmouse_color = intern ("mouse-color");
9773 staticpro (&Qmouse_color);
9774 Qnone = intern ("none");
9775 staticpro (&Qnone);
9776 Qparent_id = intern ("parent-id");
9777 staticpro (&Qparent_id);
9778 Qscroll_bar_width = intern ("scroll-bar-width");
9779 staticpro (&Qscroll_bar_width);
9780 Qsuppress_icon = intern ("suppress-icon");
9781 staticpro (&Qsuppress_icon);
9782 Qundefined_color = intern ("undefined-color");
9783 staticpro (&Qundefined_color);
9784 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
9785 staticpro (&Qvertical_scroll_bars);
9786 Qvisibility = intern ("visibility");
9787 staticpro (&Qvisibility);
9788 Qwindow_id = intern ("window-id");
9789 staticpro (&Qwindow_id);
9790 Qx_frame_parameter = intern ("x-frame-parameter");
9791 staticpro (&Qx_frame_parameter);
9792 Qx_resource_name = intern ("x-resource-name");
9793 staticpro (&Qx_resource_name);
9794 Quser_position = intern ("user-position");
9795 staticpro (&Quser_position);
9796 Quser_size = intern ("user-size");
9797 staticpro (&Quser_size);
9798 Qscreen_gamma = intern ("screen-gamma");
9799 staticpro (&Qscreen_gamma);
9800 Qline_spacing = intern ("line-spacing");
9801 staticpro (&Qline_spacing);
9802 Qcenter = intern ("center");
9803 staticpro (&Qcenter);
9804 Qcancel_timer = intern ("cancel-timer");
9805 staticpro (&Qcancel_timer);
9806 /* This is the end of symbol initialization. */
9807
9808 Qhyper = intern ("hyper");
9809 staticpro (&Qhyper);
9810 Qsuper = intern ("super");
9811 staticpro (&Qsuper);
9812 Qmeta = intern ("meta");
9813 staticpro (&Qmeta);
9814 Qalt = intern ("alt");
9815 staticpro (&Qalt);
9816 Qctrl = intern ("ctrl");
9817 staticpro (&Qctrl);
9818 Qcontrol = intern ("control");
9819 staticpro (&Qcontrol);
9820 Qshift = intern ("shift");
9821 staticpro (&Qshift);
9822
9823 /* Text property `display' should be nonsticky by default. */
9824 Vtext_property_default_nonsticky
9825 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
9826
9827
9828 Qlaplace = intern ("laplace");
9829 staticpro (&Qlaplace);
9830
9831 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
9832 staticpro (&Qface_set_after_frame_default);
9833
9834 Fput (Qundefined_color, Qerror_conditions,
9835 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
9836 Fput (Qundefined_color, Qerror_message,
9837 build_string ("Undefined color"));
9838
9839 init_x_parm_symbols ();
9840
9841 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
9842 "List of directories to search for bitmap files for w32.");
9843 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
9844
9845 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
9846 "The shape of the pointer when over text.\n\
9847Changing the value does not affect existing frames\n\
9848unless you set the mouse color.");
9849 Vx_pointer_shape = Qnil;
9850
9851 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
9852 "The name Emacs uses to look up resources; for internal use only.\n\
9853`x-get-resource' uses this as the first component of the instance name\n\
9854when requesting resource values.\n\
9855Emacs initially sets `x-resource-name' to the name under which Emacs\n\
9856was invoked, or to the value specified with the `-name' or `-rn'\n\
9857switches, if present.");
9858 Vx_resource_name = Qnil;
9859
9860 Vx_nontext_pointer_shape = Qnil;
9861
9862 Vx_mode_pointer_shape = Qnil;
9863
9864 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
9865 "The shape of the pointer when Emacs is busy.\n\
9866This variable takes effect when you create a new frame\n\
9867or when you set the mouse color.");
9868 Vx_hourglass_pointer_shape = Qnil;
9869
9870 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
9871 "Non-zero means Emacs displays an hourglass pointer on window systems.");
9872 display_hourglass_p = 1;
9873
9874 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
9875 "*Seconds to wait before displaying an hourglass pointer.\n\
9876Value must be an integer or float.");
9877 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
9878
9879 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
9880 &Vx_sensitive_text_pointer_shape,
9881 "The shape of the pointer when over mouse-sensitive text.\n\
9882This variable takes effect when you create a new frame\n\
9883or when you set the mouse color.");
9884 Vx_sensitive_text_pointer_shape = Qnil;
9885
9886 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
9887 "A string indicating the foreground color of the cursor box.");
9888 Vx_cursor_fore_pixel = Qnil;
9889
9890 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
9891 "Non-nil if no window manager is in use.\n\
9892Emacs doesn't try to figure this out; this is always nil\n\
9893unless you set it to something else.");
9894 /* We don't have any way to find this out, so set it to nil
9895 and maybe the user would like to set it to t. */
9896 Vx_no_window_manager = Qnil;
9897
9898 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
9899 &Vx_pixel_size_width_font_regexp,
9900 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
9901\n\
9902Since Emacs gets width of a font matching with this regexp from\n\
9903PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
9904such a font. This is especially effective for such large fonts as\n\
9905Chinese, Japanese, and Korean.");
9906 Vx_pixel_size_width_font_regexp = Qnil;
9907
9908 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
9909 "Time after which cached images are removed from the cache.\n\
9910When an image has not been displayed this many seconds, remove it\n\
9911from the image cache. Value must be an integer or nil with nil\n\
9912meaning don't clear the cache.");
9913 Vimage_cache_eviction_delay = make_number (30 * 60);
9914
9915#if 0 /* MAC_TODO: implement get X resource */
9916 defsubr (&Sx_get_resource);
9917#endif
9918 defsubr (&Sx_change_window_property);
9919 defsubr (&Sx_delete_window_property);
9920 defsubr (&Sx_window_property);
9921 defsubr (&Sxw_display_color_p);
9922 defsubr (&Sx_display_grayscale_p);
9923 defsubr (&Sxw_color_defined_p);
9924 defsubr (&Sxw_color_values);
9925 defsubr (&Sx_server_max_request_size);
9926 defsubr (&Sx_server_vendor);
9927 defsubr (&Sx_server_version);
9928 defsubr (&Sx_display_pixel_width);
9929 defsubr (&Sx_display_pixel_height);
9930 defsubr (&Sx_display_mm_width);
9931 defsubr (&Sx_display_mm_height);
9932 defsubr (&Sx_display_screens);
9933 defsubr (&Sx_display_planes);
9934 defsubr (&Sx_display_color_cells);
9935 defsubr (&Sx_display_visual_class);
9936 defsubr (&Sx_display_backing_store);
9937 defsubr (&Sx_display_save_under);
9938#if 0 /* MAC_TODO: implement XParseGeometry */
9939 defsubr (&Sx_parse_geometry);
9940#endif
9941 defsubr (&Sx_create_frame);
9942#if 0 /* MAC_TODO: implement network support */
9943 defsubr (&Sx_open_connection);
9944 defsubr (&Sx_close_connection);
9945#endif
9946 defsubr (&Sx_display_list);
9947 defsubr (&Sx_synchronize);
9948
9949 /* Setting callback functions for fontset handler. */
9950 get_font_info_func = x_get_font_info;
9951
9952#if 0 /* This function pointer doesn't seem to be used anywhere.
9953 And the pointer assigned has the wrong type, anyway. */
9954 list_fonts_func = x_list_fonts;
9955#endif
9956
9957 load_font_func = x_load_font;
9958 find_ccl_program_func = x_find_ccl_program;
9959 query_font_func = x_query_font;
9960
9961 set_frame_fontset_func = x_set_font;
9962 check_window_system_func = check_mac;
9963
9964#if 0 /* MAC_TODO: Image support for Mac Images. */
9965 Qxbm = intern ("xbm");
9966 staticpro (&Qxbm);
9967 QCtype = intern (":type");
9968 staticpro (&QCtype);
9969 QCconversion = intern (":conversion");
9970 staticpro (&QCconversion);
9971 QCheuristic_mask = intern (":heuristic-mask");
9972 staticpro (&QCheuristic_mask);
9973 QCcolor_symbols = intern (":color-symbols");
9974 staticpro (&QCcolor_symbols);
9975 QCascent = intern (":ascent");
9976 staticpro (&QCascent);
9977 QCmargin = intern (":margin");
9978 staticpro (&QCmargin);
9979 QCrelief = intern (":relief");
9980 staticpro (&QCrelief);
9981 Qpostscript = intern ("postscript");
9982 staticpro (&Qpostscript);
9983 QCloader = intern (":loader");
9984 staticpro (&QCloader);
9985 QCbounding_box = intern (":bounding-box");
9986 staticpro (&QCbounding_box);
9987 QCpt_width = intern (":pt-width");
9988 staticpro (&QCpt_width);
9989 QCpt_height = intern (":pt-height");
9990 staticpro (&QCpt_height);
9991 QCindex = intern (":index");
9992 staticpro (&QCindex);
9993 Qpbm = intern ("pbm");
9994 staticpro (&Qpbm);
9995
9996#if HAVE_XPM
9997 Qxpm = intern ("xpm");
9998 staticpro (&Qxpm);
9999#endif
10000
10001#if HAVE_JPEG
10002 Qjpeg = intern ("jpeg");
10003 staticpro (&Qjpeg);
10004#endif
10005
10006#if HAVE_TIFF
10007 Qtiff = intern ("tiff");
10008 staticpro (&Qtiff);
10009#endif
10010
10011#if HAVE_GIF
10012 Qgif = intern ("gif");
10013 staticpro (&Qgif);
10014#endif
10015
10016#if HAVE_PNG
10017 Qpng = intern ("png");
10018 staticpro (&Qpng);
10019#endif
10020
10021 defsubr (&Sclear_image_cache);
10022
10023#if GLYPH_DEBUG
10024 defsubr (&Simagep);
10025 defsubr (&Slookup_image);
10026#endif
10027#endif /* TODO */
10028
10029 hourglass_atimer = NULL;
10030 hourglass_shown_p = 0;
10031#ifdef TODO /* Tooltip support not complete. */
10032 defsubr (&Sx_show_tip);
10033 defsubr (&Sx_hide_tip);
10034#endif
10035 tip_timer = Qnil;
10036 staticpro (&tip_timer);
10037 tip_frame = Qnil;
10038 staticpro (&tip_frame);
10039
10040#if 0 /* MAC_TODO */
10041 defsubr (&Sx_file_dialog);
10042#endif
10043}
10044
10045
10046void
10047init_xfns ()
10048{
10049 image_types = NULL;
10050 Vimage_types = Qnil;
10051
10052#if 0 /* TODO : Image support for W32 */
10053 define_image_type (&xbm_type);
10054 define_image_type (&gs_type);
10055 define_image_type (&pbm_type);
10056
10057#if HAVE_XPM
10058 define_image_type (&xpm_type);
10059#endif
10060
10061#if HAVE_JPEG
10062 define_image_type (&jpeg_type);
10063#endif
10064
10065#if HAVE_TIFF
10066 define_image_type (&tiff_type);
10067#endif
10068
10069#if HAVE_GIF
10070 define_image_type (&gif_type);
10071#endif
10072
10073#if HAVE_PNG
10074 define_image_type (&png_type);
10075#endif
10076#endif /* NTEMACS_TODO */
10077}
10078
10079#undef abort
10080
10081#if 0
10082void
10083w32_abort()
10084{
10085 int button;
10086 button = MessageBox (NULL,
10087 "A fatal error has occurred!\n\n"
10088 "Select Abort to exit, Retry to debug, Ignore to continue",
10089 "Emacs Abort Dialog",
10090 MB_ICONEXCLAMATION | MB_TASKMODAL
10091 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
10092 switch (button)
10093 {
10094 case IDRETRY:
10095 DebugBreak ();
10096 break;
10097 case IDIGNORE:
10098 break;
10099 case IDABORT:
10100 default:
10101 abort ();
10102 break;
10103 }
10104}
10105
10106/* For convenience when debugging. */
10107int
10108w32_last_error()
10109{
10110 return GetLastError ();
10111}
10112#endif
diff --git a/mac/src/macmenu.c b/mac/src/macmenu.c
deleted file mode 100644
index b7ed55adcec..00000000000
--- a/mac/src/macmenu.c
+++ /dev/null
@@ -1,2206 +0,0 @@
1/* Menu support for GNU Emacs on the for Mac OS.
2 Copyright (C) 2000 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */
22
23#include <config.h>
24#include <signal.h>
25
26#include <stdio.h>
27#include "lisp.h"
28#include "termhooks.h"
29#include "frame.h"
30#include "window.h"
31#include "keyboard.h"
32#include "blockinput.h"
33#include "buffer.h"
34#include "charset.h"
35#include "coding.h"
36#include "keymap.h"
37
38#include <MacTypes.h>
39#include <Menus.h>
40#include <QuickDraw.h>
41#include <ToolUtils.h>
42#include <Fonts.h>
43#include <Controls.h>
44#include <Windows.h>
45#include <Events.h>
46#if defined (__MRC__) || defined (CODEWARRIOR_VERSION_6)
47#include <ControlDefinitions.h>
48#endif
49
50/* This may include sys/types.h, and that somehow loses
51 if this is not done before the other system files. */
52#include "macterm.h"
53
54/* Load sys/types.h if not already loaded.
55 In some systems loading it twice is suicidal. */
56#ifndef makedev
57#include <sys/types.h>
58#endif
59
60#include "dispextern.h"
61
62#define POPUP_SUBMENU_ID 235
63#define MIN_MENU_ID 256
64#define MIN_SUBMENU_ID 1
65
66#define DIALOG_WINDOW_RESOURCE 130
67
68#define HAVE_DIALOGS 1
69
70#undef HAVE_MULTILINGUAL_MENU
71
72/******************************************************************/
73/* Definitions copied from lwlib.h */
74
75typedef void * XtPointer;
76
77#define True 1
78#define False 0
79
80enum button_type
81{
82 BUTTON_TYPE_NONE,
83 BUTTON_TYPE_TOGGLE,
84 BUTTON_TYPE_RADIO
85};
86
87typedef struct _widget_value
88{
89 /* name of widget */
90 char* name;
91 /* value (meaning depend on widget type) */
92 char* value;
93 /* keyboard equivalent. no implications for XtTranslations */
94 char* key;
95 /* Help string or null if none. */
96 char *help;
97 /* true if enabled */
98 Boolean enabled;
99 /* true if selected */
100 Boolean selected;
101 /* The type of a button. */
102 enum button_type button_type;
103 /* true if menu title */
104 Boolean title;
105#if 0
106 /* true if was edited (maintained by get_value) */
107 Boolean edited;
108 /* true if has changed (maintained by lw library) */
109 change_type change;
110 /* true if this widget itself has changed,
111 but not counting the other widgets found in the `next' field. */
112 change_type this_one_change;
113#endif
114 /* Contents of the sub-widgets, also selected slot for checkbox */
115 struct _widget_value* contents;
116 /* data passed to callback */
117 XtPointer call_data;
118 /* next one in the list */
119 struct _widget_value* next;
120#if 0
121 /* slot for the toolkit dependent part. Always initialize to NULL. */
122 void* toolkit_data;
123 /* tell us if we should free the toolkit data slot when freeing the
124 widget_value itself. */
125 Boolean free_toolkit_data;
126
127 /* we resource the widget_value structures; this points to the next
128 one on the free list if this one has been deallocated.
129 */
130 struct _widget_value *free_list;
131#endif
132} widget_value;
133
134/* Assumed by other routines to zero area returned. */
135#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
136 0, (sizeof (widget_value)))
137#define free_widget_value(wv) xfree (wv)
138
139/******************************************************************/
140
141#define min(x,y) (((x) < (y)) ? (x) : (y))
142#define max(x,y) (((x) > (y)) ? (x) : (y))
143
144#ifndef TRUE
145#define TRUE 1
146#define FALSE 0
147#endif /* no TRUE */
148
149Lisp_Object Vmenu_updating_frame;
150
151Lisp_Object Qdebug_on_next_call;
152
153extern Lisp_Object Qmenu_bar;
154extern Lisp_Object Qmouse_click, Qevent_kind;
155
156extern Lisp_Object QCtoggle, QCradio;
157
158extern Lisp_Object Voverriding_local_map;
159extern Lisp_Object Voverriding_local_map_menu_flag;
160
161extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
162
163extern Lisp_Object Qmenu_bar_update_hook;
164
165void set_frame_menubar ();
166
167static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
168 Lisp_Object, Lisp_Object, Lisp_Object,
169 Lisp_Object, Lisp_Object));
170static Lisp_Object mac_dialog_show ();
171static Lisp_Object mac_menu_show ();
172
173static void keymap_panes ();
174static void single_keymap_panes ();
175static void single_menu_item ();
176static void list_of_panes ();
177static void list_of_items ();
178
179static void fill_submenu (MenuHandle, widget_value *, int);
180static void fill_menubar (widget_value *);
181
182
183/* This holds a Lisp vector that holds the results of decoding
184 the keymaps or alist-of-alists that specify a menu.
185
186 It describes the panes and items within the panes.
187
188 Each pane is described by 3 elements in the vector:
189 t, the pane name, the pane's prefix key.
190 Then follow the pane's items, with 5 elements per item:
191 the item string, the enable flag, the item's value,
192 the definition, and the equivalent keyboard key's description string.
193
194 In some cases, multiple levels of menus may be described.
195 A single vector slot containing nil indicates the start of a submenu.
196 A single vector slot containing lambda indicates the end of a submenu.
197 The submenu follows a menu item which is the way to reach the submenu.
198
199 A single vector slot containing quote indicates that the
200 following items should appear on the right of a dialog box.
201
202 Using a Lisp vector to hold this information while we decode it
203 takes care of protecting all the data from GC. */
204
205#define MENU_ITEMS_PANE_NAME 1
206#define MENU_ITEMS_PANE_PREFIX 2
207#define MENU_ITEMS_PANE_LENGTH 3
208
209enum menu_item_idx
210{
211 MENU_ITEMS_ITEM_NAME = 0,
212 MENU_ITEMS_ITEM_ENABLE,
213 MENU_ITEMS_ITEM_VALUE,
214 MENU_ITEMS_ITEM_EQUIV_KEY,
215 MENU_ITEMS_ITEM_DEFINITION,
216 MENU_ITEMS_ITEM_TYPE,
217 MENU_ITEMS_ITEM_SELECTED,
218 MENU_ITEMS_ITEM_HELP,
219 MENU_ITEMS_ITEM_LENGTH
220};
221
222static Lisp_Object menu_items;
223
224/* Number of slots currently allocated in menu_items. */
225static int menu_items_allocated;
226
227/* This is the index in menu_items of the first empty slot. */
228static int menu_items_used;
229
230/* The number of panes currently recorded in menu_items,
231 excluding those within submenus. */
232static int menu_items_n_panes;
233
234/* Current depth within submenus. */
235static int menu_items_submenu_depth;
236
237/* Flag which when set indicates a dialog or menu has been posted by
238 Xt on behalf of one of the widget sets. */
239static int popup_activated_flag;
240
241static int next_menubar_widget_id;
242
243/* This is set nonzero after the user activates the menu bar, and set
244 to zero again after the menu bars are redisplayed by prepare_menu_bar.
245 While it is nonzero, all calls to set_frame_menubar go deep.
246
247 I don't understand why this is needed, but it does seem to be
248 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
249
250int pending_menu_activation;
251
252/* Initialize the menu_items structure if we haven't already done so.
253 Also mark it as currently empty. */
254
255static void
256init_menu_items ()
257{
258 if (NILP (menu_items))
259 {
260 menu_items_allocated = 60;
261 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
262 }
263
264 menu_items_used = 0;
265 menu_items_n_panes = 0;
266 menu_items_submenu_depth = 0;
267}
268
269/* Call at the end of generating the data in menu_items.
270 This fills in the number of items in the last pane. */
271
272static void
273finish_menu_items ()
274{
275}
276
277/* Call when finished using the data for the current menu
278 in menu_items. */
279
280static void
281discard_menu_items ()
282{
283 /* Free the structure if it is especially large.
284 Otherwise, hold on to it, to save time. */
285 if (menu_items_allocated > 200)
286 {
287 menu_items = Qnil;
288 menu_items_allocated = 0;
289 }
290}
291
292/* Make the menu_items vector twice as large. */
293
294static void
295grow_menu_items ()
296{
297 Lisp_Object old;
298 int old_size = menu_items_allocated;
299 old = menu_items;
300
301 menu_items_allocated *= 2;
302 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
303 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
304 old_size * sizeof (Lisp_Object));
305}
306
307/* Begin a submenu. */
308
309static void
310push_submenu_start ()
311{
312 if (menu_items_used + 1 > menu_items_allocated)
313 grow_menu_items ();
314
315 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
316 menu_items_submenu_depth++;
317}
318
319/* End a submenu. */
320
321static void
322push_submenu_end ()
323{
324 if (menu_items_used + 1 > menu_items_allocated)
325 grow_menu_items ();
326
327 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
328 menu_items_submenu_depth--;
329}
330
331/* Indicate boundary between left and right. */
332
333static void
334push_left_right_boundary ()
335{
336 if (menu_items_used + 1 > menu_items_allocated)
337 grow_menu_items ();
338
339 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
340}
341
342/* Start a new menu pane in menu_items..
343 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
344
345static void
346push_menu_pane (name, prefix_vec)
347 Lisp_Object name, prefix_vec;
348{
349 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
350 grow_menu_items ();
351
352 if (menu_items_submenu_depth == 0)
353 menu_items_n_panes++;
354 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
355 XVECTOR (menu_items)->contents[menu_items_used++] = name;
356 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
357}
358
359/* Push one menu item into the current pane. NAME is the string to
360 display. ENABLE if non-nil means this item can be selected. KEY
361 is the key generated by choosing this item, or nil if this item
362 doesn't really have a definition. DEF is the definition of this
363 item. EQUIV is the textual description of the keyboard equivalent
364 for this item (or nil if none). TYPE is the type of this menu
365 item, one of nil, `toggle' or `radio'. */
366
367static void
368push_menu_item (name, enable, key, def, equiv, type, selected, help)
369 Lisp_Object name, enable, key, def, equiv, type, selected, help;
370{
371 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
372 grow_menu_items ();
373
374 XVECTOR (menu_items)->contents[menu_items_used++] = name;
375 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
376 XVECTOR (menu_items)->contents[menu_items_used++] = key;
377 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
378 XVECTOR (menu_items)->contents[menu_items_used++] = def;
379 XVECTOR (menu_items)->contents[menu_items_used++] = type;
380 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
381 XVECTOR (menu_items)->contents[menu_items_used++] = help;
382}
383
384/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
385 and generate menu panes for them in menu_items.
386 If NOTREAL is nonzero,
387 don't bother really computing whether an item is enabled. */
388
389static void
390keymap_panes (keymaps, nmaps, notreal)
391 Lisp_Object *keymaps;
392 int nmaps;
393 int notreal;
394{
395 int mapno;
396
397 init_menu_items ();
398
399 /* Loop over the given keymaps, making a pane for each map.
400 But don't make a pane that is empty--ignore that map instead.
401 P is the number of panes we have made so far. */
402 for (mapno = 0; mapno < nmaps; mapno++)
403 single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
404
405 finish_menu_items ();
406}
407
408/* This is a recursive subroutine of keymap_panes.
409 It handles one keymap, KEYMAP.
410 The other arguments are passed along
411 or point to local variables of the previous function.
412 If NOTREAL is nonzero, only check for equivalent key bindings, don't
413 evaluate expressions in menu items and don't make any menu.
414
415 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
416
417static void
418single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
419 Lisp_Object keymap;
420 Lisp_Object pane_name;
421 Lisp_Object prefix;
422 int notreal;
423 int maxdepth;
424{
425 Lisp_Object pending_maps = Qnil;
426 Lisp_Object tail, item;
427 struct gcpro gcpro1, gcpro2;
428
429 if (maxdepth <= 0)
430 return;
431
432 push_menu_pane (pane_name, prefix);
433
434 for (tail = keymap; CONSP (tail); tail = XCDR (tail))
435 {
436 GCPRO2 (keymap, pending_maps);
437 /* Look at each key binding, and if it is a menu item add it
438 to this menu. */
439 item = XCAR (tail);
440 if (CONSP (item))
441 single_menu_item (XCAR (item), XCDR (item),
442 &pending_maps, notreal, maxdepth);
443 else if (VECTORP (item))
444 {
445 /* Loop over the char values represented in the vector. */
446 int len = XVECTOR (item)->size;
447 int c;
448 for (c = 0; c < len; c++)
449 {
450 Lisp_Object character;
451 XSETFASTINT (character, c);
452 single_menu_item (character, XVECTOR (item)->contents[c],
453 &pending_maps, notreal, maxdepth);
454 }
455 }
456 UNGCPRO;
457 }
458
459 /* Process now any submenus which want to be panes at this level. */
460 while (!NILP (pending_maps))
461 {
462 Lisp_Object elt, eltcdr, string;
463 elt = Fcar (pending_maps);
464 eltcdr = XCDR (elt);
465 string = XCAR (eltcdr);
466 /* We no longer discard the @ from the beginning of the string here.
467 Instead, we do this in mac_menu_show. */
468 single_keymap_panes (Fcar (elt), string,
469 XCDR (eltcdr), notreal, maxdepth - 1);
470 pending_maps = Fcdr (pending_maps);
471 }
472}
473
474/* This is a subroutine of single_keymap_panes that handles one
475 keymap entry.
476 KEY is a key in a keymap and ITEM is its binding.
477 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
478 separate panes.
479 If NOTREAL is nonzero, only check for equivalent key bindings, don't
480 evaluate expressions in menu items and don't make any menu.
481 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
482
483static void
484single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
485 Lisp_Object key, item;
486 Lisp_Object *pending_maps_ptr;
487 int maxdepth, notreal;
488{
489 Lisp_Object map, item_string, enabled;
490 struct gcpro gcpro1, gcpro2;
491 int res;
492
493 /* Parse the menu item and leave the result in item_properties. */
494 GCPRO2 (key, item);
495 res = parse_menu_item (item, notreal, 0);
496 UNGCPRO;
497 if (!res)
498 return; /* Not a menu item. */
499
500 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
501
502 if (notreal)
503 {
504 /* We don't want to make a menu, just traverse the keymaps to
505 precompute equivalent key bindings. */
506 if (!NILP (map))
507 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
508 return;
509 }
510
511 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
512 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
513
514 if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
515 {
516 if (!NILP (enabled))
517 /* An enabled separate pane. Remember this to handle it later. */
518 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
519 *pending_maps_ptr);
520 return;
521 }
522
523 push_menu_item (item_string, enabled, key,
524 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
525 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
526 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
527 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
528 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
529
530 /* Display a submenu using the toolkit. */
531 if (! (NILP (map) || NILP (enabled)))
532 {
533 push_submenu_start ();
534 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
535 push_submenu_end ();
536 }
537}
538
539/* Push all the panes and items of a menu described by the
540 alist-of-alists MENU.
541 This handles old-fashioned calls to x-popup-menu. */
542
543static void
544list_of_panes (menu)
545 Lisp_Object menu;
546{
547 Lisp_Object tail;
548
549 init_menu_items ();
550
551 for (tail = menu; !NILP (tail); tail = Fcdr (tail))
552 {
553 Lisp_Object elt, pane_name, pane_data;
554 elt = Fcar (tail);
555 pane_name = Fcar (elt);
556 CHECK_STRING (pane_name, 0);
557 push_menu_pane (pane_name, Qnil);
558 pane_data = Fcdr (elt);
559 CHECK_CONS (pane_data, 0);
560 list_of_items (pane_data);
561 }
562
563 finish_menu_items ();
564}
565
566/* Push the items in a single pane defined by the alist PANE. */
567
568static void
569list_of_items (pane)
570 Lisp_Object pane;
571{
572 Lisp_Object tail, item, item1;
573
574 for (tail = pane; !NILP (tail); tail = Fcdr (tail))
575 {
576 item = Fcar (tail);
577 if (STRINGP (item))
578 push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
579 else if (NILP (item))
580 push_left_right_boundary ();
581 else
582 {
583 CHECK_CONS (item, 0);
584 item1 = Fcar (item);
585 CHECK_STRING (item1, 1);
586 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
587 }
588 }
589}
590
591DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
592 "Pop up a deck-of-cards menu and return user's selection.\n\
593POSITION is a position specification. This is either a mouse button event\n\
594or a list ((XOFFSET YOFFSET) WINDOW)\n\
595where XOFFSET and YOFFSET are positions in pixels from the top left\n\
596corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\
597This controls the position of the center of the first line\n\
598in the first pane of the menu, not the top left of the menu as a whole.\n\
599If POSITION is t, it means to use the current mouse position.\n\
600\n\
601MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\
602The menu items come from key bindings that have a menu string as well as\n\
603a definition; actually, the \"definition\" in such a key binding looks like\n\
604\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\
605the keymap as a top-level element.\n\n\
606If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.\n\
607Otherwise, REAL-DEFINITION should be a valid key binding definition.\n\
608\n\
609You can also use a list of keymaps as MENU.\n\
610 Then each keymap makes a separate pane.\n\
611When MENU is a keymap or a list of keymaps, the return value\n\
612is a list of events.\n\n\
613\n\
614Alternatively, you can specify a menu of multiple panes\n\
615 with a list of the form (TITLE PANE1 PANE2...),\n\
616where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
617Each ITEM is normally a cons cell (STRING . VALUE);\n\
618but a string can appear as an item--that makes a nonselectable line\n\
619in the menu.\n\
620With this form of menu, the return value is VALUE from the chosen item.\n\
621\n\
622If POSITION is nil, don't display the menu at all, just precalculate the\n\
623cached information about equivalent key sequences.")
624 (position, menu)
625 Lisp_Object position, menu;
626{
627 Lisp_Object keymap, tem;
628 int xpos, ypos;
629 Lisp_Object title;
630 char *error_name;
631 Lisp_Object selection;
632 FRAME_PTR f;
633 Lisp_Object x, y, window;
634 int keymaps = 0;
635 int for_click = 0;
636 struct gcpro gcpro1;
637
638#ifdef HAVE_MENUS
639 if (! NILP (position))
640 {
641 check_mac ();
642
643 /* Decode the first argument: find the window and the coordinates. */
644 if (EQ (position, Qt)
645 || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
646 {
647 /* Use the mouse's current position. */
648 FRAME_PTR new_f = SELECTED_FRAME ();
649 Lisp_Object bar_window;
650 enum scroll_bar_part part;
651 unsigned long time;
652
653 if (mouse_position_hook)
654 (*mouse_position_hook) (&new_f, 1, &bar_window,
655 &part, &x, &y, &time);
656 if (new_f != 0)
657 XSETFRAME (window, new_f);
658 else
659 {
660 window = selected_window;
661 XSETFASTINT (x, 0);
662 XSETFASTINT (y, 0);
663 }
664 }
665 else
666 {
667 tem = Fcar (position);
668 if (CONSP (tem))
669 {
670 window = Fcar (Fcdr (position));
671 x = Fcar (tem);
672 y = Fcar (Fcdr (tem));
673 }
674 else
675 {
676 for_click = 1;
677 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
678 window = Fcar (tem); /* POSN_WINDOW (tem) */
679 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
680 x = Fcar (tem);
681 y = Fcdr (tem);
682 }
683 }
684
685 CHECK_NUMBER (x, 0);
686 CHECK_NUMBER (y, 0);
687
688 /* Decode where to put the menu. */
689
690 if (FRAMEP (window))
691 {
692 f = XFRAME (window);
693 xpos = 0;
694 ypos = 0;
695 }
696 else if (WINDOWP (window))
697 {
698 CHECK_LIVE_WINDOW (window, 0);
699 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
700
701 xpos = (FONT_WIDTH (FRAME_FONT (f))
702 * XFASTINT (XWINDOW (window)->left));
703 ypos = (FRAME_LINE_HEIGHT (f)
704 * XFASTINT (XWINDOW (window)->top));
705 }
706 else
707 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
708 but I don't want to make one now. */
709 CHECK_WINDOW (window, 0);
710
711 xpos += XINT (x);
712 ypos += XINT (y);
713
714 XSETFRAME (Vmenu_updating_frame, f);
715 }
716 Vmenu_updating_frame = Qnil;
717#endif /* HAVE_MENUS */
718
719 title = Qnil;
720 GCPRO1 (title);
721
722 /* Decode the menu items from what was specified. */
723
724 keymap = Fkeymapp (menu);
725 tem = Qnil;
726 if (CONSP (menu))
727 tem = Fkeymapp (Fcar (menu));
728 if (!NILP (keymap))
729 {
730 /* We were given a keymap. Extract menu info from the keymap. */
731 Lisp_Object prompt;
732 keymap = get_keymap (menu);
733
734 /* Extract the detailed info to make one pane. */
735 keymap_panes (&menu, 1, NILP (position));
736
737 /* Search for a string appearing directly as an element of the keymap.
738 That string is the title of the menu. */
739 prompt = Fkeymap_prompt (keymap);
740 if (NILP (title) && !NILP (prompt))
741 title = prompt;
742
743 /* Make that be the pane title of the first pane. */
744 if (!NILP (prompt) && menu_items_n_panes >= 0)
745 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
746
747 keymaps = 1;
748 }
749 else if (!NILP (tem))
750 {
751 /* We were given a list of keymaps. */
752 int nmaps = XFASTINT (Flength (menu));
753 Lisp_Object *maps
754 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
755 int i;
756
757 title = Qnil;
758
759 /* The first keymap that has a prompt string
760 supplies the menu title. */
761 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
762 {
763 Lisp_Object prompt;
764
765 maps[i++] = keymap = get_keymap (Fcar (tem));
766
767 prompt = Fkeymap_prompt (keymap);
768 if (NILP (title) && !NILP (prompt))
769 title = prompt;
770 }
771
772 /* Extract the detailed info to make one pane. */
773 keymap_panes (maps, nmaps, NILP (position));
774
775 /* Make the title be the pane title of the first pane. */
776 if (!NILP (title) && menu_items_n_panes >= 0)
777 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
778
779 keymaps = 1;
780 }
781 else
782 {
783 /* We were given an old-fashioned menu. */
784 title = Fcar (menu);
785 CHECK_STRING (title, 1);
786
787 list_of_panes (Fcdr (menu));
788
789 keymaps = 0;
790 }
791
792 if (NILP (position))
793 {
794 discard_menu_items ();
795 UNGCPRO;
796 return Qnil;
797 }
798
799#ifdef HAVE_MENUS
800 /* Display them in a menu. */
801 BLOCK_INPUT;
802
803 selection = mac_menu_show (f, xpos, ypos, for_click,
804 keymaps, title, &error_name);
805 UNBLOCK_INPUT;
806
807 discard_menu_items ();
808
809 UNGCPRO;
810#endif /* HAVE_MENUS */
811
812 if (error_name) error (error_name);
813 return selection;
814}
815
816#ifdef HAVE_MENUS
817
818DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
819 "Pop up a dialog box and return user's selection.\n\
820POSITION specifies which frame to use.\n\
821This is normally a mouse button event or a window or frame.\n\
822If POSITION is t, it means to use the frame the mouse is on.\n\
823The dialog box appears in the middle of the specified frame.\n\
824\n\
825CONTENTS specifies the alternatives to display in the dialog box.\n\
826It is a list of the form (TITLE ITEM1 ITEM2...).\n\
827Each ITEM is a cons cell (STRING . VALUE).\n\
828The return value is VALUE from the chosen item.\n\n\
829An ITEM may also be just a string--that makes a nonselectable item.\n\
830An ITEM may also be nil--that means to put all preceding items\n\
831on the left of the dialog box and all following items on the right.\n\
832\(By default, approximately half appear on each side.)")
833 (position, contents)
834 Lisp_Object position, contents;
835{
836 FRAME_PTR f;
837 Lisp_Object window;
838
839 check_mac ();
840
841 /* Decode the first argument: find the window or frame to use. */
842 if (EQ (position, Qt)
843 || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
844 {
845#if 0 /* Using the frame the mouse is on may not be right. */
846 /* Use the mouse's current position. */
847 FRAME_PTR new_f = SELECTED_FRAME ();
848 Lisp_Object bar_window;
849 int part;
850 unsigned long time;
851 Lisp_Object x, y;
852
853 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
854
855 if (new_f != 0)
856 XSETFRAME (window, new_f);
857 else
858 window = selected_window;
859#endif
860 window = selected_window;
861 }
862 else if (CONSP (position))
863 {
864 Lisp_Object tem;
865 tem = Fcar (position);
866 if (CONSP (tem))
867 window = Fcar (Fcdr (position));
868 else
869 {
870 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
871 window = Fcar (tem); /* POSN_WINDOW (tem) */
872 }
873 }
874 else if (WINDOWP (position) || FRAMEP (position))
875 window = position;
876 else
877 window = Qnil;
878
879 /* Decode where to put the menu. */
880
881 if (FRAMEP (window))
882 f = XFRAME (window);
883 else if (WINDOWP (window))
884 {
885 CHECK_LIVE_WINDOW (window, 0);
886 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
887 }
888 else
889 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
890 but I don't want to make one now. */
891 CHECK_WINDOW (window, 0);
892
893#ifndef HAVE_DIALOGS
894 /* Display a menu with these alternatives
895 in the middle of frame F. */
896 {
897 Lisp_Object x, y, frame, newpos;
898 XSETFRAME (frame, f);
899 XSETINT (x, x_pixel_width (f) / 2);
900 XSETINT (y, x_pixel_height (f) / 2);
901 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
902
903 return Fx_popup_menu (newpos,
904 Fcons (Fcar (contents), Fcons (contents, Qnil)));
905 }
906#else /* HAVE_DIALOGS */
907 {
908 Lisp_Object title;
909 char *error_name;
910 Lisp_Object selection;
911
912 /* Decode the dialog items from what was specified. */
913 title = Fcar (contents);
914 CHECK_STRING (title, 1);
915
916 list_of_panes (Fcons (contents, Qnil));
917
918 /* Display them in a dialog box. */
919 BLOCK_INPUT;
920 selection = mac_dialog_show (f, 0, title, &error_name);
921 UNBLOCK_INPUT;
922
923 discard_menu_items ();
924
925 if (error_name) error (error_name);
926 return selection;
927 }
928#endif /* HAVE_DIALOGS */
929}
930
931/* Activate the menu bar of frame F.
932 This is called from keyboard.c when it gets the
933 menu_bar_activate_event out of the Emacs event queue.
934
935 To activate the menu bar, we signal to the input thread that it can
936 return from the WM_INITMENU message, allowing the normal Windows
937 processing of the menus.
938
939 But first we recompute the menu bar contents (the whole tree).
940
941 This way we can safely execute Lisp code. */
942
943void
944x_activate_menubar (f)
945 FRAME_PTR f;
946{
947 SInt32 menu_choice;
948 extern Point saved_menu_event_location;
949
950 set_frame_menubar (f, 0, 1);
951 BLOCK_INPUT;
952
953 menu_choice = MenuSelect (saved_menu_event_location);
954 do_menu_choice (menu_choice);
955
956 UNBLOCK_INPUT;
957}
958
959/* This callback is called from the menu bar pulldown menu
960 when the user makes a selection.
961 Figure out what the user chose
962 and put the appropriate events into the keyboard buffer. */
963
964void
965menubar_selection_callback (FRAME_PTR f, int client_data)
966{
967 Lisp_Object prefix, entry;
968 Lisp_Object vector;
969 Lisp_Object *subprefix_stack;
970 int submenu_depth = 0;
971 int i;
972
973 if (!f)
974 return;
975 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
976 vector = f->menu_bar_vector;
977 prefix = Qnil;
978 i = 0;
979 while (i < f->menu_bar_items_used)
980 {
981 if (EQ (XVECTOR (vector)->contents[i], Qnil))
982 {
983 subprefix_stack[submenu_depth++] = prefix;
984 prefix = entry;
985 i++;
986 }
987 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
988 {
989 prefix = subprefix_stack[--submenu_depth];
990 i++;
991 }
992 else if (EQ (XVECTOR (vector)->contents[i], Qt))
993 {
994 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
995 i += MENU_ITEMS_PANE_LENGTH;
996 }
997 else
998 {
999 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1000 if (client_data == i)
1001 {
1002 int j;
1003 struct input_event buf;
1004 Lisp_Object frame;
1005
1006 XSETFRAME (frame, f);
1007 buf.kind = MENU_BAR_EVENT;
1008 buf.frame_or_window = frame;
1009 buf.arg = frame;
1010 kbd_buffer_store_event (&buf);
1011
1012 for (j = 0; j < submenu_depth; j++)
1013 if (!NILP (subprefix_stack[j]))
1014 {
1015 buf.kind = MENU_BAR_EVENT;
1016 buf.frame_or_window = frame;
1017 buf.arg = subprefix_stack[j];
1018 kbd_buffer_store_event (&buf);
1019 }
1020
1021 if (!NILP (prefix))
1022 {
1023 buf.kind = MENU_BAR_EVENT;
1024 buf.frame_or_window = frame;
1025 buf.arg = prefix;
1026 kbd_buffer_store_event (&buf);
1027 }
1028
1029 buf.kind = MENU_BAR_EVENT;
1030 buf.frame_or_window = frame;
1031 buf.arg = entry;
1032 kbd_buffer_store_event (&buf);
1033
1034#if 0
1035 /* Queue this to recompute possibly updated menubar. */
1036 buf.kind = menu_bar_activate_event;
1037 buf.frame_or_window = frame;
1038 buf.arg = Qnil;
1039 kbd_buffer_store_event (&buf);
1040#endif
1041
1042 return;
1043 }
1044 i += MENU_ITEMS_ITEM_LENGTH;
1045 }
1046 }
1047}
1048
1049/* Allocate a widget_value, blocking input. */
1050
1051widget_value *
1052xmalloc_widget_value ()
1053{
1054 widget_value *value;
1055
1056 BLOCK_INPUT;
1057 value = malloc_widget_value ();
1058 UNBLOCK_INPUT;
1059
1060 return value;
1061}
1062
1063/* This recursively calls free_widget_value on the tree of widgets.
1064 It must free all data that was malloc'ed for these widget_values.
1065 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1066 must be left alone. */
1067
1068void
1069free_menubar_widget_value_tree (wv)
1070 widget_value *wv;
1071{
1072 if (! wv) return;
1073
1074 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1075
1076 if (wv->contents && (wv->contents != (widget_value*)1))
1077 {
1078 free_menubar_widget_value_tree (wv->contents);
1079 wv->contents = (widget_value *) 0xDEADBEEF;
1080 }
1081 if (wv->next)
1082 {
1083 free_menubar_widget_value_tree (wv->next);
1084 wv->next = (widget_value *) 0xDEADBEEF;
1085 }
1086 BLOCK_INPUT;
1087 free_widget_value (wv);
1088 UNBLOCK_INPUT;
1089}
1090
1091/* Return a tree of widget_value structures for a menu bar item
1092 whose event type is ITEM_KEY (with string ITEM_NAME)
1093 and whose contents come from the list of keymaps MAPS. */
1094
1095static widget_value *
1096single_submenu (item_key, item_name, maps)
1097 Lisp_Object item_key, item_name, maps;
1098{
1099 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1100 int i;
1101 int submenu_depth = 0;
1102 Lisp_Object length;
1103 int len;
1104 Lisp_Object *mapvec;
1105 widget_value **submenu_stack;
1106 int previous_items = menu_items_used;
1107 int top_level_items = 0;
1108
1109 length = Flength (maps);
1110 len = XINT (length);
1111
1112 /* Convert the list MAPS into a vector MAPVEC. */
1113 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1114 for (i = 0; i < len; i++)
1115 {
1116 mapvec[i] = Fcar (maps);
1117 maps = Fcdr (maps);
1118 }
1119
1120 menu_items_n_panes = 0;
1121
1122 /* Loop over the given keymaps, making a pane for each map.
1123 But don't make a pane that is empty--ignore that map instead. */
1124 for (i = 0; i < len; i++)
1125 {
1126 if (SYMBOLP (mapvec[i])
1127 || (CONSP (mapvec[i])
1128 && NILP (Fkeymapp (mapvec[i]))))
1129 {
1130 /* Here we have a command at top level in the menu bar
1131 as opposed to a submenu. */
1132 top_level_items = 1;
1133 push_menu_pane (Qnil, Qnil);
1134 push_menu_item (item_name, Qt, item_key, mapvec[i],
1135 Qnil, Qnil, Qnil, Qnil);
1136 }
1137 else
1138 single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
1139 }
1140
1141 /* Create a tree of widget_value objects
1142 representing the panes and their items. */
1143
1144 submenu_stack
1145 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1146 wv = xmalloc_widget_value ();
1147 wv->name = "menu";
1148 wv->value = 0;
1149 wv->enabled = 1;
1150 wv->button_type = BUTTON_TYPE_NONE;
1151 first_wv = wv;
1152 save_wv = 0;
1153 prev_wv = 0;
1154
1155 /* Loop over all panes and items made during this call
1156 and construct a tree of widget_value objects.
1157 Ignore the panes and items made by previous calls to
1158 single_submenu, even though those are also in menu_items. */
1159 i = previous_items;
1160 while (i < menu_items_used)
1161 {
1162 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1163 {
1164 submenu_stack[submenu_depth++] = save_wv;
1165 save_wv = prev_wv;
1166 prev_wv = 0;
1167 i++;
1168 }
1169 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1170 {
1171 prev_wv = save_wv;
1172 save_wv = submenu_stack[--submenu_depth];
1173 i++;
1174 }
1175 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1176 && submenu_depth != 0)
1177 i += MENU_ITEMS_PANE_LENGTH;
1178 /* Ignore a nil in the item list.
1179 It's meaningful only for dialog boxes. */
1180 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1181 i += 1;
1182 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1183 {
1184 /* Create a new pane. */
1185 Lisp_Object pane_name, prefix;
1186 char *pane_string;
1187 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1188 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1189#ifndef HAVE_MULTILINGUAL_MENU
1190 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1191 pane_name = string_make_unibyte (pane_name);
1192#endif
1193 pane_string = (NILP (pane_name)
1194 ? "" : (char *) XSTRING (pane_name)->data);
1195 /* If there is just one top-level pane, put all its items directly
1196 under the top-level menu. */
1197 if (menu_items_n_panes == 1)
1198 pane_string = "";
1199
1200 /* If the pane has a meaningful name,
1201 make the pane a top-level menu item
1202 with its items as a submenu beneath it. */
1203 if (strcmp (pane_string, ""))
1204 {
1205 wv = xmalloc_widget_value ();
1206 if (save_wv)
1207 save_wv->next = wv;
1208 else
1209 first_wv->contents = wv;
1210 wv->name = pane_string;
1211 /* Ignore the @ that means "separate pane".
1212 This is a kludge, but this isn't worth more time. */
1213 if (!NILP (prefix) && wv->name[0] == '@')
1214 wv->name++;
1215 wv->value = 0;
1216 wv->enabled = 1;
1217 wv->button_type = BUTTON_TYPE_NONE;
1218 }
1219 save_wv = wv;
1220 prev_wv = 0;
1221 i += MENU_ITEMS_PANE_LENGTH;
1222 }
1223 else
1224 {
1225 /* Create a new item within current pane. */
1226 Lisp_Object item_name, enable, descrip, def, type, selected;
1227 Lisp_Object help;
1228
1229 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1230 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1231 descrip
1232 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1233 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
1234 type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
1235 selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
1236 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
1237
1238#ifndef HAVE_MULTILINGUAL_MENU
1239 if (STRING_MULTIBYTE (item_name))
1240 item_name = string_make_unibyte (item_name);
1241 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1242 descrip = string_make_unibyte (descrip);
1243#endif
1244
1245 wv = xmalloc_widget_value ();
1246 if (prev_wv)
1247 prev_wv->next = wv;
1248 else
1249 save_wv->contents = wv;
1250
1251 wv->name = (char *) XSTRING (item_name)->data;
1252 if (!NILP (descrip))
1253 wv->key = (char *) XSTRING (descrip)->data;
1254 wv->value = 0;
1255 /* The EMACS_INT cast avoids a warning. There's no problem
1256 as long as pointers have enough bits to hold small integers. */
1257 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1258 wv->enabled = !NILP (enable);
1259
1260 if (NILP (type))
1261 wv->button_type = BUTTON_TYPE_NONE;
1262 else if (EQ (type, QCradio))
1263 wv->button_type = BUTTON_TYPE_RADIO;
1264 else if (EQ (type, QCtoggle))
1265 wv->button_type = BUTTON_TYPE_TOGGLE;
1266 else
1267 abort ();
1268
1269 wv->selected = !NILP (selected);
1270 if (STRINGP (help))
1271 wv->help = (char *) XSTRING (help)->data;
1272 else
1273 wv->help = NULL;
1274
1275 prev_wv = wv;
1276
1277 i += MENU_ITEMS_ITEM_LENGTH;
1278 }
1279 }
1280
1281 /* If we have just one "menu item"
1282 that was originally a button, return it by itself. */
1283 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
1284 {
1285 wv = first_wv->contents;
1286 free_widget_value (first_wv);
1287 return wv;
1288 }
1289
1290 return first_wv;
1291}
1292
1293/* Set the contents of the menubar widgets of frame F.
1294 The argument FIRST_TIME is currently ignored;
1295 it is set the first time this is called, from initialize_frame_menubar. */
1296
1297void
1298set_frame_menubar (f, first_time, deep_p)
1299 FRAME_PTR f;
1300 int first_time;
1301 int deep_p;
1302{
1303 int menubar_widget = f->output_data.mac->menubar_widget;
1304 Lisp_Object items;
1305 widget_value *wv, *first_wv, *prev_wv = 0;
1306 int i;
1307
1308 XSETFRAME (Vmenu_updating_frame, f);
1309
1310 wv = xmalloc_widget_value ();
1311 wv->name = "menubar";
1312 wv->value = 0;
1313 wv->enabled = 1;
1314 wv->button_type = BUTTON_TYPE_NONE;
1315 first_wv = wv;
1316
1317 {
1318 /* Make a widget-value tree representing the entire menu trees. */
1319
1320 struct buffer *prev = current_buffer;
1321 Lisp_Object buffer;
1322 int specpdl_count = specpdl_ptr - specpdl;
1323 int previous_menu_items_used = f->menu_bar_items_used;
1324 Lisp_Object *previous_items
1325 = (Lisp_Object *) alloca (previous_menu_items_used
1326 * sizeof (Lisp_Object));
1327
1328 /* If we are making a new widget, its contents are empty,
1329 do always reinitialize them. */
1330 if (! menubar_widget)
1331 previous_menu_items_used = 0;
1332
1333 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1334 specbind (Qinhibit_quit, Qt);
1335 /* Don't let the debugger step into this code
1336 because it is not reentrant. */
1337 specbind (Qdebug_on_next_call, Qnil);
1338
1339 record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
1340 if (NILP (Voverriding_local_map_menu_flag))
1341 {
1342 specbind (Qoverriding_terminal_local_map, Qnil);
1343 specbind (Qoverriding_local_map, Qnil);
1344 }
1345
1346 set_buffer_internal_1 (XBUFFER (buffer));
1347
1348 /* Run the Lucid hook. */
1349 safe_run_hooks (Qactivate_menubar_hook);
1350 /* If it has changed current-menubar from previous value,
1351 really recompute the menubar from the value. */
1352 if (! NILP (Vlucid_menu_bar_dirty_flag))
1353 call0 (Qrecompute_lucid_menubar);
1354 safe_run_hooks (Qmenu_bar_update_hook);
1355 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1356
1357 items = FRAME_MENU_BAR_ITEMS (f);
1358
1359 inhibit_garbage_collection ();
1360
1361 /* Save the frame's previous menu bar contents data. */
1362 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1363 previous_menu_items_used * sizeof (Lisp_Object));
1364
1365 /* Fill in the current menu bar contents. */
1366 menu_items = f->menu_bar_vector;
1367 menu_items_allocated = XVECTOR (menu_items)->size;
1368 init_menu_items ();
1369 for (i = 0; i < XVECTOR (items)->size; i += 4)
1370 {
1371 Lisp_Object key, string, maps;
1372
1373 key = XVECTOR (items)->contents[i];
1374 string = XVECTOR (items)->contents[i + 1];
1375 maps = XVECTOR (items)->contents[i + 2];
1376 if (NILP (string))
1377 break;
1378
1379 wv = single_submenu (key, string, maps);
1380 if (prev_wv)
1381 prev_wv->next = wv;
1382 else
1383 first_wv->contents = wv;
1384 /* Don't set wv->name here; GC during the loop might relocate it. */
1385 wv->enabled = 1;
1386 wv->button_type = BUTTON_TYPE_NONE;
1387 prev_wv = wv;
1388 }
1389
1390 finish_menu_items ();
1391
1392 set_buffer_internal_1 (prev);
1393 unbind_to (specpdl_count, Qnil);
1394
1395 /* If there has been no change in the Lisp-level contents
1396 of the menu bar, skip redisplaying it. Just exit. */
1397
1398 for (i = 0; i < previous_menu_items_used; i++)
1399 if (menu_items_used == i
1400 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1401 break;
1402 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1403 {
1404 free_menubar_widget_value_tree (first_wv);
1405 menu_items = Qnil;
1406
1407 return;
1408 }
1409
1410 /* Now GC cannot happen during the lifetime of the widget_value,
1411 so it's safe to store data from a Lisp_String. */
1412 wv = first_wv->contents;
1413 for (i = 0; i < XVECTOR (items)->size; i += 4)
1414 {
1415 Lisp_Object string;
1416 string = XVECTOR (items)->contents[i + 1];
1417 if (NILP (string))
1418 break;
1419 wv->name = (char *) XSTRING (string)->data;
1420 wv = wv->next;
1421 }
1422
1423 f->menu_bar_vector = menu_items;
1424 f->menu_bar_items_used = menu_items_used;
1425 menu_items = Qnil;
1426 }
1427
1428 /* Create or update the menu bar widget. */
1429
1430 BLOCK_INPUT;
1431
1432 f->output_data.mac->menubar_widget = NULL; /* always NULL on Mac */
1433
1434 {
1435 int i = MIN_MENU_ID;
1436 MenuHandle menu = GetMenuHandle (i);
1437 while (menu != NULL)
1438 {
1439 DeleteMenu (i);
1440 DisposeMenu (menu);
1441 menu = GetMenuHandle (++i);
1442 }
1443
1444 i = MIN_SUBMENU_ID;
1445 menu = GetMenuHandle (i);
1446 while (menu != NULL)
1447 {
1448 DeleteMenu (i);
1449 DisposeMenu (menu);
1450 menu = GetMenuHandle (++i);
1451 }
1452 }
1453
1454 fill_menubar (first_wv->contents);
1455
1456 DrawMenuBar ();
1457
1458 free_menubar_widget_value_tree (first_wv);
1459
1460 UNBLOCK_INPUT;
1461}
1462
1463/* Called from Fx_create_frame to create the initial menubar of a
1464 frame before it is mapped, so that the window is mapped with the
1465 menubar already there instead of us tacking it on later and
1466 thrashing the window after it is visible. */
1467
1468void
1469initialize_frame_menubar (f)
1470 FRAME_PTR f;
1471{
1472 /* This function is called before the first chance to redisplay
1473 the frame. It has to be, so the frame will have the right size. */
1474 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1475 set_frame_menubar (f, 1, 1);
1476}
1477
1478/* Get rid of the menu bar of frame F, and free its storage.
1479 This is used when deleting a frame, and when turning off the menu bar. */
1480
1481void
1482free_frame_menubar (f)
1483 FRAME_PTR f;
1484{
1485 /* Nothing to do since set_frame_menubar disposes of menus before
1486 installing new ones. */
1487}
1488
1489
1490/* mac_menu_show actually displays a menu using the panes and items in
1491 menu_items and returns the value selected from it; we assume input
1492 is blocked by the caller. */
1493
1494/* F is the frame the menu is for.
1495 X and Y are the frame-relative specified position,
1496 relative to the inside upper left corner of the frame F.
1497 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1498 KEYMAPS is 1 if this menu was specified with keymaps;
1499 in that case, we return a list containing the chosen item's value
1500 and perhaps also the pane's prefix.
1501 TITLE is the specified menu title.
1502 ERROR is a place to store an error message string in case of failure.
1503 (We return nil on failure, but the value doesn't actually matter.) */
1504
1505static Lisp_Object
1506mac_menu_show (f, x, y, for_click, keymaps, title, error)
1507 FRAME_PTR f;
1508 int x;
1509 int y;
1510 int for_click;
1511 int keymaps;
1512 Lisp_Object title;
1513 char **error;
1514{
1515 int i;
1516 int menu_item_selection;
1517 MenuHandle menu;
1518 Point pos;
1519 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1520 widget_value **submenu_stack
1521 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1522 Lisp_Object *subprefix_stack
1523 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1524 int submenu_depth = 0;
1525 int first_pane;
1526 int next_release_must_exit = 0;
1527
1528 *error = NULL;
1529
1530 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1531 {
1532 *error = "Empty menu";
1533 return Qnil;
1534 }
1535
1536 /* Create a tree of widget_value objects
1537 representing the panes and their items. */
1538 wv = xmalloc_widget_value ();
1539 wv->name = "menu";
1540 wv->value = 0;
1541 wv->enabled = 1;
1542 wv->button_type = BUTTON_TYPE_NONE;
1543 first_wv = wv;
1544 first_pane = 1;
1545
1546 /* Loop over all panes and items, filling in the tree. */
1547 i = 0;
1548 while (i < menu_items_used)
1549 {
1550 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1551 {
1552 submenu_stack[submenu_depth++] = save_wv;
1553 save_wv = prev_wv;
1554 prev_wv = 0;
1555 first_pane = 1;
1556 i++;
1557 }
1558 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1559 {
1560 prev_wv = save_wv;
1561 save_wv = submenu_stack[--submenu_depth];
1562 first_pane = 0;
1563 i++;
1564 }
1565 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1566 && submenu_depth != 0)
1567 i += MENU_ITEMS_PANE_LENGTH;
1568 /* Ignore a nil in the item list.
1569 It's meaningful only for dialog boxes. */
1570 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1571 i += 1;
1572 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1573 {
1574 /* Create a new pane. */
1575 Lisp_Object pane_name, prefix;
1576 char *pane_string;
1577 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1578 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1579#ifndef HAVE_MULTILINGUAL_MENU
1580 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1581 pane_name = string_make_unibyte (pane_name);
1582#endif
1583 pane_string = (NILP (pane_name)
1584 ? "" : (char *) XSTRING (pane_name)->data);
1585 /* If there is just one top-level pane, put all its items directly
1586 under the top-level menu. */
1587 if (menu_items_n_panes == 1)
1588 pane_string = "";
1589
1590 /* If the pane has a meaningful name,
1591 make the pane a top-level menu item
1592 with its items as a submenu beneath it. */
1593 if (!keymaps && strcmp (pane_string, ""))
1594 {
1595 wv = xmalloc_widget_value ();
1596 if (save_wv)
1597 save_wv->next = wv;
1598 else
1599 first_wv->contents = wv;
1600 wv->name = pane_string;
1601 if (keymaps && !NILP (prefix))
1602 wv->name++;
1603 wv->value = 0;
1604 wv->enabled = 1;
1605 wv->button_type = BUTTON_TYPE_NONE;
1606 save_wv = wv;
1607 prev_wv = 0;
1608 }
1609 else if (first_pane)
1610 {
1611 save_wv = wv;
1612 prev_wv = 0;
1613 }
1614 first_pane = 0;
1615 i += MENU_ITEMS_PANE_LENGTH;
1616 }
1617 else
1618 {
1619 /* Create a new item within current pane. */
1620 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1621
1622 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1623 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1624 descrip
1625 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1626 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
1627 type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
1628 selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
1629 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
1630
1631#ifndef HAVE_MULTILINGUAL_MENU
1632 if (STRING_MULTIBYTE (item_name))
1633 item_name = string_make_unibyte (item_name);
1634 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1635 descrip = string_make_unibyte (descrip);
1636#endif
1637
1638 wv = xmalloc_widget_value ();
1639 if (prev_wv)
1640 prev_wv->next = wv;
1641 else
1642 save_wv->contents = wv;
1643 wv->name = (char *) XSTRING (item_name)->data;
1644 if (!NILP (descrip))
1645 wv->key = (char *) XSTRING (descrip)->data;
1646 wv->value = 0;
1647 /* Use the contents index as call_data, since we are
1648 restricted to 16-bits.. */
1649 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
1650 wv->enabled = !NILP (enable);
1651
1652 if (NILP (type))
1653 wv->button_type = BUTTON_TYPE_NONE;
1654 else if (EQ (type, QCtoggle))
1655 wv->button_type = BUTTON_TYPE_TOGGLE;
1656 else if (EQ (type, QCradio))
1657 wv->button_type = BUTTON_TYPE_RADIO;
1658 else
1659 abort ();
1660
1661 wv->selected = !NILP (selected);
1662
1663 if (STRINGP (help))
1664 wv->help = (char *) XSTRING (help)->data;
1665 else
1666 wv->help = NULL;
1667
1668 prev_wv = wv;
1669
1670 i += MENU_ITEMS_ITEM_LENGTH;
1671 }
1672 }
1673
1674 /* Deal with the title, if it is non-nil. */
1675 if (!NILP (title))
1676 {
1677 widget_value *wv_title = xmalloc_widget_value ();
1678 widget_value *wv_sep = xmalloc_widget_value ();
1679
1680 /* Maybe replace this separator with a bitmap or owner-draw item
1681 so that it looks better. Having two separators looks odd. */
1682 wv_sep->name = "--";
1683 wv_sep->next = first_wv->contents;
1684
1685#ifndef HAVE_MULTILINGUAL_MENU
1686 if (STRING_MULTIBYTE (title))
1687 title = string_make_unibyte (title);
1688#endif
1689 wv_title->name = (char *) XSTRING (title)->data;
1690 wv_title->enabled = True;
1691 wv_title->button_type = BUTTON_TYPE_NONE;
1692 wv_title->next = wv_sep;
1693 first_wv->contents = wv_title;
1694 }
1695
1696 /* Actually create the menu. */
1697 menu = NewMenu (POPUP_SUBMENU_ID, "\p");
1698 fill_submenu (menu, first_wv->contents, 0);
1699
1700 /* Adjust coordinates to be root-window-relative. */
1701 pos.h = x;
1702 pos.v = y;
1703 SetPort (FRAME_MAC_WINDOW (f));
1704 LocalToGlobal (&pos);
1705
1706 InsertMenu (menu, -1);
1707
1708 /* Display the menu. */
1709 menu_item_selection = LoWord (PopUpMenuSelect (menu, pos.v, pos.h, 0));
1710
1711 GetMenuItemRefCon (menu, menu_item_selection, &menu_item_selection);
1712
1713 DeleteMenu (POPUP_SUBMENU_ID);
1714
1715#if 0
1716 /* Clean up extraneous mouse events which might have been generated
1717 during the call. */
1718 discard_mouse_events ();
1719#endif
1720
1721 /* Free the widget_value objects we used to specify the
1722 contents. */
1723 free_menubar_widget_value_tree (first_wv);
1724
1725 DisposeMenu (menu);
1726
1727 /* Find the selected item, and its pane, to return the proper
1728 value. */
1729 if (menu_item_selection != 0)
1730 {
1731 Lisp_Object prefix, entry;
1732
1733 prefix = Qnil;
1734 i = 0;
1735 while (i < menu_items_used)
1736 {
1737 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1738 {
1739 subprefix_stack[submenu_depth++] = prefix;
1740 prefix = entry;
1741 i++;
1742 }
1743 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1744 {
1745 prefix = subprefix_stack[--submenu_depth];
1746 i++;
1747 }
1748 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1749 {
1750 prefix
1751 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1752 i += MENU_ITEMS_PANE_LENGTH;
1753 }
1754 /* Ignore a nil in the item list. It's meaningful only for
1755 dialog boxes. */
1756 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1757 i += 1;
1758 else
1759 {
1760 entry
1761 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1762 if (menu_item_selection == i)
1763 {
1764 if (keymaps != 0)
1765 {
1766 int j;
1767
1768 entry = Fcons (entry, Qnil);
1769 if (!NILP (prefix))
1770 entry = Fcons (prefix, entry);
1771 for (j = submenu_depth - 1; j >= 0; j--)
1772 if (!NILP (subprefix_stack[j]))
1773 entry = Fcons (subprefix_stack[j], entry);
1774 }
1775 return entry;
1776 }
1777 i += MENU_ITEMS_ITEM_LENGTH;
1778 }
1779 }
1780 }
1781
1782 return Qnil;
1783}
1784
1785
1786/* Construct native Mac OS menubar based on widget_value tree. */
1787
1788static int
1789mac_dialog (widget_value *wv)
1790{
1791 char *dialog_name;
1792 char *prompt;
1793 char **button_labels;
1794 UInt32 *ref_cons;
1795 int nb_buttons;
1796 int left_count;
1797 int i;
1798 int dialog_width;
1799 Rect rect;
1800 WindowPtr window_ptr;
1801 ControlHandle ch;
1802 int left;
1803 EventRecord event_record;
1804 SInt16 part_code;
1805 int control_part_code;
1806 Point mouse;
1807
1808 dialog_name = wv->name;
1809 nb_buttons = dialog_name[1] - '0';
1810 left_count = nb_buttons - (dialog_name[4] - '0');
1811 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
1812 ref_cons = (int *) alloca (sizeof (UInt32) * nb_buttons);
1813
1814 wv = wv->contents;
1815 prompt = (char *) alloca (strlen (wv->value) + 1);
1816 strcpy (prompt, wv->value);
1817 c2pstr (prompt);
1818
1819 wv = wv->next;
1820 for (i = 0; i < nb_buttons; i++)
1821 {
1822 button_labels[i] = wv->value;
1823 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
1824 strcpy (button_labels[i], wv->value);
1825 c2pstr (button_labels[i]);
1826 ref_cons[i] = (UInt32) wv->call_data;
1827 wv = wv->next;
1828 }
1829
1830 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
1831 SetPort (window_ptr);
1832
1833 TextFont (0);
1834 /* Left and right margins in the dialog are 13 pixels each.*/
1835 dialog_width = 14;
1836 /* Calculate width of dialog box: 8 pixels on each side of the text
1837 label in each button, 12 pixels between buttons. */
1838 for (i = 0; i < nb_buttons; i++)
1839 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
1840
1841 if (left_count != 0 && nb_buttons - left_count != 0)
1842 dialog_width += 12;
1843
1844 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
1845
1846 SizeWindow (window_ptr, dialog_width, 78, 0);
1847 ShowWindow (window_ptr);
1848
1849 SetPort (window_ptr);
1850 TextFont (0);
1851
1852 MoveTo (13, 29);
1853 DrawString (prompt);
1854
1855 left = 13;
1856 for (i = 0; i < nb_buttons; i++)
1857 {
1858 int button_width = StringWidth (button_labels[i]) + 16;
1859 SetRect (&rect, left, 45, left + button_width, 65);
1860 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
1861 kControlPushButtonProc, ref_cons[i]);
1862 left += button_width + 12;
1863 if (i == left_count - 1)
1864 left += 12;
1865 }
1866
1867 i = 0;
1868 while (!i)
1869 {
1870 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
1871 if (event_record.what == mouseDown)
1872 {
1873 part_code = FindWindow (event_record.where, &window_ptr);
1874 if (part_code == inContent)
1875 {
1876 mouse = event_record.where;
1877 GlobalToLocal (&mouse);
1878 control_part_code = FindControl (mouse, window_ptr, &ch);
1879 if (control_part_code == kControlButtonPart)
1880 if (TrackControl (ch, mouse, NULL))
1881 i = GetControlReference (ch);
1882 }
1883 }
1884 }
1885
1886 DisposeWindow (window_ptr);
1887
1888 return i;
1889}
1890
1891static char * button_names [] = {
1892 "button1", "button2", "button3", "button4", "button5",
1893 "button6", "button7", "button8", "button9", "button10" };
1894
1895static Lisp_Object
1896mac_dialog_show (f, keymaps, title, error)
1897 FRAME_PTR f;
1898 int keymaps;
1899 Lisp_Object title;
1900 char **error;
1901{
1902 int i, nb_buttons=0;
1903 char dialog_name[6];
1904 int menu_item_selection;
1905
1906 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1907
1908 /* Number of elements seen so far, before boundary. */
1909 int left_count = 0;
1910 /* 1 means we've seen the boundary between left-hand elts and
1911 right-hand. */
1912 int boundary_seen = 0;
1913
1914 *error = NULL;
1915
1916 if (menu_items_n_panes > 1)
1917 {
1918 *error = "Multiple panes in dialog box";
1919 return Qnil;
1920 }
1921
1922 /* Create a tree of widget_value objects representing the text label
1923 and buttons. */
1924 {
1925 Lisp_Object pane_name, prefix;
1926 char *pane_string;
1927 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
1928 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
1929 pane_string = (NILP (pane_name)
1930 ? "" : (char *) XSTRING (pane_name)->data);
1931 prev_wv = xmalloc_widget_value ();
1932 prev_wv->value = pane_string;
1933 if (keymaps && !NILP (prefix))
1934 prev_wv->name++;
1935 prev_wv->enabled = 1;
1936 prev_wv->name = "message";
1937 first_wv = prev_wv;
1938
1939 /* Loop over all panes and items, filling in the tree. */
1940 i = MENU_ITEMS_PANE_LENGTH;
1941 while (i < menu_items_used)
1942 {
1943
1944 /* Create a new item within current pane. */
1945 Lisp_Object item_name, enable, descrip, help;
1946
1947 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1948 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1949 descrip
1950 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1951 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
1952
1953 if (NILP (item_name))
1954 {
1955 free_menubar_widget_value_tree (first_wv);
1956 *error = "Submenu in dialog items";
1957 return Qnil;
1958 }
1959 if (EQ (item_name, Qquote))
1960 {
1961 /* This is the boundary between left-side elts and
1962 right-side elts. Stop incrementing right_count. */
1963 boundary_seen = 1;
1964 i++;
1965 continue;
1966 }
1967 if (nb_buttons >= 9)
1968 {
1969 free_menubar_widget_value_tree (first_wv);
1970 *error = "Too many dialog items";
1971 return Qnil;
1972 }
1973
1974 wv = xmalloc_widget_value ();
1975 prev_wv->next = wv;
1976 wv->name = (char *) button_names[nb_buttons];
1977 if (!NILP (descrip))
1978 wv->key = (char *) XSTRING (descrip)->data;
1979 wv->value = (char *) XSTRING (item_name)->data;
1980 wv->call_data = (void *) i;
1981 /* menu item is identified by its index in menu_items table */
1982 wv->enabled = !NILP (enable);
1983 prev_wv = wv;
1984
1985 if (! boundary_seen)
1986 left_count++;
1987
1988 nb_buttons++;
1989 i += MENU_ITEMS_ITEM_LENGTH;
1990 }
1991
1992 /* If the boundary was not specified, by default put half on the
1993 left and half on the right. */
1994 if (! boundary_seen)
1995 left_count = nb_buttons - nb_buttons / 2;
1996
1997 wv = xmalloc_widget_value ();
1998 wv->name = dialog_name;
1999
2000 /* Dialog boxes use a really stupid name encoding which specifies
2001 how many buttons to use and how many buttons are on the right.
2002 The Q means something also. */
2003 dialog_name[0] = 'Q';
2004 dialog_name[1] = '0' + nb_buttons;
2005 dialog_name[2] = 'B';
2006 dialog_name[3] = 'R';
2007 /* Number of buttons to put on the right. */
2008 dialog_name[4] = '0' + nb_buttons - left_count;
2009 dialog_name[5] = 0;
2010 wv->contents = first_wv;
2011 first_wv = wv;
2012 }
2013
2014 /* Actually create the dialog. */
2015#ifdef HAVE_DIALOGS
2016 menu_item_selection = mac_dialog (first_wv);
2017#else
2018 menu_item_selection = 0;
2019#endif
2020
2021 /* Free the widget_value objects we used to specify the
2022 contents. */
2023 free_menubar_widget_value_tree (first_wv);
2024
2025 /* Find the selected item, and its pane, to return the proper
2026 value. */
2027 if (menu_item_selection != 0)
2028 {
2029 Lisp_Object prefix;
2030
2031 prefix = Qnil;
2032 i = 0;
2033 while (i < menu_items_used)
2034 {
2035 Lisp_Object entry;
2036
2037 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2038 {
2039 prefix
2040 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2041 i += MENU_ITEMS_PANE_LENGTH;
2042 }
2043 else
2044 {
2045 entry
2046 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2047 if (menu_item_selection == i)
2048 {
2049 if (keymaps != 0)
2050 {
2051 entry = Fcons (entry, Qnil);
2052 if (!NILP (prefix))
2053 entry = Fcons (prefix, entry);
2054 }
2055 return entry;
2056 }
2057 i += MENU_ITEMS_ITEM_LENGTH;
2058 }
2059 }
2060 }
2061
2062 return Qnil;
2063}
2064
2065
2066/* Is this item a separator? */
2067static int
2068name_is_separator (name)
2069 char *name;
2070{
2071 /* Check if name string consists of only dashes ('-') */
2072 while (*name == '-') name++;
2073 return (*name == '\0');
2074}
2075
2076static void
2077add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent,
2078 int force_disable)
2079{
2080 Str255 item_name;
2081 int pos, i;
2082
2083 if (name_is_separator (wv->name))
2084 AppendMenu (menu, "\p-");
2085 else
2086 {
2087 AppendMenu (menu, "\pX");
2088
2089 pos = CountMItems (menu);
2090
2091 strcpy (item_name, "");
2092 for (i = 0; i < indent; i++)
2093 strcat (item_name, " ");
2094 strcat (item_name, wv->name);
2095 if (wv->key != NULL)
2096 {
2097 strcat (item_name, " ");
2098 strcat (item_name, wv->key);
2099 }
2100 c2pstr (item_name);
2101 SetMenuItemText (menu, pos, item_name);
2102
2103 if (wv->enabled && !force_disable)
2104 EnableItem (menu, pos);
2105 else
2106 DisableItem (menu, pos);
2107
2108 /* Draw radio buttons and tickboxes. */
2109 {
2110 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
2111 wv->button_type == BUTTON_TYPE_RADIO))
2112 SetItemMark (menu, pos, checkMark);
2113 else
2114 SetItemMark (menu, pos, noMark);
2115 }
2116 }
2117
2118 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
2119
2120 if (submenu != NULL)
2121 SetMenuItemHierarchicalID (menu, pos, submenu);
2122}
2123
2124static int submenu_id;
2125
2126/* Construct native Mac OS menubar based on widget_value tree. */
2127
2128static void
2129fill_submenu (MenuHandle menu, widget_value *wv, int indent)
2130{
2131 for ( ; wv != NULL; wv = wv->next)
2132 if (wv->contents)
2133 {
2134 add_menu_item (menu, wv, NULL, indent, 1);
2135
2136 fill_submenu (menu, wv->contents, indent + 1);
2137 }
2138 else
2139 add_menu_item (menu, wv, NULL, indent, 0);
2140}
2141
2142
2143/* Construct native Mac OS menu based on widget_value tree. */
2144
2145static void
2146fill_menu (MenuHandle menu, widget_value *wv)
2147{
2148 for ( ; wv != NULL; wv = wv->next)
2149 if (wv->contents)
2150 {
2151 MenuHandle submenu = NewMenu (submenu_id, "\pX");
2152 fill_submenu (submenu, wv->contents, 0);
2153 InsertMenu (submenu, -1);
2154 add_menu_item (menu, wv, submenu_id, 0, 0);
2155 submenu_id++;
2156 }
2157 else
2158 add_menu_item (menu, wv, NULL, 0, 0);
2159}
2160
2161/* Construct native Mac OS menubar based on widget_value tree. */
2162
2163static void
2164fill_menubar (widget_value *wv)
2165{
2166 int id;
2167
2168 submenu_id = MIN_SUBMENU_ID;
2169
2170 for (id = MIN_MENU_ID; wv != NULL; wv = wv->next, id++)
2171 {
2172 MenuHandle menu;
2173 Str255 title;
2174
2175 strcpy (title, wv->name);
2176 c2pstr (title);
2177 menu = NewMenu (id, title);
2178
2179 if (wv->contents)
2180 fill_menu (menu, wv->contents);
2181
2182 InsertMenu (menu, 0);
2183 }
2184}
2185
2186#endif /* HAVE_MENUS */
2187
2188void
2189syms_of_macmenu ()
2190{
2191 staticpro (&menu_items);
2192 menu_items = Qnil;
2193
2194 Qdebug_on_next_call = intern ("debug-on-next-call");
2195 staticpro (&Qdebug_on_next_call);
2196
2197 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
2198 "Frame for which we are updating a menu.\n\
2199The enable predicate for a menu command should check this variable.");
2200 Vmenu_updating_frame = Qnil;
2201
2202 defsubr (&Sx_popup_menu);
2203#ifdef HAVE_MENUS
2204 defsubr (&Sx_popup_dialog);
2205#endif
2206}
diff --git a/mac/src/macterm.c b/mac/src/macterm.c
deleted file mode 100644
index 3def0223a92..00000000000
--- a/mac/src/macterm.c
+++ /dev/null
@@ -1,12585 +0,0 @@
1/* Implementation of GUI terminal on the Mac OS.
2 Copyright (C) 2000 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */
22
23#include <config.h>
24
25/* On 4.3 these lose if they come after xterm.h. */
26/* Putting these at the beginning seems to be standard for other .c files. */
27#include <signal.h>
28
29#include <stdio.h>
30
31#include "lisp.h"
32#include "blockinput.h"
33
34/* Need syssignal.h for various externs and definitions that may be required
35 by some configurations for calls to signal later in this source file. */
36#include "syssignal.h"
37
38/* This may include sys/types.h, and that somehow loses
39 if this is not done before the other system files. */
40#include "macterm.h"
41
42#include <stdlib.h>
43#include <string.h>
44#include <alloca.h>
45
46#include <Quickdraw.h>
47#include <ToolUtils.h>
48#include <Sound.h>
49#include <Events.h>
50#include <Script.h>
51#include <Resources.h>
52#include <Fonts.h>
53#include <TextUtils.h>
54#include <LowMem.h>
55#include <Controls.h>
56#if defined (__MRC__) || defined (CODEWARRIOR_VERSION_6)
57#include <ControlDefinitions.h>
58#endif
59
60#if __profile__
61#include <profiler.h>
62#endif
63
64#include <sys/types.h>
65
66#include "systty.h"
67#include "systime.h"
68
69#ifndef INCLUDED_FCNTL
70#include <fcntl.h>
71#endif
72#include <ctype.h>
73#include <errno.h>
74#include <setjmp.h>
75#include <sys/stat.h>
76
77#include "charset.h"
78#include "ccl.h"
79#include "frame.h"
80#include "dispextern.h"
81#include "fontset.h"
82#include "termhooks.h"
83#include "termopts.h"
84#include "termchar.h"
85#include "gnu.h"
86#include "disptab.h"
87#include "buffer.h"
88#include "window.h"
89#include "keyboard.h"
90#include "intervals.h"
91#include "process.h"
92#include "atimer.h"
93#include "keymap.h"
94#include "coding.h"
95
96#ifdef HAVE_UNISTD_H
97#include <unistd.h>
98#endif
99
100#ifndef USE_X_TOOLKIT
101#define x_any_window_to_frame x_window_to_frame
102#define x_top_window_to_frame x_window_to_frame
103#endif
104
105#ifndef min
106#define min(a,b) ((a) < (b) ? (a) : (b))
107#endif
108#ifndef max
109#define max(a,b) ((a) > (b) ? (a) : (b))
110#endif
111
112#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
113
114
115/* Fringe bitmaps. */
116
117enum fringe_bitmap_type
118{
119 NO_FRINGE_BITMAP,
120 LEFT_TRUNCATION_BITMAP,
121 RIGHT_TRUNCATION_BITMAP,
122 OVERLAY_ARROW_BITMAP,
123 CONTINUED_LINE_BITMAP,
124 CONTINUATION_LINE_BITMAP,
125 ZV_LINE_BITMAP
126};
127
128/* Bitmap drawn to indicate lines not displaying text if
129 `indicate-empty-lines' is non-nil. */
130
131#define zv_width 8
132#define zv_height 72
133#define zv_period 3
134static unsigned char zv_bits[] = {
135 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
136 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
137 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
138 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
139 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
140 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
141 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
142 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
143
144/* An arrow like this: `<-'. */
145
146#define left_width 8
147#define left_height 8
148static unsigned char left_bits[] = {
149 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
150
151/* Right truncation arrow bitmap `->'. */
152
153#define right_width 8
154#define right_height 8
155static unsigned char right_bits[] = {
156 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
157
158/* Marker for continued lines. */
159
160#define continued_width 8
161#define continued_height 8
162static unsigned char continued_bits[] = {
163 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
164
165/* Marker for continuation lines. */
166
167#define continuation_width 8
168#define continuation_height 8
169static unsigned char continuation_bits[] = {
170 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
171
172/* Overlay arrow bitmap. */
173
174#if 0
175/* A bomb. */
176#define ov_width 8
177#define ov_height 8
178static unsigned char ov_bits[] = {
179 0x0c, 0x10, 0x3c, 0x7e, 0x5e, 0x5e, 0x46, 0x3c};
180#else
181/* A triangular arrow. */
182#define ov_width 8
183#define ov_height 8
184static unsigned char ov_bits[] = {
185 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0};
186#endif
187
188extern Lisp_Object Qhelp_echo;
189
190
191/* Non-zero means Emacs uses toolkit scroll bars. */
192
193int x_toolkit_scroll_bars_p;
194
195/* If a string, XTread_socket generates an event to display that string.
196 (The display is done in read_char.) */
197
198static Lisp_Object help_echo;
199static Lisp_Object help_echo_window;
200static Lisp_Object help_echo_object;
201static int help_echo_pos;
202
203/* Temporary variable for XTread_socket. */
204
205static Lisp_Object previous_help_echo;
206
207/* Non-zero means that a HELP_EVENT has been generated since Emacs
208 start. */
209
210static int any_help_event_p;
211
212/* Non-zero means draw block and hollow cursor as wide as the glyph
213 under it. For example, if a block cursor is over a tab, it will be
214 drawn as wide as that tab on the display. */
215
216int x_stretch_cursor_p;
217
218/* This is a chain of structures for all the X displays currently in
219 use. */
220
221struct x_display_info *x_display_list;
222
223/* This is a list of cons cells, each of the form (NAME
224 . FONT-LIST-CACHE), one for each element of x_display_list and in
225 the same order. NAME is the name of the frame. FONT-LIST-CACHE
226 records previous values returned by x-list-fonts. */
227
228Lisp_Object x_display_name_list;
229
230/* This is display since Mac does not support multiple ones. */
231struct mac_display_info one_mac_display_info;
232
233/* Frame being updated by update_frame. This is declared in term.c.
234 This is set by update_begin and looked at by all the XT functions.
235 It is zero while not inside an update. In that case, the XT
236 functions assume that `selected_frame' is the frame to apply to. */
237
238extern struct frame *updating_frame;
239
240/* This is a frame waiting to be auto-raised, within XTread_socket. */
241
242struct frame *pending_autoraise_frame;
243
244/* Nominal cursor position -- where to draw output.
245 HPOS and VPOS are window relative glyph matrix coordinates.
246 X and Y are window relative pixel coordinates. */
247
248struct cursor_pos output_cursor;
249
250/* Non-zero means user is interacting with a toolkit scroll bar. */
251
252static int toolkit_scroll_bar_interaction;
253
254/* Mouse movement.
255
256 Formerly, we used PointerMotionHintMask (in standard_event_mask)
257 so that we would have to call XQueryPointer after each MotionNotify
258 event to ask for another such event. However, this made mouse tracking
259 slow, and there was a bug that made it eventually stop.
260
261 Simply asking for MotionNotify all the time seems to work better.
262
263 In order to avoid asking for motion events and then throwing most
264 of them away or busy-polling the server for mouse positions, we ask
265 the server for pointer motion hints. This means that we get only
266 one event per group of mouse movements. "Groups" are delimited by
267 other kinds of events (focus changes and button clicks, for
268 example), or by XQueryPointer calls; when one of these happens, we
269 get another MotionNotify event the next time the mouse moves. This
270 is at least as efficient as getting motion events when mouse
271 tracking is on, and I suspect only negligibly worse when tracking
272 is off. */
273
274/* Where the mouse was last time we reported a mouse event. */
275
276FRAME_PTR last_mouse_frame;
277static Rect last_mouse_glyph;
278static Lisp_Object last_mouse_press_frame;
279
280/* The scroll bar in which the last X motion event occurred.
281
282 If the last X motion event occurred in a scroll bar, we set this so
283 XTmouse_position can know whether to report a scroll bar motion or
284 an ordinary motion.
285
286 If the last X motion event didn't occur in a scroll bar, we set
287 this to Qnil, to tell XTmouse_position to return an ordinary motion
288 event. */
289
290static Lisp_Object last_mouse_scroll_bar;
291
292/* This is a hack. We would really prefer that XTmouse_position would
293 return the time associated with the position it returns, but there
294 doesn't seem to be any way to wrest the time-stamp from the server
295 along with the position query. So, we just keep track of the time
296 of the last movement we received, and return that in hopes that
297 it's somewhat accurate. */
298
299static Time last_mouse_movement_time;
300
301enum mouse_tracking_type {
302 mouse_tracking_none,
303 mouse_tracking_mouse_movement,
304 mouse_tracking_scroll_bar
305};
306
307enum mouse_tracking_type mouse_tracking_in_progress = mouse_tracking_none;
308
309struct scroll_bar *tracked_scroll_bar = NULL;
310
311/* Incremented by XTread_socket whenever it really tries to read
312 events. */
313
314#ifdef __STDC__
315static int volatile input_signal_count;
316#else
317static int input_signal_count;
318#endif
319
320/* Used locally within XTread_socket. */
321
322static int x_noop_count;
323
324/* Initial values of argv and argc. */
325
326extern char **initial_argv;
327extern int initial_argc;
328
329extern Lisp_Object Vcommand_line_args, Vsystem_name;
330
331/* Tells if a window manager is present or not. */
332
333extern Lisp_Object Vx_no_window_manager;
334
335extern Lisp_Object Qface, Qmouse_face;
336
337extern int errno;
338
339/* A mask of extra modifier bits to put into every keyboard char. */
340
341extern int extra_keyboard_modifiers;
342
343static Lisp_Object Qvendor_specific_keysyms;
344
345#if 0
346extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
347#endif
348
349extern Lisp_Object x_icon_type P_ ((struct frame *));
350
351
352#if __MRC__
353QDGlobals qd; /* QuickDraw global information structure. */
354#endif
355
356
357/* Enumeration for overriding/changing the face to use for drawing
358 glyphs in x_draw_glyphs. */
359
360enum draw_glyphs_face
361{
362 DRAW_NORMAL_TEXT,
363 DRAW_INVERSE_VIDEO,
364 DRAW_CURSOR,
365 DRAW_MOUSE_FACE,
366 DRAW_IMAGE_RAISED,
367 DRAW_IMAGE_SUNKEN
368};
369
370struct frame * x_window_to_frame (struct mac_display_info *, WindowPtr);
371struct mac_display_info *mac_display_info_for_display (Display *);
372static void x_update_window_end P_ ((struct window *, int, int));
373static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
374void x_delete_display P_ ((struct x_display_info *));
375static unsigned int x_mac_to_emacs_modifiers P_ ((struct x_display_info *,
376 unsigned short));
377static int fast_find_position P_ ((struct window *, int, int *, int *,
378 int *, int *));
379static void set_output_cursor P_ ((struct cursor_pos *));
380static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
381 int *, int *, int *));
382static void note_mode_line_highlight P_ ((struct window *, int, int));
383static void note_mouse_highlight P_ ((struct frame *, int, int));
384static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
385static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
386static void show_mouse_face P_ ((struct x_display_info *,
387 enum draw_glyphs_face));
388void clear_mouse_face P_ ((struct mac_display_info *));
389static int x_io_error_quitter P_ ((Display *));
390int x_catch_errors P_ ((Display *));
391void x_uncatch_errors P_ ((Display *, int));
392void x_lower_frame P_ ((struct frame *));
393void x_scroll_bar_clear P_ ((struct frame *));
394int x_had_errors_p P_ ((Display *));
395void x_wm_set_size_hint P_ ((struct frame *, long, int));
396void x_raise_frame P_ ((struct frame *));
397void x_set_window_size P_ ((struct frame *, int, int, int));
398void x_wm_set_window_state P_ ((struct frame *, int));
399void x_wm_set_icon_pixmap P_ ((struct frame *, int));
400void x_initialize P_ ((void));
401static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
402static int x_compute_min_glyph_bounds P_ ((struct frame *));
403enum text_cursor_kinds x_specified_cursor_type P_ ((Lisp_Object, int *));
404static void x_draw_phys_cursor_glyph P_ ((struct window *,
405 struct glyph_row *,
406 enum draw_glyphs_face));
407static void x_update_end P_ ((struct frame *));
408static void XTframe_up_to_date P_ ((struct frame *));
409static void XTreassert_line_highlight P_ ((int, int));
410static void x_change_line_highlight P_ ((int, int, int, int));
411static void XTset_terminal_modes P_ ((void));
412static void XTreset_terminal_modes P_ ((void));
413static void XTcursor_to P_ ((int, int, int, int));
414static void x_write_glyphs P_ ((struct glyph *, int));
415static void x_clear_end_of_line P_ ((int));
416static void x_clear_frame P_ ((void));
417static void x_clear_cursor P_ ((struct window *));
418static void frame_highlight P_ ((struct frame *));
419static void frame_unhighlight P_ ((struct frame *));
420static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
421static void XTframe_rehighlight P_ ((struct frame *));
422static void x_frame_rehighlight P_ ((struct x_display_info *));
423static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
424static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
425static int x_intersect_rectangles P_ ((Rect *, Rect *, Rect *));
426static void expose_frame P_ ((struct frame *, int, int, int, int));
427static void expose_window_tree P_ ((struct window *, Rect *));
428static void expose_window P_ ((struct window *, Rect *));
429static void expose_area P_ ((struct window *, struct glyph_row *,
430 XRectangle *, enum glyph_row_area));
431static void expose_line P_ ((struct window *, struct glyph_row *,
432 XRectangle *));
433void x_display_cursor (struct window *, int, int, int, int, int);
434void x_update_cursor P_ ((struct frame *, int));
435static void x_update_cursor_in_window_tree P_ ((struct window *, int));
436static void x_update_window_cursor P_ ((struct window *, int));
437static void x_erase_phys_cursor P_ ((struct window *));
438void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
439static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *,
440 enum fringe_bitmap_type, int left_p));
441static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
442 GC, int));
443static int x_phys_cursor_in_rect_p P_ ((struct window *, Rect *));
444static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *));
445static void note_overwritten_text_cursor P_ ((struct window *, int, int));
446static void x_flush P_ ((struct frame *f));
447static void x_update_begin P_ ((struct frame *));
448static void x_update_window_begin P_ ((struct window *));
449static void x_draw_vertical_border P_ ((struct window *));
450static void x_after_update_window_line P_ ((struct glyph_row *));
451static INLINE void take_vertical_position_into_account P_ ((struct it *));
452static void x_produce_stretch_glyph P_ ((struct it *));
453
454static void activate_scroll_bars (FRAME_PTR);
455static void deactivate_scroll_bars (FRAME_PTR);
456
457extern int image_ascent (struct image *, struct face *);
458void x_set_offset (struct frame *, int, int, int);
459int x_bitmap_icon (struct frame *, Lisp_Object);
460void x_make_frame_visible (struct frame *);
461
462extern void window_scroll (Lisp_Object, int, int, int);
463
464/* Defined in macmenu.h. */
465extern void menubar_selection_callback (FRAME_PTR, int);
466extern void set_frame_menubar (FRAME_PTR, int, int);
467
468/* X display function emulation */
469
470/* Structure borrowed from Xlib.h to represent two-byte characters in
471 dumpglyphs. */
472
473typedef struct {
474 unsigned char byte1;
475 unsigned char byte2;
476} XChar2b;
477
478static void
479XFreePixmap (display, pixmap)
480 Display *display;
481 Pixmap pixmap;
482{
483 PixMap *p = (PixMap *) pixmap;
484
485 xfree (p->baseAddr);
486 xfree (p);
487}
488
489
490/* Set foreground color for subsequent QuickDraw commands. Assume
491 graphic port has already been set. */
492
493static void
494mac_set_forecolor (unsigned long color)
495{
496 RGBColor fg_color;
497
498 fg_color.red = RED_FROM_ULONG (color) * 256;
499 fg_color.green = GREEN_FROM_ULONG (color) * 256;
500 fg_color.blue = BLUE_FROM_ULONG (color) * 256;
501
502 RGBForeColor (&fg_color);
503}
504
505
506/* Set background color for subsequent QuickDraw commands. Assume
507 graphic port has already been set. */
508
509static void
510mac_set_backcolor (unsigned long color)
511{
512 RGBColor bg_color;
513
514 bg_color.red = RED_FROM_ULONG (color) * 256;
515 bg_color.green = GREEN_FROM_ULONG (color) * 256;
516 bg_color.blue = BLUE_FROM_ULONG (color) * 256;
517
518 RGBBackColor (&bg_color);
519}
520
521/* Set foreground and background color for subsequent QuickDraw
522 commands. Assume that the graphic port has already been set. */
523
524static void
525mac_set_colors (GC gc)
526{
527 mac_set_forecolor (gc->foreground);
528 mac_set_backcolor (gc->background);
529}
530
531/* Mac version of XDrawLine. */
532
533static void
534XDrawLine (display, w, gc, x1, y1, x2, y2)
535 Display *display;
536 WindowPtr w;
537 GC gc;
538 int x1, y1, x2, y2;
539{
540 SetPort (w);
541 mac_set_colors (gc);
542
543 MoveTo (x1, y1);
544 LineTo (x2, y2);
545}
546
547/* Mac version of XClearArea. */
548
549void
550XClearArea (display, w, x, y, width, height, exposures)
551 Display *display;
552 WindowPtr w;
553 int x, y;
554 unsigned int width, height;
555 int exposures;
556{
557 struct mac_output *mwp = (mac_output *) GetWRefCon (w);
558 Rect r;
559 XGCValues xgc;
560
561 xgc.foreground = mwp->foreground_pixel;
562 xgc.background = mwp->background_pixel;
563
564 SetPort (w);
565 mac_set_colors (&xgc);
566 SetRect (&r, x, y, x + width, y + height);
567
568 EraseRect (&r);
569}
570
571/* Mac version of XClearWindow. */
572
573static void
574XClearWindow (display, w)
575 Display *display;
576 WindowPtr w;
577{
578 struct mac_output *mwp = (mac_output *) GetWRefCon (w);
579 XGCValues xgc;
580
581 xgc.foreground = mwp->foreground_pixel;
582 xgc.background = mwp->background_pixel;
583
584 SetPort (w);
585 mac_set_colors (&xgc);
586
587 EraseRect (&(w->portRect));
588}
589
590
591/* Mac replacement for XCopyArea. */
592
593static void
594mac_draw_bitmap (display, w, gc, x, y, bitmap)
595 Display *display;
596 WindowPtr w;
597 GC gc;
598 int x, y;
599 BitMap *bitmap;
600{
601 Rect r;
602
603 SetPort (w);
604 mac_set_colors (gc);
605 SetRect (&r, x, y, x + bitmap->bounds.right, y + bitmap->bounds.bottom);
606
607 CopyBits (bitmap, &(w->portBits), &(bitmap->bounds), &r, srcCopy, 0);
608}
609
610
611/* Mac replacement for XSetClipRectangles. */
612
613static void
614mac_set_clip_rectangle (display, w, r)
615 Display *display;
616 WindowPtr w;
617 Rect *r;
618{
619 SetPort (w);
620
621 ClipRect (r);
622}
623
624
625/* Mac replacement for XSetClipMask. */
626
627static void
628mac_reset_clipping (display, w)
629 Display *display;
630 WindowPtr w;
631{
632 Rect r;
633
634 SetPort (w);
635
636 SetRect (&r, -32767, -32767, 32767, 32767);
637 ClipRect (&r);
638}
639
640
641/* Mac replacement for XCreateBitmapFromBitmapData. */
642
643static void
644mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
645 BitMap *bitmap;
646 char *bits;
647 int w, h;
648{
649 int bytes_per_row, i, j;
650
651 bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */
652 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
653 if (!bitmap->baseAddr)
654 abort ();
655
656 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
657 for (i = 0; i < h; i++)
658 for (j = 0; j < w; j++)
659 if (BitTst (bits, i * w + j))
660 BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j);
661
662 SetRect (&(bitmap->bounds), 0, 0, w, h);
663}
664
665
666static void
667mac_free_bitmap (bitmap)
668 BitMap *bitmap;
669{
670 xfree (bitmap->baseAddr);
671}
672
673/* Mac replacement for XFillRectangle. */
674
675static void
676XFillRectangle (display, w, gc, x, y, width, height)
677 Display *display;
678 WindowPtr w;
679 GC gc;
680 int x, y;
681 unsigned int width, height;
682{
683 Rect r;
684
685 SetPort (w);
686 mac_set_colors (gc);
687 SetRect (&r, x, y, x + width, y + height);
688
689 PaintRect (&r); /* using foreground color of gc */
690}
691
692
693/* Mac replacement for XDrawRectangle: dest is a window. */
694
695static void
696mac_draw_rectangle (display, w, gc, x, y, width, height)
697 Display *display;
698 WindowPtr w;
699 GC gc;
700 int x, y;
701 unsigned int width, height;
702{
703 Rect r;
704
705 SetPort (w);
706 mac_set_colors (gc);
707 SetRect (&r, x, y, x + width + 1, y + height + 1);
708
709 FrameRect (&r); /* using foreground color of gc */
710}
711
712
713/* Mac replacement for XDrawRectangle: dest is a Pixmap. */
714
715static void
716mac_draw_rectangle_to_pixmap (display, p, gc, x, y, width, height)
717 Display *display;
718 Pixmap p;
719 GC gc;
720 int x, y;
721 unsigned int width, height;
722{
723#if 0 /* MAC_TODO: draw a rectangle in a PixMap */
724 Rect r;
725
726 SetPort (w);
727 mac_set_colors (gc);
728 SetRect (&r, x, y, x + width, y + height);
729
730 FrameRect (&r); /* using foreground color of gc */
731#endif
732}
733
734
735static void
736mac_draw_string_common (display, w, gc, x, y, buf, nchars, mode,
737 bytes_per_char)
738 Display *display;
739 WindowPtr w;
740 GC gc;
741 int x, y;
742 char *buf;
743 int nchars, mode, bytes_per_char;
744{
745 SetPort (w);
746 mac_set_colors (gc);
747
748 TextFont (gc->font->mac_fontnum);
749 TextSize (gc->font->mac_fontsize);
750 TextFace (gc->font->mac_fontface);
751 TextMode (mode);
752
753 MoveTo (x, y);
754 DrawText (buf, 0, nchars * bytes_per_char);
755}
756
757
758/* Mac replacement for XDrawString. */
759
760static void
761XDrawString (display, w, gc, x, y, buf, nchars)
762 Display *display;
763 WindowPtr w;
764 GC gc;
765 int x, y;
766 char *buf;
767 int nchars;
768{
769 mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcOr, 1);
770}
771
772
773/* Mac replacement for XDrawString16. */
774
775static void
776XDrawString16 (display, w, gc, x, y, buf, nchars)
777 Display *display;
778 WindowPtr w;
779 GC gc;
780 int x, y;
781 XChar2b *buf;
782 int nchars;
783{
784 mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcOr,
785 2);
786}
787
788
789/* Mac replacement for XDrawImageString. */
790
791static void
792XDrawImageString (display, w, gc, x, y, buf, nchars)
793 Display *display;
794 WindowPtr w;
795 GC gc;
796 int x, y;
797 char *buf;
798 int nchars;
799{
800 mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcCopy, 1);
801}
802
803
804/* Mac replacement for XDrawString16. */
805
806static void
807XDrawImageString16 (display, w, gc, x, y, buf, nchars)
808 Display *display;
809 WindowPtr w;
810 GC gc;
811 int x, y;
812 XChar2b *buf;
813 int nchars;
814{
815 mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcCopy,
816 2);
817}
818
819
820/* Mac replacement for XCopyArea: dest must be window. */
821
822static void
823mac_copy_area (display, src, dest, gc, src_x, src_y, width, height, dest_x,
824 dest_y)
825 Display *display;
826 Pixmap src;
827 WindowPtr dest;
828 GC gc;
829 int src_x, src_y;
830 unsigned int width, height;
831 int dest_x, dest_y;
832{
833 Rect src_r, dest_r;
834
835 SetPort (dest);
836 mac_set_colors (gc);
837
838 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
839 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
840
841 CopyBits ((BitMap *) src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0);
842}
843
844
845#if 0
846/* Convert a pair of local coordinates to global (screen) coordinates.
847 Assume graphic port has been properly set. */
848static void
849local_to_global_coord (short *h, short *v)
850{
851 Point p;
852
853 p.h = *h;
854 p.v = *v;
855
856 LocalToGlobal (&p);
857
858 *h = p.h;
859 *v = p.v;
860}
861#endif
862
863/* Mac replacement for XCopyArea: used only for scrolling. */
864
865static void
866mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y)
867 Display *display;
868 WindowPtr w;
869 GC gc;
870 int src_x, src_y;
871 unsigned int width, height;
872 int dest_x, dest_y;
873{
874 Rect src_r, dest_r;
875
876 SetPort (w);
877#if 0
878 mac_set_colors (gc);
879#endif
880
881 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
882 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
883
884#if 0
885 /* Need to use global coordinates and screenBits since src and dest
886 areas overlap in general. */
887 local_to_global_coord (&src_r.left, &src_r.top);
888 local_to_global_coord (&src_r.right, &src_r.bottom);
889 local_to_global_coord (&dest_r.left, &dest_r.top);
890 local_to_global_coord (&dest_r.right, &dest_r.bottom);
891
892 CopyBits (&qd.screenBits, &qd.screenBits, &src_r, &dest_r, srcCopy, 0);
893#else
894 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid
895 color mapping in CopyBits. Otherwise, it will be slow. */
896 ForeColor (blackColor);
897 BackColor (whiteColor);
898 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0);
899
900 mac_set_colors (gc);
901#endif
902}
903
904
905/* Mac replacement for XCopyArea: dest must be Pixmap. */
906
907static void
908mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height,
909 dest_x, dest_y)
910 Display *display;
911 Pixmap src;
912 Pixmap dest;
913 GC gc;
914 int src_x, src_y;
915 unsigned int width, height;
916 int dest_x, dest_y;
917{
918 Rect src_r, dest_r;
919 int src_right = ((PixMap *) src)->bounds.right;
920 int src_bottom = ((PixMap *) src)->bounds.bottom;
921 int w = src_right - src_x;
922 int h = src_bottom - src_y;
923
924 mac_set_colors (gc);
925
926 SetRect (&src_r, src_x, src_y, src_right, src_bottom);
927 SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h);
928
929 CopyBits ((BitMap *) src, (BitMap *) dest, &src_r, &dest_r, srcCopy, 0);
930}
931
932
933/* Mac replacement for XChangeGC. */
934
935static void
936XChangeGC (void * ignore, XGCValues* gc, unsigned long mask,
937 XGCValues *xgcv)
938{
939 if (mask & GCForeground)
940 gc->foreground = xgcv->foreground;
941 if (mask & GCBackground)
942 gc->background = xgcv->background;
943 if (mask & GCFont)
944 gc->font = xgcv->font;
945}
946
947
948/* Mac replacement for XCreateGC. */
949
950XGCValues *
951XCreateGC (void * ignore, Window window, unsigned long mask,
952 XGCValues *xgcv)
953{
954 XGCValues *gc = (XGCValues *) xmalloc (sizeof (XGCValues));
955 bzero (gc, sizeof (XGCValues));
956
957 XChangeGC (ignore, gc, mask, xgcv);
958
959 return gc;
960}
961
962
963/* Used in xfaces.c. */
964
965void
966XFreeGC (display, gc)
967 Display *display;
968 GC gc;
969{
970 xfree (gc);
971}
972
973
974/* Mac replacement for XGetGCValues. */
975
976static void
977XGetGCValues (void* ignore, XGCValues *gc,
978 unsigned long mask, XGCValues *xgcv)
979{
980 XChangeGC (ignore, xgcv, mask, gc);
981}
982
983
984/* Mac replacement for XSetForeground. */
985
986static void
987XSetForeground (display, gc, color)
988 Display *display;
989 GC gc;
990 unsigned long color;
991{
992 gc->foreground = color;
993}
994
995
996/* Mac replacement for XSetFont. */
997
998static void
999XSetFont (display, gc, font)
1000 Display *display;
1001 GC gc;
1002 XFontStruct *font;
1003{
1004 gc->font = font;
1005}
1006
1007
1008static void
1009XTextExtents16 (XFontStruct *font, XChar2b *text, int nchars,
1010 int *direction,int *font_ascent,
1011 int *font_descent, XCharStruct *cs)
1012{
1013 /* MAC_TODO: Use GetTextMetrics to do this and inline it below. */
1014}
1015
1016
1017/* x_sync is a no-op on Mac. */
1018void
1019x_sync (f)
1020 void *f;
1021{
1022}
1023
1024
1025/* Flush display of frame F, or of all frames if F is null. */
1026
1027void
1028x_flush (f)
1029 struct frame *f;
1030{
1031#if 0 /* Nothing to do for Mac OS (needed in OS X perhaps?). */
1032 BLOCK_INPUT;
1033 if (f == NULL)
1034 {
1035 Lisp_Object rest, frame;
1036 FOR_EACH_FRAME (rest, frame)
1037 x_flush (XFRAME (frame));
1038 }
1039 else if (FRAME_X_P (f))
1040 XFlush (FRAME_MAC_DISPLAY (f));
1041 UNBLOCK_INPUT;
1042#endif
1043}
1044
1045
1046/* Remove calls to XFlush by defining XFlush to an empty replacement.
1047 Calls to XFlush should be unnecessary because the X output buffer
1048 is flushed automatically as needed by calls to XPending,
1049 XNextEvent, or XWindowEvent according to the XFlush man page.
1050 XTread_socket calls XPending. Removing XFlush improves
1051 performance. */
1052
1053#define XFlush(DISPLAY) (void) 0
1054
1055
1056/* Return the struct mac_display_info corresponding to DPY. There's
1057 only one. */
1058
1059struct mac_display_info *
1060mac_display_info_for_display (dpy)
1061 Display *dpy;
1062{
1063 return &one_mac_display_info;
1064}
1065
1066
1067
1068/***********************************************************************
1069 Starting and ending an update
1070 ***********************************************************************/
1071
1072/* Start an update of frame F. This function is installed as a hook
1073 for update_begin, i.e. it is called when update_begin is called.
1074 This function is called prior to calls to x_update_window_begin for
1075 each window being updated. Currently, there is nothing to do here
1076 because all interesting stuff is done on a window basis. */
1077
1078void
1079x_update_begin (f)
1080 struct frame *f;
1081{
1082 /* Nothing to do. */
1083}
1084
1085
1086/* Start update of window W. Set the global variable updated_window
1087 to the window being updated and set output_cursor to the cursor
1088 position of W. */
1089
1090void
1091x_update_window_begin (w)
1092 struct window *w;
1093{
1094 struct frame *f = XFRAME (WINDOW_FRAME (w));
1095 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
1096
1097 updated_window = w;
1098 set_output_cursor (&w->cursor);
1099
1100 BLOCK_INPUT;
1101
1102 if (f == display_info->mouse_face_mouse_frame)
1103 {
1104 /* Don't do highlighting for mouse motion during the update. */
1105 display_info->mouse_face_defer = 1;
1106
1107 /* If F needs to be redrawn, simply forget about any prior mouse
1108 highlighting. */
1109 if (FRAME_GARBAGED_P (f))
1110 display_info->mouse_face_window = Qnil;
1111
1112#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
1113 their mouse_face_p flag set, which means that they are always
1114 unequal to rows in a desired matrix which never have that
1115 flag set. So, rows containing mouse-face glyphs are never
1116 scrolled, and we don't have to switch the mouse highlight off
1117 here to prevent it from being scrolled. */
1118
1119 /* Can we tell that this update does not affect the window
1120 where the mouse highlight is? If so, no need to turn off.
1121 Likewise, don't do anything if the frame is garbaged;
1122 in that case, the frame's current matrix that we would use
1123 is all wrong, and we will redisplay that line anyway. */
1124 if (!NILP (display_info->mouse_face_window)
1125 && w == XWINDOW (display_info->mouse_face_window))
1126 {
1127 int i;
1128
1129 for (i = 0; i < w->desired_matrix->nrows; ++i)
1130 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
1131 break;
1132
1133 if (i < w->desired_matrix->nrows)
1134 clear_mouse_face (display_info);
1135 }
1136#endif /* 0 */
1137 }
1138
1139 UNBLOCK_INPUT;
1140}
1141
1142
1143/* Draw a vertical window border to the right of window W if W doesn't
1144 have vertical scroll bars. */
1145
1146static void
1147x_draw_vertical_border (w)
1148 struct window *w;
1149{
1150 struct frame *f = XFRAME (WINDOW_FRAME (w));
1151
1152 /* Redraw borders between horizontally adjacent windows. Don't
1153 do it for frames with vertical scroll bars because either the
1154 right scroll bar of a window, or the left scroll bar of its
1155 neighbor will suffice as a border. */
1156 if (!WINDOW_RIGHTMOST_P (w)
1157 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
1158 {
1159 int x0, x1, y0, y1;
1160
1161 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
1162 x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f);
1163 y1 -= 1;
1164
1165 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1166 f->output_data.mac->normal_gc, x1, y0, x1, y1);
1167 }
1168}
1169
1170
1171/* End update of window W (which is equal to updated_window).
1172
1173 Draw vertical borders between horizontally adjacent windows, and
1174 display W's cursor if CURSOR_ON_P is non-zero.
1175
1176 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
1177 glyphs in mouse-face were overwritten. In that case we have to
1178 make sure that the mouse-highlight is properly redrawn.
1179
1180 W may be a menu bar pseudo-window in case we don't have X toolkit
1181 support. Such windows don't have a cursor, so don't display it
1182 here. */
1183
1184void
1185x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
1186 struct window *w;
1187 int cursor_on_p, mouse_face_overwritten_p;
1188{
1189 if (!w->pseudo_window_p)
1190 {
1191 struct mac_display_info *dpyinfo
1192 = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
1193
1194 BLOCK_INPUT;
1195
1196 /* If a row with mouse-face was overwritten, arrange for
1197 XTframe_up_to_date to redisplay the mouse highlight. */
1198 if (mouse_face_overwritten_p)
1199 {
1200 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1201 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1202 dpyinfo->mouse_face_window = Qnil;
1203 }
1204
1205 if (cursor_on_p)
1206 x_display_and_set_cursor (w, 1, output_cursor.hpos,
1207 output_cursor.vpos,
1208 output_cursor.x, output_cursor.y);
1209
1210 x_draw_vertical_border (w);
1211 UNBLOCK_INPUT;
1212 }
1213
1214 updated_window = NULL;
1215}
1216
1217
1218/* End update of frame F. This function is installed as a hook in
1219 update_end. */
1220
1221void
1222x_update_end (f)
1223 struct frame *f;
1224{
1225 /* Reset the background color of Mac OS Window to that of the frame after
1226 update so that it is used by Mac Toolbox to clear the update region before
1227 an update event is generated. */
1228 SetPort (FRAME_MAC_WINDOW (f));
1229 mac_set_backcolor (FRAME_BACKGROUND_PIXEL (f));
1230
1231 /* Mouse highlight may be displayed again. */
1232 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
1233
1234 BLOCK_INPUT;
1235 XFlush (FRAME_MAC_DISPLAY (f));
1236 UNBLOCK_INPUT;
1237}
1238
1239
1240/* This function is called from various places in xdisp.c whenever a
1241 complete update has been performed. The global variable
1242 updated_window is not available here. */
1243
1244void
1245XTframe_up_to_date (f)
1246 struct frame *f;
1247{
1248 if (FRAME_X_P (f))
1249 {
1250 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1251
1252 if (dpyinfo->mouse_face_deferred_gc
1253 || f == dpyinfo->mouse_face_mouse_frame)
1254 {
1255 BLOCK_INPUT;
1256 if (dpyinfo->mouse_face_mouse_frame)
1257 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1258 dpyinfo->mouse_face_mouse_x,
1259 dpyinfo->mouse_face_mouse_y);
1260 dpyinfo->mouse_face_deferred_gc = 0;
1261 UNBLOCK_INPUT;
1262 }
1263 }
1264}
1265
1266
1267/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1268 arrow bitmaps, or clear the fringes if no bitmaps are required
1269 before DESIRED_ROW is made current. The window being updated is
1270 found in updated_window. This function It is called from
1271 update_window_line only if it is known that there are differences
1272 between bitmaps to be drawn between current row and DESIRED_ROW. */
1273
1274void
1275x_after_update_window_line (desired_row)
1276 struct glyph_row *desired_row;
1277{
1278 struct window *w = updated_window;
1279
1280 xassert (w);
1281
1282 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1283 {
1284 BLOCK_INPUT;
1285 x_draw_row_fringe_bitmaps (w, desired_row);
1286
1287 /* When a window has disappeared, make sure that no rest of
1288 full-width rows stays visible in the internal border. */
1289 if (windows_or_buffers_changed)
1290 {
1291 struct frame *f = XFRAME (w->frame);
1292 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
1293 int height = desired_row->visible_height;
1294 int x = (window_box_right (w, -1)
1295 + FRAME_X_RIGHT_FRINGE_WIDTH (f));
1296 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1297
1298 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1299 x, y, width, height, 0);
1300 }
1301
1302 UNBLOCK_INPUT;
1303 }
1304}
1305
1306
1307/* Draw the bitmap WHICH in one of the left or right fringes of
1308 window W. ROW is the glyph row for which to display the bitmap; it
1309 determines the vertical position at which the bitmap has to be
1310 drawn. */
1311
1312static void
1313x_draw_fringe_bitmap (w, row, which, left_p)
1314 struct window *w;
1315 struct glyph_row *row;
1316 enum fringe_bitmap_type which;
1317 int left_p;
1318{
1319 struct frame *f = XFRAME (WINDOW_FRAME (w));
1320 Display *display = FRAME_MAC_DISPLAY (f);
1321 WindowPtr window = FRAME_MAC_WINDOW (f);
1322 int x, y, wd, h, dy;
1323 int b1, b2;
1324 unsigned char *bits;
1325 BitMap bitmap;
1326 XGCValues gcv;
1327 struct face *face;
1328
1329 /* Must clip because of partially visible lines. */
1330 x_clip_to_row (w, row, 1);
1331
1332 /* Convert row to frame coordinates. */
1333 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
1334
1335 switch (which)
1336 {
1337 case NO_FRINGE_BITMAP:
1338 wd = 0;
1339 h = 0;
1340 break;
1341
1342 case LEFT_TRUNCATION_BITMAP:
1343 wd = left_width;
1344 h = left_height;
1345 bits = left_bits;
1346 break;
1347
1348 case OVERLAY_ARROW_BITMAP:
1349 wd = ov_width;
1350 h = ov_height;
1351 bits = ov_bits;
1352 break;
1353
1354 case RIGHT_TRUNCATION_BITMAP:
1355 wd = right_width;
1356 h = right_height;
1357 bits = right_bits;
1358 break;
1359
1360 case CONTINUED_LINE_BITMAP:
1361 wd = continued_width;
1362 h = continued_height;
1363 bits = continued_bits;
1364 break;
1365
1366 case CONTINUATION_LINE_BITMAP:
1367 wd = continuation_width;
1368 h = continuation_height;
1369 bits = continuation_bits;
1370 break;
1371
1372 case ZV_LINE_BITMAP:
1373 wd = zv_width;
1374 h = zv_height - (y % zv_period);
1375 bits = zv_bits + (y % zv_period);
1376 break;
1377
1378 default:
1379 abort ();
1380 }
1381
1382 /* Clip bitmap if too high. */
1383 if (h > row->height)
1384 h = row->height;
1385
1386 /* Set dy to the offset in the row to start drawing the bitmap. */
1387 dy = (row->height - h) / 2;
1388
1389 /* Draw the bitmap. I believe these small pixmaps can be cached
1390 by the server. */
1391 face = FACE_FROM_ID (f, FRINGE_FACE_ID);
1392 PREPARE_FACE_FOR_DISPLAY (f, face);
1393
1394 /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
1395 the fringe. */
1396 b1 = -1;
1397 if (left_p)
1398 {
1399 if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f))
1400 wd = FRAME_X_LEFT_FRINGE_WIDTH (f);
1401 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
1402 - wd
1403 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
1404 if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h)
1405 {
1406 /* If W has a vertical border to its left, don't draw over it. */
1407 int border = ((XFASTINT (w->left) > 0
1408 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
1409 ? 1 : 0);
1410 b1 = (window_box_left (w, -1)
1411 - FRAME_X_LEFT_FRINGE_WIDTH (f)
1412 + border);
1413 b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border);
1414 }
1415 }
1416 else
1417 {
1418 if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f))
1419 wd = FRAME_X_RIGHT_FRINGE_WIDTH (f);
1420 x = (window_box_right (w, -1)
1421 + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2);
1422 /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
1423 the fringe. */
1424 if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h)
1425 {
1426 b1 = window_box_right (w, -1);
1427 b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f);
1428 }
1429 }
1430
1431 if (b1 >= 0)
1432 {
1433 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
1434 XGCValues gcv;
1435 gcv.foreground = face->background;
1436
1437#if 0 /* MAC_TODO: stipple */
1438 /* In case the same realized face is used for fringes and
1439 for something displayed in the text (e.g. face `region' on
1440 mono-displays, the fill style may have been changed to
1441 FillSolid in x_draw_glyph_string_background. */
1442 if (face->stipple)
1443 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1444 else
1445 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
1446#endif
1447
1448 XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1449 &gcv,
1450 b1,
1451 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
1452 row->y)),
1453 b2,
1454 row->visible_height);
1455
1456#if 0 /* MAC_TODO: stipple */
1457 if (!face->stipple)
1458 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
1459#endif
1460 }
1461
1462 if (which == NO_FRINGE_BITMAP)
1463 return;
1464
1465 mac_create_bitmap_from_bitmap_data (&bitmap, bits, wd, h);
1466 gcv.foreground = face->foreground;
1467 gcv.background = face->background;
1468
1469 mac_draw_bitmap (display, window, &gcv, x, y + dy, &bitmap);
1470
1471 mac_free_bitmap (&bitmap);
1472 mac_reset_clipping (display, window);
1473}
1474
1475
1476/* Draw fringe bitmaps for glyph row ROW on window W. Call this
1477 function with input blocked. */
1478
1479static void
1480x_draw_row_fringe_bitmaps (w, row)
1481 struct window *w;
1482 struct glyph_row *row;
1483{
1484 struct frame *f = XFRAME (w->frame);
1485 enum fringe_bitmap_type bitmap;
1486
1487 xassert (interrupt_input_blocked);
1488
1489 /* If row is completely invisible, because of vscrolling, we
1490 don't have to draw anything. */
1491 if (row->visible_height <= 0)
1492 return;
1493
1494 if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0)
1495 {
1496 /* Decide which bitmap to draw in the left fringe. */
1497 if (row->overlay_arrow_p)
1498 bitmap = OVERLAY_ARROW_BITMAP;
1499 else if (row->truncated_on_left_p)
1500 bitmap = LEFT_TRUNCATION_BITMAP;
1501 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
1502 bitmap = CONTINUATION_LINE_BITMAP;
1503 else if (row->indicate_empty_line_p)
1504 bitmap = ZV_LINE_BITMAP;
1505 else
1506 bitmap = NO_FRINGE_BITMAP;
1507
1508 x_draw_fringe_bitmap (w, row, bitmap, 1);
1509 }
1510
1511 if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0)
1512 {
1513 /* Decide which bitmap to draw in the right fringe. */
1514 if (row->truncated_on_right_p)
1515 bitmap = RIGHT_TRUNCATION_BITMAP;
1516 else if (row->continued_p)
1517 bitmap = CONTINUED_LINE_BITMAP;
1518 else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0)
1519 bitmap = ZV_LINE_BITMAP;
1520 else
1521 bitmap = NO_FRINGE_BITMAP;
1522
1523 x_draw_fringe_bitmap (w, row, bitmap, 0);
1524 }
1525}
1526
1527
1528/***********************************************************************
1529 Line Highlighting
1530 ***********************************************************************/
1531
1532/* External interface to control of standout mode. Not used for X
1533 frames. Aborts when called. */
1534
1535void
1536XTreassert_line_highlight (new, vpos)
1537 int new, vpos;
1538{
1539 abort ();
1540}
1541
1542
1543/* Call this when about to modify line at position VPOS and change
1544 whether it is highlighted. Not used for X frames. Aborts when
1545 called. */
1546
1547void
1548x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1549 int new_highlight, vpos, y, first_unused_hpos;
1550{
1551 abort ();
1552}
1553
1554
1555/* This is called when starting Emacs and when restarting after
1556 suspend. When starting Emacs, no X window is mapped. And nothing
1557 must be done to Emacs's own window if it is suspended (though that
1558 rarely happens). */
1559
1560void
1561XTset_terminal_modes ()
1562{
1563}
1564
1565/* This is called when exiting or suspending Emacs. Exiting will make
1566 the X-windows go away, and suspending requires no action. */
1567
1568void
1569XTreset_terminal_modes ()
1570{
1571}
1572
1573
1574
1575/***********************************************************************
1576 Output Cursor
1577 ***********************************************************************/
1578
1579/* Set the global variable output_cursor to CURSOR. All cursor
1580 positions are relative to updated_window. */
1581
1582static void
1583set_output_cursor (cursor)
1584 struct cursor_pos *cursor;
1585{
1586 output_cursor.hpos = cursor->hpos;
1587 output_cursor.vpos = cursor->vpos;
1588 output_cursor.x = cursor->x;
1589 output_cursor.y = cursor->y;
1590}
1591
1592
1593/* Set a nominal cursor position.
1594
1595 HPOS and VPOS are column/row positions in a window glyph matrix. X
1596 and Y are window text area relative pixel positions.
1597
1598 If this is done during an update, updated_window will contain the
1599 window that is being updated and the position is the future output
1600 cursor position for that window. If updated_window is null, use
1601 selected_window and display the cursor at the given position. */
1602
1603void
1604XTcursor_to (vpos, hpos, y, x)
1605 int vpos, hpos, y, x;
1606{
1607 struct window *w;
1608
1609 /* If updated_window is not set, work on selected_window. */
1610 if (updated_window)
1611 w = updated_window;
1612 else
1613 w = XWINDOW (selected_window);
1614
1615 /* Set the output cursor. */
1616 output_cursor.hpos = hpos;
1617 output_cursor.vpos = vpos;
1618 output_cursor.x = x;
1619 output_cursor.y = y;
1620
1621 /* If not called as part of an update, really display the cursor.
1622 This will also set the cursor position of W. */
1623 if (updated_window == NULL)
1624 {
1625 BLOCK_INPUT;
1626 x_display_cursor (w, 1, hpos, vpos, x, y);
1627 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
1628 UNBLOCK_INPUT;
1629 }
1630}
1631
1632
1633
1634/***********************************************************************
1635 Display Iterator
1636 ***********************************************************************/
1637
1638/* Function prototypes of this page. */
1639
1640static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1641 struct glyph *,
1642 XChar2b *,
1643 int *));
1644static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1645 int, XChar2b *, int));
1646static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1647static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1648static void x_append_glyph P_ ((struct it *));
1649static void x_append_composite_glyph P_ ((struct it *));
1650static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1651 int, int, double));
1652static void x_produce_glyphs P_ ((struct it *));
1653static void x_produce_image_glyph P_ ((struct it *it));
1654
1655
1656/* Return a pointer to per-char metric information in FONT of a
1657 character pointed by B which is a pointer to an XChar2b. */
1658
1659#define PER_CHAR_METRIC(font, b) \
1660 ((font)->per_char \
1661 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1662 + (((font)->min_byte1 || (font)->max_byte1) \
1663 ? (((b)->byte1 - (font)->min_byte1) \
1664 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1665 : 0)) \
1666 : &((font)->max_bounds))
1667
1668
1669/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1670 is not contained in the font. */
1671
1672static INLINE XCharStruct *
1673x_per_char_metric (font, char2b)
1674 XFontStruct *font;
1675 XChar2b *char2b;
1676{
1677 /* The result metric information. */
1678 XCharStruct *pcm = NULL;
1679
1680 xassert (font && char2b);
1681
1682 if (font->per_char != NULL)
1683 {
1684 if (font->min_byte1 == 0 && font->max_byte1 == 0)
1685 {
1686 /* min_char_or_byte2 specifies the linear character index
1687 corresponding to the first element of the per_char array,
1688 max_char_or_byte2 is the index of the last character. A
1689 character with non-zero CHAR2B->byte1 is not in the font.
1690 A character with byte2 less than min_char_or_byte2 or
1691 greater max_char_or_byte2 is not in the font. */
1692 if (char2b->byte1 == 0
1693 && char2b->byte2 >= font->min_char_or_byte2
1694 && char2b->byte2 <= font->max_char_or_byte2)
1695 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
1696 }
1697 else
1698 {
1699 /* If either min_byte1 or max_byte1 are nonzero, both
1700 min_char_or_byte2 and max_char_or_byte2 are less than
1701 256, and the 2-byte character index values corresponding
1702 to the per_char array element N (counting from 0) are:
1703
1704 byte1 = N/D + min_byte1
1705 byte2 = N\D + min_char_or_byte2
1706
1707 where:
1708
1709 D = max_char_or_byte2 - min_char_or_byte2 + 1
1710 / = integer division
1711 \ = integer modulus */
1712 if (char2b->byte1 >= font->min_byte1
1713 && char2b->byte1 <= font->max_byte1
1714 && char2b->byte2 >= font->min_char_or_byte2
1715 && char2b->byte2 <= font->max_char_or_byte2)
1716 {
1717 pcm = (font->per_char
1718 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1719 * (char2b->byte1 - font->min_byte1))
1720 + (char2b->byte2 - font->min_char_or_byte2));
1721 }
1722 }
1723 }
1724 else
1725 {
1726 /* If the per_char pointer is null, all glyphs between the first
1727 and last character indexes inclusive have the same
1728 information, as given by both min_bounds and max_bounds. */
1729 if (char2b->byte2 >= font->min_char_or_byte2
1730 && char2b->byte2 <= font->max_char_or_byte2)
1731 pcm = &font->max_bounds;
1732 }
1733
1734 return ((pcm == NULL
1735 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
1736 ? NULL : pcm);
1737}
1738
1739
1740/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1741 the two-byte form of C. Encoding is returned in *CHAR2B. */
1742
1743static INLINE void
1744x_encode_char (c, char2b, font_info)
1745 int c;
1746 XChar2b *char2b;
1747 struct font_info *font_info;
1748{
1749 int charset = CHAR_CHARSET (c);
1750 XFontStruct *font = font_info->font;
1751
1752 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1753 This may be either a program in a special encoder language or a
1754 fixed encoding. */
1755 if (font_info->font_encoder)
1756 {
1757 /* It's a program. */
1758 struct ccl_program *ccl = font_info->font_encoder;
1759
1760 if (CHARSET_DIMENSION (charset) == 1)
1761 {
1762 ccl->reg[0] = charset;
1763 ccl->reg[1] = char2b->byte2;
1764 }
1765 else
1766 {
1767 ccl->reg[0] = charset;
1768 ccl->reg[1] = char2b->byte1;
1769 ccl->reg[2] = char2b->byte2;
1770 }
1771
1772 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1773
1774 /* We assume that MSBs are appropriately set/reset by CCL
1775 program. */
1776 if (font->max_byte1 == 0) /* 1-byte font */
1777 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
1778 else
1779 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1780 }
1781 else if (font_info->encoding[charset])
1782 {
1783 /* Fixed encoding scheme. See fontset.h for the meaning of the
1784 encoding numbers. */
1785 int enc = font_info->encoding[charset];
1786
1787 if ((enc == 1 || enc == 2)
1788 && CHARSET_DIMENSION (charset) == 2)
1789 char2b->byte1 |= 0x80;
1790
1791 if (enc == 1 || enc == 3)
1792 char2b->byte2 |= 0x80;
1793
1794 if (enc == 4)
1795 {
1796 int sjis1, sjis2;
1797
1798 ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2);
1799 char2b->byte1 = sjis1;
1800 char2b->byte2 = sjis2;
1801 }
1802 }
1803}
1804
1805
1806/* Get face and two-byte form of character C in face FACE_ID on frame
1807 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1808 means we want to display multibyte text. Value is a pointer to a
1809 realized face that is ready for display. */
1810
1811static INLINE struct face *
1812x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1813 struct frame *f;
1814 int c, face_id;
1815 XChar2b *char2b;
1816 int multibyte_p;
1817{
1818 struct face *face = FACE_FROM_ID (f, face_id);
1819
1820 if (!multibyte_p)
1821 {
1822 /* Unibyte case. We don't have to encode, but we have to make
1823 sure to use a face suitable for unibyte. */
1824 char2b->byte1 = 0;
1825 char2b->byte2 = c;
1826 face_id = FACE_FOR_CHAR (f, face, c);
1827 face = FACE_FROM_ID (f, face_id);
1828 }
1829 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1830 {
1831 /* Case of ASCII in a face known to fit ASCII. */
1832 char2b->byte1 = 0;
1833 char2b->byte2 = c;
1834 }
1835 else
1836 {
1837 int c1, c2, charset;
1838
1839 /* Split characters into bytes. If c2 is -1 afterwards, C is
1840 really a one-byte character so that byte1 is zero. */
1841 SPLIT_CHAR (c, charset, c1, c2);
1842 if (c2 > 0)
1843 char2b->byte1 = c1, char2b->byte2 = c2;
1844 else
1845 char2b->byte1 = 0, char2b->byte2 = c1;
1846
1847 /* Maybe encode the character in *CHAR2B. */
1848 if (face->font != NULL)
1849 {
1850 struct font_info *font_info
1851 = FONT_INFO_FROM_ID (f, face->font_info_id);
1852 if (font_info)
1853 x_encode_char (c, char2b, font_info);
1854 }
1855 }
1856
1857 /* Make sure X resources of the face are allocated. */
1858 xassert (face != NULL);
1859 PREPARE_FACE_FOR_DISPLAY (f, face);
1860
1861 return face;
1862}
1863
1864
1865/* Get face and two-byte form of character glyph GLYPH on frame F.
1866 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
1867 a pointer to a realized face that is ready for display. */
1868
1869static INLINE struct face *
1870x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
1871 struct frame *f;
1872 struct glyph *glyph;
1873 XChar2b *char2b;
1874 int *two_byte_p;
1875{
1876 struct face *face;
1877
1878 xassert (glyph->type == CHAR_GLYPH);
1879 face = FACE_FROM_ID (f, glyph->face_id);
1880
1881 if (two_byte_p)
1882 *two_byte_p = 0;
1883
1884 if (!glyph->multibyte_p)
1885 {
1886 /* Unibyte case. We don't have to encode, but we have to make
1887 sure to use a face suitable for unibyte. */
1888 char2b->byte1 = 0;
1889 char2b->byte2 = glyph->u.ch;
1890 }
1891 else if (glyph->u.ch < 128
1892 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
1893 {
1894 /* Case of ASCII in a face known to fit ASCII. */
1895 char2b->byte1 = 0;
1896 char2b->byte2 = glyph->u.ch;
1897 }
1898 else
1899 {
1900 int c1, c2, charset;
1901
1902 /* Split characters into bytes. If c2 is -1 afterwards, C is
1903 really a one-byte character so that byte1 is zero. */
1904 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
1905 if (c2 > 0)
1906 char2b->byte1 = c1, char2b->byte2 = c2;
1907 else
1908 char2b->byte1 = 0, char2b->byte2 = c1;
1909
1910 /* Maybe encode the character in *CHAR2B. */
1911 if (charset != CHARSET_ASCII)
1912 {
1913 struct font_info *font_info
1914 = FONT_INFO_FROM_ID (f, face->font_info_id);
1915 if (font_info)
1916 {
1917 x_encode_char (glyph->u.ch, char2b, font_info);
1918 if (two_byte_p)
1919 *two_byte_p
1920 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
1921 }
1922 }
1923 }
1924
1925 /* Make sure X resources of the face are allocated. */
1926 xassert (face != NULL);
1927 PREPARE_FACE_FOR_DISPLAY (f, face);
1928 return face;
1929}
1930
1931
1932/* Store one glyph for IT->char_to_display in IT->glyph_row.
1933 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1934
1935static INLINE void
1936x_append_glyph (it)
1937 struct it *it;
1938{
1939 struct glyph *glyph;
1940 enum glyph_row_area area = it->area;
1941
1942 xassert (it->glyph_row);
1943 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1944
1945 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1946 if (glyph < it->glyph_row->glyphs[area + 1])
1947 {
1948 glyph->charpos = CHARPOS (it->position);
1949 glyph->object = it->object;
1950 glyph->pixel_width = it->pixel_width;
1951 glyph->voffset = it->voffset;
1952 glyph->type = CHAR_GLYPH;
1953 glyph->multibyte_p = it->multibyte_p;
1954 glyph->left_box_line_p = it->start_of_box_run_p;
1955 glyph->right_box_line_p = it->end_of_box_run_p;
1956 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1957 || it->phys_descent > it->descent);
1958 glyph->padding_p = 0;
1959 glyph->glyph_not_available_p = it->glyph_not_available_p;
1960 glyph->face_id = it->face_id;
1961 glyph->u.ch = it->char_to_display;
1962 ++it->glyph_row->used[area];
1963 }
1964}
1965
1966/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1967 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1968
1969static INLINE void
1970x_append_composite_glyph (it)
1971 struct it *it;
1972{
1973 struct glyph *glyph;
1974 enum glyph_row_area area = it->area;
1975
1976 xassert (it->glyph_row);
1977
1978 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1979 if (glyph < it->glyph_row->glyphs[area + 1])
1980 {
1981 glyph->charpos = CHARPOS (it->position);
1982 glyph->object = it->object;
1983 glyph->pixel_width = it->pixel_width;
1984 glyph->voffset = it->voffset;
1985 glyph->type = COMPOSITE_GLYPH;
1986 glyph->multibyte_p = it->multibyte_p;
1987 glyph->left_box_line_p = it->start_of_box_run_p;
1988 glyph->right_box_line_p = it->end_of_box_run_p;
1989 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1990 || it->phys_descent > it->descent);
1991 glyph->padding_p = 0;
1992 glyph->glyph_not_available_p = 0;
1993 glyph->face_id = it->face_id;
1994 glyph->u.cmp_id = it->cmp_id;
1995 ++it->glyph_row->used[area];
1996 }
1997}
1998
1999
2000/* Change IT->ascent and IT->height according to the setting of
2001 IT->voffset. */
2002
2003static INLINE void
2004take_vertical_position_into_account (it)
2005 struct it *it;
2006{
2007 if (it->voffset)
2008 {
2009 if (it->voffset < 0)
2010 /* Increase the ascent so that we can display the text higher
2011 in the line. */
2012 it->ascent += abs (it->voffset);
2013 else
2014 /* Increase the descent so that we can display the text lower
2015 in the line. */
2016 it->descent += it->voffset;
2017 }
2018}
2019
2020
2021/* Produce glyphs/get display metrics for the image IT is loaded with.
2022 See the description of struct display_iterator in dispextern.h for
2023 an overview of struct display_iterator. */
2024
2025static void
2026x_produce_image_glyph (it)
2027 struct it *it;
2028{
2029 struct image *img;
2030 struct face *face;
2031
2032 xassert (it->what == IT_IMAGE);
2033
2034 face = FACE_FROM_ID (it->f, it->face_id);
2035 img = IMAGE_FROM_ID (it->f, it->image_id);
2036 xassert (img);
2037
2038 /* Make sure X resources of the face and image are loaded. */
2039 PREPARE_FACE_FOR_DISPLAY (it->f, face);
2040 prepare_image_for_display (it->f, img);
2041
2042 it->ascent = it->phys_ascent = image_ascent (img, face);
2043 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
2044 it->pixel_width = img->width + 2 * img->hmargin;
2045
2046 it->nglyphs = 1;
2047
2048 if (face->box != FACE_NO_BOX)
2049 {
2050 it->ascent += face->box_line_width;
2051 it->descent += face->box_line_width;
2052
2053 if (it->start_of_box_run_p)
2054 it->pixel_width += face->box_line_width;
2055 if (it->end_of_box_run_p)
2056 it->pixel_width += face->box_line_width;
2057 }
2058
2059 take_vertical_position_into_account (it);
2060
2061 if (it->glyph_row)
2062 {
2063 struct glyph *glyph;
2064 enum glyph_row_area area = it->area;
2065
2066 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
2067 if (glyph < it->glyph_row->glyphs[area + 1])
2068 {
2069 glyph->charpos = CHARPOS (it->position);
2070 glyph->object = it->object;
2071 glyph->pixel_width = it->pixel_width;
2072 glyph->voffset = it->voffset;
2073 glyph->type = IMAGE_GLYPH;
2074 glyph->multibyte_p = it->multibyte_p;
2075 glyph->left_box_line_p = it->start_of_box_run_p;
2076 glyph->right_box_line_p = it->end_of_box_run_p;
2077 glyph->overlaps_vertically_p = 0;
2078 glyph->padding_p = 0;
2079 glyph->glyph_not_available_p = 0;
2080 glyph->face_id = it->face_id;
2081 glyph->u.img_id = img->id;
2082 ++it->glyph_row->used[area];
2083 }
2084 }
2085}
2086
2087
2088/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
2089 of the glyph, WIDTH and HEIGHT are the width and height of the
2090 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
2091 ascent of the glyph (0 <= ASCENT <= 1). */
2092
2093static void
2094x_append_stretch_glyph (it, object, width, height, ascent)
2095 struct it *it;
2096 Lisp_Object object;
2097 int width, height;
2098 double ascent;
2099{
2100 struct glyph *glyph;
2101 enum glyph_row_area area = it->area;
2102
2103 xassert (ascent >= 0 && ascent <= 1);
2104
2105 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
2106 if (glyph < it->glyph_row->glyphs[area + 1])
2107 {
2108 glyph->charpos = CHARPOS (it->position);
2109 glyph->object = object;
2110 glyph->pixel_width = width;
2111 glyph->voffset = it->voffset;
2112 glyph->type = STRETCH_GLYPH;
2113 glyph->multibyte_p = it->multibyte_p;
2114 glyph->left_box_line_p = it->start_of_box_run_p;
2115 glyph->right_box_line_p = it->end_of_box_run_p;
2116 glyph->overlaps_vertically_p = 0;
2117 glyph->padding_p = 0;
2118 glyph->glyph_not_available_p = 0;
2119 glyph->face_id = it->face_id;
2120 glyph->u.stretch.ascent = height * ascent;
2121 glyph->u.stretch.height = height;
2122 ++it->glyph_row->used[area];
2123 }
2124}
2125
2126
2127/* Produce a stretch glyph for iterator IT. IT->object is the value
2128 of the glyph property displayed. The value must be a list
2129 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
2130 being recognized:
2131
2132 1. `:width WIDTH' specifies that the space should be WIDTH *
2133 canonical char width wide. WIDTH may be an integer or floating
2134 point number.
2135
2136 2. `:relative-width FACTOR' specifies that the width of the stretch
2137 should be computed from the width of the first character having the
2138 `glyph' property, and should be FACTOR times that width.
2139
2140 3. `:align-to HPOS' specifies that the space should be wide enough
2141 to reach HPOS, a value in canonical character units.
2142
2143 Exactly one of the above pairs must be present.
2144
2145 4. `:height HEIGHT' specifies that the height of the stretch produced
2146 should be HEIGHT, measured in canonical character units.
2147
2148 5. `:relative-height FACTOR' specifies that the height of the stretch
2149 should be FACTOR times the height of the characters having the glyph
2150 property.
2151
2152 Either none or exactly one of 4 or 5 must be present.
2153
2154 6. `:ascent ASCENT' specifies that ASCENT percent of the height
2155 of the stretch should be used for the ascent of the stretch.
2156 ASCENT must be in the range 0 <= ASCENT <= 100. */
2157
2158#define NUMVAL(X) \
2159 ((INTEGERP (X) || FLOATP (X)) \
2160 ? XFLOATINT (X) \
2161 : - 1)
2162
2163
2164static void
2165x_produce_stretch_glyph (it)
2166 struct it *it;
2167{
2168 /* (space :width WIDTH :height HEIGHT. */
2169#if GLYPH_DEBUG
2170 extern Lisp_Object Qspace;
2171#endif
2172 extern Lisp_Object QCwidth, QCheight, QCascent;
2173 extern Lisp_Object QCrelative_width, QCrelative_height;
2174 extern Lisp_Object QCalign_to;
2175 Lisp_Object prop, plist;
2176 double width = 0, height = 0, ascent = 0;
2177 struct face *face = FACE_FROM_ID (it->f, it->face_id);
2178 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
2179
2180 PREPARE_FACE_FOR_DISPLAY (it->f, face);
2181
2182 /* List should start with `space'. */
2183 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
2184 plist = XCDR (it->object);
2185
2186 /* Compute the width of the stretch. */
2187 if (prop = Fplist_get (plist, QCwidth),
2188 NUMVAL (prop) > 0)
2189 /* Absolute width `:width WIDTH' specified and valid. */
2190 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
2191 else if (prop = Fplist_get (plist, QCrelative_width),
2192 NUMVAL (prop) > 0)
2193 {
2194 /* Relative width `:relative-width FACTOR' specified and valid.
2195 Compute the width of the characters having the `glyph'
2196 property. */
2197 struct it it2;
2198 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
2199
2200 it2 = *it;
2201 if (it->multibyte_p)
2202 {
2203 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
2204 - IT_BYTEPOS (*it));
2205 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
2206 }
2207 else
2208 it2.c = *p, it2.len = 1;
2209
2210 it2.glyph_row = NULL;
2211 it2.what = IT_CHARACTER;
2212 x_produce_glyphs (&it2);
2213 width = NUMVAL (prop) * it2.pixel_width;
2214 }
2215 else if (prop = Fplist_get (plist, QCalign_to),
2216 NUMVAL (prop) > 0)
2217 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
2218 else
2219 /* Nothing specified -> width defaults to canonical char width. */
2220 width = CANON_X_UNIT (it->f);
2221
2222 /* Compute height. */
2223 if (prop = Fplist_get (plist, QCheight),
2224 NUMVAL (prop) > 0)
2225 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
2226 else if (prop = Fplist_get (plist, QCrelative_height),
2227 NUMVAL (prop) > 0)
2228 height = FONT_HEIGHT (font) * NUMVAL (prop);
2229 else
2230 height = FONT_HEIGHT (font);
2231
2232 /* Compute percentage of height used for ascent. If
2233 `:ascent ASCENT' is present and valid, use that. Otherwise,
2234 derive the ascent from the font in use. */
2235 if (prop = Fplist_get (plist, QCascent),
2236 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
2237 ascent = NUMVAL (prop) / 100.0;
2238 else
2239 ascent = (double) font->ascent / FONT_HEIGHT (font);
2240
2241 if (width <= 0)
2242 width = 1;
2243 if (height <= 0)
2244 height = 1;
2245
2246 if (it->glyph_row)
2247 {
2248 Lisp_Object object = it->stack[it->sp - 1].string;
2249 if (!STRINGP (object))
2250 object = it->w->buffer;
2251 x_append_stretch_glyph (it, object, width, height, ascent);
2252 }
2253
2254 it->pixel_width = width;
2255 it->ascent = it->phys_ascent = height * ascent;
2256 it->descent = it->phys_descent = height - it->ascent;
2257 it->nglyphs = 1;
2258
2259 if (face->box != FACE_NO_BOX)
2260 {
2261 it->ascent += face->box_line_width;
2262 it->descent += face->box_line_width;
2263
2264 if (it->start_of_box_run_p)
2265 it->pixel_width += face->box_line_width;
2266 if (it->end_of_box_run_p)
2267 it->pixel_width += face->box_line_width;
2268 }
2269
2270 take_vertical_position_into_account (it);
2271}
2272
2273/* Return proper value to be used as baseline offset of font that has
2274 ASCENT and DESCENT to draw characters by the font at the vertical
2275 center of the line of frame F.
2276
2277 Here, out task is to find the value of BOFF in the following figure;
2278
2279 -------------------------+-----------+-
2280 -+-+---------+-+ | |
2281 | | | | | |
2282 | | | | F_ASCENT F_HEIGHT
2283 | | | ASCENT | |
2284 HEIGHT | | | | |
2285 | | |-|-+------+-----------|------- baseline
2286 | | | | BOFF | |
2287 | |---------|-+-+ | |
2288 | | | DESCENT | |
2289 -+-+---------+-+ F_DESCENT |
2290 -------------------------+-----------+-
2291
2292 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
2293 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
2294 DESCENT = FONT->descent
2295 HEIGHT = FONT_HEIGHT (FONT)
2296 F_DESCENT = (F->output_data.x->font->descent
2297 - F->output_data.x->baseline_offset)
2298 F_HEIGHT = FRAME_LINE_HEIGHT (F)
2299*/
2300
2301#define VCENTER_BASELINE_OFFSET(FONT, F) \
2302 ((FONT)->descent \
2303 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
2304 - ((F)->output_data.mac->font->descent - (F)->output_data.mac->baseline_offset))
2305
2306/* Produce glyphs/get display metrics for the display element IT is
2307 loaded with. See the description of struct display_iterator in
2308 dispextern.h for an overview of struct display_iterator. */
2309
2310void
2311x_produce_glyphs (it)
2312 struct it *it;
2313{
2314 it->glyph_not_available_p = 0;
2315
2316 if (it->what == IT_CHARACTER)
2317 {
2318 XChar2b char2b;
2319 XFontStruct *font;
2320 struct face *face = FACE_FROM_ID (it->f, it->face_id);
2321 XCharStruct *pcm;
2322 int font_not_found_p;
2323 struct font_info *font_info;
2324 int boff; /* baseline offset */
2325
2326 /* Maybe translate single-byte characters to multibyte, or the
2327 other way. */
2328 it->char_to_display = it->c;
2329 if (!ASCII_BYTE_P (it->c))
2330 {
2331 if (unibyte_display_via_language_environment
2332 && SINGLE_BYTE_CHAR_P (it->c)
2333 && (it->c >= 0240
2334 || !NILP (Vnonascii_translation_table)))
2335 {
2336 it->char_to_display = unibyte_char_to_multibyte (it->c);
2337 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2338 face = FACE_FROM_ID (it->f, it->face_id);
2339 }
2340 else if (!SINGLE_BYTE_CHAR_P (it->c)
2341 && !it->multibyte_p)
2342 {
2343 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
2344 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2345 face = FACE_FROM_ID (it->f, it->face_id);
2346 }
2347 }
2348
2349 /* Get font to use. Encode IT->char_to_display. */
2350 x_get_char_face_and_encoding (it->f, it->char_to_display,
2351 it->face_id, &char2b,
2352 it->multibyte_p);
2353 font = face->font;
2354
2355 /* When no suitable font found, use the default font. */
2356 font_not_found_p = font == NULL;
2357 if (font_not_found_p)
2358 {
2359 font = FRAME_FONT (it->f);
2360 boff = it->f->output_data.mac->baseline_offset;
2361 font_info = NULL;
2362 }
2363 else
2364 {
2365 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2366 boff = font_info->baseline_offset;
2367 if (font_info->vertical_centering)
2368 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2369 }
2370
2371 if (it->char_to_display >= ' '
2372 && (!it->multibyte_p || it->char_to_display < 128))
2373 {
2374 /* Either unibyte or ASCII. */
2375 int stretched_p;
2376
2377 it->nglyphs = 1;
2378
2379 pcm = x_per_char_metric (font, &char2b);
2380 it->ascent = font->ascent + boff;
2381 it->descent = font->descent - boff;
2382
2383 if (pcm)
2384 {
2385 it->phys_ascent = pcm->ascent + boff;
2386 it->phys_descent = pcm->descent - boff;
2387 it->pixel_width = pcm->width;
2388 }
2389 else
2390 {
2391 it->glyph_not_available_p = 1;
2392 it->phys_ascent = font->ascent + boff;
2393 it->phys_descent = font->descent - boff;
2394 it->pixel_width = FONT_WIDTH (font);
2395 }
2396
2397 /* If this is a space inside a region of text with
2398 `space-width' property, change its width. */
2399 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
2400 if (stretched_p)
2401 it->pixel_width *= XFLOATINT (it->space_width);
2402
2403 /* If face has a box, add the box thickness to the character
2404 height. If character has a box line to the left and/or
2405 right, add the box line width to the character's width. */
2406 if (face->box != FACE_NO_BOX)
2407 {
2408 int thick = face->box_line_width;
2409
2410 it->ascent += thick;
2411 it->descent += thick;
2412
2413 if (it->start_of_box_run_p)
2414 it->pixel_width += thick;
2415 if (it->end_of_box_run_p)
2416 it->pixel_width += thick;
2417 }
2418
2419 /* If face has an overline, add the height of the overline
2420 (1 pixel) and a 1 pixel margin to the character height. */
2421 if (face->overline_p)
2422 it->ascent += 2;
2423
2424 take_vertical_position_into_account (it);
2425
2426 /* If we have to actually produce glyphs, do it. */
2427 if (it->glyph_row)
2428 {
2429 if (stretched_p)
2430 {
2431 /* Translate a space with a `space-width' property
2432 into a stretch glyph. */
2433 double ascent = (double) font->ascent / FONT_HEIGHT (font);
2434 x_append_stretch_glyph (it, it->object, it->pixel_width,
2435 it->ascent + it->descent, ascent);
2436 }
2437 else
2438 x_append_glyph (it);
2439
2440 /* If characters with lbearing or rbearing are displayed
2441 in this line, record that fact in a flag of the
2442 glyph row. This is used to optimize X output code. */
2443 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
2444 it->glyph_row->contains_overlapping_glyphs_p = 1;
2445 }
2446 }
2447 else if (it->char_to_display == '\n')
2448 {
2449 /* A newline has no width but we need the height of the line. */
2450 it->pixel_width = 0;
2451 it->nglyphs = 0;
2452 it->ascent = it->phys_ascent = font->ascent + boff;
2453 it->descent = it->phys_descent = font->descent - boff;
2454
2455 if (face->box != FACE_NO_BOX)
2456 {
2457 int thick = face->box_line_width;
2458 it->ascent += thick;
2459 it->descent += thick;
2460 }
2461 }
2462 else if (it->char_to_display == '\t')
2463 {
2464 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
2465 int x = it->current_x + it->continuation_lines_width;
2466 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2467
2468 it->pixel_width = next_tab_x - x;
2469 it->nglyphs = 1;
2470 it->ascent = it->phys_ascent = font->ascent + boff;
2471 it->descent = it->phys_descent = font->descent - boff;
2472
2473 if (it->glyph_row)
2474 {
2475 double ascent = (double) it->ascent / (it->ascent + it->descent);
2476 x_append_stretch_glyph (it, it->object, it->pixel_width,
2477 it->ascent + it->descent, ascent);
2478 }
2479 }
2480 else
2481 {
2482 /* A multi-byte character. Assume that the display width of the
2483 character is the width of the character multiplied by the
2484 width of the font. */
2485
2486 /* If we found a font, this font should give us the right
2487 metrics. If we didn't find a font, use the frame's
2488 default font and calculate the width of the character
2489 from the charset width; this is what old redisplay code
2490 did. */
2491 pcm = x_per_char_metric (font, &char2b);
2492 if (font_not_found_p || !pcm)
2493 {
2494 int charset = CHAR_CHARSET (it->char_to_display);
2495
2496 it->glyph_not_available_p = 1;
2497 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2498 * CHARSET_WIDTH (charset));
2499 it->phys_ascent = font->ascent + boff;
2500 it->phys_descent = font->descent - boff;
2501 }
2502 else
2503 {
2504 it->pixel_width = pcm->width;
2505 it->phys_ascent = pcm->ascent + boff;
2506 it->phys_descent = pcm->descent - boff;
2507 if (it->glyph_row
2508 && (pcm->lbearing < 0
2509 || pcm->rbearing > pcm->width))
2510 it->glyph_row->contains_overlapping_glyphs_p = 1;
2511 }
2512 it->nglyphs = 1;
2513 it->ascent = font->ascent + boff;
2514 it->descent = font->descent - boff;
2515 if (face->box != FACE_NO_BOX)
2516 {
2517 int thick = face->box_line_width;
2518 it->ascent += thick;
2519 it->descent += thick;
2520
2521 if (it->start_of_box_run_p)
2522 it->pixel_width += thick;
2523 if (it->end_of_box_run_p)
2524 it->pixel_width += thick;
2525 }
2526
2527 /* If face has an overline, add the height of the overline
2528 (1 pixel) and a 1 pixel margin to the character height. */
2529 if (face->overline_p)
2530 it->ascent += 2;
2531
2532 take_vertical_position_into_account (it);
2533
2534 if (it->glyph_row)
2535 x_append_glyph (it);
2536 }
2537 }
2538 else if (it->what == IT_COMPOSITION)
2539 {
2540 /* Note: A composition is represented as one glyph in the
2541 glyph matrix. There are no padding glyphs. */
2542 XChar2b char2b;
2543 XFontStruct *font;
2544 struct face *face = FACE_FROM_ID (it->f, it->face_id);
2545 XCharStruct *pcm;
2546 int font_not_found_p;
2547 struct font_info *font_info;
2548 int boff; /* baseline offset */
2549 struct composition *cmp = composition_table[it->cmp_id];
2550
2551 /* Maybe translate single-byte characters to multibyte. */
2552 it->char_to_display = it->c;
2553 if (unibyte_display_via_language_environment
2554 && SINGLE_BYTE_CHAR_P (it->c)
2555 && (it->c >= 0240
2556 || (it->c >= 0200
2557 && !NILP (Vnonascii_translation_table))))
2558 {
2559 it->char_to_display = unibyte_char_to_multibyte (it->c);
2560 }
2561
2562 /* Get face and font to use. Encode IT->char_to_display. */
2563 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2564 face = FACE_FROM_ID (it->f, it->face_id);
2565 x_get_char_face_and_encoding (it->f, it->char_to_display,
2566 it->face_id, &char2b, it->multibyte_p);
2567 font = face->font;
2568
2569 /* When no suitable font found, use the default font. */
2570 font_not_found_p = font == NULL;
2571 if (font_not_found_p)
2572 {
2573 font = FRAME_FONT (it->f);
2574 boff = it->f->output_data.mac->baseline_offset;
2575 font_info = NULL;
2576 }
2577 else
2578 {
2579 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2580 boff = font_info->baseline_offset;
2581 if (font_info->vertical_centering)
2582 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2583 }
2584
2585 /* There are no padding glyphs, so there is only one glyph to
2586 produce for the composition. Important is that pixel_width,
2587 ascent and descent are the values of what is drawn by
2588 draw_glyphs (i.e. the values of the overall glyphs composed). */
2589 it->nglyphs = 1;
2590
2591 /* If we have not yet calculated pixel size data of glyphs of
2592 the composition for the current face font, calculate them
2593 now. Theoretically, we have to check all fonts for the
2594 glyphs, but that requires much time and memory space. So,
2595 here we check only the font of the first glyph. This leads
2596 to incorrect display very rarely, and C-l (recenter) can
2597 correct the display anyway. */
2598 if (cmp->font != (void *) font)
2599 {
2600 /* Ascent and descent of the font of the first character of
2601 this composition (adjusted by baseline offset). Ascent
2602 and descent of overall glyphs should not be less than
2603 them respectively. */
2604 int font_ascent = font->ascent + boff;
2605 int font_descent = font->descent - boff;
2606 /* Bounding box of the overall glyphs. */
2607 int leftmost, rightmost, lowest, highest;
2608 int i, width, ascent, descent;
2609
2610 cmp->font = (void *) font;
2611
2612 /* Initialize the bounding box. */
2613 pcm = x_per_char_metric (font, &char2b);
2614 if (pcm)
2615 {
2616 width = pcm->width;
2617 ascent = pcm->ascent;
2618 descent = pcm->descent;
2619 }
2620 else
2621 {
2622 width = FONT_WIDTH (font);
2623 ascent = font->ascent;
2624 descent = font->descent;
2625 }
2626
2627 rightmost = width;
2628 lowest = - descent + boff;
2629 highest = ascent + boff;
2630 leftmost = 0;
2631
2632 if (font_info
2633 && font_info->default_ascent
2634 && CHAR_TABLE_P (Vuse_default_ascent)
2635 && !NILP (Faref (Vuse_default_ascent,
2636 make_number (it->char_to_display))))
2637 highest = font_info->default_ascent + boff;
2638
2639 /* Draw the first glyph at the normal position. It may be
2640 shifted to right later if some other glyphs are drawn at
2641 the left. */
2642 cmp->offsets[0] = 0;
2643 cmp->offsets[1] = boff;
2644
2645 /* Set cmp->offsets for the remaining glyphs. */
2646 for (i = 1; i < cmp->glyph_len; i++)
2647 {
2648 int left, right, btm, top;
2649 int ch = COMPOSITION_GLYPH (cmp, i);
2650 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2651
2652 face = FACE_FROM_ID (it->f, face_id);
2653 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2654 it->multibyte_p);
2655 font = face->font;
2656 if (font == NULL)
2657 {
2658 font = FRAME_FONT (it->f);
2659 boff = it->f->output_data.mac->baseline_offset;
2660 font_info = NULL;
2661 }
2662 else
2663 {
2664 font_info
2665 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2666 boff = font_info->baseline_offset;
2667 if (font_info->vertical_centering)
2668 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2669 }
2670
2671 pcm = x_per_char_metric (font, &char2b);
2672 if (pcm)
2673 {
2674 width = pcm->width;
2675 ascent = pcm->ascent;
2676 descent = pcm->descent;
2677 }
2678 else
2679 {
2680 width = FONT_WIDTH (font);
2681 ascent = font->ascent;
2682 descent = font->descent;
2683 }
2684
2685 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2686 {
2687 /* Relative composition with or without
2688 alternate chars. */
2689 left = (leftmost + rightmost - width) / 2;
2690 btm = - descent + boff;
2691 if (font_info && font_info->relative_compose
2692 && (! CHAR_TABLE_P (Vignore_relative_composition)
2693 || NILP (Faref (Vignore_relative_composition,
2694 make_number (ch)))))
2695 {
2696
2697 if (- descent >= font_info->relative_compose)
2698 /* One extra pixel between two glyphs. */
2699 btm = highest + 1;
2700 else if (ascent <= 0)
2701 /* One extra pixel between two glyphs. */
2702 btm = lowest - 1 - ascent - descent;
2703 }
2704 }
2705 else
2706 {
2707 /* A composition rule is specified by an integer
2708 value that encodes global and new reference
2709 points (GREF and NREF). GREF and NREF are
2710 specified by numbers as below:
2711
2712 0---1---2 -- ascent
2713 | |
2714 | |
2715 | |
2716 9--10--11 -- center
2717 | |
2718 ---3---4---5--- baseline
2719 | |
2720 6---7---8 -- descent
2721 */
2722 int rule = COMPOSITION_RULE (cmp, i);
2723 int gref, nref, grefx, grefy, nrefx, nrefy;
2724
2725 COMPOSITION_DECODE_RULE (rule, gref, nref);
2726 grefx = gref % 3, nrefx = nref % 3;
2727 grefy = gref / 3, nrefy = nref / 3;
2728
2729 left = (leftmost
2730 + grefx * (rightmost - leftmost) / 2
2731 - nrefx * width / 2);
2732 btm = ((grefy == 0 ? highest
2733 : grefy == 1 ? 0
2734 : grefy == 2 ? lowest
2735 : (highest + lowest) / 2)
2736 - (nrefy == 0 ? ascent + descent
2737 : nrefy == 1 ? descent - boff
2738 : nrefy == 2 ? 0
2739 : (ascent + descent) / 2));
2740 }
2741
2742 cmp->offsets[i * 2] = left;
2743 cmp->offsets[i * 2 + 1] = btm + descent;
2744
2745 /* Update the bounding box of the overall glyphs. */
2746 right = left + width;
2747 top = btm + descent + ascent;
2748 if (left < leftmost)
2749 leftmost = left;
2750 if (right > rightmost)
2751 rightmost = right;
2752 if (top > highest)
2753 highest = top;
2754 if (btm < lowest)
2755 lowest = btm;
2756 }
2757
2758 /* If there are glyphs whose x-offsets are negative,
2759 shift all glyphs to the right and make all x-offsets
2760 non-negative. */
2761 if (leftmost < 0)
2762 {
2763 for (i = 0; i < cmp->glyph_len; i++)
2764 cmp->offsets[i * 2] -= leftmost;
2765 rightmost -= leftmost;
2766 }
2767
2768 cmp->pixel_width = rightmost;
2769 cmp->ascent = highest;
2770 cmp->descent = - lowest;
2771 if (cmp->ascent < font_ascent)
2772 cmp->ascent = font_ascent;
2773 if (cmp->descent < font_descent)
2774 cmp->descent = font_descent;
2775 }
2776
2777 it->pixel_width = cmp->pixel_width;
2778 it->ascent = it->phys_ascent = cmp->ascent;
2779 it->descent = it->phys_descent = cmp->descent;
2780
2781 if (face->box != FACE_NO_BOX)
2782 {
2783 int thick = face->box_line_width;
2784 it->ascent += thick;
2785 it->descent += thick;
2786
2787 if (it->start_of_box_run_p)
2788 it->pixel_width += thick;
2789 if (it->end_of_box_run_p)
2790 it->pixel_width += thick;
2791 }
2792
2793 /* If face has an overline, add the height of the overline
2794 (1 pixel) and a 1 pixel margin to the character height. */
2795 if (face->overline_p)
2796 it->ascent += 2;
2797
2798 take_vertical_position_into_account (it);
2799
2800 if (it->glyph_row)
2801 x_append_composite_glyph (it);
2802 }
2803 else if (it->what == IT_IMAGE)
2804 x_produce_image_glyph (it);
2805 else if (it->what == IT_STRETCH)
2806 x_produce_stretch_glyph (it);
2807
2808 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2809 because this isn't true for images with `:ascent 100'. */
2810 xassert (it->ascent >= 0 && it->descent >= 0);
2811 if (it->area == TEXT_AREA)
2812 it->current_x += it->pixel_width;
2813
2814 it->descent += it->extra_line_spacing;
2815
2816 it->max_ascent = max (it->max_ascent, it->ascent);
2817 it->max_descent = max (it->max_descent, it->descent);
2818 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2819 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
2820}
2821
2822
2823/* Estimate the pixel height of the mode or top line on frame F.
2824 FACE_ID specifies what line's height to estimate. */
2825
2826int
2827x_estimate_mode_line_height (f, face_id)
2828 struct frame *f;
2829 enum face_id face_id;
2830{
2831 int height = 1;
2832
2833 /* This function is called so early when Emacs starts that the face
2834 cache and mode line face are not yet initialized. */
2835 if (FRAME_FACE_CACHE (f))
2836 {
2837 struct face *face = FACE_FROM_ID (f, face_id);
2838 if (face)
2839 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2840 }
2841
2842 return height;
2843}
2844
2845
2846/***********************************************************************
2847 Glyph display
2848 ***********************************************************************/
2849
2850/* A sequence of glyphs to be drawn in the same face.
2851
2852 This data structure is not really completely X specific, so it
2853 could possibly, at least partially, be useful for other systems. It
2854 is currently not part of the external redisplay interface because
2855 it's not clear what other systems will need. */
2856
2857struct glyph_string
2858{
2859 /* X-origin of the string. */
2860 int x;
2861
2862 /* Y-origin and y-position of the base line of this string. */
2863 int y, ybase;
2864
2865 /* The width of the string, not including a face extension. */
2866 int width;
2867
2868 /* The width of the string, including a face extension. */
2869 int background_width;
2870
2871 /* The height of this string. This is the height of the line this
2872 string is drawn in, and can be different from the height of the
2873 font the string is drawn in. */
2874 int height;
2875
2876 /* Number of pixels this string overwrites in front of its x-origin.
2877 This number is zero if the string has an lbearing >= 0; it is
2878 -lbearing, if the string has an lbearing < 0. */
2879 int left_overhang;
2880
2881 /* Number of pixels this string overwrites past its right-most
2882 nominal x-position, i.e. x + width. Zero if the string's
2883 rbearing is <= its nominal width, rbearing - width otherwise. */
2884 int right_overhang;
2885
2886 /* The frame on which the glyph string is drawn. */
2887 struct frame *f;
2888
2889 /* The window on which the glyph string is drawn. */
2890 struct window *w;
2891
2892 /* X display and window for convenience. */
2893 Display *display;
2894 Window window;
2895
2896 /* The glyph row for which this string was built. It determines the
2897 y-origin and height of the string. */
2898 struct glyph_row *row;
2899
2900 /* The area within row. */
2901 enum glyph_row_area area;
2902
2903 /* Characters to be drawn, and number of characters. */
2904 XChar2b *char2b;
2905 int nchars;
2906
2907 /* A face-override for drawing cursors, mouse face and similar. */
2908 enum draw_glyphs_face hl;
2909
2910 /* Face in which this string is to be drawn. */
2911 struct face *face;
2912
2913 /* Font in which this string is to be drawn. */
2914 XFontStruct *font;
2915
2916 /* Font info for this string. */
2917 struct font_info *font_info;
2918
2919 /* Non-null means this string describes (part of) a composition.
2920 All characters from char2b are drawn composed. */
2921 struct composition *cmp;
2922
2923 /* Index of this glyph string's first character in the glyph
2924 definition of CMP. If this is zero, this glyph string describes
2925 the first character of a composition. */
2926 int gidx;
2927
2928 /* 1 means this glyph strings face has to be drawn to the right end
2929 of the window's drawing area. */
2930 unsigned extends_to_end_of_line_p : 1;
2931
2932 /* 1 means the background of this string has been drawn. */
2933 unsigned background_filled_p : 1;
2934
2935 /* 1 means glyph string must be drawn with 16-bit functions. */
2936 unsigned two_byte_p : 1;
2937
2938 /* 1 means that the original font determined for drawing this glyph
2939 string could not be loaded. The member `font' has been set to
2940 the frame's default font in this case. */
2941 unsigned font_not_found_p : 1;
2942
2943 /* 1 means that the face in which this glyph string is drawn has a
2944 stipple pattern. */
2945 unsigned stippled_p : 1;
2946
2947 /* 1 means only the foreground of this glyph string must be drawn,
2948 and we should use the physical height of the line this glyph
2949 string appears in as clip rect. */
2950 unsigned for_overlaps_p : 1;
2951
2952 /* The GC to use for drawing this glyph string. */
2953 GC gc;
2954
2955 /* A pointer to the first glyph in the string. This glyph
2956 corresponds to char2b[0]. Needed to draw rectangles if
2957 font_not_found_p is 1. */
2958 struct glyph *first_glyph;
2959
2960 /* Image, if any. */
2961 struct image *img;
2962
2963 struct glyph_string *next, *prev;
2964};
2965
2966
2967#if 0
2968
2969static void
2970x_dump_glyph_string (s)
2971 struct glyph_string *s;
2972{
2973 fprintf (stderr, "glyph string\n");
2974 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2975 s->x, s->y, s->width, s->height);
2976 fprintf (stderr, " ybase = %d\n", s->ybase);
2977 fprintf (stderr, " hl = %d\n", s->hl);
2978 fprintf (stderr, " left overhang = %d, right = %d\n",
2979 s->left_overhang, s->right_overhang);
2980 fprintf (stderr, " nchars = %d\n", s->nchars);
2981 fprintf (stderr, " extends to end of line = %d\n",
2982 s->extends_to_end_of_line_p);
2983 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2984 fprintf (stderr, " bg width = %d\n", s->background_width);
2985}
2986
2987#endif /* GLYPH_DEBUG */
2988
2989
2990
2991static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2992 struct glyph_string **,
2993 struct glyph_string *,
2994 struct glyph_string *));
2995static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2996 struct glyph_string **,
2997 struct glyph_string *,
2998 struct glyph_string *));
2999static void x_append_glyph_string P_ ((struct glyph_string **,
3000 struct glyph_string **,
3001 struct glyph_string *));
3002static int x_left_overwritten P_ ((struct glyph_string *));
3003static int x_left_overwriting P_ ((struct glyph_string *));
3004static int x_right_overwritten P_ ((struct glyph_string *));
3005static int x_right_overwriting P_ ((struct glyph_string *));
3006static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
3007 int));
3008static void x_init_glyph_string P_ ((struct glyph_string *,
3009 XChar2b *, struct window *,
3010 struct glyph_row *,
3011 enum glyph_row_area, int,
3012 enum draw_glyphs_face));
3013static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
3014 enum glyph_row_area, int, int,
3015 enum draw_glyphs_face, int *, int *, int));
3016static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
3017static void x_set_glyph_string_gc P_ ((struct glyph_string *));
3018static void x_draw_glyph_string_background P_ ((struct glyph_string *,
3019 int));
3020static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
3021static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
3022static void x_draw_glyph_string_box P_ ((struct glyph_string *));
3023static void x_draw_glyph_string P_ ((struct glyph_string *));
3024static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
3025static void x_set_cursor_gc P_ ((struct glyph_string *));
3026static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
3027static void x_set_mouse_face_gc P_ ((struct glyph_string *));
3028static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
3029 int *, int *));
3030static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
3031static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
3032 unsigned long *, double, int));
3033static void x_setup_relief_color P_ ((struct frame *, struct relief *,
3034 double, int, unsigned long));
3035static void x_setup_relief_colors P_ ((struct glyph_string *));
3036static void x_draw_image_glyph_string P_ ((struct glyph_string *));
3037static void x_draw_image_relief P_ ((struct glyph_string *));
3038static void x_draw_image_foreground P_ ((struct glyph_string *));
3039static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
3040static void x_fill_image_glyph_string P_ ((struct glyph_string *));
3041static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
3042 int, int, int));
3043static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
3044 int, int, int, int, XRectangle *));
3045static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
3046 int, int, int, XRectangle *));
3047static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
3048 enum glyph_row_area));
3049static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
3050 struct glyph_row *,
3051 enum glyph_row_area, int, int));
3052
3053#if GLYPH_DEBUG
3054static void x_check_font P_ ((struct frame *, XFontStruct *));
3055#endif
3056
3057
3058/* Append the list of glyph strings with head H and tail T to the list
3059 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
3060
3061static INLINE void
3062x_append_glyph_string_lists (head, tail, h, t)
3063 struct glyph_string **head, **tail;
3064 struct glyph_string *h, *t;
3065{
3066 if (h)
3067 {
3068 if (*head)
3069 (*tail)->next = h;
3070 else
3071 *head = h;
3072 h->prev = *tail;
3073 *tail = t;
3074 }
3075}
3076
3077
3078/* Prepend the list of glyph strings with head H and tail T to the
3079 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
3080 result. */
3081
3082static INLINE void
3083x_prepend_glyph_string_lists (head, tail, h, t)
3084 struct glyph_string **head, **tail;
3085 struct glyph_string *h, *t;
3086{
3087 if (h)
3088 {
3089 if (*head)
3090 (*head)->prev = t;
3091 else
3092 *tail = t;
3093 t->next = *head;
3094 *head = h;
3095 }
3096}
3097
3098
3099/* Append glyph string S to the list with head *HEAD and tail *TAIL.
3100 Set *HEAD and *TAIL to the resulting list. */
3101
3102static INLINE void
3103x_append_glyph_string (head, tail, s)
3104 struct glyph_string **head, **tail;
3105 struct glyph_string *s;
3106{
3107 s->next = s->prev = NULL;
3108 x_append_glyph_string_lists (head, tail, s, s);
3109}
3110
3111
3112/* Set S->gc to a suitable GC for drawing glyph string S in cursor
3113 face. */
3114
3115static void
3116x_set_cursor_gc (s)
3117 struct glyph_string *s;
3118{
3119 if (s->font == FRAME_FONT (s->f)
3120 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
3121 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
3122 && !s->cmp)
3123 s->gc = s->f->output_data.mac->cursor_gc;
3124 else
3125 {
3126 /* Cursor on non-default face: must merge. */
3127 XGCValues xgcv;
3128 unsigned long mask;
3129
3130 xgcv.background = s->f->output_data.mac->cursor_pixel;
3131 xgcv.foreground = s->face->background;
3132
3133 /* If the glyph would be invisible, try a different foreground. */
3134 if (xgcv.foreground == xgcv.background)
3135 xgcv.foreground = s->face->foreground;
3136 if (xgcv.foreground == xgcv.background)
3137 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
3138 if (xgcv.foreground == xgcv.background)
3139 xgcv.foreground = s->face->foreground;
3140
3141 /* Make sure the cursor is distinct from text in this face. */
3142 if (xgcv.background == s->face->background
3143 && xgcv.foreground == s->face->foreground)
3144 {
3145 xgcv.background = s->face->foreground;
3146 xgcv.foreground = s->face->background;
3147 }
3148
3149 IF_DEBUG (x_check_font (s->f, s->font));
3150 xgcv.font = s->font;
3151 mask = GCForeground | GCBackground | GCFont;
3152
3153 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
3154 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
3155 mask, &xgcv);
3156 else
3157 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
3158 = XCreateGC (s->display, s->window, mask, &xgcv);
3159
3160 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
3161 }
3162}
3163
3164
3165/* Set up S->gc of glyph string S for drawing text in mouse face. */
3166
3167static void
3168x_set_mouse_face_gc (s)
3169 struct glyph_string *s;
3170{
3171 int face_id;
3172 struct face *face;
3173
3174 /* What face has to be used for the mouse face? */
3175 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
3176 face = FACE_FROM_ID (s->f, face_id);
3177 if (s->first_glyph->type == CHAR_GLYPH)
3178 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
3179 else
3180 face_id = FACE_FOR_CHAR (s->f, face, 0);
3181 s->face = FACE_FROM_ID (s->f, face_id);
3182 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
3183
3184 /* If font in this face is same as S->font, use it. */
3185 if (s->font == s->face->font)
3186 s->gc = s->face->gc;
3187 else
3188 {
3189 /* Otherwise construct scratch_cursor_gc with values from FACE
3190 but font FONT. */
3191 XGCValues xgcv;
3192 unsigned long mask;
3193
3194 xgcv.background = s->face->background;
3195 xgcv.foreground = s->face->foreground;
3196 IF_DEBUG (x_check_font (s->f, s->font));
3197 xgcv.font = s->font;
3198 mask = GCForeground | GCBackground | GCFont;
3199
3200 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
3201 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
3202 mask, &xgcv);
3203 else
3204 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
3205 = XCreateGC (s->display, s->window, mask, &xgcv);
3206
3207 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
3208 }
3209
3210 xassert (s->gc != 0);
3211}
3212
3213
3214/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
3215 Faces to use in the mode line have already been computed when the
3216 matrix was built, so there isn't much to do, here. */
3217
3218static INLINE void
3219x_set_mode_line_face_gc (s)
3220 struct glyph_string *s;
3221{
3222 s->gc = s->face->gc;
3223}
3224
3225
3226/* Set S->gc of glyph string S for drawing that glyph string. Set
3227 S->stippled_p to a non-zero value if the face of S has a stipple
3228 pattern. */
3229
3230static INLINE void
3231x_set_glyph_string_gc (s)
3232 struct glyph_string *s;
3233{
3234 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
3235
3236 if (s->hl == DRAW_NORMAL_TEXT)
3237 {
3238 s->gc = s->face->gc;
3239 s->stippled_p = s->face->stipple != 0;
3240 }
3241 else if (s->hl == DRAW_INVERSE_VIDEO)
3242 {
3243 x_set_mode_line_face_gc (s);
3244 s->stippled_p = s->face->stipple != 0;
3245 }
3246 else if (s->hl == DRAW_CURSOR)
3247 {
3248 x_set_cursor_gc (s);
3249 s->stippled_p = 0;
3250 }
3251 else if (s->hl == DRAW_MOUSE_FACE)
3252 {
3253 x_set_mouse_face_gc (s);
3254 s->stippled_p = s->face->stipple != 0;
3255 }
3256 else if (s->hl == DRAW_IMAGE_RAISED
3257 || s->hl == DRAW_IMAGE_SUNKEN)
3258 {
3259 s->gc = s->face->gc;
3260 s->stippled_p = s->face->stipple != 0;
3261 }
3262 else
3263 {
3264 s->gc = s->face->gc;
3265 s->stippled_p = s->face->stipple != 0;
3266 }
3267
3268 /* GC must have been set. */
3269 xassert (s->gc != 0);
3270}
3271
3272
3273/* Return in *R the clipping rectangle for glyph string S. */
3274
3275static void
3276x_get_glyph_string_clip_rect (s, r)
3277 struct glyph_string *s;
3278 Rect *r;
3279{
3280 int r_height, r_width;
3281
3282 if (s->row->full_width_p)
3283 {
3284 /* Draw full-width. X coordinates are relative to S->w->left. */
3285 int canon_x = CANON_X_UNIT (s->f);
3286
3287 r->left = WINDOW_LEFT_MARGIN (s->w) * canon_x;
3288 r_width = XFASTINT (s->w->width) * canon_x;
3289
3290 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
3291 {
3292 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
3293 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
3294 r->left -= width;
3295 }
3296
3297 r->left += FRAME_INTERNAL_BORDER_WIDTH (s->f);
3298
3299 /* Unless displaying a mode or menu bar line, which are always
3300 fully visible, clip to the visible part of the row. */
3301 if (s->w->pseudo_window_p)
3302 r_height = s->row->visible_height;
3303 else
3304 r_height = s->height;
3305 }
3306 else
3307 {
3308 /* This is a text line that may be partially visible. */
3309 r->left = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
3310 r_width = window_box_width (s->w, s->area);
3311 r_height = s->row->visible_height;
3312 }
3313
3314 /* Don't use S->y for clipping because it doesn't take partially
3315 visible lines into account. For example, it can be negative for
3316 partially visible lines at the top of a window. */
3317 if (!s->row->full_width_p
3318 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
3319 r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
3320 else
3321 r->top = max (0, s->row->y);
3322
3323 /* If drawing a tool-bar window, draw it over the internal border
3324 at the top of the window. */
3325 if (s->w == XWINDOW (s->f->tool_bar_window))
3326 r->top -= s->f->output_data.mac->internal_border_width;
3327
3328 /* If S draws overlapping rows, it's sufficient to use the top and
3329 bottom of the window for clipping because this glyph string
3330 intentionally draws over other lines. */
3331 if (s->for_overlaps_p)
3332 {
3333 r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
3334 r_height = window_text_bottom_y (s->w) - r->top;
3335 }
3336
3337 r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top);
3338
3339 r->bottom = r->top + r_height;
3340 r->right = r->left + r_width;
3341}
3342
3343
3344/* Set clipping for output of glyph string S. S may be part of a mode
3345 line or menu if we don't have X toolkit support. */
3346
3347static INLINE void
3348x_set_glyph_string_clipping (s)
3349 struct glyph_string *s;
3350{
3351 Rect r;
3352 x_get_glyph_string_clip_rect (s, &r);
3353 mac_set_clip_rectangle (s->display, s->window, &r);
3354}
3355
3356
3357/* Compute left and right overhang of glyph string S. If S is a glyph
3358 string for a composition, assume overhangs don't exist. */
3359
3360static INLINE void
3361x_compute_glyph_string_overhangs (s)
3362 struct glyph_string *s;
3363{
3364 if (s->cmp == NULL
3365 && s->first_glyph->type == CHAR_GLYPH)
3366 {
3367 XCharStruct cs;
3368 int direction, font_ascent, font_descent;
3369 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
3370 &font_ascent, &font_descent, &cs);
3371 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
3372 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
3373 }
3374}
3375
3376
3377/* Compute overhangs and x-positions for glyph string S and its
3378 predecessors, or successors. X is the starting x-position for S.
3379 BACKWARD_P non-zero means process predecessors. */
3380
3381static void
3382x_compute_overhangs_and_x (s, x, backward_p)
3383 struct glyph_string *s;
3384 int x;
3385 int backward_p;
3386{
3387 if (backward_p)
3388 {
3389 while (s)
3390 {
3391 x_compute_glyph_string_overhangs (s);
3392 x -= s->width;
3393 s->x = x;
3394 s = s->prev;
3395 }
3396 }
3397 else
3398 {
3399 while (s)
3400 {
3401 x_compute_glyph_string_overhangs (s);
3402 s->x = x;
3403 x += s->width;
3404 s = s->next;
3405 }
3406 }
3407}
3408
3409
3410/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
3411 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
3412 assumed to be zero. */
3413
3414void
3415x_get_glyph_overhangs (glyph, f, left, right)
3416 struct glyph *glyph;
3417 struct frame *f;
3418 int *left, *right;
3419{
3420 *left = *right = 0;
3421
3422 if (glyph->type == CHAR_GLYPH)
3423 {
3424 XFontStruct *font;
3425 struct face *face;
3426 struct font_info *font_info;
3427 XChar2b char2b;
3428 XCharStruct *pcm;
3429
3430 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
3431 font = face->font;
3432 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
3433 if (font
3434 && (pcm = x_per_char_metric (font, &char2b)))
3435 {
3436 if (pcm->rbearing > pcm->width)
3437 *right = pcm->rbearing - pcm->width;
3438 if (pcm->lbearing < 0)
3439 *left = -pcm->lbearing;
3440 }
3441 }
3442}
3443
3444
3445/* Return the index of the first glyph preceding glyph string S that
3446 is overwritten by S because of S's left overhang. Value is -1
3447 if no glyphs are overwritten. */
3448
3449static int
3450x_left_overwritten (s)
3451 struct glyph_string *s;
3452{
3453 int k;
3454
3455 if (s->left_overhang)
3456 {
3457 int x = 0, i;
3458 struct glyph *glyphs = s->row->glyphs[s->area];
3459 int first = s->first_glyph - glyphs;
3460
3461 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
3462 x -= glyphs[i].pixel_width;
3463
3464 k = i + 1;
3465 }
3466 else
3467 k = -1;
3468
3469 return k;
3470}
3471
3472
3473/* Return the index of the first glyph preceding glyph string S that
3474 is overwriting S because of its right overhang. Value is -1 if no
3475 glyph in front of S overwrites S. */
3476
3477static int
3478x_left_overwriting (s)
3479 struct glyph_string *s;
3480{
3481 int i, k, x;
3482 struct glyph *glyphs = s->row->glyphs[s->area];
3483 int first = s->first_glyph - glyphs;
3484
3485 k = -1;
3486 x = 0;
3487 for (i = first - 1; i >= 0; --i)
3488 {
3489 int left, right;
3490 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3491 if (x + right > 0)
3492 k = i;
3493 x -= glyphs[i].pixel_width;
3494 }
3495
3496 return k;
3497}
3498
3499
3500/* Return the index of the last glyph following glyph string S that is
3501 not overwritten by S because of S's right overhang. Value is -1 if
3502 no such glyph is found. */
3503
3504static int
3505x_right_overwritten (s)
3506 struct glyph_string *s;
3507{
3508 int k = -1;
3509
3510 if (s->right_overhang)
3511 {
3512 int x = 0, i;
3513 struct glyph *glyphs = s->row->glyphs[s->area];
3514 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
3515 int end = s->row->used[s->area];
3516
3517 for (i = first; i < end && s->right_overhang > x; ++i)
3518 x += glyphs[i].pixel_width;
3519
3520 k = i;
3521 }
3522
3523 return k;
3524}
3525
3526
3527/* Return the index of the last glyph following glyph string S that
3528 overwrites S because of its left overhang. Value is negative
3529 if no such glyph is found. */
3530
3531static int
3532x_right_overwriting (s)
3533 struct glyph_string *s;
3534{
3535 int i, k, x;
3536 int end = s->row->used[s->area];
3537 struct glyph *glyphs = s->row->glyphs[s->area];
3538 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
3539
3540 k = -1;
3541 x = 0;
3542 for (i = first; i < end; ++i)
3543 {
3544 int left, right;
3545 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3546 if (x - left < 0)
3547 k = i;
3548 x += glyphs[i].pixel_width;
3549 }
3550
3551 return k;
3552}
3553
3554
3555/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3556
3557static INLINE void
3558x_clear_glyph_string_rect (s, x, y, w, h)
3559 struct glyph_string *s;
3560 int x, y, w, h;
3561{
3562 XGCValues xgcv;
3563
3564 xgcv.foreground = s->gc->background;
3565 XFillRectangle (s->display, s->window, &xgcv, x, y, w, h);
3566}
3567
3568
3569/* Draw the background of glyph_string S. If S->background_filled_p
3570 is non-zero don't draw it. FORCE_P non-zero means draw the
3571 background even if it wouldn't be drawn normally. This is used
3572 when a string preceding S draws into the background of S, or S
3573 contains the first component of a composition. */
3574
3575static void
3576x_draw_glyph_string_background (s, force_p)
3577 struct glyph_string *s;
3578 int force_p;
3579{
3580 /* Nothing to do if background has already been drawn or if it
3581 shouldn't be drawn in the first place. */
3582 if (!s->background_filled_p)
3583 {
3584#if 0 /* MAC_TODO: stipple */
3585 if (s->stippled_p)
3586 {
3587 /* Fill background with a stipple pattern. */
3588 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3589 XFillRectangle (s->display, s->window, s->gc, s->x,
3590 s->y + s->face->box_line_width,
3591 s->background_width,
3592 s->height - 2 * s->face->box_line_width);
3593 XSetFillStyle (s->display, s->gc, FillSolid);
3594 s->background_filled_p = 1;
3595 }
3596 else
3597#endif
3598 if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3599 || s->font_not_found_p
3600 || s->extends_to_end_of_line_p
3601 || force_p)
3602 {
3603 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3604 s->background_width,
3605 s->height - 2 * s->face->box_line_width);
3606 s->background_filled_p = 1;
3607 }
3608 }
3609}
3610
3611
3612/* Draw the foreground of glyph string S. */
3613
3614static void
3615x_draw_glyph_string_foreground (s)
3616 struct glyph_string *s;
3617{
3618 int i, x;
3619
3620 /* If first glyph of S has a left box line, start drawing the text
3621 of S to the right of that box line. */
3622 if (s->face->box != FACE_NO_BOX
3623 && s->first_glyph->left_box_line_p)
3624 x = s->x + s->face->box_line_width;
3625 else
3626 x = s->x;
3627
3628 /* Draw characters of S as rectangles if S's font could not be
3629 loaded. */
3630 if (s->font_not_found_p)
3631 {
3632 for (i = 0; i < s->nchars; ++i)
3633 {
3634 struct glyph *g = s->first_glyph + i;
3635 mac_draw_rectangle (s->display, s->window,
3636 s->gc, x, s->y, g->pixel_width - 1,
3637 s->height - 1);
3638 x += g->pixel_width;
3639 }
3640 }
3641 else
3642 {
3643 char *char1b = (char *) s->char2b;
3644 int boff = s->font_info->baseline_offset;
3645
3646 if (s->font_info->vertical_centering)
3647 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3648
3649 /* If we can use 8-bit functions, condense S->char2b. */
3650 if (!s->two_byte_p)
3651 for (i = 0; i < s->nchars; ++i)
3652 char1b[i] = s->char2b[i].byte2;
3653
3654 /* Draw text with XDrawString if background has already been
3655 filled. Otherwise, use XDrawImageString. (Note that
3656 XDrawImageString is usually faster than XDrawString.) Always
3657 use XDrawImageString when drawing the cursor so that there is
3658 no chance that characters under a box cursor are invisible. */
3659 if (s->for_overlaps_p
3660 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3661 {
3662 /* Draw characters with 16-bit or 8-bit functions. */
3663 if (s->two_byte_p)
3664 XDrawString16 (s->display, s->window, s->gc, x,
3665 s->ybase - boff, s->char2b, s->nchars);
3666 else
3667 XDrawString (s->display, s->window, s->gc, x,
3668 s->ybase - boff, char1b, s->nchars);
3669 }
3670 else
3671 {
3672 if (s->two_byte_p)
3673 XDrawImageString16 (s->display, s->window, s->gc, x,
3674 s->ybase - boff, s->char2b, s->nchars);
3675 else
3676 XDrawImageString (s->display, s->window, s->gc, x,
3677 s->ybase - boff, char1b, s->nchars);
3678 }
3679 }
3680}
3681
3682/* Draw the foreground of composite glyph string S. */
3683
3684static void
3685x_draw_composite_glyph_string_foreground (s)
3686 struct glyph_string *s;
3687{
3688 int i, x;
3689
3690 /* If first glyph of S has a left box line, start drawing the text
3691 of S to the right of that box line. */
3692 if (s->face->box != FACE_NO_BOX
3693 && s->first_glyph->left_box_line_p)
3694 x = s->x + s->face->box_line_width;
3695 else
3696 x = s->x;
3697
3698 /* S is a glyph string for a composition. S->gidx is the index of
3699 the first character drawn for glyphs of this composition.
3700 S->gidx == 0 means we are drawing the very first character of
3701 this composition. */
3702
3703 /* Draw a rectangle for the composition if the font for the very
3704 first character of the composition could not be loaded. */
3705 if (s->font_not_found_p)
3706 {
3707 if (s->gidx == 0)
3708 mac_draw_rectangle (s->display, s->window, s->gc, x, s->y,
3709 s->width - 1, s->height - 1);
3710 }
3711 else
3712 {
3713 for (i = 0; i < s->nchars; i++, ++s->gidx)
3714 XDrawString16 (s->display, s->window, s->gc,
3715 x + s->cmp->offsets[s->gidx * 2],
3716 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3717 s->char2b + i, 1);
3718 }
3719}
3720
3721
3722#ifdef USE_X_TOOLKIT
3723
3724static struct frame *x_frame_of_widget P_ ((Widget));
3725
3726
3727/* Return the frame on which widget WIDGET is used.. Abort if frame
3728 cannot be determined. */
3729
3730static struct frame *
3731x_frame_of_widget (widget)
3732 Widget widget;
3733{
3734 struct x_display_info *dpyinfo;
3735 Lisp_Object tail;
3736 struct frame *f;
3737
3738 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3739
3740 /* Find the top-level shell of the widget. Note that this function
3741 can be called when the widget is not yet realized, so XtWindow
3742 (widget) == 0. That's the reason we can't simply use
3743 x_any_window_to_frame. */
3744 while (!XtIsTopLevelShell (widget))
3745 widget = XtParent (widget);
3746
3747 /* Look for a frame with that top-level widget. Allocate the color
3748 on that frame to get the right gamma correction value. */
3749 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3750 if (GC_FRAMEP (XCAR (tail))
3751 && (f = XFRAME (XCAR (tail)),
3752 (f->output_data.nothing != 1
3753 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3754 && f->output_data.x->widget == widget)
3755 return f;
3756
3757 abort ();
3758}
3759
3760
3761/* Allocate the color COLOR->pixel on the screen and display of
3762 widget WIDGET in colormap CMAP. If an exact match cannot be
3763 allocated, try the nearest color available. Value is non-zero
3764 if successful. This is called from lwlib. */
3765
3766int
3767x_alloc_nearest_color_for_widget (widget, cmap, color)
3768 Widget widget;
3769 Colormap cmap;
3770 XColor *color;
3771{
3772 struct frame *f = x_frame_of_widget (widget);
3773 return x_alloc_nearest_color (f, cmap, color);
3774}
3775
3776
3777#endif /* USE_X_TOOLKIT */
3778
3779#if 0
3780
3781/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3782 CMAP. If an exact match can't be allocated, try the nearest color
3783 available. Value is non-zero if successful. Set *COLOR to the
3784 color allocated. */
3785
3786int
3787x_alloc_nearest_color (f, cmap, color)
3788 struct frame *f;
3789 Colormap cmap;
3790 XColor *color;
3791{
3792 Display *display = FRAME_X_DISPLAY (f);
3793 Screen *screen = FRAME_X_SCREEN (f);
3794 int rc;
3795
3796 gamma_correct (f, color);
3797 rc = XAllocColor (display, cmap, color);
3798 if (rc == 0)
3799 {
3800 /* If we got to this point, the colormap is full, so we're going
3801 to try to get the next closest color. The algorithm used is
3802 a least-squares matching, which is what X uses for closest
3803 color matching with StaticColor visuals. */
3804 int nearest, i;
3805 unsigned long nearest_delta = ~0;
3806 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3807 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3808
3809 for (i = 0; i < ncells; ++i)
3810 cells[i].pixel = i;
3811 XQueryColors (display, cmap, cells, ncells);
3812
3813 for (nearest = i = 0; i < ncells; ++i)
3814 {
3815 long dred = (color->red >> 8) - (cells[i].red >> 8);
3816 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3817 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3818 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3819
3820 if (delta < nearest_delta)
3821 {
3822 nearest = i;
3823 nearest_delta = delta;
3824 }
3825 }
3826
3827 color->red = cells[nearest].red;
3828 color->green = cells[nearest].green;
3829 color->blue = cells[nearest].blue;
3830 rc = XAllocColor (display, cmap, color);
3831 }
3832
3833#ifdef DEBUG_X_COLORS
3834 if (rc)
3835 register_color (color->pixel);
3836#endif /* DEBUG_X_COLORS */
3837
3838 return rc;
3839}
3840
3841
3842/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3843 It's necessary to do this instead of just using PIXEL directly to
3844 get color reference counts right. */
3845
3846unsigned long
3847x_copy_color (f, pixel)
3848 struct frame *f;
3849 unsigned long pixel;
3850{
3851 XColor color;
3852
3853 color.pixel = pixel;
3854 BLOCK_INPUT;
3855 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3856 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3857 UNBLOCK_INPUT;
3858#ifdef DEBUG_X_COLORS
3859 register_color (pixel);
3860#endif
3861 return color.pixel;
3862}
3863
3864
3865/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3866 It's necessary to do this instead of just using PIXEL directly to
3867 get color reference counts right. */
3868
3869unsigned long
3870x_copy_dpy_color (dpy, cmap, pixel)
3871 Display *dpy;
3872 Colormap cmap;
3873 unsigned long pixel;
3874{
3875 XColor color;
3876
3877 color.pixel = pixel;
3878 BLOCK_INPUT;
3879 XQueryColor (dpy, cmap, &color);
3880 XAllocColor (dpy, cmap, &color);
3881 UNBLOCK_INPUT;
3882#ifdef DEBUG_X_COLORS
3883 register_color (pixel);
3884#endif
3885 return color.pixel;
3886}
3887
3888#endif
3889
3890/* Allocate a color which is lighter or darker than *COLOR by FACTOR
3891 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3892 If this produces the same color as COLOR, try a color where all RGB
3893 values have DELTA added. Return the allocated color in *COLOR.
3894 DISPLAY is the X display, CMAP is the colormap to operate on.
3895 Value is non-zero if successful. */
3896
3897static int
3898mac_alloc_lighter_color (f, color, factor, delta)
3899 struct frame *f;
3900 unsigned long *color;
3901 double factor;
3902 int delta;
3903{
3904 unsigned long new;
3905
3906 /* Change RGB values by specified FACTOR. Avoid overflow! */
3907 xassert (factor >= 0);
3908 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3909 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3910 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3911 if (new == *color)
3912 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3913 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3914 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3915
3916 /* MAC_TODO: Map to palette and retry with delta if same? */
3917 /* MAC_TODO: Free colors (if using palette)? */
3918
3919 if (new == *color)
3920 return 0;
3921
3922 *color = new;
3923
3924 return 1;
3925}
3926
3927
3928/* Set up the foreground color for drawing relief lines of glyph
3929 string S. RELIEF is a pointer to a struct relief containing the GC
3930 with which lines will be drawn. Use a color that is FACTOR or
3931 DELTA lighter or darker than the relief's background which is found
3932 in S->f->output_data.x->relief_background. If such a color cannot
3933 be allocated, use DEFAULT_PIXEL, instead. */
3934
3935static void
3936x_setup_relief_color (f, relief, factor, delta, default_pixel)
3937 struct frame *f;
3938 struct relief *relief;
3939 double factor;
3940 int delta;
3941 unsigned long default_pixel;
3942{
3943 XGCValues xgcv;
3944 struct mac_output *di = f->output_data.mac;
3945 unsigned long mask = GCForeground;
3946 unsigned long pixel;
3947 unsigned long background = di->relief_background;
3948 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3949
3950 /* MAC_TODO: Free colors (if using palette)? */
3951
3952 /* Allocate new color. */
3953 xgcv.foreground = default_pixel;
3954 pixel = background;
3955 if (mac_alloc_lighter_color (f, &pixel, factor, delta))
3956 {
3957 relief->allocated_p = 1;
3958 xgcv.foreground = relief->pixel = pixel;
3959 }
3960
3961 if (relief->gc == 0)
3962 {
3963#if 0 /* MAC_TODO: stipple */
3964 xgcv.stipple = dpyinfo->gray;
3965 mask |= GCStipple;
3966#endif
3967 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3968 }
3969 else
3970 XChangeGC (NULL, relief->gc, mask, &xgcv);
3971}
3972
3973
3974/* Set up colors for the relief lines around glyph string S. */
3975
3976static void
3977x_setup_relief_colors (s)
3978 struct glyph_string *s;
3979{
3980 struct mac_output *di = s->f->output_data.mac;
3981 unsigned long color;
3982
3983 if (s->face->use_box_color_for_shadows_p)
3984 color = s->face->box_color;
3985 else
3986 {
3987 XGCValues xgcv;
3988
3989 /* Get the background color of the face. */
3990 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3991 color = xgcv.background;
3992 }
3993
3994 if (di->white_relief.gc == 0
3995 || color != di->relief_background)
3996 {
3997 di->relief_background = color;
3998 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3999 WHITE_PIX_DEFAULT (s->f));
4000 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
4001 BLACK_PIX_DEFAULT (s->f));
4002 }
4003}
4004
4005
4006/* Draw a relief on frame F inside the rectangle given by LEFT_X,
4007 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
4008 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
4009 relief. LEFT_P non-zero means draw a relief on the left side of
4010 the rectangle. RIGHT_P non-zero means draw a relief on the right
4011 side of the rectangle. CLIP_RECT is the clipping rectangle to use
4012 when drawing. */
4013
4014static void
4015x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
4016 raised_p, left_p, right_p, clip_rect)
4017 struct frame *f;
4018 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
4019 Rect *clip_rect;
4020{
4021 int i;
4022 GC gc;
4023
4024 if (raised_p)
4025 gc = f->output_data.mac->white_relief.gc;
4026 else
4027 gc = f->output_data.mac->black_relief.gc;
4028 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect);
4029
4030 /* Top. */
4031 for (i = 0; i < width; ++i)
4032 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4033 left_x + i * left_p, top_y + i,
4034 right_x + 1 - i * right_p, top_y + i);
4035
4036 /* Left. */
4037 if (left_p)
4038 for (i = 0; i < width; ++i)
4039 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4040 left_x + i, top_y + i, left_x + i, bottom_y - i);
4041
4042 mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
4043 if (raised_p)
4044 gc = f->output_data.mac->black_relief.gc;
4045 else
4046 gc = f->output_data.mac->white_relief.gc;
4047 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect);
4048
4049 /* Bottom. */
4050 for (i = 0; i < width; ++i)
4051 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4052 left_x + i * left_p, bottom_y - i,
4053 right_x + 1 - i * right_p, bottom_y - i);
4054
4055 /* Right. */
4056 if (right_p)
4057 for (i = 0; i < width; ++i)
4058 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4059 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
4060
4061 mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
4062}
4063
4064
4065/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
4066 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
4067 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
4068 left side of the rectangle. RIGHT_P non-zero means draw a line
4069 on the right side of the rectangle. CLIP_RECT is the clipping
4070 rectangle to use when drawing. */
4071
4072static void
4073x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4074 left_p, right_p, clip_rect)
4075 struct glyph_string *s;
4076 int left_x, top_y, right_x, bottom_y, left_p, right_p;
4077 Rect *clip_rect;
4078{
4079 XGCValues xgcv;
4080
4081 xgcv.foreground = s->face->box_color;
4082 mac_set_clip_rectangle (s->display, s->window, clip_rect);
4083
4084 /* Top. */
4085 XFillRectangle (s->display, s->window, &xgcv,
4086 left_x, top_y, right_x - left_x, width);
4087
4088 /* Left. */
4089 if (left_p)
4090 XFillRectangle (s->display, s->window, &xgcv,
4091 left_x, top_y, width, bottom_y - top_y);
4092
4093 /* Bottom. */
4094 XFillRectangle (s->display, s->window, &xgcv,
4095 left_x, bottom_y - width, right_x - left_x, width);
4096
4097 /* Right. */
4098 if (right_p)
4099 XFillRectangle (s->display, s->window, &xgcv,
4100 right_x - width, top_y, width, bottom_y - top_y);
4101
4102 mac_reset_clipping (s->display, s->window);
4103}
4104
4105
4106/* Draw a box around glyph string S. */
4107
4108static void
4109x_draw_glyph_string_box (s)
4110 struct glyph_string *s;
4111{
4112 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
4113 int left_p, right_p;
4114 struct glyph *last_glyph;
4115 Rect clip_rect;
4116
4117 last_x = window_box_right (s->w, s->area);
4118 if (s->row->full_width_p
4119 && !s->w->pseudo_window_p)
4120 {
4121 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
4122 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
4123 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
4124 }
4125
4126 /* The glyph that may have a right box line. */
4127 last_glyph = (s->cmp || s->img
4128 ? s->first_glyph
4129 : s->first_glyph + s->nchars - 1);
4130
4131 width = s->face->box_line_width;
4132 raised_p = s->face->box == FACE_RAISED_BOX;
4133 left_x = s->x;
4134 right_x = ((s->row->full_width_p
4135 ? last_x - 1
4136 : min (last_x, s->x + s->background_width) - 1));
4137 top_y = s->y;
4138 bottom_y = top_y + s->height - 1;
4139
4140 left_p = (s->first_glyph->left_box_line_p
4141 || (s->hl == DRAW_MOUSE_FACE
4142 && (s->prev == NULL
4143 || s->prev->hl != s->hl)));
4144 right_p = (last_glyph->right_box_line_p
4145 || (s->hl == DRAW_MOUSE_FACE
4146 && (s->next == NULL
4147 || s->next->hl != s->hl)));
4148
4149 x_get_glyph_string_clip_rect (s, &clip_rect);
4150
4151 if (s->face->box == FACE_SIMPLE_BOX)
4152 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4153 left_p, right_p, &clip_rect);
4154 else
4155 {
4156 x_setup_relief_colors (s);
4157 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4158 width, raised_p, left_p, right_p, &clip_rect);
4159 }
4160}
4161
4162
4163/* Draw foreground of image glyph string S. */
4164
4165static void
4166x_draw_image_foreground (s)
4167 struct glyph_string *s;
4168{
4169 int x;
4170 int y = s->ybase - image_ascent (s->img, s->face);
4171
4172 /* If first glyph of S has a left box line, start drawing it to the
4173 right of that line. */
4174 if (s->face->box != FACE_NO_BOX
4175 && s->first_glyph->left_box_line_p)
4176 x = s->x + s->face->box_line_width;
4177 else
4178 x = s->x;
4179
4180 /* If there is a margin around the image, adjust x- and y-position
4181 by that margin. */
4182 x += s->img->hmargin;
4183 y += s->img->vmargin;
4184
4185 if (s->img->pixmap)
4186 {
4187#if 0 /* MAC_TODO: image mask */
4188 if (s->img->mask)
4189 {
4190 /* We can't set both a clip mask and use XSetClipRectangles
4191 because the latter also sets a clip mask. We also can't
4192 trust on the shape extension to be available
4193 (XShapeCombineRegion). So, compute the rectangle to draw
4194 manually. */
4195 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4196 | GCFunction);
4197 XGCValues xgcv;
4198 XRectangle clip_rect, image_rect, r;
4199
4200 xgcv.clip_mask = s->img->mask;
4201 xgcv.clip_x_origin = x;
4202 xgcv.clip_y_origin = y;
4203 xgcv.function = GXcopy;
4204 XChangeGC (s->display, s->gc, mask, &xgcv);
4205
4206 x_get_glyph_string_clip_rect (s, &clip_rect);
4207 image_rect.x = x;
4208 image_rect.y = y;
4209 image_rect.width = s->img->width;
4210 image_rect.height = s->img->height;
4211 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4212 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4213 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4214 }
4215 else
4216#endif
4217 {
4218 mac_copy_area (s->display, s->img->pixmap, s->window, s->gc,
4219 0, 0, s->img->width, s->img->height, x, y);
4220
4221 /* When the image has a mask, we can expect that at
4222 least part of a mouse highlight or a block cursor will
4223 be visible. If the image doesn't have a mask, make
4224 a block cursor visible by drawing a rectangle around
4225 the image. I believe it's looking better if we do
4226 nothing here for mouse-face. */
4227 if (s->hl == DRAW_CURSOR)
4228 mac_draw_rectangle (s->display, s->window, s->gc, x, y,
4229 s->img->width - 1, s->img->height - 1);
4230 }
4231 }
4232 else
4233 /* Draw a rectangle if image could not be loaded. */
4234 mac_draw_rectangle (s->display, s->window, s->gc, x, y,
4235 s->img->width - 1, s->img->height - 1);
4236}
4237
4238
4239/* Draw a relief around the image glyph string S. */
4240
4241static void
4242x_draw_image_relief (s)
4243 struct glyph_string *s;
4244{
4245 int x0, y0, x1, y1, thick, raised_p;
4246 Rect r;
4247 int x;
4248 int y = s->ybase - image_ascent (s->img, s->face);
4249
4250 /* If first glyph of S has a left box line, start drawing it to the
4251 right of that line. */
4252 if (s->face->box != FACE_NO_BOX
4253 && s->first_glyph->left_box_line_p)
4254 x = s->x + s->face->box_line_width;
4255 else
4256 x = s->x;
4257
4258 /* If there is a margin around the image, adjust x- and y-position
4259 by that margin. */
4260 x += s->img->hmargin;
4261 y += s->img->vmargin;
4262
4263 if (s->hl == DRAW_IMAGE_SUNKEN
4264 || s->hl == DRAW_IMAGE_RAISED)
4265 {
4266 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
4267 raised_p = s->hl == DRAW_IMAGE_RAISED;
4268 }
4269 else
4270 {
4271 thick = abs (s->img->relief);
4272 raised_p = s->img->relief > 0;
4273 }
4274
4275 x0 = x - thick;
4276 y0 = y - thick;
4277 x1 = x + s->img->width + thick - 1;
4278 y1 = y + s->img->height + thick - 1;
4279
4280 x_setup_relief_colors (s);
4281 x_get_glyph_string_clip_rect (s, &r);
4282 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4283}
4284
4285
4286/* Draw the foreground of image glyph string S to PIXMAP. */
4287
4288static void
4289x_draw_image_foreground_1 (s, pixmap)
4290 struct glyph_string *s;
4291 Pixmap pixmap;
4292{
4293 int x;
4294 int y = s->ybase - s->y - image_ascent (s->img, s->face);
4295
4296 /* If first glyph of S has a left box line, start drawing it to the
4297 right of that line. */
4298 if (s->face->box != FACE_NO_BOX
4299 && s->first_glyph->left_box_line_p)
4300 x = s->face->box_line_width;
4301 else
4302 x = 0;
4303
4304 /* If there is a margin around the image, adjust x- and y-position
4305 by that margin. */
4306 x += s->img->hmargin;
4307 y += s->img->vmargin;
4308
4309 if (s->img->pixmap)
4310 {
4311#if 0 /* MAC_TODO: image mask */
4312 if (s->img->mask)
4313 {
4314 /* We can't set both a clip mask and use XSetClipRectangles
4315 because the latter also sets a clip mask. We also can't
4316 trust on the shape extension to be available
4317 (XShapeCombineRegion). So, compute the rectangle to draw
4318 manually. */
4319 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4320 | GCFunction);
4321 XGCValues xgcv;
4322
4323 xgcv.clip_mask = s->img->mask;
4324 xgcv.clip_x_origin = x;
4325 xgcv.clip_y_origin = y;
4326 xgcv.function = GXcopy;
4327 XChangeGC (s->display, s->gc, mask, &xgcv);
4328
4329 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4330 0, 0, s->img->width, s->img->height, x, y);
4331 XSetClipMask (s->display, s->gc, None);
4332 }
4333 else
4334#endif
4335 {
4336 mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc,
4337 0, 0, s->img->width, s->img->height, x, y);
4338
4339 /* When the image has a mask, we can expect that at
4340 least part of a mouse highlight or a block cursor will
4341 be visible. If the image doesn't have a mask, make
4342 a block cursor visible by drawing a rectangle around
4343 the image. I believe it's looking better if we do
4344 nothing here for mouse-face. */
4345 if (s->hl == DRAW_CURSOR)
4346 mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y,
4347 s->img->width - 1, s->img->height - 1);
4348 }
4349 }
4350 else
4351 /* Draw a rectangle if image could not be loaded. */
4352 mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y,
4353 s->img->width - 1, s->img->height - 1);
4354}
4355
4356
4357/* Draw part of the background of glyph string S. X, Y, W, and H
4358 give the rectangle to draw. */
4359
4360static void
4361x_draw_glyph_string_bg_rect (s, x, y, w, h)
4362 struct glyph_string *s;
4363 int x, y, w, h;
4364{
4365#if 0 /* MAC_TODO: stipple */
4366 if (s->stippled_p)
4367 {
4368 /* Fill background with a stipple pattern. */
4369 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4370 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4371 XSetFillStyle (s->display, s->gc, FillSolid);
4372 }
4373 else
4374#endif
4375 x_clear_glyph_string_rect (s, x, y, w, h);
4376}
4377
4378
4379/* Draw image glyph string S.
4380
4381 s->y
4382 s->x +-------------------------
4383 | s->face->box
4384 |
4385 | +-------------------------
4386 | | s->img->vmargin
4387 | |
4388 | | +-------------------
4389 | | | the image
4390
4391 */
4392
4393static void
4394x_draw_image_glyph_string (s)
4395 struct glyph_string *s;
4396{
4397 int x, y;
4398 int box_line_width = s->face->box_line_width;
4399 int height;
4400 Pixmap pixmap = 0;
4401
4402 height = s->height - 2 * box_line_width;
4403
4404 /* Fill background with face under the image. Do it only if row is
4405 taller than image or if image has a clip mask to reduce
4406 flickering. */
4407 s->stippled_p = s->face->stipple != 0;
4408 if (height > s->img->height
4409 || s->img->vmargin
4410 || s->img->hmargin
4411#if 0 /* MAC_TODO: image mask */
4412 || s->img->mask
4413#endif
4414 || s->img->pixmap == 0
4415 || s->width != s->background_width)
4416 {
4417 if (box_line_width && s->first_glyph->left_box_line_p)
4418 x = s->x + box_line_width;
4419 else
4420 x = s->x;
4421
4422 y = s->y + box_line_width;
4423
4424#if 0 /* MAC_TODO: image mask */
4425 if (s->img->mask)
4426 {
4427 /* Create a pixmap as large as the glyph string Fill it with
4428 the background color. Copy the image to it, using its
4429 mask. Copy the temporary pixmap to the display. */
4430 Screen *screen = FRAME_X_SCREEN (s->f);
4431 int depth = DefaultDepthOfScreen (screen);
4432
4433 /* Create a pixmap as large as the glyph string. */
4434 pixmap = XCreatePixmap (s->display, s->window,
4435 s->background_width,
4436 s->height, depth);
4437
4438 /* Don't clip in the following because we're working on the
4439 pixmap. */
4440 XSetClipMask (s->display, s->gc, None);
4441
4442 /* Fill the pixmap with the background color/stipple. */
4443 if (s->stippled_p)
4444 {
4445 /* Fill background with a stipple pattern. */
4446 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4447 XFillRectangle (s->display, pixmap, s->gc,
4448 0, 0, s->background_width, s->height);
4449 XSetFillStyle (s->display, s->gc, FillSolid);
4450 }
4451 else
4452 {
4453 XGCValues xgcv;
4454 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4455 &xgcv);
4456 XSetForeground (s->display, s->gc, xgcv.background);
4457 XFillRectangle (s->display, pixmap, s->gc,
4458 0, 0, s->background_width, s->height);
4459 XSetForeground (s->display, s->gc, xgcv.foreground);
4460 }
4461 }
4462 else
4463#endif
4464 /* Implementation idea: Is it possible to construct a mask?
4465 We could look at the color at the margins of the image, and
4466 say that this color is probably the background color of the
4467 image. */
4468 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4469
4470 s->background_filled_p = 1;
4471 }
4472
4473 /* Draw the foreground. */
4474 if (pixmap != 0)
4475 {
4476 x_draw_image_foreground_1 (s, pixmap);
4477 x_set_glyph_string_clipping (s);
4478 mac_copy_area (s->display, pixmap, s->window, s->gc,
4479 0, 0, s->background_width, s->height, s->x, s->y);
4480 XFreePixmap (s->display, pixmap);
4481 }
4482 else
4483 x_draw_image_foreground (s);
4484
4485 /* If we must draw a relief around the image, do it. */
4486 if (s->img->relief
4487 || s->hl == DRAW_IMAGE_RAISED
4488 || s->hl == DRAW_IMAGE_SUNKEN)
4489 x_draw_image_relief (s);
4490}
4491
4492
4493/* Draw stretch glyph string S. */
4494
4495static void
4496x_draw_stretch_glyph_string (s)
4497 struct glyph_string *s;
4498{
4499 xassert (s->first_glyph->type == STRETCH_GLYPH);
4500 s->stippled_p = s->face->stipple != 0;
4501
4502 if (s->hl == DRAW_CURSOR
4503 && !x_stretch_cursor_p)
4504 {
4505 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4506 as wide as the stretch glyph. */
4507 int width = min (CANON_X_UNIT (s->f), s->background_width);
4508
4509 /* Draw cursor. */
4510 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
4511
4512 /* Clear rest using the GC of the original non-cursor face. */
4513 if (width < s->background_width)
4514 {
4515 GC gc = s->face->gc;
4516 int x = s->x + width, y = s->y;
4517 int w = s->background_width - width, h = s->height;
4518 Rect r;
4519
4520 x_get_glyph_string_clip_rect (s, &r);
4521 mac_set_clip_rectangle (s->display, s->window, &r);
4522
4523#if 0 /* MAC_TODO: stipple */
4524 if (s->face->stipple)
4525 {
4526 /* Fill background with a stipple pattern. */
4527 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4528 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4529 XSetFillStyle (s->display, gc, FillSolid);
4530 }
4531 else
4532#endif
4533 {
4534 XGCValues xgcv;
4535 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4536 XSetForeground (s->display, gc, xgcv.background);
4537 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4538 XSetForeground (s->display, gc, xgcv.foreground);
4539 }
4540 }
4541 }
4542 else
4543 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4544 s->height);
4545
4546 s->background_filled_p = 1;
4547}
4548
4549
4550/* Draw glyph string S. */
4551
4552static void
4553x_draw_glyph_string (s)
4554 struct glyph_string *s;
4555{
4556 /* If S draws into the background of its successor, draw the
4557 background of the successor first so that S can draw into it.
4558 This makes S->next use XDrawString instead of XDrawImageString. */
4559 if (s->next && s->right_overhang && !s->for_overlaps_p)
4560 {
4561 xassert (s->next->img == NULL);
4562 x_set_glyph_string_gc (s->next);
4563 x_set_glyph_string_clipping (s->next);
4564 x_draw_glyph_string_background (s->next, 1);
4565 }
4566
4567 /* Set up S->gc, set clipping and draw S. */
4568 x_set_glyph_string_gc (s);
4569 x_set_glyph_string_clipping (s);
4570
4571 switch (s->first_glyph->type)
4572 {
4573 case IMAGE_GLYPH:
4574 x_draw_image_glyph_string (s);
4575 break;
4576
4577 case STRETCH_GLYPH:
4578 x_draw_stretch_glyph_string (s);
4579 break;
4580
4581 case CHAR_GLYPH:
4582 if (s->for_overlaps_p)
4583 s->background_filled_p = 1;
4584 else
4585 x_draw_glyph_string_background (s, 0);
4586 x_draw_glyph_string_foreground (s);
4587 break;
4588
4589 case COMPOSITE_GLYPH:
4590 if (s->for_overlaps_p || s->gidx > 0)
4591 s->background_filled_p = 1;
4592 else
4593 x_draw_glyph_string_background (s, 1);
4594 x_draw_composite_glyph_string_foreground (s);
4595 break;
4596
4597 default:
4598 abort ();
4599 }
4600
4601 if (!s->for_overlaps_p)
4602 {
4603 /* Draw underline. */
4604 if (s->face->underline_p)
4605 {
4606 unsigned long h = 1;
4607 unsigned long dy = s->height - h;
4608
4609 if (s->face->underline_defaulted_p)
4610 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4611 s->width, h);
4612 else
4613 {
4614 XGCValues xgcv;
4615 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4616 XSetForeground (s->display, s->gc, s->face->underline_color);
4617 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4618 s->width, h);
4619 XSetForeground (s->display, s->gc, xgcv.foreground);
4620 }
4621 }
4622
4623 /* Draw overline. */
4624 if (s->face->overline_p)
4625 {
4626 unsigned long dy = 0, h = 1;
4627
4628 if (s->face->overline_color_defaulted_p)
4629 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4630 s->width, h);
4631 else
4632 {
4633 XGCValues xgcv;
4634 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4635 XSetForeground (s->display, s->gc, s->face->overline_color);
4636 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4637 s->width, h);
4638 XSetForeground (s->display, s->gc, xgcv.foreground);
4639 }
4640 }
4641
4642 /* Draw strike-through. */
4643 if (s->face->strike_through_p)
4644 {
4645 unsigned long h = 1;
4646 unsigned long dy = (s->height - h) / 2;
4647
4648 if (s->face->strike_through_color_defaulted_p)
4649 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4650 s->width, h);
4651 else
4652 {
4653 XGCValues xgcv;
4654 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4655 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4656 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4657 s->width, h);
4658 XSetForeground (s->display, s->gc, xgcv.foreground);
4659 }
4660 }
4661
4662 /* Draw relief. */
4663 if (s->face->box != FACE_NO_BOX)
4664 x_draw_glyph_string_box (s);
4665 }
4666
4667 /* Reset clipping. */
4668 mac_reset_clipping (s->display, s->window);
4669}
4670
4671
4672static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4673 struct face **, int));
4674
4675
4676/* Fill glyph string S with composition components specified by S->cmp.
4677
4678 FACES is an array of faces for all components of this composition.
4679 S->gidx is the index of the first component for S.
4680 OVERLAPS_P non-zero means S should draw the foreground only, and
4681 use its physical height for clipping.
4682
4683 Value is the index of a component not in S. */
4684
4685static int
4686x_fill_composite_glyph_string (s, faces, overlaps_p)
4687 struct glyph_string *s;
4688 struct face **faces;
4689 int overlaps_p;
4690{
4691 int i;
4692
4693 xassert (s);
4694
4695 s->for_overlaps_p = overlaps_p;
4696
4697 s->face = faces[s->gidx];
4698 s->font = s->face->font;
4699 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4700
4701 /* For all glyphs of this composition, starting at the offset
4702 S->gidx, until we reach the end of the definition or encounter a
4703 glyph that requires the different face, add it to S. */
4704 ++s->nchars;
4705 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4706 ++s->nchars;
4707
4708 /* All glyph strings for the same composition has the same width,
4709 i.e. the width set for the first component of the composition. */
4710
4711 s->width = s->first_glyph->pixel_width;
4712
4713 /* If the specified font could not be loaded, use the frame's
4714 default font, but record the fact that we couldn't load it in
4715 the glyph string so that we can draw rectangles for the
4716 characters of the glyph string. */
4717 if (s->font == NULL)
4718 {
4719 s->font_not_found_p = 1;
4720 s->font = FRAME_FONT (s->f);
4721 }
4722
4723 /* Adjust base line for subscript/superscript text. */
4724 s->ybase += s->first_glyph->voffset;
4725
4726 xassert (s->face && s->face->gc);
4727
4728 /* This glyph string must always be drawn with 16-bit functions. */
4729 s->two_byte_p = 1;
4730
4731 return s->gidx + s->nchars;
4732}
4733
4734
4735/* Fill glyph string S from a sequence of character glyphs.
4736
4737 FACE_ID is the face id of the string. START is the index of the
4738 first glyph to consider, END is the index of the last + 1.
4739 OVERLAPS_P non-zero means S should draw the foreground only, and
4740 use its physical height for clipping.
4741
4742 Value is the index of the first glyph not in S. */
4743
4744static int
4745x_fill_glyph_string (s, face_id, start, end, overlaps_p)
4746 struct glyph_string *s;
4747 int face_id;
4748 int start, end, overlaps_p;
4749{
4750 struct glyph *glyph, *last;
4751 int voffset;
4752 int glyph_not_available_p;
4753
4754 xassert (s->f == XFRAME (s->w->frame));
4755 xassert (s->nchars == 0);
4756 xassert (start >= 0 && end > start);
4757
4758 s->for_overlaps_p = overlaps_p,
4759 glyph = s->row->glyphs[s->area] + start;
4760 last = s->row->glyphs[s->area] + end;
4761 voffset = glyph->voffset;
4762
4763 glyph_not_available_p = glyph->glyph_not_available_p;
4764
4765 while (glyph < last
4766 && glyph->type == CHAR_GLYPH
4767 && glyph->voffset == voffset
4768 /* Same face id implies same font, nowadays. */
4769 && glyph->face_id == face_id
4770 && glyph->glyph_not_available_p == glyph_not_available_p)
4771 {
4772 int two_byte_p;
4773
4774 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
4775 s->char2b + s->nchars,
4776 &two_byte_p);
4777 s->two_byte_p = two_byte_p;
4778 ++s->nchars;
4779 xassert (s->nchars <= end - start);
4780 s->width += glyph->pixel_width;
4781 ++glyph;
4782 }
4783
4784 s->font = s->face->font;
4785 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4786
4787 /* If the specified font could not be loaded, use the frame's font,
4788 but record the fact that we couldn't load it in
4789 S->font_not_found_p so that we can draw rectangles for the
4790 characters of the glyph string. */
4791 if (s->font == NULL || glyph_not_available_p)
4792 {
4793 s->font_not_found_p = 1;
4794 s->font = FRAME_FONT (s->f);
4795 }
4796
4797 /* Adjust base line for subscript/superscript text. */
4798 s->ybase += voffset;
4799
4800 xassert (s->face && s->face->gc);
4801 return glyph - s->row->glyphs[s->area];
4802}
4803
4804
4805/* Fill glyph string S from image glyph S->first_glyph. */
4806
4807static void
4808x_fill_image_glyph_string (s)
4809 struct glyph_string *s;
4810{
4811 xassert (s->first_glyph->type == IMAGE_GLYPH);
4812 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
4813 xassert (s->img);
4814 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
4815 s->font = s->face->font;
4816 s->width = s->first_glyph->pixel_width;
4817
4818 /* Adjust base line for subscript/superscript text. */
4819 s->ybase += s->first_glyph->voffset;
4820}
4821
4822
4823/* Fill glyph string S from a sequence of stretch glyphs.
4824
4825 ROW is the glyph row in which the glyphs are found, AREA is the
4826 area within the row. START is the index of the first glyph to
4827 consider, END is the index of the last + 1.
4828
4829 Value is the index of the first glyph not in S. */
4830
4831static int
4832x_fill_stretch_glyph_string (s, row, area, start, end)
4833 struct glyph_string *s;
4834 struct glyph_row *row;
4835 enum glyph_row_area area;
4836 int start, end;
4837{
4838 struct glyph *glyph, *last;
4839 int voffset, face_id;
4840
4841 xassert (s->first_glyph->type == STRETCH_GLYPH);
4842
4843 glyph = s->row->glyphs[s->area] + start;
4844 last = s->row->glyphs[s->area] + end;
4845 face_id = glyph->face_id;
4846 s->face = FACE_FROM_ID (s->f, face_id);
4847 s->font = s->face->font;
4848 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4849 s->width = glyph->pixel_width;
4850 voffset = glyph->voffset;
4851
4852 for (++glyph;
4853 (glyph < last
4854 && glyph->type == STRETCH_GLYPH
4855 && glyph->voffset == voffset
4856 && glyph->face_id == face_id);
4857 ++glyph)
4858 s->width += glyph->pixel_width;
4859
4860 /* Adjust base line for subscript/superscript text. */
4861 s->ybase += voffset;
4862
4863 xassert (s->face && s->face->gc);
4864 return glyph - s->row->glyphs[s->area];
4865}
4866
4867
4868/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4869 of XChar2b structures for S; it can't be allocated in
4870 x_init_glyph_string because it must be allocated via `alloca'. W
4871 is the window on which S is drawn. ROW and AREA are the glyph row
4872 and area within the row from which S is constructed. START is the
4873 index of the first glyph structure covered by S. HL is a
4874 face-override for drawing S. */
4875
4876static void
4877x_init_glyph_string (s, char2b, w, row, area, start, hl)
4878 struct glyph_string *s;
4879 XChar2b *char2b;
4880 struct window *w;
4881 struct glyph_row *row;
4882 enum glyph_row_area area;
4883 int start;
4884 enum draw_glyphs_face hl;
4885{
4886 bzero (s, sizeof *s);
4887 s->w = w;
4888 s->f = XFRAME (w->frame);
4889 s->display = FRAME_MAC_DISPLAY (s->f);
4890 s->window = FRAME_MAC_WINDOW (s->f);
4891 s->char2b = char2b;
4892 s->hl = hl;
4893 s->row = row;
4894 s->area = area;
4895 s->first_glyph = row->glyphs[area] + start;
4896 s->height = row->height;
4897 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4898
4899 /* Display the internal border below the tool-bar window. */
4900 if (s->w == XWINDOW (s->f->tool_bar_window))
4901 s->y -= s->f->output_data.mac->internal_border_width;
4902
4903 s->ybase = s->y + row->ascent;
4904}
4905
4906
4907/* Set background width of glyph string S. START is the index of the
4908 first glyph following S. LAST_X is the right-most x-position + 1
4909 in the drawing area. */
4910
4911static INLINE void
4912x_set_glyph_string_background_width (s, start, last_x)
4913 struct glyph_string *s;
4914 int start;
4915 int last_x;
4916{
4917 /* If the face of this glyph string has to be drawn to the end of
4918 the drawing area, set S->extends_to_end_of_line_p. */
4919 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4920
4921 if (start == s->row->used[s->area]
4922 && s->hl == DRAW_NORMAL_TEXT
4923 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4924 || s->face->background != default_face->background
4925 || s->face->stipple != default_face->stipple))
4926 s->extends_to_end_of_line_p = 1;
4927
4928 /* If S extends its face to the end of the line, set its
4929 background_width to the distance to the right edge of the drawing
4930 area. */
4931 if (s->extends_to_end_of_line_p)
4932 s->background_width = last_x - s->x + 1;
4933 else
4934 s->background_width = s->width;
4935}
4936
4937
4938/* Add a glyph string for a stretch glyph to the list of strings
4939 between HEAD and TAIL. START is the index of the stretch glyph in
4940 row area AREA of glyph row ROW. END is the index of the last glyph
4941 in that glyph row area. X is the current output position assigned
4942 to the new glyph string constructed. HL overrides that face of the
4943 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4944 is the right-most x-position of the drawing area. */
4945
4946/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4947 and below -- keep them on one line. */
4948#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
4949 do \
4950 { \
4951 s = (struct glyph_string *) alloca (sizeof *s); \
4952 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4953 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
4954 x_append_glyph_string (&HEAD, &TAIL, s); \
4955 s->x = (X); \
4956 } \
4957 while (0)
4958
4959
4960/* Add a glyph string for an image glyph to the list of strings
4961 between HEAD and TAIL. START is the index of the image glyph in
4962 row area AREA of glyph row ROW. END is the index of the last glyph
4963 in that glyph row area. X is the current output position assigned
4964 to the new glyph string constructed. HL overrides that face of the
4965 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4966 is the right-most x-position of the drawing area. */
4967
4968#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
4969 do \
4970 { \
4971 s = (struct glyph_string *) alloca (sizeof *s); \
4972 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4973 x_fill_image_glyph_string (s); \
4974 x_append_glyph_string (&HEAD, &TAIL, s); \
4975 ++START; \
4976 s->x = (X); \
4977 } \
4978 while (0)
4979
4980
4981/* Add a glyph string for a sequence of character glyphs to the list
4982 of strings between HEAD and TAIL. START is the index of the first
4983 glyph in row area AREA of glyph row ROW that is part of the new
4984 glyph string. END is the index of the last glyph in that glyph row
4985 area. X is the current output position assigned to the new glyph
4986 string constructed. HL overrides that face of the glyph; e.g. it
4987 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4988 right-most x-position of the drawing area. */
4989
4990#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
4991 do \
4992 { \
4993 int c, face_id; \
4994 XChar2b *char2b; \
4995 \
4996 c = (ROW)->glyphs[AREA][START].u.ch; \
4997 face_id = (ROW)->glyphs[AREA][START].face_id; \
4998 \
4999 s = (struct glyph_string *) alloca (sizeof *s); \
5000 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
5001 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
5002 x_append_glyph_string (&HEAD, &TAIL, s); \
5003 s->x = (X); \
5004 START = x_fill_glyph_string (s, face_id, START, END, \
5005 OVERLAPS_P); \
5006 } \
5007 while (0)
5008
5009
5010/* Add a glyph string for a composite sequence to the list of strings
5011 between HEAD and TAIL. START is the index of the first glyph in
5012 row area AREA of glyph row ROW that is part of the new glyph
5013 string. END is the index of the last glyph in that glyph row area.
5014 X is the current output position assigned to the new glyph string
5015 constructed. HL overrides that face of the glyph; e.g. it is
5016 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
5017 x-position of the drawing area. */
5018
5019#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
5020 do { \
5021 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
5022 int face_id = (ROW)->glyphs[AREA][START].face_id; \
5023 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
5024 struct composition *cmp = composition_table[cmp_id]; \
5025 int glyph_len = cmp->glyph_len; \
5026 XChar2b *char2b; \
5027 struct face **faces; \
5028 struct glyph_string *first_s = NULL; \
5029 int n; \
5030 \
5031 base_face = base_face->ascii_face; \
5032 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
5033 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
5034 /* At first, fill in `char2b' and `faces'. */ \
5035 for (n = 0; n < glyph_len; n++) \
5036 { \
5037 int c = COMPOSITION_GLYPH (cmp, n); \
5038 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
5039 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
5040 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
5041 this_face_id, char2b + n, 1); \
5042 } \
5043 \
5044 /* Make glyph_strings for each glyph sequence that is drawable by \
5045 the same face, and append them to HEAD/TAIL. */ \
5046 for (n = 0; n < cmp->glyph_len;) \
5047 { \
5048 s = (struct glyph_string *) alloca (sizeof *s); \
5049 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
5050 x_append_glyph_string (&(HEAD), &(TAIL), s); \
5051 s->cmp = cmp; \
5052 s->gidx = n; \
5053 s->x = (X); \
5054 \
5055 if (n == 0) \
5056 first_s = s; \
5057 \
5058 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
5059 } \
5060 \
5061 ++START; \
5062 s = first_s; \
5063 } while (0)
5064
5065
5066/* Build a list of glyph strings between HEAD and TAIL for the glyphs
5067 of AREA of glyph row ROW on window W between indices START and END.
5068 HL overrides the face for drawing glyph strings, e.g. it is
5069 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
5070 x-positions of the drawing area.
5071
5072 This is an ugly monster macro construct because we must use alloca
5073 to allocate glyph strings (because x_draw_glyphs can be called
5074 asynchronously). */
5075
5076#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
5077 do \
5078 { \
5079 HEAD = TAIL = NULL; \
5080 while (START < END) \
5081 { \
5082 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
5083 switch (first_glyph->type) \
5084 { \
5085 case CHAR_GLYPH: \
5086 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
5087 TAIL, HL, X, LAST_X, \
5088 OVERLAPS_P); \
5089 break; \
5090 \
5091 case COMPOSITE_GLYPH: \
5092 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5093 HEAD, TAIL, HL, X, LAST_X,\
5094 OVERLAPS_P); \
5095 break; \
5096 \
5097 case STRETCH_GLYPH: \
5098 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5099 HEAD, TAIL, HL, X, LAST_X); \
5100 break; \
5101 \
5102 case IMAGE_GLYPH: \
5103 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5104 TAIL, HL, X, LAST_X); \
5105 break; \
5106 \
5107 default: \
5108 abort (); \
5109 } \
5110 \
5111 x_set_glyph_string_background_width (s, START, LAST_X); \
5112 (X) += s->width; \
5113 } \
5114 } \
5115 while (0)
5116
5117
5118/* Draw glyphs between START and END in AREA of ROW on window W,
5119 starting at x-position X. X is relative to AREA in W. HL is a
5120 face-override with the following meaning:
5121
5122 DRAW_NORMAL_TEXT draw normally
5123 DRAW_CURSOR draw in cursor face
5124 DRAW_MOUSE_FACE draw in mouse face.
5125 DRAW_INVERSE_VIDEO draw in mode line face
5126 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5127 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5128
5129 If REAL_START is non-null, return in *REAL_START the real starting
5130 position for display. This can be different from START in case
5131 overlapping glyphs must be displayed. If REAL_END is non-null,
5132 return in *REAL_END the real end position for display. This can be
5133 different from END in case overlapping glyphs must be displayed.
5134
5135 If OVERLAPS_P is non-zero, draw only the foreground of characters
5136 and clip to the physical height of ROW.
5137
5138 Value is the x-position reached, relative to AREA of W. */
5139
5140static int
5141x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
5142 overlaps_p)
5143 struct window *w;
5144 int x;
5145 struct glyph_row *row;
5146 enum glyph_row_area area;
5147 int start, end;
5148 enum draw_glyphs_face hl;
5149 int *real_start, *real_end;
5150 int overlaps_p;
5151{
5152 struct glyph_string *head, *tail;
5153 struct glyph_string *s;
5154 int last_x, area_width;
5155 int x_reached;
5156 int i, j;
5157
5158 /* Let's rather be paranoid than getting a SEGV. */
5159 start = max (0, start);
5160 end = min (end, row->used[area]);
5161 if (real_start)
5162 *real_start = start;
5163 if (real_end)
5164 *real_end = end;
5165
5166 /* Translate X to frame coordinates. Set last_x to the right
5167 end of the drawing area. */
5168 if (row->full_width_p)
5169 {
5170 /* X is relative to the left edge of W, without scroll bars
5171 or fringes. */
5172 struct frame *f = XFRAME (w->frame);
5173 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
5174
5175 x += window_left_x;
5176 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5177 last_x = window_left_x + area_width;
5178
5179 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5180 {
5181 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
5182 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5183 last_x += width;
5184 else
5185 x -= width;
5186 }
5187
5188 x += FRAME_INTERNAL_BORDER_WIDTH (f);
5189 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
5190 }
5191 else
5192 {
5193 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5194 area_width = window_box_width (w, area);
5195 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
5196 }
5197
5198 /* Build a doubly-linked list of glyph_string structures between
5199 head and tail from what we have to draw. Note that the macro
5200 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5201 the reason we use a separate variable `i'. */
5202 i = start;
5203 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5204 overlaps_p);
5205 if (tail)
5206 x_reached = tail->x + tail->background_width;
5207 else
5208 x_reached = x;
5209
5210 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5211 the row, redraw some glyphs in front or following the glyph
5212 strings built above. */
5213 if (!overlaps_p && row->contains_overlapping_glyphs_p)
5214 {
5215 int dummy_x = 0;
5216 struct glyph_string *h, *t;
5217
5218 /* Compute overhangs for all glyph strings. */
5219 for (s = head; s; s = s->next)
5220 x_compute_glyph_string_overhangs (s);
5221
5222 /* Prepend glyph strings for glyphs in front of the first glyph
5223 string that are overwritten because of the first glyph
5224 string's left overhang. The background of all strings
5225 prepended must be drawn because the first glyph string
5226 draws over it. */
5227 i = x_left_overwritten (head);
5228 if (i >= 0)
5229 {
5230 j = i;
5231 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
5232 DRAW_NORMAL_TEXT, dummy_x, last_x,
5233 overlaps_p);
5234 start = i;
5235 if (real_start)
5236 *real_start = start;
5237 x_compute_overhangs_and_x (t, head->x, 1);
5238 x_prepend_glyph_string_lists (&head, &tail, h, t);
5239 }
5240
5241 /* Prepend glyph strings for glyphs in front of the first glyph
5242 string that overwrite that glyph string because of their
5243 right overhang. For these strings, only the foreground must
5244 be drawn, because it draws over the glyph string at `head'.
5245 The background must not be drawn because this would overwrite
5246 right overhangs of preceding glyphs for which no glyph
5247 strings exist. */
5248 i = x_left_overwriting (head);
5249 if (i >= 0)
5250 {
5251 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
5252 DRAW_NORMAL_TEXT, dummy_x, last_x,
5253 overlaps_p);
5254 for (s = h; s; s = s->next)
5255 s->background_filled_p = 1;
5256 if (real_start)
5257 *real_start = i;
5258 x_compute_overhangs_and_x (t, head->x, 1);
5259 x_prepend_glyph_string_lists (&head, &tail, h, t);
5260 }
5261
5262 /* Append glyphs strings for glyphs following the last glyph
5263 string tail that are overwritten by tail. The background of
5264 these strings has to be drawn because tail's foreground draws
5265 over it. */
5266 i = x_right_overwritten (tail);
5267 if (i >= 0)
5268 {
5269 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
5270 DRAW_NORMAL_TEXT, x, last_x,
5271 overlaps_p);
5272 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5273 x_append_glyph_string_lists (&head, &tail, h, t);
5274 if (real_end)
5275 *real_end = i;
5276 }
5277
5278 /* Append glyph strings for glyphs following the last glyph
5279 string tail that overwrite tail. The foreground of such
5280 glyphs has to be drawn because it writes into the background
5281 of tail. The background must not be drawn because it could
5282 paint over the foreground of following glyphs. */
5283 i = x_right_overwriting (tail);
5284 if (i >= 0)
5285 {
5286 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
5287 DRAW_NORMAL_TEXT, x, last_x,
5288 overlaps_p);
5289 for (s = h; s; s = s->next)
5290 s->background_filled_p = 1;
5291 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5292 x_append_glyph_string_lists (&head, &tail, h, t);
5293 if (real_end)
5294 *real_end = i;
5295 }
5296 }
5297
5298 /* Draw all strings. */
5299 for (s = head; s; s = s->next)
5300 x_draw_glyph_string (s);
5301
5302 /* Value is the x-position up to which drawn, relative to AREA of W.
5303 This doesn't include parts drawn because of overhangs. */
5304 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5305 if (!row->full_width_p)
5306 {
5307 if (area > LEFT_MARGIN_AREA)
5308 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5309 if (area > TEXT_AREA)
5310 x_reached -= window_box_width (w, TEXT_AREA);
5311 }
5312 return x_reached;
5313}
5314
5315
5316/* Fix the display of area AREA of overlapping row ROW in window W. */
5317
5318void
5319x_fix_overlapping_area (w, row, area)
5320 struct window *w;
5321 struct glyph_row *row;
5322 enum glyph_row_area area;
5323{
5324 int i, x;
5325
5326 BLOCK_INPUT;
5327
5328 if (area == LEFT_MARGIN_AREA)
5329 x = 0;
5330 else if (area == TEXT_AREA)
5331 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5332 else
5333 x = (window_box_width (w, LEFT_MARGIN_AREA)
5334 + window_box_width (w, TEXT_AREA));
5335
5336 for (i = 0; i < row->used[area];)
5337 {
5338 if (row->glyphs[area][i].overlaps_vertically_p)
5339 {
5340 int start = i, start_x = x;
5341
5342 do
5343 {
5344 x += row->glyphs[area][i].pixel_width;
5345 ++i;
5346 }
5347 while (i < row->used[area]
5348 && row->glyphs[area][i].overlaps_vertically_p);
5349
5350 x_draw_glyphs (w, start_x, row, area, start, i,
5351 (row->inverse_p
5352 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5353 NULL, NULL, 1);
5354 }
5355 else
5356 {
5357 x += row->glyphs[area][i].pixel_width;
5358 ++i;
5359 }
5360 }
5361
5362 UNBLOCK_INPUT;
5363}
5364
5365
5366/* Output LEN glyphs starting at START at the nominal cursor position.
5367 Advance the nominal cursor over the text. The global variable
5368 updated_window contains the window being updated, updated_row is
5369 the glyph row being updated, and updated_area is the area of that
5370 row being updated. */
5371
5372void
5373x_write_glyphs (start, len)
5374 struct glyph *start;
5375 int len;
5376{
5377 int x, hpos, real_start, real_end;
5378
5379 xassert (updated_window && updated_row);
5380 BLOCK_INPUT;
5381
5382 /* Write glyphs. */
5383
5384 hpos = start - updated_row->glyphs[updated_area];
5385 x = x_draw_glyphs (updated_window, output_cursor.x,
5386 updated_row, updated_area,
5387 hpos, hpos + len,
5388 (updated_row->inverse_p
5389 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5390 &real_start, &real_end, 0);
5391
5392 /* If we drew over the cursor, note that it is not visible any more. */
5393 note_overwritten_text_cursor (updated_window, real_start,
5394 real_end - real_start);
5395
5396 UNBLOCK_INPUT;
5397
5398 /* Advance the output cursor. */
5399 output_cursor.hpos += len;
5400 output_cursor.x = x;
5401}
5402
5403
5404/* Insert LEN glyphs from START at the nominal cursor position. */
5405
5406void
5407x_insert_glyphs (start, len)
5408 struct glyph *start;
5409 register int len;
5410{
5411 struct frame *f;
5412 struct window *w;
5413 int line_height, shift_by_width, shifted_region_width;
5414 struct glyph_row *row;
5415 struct glyph *glyph;
5416 int frame_x, frame_y, hpos, real_start, real_end;
5417
5418 xassert (updated_window && updated_row);
5419 BLOCK_INPUT;
5420 w = updated_window;
5421 f = XFRAME (WINDOW_FRAME (w));
5422
5423 /* Get the height of the line we are in. */
5424 row = updated_row;
5425 line_height = row->height;
5426
5427 /* Get the width of the glyphs to insert. */
5428 shift_by_width = 0;
5429 for (glyph = start; glyph < start + len; ++glyph)
5430 shift_by_width += glyph->pixel_width;
5431
5432 /* Get the width of the region to shift right. */
5433 shifted_region_width = (window_box_width (w, updated_area)
5434 - output_cursor.x
5435 - shift_by_width);
5436
5437 /* Shift right. */
5438 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
5439 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5440
5441 mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
5442 f->output_data.mac->normal_gc,
5443 frame_x, frame_y,
5444 shifted_region_width, line_height,
5445 frame_x + shift_by_width, frame_y);
5446
5447 /* Write the glyphs. */
5448 hpos = start - row->glyphs[updated_area];
5449 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
5450 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
5451 note_overwritten_text_cursor (w, real_start, real_end - real_start);
5452
5453 /* Advance the output cursor. */
5454 output_cursor.hpos += len;
5455 output_cursor.x += shift_by_width;
5456 UNBLOCK_INPUT;
5457}
5458
5459
5460/* Delete N glyphs at the nominal cursor position. Not implemented
5461 for X frames. */
5462
5463void
5464x_delete_glyphs (n)
5465 register int n;
5466{
5467 abort ();
5468}
5469
5470
5471/* Erase the current text line from the nominal cursor position
5472 (inclusive) to pixel column TO_X (exclusive). The idea is that
5473 everything from TO_X onward is already erased.
5474
5475 TO_X is a pixel position relative to updated_area of
5476 updated_window. TO_X == -1 means clear to the end of this area. */
5477
5478void
5479x_clear_end_of_line (to_x)
5480 int to_x;
5481{
5482 struct frame *f;
5483 struct window *w = updated_window;
5484 int max_x, min_y, max_y;
5485 int from_x, from_y, to_y;
5486
5487 xassert (updated_window && updated_row);
5488 f = XFRAME (w->frame);
5489
5490 if (updated_row->full_width_p)
5491 {
5492 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5493 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5494 && !w->pseudo_window_p)
5495 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
5496 }
5497 else
5498 max_x = window_box_width (w, updated_area);
5499 max_y = window_text_bottom_y (w);
5500
5501 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5502 of window. For TO_X > 0, truncate to end of drawing area. */
5503 if (to_x == 0)
5504 return;
5505 else if (to_x < 0)
5506 to_x = max_x;
5507 else
5508 to_x = min (to_x, max_x);
5509
5510 to_y = min (max_y, output_cursor.y + updated_row->height);
5511
5512 /* Notice if the cursor will be cleared by this operation. */
5513 if (!updated_row->full_width_p)
5514 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
5515
5516 from_x = output_cursor.x;
5517
5518 /* Translate to frame coordinates. */
5519 if (updated_row->full_width_p)
5520 {
5521 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5522 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5523 }
5524 else
5525 {
5526 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5527 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5528 }
5529
5530 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
5531 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5532 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5533
5534 /* Prevent inadvertently clearing to end of the X window. */
5535 if (to_x > from_x && to_y > from_y)
5536 {
5537 BLOCK_INPUT;
5538 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
5539 from_x, from_y, to_x - from_x, to_y - from_y,
5540 0);
5541 UNBLOCK_INPUT;
5542 }
5543}
5544
5545
5546/* Clear entire frame. If updating_frame is non-null, clear that
5547 frame. Otherwise clear the selected frame. */
5548
5549void
5550x_clear_frame ()
5551{
5552 struct frame *f;
5553
5554 if (updating_frame)
5555 f = updating_frame;
5556 else
5557 f = SELECTED_FRAME ();
5558
5559 /* Clearing the frame will erase any cursor, so mark them all as no
5560 longer visible. */
5561 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5562 output_cursor.hpos = output_cursor.vpos = 0;
5563 output_cursor.x = -1;
5564
5565 /* We don't set the output cursor here because there will always
5566 follow an explicit cursor_to. */
5567 BLOCK_INPUT;
5568 XClearWindow (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
5569
5570#if 0 /* Clearing frame on Mac OS clears scroll bars. */
5571 /* We have to clear the scroll bars, too. If we have changed
5572 colors or something like that, then they should be notified. */
5573 x_scroll_bar_clear (f);
5574#endif
5575
5576 XFlush (FRAME_MAC_DISPLAY (f));
5577 UNBLOCK_INPUT;
5578}
5579
5580
5581
5582/* Invert the middle quarter of the frame for .15 sec. */
5583
5584/* We use the select system call to do the waiting, so we have to make
5585 sure it's available. If it isn't, we just won't do visual bells. */
5586
5587#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5588
5589/* Subtract the `struct timeval' values X and Y, storing the result in
5590 *RESULT. Return 1 if the difference is negative, otherwise 0. */
5591
5592static int
5593timeval_subtract (result, x, y)
5594 struct timeval *result, x, y;
5595{
5596 /* Perform the carry for the later subtraction by updating y. This
5597 is safer because on some systems the tv_sec member is unsigned. */
5598 if (x.tv_usec < y.tv_usec)
5599 {
5600 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5601 y.tv_usec -= 1000000 * nsec;
5602 y.tv_sec += nsec;
5603 }
5604
5605 if (x.tv_usec - y.tv_usec > 1000000)
5606 {
5607 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5608 y.tv_usec += 1000000 * nsec;
5609 y.tv_sec -= nsec;
5610 }
5611
5612 /* Compute the time remaining to wait. tv_usec is certainly
5613 positive. */
5614 result->tv_sec = x.tv_sec - y.tv_sec;
5615 result->tv_usec = x.tv_usec - y.tv_usec;
5616
5617 /* Return indication of whether the result should be considered
5618 negative. */
5619 return x.tv_sec < y.tv_sec;
5620}
5621
5622void
5623XTflash (f)
5624 struct frame *f;
5625{
5626 BLOCK_INPUT;
5627
5628 FlashMenuBar (0);
5629
5630 {
5631 struct timeval wakeup;
5632
5633 EMACS_GET_TIME (wakeup);
5634
5635 /* Compute time to wait until, propagating carry from usecs. */
5636 wakeup.tv_usec += 150000;
5637 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5638 wakeup.tv_usec %= 1000000;
5639
5640 /* Keep waiting until past the time wakeup. */
5641 while (1)
5642 {
5643 struct timeval timeout;
5644
5645 EMACS_GET_TIME (timeout);
5646
5647 /* In effect, timeout = wakeup - timeout.
5648 Break if result would be negative. */
5649 if (timeval_subtract (&timeout, wakeup, timeout))
5650 break;
5651
5652 /* Try to wait that long--but we might wake up sooner. */
5653 select (0, NULL, NULL, NULL, &timeout);
5654 }
5655 }
5656
5657 FlashMenuBar (0);
5658
5659 UNBLOCK_INPUT;
5660}
5661
5662#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
5663
5664
5665/* Make audible bell. */
5666
5667void
5668XTring_bell ()
5669{
5670 struct frame *f = SELECTED_FRAME ();
5671
5672#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5673 if (visible_bell)
5674 XTflash (f);
5675 else
5676#endif
5677 {
5678 BLOCK_INPUT;
5679 SysBeep (1);
5680 XFlush (FRAME_MAC_DISPLAY (f));
5681 UNBLOCK_INPUT;
5682 }
5683}
5684
5685
5686
5687/* Specify how many text lines, from the top of the window,
5688 should be affected by insert-lines and delete-lines operations.
5689 This, and those operations, are used only within an update
5690 that is bounded by calls to x_update_begin and x_update_end. */
5691
5692void
5693XTset_terminal_window (n)
5694 register int n;
5695{
5696 /* This function intentionally left blank. */
5697}
5698
5699
5700
5701/***********************************************************************
5702 Line Dance
5703 ***********************************************************************/
5704
5705/* Perform an insert-lines or delete-lines operation, inserting N
5706 lines or deleting -N lines at vertical position VPOS. */
5707
5708void
5709x_ins_del_lines (vpos, n)
5710 int vpos, n;
5711{
5712 abort ();
5713}
5714
5715
5716/* Scroll part of the display as described by RUN. */
5717
5718void
5719x_scroll_run (w, run)
5720 struct window *w;
5721 struct run *run;
5722{
5723 struct frame *f = XFRAME (w->frame);
5724 int x, y, width, height, from_y, to_y, bottom_y;
5725
5726 /* Get frame-relative bounding box of the text display area of W,
5727 without mode lines. Include in this box the left and right
5728 fringes of W. */
5729 window_box (w, -1, &x, &y, &width, &height);
5730 width += FRAME_X_FRINGE_WIDTH (f);
5731 x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
5732
5733 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5734 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5735 bottom_y = y + height;
5736
5737 if (to_y < from_y)
5738 {
5739 /* Scrolling up. Make sure we don't copy part of the mode
5740 line at the bottom. */
5741 if (from_y + run->height > bottom_y)
5742 height = bottom_y - from_y;
5743 else
5744 height = run->height;
5745 }
5746 else
5747 {
5748 /* Scolling down. Make sure we don't copy over the mode line.
5749 at the bottom. */
5750 if (to_y + run->height > bottom_y)
5751 height = bottom_y - to_y;
5752 else
5753 height = run->height;
5754 }
5755
5756 BLOCK_INPUT;
5757
5758 /* Cursor off. Will be switched on again in x_update_window_end. */
5759 updated_window = w;
5760 x_clear_cursor (w);
5761
5762 mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
5763 f->output_data.mac->normal_gc,
5764 x, from_y,
5765 width, height,
5766 x, to_y);
5767
5768 UNBLOCK_INPUT;
5769}
5770
5771
5772
5773/***********************************************************************
5774 Exposure Events
5775 ***********************************************************************/
5776
5777/* Redisplay an exposed area of frame F. X and Y are the upper-left
5778 corner of the exposed rectangle. W and H are width and height of
5779 the exposed area. All are pixel values. W or H zero means redraw
5780 the entire frame. */
5781
5782static void
5783expose_frame (f, x, y, w, h)
5784 struct frame *f;
5785 int x, y, w, h;
5786{
5787 Rect r;
5788
5789 TRACE ((stderr, "expose_frame "));
5790
5791 /* No need to redraw if frame will be redrawn soon. */
5792 if (FRAME_GARBAGED_P (f))
5793 {
5794 TRACE ((stderr, " garbaged\n"));
5795 return;
5796 }
5797
5798 /* MAC_TODO: this is a kludge, but if scroll bars are not activated
5799 or deactivated here, for unknown reasons, activated scroll bars
5800 are shown in deactivated frames in some instances. */
5801 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
5802 activate_scroll_bars (f);
5803 else
5804 deactivate_scroll_bars (f);
5805
5806 /* If basic faces haven't been realized yet, there is no point in
5807 trying to redraw anything. This can happen when we get an expose
5808 event while Emacs is starting, e.g. by moving another window. */
5809 if (FRAME_FACE_CACHE (f) == NULL
5810 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5811 {
5812 TRACE ((stderr, " no faces\n"));
5813 return;
5814 }
5815
5816 if (w == 0 || h == 0)
5817 {
5818 r.left = r.top = 0;
5819 r.right = CANON_X_UNIT (f) * f->width;
5820 r.bottom = CANON_Y_UNIT (f) * f->height;
5821 }
5822 else
5823 {
5824 r.left = x;
5825 r.top = y;
5826 r.right = x + w;
5827 r.bottom = y + h;
5828 }
5829
5830 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom));
5831 expose_window_tree (XWINDOW (f->root_window), &r);
5832
5833 if (WINDOWP (f->tool_bar_window))
5834 {
5835 struct window *w = XWINDOW (f->tool_bar_window);
5836 Rect window_rect;
5837 Rect intersection_rect;
5838 int window_x, window_y, window_width, window_height;
5839
5840
5841 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5842 window_rect.left = window_x;
5843 window_rect.top = window_y;
5844 window_rect.right = window_x + window_width;
5845 window_rect.bottom = window_y + window_height;
5846
5847 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5848 expose_window (w, &intersection_rect);
5849 }
5850
5851#ifndef USE_X_TOOLKIT
5852 if (WINDOWP (f->menu_bar_window))
5853 {
5854 struct window *w = XWINDOW (f->menu_bar_window);
5855 Rect window_rect;
5856 Rect intersection_rect;
5857 int window_x, window_y, window_width, window_height;
5858
5859
5860 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5861 window_rect.left = window_x;
5862 window_rect.top = window_y;
5863 window_rect.right = window_x + window_width;
5864 window_rect.bottom = window_y + window_height;
5865
5866 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5867 expose_window (w, &intersection_rect);
5868 }
5869#endif /* not USE_X_TOOLKIT */
5870}
5871
5872
5873/* Redraw (parts) of all windows in the window tree rooted at W that
5874 intersect R. R contains frame pixel coordinates. */
5875
5876static void
5877expose_window_tree (w, r)
5878 struct window *w;
5879 Rect *r;
5880{
5881 while (w)
5882 {
5883 if (!NILP (w->hchild))
5884 expose_window_tree (XWINDOW (w->hchild), r);
5885 else if (!NILP (w->vchild))
5886 expose_window_tree (XWINDOW (w->vchild), r);
5887 else
5888 {
5889 Rect window_rect;
5890 Rect intersection_rect;
5891 struct frame *f = XFRAME (w->frame);
5892 int window_x, window_y, window_width, window_height;
5893
5894 /* Frame-relative pixel rectangle of W. */
5895 window_box (w, -1, &window_x, &window_y, &window_width,
5896 &window_height);
5897 window_rect.left
5898 = (window_x
5899 - FRAME_X_LEFT_FRINGE_WIDTH (f)
5900 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_Y_UNIT (f));
5901 window_rect.top = window_y;
5902 window_rect.right = window_rect.left
5903 + (window_width
5904 + FRAME_X_FRINGE_WIDTH (f)
5905 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5906 window_rect.bottom = window_rect.top
5907 + window_height + CURRENT_MODE_LINE_HEIGHT (w);
5908
5909 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5910 expose_window (w, &intersection_rect);
5911 }
5912
5913 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5914 }
5915}
5916
5917
5918/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5919 which intersects rectangle R. R is in window-relative coordinates. */
5920
5921static void
5922expose_area (w, row, r, area)
5923 struct window *w;
5924 struct glyph_row *row;
5925 Rect *r;
5926 enum glyph_row_area area;
5927{
5928 int x;
5929 struct glyph *first = row->glyphs[area];
5930 struct glyph *end = row->glyphs[area] + row->used[area];
5931 struct glyph *last;
5932 int first_x;
5933
5934 /* Set x to the window-relative start position for drawing glyphs of
5935 AREA. The first glyph of the text area can be partially visible.
5936 The first glyphs of other areas cannot. */
5937 if (area == LEFT_MARGIN_AREA)
5938 x = 0;
5939 else if (area == TEXT_AREA)
5940 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5941 else
5942 x = (window_box_width (w, LEFT_MARGIN_AREA)
5943 + window_box_width (w, TEXT_AREA));
5944
5945 if (area == TEXT_AREA && row->fill_line_p)
5946 /* If row extends face to end of line write the whole line. */
5947 x_draw_glyphs (w, x, row, area,
5948 0, row->used[area],
5949 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5950 NULL, NULL, 0);
5951 else
5952 {
5953 /* Find the first glyph that must be redrawn. */
5954 while (first < end
5955 && x + first->pixel_width < r->left)
5956 {
5957 x += first->pixel_width;
5958 ++first;
5959 }
5960
5961 /* Find the last one. */
5962 last = first;
5963 first_x = x;
5964 while (last < end
5965 && x < r->right)
5966 {
5967 x += last->pixel_width;
5968 ++last;
5969 }
5970
5971 /* Repaint. */
5972 if (last > first)
5973 x_draw_glyphs (w, first_x, row, area,
5974 first - row->glyphs[area],
5975 last - row->glyphs[area],
5976 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5977 NULL, NULL, 0);
5978 }
5979}
5980
5981
5982/* Redraw the parts of the glyph row ROW on window W intersecting
5983 rectangle R. R is in window-relative coordinates. */
5984
5985static void
5986expose_line (w, row, r)
5987 struct window *w;
5988 struct glyph_row *row;
5989 Rect *r;
5990{
5991 xassert (row->enabled_p);
5992
5993 if (row->mode_line_p || w->pseudo_window_p)
5994 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5995 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5996 NULL, NULL, 0);
5997 else
5998 {
5999 if (row->used[LEFT_MARGIN_AREA])
6000 expose_area (w, row, r, LEFT_MARGIN_AREA);
6001 if (row->used[TEXT_AREA])
6002 expose_area (w, row, r, TEXT_AREA);
6003 if (row->used[RIGHT_MARGIN_AREA])
6004 expose_area (w, row, r, RIGHT_MARGIN_AREA);
6005 x_draw_row_fringe_bitmaps (w, row);
6006 }
6007}
6008
6009
6010/* Return non-zero if W's cursor intersects rectangle R. */
6011
6012static int
6013x_phys_cursor_in_rect_p (w, r)
6014 struct window *w;
6015 Rect *r;
6016{
6017 Rect cr, result;
6018 struct glyph *cursor_glyph;
6019
6020 cursor_glyph = get_phys_cursor_glyph (w);
6021 if (cursor_glyph)
6022 {
6023 cr.left = w->phys_cursor.x;
6024 cr.top = w->phys_cursor.y;
6025 cr.right = cr.left + cursor_glyph->pixel_width;
6026 cr.bottom = cr.top + w->phys_cursor_height;
6027 return x_intersect_rectangles (&cr, r, &result);
6028 }
6029 else
6030 return 0;
6031}
6032
6033
6034/* Redraw a rectangle of window W. R is a rectangle in window
6035 relative coordinates. Call this function with input blocked. */
6036
6037static void
6038expose_window (w, r)
6039 struct window *w;
6040 Rect *r;
6041{
6042 struct glyph_row *row;
6043 int y;
6044 int yb = window_text_bottom_y (w);
6045 int cursor_cleared_p;
6046
6047 /* If window is not yet fully initialized, do nothing. This can
6048 happen when toolkit scroll bars are used and a window is split.
6049 Reconfiguring the scroll bar will generate an expose for a newly
6050 created window. */
6051 if (w->current_matrix == NULL)
6052 return;
6053
6054 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6055 r->left, r->top, r->right, r->bottom));
6056
6057 /* Convert to window coordinates. */
6058 r->left = FRAME_TO_WINDOW_PIXEL_X (w, r->left);
6059 r->top = FRAME_TO_WINDOW_PIXEL_Y (w, r->top);
6060 r->right = FRAME_TO_WINDOW_PIXEL_X (w, r->right);
6061 r->bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r->bottom);
6062
6063 /* Turn off the cursor. */
6064 if (!w->pseudo_window_p
6065 && x_phys_cursor_in_rect_p (w, r))
6066 {
6067 x_clear_cursor (w);
6068 cursor_cleared_p = 1;
6069 }
6070 else
6071 cursor_cleared_p = 0;
6072
6073 /* Find the first row intersecting the rectangle R. */
6074 row = w->current_matrix->rows;
6075 y = 0;
6076 while (row->enabled_p
6077 && y < yb
6078 && y + row->height < r->top)
6079 {
6080 y += row->height;
6081 ++row;
6082 }
6083
6084 /* Display the text in the rectangle, one text line at a time. */
6085 while (row->enabled_p
6086 && y < yb
6087 && y < r->bottom)
6088 {
6089 expose_line (w, row, r);
6090 y += row->height;
6091 ++row;
6092 }
6093
6094 /* Display the mode line if there is one. */
6095 if (WINDOW_WANTS_MODELINE_P (w)
6096 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6097 row->enabled_p)
6098 && row->y < r->bottom)
6099 expose_line (w, row, r);
6100
6101 if (!w->pseudo_window_p)
6102 {
6103 /* Draw border between windows. */
6104 x_draw_vertical_border (w);
6105
6106 /* Turn the cursor on again. */
6107 if (cursor_cleared_p)
6108 x_update_window_cursor (w, 1);
6109 }
6110
6111 /* Display scroll bar for this window. */
6112 if (!NILP (w->vertical_scroll_bar))
6113 {
6114 ControlHandle ch
6115 = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar));
6116
6117 Draw1Control (ch);
6118 }
6119}
6120
6121
6122/* Determine the intersection of two rectangles R1 and R2. Return
6123 the intersection in *RESULT. Value is non-zero if RESULT is not
6124 empty. */
6125
6126static int
6127x_intersect_rectangles (r1, r2, result)
6128 Rect *r1, *r2, *result;
6129{
6130 Rect *left, *right;
6131 Rect *upper, *lower;
6132 int intersection_p = 0;
6133
6134 /* Rerrange so that R1 is the left-most rectangle. */
6135 if (r1->left < r2->left)
6136 left = r1, right = r2;
6137 else
6138 left = r2, right = r1;
6139
6140 /* X0 of the intersection is right.x0, if this is inside R1,
6141 otherwise there is no intersection. */
6142 if (right->left <= left->right)
6143 {
6144 result->left = right->left;
6145
6146 /* The right end of the intersection is the minimum of the
6147 the right ends of left and right. */
6148 result->right = min (left->right, right->right);
6149
6150 /* Same game for Y. */
6151 if (r1->top < r2->top)
6152 upper = r1, lower = r2;
6153 else
6154 upper = r2, lower = r1;
6155
6156 /* The upper end of the intersection is lower.y0, if this is inside
6157 of upper. Otherwise, there is no intersection. */
6158 if (lower->top <= upper->bottom)
6159 {
6160 result->top = lower->top;
6161
6162 /* The lower end of the intersection is the minimum of the lower
6163 ends of upper and lower. */
6164 result->bottom = min (lower->bottom, upper->bottom);
6165 intersection_p = 1;
6166 }
6167 }
6168
6169 return intersection_p;
6170}
6171
6172
6173
6174
6175
6176static void
6177frame_highlight (f)
6178 struct frame *f;
6179{
6180 x_update_cursor (f, 1);
6181}
6182
6183static void
6184frame_unhighlight (f)
6185 struct frame *f;
6186{
6187 x_update_cursor (f, 1);
6188}
6189
6190/* The focus has changed. Update the frames as necessary to reflect
6191 the new situation. Note that we can't change the selected frame
6192 here, because the Lisp code we are interrupting might become confused.
6193 Each event gets marked with the frame in which it occurred, so the
6194 Lisp code can tell when the switch took place by examining the events. */
6195
6196static void
6197x_new_focus_frame (dpyinfo, frame)
6198 struct x_display_info *dpyinfo;
6199 struct frame *frame;
6200{
6201 struct frame *old_focus = dpyinfo->x_focus_frame;
6202
6203 if (frame != dpyinfo->x_focus_frame)
6204 {
6205 /* Set this before calling other routines, so that they see
6206 the correct value of x_focus_frame. */
6207 dpyinfo->x_focus_frame = frame;
6208
6209 if (old_focus && old_focus->auto_lower)
6210 x_lower_frame (old_focus);
6211
6212#if 0
6213 selected_frame = frame;
6214 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6215 selected_frame);
6216 Fselect_window (selected_frame->selected_window);
6217 choose_minibuf_frame ();
6218#endif /* ! 0 */
6219
6220 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6221 pending_autoraise_frame = dpyinfo->x_focus_frame;
6222 else
6223 pending_autoraise_frame = 0;
6224 }
6225
6226 x_frame_rehighlight (dpyinfo);
6227}
6228
6229/* Handle an event saying the mouse has moved out of an Emacs frame. */
6230
6231static void
6232x_mouse_leave (dpyinfo)
6233 struct x_display_info *dpyinfo;
6234{
6235 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
6236}
6237
6238/* The focus has changed, or we have redirected a frame's focus to
6239 another frame (this happens when a frame uses a surrogate
6240 mini-buffer frame). Shift the highlight as appropriate.
6241
6242 The FRAME argument doesn't necessarily have anything to do with which
6243 frame is being highlighted or un-highlighted; we only use it to find
6244 the appropriate X display info. */
6245
6246void
6247XTframe_rehighlight (frame)
6248 struct frame *frame;
6249{
6250 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6251}
6252
6253static void
6254x_frame_rehighlight (dpyinfo)
6255 struct x_display_info *dpyinfo;
6256{
6257 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6258
6259 if (dpyinfo->x_focus_frame)
6260 {
6261 dpyinfo->x_highlight_frame
6262 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6263 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6264 : dpyinfo->x_focus_frame);
6265 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
6266 {
6267 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6268 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
6269 }
6270 }
6271 else
6272 dpyinfo->x_highlight_frame = 0;
6273
6274 if (dpyinfo->x_highlight_frame != old_highlight)
6275 {
6276 if (old_highlight)
6277 frame_unhighlight (old_highlight);
6278 if (dpyinfo->x_highlight_frame)
6279 frame_highlight (dpyinfo->x_highlight_frame);
6280 }
6281}
6282
6283
6284
6285/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
6286
6287#if 0
6288/* Initialize mode_switch_bit and modifier_meaning. */
6289static void
6290x_find_modifier_meanings (dpyinfo)
6291 struct x_display_info *dpyinfo;
6292{
6293 int min_code, max_code;
6294 KeySym *syms;
6295 int syms_per_code;
6296 XModifierKeymap *mods;
6297
6298 dpyinfo->meta_mod_mask = 0;
6299 dpyinfo->shift_lock_mask = 0;
6300 dpyinfo->alt_mod_mask = 0;
6301 dpyinfo->super_mod_mask = 0;
6302 dpyinfo->hyper_mod_mask = 0;
6303
6304#ifdef HAVE_X11R4
6305 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
6306#else
6307 min_code = dpyinfo->display->min_keycode;
6308 max_code = dpyinfo->display->max_keycode;
6309#endif
6310
6311 syms = XGetKeyboardMapping (dpyinfo->display,
6312 min_code, max_code - min_code + 1,
6313 &syms_per_code);
6314 mods = XGetModifierMapping (dpyinfo->display);
6315
6316 /* Scan the modifier table to see which modifier bits the Meta and
6317 Alt keysyms are on. */
6318 {
6319 int row, col; /* The row and column in the modifier table. */
6320
6321 for (row = 3; row < 8; row++)
6322 for (col = 0; col < mods->max_keypermod; col++)
6323 {
6324 KeyCode code
6325 = mods->modifiermap[(row * mods->max_keypermod) + col];
6326
6327 /* Zeroes are used for filler. Skip them. */
6328 if (code == 0)
6329 continue;
6330
6331 /* Are any of this keycode's keysyms a meta key? */
6332 {
6333 int code_col;
6334
6335 for (code_col = 0; code_col < syms_per_code; code_col++)
6336 {
6337 int sym = syms[((code - min_code) * syms_per_code) + code_col];
6338
6339 switch (sym)
6340 {
6341 case XK_Meta_L:
6342 case XK_Meta_R:
6343 dpyinfo->meta_mod_mask |= (1 << row);
6344 break;
6345
6346 case XK_Alt_L:
6347 case XK_Alt_R:
6348 dpyinfo->alt_mod_mask |= (1 << row);
6349 break;
6350
6351 case XK_Hyper_L:
6352 case XK_Hyper_R:
6353 dpyinfo->hyper_mod_mask |= (1 << row);
6354 break;
6355
6356 case XK_Super_L:
6357 case XK_Super_R:
6358 dpyinfo->super_mod_mask |= (1 << row);
6359 break;
6360
6361 case XK_Shift_Lock:
6362 /* Ignore this if it's not on the lock modifier. */
6363 if ((1 << row) == LockMask)
6364 dpyinfo->shift_lock_mask = LockMask;
6365 break;
6366 }
6367 }
6368 }
6369 }
6370 }
6371
6372 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
6373 if (! dpyinfo->meta_mod_mask)
6374 {
6375 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6376 dpyinfo->alt_mod_mask = 0;
6377 }
6378
6379 /* If some keys are both alt and meta,
6380 make them just meta, not alt. */
6381 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
6382 {
6383 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
6384 }
6385
6386 XFree ((char *) syms);
6387 XFreeModifiermap (mods);
6388}
6389
6390#endif
6391
6392/* Convert between the modifier bits X uses and the modifier bits
6393 Emacs uses. */
6394
6395static unsigned int
6396x_mac_to_emacs_modifiers (dpyinfo, state)
6397 struct x_display_info *dpyinfo;
6398 unsigned short state;
6399{
6400 return (((state & shiftKey) ? shift_modifier : 0)
6401 | ((state & controlKey) ? ctrl_modifier : 0)
6402 | ((state & cmdKey) ? meta_modifier : 0)
6403 | ((state & optionKey) ? alt_modifier : 0));
6404}
6405
6406#if 0
6407static unsigned short
6408x_emacs_to_x_modifiers (dpyinfo, state)
6409 struct x_display_info *dpyinfo;
6410 unsigned int state;
6411{
6412 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6413 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6414 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6415 | ((state & shift_modifier) ? ShiftMask : 0)
6416 | ((state & ctrl_modifier) ? ControlMask : 0)
6417 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
6418}
6419#endif
6420
6421/* Convert a keysym to its name. */
6422
6423char *
6424x_get_keysym_name (keysym)
6425 int keysym;
6426{
6427 char *value;
6428
6429 BLOCK_INPUT;
6430#if 0
6431 value = XKeysymToString (keysym);
6432#else
6433 value = 0;
6434#endif
6435 UNBLOCK_INPUT;
6436
6437 return value;
6438}
6439
6440
6441
6442/* Mouse clicks and mouse movement. Rah. */
6443
6444/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6445 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6446 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6447 not force the value into range. */
6448
6449void
6450pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
6451 FRAME_PTR f;
6452 register int pix_x, pix_y;
6453 register int *x, *y;
6454 Rect *bounds;
6455 int noclip;
6456{
6457 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
6458 even for negative values. */
6459 if (pix_x < 0)
6460 pix_x -= FONT_WIDTH ((f)->output_data.mac->font) - 1;
6461 if (pix_y < 0)
6462 pix_y -= (f)->output_data.mac->line_height - 1;
6463
6464 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6465 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6466
6467 if (bounds)
6468 {
6469 bounds->left = CHAR_TO_PIXEL_COL (f, pix_x);
6470 bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y);
6471 bounds->right = bounds->left + FONT_WIDTH (f->output_data.mac->font);
6472 bounds->bottom = bounds->top + f->output_data.mac->line_height;
6473 }
6474
6475 if (!noclip)
6476 {
6477 if (pix_x < 0)
6478 pix_x = 0;
6479 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6480 pix_x = FRAME_WINDOW_WIDTH (f);
6481
6482 if (pix_y < 0)
6483 pix_y = 0;
6484 else if (pix_y > f->height)
6485 pix_y = f->height;
6486 }
6487
6488 *x = pix_x;
6489 *y = pix_y;
6490}
6491
6492
6493/* Given HPOS/VPOS in the current matrix of W, return corresponding
6494 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6495 can't tell the positions because W's display is not up to date,
6496 return 0. */
6497
6498static int
6499glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6500 struct window *w;
6501 int hpos, vpos;
6502 int *frame_x, *frame_y;
6503{
6504 int success_p;
6505
6506 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6507 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6508
6509 if (display_completed)
6510 {
6511 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6512 struct glyph *glyph = row->glyphs[TEXT_AREA];
6513 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6514
6515 *frame_y = row->y;
6516 *frame_x = row->x;
6517 while (glyph < end)
6518 {
6519 *frame_x += glyph->pixel_width;
6520 ++glyph;
6521 }
6522
6523 success_p = 1;
6524 }
6525 else
6526 {
6527 *frame_y = *frame_x = 0;
6528 success_p = 0;
6529 }
6530
6531 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6532 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6533 return success_p;
6534}
6535
6536
6537/* Prepare a mouse-event in *RESULT for placement in the input queue.
6538
6539 If the event is a button press, then note that we have grabbed
6540 the mouse. */
6541
6542static Lisp_Object
6543construct_mouse_click (result, event, f)
6544 struct input_event *result;
6545 EventRecord *event;
6546 struct frame *f;
6547{
6548 Point mouseLoc;
6549
6550 result->kind = mouse_click;
6551 result->code = 0; /* only one mouse button */
6552 result->timestamp = event->when;
6553 result->modifiers = event->what == mouseDown ? down_modifier : up_modifier;
6554
6555 mouseLoc = event->where;
6556 SetPort (FRAME_MAC_WINDOW (f));
6557 GlobalToLocal (&mouseLoc);
6558 XSETINT (result->x, mouseLoc.h);
6559 XSETINT (result->y, mouseLoc.v);
6560
6561 XSETFRAME (result->frame_or_window, f);
6562
6563 result->arg = Qnil;
6564 return Qnil;
6565}
6566
6567
6568/* Function to report a mouse movement to the mainstream Emacs code.
6569 The input handler calls this.
6570
6571 We have received a mouse movement event, which is given in *event.
6572 If the mouse is over a different glyph than it was last time, tell
6573 the mainstream emacs code by setting mouse_moved. If not, ask for
6574 another motion event, so we can check again the next time it moves. */
6575
6576static Point last_mouse_motion_position;
6577static Lisp_Object last_mouse_motion_frame;
6578
6579static void
6580note_mouse_movement (frame, pos)
6581 FRAME_PTR frame;
6582 Point *pos;
6583{
6584 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
6585 last_mouse_motion_position = *pos;
6586 XSETFRAME (last_mouse_motion_frame, frame);
6587
6588 if (!PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect))
6589 {
6590 frame->mouse_moved = 1;
6591 last_mouse_scroll_bar = Qnil;
6592 note_mouse_highlight (frame, -1, -1);
6593 }
6594 /* Has the mouse moved off the glyph it was on at the last sighting? */
6595 else if (pos->h < last_mouse_glyph.left
6596 || pos->h >= last_mouse_glyph.right
6597 || pos->v < last_mouse_glyph.top
6598 || pos->v >= last_mouse_glyph.bottom)
6599 {
6600 frame->mouse_moved = 1;
6601 last_mouse_scroll_bar = Qnil;
6602 note_mouse_highlight (frame, pos->h, pos->v);
6603 }
6604}
6605
6606/* This is used for debugging, to turn off note_mouse_highlight. */
6607
6608int disable_mouse_highlight;
6609
6610
6611
6612/************************************************************************
6613 Mouse Face
6614 ************************************************************************/
6615
6616/* Find the glyph under window-relative coordinates X/Y in window W.
6617 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6618 strings. Return in *HPOS and *VPOS the row and column number of
6619 the glyph found. Return in *AREA the glyph area containing X.
6620 Value is a pointer to the glyph found or null if X/Y is not on
6621 text, or we can't tell because W's current matrix is not up to
6622 date. */
6623
6624static struct glyph *
6625x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6626 struct window *w;
6627 int x, y;
6628 int *hpos, *vpos, *area;
6629{
6630 struct glyph *glyph, *end;
6631 struct glyph_row *row = NULL;
6632 int x0, i, left_area_width;
6633
6634 /* Find row containing Y. Give up if some row is not enabled. */
6635 for (i = 0; i < w->current_matrix->nrows; ++i)
6636 {
6637 row = MATRIX_ROW (w->current_matrix, i);
6638 if (!row->enabled_p)
6639 return NULL;
6640 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6641 break;
6642 }
6643
6644 *vpos = i;
6645 *hpos = 0;
6646
6647 /* Give up if Y is not in the window. */
6648 if (i == w->current_matrix->nrows)
6649 return NULL;
6650
6651 /* Get the glyph area containing X. */
6652 if (w->pseudo_window_p)
6653 {
6654 *area = TEXT_AREA;
6655 x0 = 0;
6656 }
6657 else
6658 {
6659 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6660 if (x < left_area_width)
6661 {
6662 *area = LEFT_MARGIN_AREA;
6663 x0 = 0;
6664 }
6665 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6666 {
6667 *area = TEXT_AREA;
6668 x0 = row->x + left_area_width;
6669 }
6670 else
6671 {
6672 *area = RIGHT_MARGIN_AREA;
6673 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6674 }
6675 }
6676
6677 /* Find glyph containing X. */
6678 glyph = row->glyphs[*area];
6679 end = glyph + row->used[*area];
6680 while (glyph < end)
6681 {
6682 if (x < x0 + glyph->pixel_width)
6683 {
6684 if (w->pseudo_window_p)
6685 break;
6686 else if (BUFFERP (glyph->object))
6687 break;
6688 }
6689
6690 x0 += glyph->pixel_width;
6691 ++glyph;
6692 }
6693
6694 if (glyph == end)
6695 return NULL;
6696
6697 *hpos = glyph - row->glyphs[*area];
6698 return glyph;
6699}
6700
6701
6702/* Convert frame-relative x/y to coordinates relative to window W.
6703 Takes pseudo-windows into account. */
6704
6705static void
6706frame_to_window_pixel_xy (w, x, y)
6707 struct window *w;
6708 int *x, *y;
6709{
6710 if (w->pseudo_window_p)
6711 {
6712 /* A pseudo-window is always full-width, and starts at the
6713 left edge of the frame, plus a frame border. */
6714 struct frame *f = XFRAME (w->frame);
6715 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6716 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6717 }
6718 else
6719 {
6720 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6721 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6722 }
6723}
6724
6725
6726/* Take proper action when mouse has moved to the mode or top line of
6727 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6728 mode line. X is relative to the start of the text display area of
6729 W, so the width of fringes and scroll bars must be subtracted
6730 to get a position relative to the start of the mode line. */
6731
6732static void
6733note_mode_line_highlight (w, x, mode_line_p)
6734 struct window *w;
6735 int x, mode_line_p;
6736{
6737 struct frame *f = XFRAME (w->frame);
6738 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6739 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6740 struct glyph_row *row;
6741
6742 if (mode_line_p)
6743 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6744 else
6745 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
6746
6747 if (row->enabled_p)
6748 {
6749 struct glyph *glyph, *end;
6750 Lisp_Object help, map;
6751 int x0;
6752
6753 /* Find the glyph under X. */
6754 glyph = row->glyphs[TEXT_AREA];
6755 end = glyph + row->used[TEXT_AREA];
6756 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
6757 + FRAME_X_LEFT_FRINGE_WIDTH (f));
6758 while (glyph < end
6759 && x >= x0 + glyph->pixel_width)
6760 {
6761 x0 += glyph->pixel_width;
6762 ++glyph;
6763 }
6764
6765 if (glyph < end
6766 && STRINGP (glyph->object)
6767 && XSTRING (glyph->object)->intervals
6768 && glyph->charpos >= 0
6769 && glyph->charpos < XSTRING (glyph->object)->size)
6770 {
6771 /* If we're on a string with `help-echo' text property,
6772 arrange for the help to be displayed. This is done by
6773 setting the global variable help_echo to the help string. */
6774 help = Fget_text_property (make_number (glyph->charpos),
6775 Qhelp_echo, glyph->object);
6776 if (!NILP (help))
6777 {
6778 help_echo = help;
6779 XSETWINDOW (help_echo_window, w);
6780 help_echo_object = glyph->object;
6781 help_echo_pos = glyph->charpos;
6782 }
6783
6784 /* Change the mouse pointer according to what is under X/Y. */
6785 map = Fget_text_property (make_number (glyph->charpos),
6786 Qlocal_map, glyph->object);
6787 if (KEYMAPP (map))
6788 cursor = f->output_data.mac->nontext_cursor;
6789 else
6790 {
6791 map = Fget_text_property (make_number (glyph->charpos),
6792 Qkeymap, glyph->object);
6793 if (KEYMAPP (map))
6794 cursor = f->output_data.mac->nontext_cursor;
6795 }
6796 }
6797 }
6798
6799#if 0 /* MAC_TODO: mouse cursor */
6800 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6801#endif
6802}
6803
6804
6805/* Take proper action when the mouse has moved to position X, Y on
6806 frame F as regards highlighting characters that have mouse-face
6807 properties. Also de-highlighting chars where the mouse was before.
6808 X and Y can be negative or out of range. */
6809
6810static void
6811note_mouse_highlight (f, x, y)
6812 struct frame *f;
6813 int x, y;
6814{
6815 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6816 int portion;
6817 Lisp_Object window;
6818 struct window *w;
6819
6820 /* When a menu is active, don't highlight because this looks odd. */
6821#ifdef USE_X_TOOLKIT
6822 if (popup_activated ())
6823 return;
6824#endif
6825
6826 if (disable_mouse_highlight
6827 || !f->glyphs_initialized_p)
6828 return;
6829
6830 dpyinfo->mouse_face_mouse_x = x;
6831 dpyinfo->mouse_face_mouse_y = y;
6832 dpyinfo->mouse_face_mouse_frame = f;
6833
6834 if (dpyinfo->mouse_face_defer)
6835 return;
6836
6837 if (gc_in_progress)
6838 {
6839 dpyinfo->mouse_face_deferred_gc = 1;
6840 return;
6841 }
6842
6843 /* Which window is that in? */
6844 window = window_from_coordinates (f, x, y, &portion, 1);
6845
6846 /* If we were displaying active text in another window, clear that. */
6847 if (! EQ (window, dpyinfo->mouse_face_window))
6848 clear_mouse_face (dpyinfo);
6849
6850 /* Not on a window -> return. */
6851 if (!WINDOWP (window))
6852 return;
6853
6854 /* Convert to window-relative pixel coordinates. */
6855 w = XWINDOW (window);
6856 frame_to_window_pixel_xy (w, &x, &y);
6857
6858 /* Handle tool-bar window differently since it doesn't display a
6859 buffer. */
6860 if (EQ (window, f->tool_bar_window))
6861 {
6862 note_tool_bar_highlight (f, x, y);
6863 return;
6864 }
6865
6866 if (portion == 1 || portion == 3)
6867 {
6868 /* Mouse is on the mode or top line. */
6869 note_mode_line_highlight (w, x, portion == 1);
6870 return;
6871 }
6872#if 0 /* MAC_TODO: mouse cursor */
6873 else
6874 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6875 f->output_data.x->text_cursor);
6876#endif
6877
6878 /* Are we in a window whose display is up to date?
6879 And verify the buffer's text has not changed. */
6880 if (/* Within text portion of the window. */
6881 portion == 0
6882 && EQ (w->window_end_valid, w->buffer)
6883 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6884 && (XFASTINT (w->last_overlay_modified)
6885 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
6886 {
6887 int hpos, vpos, pos, i, area;
6888 struct glyph *glyph;
6889
6890 /* Find the glyph under X/Y. */
6891 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6892
6893 /* Clear mouse face if X/Y not over text. */
6894 if (glyph == NULL
6895 || area != TEXT_AREA
6896 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
6897 {
6898 clear_mouse_face (dpyinfo);
6899 return;
6900 }
6901
6902 pos = glyph->charpos;
6903 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6904
6905 /* Check for mouse-face and help-echo. */
6906 {
6907 Lisp_Object mouse_face, overlay, position;
6908 Lisp_Object *overlay_vec;
6909 int len, noverlays;
6910 struct buffer *obuf;
6911 int obegv, ozv;
6912
6913 /* If we get an out-of-range value, return now; avoid an error. */
6914 if (pos > BUF_Z (XBUFFER (w->buffer)))
6915 return;
6916
6917 /* Make the window's buffer temporarily current for
6918 overlays_at and compute_char_face. */
6919 obuf = current_buffer;
6920 current_buffer = XBUFFER (w->buffer);
6921 obegv = BEGV;
6922 ozv = ZV;
6923 BEGV = BEG;
6924 ZV = Z;
6925
6926 /* Is this char mouse-active or does it have help-echo? */
6927 XSETINT (position, pos);
6928
6929 /* Put all the overlays we want in a vector in overlay_vec.
6930 Store the length in len. If there are more than 10, make
6931 enough space for all, and try again. */
6932 len = 10;
6933 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6934 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6935 if (noverlays > len)
6936 {
6937 len = noverlays;
6938 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6939 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6940 }
6941
6942 /* Sort overlays into increasing priority order. */
6943 noverlays = sort_overlays (overlay_vec, noverlays, w);
6944
6945 /* Check mouse-face highlighting. */
6946 if (! (EQ (window, dpyinfo->mouse_face_window)
6947 && vpos >= dpyinfo->mouse_face_beg_row
6948 && vpos <= dpyinfo->mouse_face_end_row
6949 && (vpos > dpyinfo->mouse_face_beg_row
6950 || hpos >= dpyinfo->mouse_face_beg_col)
6951 && (vpos < dpyinfo->mouse_face_end_row
6952 || hpos < dpyinfo->mouse_face_end_col
6953 || dpyinfo->mouse_face_past_end)))
6954 {
6955 /* Clear the display of the old active region, if any. */
6956 clear_mouse_face (dpyinfo);
6957
6958 /* Find the highest priority overlay that has a mouse-face prop. */
6959 overlay = Qnil;
6960 for (i = noverlays - 1; i >= 0; --i)
6961 {
6962 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6963 if (!NILP (mouse_face))
6964 {
6965 overlay = overlay_vec[i];
6966 break;
6967 }
6968 }
6969
6970 /* If no overlay applies, get a text property. */
6971 if (NILP (overlay))
6972 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6973
6974 /* Handle the overlay case. */
6975 if (! NILP (overlay))
6976 {
6977 /* Find the range of text around this char that
6978 should be active. */
6979 Lisp_Object before, after;
6980 int ignore;
6981
6982 before = Foverlay_start (overlay);
6983 after = Foverlay_end (overlay);
6984 /* Record this as the current active region. */
6985 fast_find_position (w, XFASTINT (before),
6986 &dpyinfo->mouse_face_beg_col,
6987 &dpyinfo->mouse_face_beg_row,
6988 &dpyinfo->mouse_face_beg_x,
6989 &dpyinfo->mouse_face_beg_y);
6990 dpyinfo->mouse_face_past_end
6991 = !fast_find_position (w, XFASTINT (after),
6992 &dpyinfo->mouse_face_end_col,
6993 &dpyinfo->mouse_face_end_row,
6994 &dpyinfo->mouse_face_end_x,
6995 &dpyinfo->mouse_face_end_y);
6996 dpyinfo->mouse_face_window = window;
6997 dpyinfo->mouse_face_face_id
6998 = face_at_buffer_position (w, pos, 0, 0,
6999 &ignore, pos + 1, 1);
7000
7001 /* Display it as active. */
7002 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7003 }
7004 /* Handle the text property case. */
7005 else if (! NILP (mouse_face))
7006 {
7007 /* Find the range of text around this char that
7008 should be active. */
7009 Lisp_Object before, after, beginning, end;
7010 int ignore;
7011
7012 beginning = Fmarker_position (w->start);
7013 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
7014 - XFASTINT (w->window_end_pos)));
7015 before
7016 = Fprevious_single_property_change (make_number (pos + 1),
7017 Qmouse_face,
7018 w->buffer, beginning);
7019 after
7020 = Fnext_single_property_change (position, Qmouse_face,
7021 w->buffer, end);
7022 /* Record this as the current active region. */
7023 fast_find_position (w, XFASTINT (before),
7024 &dpyinfo->mouse_face_beg_col,
7025 &dpyinfo->mouse_face_beg_row,
7026 &dpyinfo->mouse_face_beg_x,
7027 &dpyinfo->mouse_face_beg_y);
7028 dpyinfo->mouse_face_past_end
7029 = !fast_find_position (w, XFASTINT (after),
7030 &dpyinfo->mouse_face_end_col,
7031 &dpyinfo->mouse_face_end_row,
7032 &dpyinfo->mouse_face_end_x,
7033 &dpyinfo->mouse_face_end_y);
7034 dpyinfo->mouse_face_window = window;
7035 dpyinfo->mouse_face_face_id
7036 = face_at_buffer_position (w, pos, 0, 0,
7037 &ignore, pos + 1, 1);
7038
7039 /* Display it as active. */
7040 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7041 }
7042 }
7043
7044 /* Look for a `help-echo' property. */
7045 {
7046 Lisp_Object help, overlay;
7047
7048 /* Check overlays first. */
7049 help = Qnil;
7050 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7051 {
7052 overlay = overlay_vec[i];
7053 help = Foverlay_get (overlay, Qhelp_echo);
7054 }
7055
7056 if (!NILP (help))
7057 {
7058 help_echo = help;
7059 help_echo_window = window;
7060 help_echo_object = overlay;
7061 help_echo_pos = pos;
7062 }
7063 else
7064 {
7065 /* Try text properties. */
7066 if ((STRINGP (glyph->object)
7067 && glyph->charpos >= 0
7068 && glyph->charpos < XSTRING (glyph->object)->size)
7069 || (BUFFERP (glyph->object)
7070 && glyph->charpos >= BEGV
7071 && glyph->charpos < ZV))
7072 help = Fget_text_property (make_number (glyph->charpos),
7073 Qhelp_echo, glyph->object);
7074
7075 if (!NILP (help))
7076 {
7077 help_echo = help;
7078 help_echo_window = window;
7079 help_echo_object = glyph->object;
7080 help_echo_pos = glyph->charpos;
7081 }
7082 }
7083 }
7084
7085 BEGV = obegv;
7086 ZV = ozv;
7087 current_buffer = obuf;
7088 }
7089 }
7090}
7091
7092static void
7093redo_mouse_highlight ()
7094{
7095 if (!NILP (last_mouse_motion_frame)
7096 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7097 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7098 last_mouse_motion_position.h,
7099 last_mouse_motion_position.v);
7100}
7101
7102
7103
7104/***********************************************************************
7105 Tool-bars
7106 ***********************************************************************/
7107
7108static int x_tool_bar_item P_ ((struct frame *, int, int,
7109 struct glyph **, int *, int *, int *));
7110
7111/* Tool-bar item index of the item on which a mouse button was pressed
7112 or -1. */
7113
7114static int last_tool_bar_item;
7115
7116
7117/* Get information about the tool-bar item at position X/Y on frame F.
7118 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7119 the current matrix of the tool-bar window of F, or NULL if not
7120 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
7121 item in F->current_tool_bar_items. Value is
7122
7123 -1 if X/Y is not on a tool-bar item
7124 0 if X/Y is on the same item that was highlighted before.
7125 1 otherwise. */
7126
7127static int
7128x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
7129 struct frame *f;
7130 int x, y;
7131 struct glyph **glyph;
7132 int *hpos, *vpos, *prop_idx;
7133{
7134 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7135 struct window *w = XWINDOW (f->tool_bar_window);
7136 int area;
7137
7138 /* Find the glyph under X/Y. */
7139 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
7140 if (*glyph == NULL)
7141 return -1;
7142
7143 /* Get the start of this tool-bar item's properties in
7144 f->current_tool_bar_items. */
7145 if (!tool_bar_item_info (f, *glyph, prop_idx))
7146 return -1;
7147
7148 /* Is mouse on the highlighted item? */
7149 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
7150 && *vpos >= dpyinfo->mouse_face_beg_row
7151 && *vpos <= dpyinfo->mouse_face_end_row
7152 && (*vpos > dpyinfo->mouse_face_beg_row
7153 || *hpos >= dpyinfo->mouse_face_beg_col)
7154 && (*vpos < dpyinfo->mouse_face_end_row
7155 || *hpos < dpyinfo->mouse_face_end_col
7156 || dpyinfo->mouse_face_past_end))
7157 return 0;
7158
7159 return 1;
7160}
7161
7162
7163/* Handle mouse button event on the tool-bar of frame F, at
7164 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7165 or ButtonRelase. */
7166
7167static void
7168x_handle_tool_bar_click (f, button_event)
7169 struct frame *f;
7170 EventRecord *button_event;
7171{
7172 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7173 struct window *w = XWINDOW (f->tool_bar_window);
7174 int hpos, vpos, prop_idx;
7175 struct glyph *glyph;
7176 Lisp_Object enabled_p;
7177 int x = button_event->where.h;
7178 int y = button_event->where.v;
7179
7180 /* If not on the highlighted tool-bar item, return. */
7181 frame_to_window_pixel_xy (w, &x, &y);
7182 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
7183 return;
7184
7185 /* If item is disabled, do nothing. */
7186 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
7187 if (NILP (enabled_p))
7188 return;
7189
7190 if (button_event->what == mouseDown)
7191 {
7192 /* Show item in pressed state. */
7193 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7194 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
7195 last_tool_bar_item = prop_idx;
7196 }
7197 else
7198 {
7199 Lisp_Object key, frame;
7200 struct input_event event;
7201
7202 /* Show item in released state. */
7203 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7204 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7205
7206 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
7207
7208 XSETFRAME (frame, f);
7209 event.kind = TOOL_BAR_EVENT;
7210 event.frame_or_window = frame;
7211 event.arg = frame;
7212 kbd_buffer_store_event (&event);
7213
7214 event.kind = TOOL_BAR_EVENT;
7215 event.frame_or_window = frame;
7216 event.arg = key;
7217 event.modifiers = x_mac_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7218 button_event->modifiers);
7219 kbd_buffer_store_event (&event);
7220 last_tool_bar_item = -1;
7221 }
7222}
7223
7224
7225/* Possibly highlight a tool-bar item on frame F when mouse moves to
7226 tool-bar window-relative coordinates X/Y. Called from
7227 note_mouse_highlight. */
7228
7229static void
7230note_tool_bar_highlight (f, x, y)
7231 struct frame *f;
7232 int x, y;
7233{
7234 Lisp_Object window = f->tool_bar_window;
7235 struct window *w = XWINDOW (window);
7236 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7237 int hpos, vpos;
7238 struct glyph *glyph;
7239 struct glyph_row *row;
7240 int i;
7241 Lisp_Object enabled_p;
7242 int prop_idx;
7243 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
7244 int mouse_down_p, rc;
7245
7246 /* Function note_mouse_highlight is called with negative x(y
7247 values when mouse moves outside of the frame. */
7248 if (x <= 0 || y <= 0)
7249 {
7250 clear_mouse_face (dpyinfo);
7251 return;
7252 }
7253
7254 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
7255 if (rc < 0)
7256 {
7257 /* Not on tool-bar item. */
7258 clear_mouse_face (dpyinfo);
7259 return;
7260 }
7261 else if (rc == 0)
7262 /* On same tool-bar item as before. */
7263 goto set_help_echo;
7264
7265 clear_mouse_face (dpyinfo);
7266
7267 /* Mouse is down, but on different tool-bar item? */
7268 mouse_down_p = (dpyinfo->grabbed
7269 && f == last_mouse_frame
7270 && FRAME_LIVE_P (f));
7271 if (mouse_down_p
7272 && last_tool_bar_item != prop_idx)
7273 return;
7274
7275 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7276 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7277
7278 /* If tool-bar item is not enabled, don't highlight it. */
7279 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
7280 if (!NILP (enabled_p))
7281 {
7282 /* Compute the x-position of the glyph. In front and past the
7283 image is a space. We include this is the highlighted area. */
7284 row = MATRIX_ROW (w->current_matrix, vpos);
7285 for (i = x = 0; i < hpos; ++i)
7286 x += row->glyphs[TEXT_AREA][i].pixel_width;
7287
7288 /* Record this as the current active region. */
7289 dpyinfo->mouse_face_beg_col = hpos;
7290 dpyinfo->mouse_face_beg_row = vpos;
7291 dpyinfo->mouse_face_beg_x = x;
7292 dpyinfo->mouse_face_beg_y = row->y;
7293 dpyinfo->mouse_face_past_end = 0;
7294
7295 dpyinfo->mouse_face_end_col = hpos + 1;
7296 dpyinfo->mouse_face_end_row = vpos;
7297 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7298 dpyinfo->mouse_face_end_y = row->y;
7299 dpyinfo->mouse_face_window = window;
7300 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
7301
7302 /* Display it as active. */
7303 show_mouse_face (dpyinfo, draw);
7304 dpyinfo->mouse_face_image_state = draw;
7305 }
7306
7307 set_help_echo:
7308
7309 /* Set help_echo to a help string.to display for this tool-bar item.
7310 XTread_socket does the rest. */
7311 help_echo_object = help_echo_window = Qnil;
7312 help_echo_pos = -1;
7313 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
7314 if (NILP (help_echo))
7315 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
7316}
7317
7318
7319
7320/* Find the glyph matrix position of buffer position POS in window W.
7321 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7322 current glyphs must be up to date. If POS is above window start
7323 return (0, 0, 0, 0). If POS is after end of W, return end of
7324 last line in W. */
7325
7326static int
7327fast_find_position (w, pos, hpos, vpos, x, y)
7328 struct window *w;
7329 int pos;
7330 int *hpos, *vpos, *x, *y;
7331{
7332 int i;
7333 int lastcol;
7334 int maybe_next_line_p = 0;
7335 int line_start_position;
7336 int yb = window_text_bottom_y (w);
7337 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
7338 struct glyph_row *best_row = row;
7339 int row_vpos = 0, best_row_vpos = 0;
7340 int current_x;
7341
7342 while (row->y < yb)
7343 {
7344 if (row->used[TEXT_AREA])
7345 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7346 else
7347 line_start_position = 0;
7348
7349 if (line_start_position > pos)
7350 break;
7351 /* If the position sought is the end of the buffer,
7352 don't include the blank lines at the bottom of the window. */
7353 else if (line_start_position == pos
7354 && pos == BUF_ZV (XBUFFER (w->buffer)))
7355 {
7356 maybe_next_line_p = 1;
7357 break;
7358 }
7359 else if (line_start_position > 0)
7360 {
7361 best_row = row;
7362 best_row_vpos = row_vpos;
7363 }
7364
7365 if (row->y + row->height >= yb)
7366 break;
7367
7368 ++row;
7369 ++row_vpos;
7370 }
7371
7372 /* Find the right column within BEST_ROW. */
7373 lastcol = 0;
7374 current_x = best_row->x;
7375 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
7376 {
7377 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7378 int charpos;
7379
7380 charpos = glyph->charpos;
7381 if (charpos == pos)
7382 {
7383 *hpos = i;
7384 *vpos = best_row_vpos;
7385 *x = current_x;
7386 *y = best_row->y;
7387 return 1;
7388 }
7389 else if (charpos > pos)
7390 break;
7391 else if (charpos > 0)
7392 lastcol = i;
7393
7394 current_x += glyph->pixel_width;
7395 }
7396
7397 /* If we're looking for the end of the buffer,
7398 and we didn't find it in the line we scanned,
7399 use the start of the following line. */
7400 if (maybe_next_line_p)
7401 {
7402 ++best_row;
7403 ++best_row_vpos;
7404 lastcol = 0;
7405 current_x = best_row->x;
7406 }
7407
7408 *vpos = best_row_vpos;
7409 *hpos = lastcol + 1;
7410 *x = current_x;
7411 *y = best_row->y;
7412 return 0;
7413}
7414
7415
7416/* Display the active region described by mouse_face_*
7417 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7418
7419static void
7420show_mouse_face (dpyinfo, draw)
7421 struct mac_display_info *dpyinfo;
7422 enum draw_glyphs_face draw;
7423{
7424 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
7425 struct frame *f = XFRAME (WINDOW_FRAME (w));
7426 int i;
7427 int cursor_off_p = 0;
7428 struct cursor_pos saved_cursor;
7429
7430 saved_cursor = output_cursor;
7431
7432 /* If window is in the process of being destroyed, don't bother
7433 to do anything. */
7434 if (w->current_matrix == NULL)
7435 goto set_x_cursor;
7436
7437 /* Recognize when we are called to operate on rows that don't exist
7438 anymore. This can happen when a window is split. */
7439 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7440 goto set_x_cursor;
7441
7442 set_output_cursor (&w->phys_cursor);
7443
7444 /* Note that mouse_face_beg_row etc. are window relative. */
7445 for (i = dpyinfo->mouse_face_beg_row;
7446 i <= dpyinfo->mouse_face_end_row;
7447 i++)
7448 {
7449 int start_hpos, end_hpos, start_x;
7450 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7451
7452 /* Don't do anything if row doesn't have valid contents. */
7453 if (!row->enabled_p)
7454 continue;
7455
7456 /* For all but the first row, the highlight starts at column 0. */
7457 if (i == dpyinfo->mouse_face_beg_row)
7458 {
7459 start_hpos = dpyinfo->mouse_face_beg_col;
7460 start_x = dpyinfo->mouse_face_beg_x;
7461 }
7462 else
7463 {
7464 start_hpos = 0;
7465 start_x = 0;
7466 }
7467
7468 if (i == dpyinfo->mouse_face_end_row)
7469 end_hpos = dpyinfo->mouse_face_end_col;
7470 else
7471 end_hpos = row->used[TEXT_AREA];
7472
7473 /* If the cursor's in the text we are about to rewrite, turn the
7474 cursor off. */
7475 if (!w->pseudo_window_p
7476 && i == output_cursor.vpos
7477 && output_cursor.hpos >= start_hpos - 1
7478 && output_cursor.hpos <= end_hpos)
7479 {
7480 x_update_window_cursor (w, 0);
7481 cursor_off_p = 1;
7482 }
7483
7484 if (end_hpos > start_hpos)
7485 {
7486 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7487 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7488 start_hpos, end_hpos, draw, NULL, NULL, 0);
7489 }
7490 }
7491
7492 /* If we turned the cursor off, turn it back on. */
7493 if (cursor_off_p)
7494 x_display_cursor (w, 1,
7495 output_cursor.hpos, output_cursor.vpos,
7496 output_cursor.x, output_cursor.y);
7497
7498 output_cursor = saved_cursor;
7499
7500 set_x_cursor:
7501#if 0 /* MAC_TODO: mouse cursor */
7502 /* Change the mouse cursor. */
7503 if (draw == DRAW_NORMAL_TEXT)
7504 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7505 f->output_data.x->text_cursor);
7506 else if (draw == DRAW_MOUSE_FACE)
7507 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7508 f->output_data.x->cross_cursor);
7509 else
7510 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7511 f->output_data.x->nontext_cursor);
7512#endif
7513 ;
7514}
7515
7516/* Clear out the mouse-highlighted active region.
7517 Redraw it un-highlighted first. */
7518
7519void
7520clear_mouse_face (dpyinfo)
7521 struct mac_display_info *dpyinfo;
7522{
7523 if (!NILP (tip_frame))
7524 return;
7525
7526 if (! NILP (dpyinfo->mouse_face_window))
7527 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7528
7529 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7530 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7531 dpyinfo->mouse_face_window = Qnil;
7532}
7533
7534
7535/* Clear any mouse-face on window W. This function is part of the
7536 redisplay interface, and is called from try_window_id and similar
7537 functions to ensure the mouse-highlight is off. */
7538
7539void
7540x_clear_mouse_face (w)
7541 struct window *w;
7542{
7543 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
7544 Lisp_Object window;
7545
7546 XSETWINDOW (window, w);
7547 if (EQ (window, dpyinfo->mouse_face_window))
7548 clear_mouse_face (dpyinfo);
7549}
7550
7551
7552/* Just discard the mouse face information for frame F, if any.
7553 This is used when the size of F is changed. */
7554
7555static void
7556cancel_mouse_face (f)
7557 FRAME_PTR f;
7558{
7559 Lisp_Object window;
7560 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7561
7562 window = dpyinfo->mouse_face_window;
7563 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7564 {
7565 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7566 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7567 dpyinfo->mouse_face_window = Qnil;
7568 }
7569}
7570
7571static struct scroll_bar *x_window_to_scroll_bar ();
7572static void x_scroll_bar_report_motion ();
7573
7574/* Return the current position of the mouse.
7575 *fp should be a frame which indicates which display to ask about.
7576
7577 If the mouse movement started in a scroll bar, set *fp, *bar_window,
7578 and *part to the frame, window, and scroll bar part that the mouse
7579 is over. Set *x and *y to the portion and whole of the mouse's
7580 position on the scroll bar.
7581
7582 If the mouse movement started elsewhere, set *fp to the frame the
7583 mouse is on, *bar_window to nil, and *x and *y to the character cell
7584 the mouse is over.
7585
7586 Set *time to the server time-stamp for the time at which the mouse
7587 was at this position.
7588
7589 Don't store anything if we don't have a valid set of values to report.
7590
7591 This clears the mouse_moved flag, so we can wait for the next mouse
7592 movement. */
7593
7594void
7595XTmouse_position (fp, insist, bar_window, part, x, y, time)
7596 FRAME_PTR *fp;
7597 int insist;
7598 Lisp_Object *bar_window;
7599 enum scroll_bar_part *part;
7600 Lisp_Object *x, *y;
7601 unsigned long *time;
7602{
7603 Point mouse_pos;
7604 int ignore1, ignore2;
7605 WindowPtr wp = FrontWindow ();
7606 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
7607 Lisp_Object frame, tail;
7608
7609 BLOCK_INPUT;
7610
7611 if (! NILP (last_mouse_scroll_bar) && insist == 0)
7612 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
7613 else
7614 {
7615 /* Clear the mouse-moved flag for every frame on this display. */
7616 FOR_EACH_FRAME (tail, frame)
7617 XFRAME (frame)->mouse_moved = 0;
7618
7619 last_mouse_scroll_bar = Qnil;
7620
7621 SetPort (wp);
7622 GetMouse (&mouse_pos);
7623
7624 pixel_to_glyph_coords (f, mouse_pos.h, mouse_pos.v, &ignore1, &ignore2,
7625 &last_mouse_glyph, insist);
7626
7627 *bar_window = Qnil;
7628 *part = scroll_bar_handle;
7629 *fp = f;
7630 XSETINT (*x, mouse_pos.h);
7631 XSETINT (*y, mouse_pos.v);
7632 *time = last_mouse_movement_time;
7633 }
7634
7635 UNBLOCK_INPUT;
7636}
7637
7638
7639/************************************************************************
7640 Scroll bars, general
7641 ************************************************************************/
7642
7643/* Create a scroll bar and return the scroll bar vector for it. W is
7644 the Emacs window on which to create the scroll bar. TOP, LEFT,
7645 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
7646 scroll bar. */
7647
7648static struct scroll_bar *
7649x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
7650 struct window *w;
7651 int top, left, width, height, disp_top, disp_height;
7652{
7653 struct frame *f = XFRAME (w->frame);
7654 struct scroll_bar *bar
7655 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
7656 Rect r;
7657 ControlHandle ch;
7658
7659 BLOCK_INPUT;
7660
7661 r.left = left;
7662 r.top = disp_top;
7663 r.right = left + width;
7664 r.bottom = disp_top + disp_height;
7665
7666 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0, scrollBarProc,
7667 0L);
7668 SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch);
7669 SetControlReference (ch, (long) bar);
7670
7671 XSETWINDOW (bar->window, w);
7672 XSETINT (bar->top, top);
7673 XSETINT (bar->left, left);
7674 XSETINT (bar->width, width);
7675 XSETINT (bar->height, height);
7676 XSETINT (bar->start, 0);
7677 XSETINT (bar->end, 0);
7678 bar->dragging = Qnil;
7679
7680 /* Add bar to its frame's list of scroll bars. */
7681 bar->next = FRAME_SCROLL_BARS (f);
7682 bar->prev = Qnil;
7683 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
7684 if (!NILP (bar->next))
7685 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
7686
7687 UNBLOCK_INPUT;
7688 return bar;
7689}
7690
7691
7692/* Draw BAR's handle in the proper position.
7693
7694 If the handle is already drawn from START to END, don't bother
7695 redrawing it, unless REBUILD is non-zero; in that case, always
7696 redraw it. (REBUILD is handy for drawing the handle after expose
7697 events.)
7698
7699 Normally, we want to constrain the start and end of the handle to
7700 fit inside its rectangle, but if the user is dragging the scroll
7701 bar handle, we want to let them drag it down all the way, so that
7702 the bar's top is as far down as it goes; otherwise, there's no way
7703 to move to the very end of the buffer. */
7704
7705static void
7706x_scroll_bar_set_handle (bar, start, end, rebuild)
7707 struct scroll_bar *bar;
7708 int start, end;
7709 int rebuild;
7710{
7711 int dragging = ! NILP (bar->dragging);
7712 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
7713 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7714
7715 /* If the display is already accurate, do nothing. */
7716 if (! rebuild
7717 && start == XINT (bar->start)
7718 && end == XINT (bar->end))
7719 return;
7720
7721 BLOCK_INPUT;
7722
7723 {
7724 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
7725 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
7726 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
7727
7728 /* Make sure the values are reasonable, and try to preserve
7729 the distance between start and end. */
7730 {
7731 int length = end - start;
7732
7733 if (start < 0)
7734 start = 0;
7735 else if (start > top_range)
7736 start = top_range;
7737 end = start + length;
7738
7739 if (end < start)
7740 end = start;
7741 else if (end > top_range && ! dragging)
7742 end = top_range;
7743 }
7744
7745 /* Store the adjusted setting in the scroll bar. */
7746 XSETINT (bar->start, start);
7747 XSETINT (bar->end, end);
7748
7749 /* Clip the end position, just for display. */
7750 if (end > top_range)
7751 end = top_range;
7752
7753 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
7754 below top positions, to make sure the handle is always at least
7755 that many pixels tall. */
7756 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
7757
7758 SetControlMinimum (ch, 0);
7759 /* Don't inadvertently activate deactivated scroll bars */
7760 if (GetControlMaximum (ch) != -1)
7761 SetControlMaximum (ch,
7762 VERTICAL_SCROLL_BAR_TOP_RANGE (f,
7763 XINT (bar->height))
7764 - 1);
7765 SetControlValue (ch, start);
7766#if 0 /* MAC_TODO: detect Appearance Manager 1.1 before use. */
7767 SetControlViewSize (ch, end);
7768#endif
7769 }
7770
7771 UNBLOCK_INPUT;
7772}
7773
7774
7775/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
7776 nil. */
7777
7778static void
7779x_scroll_bar_remove (bar)
7780 struct scroll_bar *bar;
7781{
7782 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7783
7784 BLOCK_INPUT;
7785
7786 /* Destroy the Mac scroll bar control */
7787 DisposeControl (SCROLL_BAR_CONTROL_HANDLE (bar));
7788
7789 /* Disassociate this scroll bar from its window. */
7790 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
7791
7792 UNBLOCK_INPUT;
7793}
7794
7795
7796/* Set the handle of the vertical scroll bar for WINDOW to indicate
7797 that we are displaying PORTION characters out of a total of WHOLE
7798 characters, starting at POSITION. If WINDOW has no scroll bar,
7799 create one. */
7800
7801static void
7802XTset_vertical_scroll_bar (w, portion, whole, position)
7803 struct window *w;
7804 int portion, whole, position;
7805{
7806 struct frame *f = XFRAME (w->frame);
7807 struct scroll_bar *bar;
7808 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
7809 int window_x, window_y, window_width, window_height;
7810
7811 /* Get window dimensions. */
7812 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
7813 top = window_y;
7814 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
7815 height = window_height;
7816
7817 /* Compute the left edge of the scroll bar area. */
7818 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7819 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
7820 else
7821 left = XFASTINT (w->left);
7822 left *= CANON_X_UNIT (f);
7823 left += FRAME_INTERNAL_BORDER_WIDTH (f);
7824
7825 /* Compute the width of the scroll bar which might be less than
7826 the width of the area reserved for the scroll bar. */
7827 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
7828 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
7829 else
7830 sb_width = width;
7831
7832 /* Compute the left edge of the scroll bar. */
7833 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7834 sb_left = left + width - sb_width - (width - sb_width) / 2;
7835 else
7836 sb_left = left + (width - sb_width) / 2;
7837
7838 /* Adjustments according to Inside Macintosh to make it look nice */
7839 disp_top = top;
7840 disp_height = height;
7841 if (disp_top == 0)
7842 {
7843 disp_top = -1;
7844 disp_height++;
7845 }
7846 else if (disp_top == PIXEL_HEIGHT (f) - 16)
7847 {
7848 disp_top++;
7849 disp_height--;
7850 }
7851
7852 if (sb_left + sb_width == PIXEL_WIDTH (f))
7853 sb_left++;
7854
7855 /* Does the scroll bar exist yet? */
7856 if (NILP (w->vertical_scroll_bar))
7857 {
7858 BLOCK_INPUT;
7859 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
7860 left, top, width, height, 0);
7861 UNBLOCK_INPUT;
7862 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
7863 disp_height);
7864 XSETVECTOR (w->vertical_scroll_bar, bar);
7865 }
7866 else
7867 {
7868 /* It may just need to be moved and resized. */
7869 ControlHandle ch;
7870
7871 bar = XSCROLL_BAR (w->vertical_scroll_bar);
7872 ch = SCROLL_BAR_CONTROL_HANDLE (bar);
7873
7874 BLOCK_INPUT;
7875
7876 /* If already correctly positioned, do nothing. */
7877 if (XINT (bar->left) == sb_left
7878 && XINT (bar->top) == top
7879 && XINT (bar->width) == sb_width
7880 && XINT (bar->height) == height)
7881 Draw1Control (ch);
7882 else
7883 {
7884 if (sb_left + sb_width >= PIXEL_WIDTH (f))
7885 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
7886 sb_left - 1, top, 1, height, 0);
7887
7888 HideControl (ch);
7889 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
7890 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7891 disp_height);
7892 ShowControl (ch);
7893
7894 /* Remember new settings. */
7895 XSETINT (bar->left, sb_left);
7896 XSETINT (bar->top, top);
7897 XSETINT (bar->width, sb_width);
7898 XSETINT (bar->height, height);
7899 }
7900
7901 UNBLOCK_INPUT;
7902 }
7903
7904 /* Set the scroll bar's current state, unless we're currently being
7905 dragged. */
7906 if (NILP (bar->dragging))
7907 {
7908 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
7909
7910 if (whole == 0)
7911 x_scroll_bar_set_handle (bar, 0, top_range, 0);
7912 else
7913 {
7914 int start = ((double) position * top_range) / whole;
7915 int end = ((double) (position + portion) * top_range) / whole;
7916 x_scroll_bar_set_handle (bar, start, end, 0);
7917 }
7918 }
7919}
7920
7921
7922/* The following three hooks are used when we're doing a thorough
7923 redisplay of the frame. We don't explicitly know which scroll bars
7924 are going to be deleted, because keeping track of when windows go
7925 away is a real pain - "Can you say set-window-configuration, boys
7926 and girls?" Instead, we just assert at the beginning of redisplay
7927 that *all* scroll bars are to be removed, and then save a scroll bar
7928 from the fiery pit when we actually redisplay its window. */
7929
7930/* Arrange for all scroll bars on FRAME to be removed at the next call
7931 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
7932 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
7933
7934static void
7935XTcondemn_scroll_bars (frame)
7936 FRAME_PTR frame;
7937{
7938 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
7939 while (! NILP (FRAME_SCROLL_BARS (frame)))
7940 {
7941 Lisp_Object bar;
7942 bar = FRAME_SCROLL_BARS (frame);
7943 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
7944 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
7945 XSCROLL_BAR (bar)->prev = Qnil;
7946 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
7947 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
7948 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
7949 }
7950}
7951
7952/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
7953 Note that WINDOW isn't necessarily condemned at all. */
7954static void
7955XTredeem_scroll_bar (window)
7956 struct window *window;
7957{
7958 struct scroll_bar *bar;
7959
7960 /* We can't redeem this window's scroll bar if it doesn't have one. */
7961 if (NILP (window->vertical_scroll_bar))
7962 abort ();
7963
7964 bar = XSCROLL_BAR (window->vertical_scroll_bar);
7965
7966 /* Unlink it from the condemned list. */
7967 {
7968 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
7969
7970 if (NILP (bar->prev))
7971 {
7972 /* If the prev pointer is nil, it must be the first in one of
7973 the lists. */
7974 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
7975 /* It's not condemned. Everything's fine. */
7976 return;
7977 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
7978 window->vertical_scroll_bar))
7979 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
7980 else
7981 /* If its prev pointer is nil, it must be at the front of
7982 one or the other! */
7983 abort ();
7984 }
7985 else
7986 XSCROLL_BAR (bar->prev)->next = bar->next;
7987
7988 if (! NILP (bar->next))
7989 XSCROLL_BAR (bar->next)->prev = bar->prev;
7990
7991 bar->next = FRAME_SCROLL_BARS (f);
7992 bar->prev = Qnil;
7993 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
7994 if (! NILP (bar->next))
7995 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
7996 }
7997}
7998
7999/* Remove all scroll bars on FRAME that haven't been saved since the
8000 last call to `*condemn_scroll_bars_hook'. */
8001
8002static void
8003XTjudge_scroll_bars (f)
8004 FRAME_PTR f;
8005{
8006 Lisp_Object bar, next;
8007
8008 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
8009
8010 /* Clear out the condemned list now so we won't try to process any
8011 more events on the hapless scroll bars. */
8012 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
8013
8014 for (; ! NILP (bar); bar = next)
8015 {
8016 struct scroll_bar *b = XSCROLL_BAR (bar);
8017
8018 x_scroll_bar_remove (b);
8019
8020 next = b->next;
8021 b->next = b->prev = Qnil;
8022 }
8023
8024 /* Now there should be no references to the condemned scroll bars,
8025 and they should get garbage-collected. */
8026}
8027
8028
8029static void
8030activate_scroll_bars (frame)
8031 FRAME_PTR frame;
8032{
8033 Lisp_Object bar;
8034 ControlHandle ch;
8035
8036 bar = FRAME_SCROLL_BARS (frame);
8037 while (! NILP (bar))
8038 {
8039 ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar));
8040 SetControlMaximum (ch,
8041 VERTICAL_SCROLL_BAR_TOP_RANGE (frame,
8042 XINT (XSCROLL_BAR (bar)
8043 ->height)) - 1);
8044
8045 bar = XSCROLL_BAR (bar)->next;
8046 }
8047}
8048
8049
8050static void
8051deactivate_scroll_bars (frame)
8052 FRAME_PTR frame;
8053{
8054 Lisp_Object bar;
8055 ControlHandle ch;
8056
8057 bar = FRAME_SCROLL_BARS (frame);
8058 while (! NILP (bar))
8059 {
8060 ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar));
8061 SetControlMaximum (ch, XINT (-1));
8062
8063 bar = XSCROLL_BAR (bar)->next;
8064 }
8065}
8066
8067/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8068 is set to something other than no_event, it is enqueued.
8069
8070 This may be called from a signal handler, so we have to ignore GC
8071 mark bits. */
8072
8073static void
8074x_scroll_bar_handle_click (bar, part_code, er, bufp)
8075 struct scroll_bar *bar;
8076 int part_code;
8077 EventRecord *er;
8078 struct input_event *bufp;
8079{
8080 if (! GC_WINDOWP (bar->window))
8081 abort ();
8082
8083 bufp->kind = scroll_bar_click;
8084 bufp->frame_or_window = bar->window;
8085 bufp->arg = Qnil;
8086
8087 bar->dragging = Qnil;
8088
8089 switch (part_code)
8090 {
8091 case kControlUpButtonPart:
8092 bufp->part = scroll_bar_up_arrow;
8093 break;
8094 case kControlDownButtonPart:
8095 bufp->part = scroll_bar_down_arrow;
8096 break;
8097 case kControlPageUpPart:
8098 bufp->part = scroll_bar_above_handle;
8099 break;
8100 case kControlPageDownPart:
8101 bufp->part = scroll_bar_below_handle;
8102 break;
8103 case kControlIndicatorPart:
8104 if (er->what == mouseDown)
8105 bar->dragging = make_number (0);
8106 XSETVECTOR (last_mouse_scroll_bar, bar);
8107 bufp->part = scroll_bar_handle;
8108 break;
8109 }
8110}
8111
8112
8113/* Handle some mouse motion while someone is dragging the scroll bar.
8114
8115 This may be called from a signal handler, so we have to ignore GC
8116 mark bits. */
8117
8118static void
8119x_scroll_bar_note_movement (bar, y_pos, t)
8120 struct scroll_bar *bar;
8121 int y_pos;
8122 Time t;
8123{
8124 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8125
8126 last_mouse_movement_time = t;
8127
8128 f->mouse_moved = 1;
8129 XSETVECTOR (last_mouse_scroll_bar, bar);
8130
8131 /* If we're dragging the bar, display it. */
8132 if (! GC_NILP (bar->dragging))
8133 {
8134 /* Where should the handle be now? */
8135 int new_start = y_pos - 24;
8136
8137 if (new_start != XINT (bar->start))
8138 {
8139 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
8140
8141 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
8142 }
8143 }
8144}
8145
8146
8147/* Return information to the user about the current position of the
8148 mouse on the scroll bar. */
8149
8150static void
8151x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8152 FRAME_PTR *fp;
8153 Lisp_Object *bar_window;
8154 enum scroll_bar_part *part;
8155 Lisp_Object *x, *y;
8156 unsigned long *time;
8157{
8158 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
8159 WindowPtr wp = FrontWindow ();
8160 Point mouse_pos;
8161 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
8162 int win_y, top_range;
8163
8164 SetPort (wp);
8165 GetMouse (&mouse_pos);
8166
8167 win_y = mouse_pos.v - XINT (bar->top);
8168 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
8169
8170 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8171
8172 win_y -= 24;
8173
8174 if (! NILP (bar->dragging))
8175 win_y -= XINT (bar->dragging);
8176
8177 if (win_y < 0)
8178 win_y = 0;
8179 if (win_y > top_range)
8180 win_y = top_range;
8181
8182 *fp = f;
8183 *bar_window = bar->window;
8184
8185 if (! NILP (bar->dragging))
8186 *part = scroll_bar_handle;
8187 else if (win_y < XINT (bar->start))
8188 *part = scroll_bar_above_handle;
8189 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8190 *part = scroll_bar_handle;
8191 else
8192 *part = scroll_bar_below_handle;
8193
8194 XSETINT (*x, win_y);
8195 XSETINT (*y, top_range);
8196
8197 f->mouse_moved = 0;
8198 last_mouse_scroll_bar = Qnil;
8199
8200 *time = last_mouse_movement_time;
8201}
8202
8203/***********************************************************************
8204 Text Cursor
8205 ***********************************************************************/
8206
8207/* Note if the text cursor of window W has been overwritten by a
8208 drawing operation that outputs N glyphs starting at HPOS in the
8209 line given by output_cursor.vpos. N < 0 means all the rest of the
8210 line after HPOS has been written. */
8211
8212static void
8213note_overwritten_text_cursor (w, hpos, n)
8214 struct window *w;
8215 int hpos, n;
8216{
8217 if (updated_area == TEXT_AREA
8218 && output_cursor.vpos == w->phys_cursor.vpos
8219 && hpos <= w->phys_cursor.hpos
8220 && (n < 0
8221 || hpos + n > w->phys_cursor.hpos))
8222 w->phys_cursor_on_p = 0;
8223}
8224
8225
8226/* Set clipping for output in glyph row ROW. W is the window in which
8227 we operate. GC is the graphics context to set clipping in.
8228 WHOLE_LINE_P non-zero means include the areas used for truncation
8229 mark display and alike in the clipping rectangle.
8230
8231 ROW may be a text row or, e.g., a mode line. Text rows must be
8232 clipped to the interior of the window dedicated to text display,
8233 mode lines must be clipped to the whole window. */
8234
8235static void
8236x_clip_to_row (w, row, gc, whole_line_p)
8237 struct window *w;
8238 struct glyph_row *row;
8239 GC gc;
8240 int whole_line_p;
8241{
8242 struct frame *f = XFRAME (WINDOW_FRAME (w));
8243 Rect clip_rect;
8244 int window_x, window_y, window_width, window_height;
8245
8246 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
8247
8248 clip_rect.left = WINDOW_TO_FRAME_PIXEL_X (w, 0);
8249 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
8250 clip_rect.top = max (clip_rect.top, window_y);
8251 clip_rect.right = clip_rect.left + window_width;
8252 clip_rect.bottom = clip_rect.top + row->visible_height;
8253
8254 /* If clipping to the whole line, including trunc marks, extend
8255 the rectangle to the left and increase its width. */
8256 if (whole_line_p)
8257 {
8258 clip_rect.left -= FRAME_X_LEFT_FRINGE_WIDTH (f);
8259 clip_rect.right += FRAME_X_FRINGE_WIDTH (f);
8260 }
8261
8262 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), &clip_rect);
8263}
8264
8265
8266/* Draw a hollow box cursor on window W in glyph row ROW. */
8267
8268static void
8269x_draw_hollow_cursor (w, row)
8270 struct window *w;
8271 struct glyph_row *row;
8272{
8273 struct frame *f = XFRAME (WINDOW_FRAME (w));
8274 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8275 Display *dpy = FRAME_MAC_DISPLAY (f);
8276 int x, y, wd, h;
8277 XGCValues xgcv;
8278 struct glyph *cursor_glyph;
8279 GC gc;
8280
8281 /* Compute frame-relative coordinates from window-relative
8282 coordinates. */
8283 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8284 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
8285 + row->ascent - w->phys_cursor_ascent);
8286 h = row->height - 1;
8287
8288 /* Get the glyph the cursor is on. If we can't tell because
8289 the current matrix is invalid or such, give up. */
8290 cursor_glyph = get_phys_cursor_glyph (w);
8291 if (cursor_glyph == NULL)
8292 return;
8293
8294 /* Compute the width of the rectangle to draw. If on a stretch
8295 glyph, and `x-stretch-block-cursor' is nil, don't draw a
8296 rectangle as wide as the glyph, but use a canonical character
8297 width instead. */
8298 wd = cursor_glyph->pixel_width - 1;
8299 if (cursor_glyph->type == STRETCH_GLYPH
8300 && !x_stretch_cursor_p)
8301 wd = min (CANON_X_UNIT (f), wd);
8302
8303 /* The foreground of cursor_gc is typically the same as the normal
8304 background color, which can cause the cursor box to be invisible. */
8305 xgcv.foreground = f->output_data.mac->cursor_pixel;
8306 if (dpyinfo->scratch_cursor_gc)
8307 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
8308 else
8309 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
8310 GCForeground, &xgcv);
8311 gc = dpyinfo->scratch_cursor_gc;
8312
8313 /* Set clipping, draw the rectangle, and reset clipping again. */
8314 x_clip_to_row (w, row, gc, 0);
8315 mac_draw_rectangle (dpy, FRAME_MAC_WINDOW (f), gc, x, y, wd, h);
8316 mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f));
8317}
8318
8319
8320/* Draw a bar cursor on window W in glyph row ROW.
8321
8322 Implementation note: One would like to draw a bar cursor with an
8323 angle equal to the one given by the font property XA_ITALIC_ANGLE.
8324 Unfortunately, I didn't find a font yet that has this property set.
8325 --gerd. */
8326
8327static void
8328x_draw_bar_cursor (w, row, width)
8329 struct window *w;
8330 struct glyph_row *row;
8331 int width;
8332{
8333 /* If cursor hpos is out of bounds, don't draw garbage. This can
8334 happen in mini-buffer windows when switching between echo area
8335 glyphs and mini-buffer. */
8336 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
8337 {
8338 struct frame *f = XFRAME (w->frame);
8339 struct glyph *cursor_glyph;
8340 GC gc;
8341 int x;
8342 unsigned long mask;
8343 XGCValues xgcv;
8344 Display *dpy;
8345 Window window;
8346
8347 cursor_glyph = get_phys_cursor_glyph (w);
8348 if (cursor_glyph == NULL)
8349 return;
8350
8351 xgcv.background = f->output_data.mac->cursor_pixel;
8352 xgcv.foreground = f->output_data.mac->cursor_pixel;
8353 mask = GCForeground | GCBackground;
8354 dpy = FRAME_MAC_DISPLAY (f);
8355 window = FRAME_MAC_WINDOW (f);
8356 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
8357
8358 if (gc)
8359 XChangeGC (dpy, gc, mask, &xgcv);
8360 else
8361 {
8362 gc = XCreateGC (dpy, window, mask, &xgcv);
8363 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
8364 }
8365
8366 if (width < 0)
8367 width = f->output_data.mac->cursor_width;
8368
8369 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8370 x_clip_to_row (w, row, gc, 0);
8371 XFillRectangle (dpy, window, gc,
8372 x,
8373 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
8374 min (cursor_glyph->pixel_width, width),
8375 row->height);
8376 mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f));
8377 }
8378}
8379
8380
8381/* Clear the cursor of window W to background color, and mark the
8382 cursor as not shown. This is used when the text where the cursor
8383 is is about to be rewritten. */
8384
8385static void
8386x_clear_cursor (w)
8387 struct window *w;
8388{
8389 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
8390 x_update_window_cursor (w, 0);
8391}
8392
8393
8394/* Draw the cursor glyph of window W in glyph row ROW. See the
8395 comment of x_draw_glyphs for the meaning of HL. */
8396
8397static void
8398x_draw_phys_cursor_glyph (w, row, hl)
8399 struct window *w;
8400 struct glyph_row *row;
8401 enum draw_glyphs_face hl;
8402{
8403 /* If cursor hpos is out of bounds, don't draw garbage. This can
8404 happen in mini-buffer windows when switching between echo area
8405 glyphs and mini-buffer. */
8406 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
8407 {
8408 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
8409 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
8410 hl, 0, 0, 0);
8411
8412 /* When we erase the cursor, and ROW is overlapped by other
8413 rows, make sure that these overlapping parts of other rows
8414 are redrawn. */
8415 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
8416 {
8417 if (row > w->current_matrix->rows
8418 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
8419 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
8420
8421 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
8422 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
8423 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
8424 }
8425 }
8426}
8427
8428
8429/* Erase the image of a cursor of window W from the screen. */
8430
8431static void
8432x_erase_phys_cursor (w)
8433 struct window *w;
8434{
8435 struct frame *f = XFRAME (w->frame);
8436 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8437 int hpos = w->phys_cursor.hpos;
8438 int vpos = w->phys_cursor.vpos;
8439 int mouse_face_here_p = 0;
8440 struct glyph_matrix *active_glyphs = w->current_matrix;
8441 struct glyph_row *cursor_row;
8442 struct glyph *cursor_glyph;
8443 enum draw_glyphs_face hl;
8444
8445 /* No cursor displayed or row invalidated => nothing to do on the
8446 screen. */
8447 if (w->phys_cursor_type == NO_CURSOR)
8448 goto mark_cursor_off;
8449
8450 /* VPOS >= active_glyphs->nrows means that window has been resized.
8451 Don't bother to erase the cursor. */
8452 if (vpos >= active_glyphs->nrows)
8453 goto mark_cursor_off;
8454
8455 /* If row containing cursor is marked invalid, there is nothing we
8456 can do. */
8457 cursor_row = MATRIX_ROW (active_glyphs, vpos);
8458 if (!cursor_row->enabled_p)
8459 goto mark_cursor_off;
8460
8461 /* If row is completely invisible, don't attempt to delete a cursor which
8462 isn't there. This can happen if cursor is at top of a window, and
8463 we switch to a buffer with a header line in that window. */
8464 if (cursor_row->visible_height <= 0)
8465 goto mark_cursor_off;
8466
8467 /* This can happen when the new row is shorter than the old one.
8468 In this case, either x_draw_glyphs or clear_end_of_line
8469 should have cleared the cursor. Note that we wouldn't be
8470 able to erase the cursor in this case because we don't have a
8471 cursor glyph at hand. */
8472 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
8473 goto mark_cursor_off;
8474
8475 /* If the cursor is in the mouse face area, redisplay that when
8476 we clear the cursor. */
8477 if (! NILP (dpyinfo->mouse_face_window)
8478 && w == XWINDOW (dpyinfo->mouse_face_window)
8479 && (vpos > dpyinfo->mouse_face_beg_row
8480 || (vpos == dpyinfo->mouse_face_beg_row
8481 && hpos >= dpyinfo->mouse_face_beg_col))
8482 && (vpos < dpyinfo->mouse_face_end_row
8483 || (vpos == dpyinfo->mouse_face_end_row
8484 && hpos < dpyinfo->mouse_face_end_col))
8485 /* Don't redraw the cursor's spot in mouse face if it is at the
8486 end of a line (on a newline). The cursor appears there, but
8487 mouse highlighting does not. */
8488 && cursor_row->used[TEXT_AREA] > hpos)
8489 mouse_face_here_p = 1;
8490
8491 /* Maybe clear the display under the cursor. */
8492 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
8493 {
8494 int x;
8495 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
8496
8497 cursor_glyph = get_phys_cursor_glyph (w);
8498 if (cursor_glyph == NULL)
8499 goto mark_cursor_off;
8500
8501 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
8502
8503 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
8504 x,
8505 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
8506 cursor_row->y)),
8507 cursor_glyph->pixel_width,
8508 cursor_row->visible_height,
8509 0);
8510 }
8511
8512 /* Erase the cursor by redrawing the character underneath it. */
8513 if (mouse_face_here_p)
8514 hl = DRAW_MOUSE_FACE;
8515 else if (cursor_row->inverse_p)
8516 hl = DRAW_INVERSE_VIDEO;
8517 else
8518 hl = DRAW_NORMAL_TEXT;
8519 x_draw_phys_cursor_glyph (w, cursor_row, hl);
8520
8521 mark_cursor_off:
8522 w->phys_cursor_on_p = 0;
8523 w->phys_cursor_type = NO_CURSOR;
8524}
8525
8526
8527/* Display or clear cursor of window W. If ON is zero, clear the
8528 cursor. If it is non-zero, display the cursor. If ON is nonzero,
8529 where to put the cursor is specified by HPOS, VPOS, X and Y. */
8530
8531void
8532x_display_and_set_cursor (w, on, hpos, vpos, x, y)
8533 struct window *w;
8534 int on, hpos, vpos, x, y;
8535{
8536 struct frame *f = XFRAME (w->frame);
8537 int new_cursor_type;
8538 int new_cursor_width;
8539 struct glyph_matrix *current_glyphs;
8540 struct glyph_row *glyph_row;
8541 struct glyph *glyph;
8542
8543 /* This is pointless on invisible frames, and dangerous on garbaged
8544 windows and frames; in the latter case, the frame or window may
8545 be in the midst of changing its size, and x and y may be off the
8546 window. */
8547 if (! FRAME_VISIBLE_P (f)
8548 || FRAME_GARBAGED_P (f)
8549 || vpos >= w->current_matrix->nrows
8550 || hpos >= w->current_matrix->matrix_w)
8551 return;
8552
8553 /* If cursor is off and we want it off, return quickly. */
8554 if (!on && !w->phys_cursor_on_p)
8555 return;
8556
8557 current_glyphs = w->current_matrix;
8558 glyph_row = MATRIX_ROW (current_glyphs, vpos);
8559 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
8560
8561 /* If cursor row is not enabled, we don't really know where to
8562 display the cursor. */
8563 if (!glyph_row->enabled_p)
8564 {
8565 w->phys_cursor_on_p = 0;
8566 return;
8567 }
8568
8569 xassert (interrupt_input_blocked);
8570
8571 /* Set new_cursor_type to the cursor we want to be displayed. In a
8572 mini-buffer window, we want the cursor only to appear if we are
8573 reading input from this window. For the selected window, we want
8574 the cursor type given by the frame parameter. If explicitly
8575 marked off, draw no cursor. In all other cases, we want a hollow
8576 box cursor. */
8577 new_cursor_width = -1;
8578 if (cursor_in_echo_area
8579 && FRAME_HAS_MINIBUF_P (f)
8580 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
8581 {
8582 if (w == XWINDOW (echo_area_window))
8583 new_cursor_type = FRAME_DESIRED_CURSOR (f);
8584 else
8585 new_cursor_type = HOLLOW_BOX_CURSOR;
8586 }
8587 else
8588 {
8589 if (w != XWINDOW (selected_window)
8590 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
8591 {
8592 extern int cursor_in_non_selected_windows;
8593
8594 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
8595 new_cursor_type = NO_CURSOR;
8596 else
8597 new_cursor_type = HOLLOW_BOX_CURSOR;
8598 }
8599 else if (w->cursor_off_p)
8600 new_cursor_type = NO_CURSOR;
8601 else
8602 {
8603 struct buffer *b = XBUFFER (w->buffer);
8604
8605 if (EQ (b->cursor_type, Qt))
8606 new_cursor_type = FRAME_DESIRED_CURSOR (f);
8607 else
8608 new_cursor_type = x_specified_cursor_type (b->cursor_type,
8609 &new_cursor_width);
8610 }
8611 }
8612
8613 /* If cursor is currently being shown and we don't want it to be or
8614 it is in the wrong place, or the cursor type is not what we want,
8615 erase it. */
8616 if (w->phys_cursor_on_p
8617 && (!on
8618 || w->phys_cursor.x != x
8619 || w->phys_cursor.y != y
8620 || new_cursor_type != w->phys_cursor_type))
8621 x_erase_phys_cursor (w);
8622
8623 /* If the cursor is now invisible and we want it to be visible,
8624 display it. */
8625 if (on && !w->phys_cursor_on_p)
8626 {
8627 w->phys_cursor_ascent = glyph_row->ascent;
8628 w->phys_cursor_height = glyph_row->height;
8629
8630 /* Set phys_cursor_.* before x_draw_.* is called because some
8631 of them may need the information. */
8632 w->phys_cursor.x = x;
8633 w->phys_cursor.y = glyph_row->y;
8634 w->phys_cursor.hpos = hpos;
8635 w->phys_cursor.vpos = vpos;
8636 w->phys_cursor_type = new_cursor_type;
8637 w->phys_cursor_on_p = 1;
8638
8639 switch (new_cursor_type)
8640 {
8641 case HOLLOW_BOX_CURSOR:
8642 x_draw_hollow_cursor (w, glyph_row);
8643 break;
8644
8645 case FILLED_BOX_CURSOR:
8646 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
8647 break;
8648
8649 case BAR_CURSOR:
8650 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
8651 break;
8652
8653 case NO_CURSOR:
8654 break;
8655
8656 default:
8657 abort ();
8658 }
8659
8660#ifdef HAVE_X_I18N
8661 if (w == XWINDOW (f->selected_window))
8662 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
8663 xic_set_preeditarea (w, x, y);
8664#endif
8665 }
8666
8667#ifndef XFlush
8668 if (updating_frame != f)
8669 XFlush (FRAME_X_DISPLAY (f));
8670#endif
8671}
8672
8673
8674/* Display the cursor on window W, or clear it. X and Y are window
8675 relative pixel coordinates. HPOS and VPOS are glyph matrix
8676 positions. If W is not the selected window, display a hollow
8677 cursor. ON non-zero means display the cursor at X, Y which
8678 correspond to HPOS, VPOS, otherwise it is cleared. */
8679
8680void
8681x_display_cursor (w, on, hpos, vpos, x, y)
8682 struct window *w;
8683 int on, hpos, vpos, x, y;
8684{
8685 BLOCK_INPUT;
8686 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
8687 UNBLOCK_INPUT;
8688}
8689
8690
8691/* Display the cursor on window W, or clear it, according to ON_P.
8692 Don't change the cursor's position. */
8693
8694void
8695x_update_cursor (f, on_p)
8696 struct frame *f;
8697{
8698 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
8699}
8700
8701
8702/* Call x_update_window_cursor with parameter ON_P on all leaf windows
8703 in the window tree rooted at W. */
8704
8705static void
8706x_update_cursor_in_window_tree (w, on_p)
8707 struct window *w;
8708 int on_p;
8709{
8710 while (w)
8711 {
8712 if (!NILP (w->hchild))
8713 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
8714 else if (!NILP (w->vchild))
8715 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
8716 else
8717 x_update_window_cursor (w, on_p);
8718
8719 w = NILP (w->next) ? 0 : XWINDOW (w->next);
8720 }
8721}
8722
8723
8724/* Switch the display of W's cursor on or off, according to the value
8725 of ON. */
8726
8727static void
8728x_update_window_cursor (w, on)
8729 struct window *w;
8730 int on;
8731{
8732 /* Don't update cursor in windows whose frame is in the process
8733 of being deleted. */
8734 if (w->current_matrix)
8735 {
8736 BLOCK_INPUT;
8737 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
8738 w->phys_cursor.x, w->phys_cursor.y);
8739 UNBLOCK_INPUT;
8740 }
8741}
8742
8743
8744#if 0 /* MAC_TODO: no icon and X error handling (?) */
8745/* Icons. */
8746
8747/* Refresh bitmap kitchen sink icon for frame F
8748 when we get an expose event for it. */
8749
8750void
8751refreshicon (f)
8752 struct frame *f;
8753{
8754 /* Normally, the window manager handles this function. */
8755}
8756
8757/* Make the x-window of frame F use the gnu icon bitmap. */
8758
8759int
8760x_bitmap_icon (f, file)
8761 struct frame *f;
8762 Lisp_Object file;
8763{
8764 int bitmap_id;
8765
8766 if (FRAME_X_WINDOW (f) == 0)
8767 return 1;
8768
8769 /* Free up our existing icon bitmap if any. */
8770 if (f->output_data.x->icon_bitmap > 0)
8771 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
8772 f->output_data.x->icon_bitmap = 0;
8773
8774 if (STRINGP (file))
8775 bitmap_id = x_create_bitmap_from_file (f, file);
8776 else
8777 {
8778 /* Create the GNU bitmap if necessary. */
8779 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
8780 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
8781 = x_create_bitmap_from_data (f, gnu_bits,
8782 gnu_width, gnu_height);
8783
8784 /* The first time we create the GNU bitmap,
8785 this increments the ref-count one extra time.
8786 As a result, the GNU bitmap is never freed.
8787 That way, we don't have to worry about allocating it again. */
8788 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
8789
8790 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
8791 }
8792
8793 x_wm_set_icon_pixmap (f, bitmap_id);
8794 f->output_data.x->icon_bitmap = bitmap_id;
8795
8796 return 0;
8797}
8798
8799
8800/* Make the x-window of frame F use a rectangle with text.
8801 Use ICON_NAME as the text. */
8802
8803int
8804x_text_icon (f, icon_name)
8805 struct frame *f;
8806 char *icon_name;
8807{
8808 if (FRAME_X_WINDOW (f) == 0)
8809 return 1;
8810
8811#ifdef HAVE_X11R4
8812 {
8813 XTextProperty text;
8814 text.value = (unsigned char *) icon_name;
8815 text.encoding = XA_STRING;
8816 text.format = 8;
8817 text.nitems = strlen (icon_name);
8818#ifdef USE_X_TOOLKIT
8819 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
8820 &text);
8821#else /* not USE_X_TOOLKIT */
8822 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
8823#endif /* not USE_X_TOOLKIT */
8824 }
8825#else /* not HAVE_X11R4 */
8826 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
8827#endif /* not HAVE_X11R4 */
8828
8829 if (f->output_data.x->icon_bitmap > 0)
8830 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
8831 f->output_data.x->icon_bitmap = 0;
8832 x_wm_set_icon_pixmap (f, 0);
8833
8834 return 0;
8835}
8836
8837#define X_ERROR_MESSAGE_SIZE 200
8838
8839/* If non-nil, this should be a string.
8840 It means catch X errors and store the error message in this string. */
8841
8842static Lisp_Object x_error_message_string;
8843
8844/* An X error handler which stores the error message in
8845 x_error_message_string. This is called from x_error_handler if
8846 x_catch_errors is in effect. */
8847
8848static void
8849x_error_catcher (display, error)
8850 Display *display;
8851 XErrorEvent *error;
8852{
8853 XGetErrorText (display, error->error_code,
8854 XSTRING (x_error_message_string)->data,
8855 X_ERROR_MESSAGE_SIZE);
8856}
8857
8858/* Begin trapping X errors for display DPY. Actually we trap X errors
8859 for all displays, but DPY should be the display you are actually
8860 operating on.
8861
8862 After calling this function, X protocol errors no longer cause
8863 Emacs to exit; instead, they are recorded in the string
8864 stored in x_error_message_string.
8865
8866 Calling x_check_errors signals an Emacs error if an X error has
8867 occurred since the last call to x_catch_errors or x_check_errors.
8868
8869 Calling x_uncatch_errors resumes the normal error handling. */
8870
8871void x_check_errors ();
8872static Lisp_Object x_catch_errors_unwind ();
8873
8874int
8875x_catch_errors (dpy)
8876 Display *dpy;
8877{
8878 int count = specpdl_ptr - specpdl;
8879
8880 /* Make sure any errors from previous requests have been dealt with. */
8881 XSync (dpy, False);
8882
8883 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
8884
8885 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
8886 XSTRING (x_error_message_string)->data[0] = 0;
8887
8888 return count;
8889}
8890
8891/* Unbind the binding that we made to check for X errors. */
8892
8893static Lisp_Object
8894x_catch_errors_unwind (old_val)
8895 Lisp_Object old_val;
8896{
8897 x_error_message_string = old_val;
8898 return Qnil;
8899}
8900
8901/* If any X protocol errors have arrived since the last call to
8902 x_catch_errors or x_check_errors, signal an Emacs error using
8903 sprintf (a buffer, FORMAT, the x error message text) as the text. */
8904
8905void
8906x_check_errors (dpy, format)
8907 Display *dpy;
8908 char *format;
8909{
8910 /* Make sure to catch any errors incurred so far. */
8911 XSync (dpy, False);
8912
8913 if (XSTRING (x_error_message_string)->data[0])
8914 error (format, XSTRING (x_error_message_string)->data);
8915}
8916
8917/* Nonzero if we had any X protocol errors
8918 since we did x_catch_errors on DPY. */
8919
8920int
8921x_had_errors_p (dpy)
8922 Display *dpy;
8923{
8924 /* Make sure to catch any errors incurred so far. */
8925 XSync (dpy, False);
8926
8927 return XSTRING (x_error_message_string)->data[0] != 0;
8928}
8929
8930/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
8931
8932void
8933x_clear_errors (dpy)
8934 Display *dpy;
8935{
8936 XSTRING (x_error_message_string)->data[0] = 0;
8937}
8938
8939/* Stop catching X protocol errors and let them make Emacs die.
8940 DPY should be the display that was passed to x_catch_errors.
8941 COUNT should be the value that was returned by
8942 the corresponding call to x_catch_errors. */
8943
8944void
8945x_uncatch_errors (dpy, count)
8946 Display *dpy;
8947 int count;
8948{
8949 unbind_to (count, Qnil);
8950}
8951
8952#if 0
8953static unsigned int x_wire_count;
8954x_trace_wire ()
8955{
8956 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
8957}
8958#endif /* ! 0 */
8959
8960
8961/* Handle SIGPIPE, which can happen when the connection to a server
8962 simply goes away. SIGPIPE is handled by x_connection_signal.
8963 Don't need to do anything, because the write which caused the
8964 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
8965 which will do the appropriate cleanup for us. */
8966
8967static SIGTYPE
8968x_connection_signal (signalnum) /* If we don't have an argument, */
8969 int signalnum; /* some compilers complain in signal calls. */
8970{
8971#ifdef USG
8972 /* USG systems forget handlers when they are used;
8973 must reestablish each time */
8974 signal (signalnum, x_connection_signal);
8975#endif /* USG */
8976}
8977
8978/* Handling X errors. */
8979
8980/* Handle the loss of connection to display DISPLAY. */
8981
8982static SIGTYPE
8983x_connection_closed (display, error_message)
8984 Display *display;
8985 char *error_message;
8986{
8987 struct x_display_info *dpyinfo = x_display_info_for_display (display);
8988 Lisp_Object frame, tail;
8989
8990 /* Indicate that this display is dead. */
8991
8992#if 0 /* Closing the display caused a bus error on OpenWindows. */
8993#ifdef USE_X_TOOLKIT
8994 XtCloseDisplay (display);
8995#endif
8996#endif
8997
8998 if (dpyinfo)
8999 dpyinfo->display = 0;
9000
9001 /* First delete frames whose mini-buffers are on frames
9002 that are on the dead display. */
9003 FOR_EACH_FRAME (tail, frame)
9004 {
9005 Lisp_Object minibuf_frame;
9006 minibuf_frame
9007 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
9008 if (FRAME_X_P (XFRAME (frame))
9009 && FRAME_X_P (XFRAME (minibuf_frame))
9010 && ! EQ (frame, minibuf_frame)
9011 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
9012 Fdelete_frame (frame, Qt);
9013 }
9014
9015 /* Now delete all remaining frames on the dead display.
9016 We are now sure none of these is used as the mini-buffer
9017 for another frame that we need to delete. */
9018 FOR_EACH_FRAME (tail, frame)
9019 if (FRAME_X_P (XFRAME (frame))
9020 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
9021 {
9022 /* Set this to t so that Fdelete_frame won't get confused
9023 trying to find a replacement. */
9024 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
9025 Fdelete_frame (frame, Qt);
9026 }
9027
9028 if (dpyinfo)
9029 x_delete_display (dpyinfo);
9030
9031 if (x_display_list == 0)
9032 {
9033 fprintf (stderr, "%s\n", error_message);
9034 shut_down_emacs (0, 0, Qnil);
9035 exit (70);
9036 }
9037
9038 /* Ordinary stack unwind doesn't deal with these. */
9039#ifdef SIGIO
9040 sigunblock (sigmask (SIGIO));
9041#endif
9042 sigunblock (sigmask (SIGALRM));
9043 TOTALLY_UNBLOCK_INPUT;
9044
9045 clear_waiting_for_input ();
9046 error ("%s", error_message);
9047}
9048
9049/* This is the usual handler for X protocol errors.
9050 It kills all frames on the display that we got the error for.
9051 If that was the only one, it prints an error message and kills Emacs. */
9052
9053static void
9054x_error_quitter (display, error)
9055 Display *display;
9056 XErrorEvent *error;
9057{
9058 char buf[256], buf1[356];
9059
9060 /* Note that there is no real way portable across R3/R4 to get the
9061 original error handler. */
9062
9063 XGetErrorText (display, error->error_code, buf, sizeof (buf));
9064 sprintf (buf1, "X protocol error: %s on protocol request %d",
9065 buf, error->request_code);
9066 x_connection_closed (display, buf1);
9067}
9068
9069/* This is the first-level handler for X protocol errors.
9070 It calls x_error_quitter or x_error_catcher. */
9071
9072static int
9073x_error_handler (display, error)
9074 Display *display;
9075 XErrorEvent *error;
9076{
9077 if (! NILP (x_error_message_string))
9078 x_error_catcher (display, error);
9079 else
9080 x_error_quitter (display, error);
9081 return 0;
9082}
9083
9084/* This is the handler for X IO errors, always.
9085 It kills all frames on the display that we lost touch with.
9086 If that was the only one, it prints an error message and kills Emacs. */
9087
9088static int
9089x_io_error_quitter (display)
9090 Display *display;
9091{
9092 char buf[256];
9093
9094 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
9095 x_connection_closed (display, buf);
9096 return 0;
9097}
9098#endif
9099
9100/* Changing the font of the frame. */
9101
9102/* Give frame F the font named FONTNAME as its default font, and
9103 return the full name of that font. FONTNAME may be a wildcard
9104 pattern; in that case, we choose some font that fits the pattern.
9105 The return value shows which font we chose. */
9106
9107Lisp_Object
9108x_new_font (f, fontname)
9109 struct frame *f;
9110 register char *fontname;
9111{
9112 struct font_info *fontp
9113 = FS_LOAD_FONT (f, 0, fontname, -1);
9114
9115 if (!fontp)
9116 return Qnil;
9117
9118 f->output_data.mac->font = (XFontStruct *) (fontp->font);
9119 f->output_data.mac->baseline_offset = fontp->baseline_offset;
9120 f->output_data.mac->fontset = -1;
9121
9122 /* Compute the scroll bar width in character columns. */
9123 if (f->scroll_bar_pixel_width > 0)
9124 {
9125 int wid = FONT_WIDTH (f->output_data.mac->font);
9126 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
9127 }
9128 else
9129 {
9130 int wid = FONT_WIDTH (f->output_data.mac->font);
9131 f->scroll_bar_cols = (14 + wid - 1) / wid;
9132 }
9133
9134 /* Now make the frame display the given font. */
9135 if (FRAME_MAC_WINDOW (f) != 0)
9136 {
9137 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
9138 f->output_data.mac->font);
9139 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
9140 f->output_data.mac->font);
9141 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
9142 f->output_data.mac->font);
9143
9144 frame_update_line_height (f);
9145 x_set_window_size (f, 0, f->width, f->height);
9146 }
9147 else
9148 /* If we are setting a new frame's font for the first time, there
9149 are no faces yet, so this font's height is the line height. */
9150 f->output_data.mac->line_height = FONT_HEIGHT (f->output_data.mac->font);
9151
9152 return build_string (fontp->full_name);
9153}
9154
9155/* Give frame F the fontset named FONTSETNAME as its default font, and
9156 return the full name of that fontset. FONTSETNAME may be a
9157 wildcard pattern; in that case, we choose some fontset that fits
9158 the pattern. The return value shows which fontset we chose. */
9159
9160Lisp_Object
9161x_new_fontset (f, fontsetname)
9162 struct frame *f;
9163 char *fontsetname;
9164{
9165 int fontset = fs_query_fontset (build_string (fontsetname), 0);
9166 Lisp_Object result;
9167
9168 if (fontset < 0)
9169 return Qnil;
9170
9171 if (f->output_data.mac->fontset == fontset)
9172 /* This fontset is already set in frame F. There's nothing more
9173 to do. */
9174 return fontset_name (fontset);
9175
9176 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
9177
9178 if (!STRINGP (result))
9179 /* Can't load ASCII font. */
9180 return Qnil;
9181
9182 /* Since x_new_font doesn't update any fontset information, do it
9183 now. */
9184 f->output_data.mac->fontset = fontset;
9185
9186#ifdef HAVE_X_I18N
9187 if (FRAME_XIC (f)
9188 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
9189 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
9190#endif
9191
9192 return build_string (fontsetname);
9193}
9194
9195/* Compute actual fringe widths */
9196
9197void
9198x_compute_fringe_widths (f, redraw)
9199 struct frame *f;
9200 int redraw;
9201{
9202 int o_left = f->output_data.mac->left_fringe_width;
9203 int o_right = f->output_data.mac->right_fringe_width;
9204 int o_cols = f->output_data.mac->fringe_cols;
9205
9206 Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
9207 Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
9208 int left_fringe_width, right_fringe_width;
9209
9210 if (!NILP (left_fringe))
9211 left_fringe = Fcdr (left_fringe);
9212 if (!NILP (right_fringe))
9213 right_fringe = Fcdr (right_fringe);
9214
9215 left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
9216 XINT (left_fringe));
9217 right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
9218 XINT (right_fringe));
9219
9220 if (left_fringe_width || right_fringe_width)
9221 {
9222 int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
9223 int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
9224 int conf_wid = left_wid + right_wid;
9225 int font_wid = FONT_WIDTH (f->output_data.mac->font);
9226 int cols = (left_wid + right_wid + font_wid-1) / font_wid;
9227 int real_wid = cols * font_wid;
9228 if (left_wid && right_wid)
9229 {
9230 if (left_fringe_width < 0)
9231 {
9232 /* Left fringe width is fixed, adjust right fringe if necessary */
9233 f->output_data.mac->left_fringe_width = left_wid;
9234 f->output_data.mac->right_fringe_width = real_wid - left_wid;
9235 }
9236 else if (right_fringe_width < 0)
9237 {
9238 /* Right fringe width is fixed, adjust left fringe if necessary */
9239 f->output_data.mac->left_fringe_width = real_wid - right_wid;
9240 f->output_data.mac->right_fringe_width = right_wid;
9241 }
9242 else
9243 {
9244 /* Adjust both fringes with an equal amount.
9245 Note that we are doing integer arithmetic here, so don't
9246 lose a pixel if the total width is an odd number. */
9247 int fill = real_wid - conf_wid;
9248 f->output_data.mac->left_fringe_width = left_wid + fill/2;
9249 f->output_data.mac->right_fringe_width = right_wid + fill - fill/2;
9250 }
9251 }
9252 else if (left_fringe_width)
9253 {
9254 f->output_data.mac->left_fringe_width = real_wid;
9255 f->output_data.mac->right_fringe_width = 0;
9256 }
9257 else
9258 {
9259 f->output_data.mac->left_fringe_width = 0;
9260 f->output_data.mac->right_fringe_width = real_wid;
9261 }
9262 f->output_data.mac->fringe_cols = cols;
9263 f->output_data.mac->fringes_extra = real_wid;
9264 }
9265 else
9266 {
9267 f->output_data.mac->left_fringe_width = 0;
9268 f->output_data.mac->right_fringe_width = 0;
9269 f->output_data.mac->fringe_cols = 0;
9270 f->output_data.mac->fringes_extra = 0;
9271 }
9272
9273 if (redraw && FRAME_VISIBLE_P (f))
9274 if (o_left != f->output_data.mac->left_fringe_width ||
9275 o_right != f->output_data.mac->right_fringe_width ||
9276 o_cols != f->output_data.mac->fringe_cols)
9277 redraw_frame (f);
9278}
9279
9280#if 0 /* MAC_TODO: inline input methods for Mac */
9281/***********************************************************************
9282 X Input Methods
9283 ***********************************************************************/
9284
9285#ifdef HAVE_X_I18N
9286
9287#ifdef HAVE_X11R6
9288
9289/* XIM destroy callback function, which is called whenever the
9290 connection to input method XIM dies. CLIENT_DATA contains a
9291 pointer to the x_display_info structure corresponding to XIM. */
9292
9293static void
9294xim_destroy_callback (xim, client_data, call_data)
9295 XIM xim;
9296 XPointer client_data;
9297 XPointer call_data;
9298{
9299 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
9300 Lisp_Object frame, tail;
9301
9302 BLOCK_INPUT;
9303
9304 /* No need to call XDestroyIC.. */
9305 FOR_EACH_FRAME (tail, frame)
9306 {
9307 struct frame *f = XFRAME (frame);
9308 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
9309 {
9310 FRAME_XIC (f) = NULL;
9311 if (FRAME_XIC_FONTSET (f))
9312 {
9313 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
9314 FRAME_XIC_FONTSET (f) = NULL;
9315 }
9316 }
9317 }
9318
9319 /* No need to call XCloseIM. */
9320 dpyinfo->xim = NULL;
9321 XFree (dpyinfo->xim_styles);
9322 UNBLOCK_INPUT;
9323}
9324
9325#endif /* HAVE_X11R6 */
9326
9327/* Open the connection to the XIM server on display DPYINFO.
9328 RESOURCE_NAME is the resource name Emacs uses. */
9329
9330static void
9331xim_open_dpy (dpyinfo, resource_name)
9332 struct x_display_info *dpyinfo;
9333 char *resource_name;
9334{
9335#ifdef USE_XIM
9336 XIM xim;
9337
9338 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
9339 dpyinfo->xim = xim;
9340
9341 if (xim)
9342 {
9343#ifdef HAVE_X11R6
9344 XIMCallback destroy;
9345#endif
9346
9347 /* Get supported styles and XIM values. */
9348 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
9349
9350#ifdef HAVE_X11R6
9351 destroy.callback = xim_destroy_callback;
9352 destroy.client_data = (XPointer)dpyinfo;
9353 /* This isn't prototyped in OSF 5.0. */
9354 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
9355#endif
9356 }
9357
9358#else /* not USE_XIM */
9359 dpyinfo->xim = NULL;
9360#endif /* not USE_XIM */
9361}
9362
9363
9364#ifdef HAVE_X11R6_XIM
9365
9366struct xim_inst_t
9367{
9368 struct x_display_info *dpyinfo;
9369 char *resource_name;
9370};
9371
9372/* XIM instantiate callback function, which is called whenever an XIM
9373 server is available. DISPLAY is teh display of the XIM.
9374 CLIENT_DATA contains a pointer to an xim_inst_t structure created
9375 when the callback was registered. */
9376
9377static void
9378xim_instantiate_callback (display, client_data, call_data)
9379 Display *display;
9380 XPointer client_data;
9381 XPointer call_data;
9382{
9383 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
9384 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
9385
9386 /* We don't support multiple XIM connections. */
9387 if (dpyinfo->xim)
9388 return;
9389
9390 xim_open_dpy (dpyinfo, xim_inst->resource_name);
9391
9392 /* Create XIC for the existing frames on the same display, as long
9393 as they have no XIC. */
9394 if (dpyinfo->xim && dpyinfo->reference_count > 0)
9395 {
9396 Lisp_Object tail, frame;
9397
9398 BLOCK_INPUT;
9399 FOR_EACH_FRAME (tail, frame)
9400 {
9401 struct frame *f = XFRAME (frame);
9402
9403 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
9404 if (FRAME_XIC (f) == NULL)
9405 {
9406 create_frame_xic (f);
9407 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
9408 xic_set_statusarea (f);
9409 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
9410 {
9411 struct window *w = XWINDOW (f->selected_window);
9412 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
9413 }
9414 }
9415 }
9416
9417 UNBLOCK_INPUT;
9418 }
9419}
9420
9421#endif /* HAVE_X11R6_XIM */
9422
9423
9424/* Open a connection to the XIM server on display DPYINFO.
9425 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
9426 connection only at the first time. On X11R6, open the connection
9427 in the XIM instantiate callback function. */
9428
9429static void
9430xim_initialize (dpyinfo, resource_name)
9431 struct x_display_info *dpyinfo;
9432 char *resource_name;
9433{
9434#ifdef USE_XIM
9435#ifdef HAVE_X11R6_XIM
9436 struct xim_inst_t *xim_inst;
9437 int len;
9438
9439 dpyinfo->xim = NULL;
9440 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
9441 xim_inst->dpyinfo = dpyinfo;
9442 len = strlen (resource_name);
9443 xim_inst->resource_name = (char *) xmalloc (len + 1);
9444 bcopy (resource_name, xim_inst->resource_name, len + 1);
9445 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
9446 resource_name, EMACS_CLASS,
9447 xim_instantiate_callback,
9448 /* Fixme: This is XPointer in
9449 XFree86 but (XPointer *) on
9450 Tru64, at least. */
9451 (XPointer) xim_inst);
9452#else /* not HAVE_X11R6_XIM */
9453 dpyinfo->xim = NULL;
9454 xim_open_dpy (dpyinfo, resource_name);
9455#endif /* not HAVE_X11R6_XIM */
9456
9457#else /* not USE_XIM */
9458 dpyinfo->xim = NULL;
9459#endif /* not USE_XIM */
9460}
9461
9462
9463/* Close the connection to the XIM server on display DPYINFO. */
9464
9465static void
9466xim_close_dpy (dpyinfo)
9467 struct x_display_info *dpyinfo;
9468{
9469#ifdef USE_XIM
9470#ifdef HAVE_X11R6_XIM
9471 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
9472 NULL, EMACS_CLASS,
9473 xim_instantiate_callback, NULL);
9474#endif /* not HAVE_X11R6_XIM */
9475 XCloseIM (dpyinfo->xim);
9476 dpyinfo->xim = NULL;
9477 XFree (dpyinfo->xim_styles);
9478#endif /* USE_XIM */
9479}
9480
9481#endif /* not HAVE_X11R6_XIM */
9482
9483#endif
9484
9485/* Calculate the absolute position in frame F
9486 from its current recorded position values and gravity. */
9487
9488static void
9489x_calc_absolute_position (f)
9490 struct frame *f;
9491{
9492 Point pt;
9493 int flags = f->output_data.mac->size_hint_flags;
9494
9495 pt.h = pt.v = 0;
9496
9497 /* Find the position of the outside upper-left corner of
9498 the inner window, with respect to the outer window. */
9499 if (f->output_data.mac->parent_desc != FRAME_MAC_DISPLAY_INFO (f)->root_window)
9500 {
9501 GrafPtr savePort;
9502 GetPort (&savePort);
9503 SetPort (FRAME_MAC_WINDOW (f));
9504 SetPt(&pt, FRAME_MAC_WINDOW (f)->portRect.left, FRAME_MAC_WINDOW (f)->portRect.top);
9505 LocalToGlobal (&pt);
9506 SetPort (savePort);
9507 }
9508
9509 /* Treat negative positions as relative to the leftmost bottommost
9510 position that fits on the screen. */
9511 if (flags & XNegative)
9512 f->output_data.mac->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
9513 - 2 * f->output_data.mac->border_width - pt.h
9514 - PIXEL_WIDTH (f)
9515 + f->output_data.mac->left_pos);
9516 /* NTEMACS_TODO: Subtract menubar height? */
9517 if (flags & YNegative)
9518 f->output_data.mac->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
9519 - 2 * f->output_data.mac->border_width - pt.v
9520 - PIXEL_HEIGHT (f)
9521 + f->output_data.mac->top_pos);
9522 /* The left_pos and top_pos
9523 are now relative to the top and left screen edges,
9524 so the flags should correspond. */
9525 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
9526}
9527
9528/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
9529 to really change the position, and 0 when calling from
9530 x_make_frame_visible (in that case, XOFF and YOFF are the current
9531 position values). It is -1 when calling from x_set_frame_parameters,
9532 which means, do adjust for borders but don't change the gravity. */
9533
9534void
9535x_set_offset (f, xoff, yoff, change_gravity)
9536 struct frame *f;
9537 register int xoff, yoff;
9538 int change_gravity;
9539{
9540 if (change_gravity > 0)
9541 {
9542 f->output_data.mac->top_pos = yoff;
9543 f->output_data.mac->left_pos = xoff;
9544 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
9545 if (xoff < 0)
9546 f->output_data.mac->size_hint_flags |= XNegative;
9547 if (yoff < 0)
9548 f->output_data.mac->size_hint_flags |= YNegative;
9549 f->output_data.mac->win_gravity = NorthWestGravity;
9550 }
9551 x_calc_absolute_position (f);
9552
9553 BLOCK_INPUT;
9554 x_wm_set_size_hint (f, (long) 0, 0);
9555
9556 MoveWindow (f->output_data.mac->mWP, xoff + 6, yoff + 42, false);
9557
9558 UNBLOCK_INPUT;
9559}
9560
9561/* Call this to change the size of frame F's x-window.
9562 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
9563 for this size change and subsequent size changes.
9564 Otherwise we leave the window gravity unchanged. */
9565
9566void
9567x_set_window_size (f, change_gravity, cols, rows)
9568 struct frame *f;
9569 int change_gravity;
9570 int cols, rows;
9571{
9572 int pixelwidth, pixelheight;
9573
9574 check_frame_size (f, &rows, &cols);
9575 f->output_data.mac->vertical_scroll_bar_extra
9576 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
9577 ? 0
9578 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
9579 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
9580 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
9581
9582 x_compute_fringe_widths (f, 0);
9583
9584 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
9585 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
9586
9587 f->output_data.mac->win_gravity = NorthWestGravity;
9588 x_wm_set_size_hint (f, (long) 0, 0);
9589
9590 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
9591
9592 /* Now, strictly speaking, we can't be sure that this is accurate,
9593 but the window manager will get around to dealing with the size
9594 change request eventually, and we'll hear how it went when the
9595 ConfigureNotify event gets here.
9596
9597 We could just not bother storing any of this information here,
9598 and let the ConfigureNotify event set everything up, but that
9599 might be kind of confusing to the Lisp code, since size changes
9600 wouldn't be reported in the frame parameters until some random
9601 point in the future when the ConfigureNotify event arrives.
9602
9603 We pass 1 for DELAY since we can't run Lisp code inside of
9604 a BLOCK_INPUT. */
9605 change_frame_size (f, rows, cols, 0, 1, 0);
9606 PIXEL_WIDTH (f) = pixelwidth;
9607 PIXEL_HEIGHT (f) = pixelheight;
9608
9609 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
9610 receive in the ConfigureNotify event; if we get what we asked
9611 for, then the event won't cause the screen to become garbaged, so
9612 we have to make sure to do it here. */
9613 SET_FRAME_GARBAGED (f);
9614
9615 XFlush (FRAME_X_DISPLAY (f));
9616
9617 /* If cursor was outside the new size, mark it as off. */
9618 mark_window_cursors_off (XWINDOW (f->root_window));
9619
9620 /* Clear out any recollection of where the mouse highlighting was,
9621 since it might be in a place that's outside the new frame size.
9622 Actually checking whether it is outside is a pain in the neck,
9623 so don't try--just let the highlighting be done afresh with new size. */
9624 cancel_mouse_face (f);
9625}
9626
9627/* Mouse warping. */
9628
9629void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
9630
9631void
9632x_set_mouse_position (f, x, y)
9633 struct frame *f;
9634 int x, y;
9635{
9636 int pix_x, pix_y;
9637
9638 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.mac->font) / 2;
9639 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.mac->line_height / 2;
9640
9641 if (pix_x < 0) pix_x = 0;
9642 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
9643
9644 if (pix_y < 0) pix_y = 0;
9645 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
9646
9647 x_set_mouse_pixel_position (f, pix_x, pix_y);
9648}
9649
9650/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
9651
9652void
9653x_set_mouse_pixel_position (f, pix_x, pix_y)
9654 struct frame *f;
9655 int pix_x, pix_y;
9656{
9657#if 0 /* MAC_TODO: CursorDeviceMoveTo is non-Carbon */
9658 BLOCK_INPUT;
9659
9660 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
9661 0, 0, 0, 0, pix_x, pix_y);
9662 UNBLOCK_INPUT;
9663#endif
9664}
9665
9666/* focus shifting, raising and lowering. */
9667
9668static void
9669x_focus_on_frame (f)
9670 struct frame *f;
9671{
9672#if 0 /* This proves to be unpleasant. */
9673 x_raise_frame (f);
9674#endif
9675#if 0
9676 /* I don't think that the ICCCM allows programs to do things like this
9677 without the interaction of the window manager. Whatever you end up
9678 doing with this code, do it to x_unfocus_frame too. */
9679 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9680 RevertToPointerRoot, CurrentTime);
9681#endif /* ! 0 */
9682}
9683
9684static void
9685x_unfocus_frame (f)
9686 struct frame *f;
9687{
9688#if 0
9689 /* Look at the remarks in x_focus_on_frame. */
9690 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
9691 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
9692 RevertToPointerRoot, CurrentTime);
9693#endif /* ! 0 */
9694}
9695
9696/* Raise frame F. */
9697
9698void
9699x_raise_frame (f)
9700 struct frame *f;
9701{
9702 if (f->async_visible)
9703 SelectWindow (FRAME_MAC_WINDOW (f));
9704}
9705
9706/* Lower frame F. */
9707
9708void
9709x_lower_frame (f)
9710 struct frame *f;
9711{
9712 if (f->async_visible)
9713 SendBehind (FRAME_MAC_WINDOW (f), nil);
9714}
9715
9716void
9717XTframe_raise_lower (f, raise_flag)
9718 FRAME_PTR f;
9719 int raise_flag;
9720{
9721 if (raise_flag)
9722 x_raise_frame (f);
9723 else
9724 x_lower_frame (f);
9725}
9726
9727/* Change of visibility. */
9728
9729/* This tries to wait until the frame is really visible.
9730 However, if the window manager asks the user where to position
9731 the frame, this will return before the user finishes doing that.
9732 The frame will not actually be visible at that time,
9733 but it will become visible later when the window manager
9734 finishes with it. */
9735
9736void
9737x_make_frame_visible (f)
9738 struct frame *f;
9739{
9740 Lisp_Object type;
9741 int original_top, original_left;
9742
9743 BLOCK_INPUT;
9744
9745 if (! FRAME_VISIBLE_P (f))
9746 {
9747 /* We test FRAME_GARBAGED_P here to make sure we don't
9748 call x_set_offset a second time
9749 if we get to x_make_frame_visible a second time
9750 before the window gets really visible. */
9751 if (! FRAME_ICONIFIED_P (f)
9752 && ! f->output_data.mac->asked_for_visible)
9753 x_set_offset (f, f->output_data.mac->left_pos,
9754 f->output_data.mac->top_pos, 0);
9755
9756 f->output_data.mac->asked_for_visible = 1;
9757
9758 ShowWindow (FRAME_MAC_WINDOW (f));
9759 }
9760
9761 XFlush (FRAME_MAC_DISPLAY (f));
9762
9763 /* Synchronize to ensure Emacs knows the frame is visible
9764 before we do anything else. We do this loop with input not blocked
9765 so that incoming events are handled. */
9766 {
9767 Lisp_Object frame;
9768 int count;
9769
9770 /* This must come after we set COUNT. */
9771 UNBLOCK_INPUT;
9772
9773 XSETFRAME (frame, f);
9774
9775 /* Wait until the frame is visible. Process X events until a
9776 MapNotify event has been seen, or until we think we won't get a
9777 MapNotify at all.. */
9778 for (count = input_signal_count + 10;
9779 input_signal_count < count && !FRAME_VISIBLE_P (f);)
9780 {
9781 /* Force processing of queued events. */
9782 x_sync (f);
9783
9784 /* Machines that do polling rather than SIGIO have been
9785 observed to go into a busy-wait here. So we'll fake an
9786 alarm signal to let the handler know that there's something
9787 to be read. We used to raise a real alarm, but it seems
9788 that the handler isn't always enabled here. This is
9789 probably a bug. */
9790 if (input_polling_used ())
9791 {
9792 /* It could be confusing if a real alarm arrives while
9793 processing the fake one. Turn it off and let the
9794 handler reset it. */
9795 extern void poll_for_input_1 P_ ((void));
9796 int old_poll_suppress_count = poll_suppress_count;
9797 poll_suppress_count = 1;
9798 poll_for_input_1 ();
9799 poll_suppress_count = old_poll_suppress_count;
9800 }
9801
9802 /* See if a MapNotify event has been processed. */
9803 FRAME_SAMPLE_VISIBILITY (f);
9804 }
9805 }
9806}
9807
9808/* Change from mapped state to withdrawn state. */
9809
9810/* Make the frame visible (mapped and not iconified). */
9811
9812void
9813x_make_frame_invisible (f)
9814 struct frame *f;
9815{
9816 /* Don't keep the highlight on an invisible frame. */
9817 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
9818 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
9819
9820 BLOCK_INPUT;
9821
9822 HideWindow (FRAME_MAC_WINDOW (f));
9823
9824 /* We can't distinguish this from iconification
9825 just by the event that we get from the server.
9826 So we can't win using the usual strategy of letting
9827 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
9828 and synchronize with the server to make sure we agree. */
9829 f->visible = 0;
9830 FRAME_ICONIFIED_P (f) = 0;
9831 f->async_visible = 0;
9832 f->async_iconified = 0;
9833
9834 UNBLOCK_INPUT;
9835}
9836
9837/* Change window state from mapped to iconified. */
9838
9839void
9840x_iconify_frame (f)
9841 struct frame *f;
9842{
9843#if 0 /* MAC_TODO: really no iconify on Mac */
9844 int result;
9845 Lisp_Object type;
9846
9847 /* Don't keep the highlight on an invisible frame. */
9848 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
9849 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9850
9851 if (f->async_iconified)
9852 return;
9853
9854 BLOCK_INPUT;
9855
9856 FRAME_SAMPLE_VISIBILITY (f);
9857
9858 type = x_icon_type (f);
9859 if (!NILP (type))
9860 x_bitmap_icon (f, type);
9861
9862#ifdef USE_X_TOOLKIT
9863
9864 if (! FRAME_VISIBLE_P (f))
9865 {
9866 if (! EQ (Vx_no_window_manager, Qt))
9867 x_wm_set_window_state (f, IconicState);
9868 /* This was XtPopup, but that did nothing for an iconified frame. */
9869 XtMapWidget (f->output_data.x->widget);
9870 /* The server won't give us any event to indicate
9871 that an invisible frame was changed to an icon,
9872 so we have to record it here. */
9873 f->iconified = 1;
9874 f->visible = 1;
9875 f->async_iconified = 1;
9876 f->async_visible = 0;
9877 UNBLOCK_INPUT;
9878 return;
9879 }
9880
9881 result = XIconifyWindow (FRAME_X_DISPLAY (f),
9882 XtWindow (f->output_data.x->widget),
9883 DefaultScreen (FRAME_X_DISPLAY (f)));
9884 UNBLOCK_INPUT;
9885
9886 if (!result)
9887 error ("Can't notify window manager of iconification");
9888
9889 f->async_iconified = 1;
9890 f->async_visible = 0;
9891
9892
9893 BLOCK_INPUT;
9894 XFlush (FRAME_X_DISPLAY (f));
9895 UNBLOCK_INPUT;
9896#else /* not USE_X_TOOLKIT */
9897
9898 /* Make sure the X server knows where the window should be positioned,
9899 in case the user deiconifies with the window manager. */
9900 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
9901 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
9902
9903 /* Since we don't know which revision of X we're running, we'll use both
9904 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
9905
9906 /* X11R4: send a ClientMessage to the window manager using the
9907 WM_CHANGE_STATE type. */
9908 {
9909 XEvent message;
9910
9911 message.xclient.window = FRAME_X_WINDOW (f);
9912 message.xclient.type = ClientMessage;
9913 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
9914 message.xclient.format = 32;
9915 message.xclient.data.l[0] = IconicState;
9916
9917 if (! XSendEvent (FRAME_X_DISPLAY (f),
9918 DefaultRootWindow (FRAME_X_DISPLAY (f)),
9919 False,
9920 SubstructureRedirectMask | SubstructureNotifyMask,
9921 &message))
9922 {
9923 UNBLOCK_INPUT_RESIGNAL;
9924 error ("Can't notify window manager of iconification");
9925 }
9926 }
9927
9928 /* X11R3: set the initial_state field of the window manager hints to
9929 IconicState. */
9930 x_wm_set_window_state (f, IconicState);
9931
9932 if (!FRAME_VISIBLE_P (f))
9933 {
9934 /* If the frame was withdrawn, before, we must map it. */
9935 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
9936 }
9937
9938 f->async_iconified = 1;
9939 f->async_visible = 0;
9940
9941 XFlush (FRAME_X_DISPLAY (f));
9942 UNBLOCK_INPUT;
9943#endif /* not USE_X_TOOLKIT */
9944#endif
9945}
9946
9947/* Destroy the X window of frame F. */
9948
9949void
9950x_destroy_window (f)
9951 struct frame *f;
9952{
9953 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9954
9955 BLOCK_INPUT;
9956
9957 DisposeWindow (FRAME_MAC_WINDOW (f));
9958
9959 free_frame_menubar (f);
9960 free_frame_faces (f);
9961
9962 xfree (f->output_data.mac);
9963 f->output_data.mac = 0;
9964 if (f == dpyinfo->x_focus_frame)
9965 dpyinfo->x_focus_frame = 0;
9966 if (f == dpyinfo->x_focus_event_frame)
9967 dpyinfo->x_focus_event_frame = 0;
9968 if (f == dpyinfo->x_highlight_frame)
9969 dpyinfo->x_highlight_frame = 0;
9970
9971 dpyinfo->reference_count--;
9972
9973 if (f == dpyinfo->mouse_face_mouse_frame)
9974 {
9975 dpyinfo->mouse_face_beg_row
9976 = dpyinfo->mouse_face_beg_col = -1;
9977 dpyinfo->mouse_face_end_row
9978 = dpyinfo->mouse_face_end_col = -1;
9979 dpyinfo->mouse_face_window = Qnil;
9980 dpyinfo->mouse_face_deferred_gc = 0;
9981 dpyinfo->mouse_face_mouse_frame = 0;
9982 }
9983
9984 UNBLOCK_INPUT;
9985}
9986
9987/* Setting window manager hints. */
9988
9989/* Set the normal size hints for the window manager, for frame F.
9990 FLAGS is the flags word to use--or 0 meaning preserve the flags
9991 that the window now has.
9992 If USER_POSITION is nonzero, we set the USPosition
9993 flag (this is useful when FLAGS is 0). */
9994
9995void
9996x_wm_set_size_hint (f, flags, user_position)
9997 struct frame *f;
9998 long flags;
9999 int user_position;
10000{
10001#if 0 /* MAC_TODO: connect this to the Appearance Manager */
10002 XSizeHints size_hints;
10003
10004#ifdef USE_X_TOOLKIT
10005 Arg al[2];
10006 int ac = 0;
10007 Dimension widget_width, widget_height;
10008 Window window = XtWindow (f->output_data.x->widget);
10009#else /* not USE_X_TOOLKIT */
10010 Window window = FRAME_X_WINDOW (f);
10011#endif /* not USE_X_TOOLKIT */
10012
10013 /* Setting PMaxSize caused various problems. */
10014 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
10015
10016 size_hints.x = f->output_data.x->left_pos;
10017 size_hints.y = f->output_data.x->top_pos;
10018
10019#ifdef USE_X_TOOLKIT
10020 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
10021 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
10022 XtGetValues (f->output_data.x->widget, al, ac);
10023 size_hints.height = widget_height;
10024 size_hints.width = widget_width;
10025#else /* not USE_X_TOOLKIT */
10026 size_hints.height = PIXEL_HEIGHT (f);
10027 size_hints.width = PIXEL_WIDTH (f);
10028#endif /* not USE_X_TOOLKIT */
10029
10030 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
10031 size_hints.height_inc = f->output_data.x->line_height;
10032 size_hints.max_width
10033 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
10034 size_hints.max_height
10035 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
10036
10037 /* Calculate the base and minimum sizes.
10038
10039 (When we use the X toolkit, we don't do it here.
10040 Instead we copy the values that the widgets are using, below.) */
10041#ifndef USE_X_TOOLKIT
10042 {
10043 int base_width, base_height;
10044 int min_rows = 0, min_cols = 0;
10045
10046 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
10047 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
10048
10049 check_frame_size (f, &min_rows, &min_cols);
10050
10051 /* The window manager uses the base width hints to calculate the
10052 current number of rows and columns in the frame while
10053 resizing; min_width and min_height aren't useful for this
10054 purpose, since they might not give the dimensions for a
10055 zero-row, zero-column frame.
10056
10057 We use the base_width and base_height members if we have
10058 them; otherwise, we set the min_width and min_height members
10059 to the size for a zero x zero frame. */
10060
10061#ifdef HAVE_X11R4
10062 size_hints.flags |= PBaseSize;
10063 size_hints.base_width = base_width;
10064 size_hints.base_height = base_height;
10065 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
10066 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
10067#else
10068 size_hints.min_width = base_width;
10069 size_hints.min_height = base_height;
10070#endif
10071 }
10072
10073 /* If we don't need the old flags, we don't need the old hint at all. */
10074 if (flags)
10075 {
10076 size_hints.flags |= flags;
10077 goto no_read;
10078 }
10079#endif /* not USE_X_TOOLKIT */
10080
10081 {
10082 XSizeHints hints; /* Sometimes I hate X Windows... */
10083 long supplied_return;
10084 int value;
10085
10086#ifdef HAVE_X11R4
10087 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
10088 &supplied_return);
10089#else
10090 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
10091#endif
10092
10093#ifdef USE_X_TOOLKIT
10094 size_hints.base_height = hints.base_height;
10095 size_hints.base_width = hints.base_width;
10096 size_hints.min_height = hints.min_height;
10097 size_hints.min_width = hints.min_width;
10098#endif
10099
10100 if (flags)
10101 size_hints.flags |= flags;
10102 else
10103 {
10104 if (value == 0)
10105 hints.flags = 0;
10106 if (hints.flags & PSize)
10107 size_hints.flags |= PSize;
10108 if (hints.flags & PPosition)
10109 size_hints.flags |= PPosition;
10110 if (hints.flags & USPosition)
10111 size_hints.flags |= USPosition;
10112 if (hints.flags & USSize)
10113 size_hints.flags |= USSize;
10114 }
10115 }
10116
10117#ifndef USE_X_TOOLKIT
10118 no_read:
10119#endif
10120
10121#ifdef PWinGravity
10122 size_hints.win_gravity = f->output_data.x->win_gravity;
10123 size_hints.flags |= PWinGravity;
10124
10125 if (user_position)
10126 {
10127 size_hints.flags &= ~ PPosition;
10128 size_hints.flags |= USPosition;
10129 }
10130#endif /* PWinGravity */
10131
10132#ifdef HAVE_X11R4
10133 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
10134#else
10135 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
10136#endif
10137#endif /* MACTODO */
10138}
10139
10140#if 0 /* MACTODO: hide application instead of iconify? */
10141/* Used for IconicState or NormalState */
10142
10143void
10144x_wm_set_window_state (f, state)
10145 struct frame *f;
10146 int state;
10147{
10148#ifdef USE_X_TOOLKIT
10149 Arg al[1];
10150
10151 XtSetArg (al[0], XtNinitialState, state);
10152 XtSetValues (f->output_data.x->widget, al, 1);
10153#else /* not USE_X_TOOLKIT */
10154 Window window = FRAME_X_WINDOW (f);
10155
10156 f->output_data.x->wm_hints.flags |= StateHint;
10157 f->output_data.x->wm_hints.initial_state = state;
10158
10159 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
10160#endif /* not USE_X_TOOLKIT */
10161}
10162
10163void
10164x_wm_set_icon_pixmap (f, pixmap_id)
10165 struct frame *f;
10166 int pixmap_id;
10167{
10168 Pixmap icon_pixmap;
10169
10170#ifndef USE_X_TOOLKIT
10171 Window window = FRAME_X_WINDOW (f);
10172#endif
10173
10174 if (pixmap_id > 0)
10175 {
10176 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
10177 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
10178 }
10179 else
10180 {
10181 /* It seems there is no way to turn off use of an icon pixmap.
10182 The following line does it, only if no icon has yet been created,
10183 for some window managers. But with mwm it crashes.
10184 Some people say it should clear the IconPixmapHint bit in this case,
10185 but that doesn't work, and the X consortium said it isn't the
10186 right thing at all. Since there is no way to win,
10187 best to explicitly give up. */
10188#if 0
10189 f->output_data.x->wm_hints.icon_pixmap = None;
10190#else
10191 return;
10192#endif
10193 }
10194
10195#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
10196
10197 {
10198 Arg al[1];
10199 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
10200 XtSetValues (f->output_data.x->widget, al, 1);
10201 }
10202
10203#else /* not USE_X_TOOLKIT */
10204
10205 f->output_data.x->wm_hints.flags |= IconPixmapHint;
10206 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
10207
10208#endif /* not USE_X_TOOLKIT */
10209}
10210
10211#endif
10212
10213void
10214x_wm_set_icon_position (f, icon_x, icon_y)
10215 struct frame *f;
10216 int icon_x, icon_y;
10217{
10218#if 0 /* MAC_TODO: no icons on Mac */
10219#ifdef USE_X_TOOLKIT
10220 Window window = XtWindow (f->output_data.x->widget);
10221#else
10222 Window window = FRAME_X_WINDOW (f);
10223#endif
10224
10225 f->output_data.x->wm_hints.flags |= IconPositionHint;
10226 f->output_data.x->wm_hints.icon_x = icon_x;
10227 f->output_data.x->wm_hints.icon_y = icon_y;
10228
10229 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
10230#endif
10231}
10232
10233
10234/***********************************************************************
10235 Fonts
10236 ***********************************************************************/
10237
10238/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
10239
10240struct font_info *
10241x_get_font_info (f, font_idx)
10242 FRAME_PTR f;
10243 int font_idx;
10244{
10245 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
10246}
10247
10248/* the global font name table */
10249char **font_name_table = NULL;
10250int font_name_table_size = 0;
10251int font_name_count = 0;
10252
10253/* compare two strings ignoring case */
10254static int
10255stricmp (const char *s, const char *t)
10256{
10257 for ( ; tolower (*s) == tolower (*t); s++, t++)
10258 if (*s == '\0')
10259 return 0;
10260 return tolower (*s) - tolower (*t);
10261}
10262
10263/* compare two strings ignoring case and handling wildcard */
10264static int
10265wildstrieq (char *s1, char *s2)
10266{
10267 if (strcmp (s1, "*") == 0 || strcmp (s2, "*") == 0)
10268 return true;
10269
10270 return stricmp (s1, s2) == 0;
10271}
10272
10273/* Assume parameter 1 is fully qualified, no wildcards. */
10274static int
10275mac_font_pattern_match (fontname, pattern)
10276 char * fontname;
10277 char * pattern;
10278{
10279 char *regex = (char *) alloca (strlen (pattern) * 2 + 3);
10280 char *font_name_copy = (char *) alloca (strlen (fontname) + 1);
10281 char *ptr;
10282
10283 /* Copy fontname so we can modify it during comparison. */
10284 strcpy (font_name_copy, fontname);
10285
10286 ptr = regex;
10287 *ptr++ = '^';
10288
10289 /* Turn pattern into a regexp and do a regexp match. */
10290 for (; *pattern; pattern++)
10291 {
10292 if (*pattern == '?')
10293 *ptr++ = '.';
10294 else if (*pattern == '*')
10295 {
10296 *ptr++ = '.';
10297 *ptr++ = '*';
10298 }
10299 else
10300 *ptr++ = *pattern;
10301 }
10302 *ptr = '$';
10303 *(ptr + 1) = '\0';
10304
10305 return (fast_c_string_match_ignore_case (build_string (regex),
10306 font_name_copy) >= 0);
10307}
10308
10309/* Two font specs are considered to match if their foundry, family,
10310 weight, slant, and charset match. */
10311static int
10312mac_font_match (char *mf, char *xf)
10313{
10314 char m_foundry[50], m_family[50], m_weight[20], m_slant[2], m_charset[20];
10315 char x_foundry[50], x_family[50], x_weight[20], x_slant[2], x_charset[20];
10316
10317 if (sscanf (mf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s",
10318 m_foundry, m_family, m_weight, m_slant, m_charset) != 5)
10319 return mac_font_pattern_match (mf, xf);
10320
10321 if (sscanf (xf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s",
10322 x_foundry, x_family, x_weight, x_slant, x_charset) != 5)
10323 return mac_font_pattern_match (mf, xf);
10324
10325 return (wildstrieq (m_foundry, x_foundry)
10326 && wildstrieq (m_family, x_family)
10327 && wildstrieq (m_weight, x_weight)
10328 && wildstrieq (m_slant, x_slant)
10329 && wildstrieq (m_charset, x_charset))
10330 || mac_font_pattern_match (mf, xf);
10331}
10332
10333
10334static char *
10335mac_to_x_fontname (char *name, int size, Style style, short scriptcode)
10336{
10337 char foundry[32], family[32], cs[32];
10338 char xf[255], *result, *p;
10339
10340 if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3)
10341 {
10342 strcpy(foundry, "Apple");
10343 strcpy(family, name);
10344
10345 switch (scriptcode)
10346 {
10347 case smTradChinese:
10348 strcpy(cs, "big5-0");
10349 break;
10350 case smSimpChinese:
10351 strcpy(cs, "gb2312.1980-0");
10352 break;
10353 case smJapanese:
10354 strcpy(cs, "jisx0208.1983-sjis");
10355 break;
10356 case -smJapanese:
10357 /* Each Apple Japanese font is entered into the font table
10358 twice: once as a jisx0208.1983-sjis font and once as a
10359 jisx0201.1976-0 font. The latter can be used to display
10360 the ascii charset and katakana-jisx0201 charset. A
10361 negative script code signals that the name of this latter
10362 font is being built. */
10363 strcpy(cs, "jisx0201.1976-0");
10364 break;
10365 case smKorean:
10366 strcpy(cs, "ksc5601.1989-0");
10367 break;
10368 default:
10369 strcpy(cs, "mac-roman");
10370 break;
10371 }
10372 }
10373
10374 sprintf(xf, "-%s-%s-%s-%c-normal--%d-%d-75-75-m-%d-%s",
10375 foundry, family, style & bold ? "bold" : "medium",
10376 style & italic ? 'i' : 'r', size, size * 10, size * 10, cs);
10377
10378 result = (char *) xmalloc (strlen (xf) + 1);
10379 strcpy (result, xf);
10380 for (p = result; *p; p++)
10381 *p = tolower(*p);
10382 return result;
10383}
10384
10385
10386/* Convert an X font spec to the corresponding mac font name, which
10387 can then be passed to GetFNum after conversion to a Pascal string.
10388 For ordinary Mac fonts, this should just be their names, like
10389 "monaco", "Taipei", etc. Fonts converted from the GNU intlfonts
10390 collection contain their charset designation in their names, like
10391 "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both types of font
10392 names are handled accordingly. */
10393static void
10394x_font_name_to_mac_font_name (char *xf, char *mf)
10395{
10396 char foundry[32], family[32], weight[20], slant[2], cs[32];
10397
10398 strcpy (mf, "");
10399
10400 if (sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
10401 foundry, family, weight, slant, cs) != 5 &&
10402 sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
10403 foundry, family, weight, slant, cs) != 5)
10404 return;
10405
10406 if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312.1980-0") == 0
10407 || strcmp (cs, "jisx0208.1983-sjis") == 0
10408 || strcmp (cs, "jisx0201.1976-0") == 0
10409 || strcmp (cs, "ksc5601.1989-0") == 0 || strcmp (cs, "mac-roman") == 0)
10410 strcpy(mf, family);
10411 else
10412 sprintf(mf, "%s-%s-%s", foundry, family, cs);
10413}
10414
10415
10416/* Sets up the table font_name_table to contain the list of all
10417 monospace fonts in the system the first time the table is used so
10418 that the Resource Manager need not be accessed every time this
10419 information is needed. */
10420
10421static void
10422init_font_name_table ()
10423{
10424 GrafPtr port;
10425 SInt16 fontnum, old_fontnum;
10426 int num_mac_fonts = CountResources('FOND');
10427 int i, j;
10428 Handle font_handle, font_handle_2;
10429 short id, scriptcode;
10430 ResType type;
10431 Str32 name;
10432 struct FontAssoc *fat;
10433 struct AsscEntry *assc_entry;
10434
10435 GetPort (&port); /* save the current font number used */
10436 old_fontnum = port->txFont;
10437
10438 for (i = 1; i <= num_mac_fonts; i++) /* loop to get all available fonts */
10439 {
10440 font_handle = GetIndResource ('FOND', i);
10441 if (!font_handle)
10442 continue;
10443
10444 GetResInfo (font_handle, &id, &type, name);
10445 GetFNum (name, &fontnum);
10446 p2cstr (name);
10447 if (fontnum == 0)
10448 continue;
10449
10450 TextFont (fontnum);
10451 scriptcode = FontToScript (fontnum);
10452 do
10453 {
10454 HLock (font_handle);
10455
10456 if (GetResourceSizeOnDisk (font_handle) >= sizeof (struct FamRec))
10457 {
10458 fat = (struct FontAssoc *) (*font_handle
10459 + sizeof (struct FamRec));
10460 assc_entry = (struct AsscEntry *) (*font_handle
10461 + sizeof (struct FamRec)
10462 + sizeof (struct FontAssoc));
10463
10464 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
10465 {
10466 if (font_name_table_size == 0)
10467 {
10468 font_name_table_size = 16;
10469 font_name_table = (char **)
10470 xmalloc (font_name_table_size * sizeof (char *));
10471 }
10472 else if (font_name_count >= font_name_table_size ||
10473 /* fonts in Japanese scripts require two
10474 entries. */
10475 scriptcode == smJapanese &&
10476 font_name_count + 1 >= font_name_table_size)
10477 {
10478 font_name_table_size += 16;
10479 font_name_table = (char **)
10480 xrealloc (font_name_table,
10481 font_name_table_size * sizeof (char *));
10482 }
10483 font_name_table[font_name_count++]
10484 = mac_to_x_fontname (name,
10485 assc_entry->fontSize,
10486 assc_entry->fontStyle,
10487 scriptcode);
10488 /* Both jisx0208.1983-sjis and jisx0201.1976-0 parts
10489 are contained in Apple Japanese (SJIS) font. */
10490 if (smJapanese == scriptcode)
10491 {
10492 font_name_table[font_name_count++]
10493 = mac_to_x_fontname (name,
10494 assc_entry->fontSize,
10495 assc_entry->fontStyle,
10496 -smJapanese);
10497 }
10498 }
10499 }
10500
10501 HUnlock (font_handle);
10502 font_handle_2 = GetNextFOND (font_handle);
10503 ReleaseResource (font_handle);
10504 font_handle = font_handle_2;
10505 }
10506 while (ResError () == noErr && font_handle);
10507 }
10508
10509 TextFont (old_fontnum);
10510}
10511
10512
10513/* Return a list of at most MAXNAMES font specs matching the one in
10514 PATTERN. Note that each '*' in the PATTERN matches exactly one
10515 field of the font spec, unlike X in which an '*' in a font spec can
10516 match a number of fields. The result is in the Mac implementation
10517 all fonts must be specified by a font spec with all 13 fields
10518 (although many of these can be "*'s"). */
10519
10520Lisp_Object
10521x_list_fonts (struct frame *f,
10522 Lisp_Object pattern,
10523 int size,
10524 int maxnames)
10525{
10526 char *ptnstr;
10527 Lisp_Object newlist = Qnil;
10528 int n_fonts = 0;
10529 int i;
10530 struct gcpro gcpro1, gcpro2;
10531
10532 if (font_name_table == NULL) /* Initialize when first used. */
10533 init_font_name_table ();
10534
10535 ptnstr = XSTRING (pattern)->data;
10536
10537 GCPRO2 (pattern, newlist);
10538
10539 /* Scan and matching bitmap fonts. */
10540 for (i = 0; i < font_name_count; i++)
10541 {
10542 if (mac_font_pattern_match (font_name_table[i], ptnstr))
10543 {
10544 newlist = Fcons (build_string (font_name_table[i]), newlist);
10545
10546 n_fonts++;
10547 if (n_fonts >= maxnames)
10548 break;
10549 }
10550 }
10551
10552 /* MAC_TODO: add code for matching outline fonts here */
10553
10554 UNGCPRO;
10555
10556 return newlist;
10557}
10558
10559
10560#if GLYPH_DEBUG
10561
10562/* Check that FONT is valid on frame F. It is if it can be found in
10563 F's font table. */
10564
10565static void
10566x_check_font (f, font)
10567 struct frame *f;
10568 XFontStruct *font;
10569{
10570 int i;
10571 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10572
10573 xassert (font != NULL);
10574
10575 for (i = 0; i < dpyinfo->n_fonts; i++)
10576 if (dpyinfo->font_table[i].name
10577 && font == dpyinfo->font_table[i].font)
10578 break;
10579
10580 xassert (i < dpyinfo->n_fonts);
10581}
10582
10583#endif /* GLYPH_DEBUG != 0 */
10584
10585
10586/* Set *W to the minimum width, *H to the minimum font height of FONT.
10587 Note: There are (broken) X fonts out there with invalid XFontStruct
10588 min_bounds contents. For example, handa@etl.go.jp reports that
10589 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
10590 have font->min_bounds.width == 0. */
10591
10592static INLINE void
10593x_font_min_bounds (font, w, h)
10594 MacFontStruct *font;
10595 int *w, *h;
10596{
10597 *h = FONT_HEIGHT (font);
10598 *w = font->min_bounds.width;
10599
10600 /* Try to handle the case where FONT->min_bounds has invalid
10601 contents. Since the only font known to have invalid min_bounds
10602 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
10603 if (*w <= 0)
10604 *w = font->max_bounds.width;
10605}
10606
10607
10608/* Compute the smallest character width and smallest font height over
10609 all fonts available on frame F. Set the members smallest_char_width
10610 and smallest_font_height in F's x_display_info structure to
10611 the values computed. Value is non-zero if smallest_font_height or
10612 smallest_char_width become smaller than they were before. */
10613
10614static int
10615x_compute_min_glyph_bounds (f)
10616 struct frame *f;
10617{
10618 int i;
10619 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10620 MacFontStruct *font;
10621 int old_width = dpyinfo->smallest_char_width;
10622 int old_height = dpyinfo->smallest_font_height;
10623
10624 dpyinfo->smallest_font_height = 100000;
10625 dpyinfo->smallest_char_width = 100000;
10626
10627 for (i = 0; i < dpyinfo->n_fonts; ++i)
10628 if (dpyinfo->font_table[i].name)
10629 {
10630 struct font_info *fontp = dpyinfo->font_table + i;
10631 int w, h;
10632
10633 font = (MacFontStruct *) fontp->font;
10634 xassert (font != (MacFontStruct *) ~0);
10635 x_font_min_bounds (font, &w, &h);
10636
10637 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
10638 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
10639 }
10640
10641 xassert (dpyinfo->smallest_char_width > 0
10642 && dpyinfo->smallest_font_height > 0);
10643
10644 return (dpyinfo->n_fonts == 1
10645 || dpyinfo->smallest_char_width < old_width
10646 || dpyinfo->smallest_font_height < old_height);
10647}
10648
10649
10650/* Determine whether given string is a fully-specified XLFD: all 14
10651 fields are present, none is '*'. */
10652
10653static int
10654is_fully_specified_xlfd (char *p)
10655{
10656 int i;
10657 char *q;
10658
10659 if (*p != '-')
10660 return 0;
10661
10662 for (i = 0; i < 13; i++)
10663 {
10664 q = strchr (p + 1, '-');
10665 if (q == NULL)
10666 return 0;
10667 if (q - p == 2 && *(p + 1) == '*')
10668 return 0;
10669 p = q;
10670 }
10671
10672 if (strchr (p + 1, '-') != NULL)
10673 return 0;
10674
10675 if (*(p + 1) == '*' && *(p + 2) == '\0')
10676 return 0;
10677
10678 return 1;
10679}
10680
10681
10682const int kDefaultFontSize = 9;
10683
10684
10685/* MacLoadQueryFont creates and returns an internal representation for
10686 a font in a MacFontStruct struct (similar in function to
10687 XLoadQueryFont in X). There is really no concept corresponding to
10688 "loading" a font on the Mac. But we check its existence and find
10689 the font number and all other information for it and store them in
10690 the returned MacFontStruct. */
10691
10692static MacFontStruct *
10693XLoadQueryFont (Display *dpy, char *fontname)
10694{
10695 int i, size, is_two_byte_font, char_width;
10696 char *name;
10697 GrafPtr port;
10698 SInt16 old_fontnum, old_fontsize;
10699 Style old_fontface;
10700 Str32 mfontname;
10701 SInt16 fontnum;
10702 Style fontface = normal;
10703 MacFontStruct *font;
10704 FontInfo the_fontinfo;
10705 char s_weight[7], c_slant;
10706
10707 if (is_fully_specified_xlfd (fontname))
10708 name = fontname;
10709 else
10710 {
10711 for (i = 0; i < font_name_count; i++)
10712 if (mac_font_pattern_match (font_name_table[i], fontname))
10713 break;
10714
10715 if (i >= font_name_count)
10716 return NULL;
10717
10718 name = font_name_table[i];
10719 }
10720
10721 GetPort (&port); /* save the current font number used */
10722 old_fontnum = port->txFont;
10723 old_fontsize = port->txSize;
10724 old_fontface = port->txFace;
10725
10726 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%d-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &size) != 1)
10727 size = kDefaultFontSize;
10728
10729 if (sscanf (name, "-%*[^-]-%*[^-]-%6[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", s_weight) == 1)
10730 if (strcmp (s_weight, "bold") == 0)
10731 fontface |= bold;
10732
10733 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &c_slant) == 1)
10734 if (c_slant == 'i')
10735 fontface |= italic;
10736
10737 x_font_name_to_mac_font_name (name, mfontname);
10738 c2pstr (mfontname);
10739 GetFNum (mfontname, &fontnum);
10740 if (fontnum == 0)
10741 return NULL;
10742
10743 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
10744
10745 font->fontname = (char *) xmalloc (strlen (name) + 1);
10746 bcopy (name, font->fontname, strlen (name) + 1);
10747
10748 font->mac_fontnum = fontnum;
10749 font->mac_fontsize = size;
10750 font->mac_fontface = fontface;
10751 font->mac_scriptcode = FontToScript (fontnum);
10752
10753 /* Apple Japanese (SJIS) font is listed as both
10754 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0"
10755 (Roman script) in init_font_name_table(). The latter should be
10756 treated as a one-byte font. */
10757 {
10758 char cs[32];
10759
10760 if (sscanf (name,
10761 "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
10762 cs) == 1
10763 && 0 == strcmp (cs, "jisx0201.1976-0"))
10764 font->mac_scriptcode = smRoman;
10765 }
10766
10767 is_two_byte_font = font->mac_scriptcode == smJapanese ||
10768 font->mac_scriptcode == smTradChinese ||
10769 font->mac_scriptcode == smSimpChinese ||
10770 font->mac_scriptcode == smKorean;
10771
10772 TextFont (fontnum);
10773 TextSize (size);
10774 TextFace (fontface);
10775
10776 GetFontInfo (&the_fontinfo);
10777
10778 font->ascent = the_fontinfo.ascent;
10779 font->descent = the_fontinfo.descent;
10780
10781 font->min_byte1 = 0;
10782 if (is_two_byte_font)
10783 font->max_byte1 = 1;
10784 else
10785 font->max_byte1 = 0;
10786 font->min_char_or_byte2 = 0x20;
10787 font->max_char_or_byte2 = 0xff;
10788
10789 if (is_two_byte_font)
10790 {
10791 /* Use the width of an "ideographic space" of that font because
10792 the_fontinfo.widMax returns the wrong width for some fonts. */
10793 switch (font->mac_scriptcode)
10794 {
10795 case smJapanese:
10796 char_width = StringWidth("\p\x81\x40");
10797 break;
10798 case smTradChinese:
10799 char_width = StringWidth("\p\xa1\x40");
10800 break;
10801 case smSimpChinese:
10802 char_width = StringWidth("\p\xa1\xa1");
10803 break;
10804 case smKorean:
10805 char_width = StringWidth("\p\xa1\xa1");
10806 break;
10807 }
10808 }
10809 else
10810 /* Do this instead of use the_fontinfo.widMax, which incorrectly
10811 returns 15 for 12-point Monaco! */
10812 char_width = CharWidth ('m');
10813
10814 font->max_bounds.rbearing = char_width;
10815 font->max_bounds.lbearing = 0;
10816 font->max_bounds.width = char_width;
10817 font->max_bounds.ascent = the_fontinfo.ascent;
10818 font->max_bounds.descent = the_fontinfo.descent;
10819
10820 font->min_bounds = font->max_bounds;
10821
10822 if (is_two_byte_font || CharWidth ('m') == CharWidth ('i'))
10823 font->per_char = NULL;
10824 else
10825 {
10826 font->per_char = (XCharStruct *)
10827 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
10828 {
10829 int c;
10830
10831 for (c = 0x20; c <= 0xff; c++)
10832 {
10833 font->per_char[c - 0x20] = font->max_bounds;
10834 font->per_char[c - 0x20].width = CharWidth (c);
10835 }
10836 }
10837 }
10838
10839 TextFont (old_fontnum); /* restore previous font number, size and face */
10840 TextSize (old_fontsize);
10841 TextFace (old_fontface);
10842
10843 return font;
10844}
10845
10846
10847/* Load font named FONTNAME of the size SIZE for frame F, and return a
10848 pointer to the structure font_info while allocating it dynamically.
10849 If SIZE is 0, load any size of font.
10850 If loading is failed, return NULL. */
10851
10852struct font_info *
10853x_load_font (f, fontname, size)
10854 struct frame *f;
10855 register char *fontname;
10856 int size;
10857{
10858 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10859 Lisp_Object font_names;
10860
10861 /* Get a list of all the fonts that match this name. Once we
10862 have a list of matching fonts, we compare them against the fonts
10863 we already have by comparing names. */
10864 font_names = x_list_fonts (f, build_string (fontname), size, 1);
10865
10866 if (!NILP (font_names))
10867 {
10868 Lisp_Object tail;
10869 int i;
10870
10871 for (i = 0; i < dpyinfo->n_fonts; i++)
10872 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
10873 if (dpyinfo->font_table[i].name
10874 && (!strcmp (dpyinfo->font_table[i].name,
10875 XSTRING (XCAR (tail))->data)
10876 || !strcmp (dpyinfo->font_table[i].full_name,
10877 XSTRING (XCAR (tail))->data)))
10878 return (dpyinfo->font_table + i);
10879 }
10880
10881 /* Load the font and add it to the table. */
10882 {
10883 char *full_name;
10884 struct MacFontStruct *font;
10885 struct font_info *fontp;
10886 unsigned long value;
10887 int i;
10888
10889 /* If we have found fonts by x_list_font, load one of them. If
10890 not, we still try to load a font by the name given as FONTNAME
10891 because XListFonts (called in x_list_font) of some X server has
10892 a bug of not finding a font even if the font surely exists and
10893 is loadable by XLoadQueryFont. */
10894 if (size > 0 && !NILP (font_names))
10895 fontname = (char *) XSTRING (XCAR (font_names))->data;
10896
10897 font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname);
10898 if (!font)
10899 return NULL;
10900
10901 /* Find a free slot in the font table. */
10902 for (i = 0; i < dpyinfo->n_fonts; ++i)
10903 if (dpyinfo->font_table[i].name == NULL)
10904 break;
10905
10906 /* If no free slot found, maybe enlarge the font table. */
10907 if (i == dpyinfo->n_fonts
10908 && dpyinfo->n_fonts == dpyinfo->font_table_size)
10909 {
10910 int sz;
10911 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
10912 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
10913 dpyinfo->font_table
10914 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
10915 }
10916
10917 fontp = dpyinfo->font_table + i;
10918 if (i == dpyinfo->n_fonts)
10919 ++dpyinfo->n_fonts;
10920
10921 /* Now fill in the slots of *FONTP. */
10922 BLOCK_INPUT;
10923 fontp->font = font;
10924 fontp->font_idx = i;
10925 fontp->name = (char *) xmalloc (strlen (font->fontname) + 1);
10926 bcopy (font->fontname, fontp->name, strlen (font->fontname) + 1);
10927
10928 fontp->full_name = fontp->name;
10929
10930 fontp->size = font->max_bounds.width;
10931 fontp->height = FONT_HEIGHT (font);
10932 {
10933 /* For some font, ascent and descent in max_bounds field is
10934 larger than the above value. */
10935 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
10936 if (max_height > fontp->height)
10937 fontp->height = max_height;
10938 }
10939
10940 /* The slot `encoding' specifies how to map a character
10941 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
10942 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
10943 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
10944 2:0xA020..0xFF7F). For the moment, we don't know which charset
10945 uses this font. So, we set information in fontp->encoding[1]
10946 which is never used by any charset. If mapping can't be
10947 decided, set FONT_ENCODING_NOT_DECIDED. */
10948 if (font->mac_scriptcode == smJapanese)
10949 fontp->encoding[1] = 4;
10950 else
10951 {
10952 fontp->encoding[1]
10953 = (font->max_byte1 == 0
10954 /* 1-byte font */
10955 ? (font->min_char_or_byte2 < 0x80
10956 ? (font->max_char_or_byte2 < 0x80
10957 ? 0 /* 0x20..0x7F */
10958 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
10959 : 1) /* 0xA0..0xFF */
10960 /* 2-byte font */
10961 : (font->min_byte1 < 0x80
10962 ? (font->max_byte1 < 0x80
10963 ? (font->min_char_or_byte2 < 0x80
10964 ? (font->max_char_or_byte2 < 0x80
10965 ? 0 /* 0x2020..0x7F7F */
10966 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
10967 : 3) /* 0x20A0..0x7FFF */
10968 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
10969 : (font->min_char_or_byte2 < 0x80
10970 ? (font->max_char_or_byte2 < 0x80
10971 ? 2 /* 0xA020..0xFF7F */
10972 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
10973 : 1))); /* 0xA0A0..0xFFFF */
10974 }
10975
10976#if 0 /* MAC_TODO: fill these out with more reasonably values */
10977 fontp->baseline_offset
10978 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
10979 ? (long) value : 0);
10980 fontp->relative_compose
10981 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
10982 ? (long) value : 0);
10983 fontp->default_ascent
10984 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
10985 ? (long) value : 0);
10986#else
10987 fontp->baseline_offset = 0;
10988 fontp->relative_compose = 0;
10989 fontp->default_ascent = 0;
10990#endif
10991
10992 /* Set global flag fonts_changed_p to non-zero if the font loaded
10993 has a character with a smaller width than any other character
10994 before, or if the font loaded has a smalle>r height than any
10995 other font loaded before. If this happens, it will make a
10996 glyph matrix reallocation necessary. */
10997 fonts_changed_p = x_compute_min_glyph_bounds (f);
10998 UNBLOCK_INPUT;
10999 return fontp;
11000 }
11001}
11002
11003
11004/* Return a pointer to struct font_info of a font named FONTNAME for
11005 frame F. If no such font is loaded, return NULL. */
11006
11007struct font_info *
11008x_query_font (f, fontname)
11009 struct frame *f;
11010 register char *fontname;
11011{
11012 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
11013 int i;
11014
11015 for (i = 0; i < dpyinfo->n_fonts; i++)
11016 if (dpyinfo->font_table[i].name
11017 && (!strcmp (dpyinfo->font_table[i].name, fontname)
11018 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
11019 return (dpyinfo->font_table + i);
11020 return NULL;
11021}
11022
11023
11024/* Find a CCL program for a font specified by FONTP, and set the member
11025 `encoder' of the structure. */
11026
11027void
11028x_find_ccl_program (fontp)
11029 struct font_info *fontp;
11030{
11031 Lisp_Object list, elt;
11032
11033 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
11034 {
11035 elt = XCAR (list);
11036 if (CONSP (elt)
11037 && STRINGP (XCAR (elt))
11038 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
11039 >= 0))
11040 break;
11041 }
11042 if (! NILP (list))
11043 {
11044 struct ccl_program *ccl
11045 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
11046
11047 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
11048 xfree (ccl);
11049 else
11050 fontp->font_encoder = ccl;
11051 }
11052}
11053
11054
11055
11056/***********************************************************************
11057 Initialization
11058 ***********************************************************************/
11059
11060#ifdef USE_X_TOOLKIT
11061static XrmOptionDescRec emacs_options[] = {
11062 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
11063 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
11064
11065 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
11066 XrmoptionSepArg, NULL},
11067 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
11068
11069 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11070 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11071 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11072 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
11073 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
11074 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
11075 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
11076};
11077#endif /* USE_X_TOOLKIT */
11078
11079static int x_initialized;
11080
11081#ifdef MULTI_KBOARD
11082/* Test whether two display-name strings agree up to the dot that separates
11083 the screen number from the server number. */
11084static int
11085same_x_server (name1, name2)
11086 char *name1, *name2;
11087{
11088 int seen_colon = 0;
11089 unsigned char *system_name = XSTRING (Vsystem_name)->data;
11090 int system_name_length = strlen (system_name);
11091 int length_until_period = 0;
11092
11093 while (system_name[length_until_period] != 0
11094 && system_name[length_until_period] != '.')
11095 length_until_period++;
11096
11097 /* Treat `unix' like an empty host name. */
11098 if (! strncmp (name1, "unix:", 5))
11099 name1 += 4;
11100 if (! strncmp (name2, "unix:", 5))
11101 name2 += 4;
11102 /* Treat this host's name like an empty host name. */
11103 if (! strncmp (name1, system_name, system_name_length)
11104 && name1[system_name_length] == ':')
11105 name1 += system_name_length;
11106 if (! strncmp (name2, system_name, system_name_length)
11107 && name2[system_name_length] == ':')
11108 name2 += system_name_length;
11109 /* Treat this host's domainless name like an empty host name. */
11110 if (! strncmp (name1, system_name, length_until_period)
11111 && name1[length_until_period] == ':')
11112 name1 += length_until_period;
11113 if (! strncmp (name2, system_name, length_until_period)
11114 && name2[length_until_period] == ':')
11115 name2 += length_until_period;
11116
11117 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
11118 {
11119 if (*name1 == ':')
11120 seen_colon++;
11121 if (seen_colon && *name1 == '.')
11122 return 1;
11123 }
11124 return (seen_colon
11125 && (*name1 == '.' || *name1 == '\0')
11126 && (*name2 == '.' || *name2 == '\0'));
11127}
11128#endif
11129
11130struct mac_display_info *
11131x_term_init (display_name, xrm_option, resource_name)
11132 Lisp_Object display_name;
11133 char *xrm_option;
11134 char *resource_name;
11135{
11136 if (!x_initialized)
11137 {
11138 x_initialize ();
11139 x_initialized = 1;
11140 }
11141
11142 return &one_mac_display_info;
11143}
11144
11145/* Set up use of X before we make the first connection. */
11146
11147static struct redisplay_interface x_redisplay_interface =
11148{
11149 x_produce_glyphs,
11150 x_write_glyphs,
11151 x_insert_glyphs,
11152 x_clear_end_of_line,
11153 x_scroll_run,
11154 x_after_update_window_line,
11155 x_update_window_begin,
11156 x_update_window_end,
11157 XTcursor_to,
11158 x_flush,
11159 x_clear_mouse_face,
11160 x_get_glyph_overhangs,
11161 x_fix_overlapping_area
11162};
11163
11164
11165/* The Mac Event loop code */
11166
11167#include <Events.h>
11168#include <Quickdraw.h>
11169#include <Balloons.h>
11170#include <Devices.h>
11171#include <Fonts.h>
11172#include <Gestalt.h>
11173#include <Menus.h>
11174#include <Processes.h>
11175#include <Sound.h>
11176#include <ToolUtils.h>
11177#include <TextUtils.h>
11178#include <Dialogs.h>
11179#include <Script.h>
11180#include <Scrap.h>
11181#include <Types.h>
11182#include <TextEncodingConverter.h>
11183#include <Resources.h>
11184
11185#if __MWERKS__
11186#include <unix.h>
11187#endif
11188
11189#define M_APPLE 128
11190#define I_ABOUT 1
11191
11192#define WINDOW_RESOURCE 128
11193#define TERM_WINDOW_RESOURCE 129
11194
11195#define DEFAULT_NUM_COLS 80
11196
11197#define MIN_DOC_SIZE 64
11198#define MAX_DOC_SIZE 32767
11199
11200/* sleep time for WaitNextEvent */
11201#define WNE_SLEEP_AT_SUSPEND 10
11202#define WNE_SLEEP_AT_RESUME 1
11203
11204/* true when cannot handle any Mac OS events */
11205static int handling_window_update = 0;
11206
11207/* the flag appl_is_suspended is used both for determining the sleep
11208 time to be passed to WaitNextEvent and whether the cursor should be
11209 drawn when updating the display. The cursor is turned off when
11210 Emacs is suspended. Redrawing it is unnecessary and what needs to
11211 be done depends on whether the cursor lies inside or outside the
11212 redraw region. So we might as well skip drawing it when Emacs is
11213 suspended. */
11214static Boolean app_is_suspended = false;
11215static long app_sleep_time = WNE_SLEEP_AT_RESUME;
11216
11217#define EXTRA_STACK_ALLOC (256 * 1024)
11218
11219#define ARGV_STRING_LIST_ID 129
11220#define ABOUT_ALERT_ID 128
11221#define RAM_TOO_LARGE_ALERT_ID 129
11222
11223Boolean terminate_flag = false;
11224
11225/* true if using command key as meta key */
11226Lisp_Object Vmac_command_key_is_meta;
11227
11228/* convert input from Mac keyboard (assumed to be in Mac Roman coding)
11229 to this text encoding */
11230int mac_keyboard_text_encoding;
11231int current_mac_keyboard_text_encoding = kTextEncodingMacRoman;
11232
11233/* Set in term/mac-win.el to indicate that event loop can now generate
11234 drag and drop events. */
11235Lisp_Object Qmac_ready_for_drag_n_drop;
11236
11237Lisp_Object drag_and_drop_file_list;
11238
11239Point saved_menu_event_location;
11240
11241/* Apple Events */
11242static void init_required_apple_events(void);
11243static pascal OSErr do_ae_open_application(const AppleEvent *, AppleEvent *, long);
11244static pascal OSErr do_ae_print_documents(const AppleEvent *, AppleEvent *, long);
11245static pascal OSErr do_ae_open_documents(AppleEvent *, AppleEvent *, long);
11246static pascal OSErr do_ae_quit_application(AppleEvent *, AppleEvent *, long);
11247
11248extern void init_emacs_passwd_dir ();
11249extern int emacs_main (int, char **, char **);
11250extern void check_alarm ();
11251
11252extern void initialize_applescript();
11253extern void terminate_applescript();
11254
11255
11256static void
11257do_get_menus (void)
11258{
11259 Handle menubar_handle;
11260 MenuHandle menu_handle;
11261
11262 menubar_handle = GetNewMBar (128);
11263 if(menubar_handle == NULL)
11264 abort ();
11265 SetMenuBar (menubar_handle);
11266 DrawMenuBar ();
11267
11268 menu_handle = GetMenuHandle (M_APPLE);
11269 if(menu_handle != NULL)
11270 AppendResMenu (menu_handle,'DRVR');
11271 else
11272 abort ();
11273}
11274
11275
11276static void
11277do_init_managers (void)
11278{
11279 InitGraf (&qd.thePort);
11280 InitFonts ();
11281 FlushEvents (everyEvent, 0);
11282 InitWindows ();
11283 InitMenus ();
11284 TEInit ();
11285 InitDialogs (NULL);
11286 InitCursor ();
11287
11288 /* set up some extra stack space for use by emacs */
11289 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
11290
11291 /* MaxApplZone must be called for AppleScript to execute more
11292 complicated scripts */
11293 MaxApplZone ();
11294 MoreMasters ();
11295}
11296
11297
11298static void
11299do_check_ram_size (void)
11300{
11301 SInt32 physical_ram_size, logical_ram_size;
11302
11303 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr
11304 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr
11305 || physical_ram_size > 256 * 1024 * 1024
11306 || logical_ram_size > 256 * 1024 * 1024)
11307 {
11308 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL);
11309 exit (1);
11310 }
11311}
11312
11313
11314static void
11315do_window_update (WindowPtr win)
11316{
11317 struct mac_output *mwp = (mac_output *) GetWRefCon (win);
11318 struct frame *f = mwp->mFP;
11319
11320 if (f)
11321 {
11322 if (f->async_visible == 0)
11323 {
11324 f->async_visible = 1;
11325 f->async_iconified = 0;
11326 SET_FRAME_GARBAGED (f);
11327
11328 /* An update event is equivalent to MapNotify on X, so report
11329 visibility changes properly. */
11330 if (! NILP(Vframe_list) && ! NILP (XCDR (Vframe_list)))
11331 /* Force a redisplay sooner or later to update the
11332 frame titles in case this is the second frame. */
11333 record_asynch_buffer_change ();
11334 }
11335 else
11336 {
11337 BeginUpdate (win);
11338 handling_window_update = 1;
11339
11340 expose_frame (f, 0, 0, 0, 0);
11341
11342 handling_window_update = 0;
11343 EndUpdate (win);
11344 }
11345 }
11346}
11347
11348static void
11349do_window_activate (WindowPtr win)
11350{
11351 mac_output *mwp = (mac_output *) GetWRefCon (win);
11352 struct frame *f = mwp->mFP;
11353
11354 if (f)
11355 {
11356 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f);
11357 activate_scroll_bars (f);
11358 }
11359}
11360
11361static void
11362do_window_deactivate (WindowPtr win)
11363{
11364 mac_output *mwp = (mac_output *) GetWRefCon (win);
11365 struct frame *f = mwp->mFP;
11366
11367 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
11368 {
11369 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0);
11370 deactivate_scroll_bars (f);
11371 }
11372}
11373
11374static void
11375do_app_resume ()
11376{
11377 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
11378 struct frame *f = mwp->mFP;
11379
11380 SetCursor (&qd.arrow);
11381
11382 if (f)
11383 {
11384 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f);
11385 activate_scroll_bars (f);
11386 }
11387
11388 app_is_suspended = false;
11389 app_sleep_time = WNE_SLEEP_AT_RESUME;
11390}
11391
11392static void
11393do_app_suspend ()
11394{
11395 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
11396 struct frame *f = mwp->mFP;
11397
11398 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
11399 {
11400 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0);
11401 deactivate_scroll_bars (f);
11402 }
11403
11404 app_is_suspended = true;
11405 app_sleep_time = WNE_SLEEP_AT_SUSPEND;
11406}
11407
11408
11409static void
11410do_mouse_moved (Point mouse_pos)
11411{
11412 WindowPtr wp = FrontWindow ();
11413 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
11414
11415 SetPort (wp);
11416 GlobalToLocal (&mouse_pos);
11417
11418 note_mouse_movement (f, &mouse_pos);
11419}
11420
11421
11422static void
11423do_os_event (EventRecord *erp)
11424{
11425 switch((erp->message >> 24) & 0x000000FF)
11426 {
11427 case suspendResumeMessage:
11428 if((erp->message & resumeFlag) == 1)
11429 do_app_resume ();
11430 else
11431 do_app_suspend ();
11432 break;
11433
11434 case mouseMovedMessage: /* never reached */
11435 do_mouse_moved (erp->where);
11436 break;
11437 }
11438}
11439
11440static void
11441do_events (EventRecord *erp)
11442{
11443 switch (erp->what)
11444 {
11445 case updateEvt:
11446 do_window_update ((WindowPtr) erp->message);
11447 break;
11448
11449 case osEvt:
11450 do_os_event (erp);
11451 break;
11452
11453 case activateEvt:
11454 if ((erp->modifiers & activeFlag) != 0)
11455 do_window_activate ((WindowPtr) erp->message);
11456 else
11457 do_window_deactivate ((WindowPtr) erp->message);
11458 break;
11459 }
11460}
11461
11462static void
11463do_apple_menu (SInt16 menu_item)
11464{
11465 Str255 item_name;
11466 SInt16 da_driver_refnum;
11467
11468 if (menu_item == I_ABOUT)
11469 NoteAlert (ABOUT_ALERT_ID, NULL);
11470 else
11471 {
11472 GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name);
11473 da_driver_refnum = OpenDeskAcc (item_name);
11474 }
11475}
11476
11477void
11478do_menu_choice (SInt32 menu_choice)
11479{
11480 SInt16 menu_id, menu_item;
11481
11482 menu_id = HiWord (menu_choice);
11483 menu_item = LoWord (menu_choice);
11484
11485 if (menu_id == 0)
11486 return;
11487
11488 switch (menu_id)
11489 {
11490 case M_APPLE:
11491 do_apple_menu (menu_item);
11492 break;
11493
11494 default:
11495 {
11496 WindowPtr wp = FrontWindow ();
11497 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
11498 MenuHandle menu = GetMenuHandle (menu_id);
11499 if (menu)
11500 {
11501 UInt32 refcon;
11502
11503 GetMenuItemRefCon (menu, menu_item, &refcon);
11504 menubar_selection_callback (f, refcon);
11505 }
11506 }
11507 }
11508
11509 HiliteMenu (0);
11510}
11511
11512
11513/* Handle drags in size box. Based on code contributed by Ben
11514 Mesander and IM - Window Manager A. */
11515
11516static void
11517do_grow_window (WindowPtr w, EventRecord *e)
11518{
11519 long grow_size;
11520 Rect limit_rect;
11521 int rows, columns;
11522 mac_output *mwp = (mac_output *) GetWRefCon (w);
11523 struct frame *f = mwp->mFP;
11524
11525 SetRect(&limit_rect, MIN_DOC_SIZE, MIN_DOC_SIZE, MAX_DOC_SIZE, MAX_DOC_SIZE);
11526
11527 grow_size = GrowWindow (w, e->where, &limit_rect);
11528
11529 /* see if it really changed size */
11530 if (grow_size != 0)
11531 {
11532 rows = PIXEL_TO_CHAR_HEIGHT (f, HiWord (grow_size));
11533 columns = PIXEL_TO_CHAR_WIDTH (f, LoWord (grow_size));
11534
11535 x_set_window_size (f, 0, columns, rows);
11536 }
11537}
11538
11539
11540/* Handle clicks in zoom box. Calculation of "standard state" based
11541 on code in IM - Window Manager A and code contributed by Ben
11542 Mesander. The standard state of an Emacs window is 80-characters
11543 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
11544
11545static void
11546do_zoom_window (WindowPtr w, int zoom_in_or_out)
11547{
11548 GrafPtr save_port;
11549 Rect zoom_rect, port_rect;
11550 Point top_left;
11551 int w_title_height, columns, rows, width, height, dummy, x, y;
11552 mac_output *mwp = (mac_output *) GetWRefCon (w);
11553 struct frame *f = mwp->mFP;
11554
11555 GetPort (&save_port);
11556 SetPort (w);
11557 EraseRect (&(w->portRect)); /* erase to avoid flicker */
11558 if (zoom_in_or_out == inZoomOut)
11559 {
11560 SetPt(&top_left, w->portRect.left, w->portRect.top);
11561 LocalToGlobal (&top_left);
11562
11563 /* calculate height of window's title bar */
11564 w_title_height = top_left.v - 1
11565 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight();
11566
11567 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
11568 zoom_rect = qd.screenBits.bounds;
11569 zoom_rect.top += w_title_height;
11570 InsetRect (&zoom_rect, 8, 4); /* not too tight */
11571
11572 zoom_rect.right = zoom_rect.left
11573 + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
11574
11575 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState = zoom_rect;
11576 }
11577
11578 ZoomWindow (w, zoom_in_or_out, w == FrontWindow());
11579
11580 /* retrieve window size and update application values */
11581 port_rect = w->portRect;
11582 rows = PIXEL_TO_CHAR_HEIGHT (f, port_rect.bottom - port_rect.top);
11583 columns = PIXEL_TO_CHAR_WIDTH (f, port_rect.right - port_rect.left);
11584 x_set_window_size (mwp->mFP, 0, columns, rows);
11585
11586 SetPort (save_port);
11587}
11588
11589
11590/* Intialize AppleEvent dispatcher table for the required events. */
11591void
11592init_required_apple_events ()
11593{
11594 OSErr err;
11595 long result;
11596
11597 /* Make sure we have apple events before starting. */
11598 err = Gestalt (gestaltAppleEventsAttr, &result);
11599 if (err != noErr)
11600 abort ();
11601
11602 if (!(result & (1 << gestaltAppleEventsPresent)))
11603 abort ();
11604
11605 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
11606 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_open_application),
11607 0L, false);
11608 if (err != noErr)
11609 abort ();
11610
11611 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
11612 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_open_documents),
11613 0L, false);
11614 if (err != noErr)
11615 abort ();
11616
11617 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
11618 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_print_documents),
11619 0L, false);
11620 if (err != noErr)
11621 abort ();
11622
11623 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
11624 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_quit_application),
11625 0L, false);
11626 if (err != noErr)
11627 abort ();
11628}
11629
11630
11631/* Open Application Apple Event */
11632static pascal OSErr
11633do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon)
11634{
11635 return noErr;
11636}
11637
11638
11639/* Defined in mac.c. */
11640extern int
11641path_from_vol_dir_name (char *, int, short, long, char *);
11642
11643
11644/* Called when we receive an AppleEvent with an ID of
11645 "kAEOpenDocuments". This routine gets the direct parameter,
11646 extracts the FSSpecs in it, and puts their names on a list. */
11647static pascal OSErr
11648do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
11649{
11650 OSErr err, err2;
11651 AEDesc the_desc;
11652 AEKeyword keyword;
11653 DescType actual_type;
11654 Size actual_size;
11655
11656 err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc);
11657 if (err != noErr)
11658 goto descriptor_error_exit;
11659
11660 /* Check to see that we got all of the required parameters from the
11661 event descriptor. For an 'odoc' event this should just be the
11662 file list. */
11663 err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
11664 &actual_type, (Ptr) &keyword,
11665 sizeof (keyword), &actual_size);
11666 /* No error means that we found some unused parameters.
11667 errAEDescNotFound means that there are no more parameters. If we
11668 get an error code other than that, flag it. */
11669 if ((err == noErr) || (err != errAEDescNotFound))
11670 {
11671 err = errAEEventNotHandled;
11672 goto error_exit;
11673 }
11674 err = noErr;
11675
11676 /* Got all the parameters we need. Now, go through the direct
11677 object list and parse it up. */
11678 {
11679 long num_files_to_open;
11680
11681 err = AECountItems (&the_desc, &num_files_to_open);
11682 if (err == noErr)
11683 {
11684 int i;
11685
11686 /* AE file list is one based so just use that for indexing here. */
11687 for (i = 1; (err == noErr) && (i <= num_files_to_open); i++) {
11688 FSSpec fs;
11689 Str255 path_name, unix_path_name;
11690
11691 err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type,
11692 (Ptr) &fs, sizeof (fs), &actual_size);
11693 if (err != noErr) break;
11694
11695 if (path_from_vol_dir_name (path_name, 255, fs.vRefNum, fs.parID,
11696 fs.name) &&
11697 mac_to_posix_pathname (path_name, unix_path_name, 255))
11698 drag_and_drop_file_list = Fcons (build_string (unix_path_name),
11699 drag_and_drop_file_list);
11700 }
11701 }
11702 }
11703
11704error_exit:
11705 /* Nuke the coerced file list in any case */
11706 err2 = AEDisposeDesc(&the_desc);
11707
11708descriptor_error_exit:
11709 /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */
11710 return err;
11711}
11712
11713
11714/* Print Document Apple Event */
11715static pascal OSErr
11716do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon)
11717{
11718 return errAEEventNotHandled;
11719}
11720
11721
11722static pascal OSErr
11723do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon)
11724{
11725 /* FixMe: Do we need an unwind-protect or something here? And what
11726 do we do about unsaved files. Currently just forces quit rather
11727 than doing recursive callback to get user input. */
11728
11729 terminate_flag = true;
11730
11731 /* Fkill_emacs doesn't return. We have to return. (TI) */
11732 return noErr;
11733}
11734
11735
11736#if __profile__
11737void
11738profiler_exit_proc ()
11739{
11740 ProfilerDump ("\pEmacs.prof");
11741 ProfilerTerm ();
11742}
11743#endif
11744
11745/* These few functions implement Emacs as a normal Mac application
11746 (almost): set up the heap and the Toolbox, handle necessary
11747 system events plus a few simple menu events. They also set up
11748 Emacs's access to functions defined in the rest of this file.
11749 Emacs uses function hooks to perform all its terminal I/O. A
11750 complete list of these functions appear in termhooks.h. For what
11751 they do, read the comments there and see also w32term.c and
11752 xterm.c. What's noticeably missing here is the event loop, which
11753 is normally present in most Mac application. After performing the
11754 necessary Mac initializations, main passes off control to
11755 emacs_main (corresponding to main in emacs.c). Emacs_main calls
11756 mac_read_socket (defined further below) to read input. This is
11757 where WaitNextEvent is called to process Mac events. This is also
11758 where check_alarm in sysdep.c is called to simulate alarm signals.
11759 This makes the cursor jump back to its correct position after
11760 briefly jumping to that of the matching parenthesis, print useful
11761 hints and prompts in the minibuffer after the user stops typing for
11762 a wait, etc. */
11763
11764#undef main
11765int
11766main (void)
11767{
11768#if __profile__ /* is the profiler on? */
11769 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11770 exit(1);
11771#endif
11772
11773#if __MWERKS__
11774 /* set creator and type for files created by MSL */
11775 _fcreator = 'EMAx';
11776 _ftype = 'TEXT';
11777#endif
11778
11779 do_init_managers ();
11780
11781 do_get_menus ();
11782
11783 do_check_ram_size ();
11784
11785 init_emacs_passwd_dir ();
11786
11787 init_environ ();
11788
11789 initialize_applescript ();
11790
11791 init_required_apple_events ();
11792
11793 {
11794 char **argv;
11795 int argc = 0;
11796
11797 /* set up argv array from STR# resource */
11798 get_string_list (&argv, ARGV_STRING_LIST_ID);
11799 while (argv[argc])
11800 argc++;
11801
11802 /* free up AppleScript resources on exit */
11803 atexit (terminate_applescript);
11804
11805#if __profile__ /* is the profiler on? */
11806 atexit (profiler_exit_proc);
11807#endif
11808
11809 /* 3rd param "envp" never used in emacs_main */
11810 (void) emacs_main (argc, argv, 0);
11811 }
11812
11813 /* Never reached - real exit in Fkill_emacs */
11814 return 0;
11815}
11816
11817
11818/* Table for translating Mac keycode to X keysym values. Contributed
11819 by Sudhir Shenoy. */
11820static unsigned char keycode_to_xkeysym_table[] = {
11821/* 0x00 - 0x3f */
11822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11823 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11825 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11826/* 0x40 */
11827 0, '\xae' /* kp. */, 0, '\xaa' /* kp* */,
11828 0, '\xab' /* kp+ */, 0, '\x7f' /* kp_clr */,
11829 0, 0, 0, '\xaf' /* kp/ */,
11830 '\x8d' /* kp_ent */, 0, '\xad' /* kp- */, 0,
11831/* 0x50 */
11832 0, '\xbd' /* kp= */, '\xb0' /* kp0 */, '\xb1' /* kp1 */,
11833 '\xb2' /* kp2 */, '\xb3' /* kp3 */, '\xb4' /* kp4 */, '\xb5' /* kp5 */,
11834 '\xb6' /* kp6 */, '\xb7' /* kp7 */, 0, '\xb8' /* kp8 */,
11835 '\xb9' /* kp9 */, 0, 0, 0,
11836/* 0x60 */
11837 '\xc2' /* F5 */, '\xc3' /* F6 */, '\xc4' /* F7 */, '\xc0' /* F3 */,
11838 '\xc5' /* F8 */, '\xc6' /* F9 */, 0, '\xc8' /* F11 */,
11839 0, '\xca' /* F13 */, 0, '\xcb' /* F14 */,
11840 0, '\xc7' /* F10 */, 0, '\xc9' /* F12 */,
11841/* 0x70 */
11842 0, '\xcc' /* F15 */, '\x9e' /* ins */, '\x95' /* home */,
11843 '\x9a' /* pgup */, '\x9f' /* del */, '\xc1' /* F4 */, '\x9c' /* end */,
11844 '\xbf' /* F2 */, '\x9b' /* pgdown */, '\xbe' /* F1 */, '\x51' /* left */,
11845 '\x53' /* right */, '\x54' /* down */, '\x52' /* up */, 0
11846};
11847
11848static int
11849keycode_to_xkeysym (int keyCode, int *xKeySym)
11850{
11851 *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f];
11852 return *xKeySym != 0;
11853}
11854
11855/* Emacs calls this whenever it wants to read an input event from the
11856 user. */
11857int
11858XTread_socket (int sd, struct input_event *bufp, int numchars, int expected)
11859{
11860 int count = 0;
11861 EventRecord er;
11862 int the_modifiers;
11863 EventMask event_mask;
11864
11865 if (interrupt_input_blocked)
11866 {
11867 interrupt_input_pending = 1;
11868 return -1;
11869 }
11870
11871 interrupt_input_pending = 0;
11872 BLOCK_INPUT;
11873
11874 /* So people can tell when we have read the available input. */
11875 input_signal_count++;
11876
11877 if (numchars <= 0)
11878 abort ();
11879
11880 /* Don't poll for events to process (specifically updateEvt) if
11881 window update currently already in progress. A call to redisplay
11882 (in do_window_update) can be preempted by another call to
11883 redisplay, causing blank regions to be left on the screen and the
11884 cursor to be left at strange places. */
11885 if (handling_window_update)
11886 {
11887 UNBLOCK_INPUT;
11888 return 0;
11889 }
11890
11891 if (terminate_flag)
11892 Fkill_emacs (make_number (1));
11893
11894 /* It is necessary to set this (additional) argument slot of an
11895 event to nil because keyboard.c protects incompletely processed
11896 event from being garbage collected by placing them in the
11897 kbd_buffer_gcpro vector. */
11898 bufp->arg = Qnil;
11899
11900 event_mask = everyEvent;
11901 if (NILP (Fboundp (Qmac_ready_for_drag_n_drop)))
11902 event_mask -= highLevelEventMask;
11903
11904 while (WaitNextEvent (event_mask, &er, 0L, NULL) && numchars > 0)
11905 switch (er.what)
11906 {
11907 case mouseDown:
11908 case mouseUp:
11909 {
11910 WindowPtr window_ptr = FrontWindow ();
11911 SInt16 part_code;
11912
11913 if (mouse_tracking_in_progress == mouse_tracking_scroll_bar
11914 && er.what == mouseUp)
11915 {
11916 struct mac_output *mwp = (mac_output *) GetWRefCon (window_ptr);
11917 Point mouse_loc = er.where;
11918
11919 /* Convert to local coordinates of new window. */
11920 SetPort (window_ptr);
11921 GlobalToLocal (&mouse_loc);
11922
11923 bufp->code = 0; /* only one mouse button */
11924 bufp->kind = scroll_bar_click;
11925 bufp->frame_or_window = tracked_scroll_bar->window;
11926 bufp->part = scroll_bar_handle;
11927 bufp->modifiers = up_modifier;
11928 bufp->timestamp = er.when * (1000 / 60);
11929 /* ticks to milliseconds */
11930
11931 XSETINT (bufp->x, tracked_scroll_bar->left + 2);
11932 XSETINT (bufp->y, mouse_loc.v - 24);
11933 tracked_scroll_bar->dragging = Qnil;
11934 mouse_tracking_in_progress = mouse_tracking_none;
11935 tracked_scroll_bar = NULL;
11936 count++;
11937 bufp++;
11938 numchars--;
11939 break;
11940 }
11941
11942 part_code = FindWindow (er.where, &window_ptr);
11943
11944 switch (part_code)
11945 {
11946 case inMenuBar:
11947 {
11948 struct frame *f = ((mac_output *)
11949 GetWRefCon (FrontWindow ()))->mFP;
11950 saved_menu_event_location = er.where;
11951 bufp->kind = menu_bar_activate_event;
11952 XSETFRAME (bufp->frame_or_window, f);
11953 count++;
11954 bufp++;
11955 numchars--;
11956 }
11957 break;
11958
11959 case inContent:
11960 if (window_ptr != FrontWindow ())
11961 SelectWindow (window_ptr);
11962 else
11963 {
11964 int control_part_code;
11965 ControlHandle ch;
11966 struct mac_output *mwp = (mac_output *)
11967 GetWRefCon (window_ptr);
11968 Point mouse_loc = er.where;
11969
11970 /* convert to local coordinates of new window */
11971 SetPort (window_ptr);
11972 GlobalToLocal (&mouse_loc);
11973 control_part_code = FindControl (mouse_loc, window_ptr, &ch);
11974
11975 bufp->code = 0; /* only one mouse button */
11976 XSETINT (bufp->x, mouse_loc.h);
11977 XSETINT (bufp->y, mouse_loc.v);
11978 bufp->timestamp = er.when * (1000 / 60);
11979 /* ticks to milliseconds */
11980
11981 if (control_part_code != 0)
11982 {
11983 struct scroll_bar *bar = (struct scroll_bar *)
11984 GetControlReference (ch);
11985 x_scroll_bar_handle_click (bar, control_part_code, &er,
11986 bufp);
11987 if (er.what == mouseDown
11988 && control_part_code == kControlIndicatorPart)
11989 {
11990 mouse_tracking_in_progress = mouse_tracking_scroll_bar;
11991 tracked_scroll_bar = bar;
11992 }
11993 else
11994 {
11995 mouse_tracking_in_progress = mouse_tracking_none;
11996 tracked_scroll_bar = NULL;
11997 }
11998 }
11999 else
12000 {
12001 bufp->kind = mouse_click;
12002 XSETFRAME (bufp->frame_or_window, mwp->mFP);
12003 if (er.what == mouseDown)
12004 mouse_tracking_in_progress = mouse_tracking_mouse_movement;
12005 else
12006 mouse_tracking_in_progress = mouse_tracking_none;
12007 }
12008
12009 switch (er.what)
12010 {
12011 case mouseDown:
12012 bufp->modifiers = down_modifier;
12013 break;
12014 case mouseUp:
12015 bufp->modifiers = up_modifier;
12016 break;
12017 }
12018
12019 count++;
12020 bufp++;
12021 numchars--;
12022 }
12023 break;
12024
12025 case inDrag:
12026 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
12027 break;
12028
12029 case inGoAway:
12030 if (TrackGoAway (window_ptr, er.where))
12031 {
12032 bufp->kind = delete_window_event;
12033 XSETFRAME (bufp->frame_or_window,
12034 ((mac_output *) GetWRefCon (window_ptr))->mFP);
12035 count++;
12036 bufp++;
12037 numchars--;
12038 }
12039 break;
12040
12041 /* window resize handling added --ben */
12042 case inGrow:
12043 do_grow_window(window_ptr, &er);
12044 break;
12045
12046 /* window zoom handling added --ben */
12047 case inZoomIn:
12048 case inZoomOut:
12049 if (TrackBox (window_ptr, er.where, part_code))
12050 do_zoom_window (window_ptr, part_code);
12051 break;
12052
12053 default:
12054 break;
12055 }
12056 }
12057 break;
12058
12059 case updateEvt:
12060 case osEvt:
12061 case activateEvt:
12062 do_events (&er);
12063 break;
12064
12065 case keyDown:
12066 case autoKey:
12067 {
12068 int keycode = (er.message & keyCodeMask) >> 8;
12069 int xkeysym;
12070
12071 ObscureCursor ();
12072
12073 if (keycode == 0x33) /* delete key (charCode translated to 0x8) */
12074 {
12075 bufp->code = 0x7f;
12076 bufp->kind = ascii_keystroke;
12077 }
12078 else if (keycode_to_xkeysym (keycode, &xkeysym))
12079 {
12080 bufp->code = 0xff00 | xkeysym;
12081 bufp->kind = non_ascii_keystroke;
12082 }
12083 else
12084 {
12085 if (er.modifiers
12086 & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey))
12087 {
12088 /* This code comes from Keyboard Resource, Appendix
12089 C of IM - Text. This is necessary since shift is
12090 ignored in KCHR table translation when option or
12091 command is pressed. */
12092 int new_modifiers = er.modifiers & 0xf600;
12093 /* mask off option and command */
12094 int new_keycode = keycode | new_modifiers;
12095 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
12096 unsigned long some_state = 0;
12097 bufp->code = KeyTranslate (kchr_ptr, new_keycode,
12098 &some_state) & 0xff;
12099 }
12100 else
12101 bufp->code = er.message & charCodeMask;
12102 bufp->kind = ascii_keystroke;
12103 }
12104 }
12105
12106 /* If variable mac-convert-keyboard-input-to-latin-1 is non-nil,
12107 convert non-ASCII characters typed at the Mac keyboard
12108 (presumed to be in the Mac Roman encoding) to iso-latin-1
12109 encoding before they are passed to Emacs. This enables the
12110 Mac keyboard to be used to enter non-ASCII iso-latin-1
12111 characters directly. */
12112 if (mac_keyboard_text_encoding != kTextEncodingMacRoman
12113 && bufp->kind == ascii_keystroke && bufp->code >= 128)
12114 {
12115 static TECObjectRef converter = NULL;
12116 OSStatus the_err = noErr;
12117 OSStatus convert_status = noErr;
12118
12119 if (converter == NULL)
12120 {
12121 the_err = TECCreateConverter (&converter,
12122 kTextEncodingMacRoman,
12123 mac_keyboard_text_encoding);
12124 current_mac_keyboard_text_encoding = mac_keyboard_text_encoding;
12125 }
12126 else if (mac_keyboard_text_encoding != current_mac_keyboard_text_encoding)
12127 {
12128 /* Free the converter for the current encoding before
12129 creating a new one. */
12130 TECDisposeConverter (converter);
12131 the_err = TECCreateConverter (&converter,
12132 kTextEncodingMacRoman,
12133 mac_keyboard_text_encoding);
12134 current_mac_keyboard_text_encoding = mac_keyboard_text_encoding;
12135 }
12136
12137 if (the_err == noErr)
12138 {
12139 unsigned char ch = bufp->code;
12140 ByteCount actual_input_length, actual_output_length;
12141 unsigned char outch;
12142
12143 convert_status = TECConvertText (converter, &ch, 1,
12144 &actual_input_length,
12145 &outch, 1,
12146 &actual_output_length);
12147 if (convert_status == noErr
12148 && actual_input_length == 1
12149 && actual_output_length == 1)
12150 bufp->code = outch;
12151 }
12152 }
12153
12154 the_modifiers = 0;
12155 if (er.modifiers & shiftKey)
12156 the_modifiers |= shift_modifier;
12157 if (er.modifiers & controlKey)
12158 the_modifiers |= ctrl_modifier;
12159 /* use option or command key as meta depending on value of
12160 mac-command-key-is-meta */
12161 if (er.modifiers
12162 & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey))
12163 the_modifiers |= meta_modifier;
12164 bufp->modifiers = the_modifiers;
12165
12166 {
12167 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
12168 XSETFRAME (bufp->frame_or_window, mwp->mFP);
12169 }
12170
12171 bufp->timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12172
12173 count++;
12174 bufp++;
12175 numchars--;
12176 break;
12177
12178 case kHighLevelEvent:
12179 drag_and_drop_file_list = Qnil;
12180
12181 AEProcessAppleEvent(&er);
12182
12183 /* Build a drag_n_drop type event as is done in
12184 constuct_drag_n_drop in w32term.c. */
12185 if (!NILP (drag_and_drop_file_list))
12186 {
12187 struct frame *f;
12188 WindowPtr wp;
12189 Lisp_Object frame;
12190
12191 wp = FrontWindow ();
12192 if (!wp)
12193 f = NULL;
12194 else
12195 f = ((mac_output *) GetWRefCon (wp))->mFP;
12196
12197 bufp->kind = drag_n_drop;
12198 bufp->code = 0;
12199 bufp->timestamp = er.when * (1000 / 60);
12200 /* ticks to milliseconds */
12201 bufp->modifiers = 0;
12202
12203 XSETINT (bufp->x, 0);
12204 XSETINT (bufp->y, 0);
12205
12206 XSETFRAME (frame, f);
12207 bufp->frame_or_window = Fcons (frame, drag_and_drop_file_list);
12208
12209 /* Regardless of whether Emacs was suspended or in the
12210 foreground, ask it to redraw its entire screen.
12211 Otherwise parts of the screen can be left in an
12212 inconsistent state. */
12213 if (wp)
12214 InvalRect (&(wp->portRect));
12215
12216 count++;
12217 bufp++;
12218 numchars--;
12219 }
12220
12221 default:
12222 break;
12223 }
12224
12225 /* If the focus was just given to an autoraising frame,
12226 raise it now. */
12227 /* ??? This ought to be able to handle more than one such frame. */
12228 if (pending_autoraise_frame)
12229 {
12230 x_raise_frame (pending_autoraise_frame);
12231 pending_autoraise_frame = 0;
12232 }
12233
12234 check_alarm (); /* simulate the handling of a SIGALRM */
12235
12236 {
12237 static Point old_mouse_pos = { -1, -1 };
12238
12239 if (app_is_suspended)
12240 {
12241 old_mouse_pos.h = -1;
12242 old_mouse_pos.v = -1;
12243 }
12244 else
12245 {
12246 Point mouse_pos;
12247 WindowPtr wp = FrontWindow ();
12248 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
12249 Lisp_Object bar;
12250 struct scroll_bar *sb;
12251
12252 SetPort (wp);
12253 GetMouse (&mouse_pos);
12254
12255 if (!EqualPt (mouse_pos, old_mouse_pos))
12256 {
12257 if (mouse_tracking_in_progress == mouse_tracking_scroll_bar
12258 && tracked_scroll_bar)
12259 x_scroll_bar_note_movement (tracked_scroll_bar,
12260 mouse_pos.v
12261 - XINT (tracked_scroll_bar->top),
12262 TickCount() * (1000 / 60));
12263 else
12264 note_mouse_movement (f, &mouse_pos);
12265
12266 old_mouse_pos = mouse_pos;
12267 }
12268 }
12269 }
12270
12271 UNBLOCK_INPUT;
12272
12273 return count;
12274}
12275
12276
12277/* Need to override CodeWarrior's input function so no conversion is
12278 done on newlines Otherwise compiled functions in .elc files will be
12279 read incorrectly. Defined in ...:MSL C:MSL
12280 Common:Source:buffer_io.c. */
12281#ifdef __MWERKS__
12282void
12283__convert_to_newlines (unsigned char * p, size_t * n)
12284{
12285#pragma unused(p,n)
12286}
12287
12288void
12289__convert_from_newlines (unsigned char * p, size_t * n)
12290{
12291#pragma unused(p,n)
12292}
12293#endif
12294
12295
12296/* Initialize the struct pointed to by MW to represent a new COLS x
12297 ROWS Macintosh window, using font with name FONTNAME and size
12298 FONTSIZE. */
12299void
12300NewMacWindow (FRAME_PTR fp)
12301{
12302 mac_output *mwp;
12303 static int making_terminal_window = 1;
12304
12305 mwp = fp->output_data.mac;
12306
12307 if (making_terminal_window)
12308 {
12309 if (!(mwp->mWP = GetNewCWindow (TERM_WINDOW_RESOURCE, NULL,
12310 (WindowPtr) -1)))
12311 abort ();
12312 making_terminal_window = 0;
12313 }
12314 else
12315 if (!(mwp->mWP = GetNewCWindow (WINDOW_RESOURCE, NULL, (WindowPtr) -1)))
12316 abort ();
12317
12318
12319 SetWRefCon (mwp->mWP, (long) mwp);
12320 /* so that update events can find this mac_output struct */
12321 mwp->mFP = fp; /* point back to emacs frame */
12322
12323 SetPort (mwp->mWP);
12324
12325 mwp->fontset = -1;
12326
12327 SizeWindow (mwp->mWP, mwp->pixel_width, mwp->pixel_height, false);
12328 ShowWindow (mwp->mWP);
12329
12330}
12331
12332
12333void make_mac_frame (struct frame *f)
12334{
12335 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12336 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12337
12338 NewMacWindow(f);
12339 f->output_data.mac->background_pixel = 0xffffff;
12340 f->output_data.mac->foreground_pixel = 0;
12341
12342 f->output_data.mac->cursor_pixel = 0;
12343 f->output_data.mac->border_pixel = 0x00ff00;
12344 f->output_data.mac->mouse_pixel = 0xff00ff;
12345 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12346
12347 f->output_data.mac->desired_cursor = FILLED_BOX_CURSOR;
12348
12349 f->output_data.mac->fontset = -1;
12350 f->output_data.mac->scroll_bar_foreground_pixel = -1;
12351 f->output_data.mac->scroll_bar_background_pixel = -1;
12352 f->output_data.mac->left_pos = 4;
12353 f->output_data.mac->top_pos = 4;
12354 f->output_data.mac->border_width = 0;
12355 f->output_data.mac->explicit_parent = 0;
12356
12357 f->output_data.mac->internal_border_width = 0;
12358
12359 f->output_method = output_mac;
12360
12361 f->auto_raise = 1;
12362 f->auto_lower = 1;
12363
12364 f->new_width = 0;
12365 f->new_height = 0;
12366}
12367
12368void make_mac_terminal_frame (struct frame *f)
12369{
12370 Lisp_Object frame;
12371
12372 XSETFRAME (frame, f);
12373
12374 f->output_method = output_mac;
12375 f->output_data.mac = (struct mac_output *)
12376 xmalloc (sizeof (struct mac_output));
12377 bzero (f->output_data.mac, sizeof (struct mac_output));
12378 f->output_data.mac->fontset = -1;
12379 f->output_data.mac->scroll_bar_foreground_pixel = -1;
12380 f->output_data.mac->scroll_bar_background_pixel = -1;
12381
12382 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12383
12384 f->width = 96;
12385 f->height = 4;
12386
12387 make_mac_frame (f);
12388
12389 Fmodify_frame_parameters (frame,
12390 Fcons (Fcons (Qfont,
12391 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12392 Fmodify_frame_parameters (frame,
12393 Fcons (Fcons (Qforeground_color,
12394 build_string ("black")), Qnil));
12395 Fmodify_frame_parameters (frame,
12396 Fcons (Fcons (Qbackground_color,
12397 build_string ("white")), Qnil));
12398}
12399
12400void
12401mac_initialize_display_info ()
12402{
12403 struct mac_display_info *dpyinfo = &one_mac_display_info;
12404 GDHandle main_device_handle;
12405
12406 bzero (dpyinfo, sizeof (*dpyinfo));
12407
12408 /* Put it on x_display_name_list. */
12409 x_display_name_list = Fcons (Fcons (build_string ("Mac"), Qnil),
12410 x_display_name_list);
12411 dpyinfo->name_list_element = XCAR (x_display_name_list);
12412
12413 main_device_handle = LMGetMainDevice();
12414
12415 dpyinfo->reference_count = 0;
12416 dpyinfo->resx = 75.0;
12417 dpyinfo->resy = 75.0;
12418 dpyinfo->n_planes = 1;
12419 dpyinfo->n_cbits = 16;
12420 dpyinfo->height = (**main_device_handle).gdRect.bottom;
12421 dpyinfo->width = (**main_device_handle).gdRect.right;
12422 dpyinfo->grabbed = 0;
12423 dpyinfo->root_window = NULL;
12424
12425 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12426 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12427 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12428 dpyinfo->mouse_face_window = Qnil;
12429
12430}
12431
12432void
12433x_initialize ()
12434{
12435 rif = &x_redisplay_interface;
12436
12437 clear_frame_hook = x_clear_frame;
12438 ins_del_lines_hook = x_ins_del_lines;
12439 change_line_highlight_hook = x_change_line_highlight;
12440 delete_glyphs_hook = x_delete_glyphs;
12441 ring_bell_hook = XTring_bell;
12442 reset_terminal_modes_hook = XTreset_terminal_modes;
12443 set_terminal_modes_hook = XTset_terminal_modes;
12444 update_begin_hook = x_update_begin;
12445 update_end_hook = x_update_end;
12446 set_terminal_window_hook = XTset_terminal_window;
12447 read_socket_hook = XTread_socket;
12448 frame_up_to_date_hook = XTframe_up_to_date;
12449 reassert_line_highlight_hook = XTreassert_line_highlight;
12450 mouse_position_hook = XTmouse_position;
12451 frame_rehighlight_hook = XTframe_rehighlight;
12452 frame_raise_lower_hook = XTframe_raise_lower;
12453
12454 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12455 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12456 redeem_scroll_bar_hook = XTredeem_scroll_bar;
12457 judge_scroll_bars_hook = XTjudge_scroll_bars;
12458
12459 estimate_mode_line_height_hook = x_estimate_mode_line_height;
12460
12461 scroll_region_ok = 1; /* we'll scroll partial frames */
12462 char_ins_del_ok = 0; /* just as fast to write the line */
12463 line_ins_del_ok = 1; /* we'll just blt 'em */
12464 fast_clear_end_of_line = 1; /* X does this well */
12465 memory_below_frame = 0; /* we don't remember what scrolls
12466 off the bottom */
12467 baud_rate = 19200;
12468
12469 x_noop_count = 0;
12470 last_tool_bar_item = -1;
12471 any_help_event_p = 0;
12472
12473 /* Try to use interrupt input; if we can't, then start polling. */
12474 Fset_input_mode (Qt, Qnil, Qt, Qnil);
12475
12476#ifdef USE_X_TOOLKIT
12477 XtToolkitInitialize ();
12478 Xt_app_con = XtCreateApplicationContext ();
12479 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
12480
12481 /* Install an asynchronous timer that processes Xt timeout events
12482 every 0.1s. This is necessary because some widget sets use
12483 timeouts internally, for example the LessTif menu bar, or the
12484 Xaw3d scroll bar. When Xt timouts aren't processed, these
12485 widgets don't behave normally. */
12486 {
12487 EMACS_TIME interval;
12488 EMACS_SET_SECS_USECS (interval, 0, 100000);
12489 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
12490 }
12491#endif
12492
12493#if USE_TOOLKIT_SCROLL_BARS
12494 xaw3d_arrow_scroll = False;
12495 xaw3d_pick_top = True;
12496#endif
12497
12498#if 0
12499 /* Note that there is no real way portable across R3/R4 to get the
12500 original error handler. */
12501 XSetErrorHandler (x_error_handler);
12502 XSetIOErrorHandler (x_io_error_quitter);
12503
12504 /* Disable Window Change signals; they are handled by X events. */
12505#ifdef SIGWINCH
12506 signal (SIGWINCH, SIG_DFL);
12507#endif /* ! defined (SIGWINCH) */
12508
12509 signal (SIGPIPE, x_connection_signal);
12510#endif
12511
12512 mac_initialize_display_info ();
12513}
12514
12515
12516void
12517syms_of_macterm ()
12518{
12519#if 0
12520 staticpro (&x_error_message_string);
12521 x_error_message_string = Qnil;
12522#endif
12523
12524 staticpro (&x_display_name_list);
12525 x_display_name_list = Qnil;
12526
12527 staticpro (&last_mouse_scroll_bar);
12528 last_mouse_scroll_bar = Qnil;
12529
12530 staticpro (&Qvendor_specific_keysyms);
12531 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
12532
12533 staticpro (&last_mouse_press_frame);
12534 last_mouse_press_frame = Qnil;
12535
12536 Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop");
12537 staticpro (&Qmac_ready_for_drag_n_drop);
12538
12539 help_echo = Qnil;
12540 staticpro (&help_echo);
12541 help_echo_object = Qnil;
12542 staticpro (&help_echo_object);
12543 help_echo_window = Qnil;
12544 staticpro (&help_echo_window);
12545 previous_help_echo = Qnil;
12546 staticpro (&previous_help_echo);
12547 help_echo_pos = -1;
12548
12549 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
12550 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
12551For example, if a block cursor is over a tab, it will be drawn as\n\
12552wide as that tab on the display.");
12553 x_stretch_cursor_p = 0;
12554
12555 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
12556 "If not nil, Emacs uses toolkit scroll bars.");
12557#if USE_TOOLKIT_SCROLL_BARS
12558 x_toolkit_scroll_bars_p = 1;
12559#else
12560 x_toolkit_scroll_bars_p = 0;
12561#endif
12562
12563 staticpro (&last_mouse_motion_frame);
12564 last_mouse_motion_frame = Qnil;
12565
12566 DEFVAR_LISP ("mac-command-key-is-meta", &Vmac_command_key_is_meta,
12567 "Non-nil means that the command key is used as the Emacs meta key.\n\
12568Otherwise the option key is used.");
12569 Vmac_command_key_is_meta = Qt;
12570
12571 DEFVAR_INT ("mac-keyboard-text-encoding", &mac_keyboard_text_encoding,
12572 "One of the Text Encoding Base constant values defined in the\n\
12573Basic Text Constants section of Inside Macintosh - Text Encoding\n\
12574Conversion Manager. Its value determines the encoding characters\n\
12575typed at the Mac keyboard (presumed to be in the MacRoman encoding)\n\
12576will convert into. E.g., if it is set to kTextEncodingMacRoman (0),\n\
12577its default value, no conversion takes place. If it is set to\n\
12578kTextEncodingISOLatin1 (0x201) or kTextEncodingISOLatin2 (0x202),\n\
12579characters typed on Mac keyboard are first converted into the\n\
12580ISO Latin-1 or ISO Latin-2 encoding, respectively before being\n\
12581passed to Emacs. Together with Emacs's set-keyboard-coding-system\n\
12582command, this enables the Mac keyboard to be used to enter non-ASCII\n\
12583characters directly.");
12584 mac_keyboard_text_encoding = kTextEncodingMacRoman;
12585}