aboutsummaryrefslogtreecommitdiffstats
path: root/mac/src
diff options
context:
space:
mode:
authorAndrew Choi2000-10-22 16:50:16 +0000
committerAndrew Choi2000-10-22 16:50:16 +0000
commit1a578e9be2034298bb8ac29b7b84086a4ab290f4 (patch)
tree52e921cd58e9ac6688757ff1b1d0531c9820475f /mac/src
parentd371949a0f0d152bcc9013b7bbd15418465a1792 (diff)
downloademacs-1a578e9be2034298bb8ac29b7b84086a4ab290f4.tar.gz
emacs-1a578e9be2034298bb8ac29b7b84086a4ab290f4.zip
Initial check-in: changes for building Emacs under Mac OS.
2000-10-23 Andrew Choi <akochoi@i-cable.com> * dispextern.h [macintosh]: Include macgui.h instead of macterm.h. * dispnew.c [macintosh]: Include macterm.h. (init_display) [macintosh]: initialization for window system. * emacs.c (main) [macintosh]: Call syms_of_textprop, syms_of_macfns, syms_of_ccl, syms_of_fontset, syms_of_xterm, syms_of_search, x_term_init, and init_keyboard before calling init_window_once. Also, call syms_of_xmenu. * fontset.c (syms_of_fontset) [macintosh]: Set ASCII font of default fontset to Monaco. * frame.c [macintosh]: Include macterm.h. Remove declarations of NewMacWindow and DisposeMacWindow. (make_terminal_frame) [macintosh]: Call make_mac_terminal_frame instead of calling NewMacWindow and setting fields of f->output_data.mac directly. Call init_frame_faces. (Fdelete_frame) [macintosh]: Remove unused code. (Fmodify_frame_parameters) [macintosh]: Call x_set_frame_parameters instead of mac_set_frame_parameters. * frame.h [macintosh]: Define menu_bar_lines field in struct frame. Define FRAME_EXTERNAL_MENU_BAR macro. * keyboard.c [macintosh]: Include macterm.h. (kbd_buffer_get_event) [macintosh]: Generate delete_window_event and menu_bar_activate_event type events as for X and NT. (make_lispy_event) [macintosh]: Construct lisp events of type MENU_BAR_EVENT as for X and NT. * sysdep.c [macintosh]: Remove declaration for sys_signal. Include stdlib.h. Remove definition of Vx_bitmap_file_path. (sys_subshell) [macintosh]: Remove definition entirely. (init_sys_modes) [macintosh]: Do not initialize Vwindow_system and Vwindow_system_version here. Remove initialization of Vx_bitmap_file_path. (read_input_waiting): Correct the number of parameters passed to read_socket_hook. Move all Macintosh functions to mac/mac.c. * term.c [macintosh]: Include macterm.h. * window.c [macintosh]: Include macterm.h. * xdisp.c [macintosh]: Include macterm.h. Declare set_frame_menubar and pending_menu_activation. (echo_area_display) [macintosh]: Do not return if terminal frame is the selected frame. (update_menu_bar) [macintosh]: Check FRAME_EXTERNAL_MENU_BAR (f). Allow only the selected frame to set menu bar. (redisplay_window) [macintosh]: Obtain menu bar to redisplay by calling FRAME_EXTERNAL_MENU_BAR (f). (display_menu_bar) [macintosh]: Check FRAME_MAC_P (f). * xfaces.c [macintosh]: Include macterm.h. Define x_display_info and check_x. Declare XCreateGC. Define x_create_gc and x_free_gc. Initialize font_sort_order. (x_face_list_fonts) [macintosh]: Use the same code as WINDOWSNT, but call x_list_fonts instead of w32_list_fonts. (Finternal_face_x_get_resource) [macintosh]: Do not call display_x_get_resource. (prepare_face_for_display) [macintosh]: Set xgcv.font. (realize_x_face) [macintosh]: Load the font if it is specified in ATTRS. (syms_of_xfaces) [macintosh]: Initialize Vscalable_fonts_allowed to Qt. * cus-edit.el (custom-button-face): Use 3D look for mac. (custom-button-pressed-face): Likewise. * faces.el (set-face-attributes-from-resources): Handle mac frames in the same way as x and w32 frames. (face-valid-attribute-values): Likewise. (read-face-attribute): Likewise. (defined-colors): Likewise. (color-defined-p): Likewise. (color-values): Likewise. (display-grayscale-p): Likewise. (face-set-after-frame-default): Likewise. (mode-line): Same default face as for x and w32. (tool-bar): Likewise. * frame.el: Remove call to frame-notice-user-settings at end of the file. * info.el (Info-fontify-node): make underlines invisible for mac as for x, pc, and w32 frame types. * term/mac-win.el: New file.
Diffstat (limited to 'mac/src')
-rw-r--r--mac/src/Emacs.r700
-rw-r--r--mac/src/EmacsMPW.r47
-rw-r--r--mac/src/chdir.c43
-rw-r--r--mac/src/mac.c2637
-rw-r--r--mac/src/macfns.c9913
-rw-r--r--mac/src/macmenu.c2206
-rw-r--r--mac/src/macterm.c12446
7 files changed, 27992 insertions, 0 deletions
diff --git a/mac/src/Emacs.r b/mac/src/Emacs.r
new file mode 100644
index 00000000000..4a66d7cf49c
--- /dev/null
+++ b/mac/src/Emacs.r
@@ -0,0 +1,700 @@
1/* Resource definitions for GNU Emacs on the Macintosh.
2 Copyright (C) 1999, 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 "Types.r"
24/* added for finder icon balloon help --ben */
25#include "Balloons.r"
26
27/* Define to use gnu icon */
28/* #define GNU_ICON 1 */
29
30resource 'STR#' (128) {
31 {
32 "TERM=macterm",
33 "TERMCAP=macterm:co#80:li#40:up=up:do=do:le=le:nd=nd:cm=cm:cs=cs:ce=ce:cd=cd:cl=cl:al=al:dl=dl:",
34 /* "HOME=/Ix/Data Files/Emacs Mac Port/emacs-20.4/mac/", */
35 /* "MAIL=/Ix/System Folder/Eudora Folder/In" */
36 }
37};
38
39resource 'STR#' (129) {
40 {
41 "emacs",
42 "-l",
43 "loadup"
44 }
45};
46
47/* added for finder icon balloon help --ben */
48resource 'hfdr' (-5696) { /*help for emacs icon*/
49 /*header component*/
50 HelpMgrVersion, hmDefaultOptions, 0, 0,
51 { /*icon component*/
52 HMSTRResItem { /*use 'STR ' resource 128*/
53 128
54 }
55 }
56};
57
58/* added for finder icon balloon help --ben */
59resource 'STR ' (128) { /*help message for emacs icon*/
60 "GNU Emacs\0xd1the extensible, customizable, self-documenting real-time display editor."
61};
62
63resource 'MENU' (128, preload) {
64 128,
65 textMenuProc,
66 0x7FFFFFFD,
67 enabled,
68 apple,
69 { /* array: 2 elements */
70 /* [1] */
71 "About Emacs\0xc9", noIcon, noKey, noMark, plain,
72 /* [2] */
73 "-", noIcon, noKey, noMark, plain
74 }
75};
76
77resource 'MBAR' (128, "MBAR for Menus1", preload) {
78 { /* array MenuArray: 1 element */
79 /* [1] */
80 128
81 }
82};
83
84resource 'WIND' (128, "Window", purgeable) {
85 {68, 33, 554, 754},
86 kWindowFullZoomGrowDocumentProc,
87 invisible,
88 goAway,
89 0x0,
90 "Terminal",
91 kWindowStaggerMainScreen
92};
93
94resource 'WIND' (129, "Terminal window", purgeable) {
95 {32, 8, 76, 620},
96 kWindowModalDialogProc,
97 invisible,
98 goAway,
99 0x0,
100 "Terminal",
101 kWindowDefaultPosition
102};
103
104resource 'WIND' (130, "Dialog window", purgeable) {
105 {32, 8, 42, 18},
106 kWindowModalDialogProc,
107 invisible,
108 goAway,
109 0x0,
110 "Terminal",
111 kWindowDefaultPosition
112};
113
114resource 'ALRT' (128, "About Box", purgeable) {
115 {40, 20, 160, 297},
116 128,
117 { /* array: 4 elements */
118 /* [1] */
119 OK, visible, silent,
120 /* [2] */
121 OK, visible, silent,
122 /* [3] */
123 OK, visible, silent,
124 /* [4] */
125 OK, visible, silent
126 },
127 centerMainScreen
128};
129
130resource 'DITL' (128, purgeable) {
131 { /* array DITLarray: 2 elements */
132 /* [1] */
133 {88, 185, 108, 265},
134 Button {
135 enabled,
136 "OK"
137 },
138 /* [2] */
139 {10, 60, 72, 278},
140 StaticText {
141 disabled,
142 "GNU Emacs 21.0.90 for Mac OS\n"
143 "(11 October 2000 release)\n"
144 "Report bugs to akochoi@users.sourceforge.net"
145 }
146 }
147};
148
149resource 'BNDL' (128) {
150 'EMAx',
151 0,
152 { /* array TypeArray: 2 elements */
153 /* [1] */
154 'FREF',
155 { /* array IDArray: 2 elements */
156 /* [1] */
157 0, 128,
158 /* [2] */
159 1, 129
160 },
161 /* [2] */
162 'ICN#',
163 { /* array IDArray: 2 elements */
164 /* [1] */
165 0, 128,
166 /* [2] */
167 1, 129
168 }
169 }
170};
171
172resource 'FREF' (128) {
173 'APPL',
174 0,
175 ""
176};
177
178resource 'FREF' (129) {
179 'TEXT',
180 1,
181 ""
182};
183
184resource 'vers' (1) {
185 0x1,
186 0x0,
187 development,
188 0x0,
189 0,
190 "d6",
191 "GNU Emacs 21.1 for Mac OS\n\0xa9 2"
192 "000 Free Software Foundation"
193};
194
195data 'EMAx' (0, "Owner resource") {
196 $"00" /* . */
197};
198
199#ifdef GNU_ICON
200resource 'ICN#' (128) {
201 { /* array: 2 elements */
202 /* [1] */
203 $"0000 0000 0000 0000 0000 0080 0000 0040"
204 $"0100 0030 0203 5808 0408 8400 0418 0220"
205 $"0420 0008 0464 9C80 04C1 0018 0000 0004"
206 $"118B 0120 000A 0000 0614 8180 0204 2080"
207 $"0468 0080 0480 4480 0000 0080 0148 08C0"
208 $"0120 00C0 0182 4020 0388 0120 0181 2040"
209 $"01E8 B040 00E0 70C0 0078 9880 003A 9880"
210 $"001E 4000 000F C0",
211 /* [2] */
212 $"0000 0000 0000 0100 0000 0180 0000 00E0"
213 $"0100 3030 0203 F818 063F FC18 0E3F FE38"
214 $"1C7F FF78 1CFF FFF8 1CFF FFF8 1E7F FFFC"
215 $"1FFF FF38 1FFF FF80 0FFF FF80 07FF FF80"
216 $"0FFF FF80 0FFF FFC0 01FF FFC0 03FF FFC0"
217 $"03FF FFC0 03FF FFE0 03FF FFE0 03FF FFE0"
218 $"01FF FFC0 01FF FFC0 00FF FFC0 007F FF80"
219 $"001F E700 000F C000 0004 80"
220 }
221};
222#else
223resource 'ICN#' (128) {
224 { /* array: 2 elements */
225 /* [1] */
226 $"0000 0000 0000 0000 0001 F000 07DE 0F60"
227 $"0860 0090 1200 0028 1200 0008 0800 0008"
228 $"0800 0008 1000 0004 1000 0004 2000 0004"
229 $"2000 0044 4018 12C2 4018 0002 4018 0082"
230 $"4002 0C42 2000 1E02 2004 1E42 2004 0C02"
231 $"2004 0042 2002 0082 5001 8F05 8800 7004"
232 $"0800 0008 0400 0010 0200 0060 01C0 0380"
233 $"003F FC00 2000 0000 4000 0000 80",
234 /* [2] */
235 $"0000 0000 0000 0000 0001 F000 07DF FF60"
236 $"0FFF FFF0 1FFF FFF8 1FFF FFF8 0FFF FFF8"
237 $"0FFF FFF8 1FFF FFFC 1FFF FFFC 3FFF FFFC"
238 $"3FFF FFFC 7FFF FFFE 7FFF FFFE 7FFF FFFE"
239 $"7FFF FFFE 3FFF FFFE 3FFF FFFE 3FFF FFFE"
240 $"3FFF FFFE 3FFF FFFE 7FFF FFFF FFFF FFFF"
241 $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
242 $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
243 }
244};
245#endif
246
247#ifdef GNU_ICON
248resource 'icl4' (128) {
249 $"0000 0000 0000 0000 0000 0000 0000 0000"
250 $"0000 0000 0000 0000 0000 000C 0000 0000"
251 $"0000 0000 0000 0000 0000 000C F000 0000"
252 $"0000 0000 0000 0000 0000 0000 CFD0 0000"
253 $"0000 000F 0000 0000 00CC 0000 00FF 0000"
254 $"0000 00F0 0000 00FF CFCF F000 000C F000"
255 $"0000 0FD0 00CD FD0C F000 CF00 000C D000"
256 $"0000 CFC0 00DF F000 C000 00F0 00FC C000"
257 $"000C DF00 0DFD 0CD0 0000 DCDD 0DC0 F000"
258 $"000D 0F00 DFFC 0F00 FDDF FFDD FC0D D000"
259 $"000C 0F00 FFC0 DCDF 0000 DC00 00CF F000"
260 $"000C 0CD0 0C0C CDC0 000C 0CCD CCCC CF00"
261 $"000F 00CF F0DC FCFF DDC0 CDDF 00FD C000"
262 $"000D D000 CDC0 FCFC 0CDC CCCD C000 0000"
263 $"0000 CFF0 D00F 0F0C F0CD CCCF F000 0000"
264 $"0000 0CFC 00CD 0F0D D0FD CCCD F000 0000"
265 $"0000 CFCC DFF0 FC0C DCCC CCCC F000 0000"
266 $"0000 DFC0 FDDC 0C0C DFC0 CEDC FC00 0000"
267 $"0000 000C DDCC CDC0 C00C CCCC FC00 0000"
268 $"0000 00CF CF0C FC0C 0000 F00D FF00 0000"
269 $"0000 00CF D0FC 0CCC C000 0CCC FF00 0000"
270 $"0000 00CF F0DC 0CFC CFCD DDDC DCF0 0000"
271 $"0000 00FF FCD0 FDCC DDC0 00DF 0DF0 0000"
272 $"0000 00CF FDCD 0DCF CDFC CC0D 0FC0 0000"
273 $"0000 000F FFFC FCD0 F0FF C000 DF00 0000"
274 $"0000 000C FFF0 CDCD DFFF DCCC FF00 0000"
275 $"0000 0000 CFFF FC0D F0CF F000 FC00 0000"
276 $"0000 0000 0CFF FDF0 F0DF FDDD F000 0000"
277 $"0000 0000 000F FFFC CFC0 0DDD 0000 0000"
278 $"0000 0000 0000 FFFF FF00 0000 0000 0000"
279 $"0000 0000 0000 0C00 C0"
280};
281#else
282resource 'icl4' (128) {
283 $"0000 0000 0000 0000 0000 0000 0000 0000"
284 $"0000 0000 0000 0000 0000 0000 0000 0000"
285 $"0000 0000 0000 000F FFFF 0000 0000 0000"
286 $"0000 0FFF FF0F FFF0 0000 FFFF 0FF0 0000"
287 $"0000 FCCC CFF0 0000 0000 0000 FCCF 0000"
288 $"000F 0DED CC00 0000 0000 0000 0DEC F000"
289 $"000F 0DED C000 0000 0000 0000 00DD F000"
290 $"0000 F0D0 0000 0000 0000 0000 0000 F000"
291 $"0000 FC00 0000 0000 0000 0000 0000 F000"
292 $"000F 0000 0000 0000 0000 0000 0000 0F00"
293 $"000F 0000 0000 0000 0000 0000 0000 0F00"
294 $"00F0 0000 0000 0000 0000 0000 0000 0F00"
295 $"00F0 0000 0000 0000 0000 0000 DEC0 0F00"
296 $"0F00 0000 00CE EC00 0CCC CCCC FFC0 00F0"
297 $"0F00 0000 0CDF FD0C C000 000D CDC0 00F0"
298 $"0F00 0000 00CE ECD0 0000 CC00 D000 00F0"
299 $"0F00 0000 0000 00D0 000C EEC0 0D00 00F0"
300 $"00F0 0000 0000 0D00 00CE AAEC 0D00 00F0"
301 $"00F0 0000 0000 0D00 00CE AAEC 0D00 00F0"
302 $"00F0 0000 0000 0D00 000C EEC0 0D00 00F0"
303 $"00F0 0000 0000 0D00 0000 CC00 0D00 00F0"
304 $"00F0 0000 0000 0CD0 0000 0000 E000 00F0"
305 $"0F0F 0000 0000 00CD D000 EEEE 0000 0F0F"
306 $"F000 F000 0000 0000 0EEE 0000 0000 0F00"
307 $"0000 F000 0000 0000 0000 0D00 0000 FC00"
308 $"0000 0F00 0000 0000 0000 0D00 000F C000"
309 $"0000 00F0 0000 0000 0000 0C00 0FFC C000"
310 $"0000 C00F FF00 0000 0000 00EE ECCC 0000"
311 $"000D 0000 0CFF FFFF FEEE EECC CCC0 0000"
312 $"0CF0 0000 0000 CCCC CCCC CC0C 0C00 0C00"
313 $"CEC0 0000 0000 0000 0000 0000 0000 0DC0"
314 $"FD00 0000 0000 0000 0000 0000 0000 00D0"
315};
316#endif
317
318#ifdef GNU_ICON
319resource 'icl8' (128) {
320 $"0000 0000 0000 0000 0000 0000 0000 0000"
321 $"0000 0000 0000 0000 0000 0000 0000 0000"
322 $"0000 0000 0000 0000 0000 0000 0000 0000"
323 $"0000 0000 0000 002B 0000 0000 0000 0000"
324 $"0000 0000 0000 0000 0000 0000 0000 0000"
325 $"0000 0000 0000 002B FF00 0000 0000 0000"
326 $"0000 0000 0000 0000 0000 0000 0000 0000"
327 $"0000 0000 0000 0000 2BFF F900 0000 0000"
328 $"0000 0000 0000 00FF 0000 0000 0000 0000"
329 $"0000 2B2B 0000 0000 0000 FFFF 0000 0000"
330 $"0000 0000 0000 FF00 0000 0000 0000 FFFF"
331 $"2BFF 2BFF FF00 0000 0000 002B FF00 0000"
332 $"0000 0000 00FF F900 0000 2BF9 FFF9 002B"
333 $"FF00 0000 2BFF 0000 0000 002B F900 0000"
334 $"0000 0000 2BFF 2B00 0000 F9FF FF00 0000"
335 $"2B00 0000 0000 FF00 0000 FF2B 2B00 0000"
336 $"0000 002B F9FF 0000 00F9 FFF9 002B F900"
337 $"0000 0000 F92B F9F9 00F9 2B00 FF00 0000"
338 $"0000 00F9 00FF 0000 F9FF FF2B 00FF 0000"
339 $"FFF9 F9FF FFFF F9F9 FF2B 00F9 F900 0000"
340 $"0000 002B 00FF 0000 FFFF 2B00 F92B F9FF"
341 $"0000 0000 F92B 0000 0000 2BFF FF00 0000"
342 $"0000 002B 002B F900 002B 002B 2BF9 2B00"
343 $"0000 002B 002B 2BF9 2B2B 2B2B 2BFF 0000"
344 $"0000 00FF 0000 2BFF FF00 F92B FF2B FFFF"
345 $"F9F9 2B00 2BF9 F9FF 0000 FFF9 2B00 0000"
346 $"0000 00F9 F900 0000 2BF9 2B00 FF2B FF2B"
347 $"002B F92B 2B2B 2BF9 2B00 0000 0000 0000"
348 $"0000 0000 2BFF FF00 F900 00FF 00FF 002B"
349 $"FF00 2BF9 2B2B 2BFF FF00 0000 0000 0000"
350 $"0000 0000 002B FF2B 0000 2BF9 00FF 00F9"
351 $"F900 FFF9 2B2B 2BF9 FF00 0000 0000 0000"
352 $"0000 0000 2BFF 2B2B F9FF FF00 FF2B 002B"
353 $"F92B 2B2B 2B2B 2B2B FF00 0000 0000 0000"
354 $"0000 0000 F9FF 2B00 FFF9 F92B 002B 002B"
355 $"F9FF 2B00 2BFC F92B FF2B 0000 0000 0000"
356 $"0000 0000 0000 002B F9F9 2B2B 2BF9 2B00"
357 $"2B00 002B 2B2B 2B2B FF2B 0000 0000 0000"
358 $"0000 0000 0000 2BFF 2BFF 002B FF2B 002B"
359 $"0000 0000 FF00 00F9 FFFF 0000 0000 0000"
360 $"0000 0000 0000 2BFF F900 FF2B 002B 2B2B"
361 $"2B00 0000 002B 2B2B FFFF 0000 0000 0000"
362 $"0000 0000 0000 2BFF FF00 F92B 002B FF2B"
363 $"2BFF 2BF9 F9F9 F92B F92B FF00 0000 0000"
364 $"0000 0000 0000 FFFF FF2B F900 FFF9 2B2B"
365 $"F9F9 2B00 0000 F9FF 00F9 FF00 0000 0000"
366 $"0000 0000 0000 2BFF FFF9 2BF9 00F9 2BFF"
367 $"2BF9 FF2B 2B2B 00F9 00FF 2B00 0000 0000"
368 $"0000 0000 0000 00FF FFFF FF2B FF2B F900"
369 $"FF00 FFFF 2B00 0000 F9FF 0000 0000 0000"
370 $"0000 0000 0000 002B FFFF FF00 2BF9 2BF9"
371 $"F9FF FFFF F92B 2B2B FFFF 0000 0000 0000"
372 $"0000 0000 0000 0000 2BFF FFFF FF2B 00F9"
373 $"FF00 2BFF FF00 0000 FF2B 0000 0000 0000"
374 $"0000 0000 0000 0000 002B FFFF FFF9 FF00"
375 $"FF00 F9FF FFF9 F9F9 FF00 0000 0000 0000"
376 $"0000 0000 0000 0000 0000 00FF FFFF FF2B"
377 $"2BFF 2B00 00F9 F9F9 0000 0000 0000 0000"
378 $"0000 0000 0000 0000 0000 0000 FFFF FFFF"
379 $"FFFF 0000 0000 0000 0000 0000 0000 0000"
380 $"0000 0000 0000 0000 0000 0000 002B 0000"
381 $"2B"
382};
383#else
384resource 'icl8' (128) {
385 $"0000 0000 0000 0000 0000 0000 0000 0000"
386 $"0000 0000 0000 0000 0000 0000 0000 0000"
387 $"0000 0000 0000 0000 0000 0000 0000 0000"
388 $"0000 0000 0000 0000 0000 0000 0000 0000"
389 $"0000 0000 0000 0000 0000 0000 0000 00FF"
390 $"FFFF FFFF 0000 0000 0000 0000 0000 0000"
391 $"0000 0000 00FF FFFF FFFF F5FF FFFF FFF5"
392 $"F5F5 F5F5 FFFF FFFF 00FF FF00 0000 0000"
393 $"0000 0000 FFF6 F6F6 F6FF FFF5 F5F5 F5F5"
394 $"F5F5 F5F5 F5F5 F5F5 FFF7 F6FF 0000 0000"
395 $"0000 00FF F5F9 FBF9 F7F7 F5F5 F5F5 F5F5"
396 $"F5F5 F5F5 F5F5 F5F5 F5F9 FCF6 FF00 0000"
397 $"0000 00FF F5F9 FBF9 F7F5 F5F5 F5F5 F5F5"
398 $"F5F5 F5F5 F5F5 F5F5 F5F5 F9F9 FF00 0000"
399 $"0000 0000 FFF5 F9F5 F5F5 F5F5 F5F5 F5F5"
400 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FF00 0000"
401 $"0000 0000 FFF7 F5F5 F5F5 F5F5 F5F5 F5F5"
402 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FF00 0000"
403 $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
404 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF 0000"
405 $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
406 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF 0000"
407 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
408 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF 0000"
409 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
410 $"F5F5 F5F5 F5F5 F5F5 F9FC F6F5 F5FF 0000"
411 $"00FF F5F5 F5F5 F5F5 F5F5 F7FB FBF7 F5F5"
412 $"F5F6 F6F7 F7F7 F7F8 FFFF F7F5 F5F5 FF00"
413 $"00FF F5F5 F5F5 F5F5 F5F6 F9FF FFF9 F5F7"
414 $"F7F5 F5F5 F5F5 F5F9 F7F9 F6F5 F5F5 FF00"
415 $"00FF F5F5 F5F5 F5F5 F5F5 F7FB FCF7 F9F5"
416 $"F5F5 F5F5 F6F6 F5F5 F9F5 F5F5 F5F5 FF00"
417 $"00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F9F5"
418 $"F5F5 F5F7 FBFB F7F5 F5F9 F5F5 F5F5 FF00"
419 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5"
420 $"F5F5 F7FB FDFD ACF7 F5F9 F5F5 F5F5 FF00"
421 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5"
422 $"F5F5 F7FB FDFD ACF7 F5F9 F5F5 F5F5 FE00"
423 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5"
424 $"F5F5 F5F7 FBFB F7F5 F5F9 F5F5 F5F5 FE00"
425 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5"
426 $"F5F5 F5F5 F7F7 F5F5 F5FA F5F5 F5F5 FE00"
427 $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F7 F9F5"
428 $"F5F5 F5F5 F5F5 F5F5 FBF5 F5F5 F5F5 FF00"
429 $"00FF F5FF F5F5 F5F5 F5F5 F5F5 F5F5 F7F9"
430 $"F9F5 F5F5 FBFB FBFB F5F5 F5F5 F5FE F5FF"
431 $"FFF5 F5F5 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5"
432 $"F5FB FBFB F5F5 F5F5 F5F5 F5F5 F5FF F5F5"
433 $"F5F5 F5F5 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5"
434 $"F5F5 F5F5 F5F9 F5F5 F5F5 F5F5 FFF6 F5F5"
435 $"F5F5 F5F5 F5FF F5F5 F5F5 F5F5 F5F5 F5F5"
436 $"F5F5 F5F5 F5F9 F5F5 F5F5 F5FF F6F5 F5F5"
437 $"F5F5 F5F5 F5F5 FFF5 F5F5 F5F5 F5F5 F5F5"
438 $"F5F5 F5F5 F5F6 F5F5 F5FF FFF7 F6F5 F5F5"
439 $"F5F5 F5F5 F7F5 F5FF FFFF F5F5 F5F5 F5F5"
440 $"F5F5 F5F5 F5F5 ACAC ACF7 F6F6 F5F5 F5F5"
441 $"F5F5 F5F9 F5F5 F5F5 F5F7 FFFF FFFF FFFF"
442 $"FFFC FCAC ACAC F6F6 F7F6 F6F5 F5F5 F5F5"
443 $"F5F6 FFF5 F5F5 F5F5 F5F5 F5F5 F6F7 F6F7"
444 $"F6F7 F6F6 F6F6 F5F6 F5F6 F5F5 F5F7 F5F5"
445 $"F6FC F7F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
446 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F9 F7F5"
447 $"FFF9 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
448 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F9F5"
449};
450#endif
451
452#ifdef GNU_ICON
453resource 'ics#' (128) {
454 { /* array: 2 elements */
455 /* [1] */
456 $"0000 0008 11E6 26B4 2EEA 2906 5B14 36D8"
457 $"2EA8 1A28 1D8C 1B5C 1EC8 0FE8 0780",
458 /* [2] */
459 $"0010 001C 11FE 37FE 7FFE 7FFE 7FFE 3FF8"
460 $"3FF8 1FF8 1FFC 1FFC 1FF8 0FF8 07F0 0280"
461 }
462};
463#else
464resource 'ics#' (128) {
465 { /* array: 2 elements */
466 /* [1] */
467 $"0000 0000 0001 604B 6000 6002 0831 0078"
468 $"1079 1030 1001 0802 063C 01C0",
469 /* [2] */
470 $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
471 $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
472 }
473};
474#endif
475
476#ifdef GNU_ICON
477resource 'ics4' (128) {
478 $"0000 0000 000C 0000 0000 0000 000C FD00"
479 $"000F 000F FFF0 0FF0 00FD 0FFC F0FF 0FD0"
480 $"0DF0 FFFD FFFD FDF0 0CFD FCDF 0CDD CFF0"
481 $"0FDF FDFF DDDF CFC0 00FF DFFD FFCF F000"
482 $"00FC FFFC FCED F000 000F FCFC CCFD F000"
483 $"000F FFCF FDDD FF00 000F FDFF DFCF FF00"
484 $"000F FFFD FFDC F000 0000 FFFF FFFD F000"
485 $"0000 0FFF FCDD 0000 0000 00C0 C0"
486};
487#else
488resource 'ics4' (128) {
489 $"0000 0000 0000 0000 0000 0000 0000 0000"
490 $"0000 0000 0000 00DE CEEC 000C CCCC CCFF"
491 $"DFFD 0CC0 0000 0DCD CEEC D000 00CC 00D0"
492 $"0000 D000 0CEE C00D 000D 0000 CEAA EC0D"
493 $"000D 0000 CEAA EC0D 000D 0000 0CEE C00D"
494 $"000D 0000 00CC 000D 000C D000 0000 00E0"
495 $"0000 CDD0 00EE EE00 0000 000E EE00 0000"
496 $"0000 0000 000D 0000 0000 0000 000D"
497};
498#endif
499
500#ifdef GNU_ICON
501resource 'ics8' (128) {
502 $"0000 0000 0000 0000 0000 002B 0000 0000"
503 $"0000 0000 0000 0000 0000 002B FFF9 0000"
504 $"0000 00FF 0000 00FF FFFF FF00 00FF FF00"
505 $"0000 FFF9 00FF FF2B FF00 FFFF 00FF F900"
506 $"00F9 FF00 FFFF FFF9 FFFF FFF9 FFF9 FF00"
507 $"002B FFF9 FF2B F9FF 002B F9F9 2BFF FF00"
508 $"00FF F9FF FFF9 FFFF F9F9 F9FF 2BFF 2B00"
509 $"0000 FFFF F9FF FFF9 FFFF 2BFF FF00 0000"
510 $"0000 FF2B FFFF FF2B FF2B FCF9 FF00 0000"
511 $"0000 00FF FF2B FF2B 2B2B FFF9 FF00 0000"
512 $"0000 00FF FFFF 2BFF FFF9 F9F9 FFFF 0000"
513 $"0000 00FF FFF9 FFFF F9FF 2BFF FFFF 0000"
514 $"0000 00FF FFFF FFF9 FFFF F92B FF00 0000"
515 $"0000 0000 FFFF FFFF FFFF FFF9 FF00 0000"
516 $"0000 0000 00FF FFFF FF2B F9F9 0000 0000"
517 $"0000 0000 0000 2B00 2B"
518};
519#else
520resource 'ics8' (128) {
521 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
522 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5"
523 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F9FC"
524 $"F7FB FBF7 F5F5 F5F6 F6F7 F7F7 F7F8 FFFF"
525 $"F9FF FFF9 F5F7 F7F5 F5F5 F5F5 F5F9 F7F9"
526 $"F7FB FCF7 F9F5 F5F5 F5F5 F6F6 F5F5 F9F5"
527 $"F5F5 F5F5 F9F5 F5F5 F5F7 FBFB F7F5 F5F9"
528 $"F5F5 F5F9 F5F5 F5F5 F7FB FDFD ACF7 F5F9"
529 $"F5F5 F5F9 F5F5 F5F5 F7FB FDFD ACF7 F5F9"
530 $"F5F5 F5F9 F5F5 F5F5 F5F7 FBFB F7F5 F5F9"
531 $"F5F5 F5F9 F5F5 F5F5 F5F5 F7F7 F5F5 F5FA"
532 $"F5F5 F5F7 F9F5 F5F5 F5F5 F5F5 F5F5 FBF5"
533 $"F5F5 F5F5 F7F9 F9F5 F5F5 FBFB FBFB F5F5"
534 $"F5F5 F5F5 F5F5 F5FB FBFB F5F5 F5F5 F5F5"
535 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5 F5F5"
536 $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5 F5F5"
537};
538#endif
539
540resource 'ICN#' (129) {
541 { /* array: 2 elements */
542 /* [1] */
543 $"0000 0300 0000 1C80 0000 E0B0 0007 00F0"
544 $"0038 0070 01C0 0038 0E00 8038 7008 4038"
545 $"8008 2038 8004 0038 8080 041C C086 301C"
546 $"C087 311C 4007 BB8C 6167 378C 6170 070E"
547 $"2130 6006 3031 FC06 3047 FE06 10E7 FF02"
548 $"1867 FF82 1847 FF03 080F FE07 0C1F E03C"
549 $"0C0F C1F0 0406 0F80 0400 7C00 0203 E000"
550 $"031F 0000 01F8 0000 00C0",
551 /* [2] */
552 $"0000 0300 0000 1F80 0000 FFB0 0007 FFF0"
553 $"003F FFF0 01FF FFF8 0FFF FFF8 7FFF FFF8"
554 $"FFFF FFF8 FFFF FFF8 FFFF FFFC FFFF FFFC"
555 $"FFFF FFFC 7FFF FFFC 7FFF FFFC 7FFF FFFE"
556 $"3FFF FFFE 3FFF FFFE 3FFF FFFE 1FFF FFFE"
557 $"1FFF FFFE 1FFF FFFF 0FFF FFFF 0FFF FFFC"
558 $"0FFF FFF0 07FF FF80 07FF FC00 03FF E000"
559 $"03FF 0000 01F8 0000 00C0"
560 }
561};
562
563resource 'icl4' (129) {
564 $"0000 0000 0000 0000 0000 00FF 0000 0000"
565 $"0000 0000 0000 0000 000F FF0C F000 0000"
566 $"0000 0000 0000 0000 FFF0 0000 F0FF 0000"
567 $"0000 0000 0000 0FFF 0000 0000 FFDF 0000"
568 $"0000 0000 00FF F000 0000 0000 CFEF 0000"
569 $"0000 000F FF00 0000 0000 0000 00ED F000"
570 $"0000 FFF0 0000 0000 DC00 0000 00AD F000"
571 $"0FFF 0000 0000 E000 0DC0 0000 00FE F000"
572 $"F000 0000 0000 DC00 0CD0 0000 00FE F000"
573 $"F000 0000 CC00 CC00 00C0 0C00 00FA F000"
574 $"F000 0000 D000 00C0 00C0 0DCC 00CF EF00"
575 $"EF00 0000 E000 0EED C0ED C0DD 000F EF00"
576 $"EFC0 0000 DC00 CEEF CCEF D0DD 000F AF00"
577 $"DFC0 000C 00C0 CEFE D0EF D0ED E00C FF00"
578 $"0EFC 00CD 0EDC 0DDE 00DF CDEE EC00 FF00"
579 $"0EFC 000E 0DEE 00CC 00CC CDFE D000 FFF0"
580 $"0DFC 000D CCFE C00C DEDD 0CDC 0000 CFF0"
581 $"00EF C00C 0CDE 00CE FFFF AE00 0000 0FF0"
582 $"00EF C000 DD0C 0DEE FFFF FEED C000 0FF0"
583 $"00DF C000 DFE0 CDFF FFFF FFAF C000 0CF0"
584 $"000E FC00 DEE0 CAFF FFFF FFFE D000 0CFD"
585 $"000E FC00 CED0 DEFF FFFF FFFE C000 0CFF"
586 $"000D FC00 0C0C EFFF FFFF AEDD 00CC CFFF"
587 $"0000 EF00 000D EFFF FADD C00C CCFF FED0"
588 $"0000 EF00 000C FAFF AED0 CCCF FFEE D000"
589 $"0000 DF00 000C DEED CCCC FFFE ED00 0000"
590 $"0000 0E00 0000 0CCC CFFF EED0 0000 0000"
591 $"0000 0DFD 0000 CCFF FEED 0000 0000 0000"
592 $"0000 00EF DDDF FFEE D000 0000 0000 0000"
593 $"0000 000E FFFE ED00 0000 0000 0000 0000"
594 $"0000 0000 DDD0"
595};
596
597resource 'icl8' (129) {
598 $"0000 0000 0000 0000 0000 0000 0000 0000"
599 $"0000 0000 0000 FFFF 0000 0000 0000 0000"
600 $"0000 0000 0000 0000 0000 0000 0000 0000"
601 $"0000 00FF FFFF 00F7 FF00 0000 0000 0000"
602 $"0000 0000 0000 0000 0000 0000 0000 0000"
603 $"FFFF FF00 0000 0000 FF00 FFFF 0000 0000"
604 $"0000 0000 0000 0000 0000 0000 00FF FFFF"
605 $"0000 0000 0000 0000 FFFF FAFF 0000 0000"
606 $"0000 0000 0000 0000 0000 FFFF FF00 0000"
607 $"0000 0000 0000 0000 F7FF FCFF 0000 0000"
608 $"0000 0000 0000 00FF FFFF 0000 0000 0000"
609 $"F500 0000 0000 0000 0000 FCFA FF00 0000"
610 $"0000 0000 FFFF FF00 0000 0000 0000 0000"
611 $"812B 0000 0000 0000 0000 FDFA FF00 0000"
612 $"00FF FFFF 0000 0000 0000 0000 FBF5 0000"
613 $"0081 2B00 0000 0000 0000 FFFC FF00 0000"
614 $"FF00 0000 0000 0000 00F5 0000 F9F8 0000"
615 $"00F8 FA00 0000 0000 0000 FFFC FF00 0000"
616 $"FF00 0000 0000 0000 F8F8 0000 F7F8 0000"
617 $"00F5 2B00 002B 0000 0000 FFFD FF00 0000"
618 $"FF00 0000 0000 00F5 FA00 0000 00F5 F800"
619 $"0000 2B00 00FA F8F6 0000 F7FF FCFF 0000"
620 $"FCFF 0000 0000 0000 FB00 0000 00FB FCF9"
621 $"F600 FBFA F700 5656 0000 00FF FCFF 0000"
622 $"FCFF F700 0000 0000 81F6 0000 F8FC ACFE"
623 $"F72B ACFE 5600 F9FA 0000 00FF FDFF 0000"
624 $"F9FF F700 0000 F5F7 F500 F600 2BAC FEFC"
625 $"FA00 FCFF 81F5 FB81 FBF5 00F7 FFFF 0000"
626 $"00FC FFF6 0000 2B81 00FC 81F8 0081 81FC"
627 $"F500 FAFF 2B81 ACFC FCF6 0000 FFFF 0000"
628 $"00FC FFF6 0000 00FB 0081 FCAC F500 F82B"
629 $"0000 F8F8 2B81 FFAC F900 0000 FFFF FF00"
630 $"00F9 FFF6 0000 0081 F6F8 FFAC F700 00F8"
631 $"F9FC FA56 00F6 562B 0000 0000 F7FF FF00"
632 $"0000 FCFF F700 00F7 002B FAFB F500 F7FC"
633 $"FEFF FFFF FDFB F500 0000 0000 00FF FF00"
634 $"0000 FCFF F700 0000 F9FA F5F8 0081 FCAC"
635 $"FFFF FFFF FFFC AC56 2B00 0000 00FF FF00"
636 $"0000 F9FF F700 0000 81FF AC00 F781 FFFF"
637 $"FFFF FFFF FFFF FDFE F800 0000 00F7 FF00"
638 $"0000 00FC FFF7 0000 56FC FBF5 F7FD FFFF"
639 $"FFFF FFFF FFFF FFAC 8100 0000 00F6 FFF9"
640 $"0000 00FC FFF7 0000 2BAC 5600 F9FC FFFF"
641 $"FFFF FFFF FFFF FFFB F700 0000 00F7 FFFF"
642 $"0000 00F9 FFF7 0000 F5F6 002B FBFE FFFF"
643 $"FFFF FFFE FDFC FA56 0000 F7F7 F7FF FFFF"
644 $"0000 0000 FCFF 0000 0000 00FA ACFF FFFF"
645 $"FFFD 8156 2BF5 00F7 F7F7 FFFF FFFC F900"
646 $"0000 0000 FCFF 0000 0000 00F7 FEFD FFFE"
647 $"FDFC F900 F7F7 F7FF FFFF FCFC F900 0000"
648 $"0000 0000 F9FF 0000 0000 00F6 56AC FBF9"
649 $"F7F6 F7F7 FFFF FFFC FCF9 0000 0000 0000"
650 $"0000 0000 00FC 0000 0000 0000 002B F7F7"
651 $"F7FF FFFF FCFC F900 0000 0000 0000 0000"
652 $"0000 0000 00F9 FFF9 0000 0000 F7F7 FFFF"
653 $"FFFC FCF9 0000 0000 0000 0000 0000 0000"
654 $"0000 0000 0000 FCFF F9F9 F9FF FFFF FCFC"
655 $"F900 0000 0000 0000 0000 0000 0000 0000"
656 $"0000 0000 0000 00FC FFFF FFFC FCF9 0000"
657 $"0000 0000 0000 0000 0000 0000 0000 0000"
658 $"0000 0000 0000 0000 FAFA F9"
659};
660
661resource 'ics#' (129) {
662 { /* array: 2 elements */
663 /* [1] */
664 $"0030 01CC 0E04 7006 8006 8006 8352 4412"
665 $"44C3 49F1 2BF1 23C7 23B8 01C0 1E",
666 /* [2] */
667 $"0030 01FC 0FFC 7FFE FFFE FFFE FFFE 7FFE"
668 $"7FFF 7FFF 3FFF 3FFF 3FF8 3FC0 1E"
669 }
670};
671
672resource 'ics4' (129) {
673 $"0000 0000 0CFF C000 0000 0CCF FFC0 EE00"
674 $"00CC FFFC 0000 CEC0 CFFF C0C0 C000 0ED0"
675 $"F000 C0C0 CC00 0FD0 F000 C0CD 0CCC 0DA0"
676 $"FC0C C0DF CACD CCF0 DF0C DFCD 0DDA C0FC"
677 $"CF0C CD0C EEDC 00EF 0FC0 FCCF FFFE C0DF"
678 $"0DF0 DCDF FFFA C0CF 0CF0 0CAF FEDC CFFD"
679 $"00F0 0CEE DCFF FDC0 00CD 00CF FFDC 0000"
680 $"000D FFFD C000 0000 0000 CC"
681};
682
683resource 'ics8' (129) {
684 $"0000 0000 0000 0000 F5F7 FFFF 2BF5 0000"
685 $"0000 0000 00F6 F7FF FFFF F600 ACAC 0000"
686 $"0000 F6F7 FFFF FFF6 0000 0000 F8AC F700"
687 $"2BFF FFFF F600 F600 F8F5 0000 00AC FA00"
688 $"FFF5 0000 F6F5 F700 F6F6 F500 F5FE FA00"
689 $"FFF5 00F5 F700 F756 F5F8 2BF7 0081 FDF5"
690 $"FF2B 00F6 F700 FAFE F7FD F8FA 2BF7 FF00"
691 $"56FF 00F7 56FF 2B56 F556 56FD F800 FEF7"
692 $"2BFF F5F6 F7FA F5F8 ACFC F92B 0000 FBFF"
693 $"00FF F700 FFF8 F8FE FFFF FFFC F600 56FF"
694 $"0056 FF00 FAF7 81FF FFFF FFFD 2B00 F6FF"
695 $"002B FFF5 002B FDFF FFFC 56F7 F7FF FF81"
696 $"0000 FFF5 00F6 FCFB FAF7 FFFF FFF9 F600"
697 $"0000 F8F9 0000 F7FF FFFF F9F6 0000 0000"
698 $"0000 0081 FFFF FFF9 F600 0000 0000 0000"
699 $"0000 0000 F8F6"
700};
diff --git a/mac/src/EmacsMPW.r b/mac/src/EmacsMPW.r
new file mode 100644
index 00000000000..c4ff17f9914
--- /dev/null
+++ b/mac/src/EmacsMPW.r
@@ -0,0 +1,47 @@
1/* Resource definitions for GNU Emacs on the Macintosh when building
2 under MPW.
3
4 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs; see the file COPYING. If not, write to
20the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
22
23/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */
24
25#include "Types.r"
26#include "CodeFragmentTypes.r"
27
28resource 'SIZE' (-1) {
29 reserved,
30 acceptSuspendResumeEvents,
31 reserved,
32 canBackground,
33 doesActivateOnFGSwitch,
34 backgroundAndForeground,
35 dontGetFrontClicks,
36 ignoreAppDiedEvents,
37 is32BitCompatible,
38 isHighLevelEventAware,
39 onlyLocalHLEvents,
40 notStationeryAware,
41 dontUseTextEditServices,
42 reserved,
43 reserved,
44 reserved,
45 16777216,
46 16777216
47};
diff --git a/mac/src/chdir.c b/mac/src/chdir.c
new file mode 100644
index 00000000000..5bf9354b4f5
--- /dev/null
+++ b/mac/src/chdir.c
@@ -0,0 +1,43 @@
1/* Implementation of chdir on the Mac for use with make-docfile.
2 Copyright (C) 1999, 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 <string.h>
24#include <Files.h>
25#include <TextUtils.h>
26
27int chdir(const char *path)
28{
29 WDPBRec wdpb;
30
31 Str255 mypath;
32 OSErr error;
33
34 strcpy(mypath, path);
35 c2pstr(mypath);
36
37 wdpb.ioNamePtr = mypath;
38 wdpb.ioVRefNum = 0;
39 wdpb.ioWDDirID = 0;
40 error = PBHSetVolSync(&wdpb);
41
42 return error == noErr ? 0 : -1;
43}
diff --git a/mac/src/mac.c b/mac/src/mac.c
new file mode 100644
index 00000000000..08d2aa2d8bb
--- /dev/null
+++ b/mac/src/mac.c
@@ -0,0 +1,2637 @@
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_unix_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
153unix_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 (unix_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_IFLNK;
334 buf->st_mode &= ~S_IFREG;
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 return result;
372
373 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
374 return -1;
375
376 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
377 if (len > -1)
378 {
379 fully_resolved_name[len] = '\0';
380 /* in fact our readlink terminates strings */
381 return lstat (fully_resolved_name, sb);
382 }
383 else
384 return lstat (true_pathname, sb);
385}
386
387
388#if __MRC__
389/* CW defines fstat in stat.mac.c while MPW does not provide this
390 function. Without the information of how to get from a file
391 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
392 to implement this function. Fortunately, there is only one place
393 where this function is called in our configuration: in fileio.c,
394 where only the st_dev and st_ino fields are used to determine
395 whether two fildes point to different i-nodes to prevent copying
396 a file onto itself equal. What we have here probably needs
397 improvement. */
398
399int
400fstat (int fildes, struct stat *buf)
401{
402 buf->st_dev = 0;
403 buf->st_ino = fildes;
404 buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */
405 return 0; /* success */
406}
407#endif /* __MRC__ */
408
409
410/* Adapted from Think Reference code example. */
411
412int
413mkdir (const char *dirname, int mode)
414{
415#pragma unused(mode)
416
417 HFileParam hfpb;
418 char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1];
419
420 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
421 return -1;
422
423 if (unix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0)
424 return -1;
425
426 c2pstr (mac_pathname);
427 hfpb.ioNamePtr = mac_pathname;
428 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
429 hfpb.ioDirID = 0; /* parent is the root */
430
431 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
432 /* just return the Mac OSErr code for now */
433 return errno == noErr ? 0 : -1;
434}
435
436
437#undef rmdir
438sys_rmdir (const char *dirname)
439{
440 HFileParam hfpb;
441 char mac_pathname[MAXPATHLEN+1];
442
443 if (unix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0)
444 return -1;
445
446 c2pstr (mac_pathname);
447 hfpb.ioNamePtr = mac_pathname;
448 hfpb.ioVRefNum = 0; /* ignored unless name is invalid */
449 hfpb.ioDirID = 0; /* parent is the root */
450
451 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
452 return errno == noErr ? 0 : -1;
453}
454
455
456#ifdef __MRC__
457/* No implementation yet. */
458int
459execvp (const char *path, ...)
460{
461 return -1;
462}
463#endif /* __MRC__ */
464
465
466int
467utime (const char *path, const struct utimbuf *times)
468{
469 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
470 int len;
471 char mac_pathname[MAXPATHLEN+1];
472 CInfoPBRec cipb;
473
474 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
475 return -1;
476
477 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
478 if (len > -1)
479 fully_resolved_name[len] = '\0';
480 else
481 strcpy (fully_resolved_name, true_pathname);
482
483 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
484 return -1;
485
486 c2pstr (mac_pathname);
487 cipb.hFileInfo.ioNamePtr = mac_pathname;
488 cipb.hFileInfo.ioVRefNum = 0;
489 cipb.hFileInfo.ioDirID = 0;
490 cipb.hFileInfo.ioFDirIndex = 0;
491 /* set to 0 to get information about specific dir or file */
492
493 errno = PBGetCatInfo (&cipb, false);
494 if (errno != noErr)
495 return -1;
496
497 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */
498 {
499 if (times)
500 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
501 else
502 GetDateTime (&cipb.dirInfo.ioDrMdDat);
503 }
504 else
505 {
506 if (times)
507 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
508 else
509 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
510 }
511
512 errno = PBSetCatInfo (&cipb, false);
513 return errno == noErr ? 0 : -1;
514}
515
516
517#ifndef F_OK
518#define F_OK 0
519#endif
520#ifndef X_OK
521#define X_OK 1
522#endif
523#ifndef W_OK
524#define W_OK 2
525#endif
526
527/* Like stat, but test for access mode in hfpb.ioFlAttrib */
528int
529access (const char *path, int mode)
530{
531 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
532 int len;
533 char mac_pathname[MAXPATHLEN+1];
534 CInfoPBRec cipb;
535
536 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
537 return -1;
538
539 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
540 if (len > -1)
541 fully_resolved_name[len] = '\0';
542 else
543 strcpy (fully_resolved_name, true_pathname);
544
545 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
546 return -1;
547
548 c2pstr (mac_pathname);
549 cipb.hFileInfo.ioNamePtr = mac_pathname;
550 cipb.hFileInfo.ioVRefNum = 0;
551 cipb.hFileInfo.ioDirID = 0;
552 cipb.hFileInfo.ioFDirIndex = 0;
553 /* set to 0 to get information about specific dir or file */
554
555 errno = PBGetCatInfo (&cipb, false);
556 if (errno != noErr)
557 return -1;
558
559 if (mode == F_OK) /* got this far, file exists */
560 return 0;
561
562 if (mode & X_OK)
563 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
564 return 0;
565 else
566 {
567 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
568 return 0;
569 else
570 return -1;
571 }
572
573 if (mode & W_OK)
574 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0;
575 /* don't allow if lock bit is on */
576
577 return -1;
578}
579
580
581#define DEV_NULL_FD 0x10000
582
583#undef open
584int
585sys_open (const char *path, int oflag)
586{
587 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
588 int len;
589 char mac_pathname[MAXPATHLEN+1];
590
591 if (strcmp (path, "/dev/null") == 0)
592 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
593
594 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
595 return -1;
596
597 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
598 if (len > -1)
599 fully_resolved_name[len] = '\0';
600 else
601 strcpy (fully_resolved_name, true_pathname);
602
603 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
604 return -1;
605 else
606 {
607#ifdef __MRC__
608 if (oflag == O_WRONLY || oflag == O_RDWR)
609 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
610#endif
611 return open (mac_pathname, oflag);
612 }
613}
614
615
616#undef creat
617int
618sys_creat (const char *path, mode_t mode)
619{
620 char true_pathname[MAXPATHLEN+1];
621 int len;
622 char mac_pathname[MAXPATHLEN+1];
623
624 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
625 return -1;
626
627 if (!unix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1))
628 return -1;
629 else
630 {
631#ifdef __MRC__
632 int result = creat (mac_pathname);
633 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
634 return result;
635#else
636 return creat (mac_pathname, mode);
637#endif
638 }
639}
640
641
642#undef unlink
643int
644sys_unlink (const char *path)
645{
646 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
647 int len;
648 char mac_pathname[MAXPATHLEN+1];
649
650 if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1)
651 return -1;
652
653 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
654 if (len > -1)
655 fully_resolved_name[len] = '\0';
656 else
657 strcpy (fully_resolved_name, true_pathname);
658
659 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
660 return -1;
661 else
662 return unlink (mac_pathname);
663}
664
665
666#undef read
667int
668sys_read (int fildes, char *buf, int count)
669{
670 if (fildes == 0) /* this should not be used for console input */
671 return -1;
672 else
673#ifdef CODEWARRIOR_VERSION_6
674 return _read (fildes, buf, count);
675#else
676 return read (fildes, buf, count);
677#endif
678}
679
680
681#undef write
682int
683sys_write (int fildes, const char *buf, int count)
684{
685 if (fildes == DEV_NULL_FD)
686 return count;
687 else
688#ifdef CODEWARRIOR_VERSION_6
689 return _write (fildes, buf, count);
690#else
691 return write (fildes, buf, count);
692#endif
693}
694
695
696#undef rename
697int
698sys_rename (const char * old_name, const char * new_name)
699{
700 char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1];
701 char fully_resolved_old_name[MAXPATHLEN+1];
702 int len;
703 char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1];
704
705 if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1)
706 return -1;
707
708 len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN);
709 if (len > -1)
710 fully_resolved_old_name[len] = '\0';
711 else
712 strcpy (fully_resolved_old_name, true_old_pathname);
713
714 if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1)
715 return -1;
716
717 if (strcmp (fully_resolved_old_name, true_new_pathname) == 0)
718 return 0;
719
720 if (!unix_to_mac_pathname (fully_resolved_old_name,
721 mac_old_name,
722 MAXPATHLEN+1))
723 return -1;
724
725 if (!unix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1))
726 return -1;
727
728 /* If a file with new_name already exists, rename deletes the old
729 file in Unix. CW version fails in these situation. So we add a
730 call to unlink here. */
731 (void) unlink (mac_new_name);
732
733 return rename (mac_old_name, mac_new_name);
734}
735
736
737#undef fopen
738extern FILE *fopen (const char *name, const char *mode);
739FILE *
740sys_fopen (const char *name, const char *mode)
741{
742 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
743 int len;
744 char mac_pathname[MAXPATHLEN+1];
745
746 if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1)
747 return 0;
748
749 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
750 if (len > -1)
751 fully_resolved_name[len] = '\0';
752 else
753 strcpy (fully_resolved_name, true_pathname);
754
755 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
756 return 0;
757 else
758 {
759#ifdef __MRC__
760 if (mode[0] == 'w' || mode[0] == 'a')
761 fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
762#endif
763 return fopen (mac_pathname, mode);
764 }
765}
766
767
768#include <Events.h>
769
770long target_ticks = 0;
771
772#ifdef __MRC__
773__sigfun alarm_signal_func = (__sigfun) 0;
774#elif __MWERKS__
775__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
776#else
777You lose!!!
778#endif
779
780
781/* These functions simulate SIG_ALRM. The stub for function signal
782 stores the signal handler function in alarm_signal_func if a
783 SIG_ALRM is encountered. check_alarm is called in XTread_socket,
784 which emacs calls periodically. A pending alarm is represented by
785 a non-zero target_ticks value. check_alarm calls the handler
786 function pointed to by alarm_signal_func if one has been set up and
787 an alarm is pending. */
788
789void
790check_alarm ()
791{
792 if (target_ticks && TickCount () > target_ticks)
793 {
794 target_ticks = 0;
795 if (alarm_signal_func)
796 (*alarm_signal_func)(SIGALRM);
797 }
798}
799
800
801int
802select(n, rfds, wfds, efds, timeout)
803 int n;
804 SELECT_TYPE *rfds;
805 SELECT_TYPE *wfds;
806 SELECT_TYPE *efds;
807 struct timeval *timeout;
808{
809 EMACS_TIME end_time, now;
810 EventRecord e;
811 unsigned long final_tick;
812
813 /* Can only handle wait for keyboard input. */
814 if (n > 1 || wfds || efds)
815 return -1;
816
817 EMACS_GET_TIME (end_time);
818 EMACS_ADD_TIME (end_time, end_time, *timeout);
819
820 do
821 {
822 /* Also return true if an event other than a keyDown has
823 occurred. This causes kbd_buffer_get_event in keyboard.c to
824 call read_avail_input which in turn calls XTread_socket to
825 poll for these events. Otherwise these never get processed
826 except but a very slow poll timer. */
827 if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e))
828 return 1;
829
830 /* Also check movement of the mouse. */
831 {
832 Point mouse_pos;
833 static Point old_mouse_pos = {-1, -1};
834
835 GetMouse (&mouse_pos);
836 if (!EqualPt (mouse_pos, old_mouse_pos))
837 {
838 old_mouse_pos = mouse_pos;
839 return 1;
840 }
841 }
842
843 Delay (1UL, &final_tick);
844
845 EMACS_GET_TIME (now);
846 EMACS_SUB_TIME (now, end_time, now);
847 }
848 while (!EMACS_TIME_NEG_P (now));
849
850 return 0;
851}
852
853
854/* Called in sys_select to wait for an alarm signal to arrive. */
855
856int
857pause ()
858{
859 unsigned long final_tick;
860
861 if (!target_ticks) /* no alarm pending */
862 return -1;
863
864 while (TickCount () <= target_ticks)
865 Delay (1UL, &final_tick); /* wait 1/60 second before retrying */
866
867 target_ticks = 0;
868 if (alarm_signal_func)
869 (*alarm_signal_func)(SIGALRM);
870
871 return 0;
872}
873
874
875int
876alarm (int seconds)
877{
878 long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0;
879
880 target_ticks = seconds ? TickCount () + 60 * seconds : 0;
881
882 return (remaining < 0) ? 0 : (unsigned int) remaining;
883}
884
885
886#undef signal
887#ifdef __MRC__
888extern __sigfun signal (int signal, __sigfun signal_func);
889__sigfun
890sys_signal (int signal_num, __sigfun signal_func)
891#elif __MWERKS__
892extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
893__signal_func_ptr
894sys_signal (int signal_num, __signal_func_ptr signal_func)
895#else
896 You lose!!!
897#endif
898{
899 if (signal_num != SIGALRM)
900 return signal (signal_num, signal_func);
901 else
902 {
903#ifdef __MRC__
904 __sigfun old_signal_func;
905#elif __MWERKS__
906 __signal_func_ptr old_signal_func;
907#else
908 You lose!!!
909#endif
910 old_signal_func = alarm_signal_func;
911 alarm_signal_func = signal_func;
912 return old_signal_func;
913 }
914}
915
916
917/* gettimeofday should return the amount of time (in a timeval
918 structure) since midnight today. The toolbox function Microseconds
919 returns the number of microseconds (in a UnsignedWide value) since
920 the machine was booted. Also making this complicated is WideAdd,
921 WideSubtract, etc. take wide values. */
922
923int
924gettimeofday (tp)
925 struct timeval *tp;
926{
927 static inited = 0;
928 static wide wall_clock_at_epoch, clicks_at_epoch;
929 UnsignedWide uw_microseconds;
930 wide w_microseconds;
931 time_t sys_time (time_t *);
932
933 /* If this function is called for the first time, record the number
934 of seconds since midnight and the number of microseconds since
935 boot at the time of this first call. */
936 if (!inited)
937 {
938 time_t systime;
939 inited = 1;
940 systime = sys_time (NULL);
941 /* Store microseconds since midnight in wall_clock_at_epoch. */
942 WideMultiply (systime, 1000000L, &wall_clock_at_epoch);
943 Microseconds (&uw_microseconds);
944 /* Store microseconds since boot in clicks_at_epoch. */
945 clicks_at_epoch.hi = uw_microseconds.hi;
946 clicks_at_epoch.lo = uw_microseconds.lo;
947 }
948
949 /* Get time since boot */
950 Microseconds (&uw_microseconds);
951
952 /* Convert to time since midnight*/
953 w_microseconds.hi = uw_microseconds.hi;
954 w_microseconds.lo = uw_microseconds.lo;
955 WideSubtract (&w_microseconds, &clicks_at_epoch);
956 WideAdd (&w_microseconds, &wall_clock_at_epoch);
957 tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec);
958
959 return 0;
960}
961
962
963#ifdef __MRC__
964unsigned int
965sleep (unsigned int seconds)
966{
967 unsigned long final_tick;
968
969 Delay (seconds * 60UL, &final_tick);
970 return (0);
971}
972#endif /* __MRC__ */
973
974
975/* The time functions adjust time values according to the difference
976 between the Unix and CW epoches. */
977
978#undef gmtime
979extern struct tm *gmtime (const time_t *);
980struct tm *
981sys_gmtime (const time_t *timer)
982{
983 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
984
985 return gmtime (&unix_time);
986}
987
988
989#undef localtime
990extern struct tm *localtime (const time_t *);
991struct tm *
992sys_localtime (const time_t *timer)
993{
994#ifdef CODEWARRIOR_VERSION_6
995 time_t unix_time = *timer;
996#else
997 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
998#endif
999
1000 return localtime (&unix_time);
1001}
1002
1003
1004#undef ctime
1005extern char *ctime (const time_t *);
1006char *
1007sys_ctime (const time_t *timer)
1008{
1009#ifdef CODEWARRIOR_VERSION_6
1010 time_t unix_time = *timer;
1011#else
1012 time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF;
1013#endif
1014
1015 return ctime (&unix_time);
1016}
1017
1018
1019#undef time
1020extern time_t time (time_t *);
1021time_t
1022sys_time (time_t *timer)
1023{
1024#ifdef CODEWARRIOR_VERSION_6
1025 time_t mac_time = time (NULL);
1026#else
1027 time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF;
1028#endif
1029
1030 if (timer)
1031 *timer = mac_time;
1032
1033 return mac_time;
1034}
1035
1036
1037/* MPW strftime broken for "%p" format */
1038#ifdef __MRC__
1039#undef strftime
1040#include <time.h>
1041size_t
1042sys_strftime (char * s, size_t maxsize, const char * format,
1043 const struct tm * timeptr)
1044{
1045 if (strcmp (format, "%p") == 0)
1046 {
1047 if (maxsize < 3)
1048 return 0;
1049 if (timeptr->tm_hour < 12)
1050 {
1051 strcpy (s, "AM");
1052 return 2;
1053 }
1054 else
1055 {
1056 strcpy (s, "PM");
1057 return 2;
1058 }
1059 }
1060 else
1061 return strftime (s, maxsize, format, timeptr);
1062}
1063#endif /* __MRC__ */
1064
1065
1066/* no subprocesses, empty wait */
1067
1068int
1069wait (int pid)
1070{
1071 return 0;
1072}
1073
1074
1075void
1076croak (char *badfunc)
1077{
1078 printf ("%s not yet implemented\r\n", badfunc);
1079 exit (1);
1080}
1081
1082
1083char *
1084index (const char * str, int chr)
1085{
1086 return strchr (str, chr);
1087}
1088
1089
1090char *
1091mktemp (char *template)
1092{
1093 int len, k;
1094 static seqnum = 0;
1095
1096 len = strlen (template);
1097 k = len - 1;
1098 while (k >= 0 && template[k] == 'X')
1099 k--;
1100
1101 k++; /* make k index of first 'X' */
1102
1103 if (k < len)
1104 {
1105 /* Zero filled, number of digits equal to the number of X's. */
1106 sprintf (&template[k], "%0*d", len-k, seqnum++);
1107
1108 return template;
1109 }
1110 else
1111 return 0;
1112}
1113
1114
1115/* Emulate getpwuid, getpwnam and others. */
1116
1117#define PASSWD_FIELD_SIZE 256
1118
1119static char my_passwd_name[PASSWD_FIELD_SIZE];
1120static char my_passwd_dir[MAXPATHLEN+1];
1121
1122static struct passwd my_passwd =
1123{
1124 my_passwd_name,
1125 my_passwd_dir,
1126};
1127
1128
1129/* Initialized by main () in macterm.c to pathname of emacs directory. */
1130
1131char emacs_passwd_dir[MAXPATHLEN+1];
1132
1133char *
1134getwd (char *);
1135
1136void
1137init_emacs_passwd_dir ()
1138{
1139 int found = false;
1140
1141 if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir))
1142 {
1143 /* Need pathname of first ancestor that begins with "emacs"
1144 since Mac emacs application is somewhere in the emacs-*
1145 tree. */
1146 int len = strlen (emacs_passwd_dir);
1147 int j = len - 1;
1148 /* j points to the "/" following the directory name being
1149 compared. */
1150 int i = j - 1;
1151 while (i >= 0 && !found)
1152 {
1153 while (i >= 0 && emacs_passwd_dir[i] != '/')
1154 i--;
1155 if (emacs_passwd_dir[i] == '/' && i+5 < len)
1156 found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0);
1157 if (found)
1158 emacs_passwd_dir[j+1] = '\0';
1159 else
1160 {
1161 j = i;
1162 i = j - 1;
1163 }
1164 }
1165 }
1166
1167 if (!found)
1168 {
1169 /* Setting to "/" probably won't work but set it to something
1170 anyway. */
1171 strcpy (emacs_passwd_dir, "/");
1172 strcpy (my_passwd_dir, "/");
1173 }
1174}
1175
1176
1177static struct passwd emacs_passwd =
1178{
1179 "emacs",
1180 emacs_passwd_dir,
1181};
1182
1183static int my_passwd_inited = 0;
1184
1185
1186static void
1187init_my_passwd ()
1188{
1189 char **owner_name;
1190
1191 /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to
1192 directory where Emacs was started. */
1193
1194 owner_name = (char **) GetResource ('STR ',-16096);
1195 if (owner_name)
1196 {
1197 HLock (owner_name);
1198 BlockMove ((unsigned char *) *owner_name,
1199 (unsigned char *) my_passwd_name,
1200 *owner_name[0]+1);
1201 HUnlock (owner_name);
1202 p2cstr ((unsigned char *) my_passwd_name);
1203 }
1204 else
1205 my_passwd_name[0] = 0;
1206}
1207
1208
1209struct passwd *
1210getpwuid (uid_t uid)
1211{
1212 if (!my_passwd_inited)
1213 {
1214 init_my_passwd ();
1215 my_passwd_inited = 1;
1216 }
1217
1218 return &my_passwd;
1219}
1220
1221
1222struct passwd *
1223getpwnam (const char *name)
1224{
1225 if (strcmp (name, "emacs") == 0)
1226 return &emacs_passwd;
1227
1228 if (!my_passwd_inited)
1229 {
1230 init_my_passwd ();
1231 my_passwd_inited = 1;
1232 }
1233
1234 return &my_passwd;
1235}
1236
1237
1238/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
1239 setpgrp, setpriority, and unrequest_sigio are defined to be empty
1240 as in msdos.c. */
1241
1242
1243int
1244fork ()
1245{
1246 return -1;
1247}
1248
1249
1250int
1251kill (int x, int y)
1252{
1253 return -1;
1254}
1255
1256
1257void
1258sys_subshell ()
1259{
1260 error ("Can't spawn subshell");
1261}
1262
1263
1264int
1265sigsetmask (int x)
1266{
1267 return 0;
1268}
1269
1270
1271int
1272sigblock (int mask)
1273{
1274 return 0;
1275}
1276
1277
1278void
1279request_sigio (void)
1280{
1281}
1282
1283
1284void
1285unrequest_sigio (void)
1286{
1287}
1288
1289
1290int
1291setpgrp ()
1292{
1293 return 0;
1294}
1295
1296
1297/* No pipes yet. */
1298
1299int
1300pipe (int _fildes[2])
1301{
1302 errno = EACCES;
1303 return -1;
1304}
1305
1306
1307/* Hard and symbolic links. */
1308
1309int
1310symlink (const char *name1, const char *name2)
1311{
1312 errno = ENOENT;
1313 return -1;
1314}
1315
1316
1317int
1318link (const char *name1, const char *name2)
1319{
1320 errno = ENOENT;
1321 return -1;
1322}
1323
1324
1325/* Determine the path name of the file specified by VREFNUM, DIRID,
1326 and NAME and place that in the buffer PATH of length
1327 MAXPATHLEN. */
1328int
1329path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num,
1330 long dir_id, ConstStr255Param name)
1331{
1332 Str255 dir_name;
1333 CInfoPBRec cipb;
1334 OSErr err;
1335
1336 if (strlen (name) > man_path_len)
1337 return 0;
1338
1339 memcpy (dir_name, name, name[0]+1);
1340 memcpy (path, name, name[0]+1);
1341 p2cstr (path);
1342
1343 cipb.dirInfo.ioDrParID = dir_id;
1344 cipb.dirInfo.ioNamePtr = dir_name;
1345
1346 do
1347 {
1348 cipb.dirInfo.ioVRefNum = vol_ref_num;
1349 cipb.dirInfo.ioFDirIndex = -1;
1350 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
1351 /* go up to parent each time */
1352
1353 err = PBGetCatInfo (&cipb, false);
1354 if (err != noErr)
1355 return 0;
1356
1357 p2cstr (dir_name);
1358 if (strlen (dir_name) + strlen (path) + 1 >= man_path_len)
1359 return 0;
1360
1361 strcat (dir_name, ":");
1362 strcat (dir_name, path);
1363 /* attach to front since we're going up directory tree */
1364 strcpy (path, dir_name);
1365 }
1366 while (cipb.dirInfo.ioDrDirID != fsRtDirID);
1367 /* stop when we see the volume's root directory */
1368
1369 return 1; /* success */
1370}
1371
1372
1373int
1374readlink (const char *path, char *buf, int bufsiz)
1375{
1376 char mac_sym_link_name[MAXPATHLEN+1];
1377 OSErr err;
1378 FSSpec fsspec;
1379 Boolean target_is_folder, was_aliased;
1380 Str255 directory_name, mac_pathname;
1381 CInfoPBRec cipb;
1382
1383 if (unix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0)
1384 return -1;
1385
1386 c2pstr (mac_sym_link_name);
1387 err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec);
1388 if (err != noErr)
1389 {
1390 errno = ENOENT;
1391 return -1;
1392 }
1393
1394 err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased);
1395 if (err != noErr || !was_aliased)
1396 {
1397 errno = ENOENT;
1398 return -1;
1399 }
1400
1401 if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID,
1402 fsspec.name) == 0)
1403 {
1404 errno = ENOENT;
1405 return -1;
1406 }
1407
1408 if (mac_to_unix_pathname (mac_pathname, buf, bufsiz) == 0)
1409 {
1410 errno = ENOENT;
1411 return -1;
1412 }
1413
1414 return strlen (buf);
1415}
1416
1417
1418/* Convert a path to one with aliases fully expanded. */
1419
1420static int
1421find_true_pathname (const char *path, char *buf, int bufsiz)
1422{
1423 char *q, temp[MAXPATHLEN+1];
1424 const char *p;
1425 int len;
1426
1427 if (bufsiz <= 0 || path == 0 || path[0] == '\0')
1428 return -1;
1429
1430 buf[0] = '\0';
1431
1432 p = path;
1433 if (*p == '/')
1434 q = strchr (p + 1, '/');
1435 else
1436 q = strchr (p, '/');
1437 len = 0; /* loop may not be entered, e.g., for "/" */
1438
1439 while (q)
1440 {
1441 strcpy (temp, buf);
1442 strncat (temp, p, q - p);
1443 len = readlink (temp, buf, bufsiz);
1444 if (len <= -1)
1445 {
1446 if (strlen (temp) + 1 > bufsiz)
1447 return -1;
1448 strcpy (buf, temp);
1449 }
1450 strcat (buf, "/");
1451 len++;
1452 p = q + 1;
1453 q = strchr(p, '/');
1454 }
1455
1456 if (len + strlen (p) + 1 >= bufsiz)
1457 return -1;
1458
1459 strcat (buf, p);
1460 return len + strlen (p);
1461}
1462
1463
1464mode_t
1465umask (mode_t numask)
1466{
1467 static mode_t mask = 022;
1468 mode_t oldmask = mask;
1469 mask = numask;
1470 return oldmask;
1471}
1472
1473
1474int
1475chmod (const char *path, mode_t mode)
1476{
1477 /* say it always succeed for now */
1478 return 0;
1479}
1480
1481
1482int
1483dup (int oldd)
1484{
1485#ifdef __MRC__
1486 return fcntl (oldd, F_DUPFD, 0);
1487#elif __MWERKS__
1488 /* current implementation of fcntl in fcntl.mac.c simply returns old
1489 descriptor */
1490 return fcntl (oldd, F_DUPFD);
1491#else
1492You lose!!!
1493#endif
1494}
1495
1496
1497/* This is from the original sysdep.c. Emulate BSD dup2. First close
1498 newd if it already exists. Then, attempt to dup oldd. If not
1499 successful, call dup2 recursively until we are, then close the
1500 unsuccessful ones. */
1501
1502int
1503dup2 (int oldd, int newd)
1504{
1505 int fd, ret;
1506
1507 close (newd);
1508
1509 fd = dup (oldd);
1510 if (fd == -1)
1511 return -1;
1512 if (fd == newd)
1513 return newd;
1514 ret = dup2 (oldd, newd);
1515 close (fd);
1516 return ret;
1517}
1518
1519
1520/* let it fail for now */
1521
1522char *
1523sbrk (int incr)
1524{
1525 return (char *) -1;
1526}
1527
1528
1529int
1530fsync (int fd)
1531{
1532 return 0;
1533}
1534
1535
1536int
1537ioctl (int d, int request, void *argp)
1538{
1539 return -1;
1540}
1541
1542
1543#ifdef __MRC__
1544int
1545isatty (int fildes)
1546{
1547 if (fildes >=0 && fildes <= 2)
1548 return 1;
1549 else
1550 return 0;
1551}
1552
1553
1554int
1555getgid ()
1556{
1557 return 100;
1558}
1559
1560
1561int
1562getegid ()
1563{
1564 return 100;
1565}
1566
1567
1568int
1569getuid ()
1570{
1571 return 200;
1572}
1573
1574
1575int
1576geteuid ()
1577{
1578 return 200;
1579}
1580#endif /* __MRC__ */
1581
1582
1583#ifdef __MWERKS__
1584#ifndef CODEWARRIOR_VERSION_6
1585#undef getpid
1586int
1587getpid ()
1588{
1589 return 9999;
1590}
1591#endif
1592#endif /* __MWERKS__ */
1593
1594
1595/* Return the path to the directory in which Emacs can create
1596 temporary files. The MacOS "temporary items" directory cannot be
1597 used because it removes the file written by a process when it
1598 exits. In that sense it's more like "/dev/null" than "/tmp" (but
1599 again not exactly). And of course Emacs needs to read back the
1600 files written by its subprocesses. So here we write the files to a
1601 directory "Emacs" in the Preferences Folder. This directory is
1602 created if it does not exist. */
1603
1604static char *
1605get_temp_dir_name ()
1606{
1607 static char *temp_dir_name = NULL;
1608 short vol_ref_num;
1609 long dir_id;
1610 OSErr err;
1611 Str255 dir_name, full_path;
1612 CInfoPBRec cpb;
1613 char unix_dir_name[MAXPATHLEN+1];
1614 DIR *dir;
1615
1616 /* Cache directory name with pointer temp_dir_name.
1617 Look for it only the first time. */
1618 if (!temp_dir_name)
1619 {
1620 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
1621 &vol_ref_num, &dir_id);
1622 if (err != noErr)
1623 return NULL;
1624
1625 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1626 return NULL;
1627
1628 if (strlen (full_path) + 6 <= MAXPATHLEN)
1629 strcat (full_path, "Emacs:");
1630 else
1631 return NULL;
1632
1633 if (!mac_to_unix_pathname (full_path, unix_dir_name, MAXPATHLEN+1))
1634 return NULL;
1635
1636 dir = opendir (unix_dir_name); /* check whether temp directory exists */
1637 if (dir)
1638 closedir (dir);
1639 else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */
1640 return NULL;
1641
1642 temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1);
1643 strcpy (temp_dir_name, unix_dir_name);
1644 }
1645
1646 return temp_dir_name;
1647}
1648
1649
1650/* Allocate and construct an array of pointers to strings from a list
1651 of strings stored in a 'STR#' resource. The returned pointer array
1652 is stored in the style of argv and environ: if the 'STR#' resource
1653 contains numString strings, an pointer array with numString+1
1654 elements is returned in which the last entry contains a null
1655 pointer. The pointer to the pointer array is passed by pointer in
1656 parameter t. The resource ID of the 'STR#' resource is passed in
1657 parameter StringListID.
1658 */
1659
1660void
1661get_string_list (char ***t, short string_list_id)
1662{
1663 Handle h;
1664 Ptr p;
1665 int i, num_strings;
1666
1667 h = GetResource ('STR#', string_list_id);
1668 if (h)
1669 {
1670 HLock (h);
1671 p = *h;
1672 num_strings = * (short *) p;
1673 p += sizeof(short);
1674 *t = (char **) malloc (sizeof (char *) * (num_strings + 1));
1675 for (i = 0; i < num_strings; i++)
1676 {
1677 short length = *p++;
1678 (*t)[i] = (char *) malloc (length + 1);
1679 strncpy ((*t)[i], p, length);
1680 (*t)[i][length] = '\0';
1681 p += length;
1682 }
1683 (*t)[num_strings] = 0;
1684 HUnlock (h);
1685 }
1686 else
1687 {
1688 /* Return no string in case GetResource fails. Bug fixed by
1689 Ikegami Tsutomu. Caused MPW build to crash without sym -on
1690 option (no sym -on implies -opt local). */
1691 *t = (char **) malloc (sizeof (char *));
1692 (*t)[0] = 0;
1693 }
1694}
1695
1696
1697static char *
1698get_path_to_system_folder ()
1699{
1700 short vol_ref_num;
1701 long dir_id;
1702 OSErr err;
1703 Str255 dir_name, full_path;
1704 CInfoPBRec cpb;
1705 static char system_folder_unix_name[MAXPATHLEN+1];
1706 DIR *dir;
1707
1708 err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
1709 &vol_ref_num, &dir_id);
1710 if (err != noErr)
1711 return NULL;
1712
1713 if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p"))
1714 return NULL;
1715
1716 if (!mac_to_unix_pathname (full_path, system_folder_unix_name, MAXPATHLEN+1))
1717 return NULL;
1718
1719 return system_folder_unix_name;
1720}
1721
1722
1723char **environ;
1724
1725#define ENVIRON_STRING_LIST_ID 128
1726
1727/* Get environment variable definitions from STR# resource. */
1728
1729void
1730init_environ ()
1731{
1732 int i;
1733
1734 get_string_list (&environ, ENVIRON_STRING_LIST_ID);
1735
1736 i = 0;
1737 while (environ[i])
1738 i++;
1739
1740 /* Make HOME directory the one Emacs starts up in if not specified
1741 by resource. */
1742 if (getenv ("HOME") == NULL)
1743 {
1744 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1745 if (environ)
1746 {
1747 environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6);
1748 if (environ[i])
1749 {
1750 strcpy (environ[i], "HOME=");
1751 strcat (environ[i], my_passwd_dir);
1752 }
1753 environ[i+1] = 0;
1754 i++;
1755 }
1756 }
1757
1758 /* Make HOME directory the one Emacs starts up in if not specified
1759 by resource. */
1760 if (getenv ("MAIL") == NULL)
1761 {
1762 environ = (char **) realloc (environ, sizeof (char *) * (i + 2));
1763 if (environ)
1764 {
1765 char * path_to_system_folder = get_path_to_system_folder ();
1766 environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22);
1767 if (environ[i])
1768 {
1769 strcpy (environ[i], "MAIL=");
1770 strcat (environ[i], path_to_system_folder);
1771 strcat (environ[i], "Eudora Folder/In");
1772 }
1773 environ[i+1] = 0;
1774 }
1775 }
1776}
1777
1778
1779/* Return the value of the environment variable NAME. */
1780
1781char *
1782getenv (const char *name)
1783{
1784 int length = strlen(name);
1785 char **e;
1786
1787 for (e = environ; *e != 0; e++)
1788 if (strncmp(*e, name, length) == 0 && (*e)[length] == '=')
1789 return &(*e)[length + 1];
1790
1791 if (strcmp (name, "TMPDIR") == 0)
1792 return get_temp_dir_name ();
1793
1794 return 0;
1795}
1796
1797
1798#ifdef __MRC__
1799/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
1800char *sys_siglist[] =
1801{
1802 "Zero is not a signal!!!",
1803 "Abort", /* 1 */
1804 "Interactive user interrupt", /* 2 */ "?",
1805 "Floating point exception", /* 4 */ "?", "?", "?",
1806 "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?",
1807 "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?",
1808 "?", "?", "?", "?", "?", "?", "?", "?",
1809 "Terminal" /* 32 */
1810};
1811#elif __MWERKS__
1812char *sys_siglist[] =
1813{
1814 "Zero is not a signal!!!",
1815 "Abort",
1816 "Floating point exception",
1817 "Illegal instruction",
1818 "Interactive user interrupt",
1819 "Segment violation",
1820 "Terminal"
1821};
1822#else
1823You lose!!!
1824#endif
1825
1826
1827#include <utsname.h>
1828
1829int
1830uname (struct utsname *name)
1831{
1832 char **system_name;
1833 system_name = GetString (-16413); /* IM - Resource Manager Reference */
1834 if (system_name)
1835 {
1836 BlockMove (*system_name, name->nodename, (*system_name)[0]+1);
1837 p2cstr (name->nodename);
1838 return 0;
1839 }
1840 else
1841 return -1;
1842}
1843
1844
1845#include <Processes.h>
1846#include <EPPC.h>
1847
1848/* Event class of HLE sent to subprocess. */
1849const OSType kEmacsSubprocessSend = 'ESND';
1850
1851/* Event class of HLE sent back from subprocess. */
1852const OSType kEmacsSubprocessReply = 'ERPY';
1853
1854
1855char *
1856mystrchr (char *s, char c)
1857{
1858 while (*s && *s != c)
1859 {
1860 if (*s == '\\')
1861 s++;
1862 s++;
1863 }
1864
1865 if (*s)
1866 {
1867 *s = '\0';
1868 return s;
1869 }
1870 else
1871 return NULL;
1872}
1873
1874
1875char *
1876mystrtok (char *s)
1877{
1878 while (*s)
1879 s++;
1880
1881 return s + 1;
1882}
1883
1884
1885void
1886mystrcpy (char *to, char *from)
1887{
1888 while (*from)
1889 {
1890 if (*from == '\\')
1891 from++;
1892 *to++ = *from++;
1893 }
1894 *to = '\0';
1895}
1896
1897
1898/* Start a Mac subprocess. Arguments for it is passed in argv (null
1899 terminated). The process should run with the default directory
1900 "workdir", read input from "infn", and write output and error to
1901 "outfn" and "errfn", resp. The Process Manager call
1902 LaunchApplication is used to start the subprocess. We use high
1903 level events as the mechanism to pass arguments to the subprocess
1904 and to make Emacs wait for the subprocess to terminate and pass
1905 back a result code. The bulk of the code here packs the arguments
1906 into one message to be passed together with the high level event.
1907 Emacs also sometimes starts a subprocess using a shell to perform
1908 wildcard filename expansion. Since we don't really have a shell on
1909 the Mac, this case is detected and the starting of the shell is
1910 by-passed. We really need to add code here to do filename
1911 expansion to support such functionality. */
1912
1913int
1914run_mac_command (argv, workdir, infn, outfn, errfn)
1915 unsigned char **argv;
1916 const char *workdir;
1917 const char *infn, *outfn, *errfn;
1918{
1919 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
1920 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
1921 int paramlen, argc, newargc, j, retries;
1922 char **newargv, *param, *p;
1923 OSErr iErr;
1924 FSSpec spec;
1925 LaunchParamBlockRec lpbr;
1926 EventRecord send_event, reply_event;
1927 RgnHandle cursor_region_handle;
1928 TargetID targ;
1929 unsigned long ref_con, len;
1930
1931 if (unix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
1932 return -1;
1933 if (unix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0)
1934 return -1;
1935 if (unix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
1936 return -1;
1937 if (unix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
1938 return -1;
1939
1940 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn)
1941 + strlen (macerrfn) + 4; /* count nulls at end of strings */
1942
1943 argc = 0;
1944 while (argv[argc])
1945 argc++;
1946
1947 if (argc == 0)
1948 return -1;
1949
1950 /* If a subprocess is invoked with a shell, we receive 3 arguments
1951 of the form: "<path to emacs bins>/sh" "-c" "<path to emacs
1952 bins>/<command> <command args>" */
1953 j = strlen (argv[0]);
1954 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0
1955 && argc == 3 && strcmp (argv[1], "-c") == 0)
1956 {
1957 char *command, *t, tempmacpathname[MAXPATHLEN+1];
1958
1959 /* The arguments for the command in argv[2] are separated by
1960 spaces. Count them and put the count in newargc. */
1961 command = (char *) alloca (strlen (argv[2])+2);
1962 strcpy (command, argv[2]);
1963 if (command[strlen (command) - 1] != ' ')
1964 strcat (command, " ");
1965
1966 t = command;
1967 newargc = 0;
1968 t = mystrchr (t, ' ');
1969 while (t)
1970 {
1971 newargc++;
1972 t = mystrchr (t+1, ' ');
1973 }
1974
1975 newargv = (char **) alloca (sizeof (char *) * newargc);
1976
1977 t = command;
1978 for (j = 0; j < newargc; j++)
1979 {
1980 newargv[j] = (char *) alloca (strlen (t) + 1);
1981 mystrcpy (newargv[j], t);
1982
1983 t = mystrtok (t);
1984 paramlen += strlen (newargv[j]) + 1;
1985 }
1986
1987 if (strncmp (newargv[0], "~emacs/", 7) == 0)
1988 {
1989 if (unix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1)
1990 == 0)
1991 return -1;
1992 }
1993 else
1994 { /* sometimes Emacs call "sh" without a path for the command */
1995#if 0
1996 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
1997 strcpy (t, "~emacs/");
1998 strcat (t, newargv[0]);
1999#endif
2000 Lisp_Object path;
2001 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path,
2002 1);
2003
2004 if (NILP (path))
2005 return -1;
2006 if (unix_to_mac_pathname (XSTRING (path)->data, tempmacpathname,
2007 MAXPATHLEN+1) == 0)
2008 return -1;
2009 }
2010 strcpy (macappname, tempmacpathname);
2011 }
2012 else
2013 {
2014 if (unix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0)
2015 return -1;
2016
2017 newargv = (char **) alloca (sizeof (char *) * argc);
2018 newargc = argc;
2019 for (j = 1; j < argc; j++)
2020 {
2021 if (strncmp (argv[j], "~emacs/", 7) == 0)
2022 {
2023 char *t = strchr (argv[j], ' ');
2024 if (t)
2025 {
2026 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
2027 strncpy (tempcmdname, argv[j], t-argv[j]);
2028 tempcmdname[t-argv[j]] = '\0';
2029 if (unix_to_mac_pathname (tempcmdname, tempmaccmdname,
2030 MAXPATHLEN+1) == 0)
2031 return -1;
2032 newargv[j] = (char *) alloca (strlen (tempmaccmdname)
2033 + strlen (t) + 1);
2034 strcpy (newargv[j], tempmaccmdname);
2035 strcat (newargv[j], t);
2036 }
2037 else
2038 {
2039 char tempmaccmdname[MAXPATHLEN+1];
2040 if (unix_to_mac_pathname (argv[j], tempmaccmdname,
2041 MAXPATHLEN+1) == 0)
2042 return -1;
2043 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
2044 strcpy (newargv[j], tempmaccmdname);
2045 }
2046 }
2047 else
2048 newargv[j] = argv[j];
2049 paramlen += strlen (newargv[j]) + 1;
2050 }
2051 }
2052
2053 /* After expanding all the arguments, we now know the length of the
2054 parameter block to be sent to the subprocess as a message
2055 attached to the HLE. */
2056 param = (char *) malloc (paramlen + 1);
2057 if (!param)
2058 return -1;
2059
2060 p = param;
2061 *p++ = newargc;
2062 /* first byte of message contains number of arguments for command */
2063 strcpy (p, macworkdir);
2064 p += strlen (macworkdir);
2065 *p++ = '\0';
2066 /* null terminate strings sent so it's possible to use strcpy over there */
2067 strcpy (p, macinfn);
2068 p += strlen (macinfn);
2069 *p++ = '\0';
2070 strcpy (p, macoutfn);
2071 p += strlen (macoutfn);
2072 *p++ = '\0';
2073 strcpy (p, macerrfn);
2074 p += strlen (macerrfn);
2075 *p++ = '\0';
2076 for (j = 1; j < newargc; j++)
2077 {
2078 strcpy (p, newargv[j]);
2079 p += strlen (newargv[j]);
2080 *p++ = '\0';
2081 }
2082
2083 c2pstr (macappname);
2084
2085 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
2086
2087 if (iErr != noErr)
2088 {
2089 free (param);
2090 return -1;
2091 }
2092
2093 lpbr.launchBlockID = extendedBlock;
2094 lpbr.launchEPBLength = extendedBlockLen;
2095 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
2096 lpbr.launchAppSpec = &spec;
2097 lpbr.launchAppParameters = NULL;
2098
2099 iErr = LaunchApplication (&lpbr); /* call the subprocess */
2100 if (iErr != noErr)
2101 {
2102 free (param);
2103 return -1;
2104 }
2105
2106 send_event.what = kHighLevelEvent;
2107 send_event.message = kEmacsSubprocessSend;
2108 /* Event ID stored in "where" unused */
2109
2110 retries = 3;
2111 /* OS may think current subprocess has terminated if previous one
2112 terminated recently. */
2113 do
2114 {
2115 iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param,
2116 paramlen + 1, receiverIDisPSN);
2117 }
2118 while (iErr == sessClosedErr && retries-- > 0);
2119
2120 if (iErr != noErr)
2121 {
2122 free (param);
2123 return -1;
2124 }
2125
2126 cursor_region_handle = NewRgn ();
2127
2128 /* Wait for the subprocess to finish, when it will send us a ERPY
2129 high level event. */
2130 while (1)
2131 if (WaitNextEvent (highLevelEventMask, &reply_event, 180,
2132 cursor_region_handle)
2133 && reply_event.message == kEmacsSubprocessReply)
2134 break;
2135
2136 /* The return code is sent through the refCon */
2137 iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len);
2138 if (iErr != noErr)
2139 {
2140 DisposeHandle ((Handle) cursor_region_handle);
2141 free (param);
2142 return -1;
2143 }
2144
2145 DisposeHandle ((Handle) cursor_region_handle);
2146 free (param);
2147
2148 return ref_con;
2149}
2150
2151
2152DIR *
2153opendir (const char *dirname)
2154{
2155 char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1];
2156 char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1];
2157 DIR *dirp;
2158 CInfoPBRec cipb;
2159 HVolumeParam vpb;
2160 int len, vol_name_len;
2161
2162 if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1)
2163 return 0;
2164
2165 len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN);
2166 if (len > -1)
2167 fully_resolved_name[len] = '\0';
2168 else
2169 strcpy (fully_resolved_name, true_pathname);
2170
2171 dirp = (DIR *) malloc (sizeof(DIR));
2172 if (!dirp)
2173 return 0;
2174
2175 /* Handle special case when dirname is "/": sets up for readir to
2176 get all mount volumes. */
2177 if (strcmp (fully_resolved_name, "/") == 0)
2178 {
2179 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
2180 dirp->current_index = 1; /* index for first volume */
2181 return dirp;
2182 }
2183
2184 /* Handle typical cases: not accessing all mounted volumes. */
2185 if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1))
2186 return 0;
2187
2188 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
2189 len = strlen (mac_pathname);
2190 if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN)
2191 strcat (mac_pathname, ":");
2192
2193 /* Extract volume name */
2194 vol_name_len = strchr (mac_pathname, ':') - mac_pathname;
2195 strncpy (vol_name, mac_pathname, vol_name_len);
2196 vol_name[vol_name_len] = '\0';
2197 strcat (vol_name, ":");
2198
2199 c2pstr (mac_pathname);
2200 cipb.hFileInfo.ioNamePtr = mac_pathname;
2201 /* using full pathname so vRefNum and DirID ignored */
2202 cipb.hFileInfo.ioVRefNum = 0;
2203 cipb.hFileInfo.ioDirID = 0;
2204 cipb.hFileInfo.ioFDirIndex = 0;
2205 /* set to 0 to get information about specific dir or file */
2206
2207 errno = PBGetCatInfo (&cipb, false);
2208 if (errno != noErr)
2209 {
2210 errno = ENOENT;
2211 return 0;
2212 }
2213
2214 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
2215 return 0; /* not a directory */
2216
2217 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
2218 dirp->getting_volumes = 0;
2219 dirp->current_index = 1; /* index for first file/directory */
2220
2221 c2pstr (vol_name);
2222 vpb.ioNamePtr = vol_name;
2223 /* using full pathname so vRefNum and DirID ignored */
2224 vpb.ioVRefNum = 0;
2225 vpb.ioVolIndex = -1;
2226 errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false);
2227 if (errno != noErr)
2228 {
2229 errno = ENOENT;
2230 return 0;
2231 }
2232
2233 dirp->vol_ref_num = vpb.ioVRefNum;
2234
2235 return dirp;
2236}
2237
2238int
2239closedir (DIR *dp)
2240{
2241 free (dp);
2242
2243 return 0;
2244}
2245
2246
2247struct dirent *
2248readdir (DIR *dp)
2249{
2250 HParamBlockRec hpblock;
2251 CInfoPBRec cipb;
2252 static struct dirent s_dirent;
2253 static Str255 s_name;
2254 int done;
2255 char *p;
2256
2257 /* Handle the root directory containing the mounted volumes. Call
2258 PBHGetVInfo specifying an index to obtain the info for a volume.
2259 PBHGetVInfo returns an error when it receives an index beyond the
2260 last volume, at which time we should return a nil dirent struct
2261 pointer. */
2262 if (dp->getting_volumes)
2263 {
2264 hpblock.volumeParam.ioNamePtr = s_name;
2265 hpblock.volumeParam.ioVRefNum = 0;
2266 hpblock.volumeParam.ioVolIndex = dp->current_index;
2267
2268 errno = PBHGetVInfo (&hpblock, false);
2269 if (errno != noErr)
2270 {
2271 errno = ENOENT;
2272 return 0;
2273 }
2274
2275 p2cstr (s_name);
2276 strcat (s_name, "/"); /* need "/" for stat to work correctly */
2277
2278 dp->current_index++;
2279
2280 s_dirent.d_ino = hpblock.volumeParam.ioVRefNum;
2281 s_dirent.d_name = s_name;
2282
2283 return &s_dirent;
2284 }
2285 else
2286 {
2287 cipb.hFileInfo.ioVRefNum = dp->vol_ref_num;
2288 cipb.hFileInfo.ioNamePtr = s_name;
2289 /* location to receive filename returned */
2290
2291 /* return only visible files */
2292 done = false;
2293 while (!done)
2294 {
2295 cipb.hFileInfo.ioDirID = dp->dir_id;
2296 /* directory ID found by opendir */
2297 cipb.hFileInfo.ioFDirIndex = dp->current_index;
2298
2299 errno = PBGetCatInfo (&cipb, false);
2300 if (errno != noErr)
2301 {
2302 errno = ENOENT;
2303 return 0;
2304 }
2305
2306 /* insist on an visibile entry */
2307 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
2308 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
2309 else
2310 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
2311
2312 dp->current_index++;
2313 }
2314
2315 p2cstr (s_name);
2316
2317 p = s_name;
2318 while (*p)
2319 {
2320 if (*p == '/')
2321 *p = ':';
2322 p++;
2323 }
2324
2325 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
2326 /* value unimportant: non-zero for valid file */
2327 s_dirent.d_name = s_name;
2328
2329 return &s_dirent;
2330 }
2331}
2332
2333
2334char *
2335getwd (char *path)
2336{
2337 char mac_pathname[MAXPATHLEN+1];
2338 Str255 directory_name;
2339 OSErr errno;
2340 CInfoPBRec cipb;
2341
2342 if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0)
2343 return NULL;
2344
2345 if (mac_to_unix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0)
2346 return 0;
2347 else
2348 return path;
2349}
2350
2351
2352void
2353initialize_applescript ()
2354{
2355 AEDesc null_desc;
2356 OSAError osaerror;
2357
2358 /* if open fails, as_scripting_component is set to NULL. Its
2359 subsequent use in OSA calls will fail with badComponentInstance
2360 error. */
2361 as_scripting_component = OpenDefaultComponent (kOSAComponentType,
2362 kAppleScriptSubtype);
2363
2364 null_desc.descriptorType = typeNull;
2365 null_desc.dataHandle = 0;
2366 osaerror = OSAMakeContext (as_scripting_component, &null_desc,
2367 kOSANullScript, &as_script_context);
2368 if (osaerror)
2369 as_script_context = kOSANullScript;
2370 /* use default context if create fails */
2371}
2372
2373
2374void terminate_applescript()
2375{
2376 OSADispose (as_scripting_component, as_script_context);
2377 CloseComponent (as_scripting_component);
2378}
2379
2380
2381/* Compile and execute the AppleScript SCRIPT and return the error
2382 status as function value. A zero is returned if compilation and
2383 execution is successful, in which case RESULT returns a pointer to
2384 a string containing the resulting script value. Otherwise, the Mac
2385 error code is returned and RESULT returns a pointer to an error
2386 string. In both cases the caller should deallocate the storage
2387 used by the string pointed to by RESULT if it is non-NULL. For
2388 documentation on the MacOS scripting architecture, see Inside
2389 Macintosh - Interapplication Communications: Scripting Components. */
2390
2391static long
2392do_applescript (char *script, char **result)
2393{
2394 AEDesc script_desc, result_desc, error_desc;
2395 OSErr error;
2396 OSAError osaerror;
2397 long length;
2398
2399 *result = 0;
2400
2401 error = AECreateDesc (typeChar, script, strlen(script), &script_desc);
2402 if (error)
2403 return error;
2404
2405 osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript,
2406 typeChar, kOSAModeNull, &result_desc);
2407
2408 if (osaerror == errOSAScriptError)
2409 {
2410 /* error executing AppleScript: retrieve error message */
2411 if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar,
2412 &error_desc))
2413 {
2414 HLock (error_desc.dataHandle);
2415 length = GetHandleSize(error_desc.dataHandle);
2416 *result = (char *) xmalloc (length + 1);
2417 if (*result)
2418 {
2419 memcpy (*result, *(error_desc.dataHandle), length);
2420 *(*result + length) = '\0';
2421 }
2422 HUnlock (error_desc.dataHandle);
2423 AEDisposeDesc (&error_desc);
2424 }
2425 }
2426 else if (osaerror == noErr) /* success: retrieve resulting script value */
2427 {
2428 HLock (result_desc.dataHandle);
2429 length = GetHandleSize(result_desc.dataHandle);
2430 *result = (char *) xmalloc (length + 1);
2431 if (*result)
2432 {
2433 memcpy (*result, *(result_desc.dataHandle), length);
2434 *(*result + length) = '\0';
2435 }
2436 HUnlock (result_desc.dataHandle);
2437 }
2438
2439 AEDisposeDesc (&script_desc);
2440 AEDisposeDesc (&result_desc);
2441
2442 return osaerror;
2443}
2444
2445
2446DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0,
2447 "Compile and execute AppleScript SCRIPT and retrieve and return the\n\
2448result. If compilation and execution are successful, the resulting script\n\
2449value is returned as a string. Otherwise the function aborts and\n\
2450displays the error message returned by the AppleScript scripting\n\
2451component.")
2452 (script)
2453 Lisp_Object script;
2454{
2455 char *result, *temp;
2456 Lisp_Object lisp_result;
2457 long status;
2458
2459 CHECK_STRING (script, 0);
2460
2461 status = do_applescript (XSTRING (script)->data, &result);
2462 if (status)
2463 {
2464 if (!result)
2465 error ("AppleScript error %ld", status);
2466 else
2467 {
2468 /* Unfortunately only OSADoScript in do_applescript knows how
2469 how large the resulting script value or error message is
2470 going to be and therefore as caller memory must be
2471 deallocated here. It is necessary to free the error
2472 message before calling error to avoid a memory leak. */
2473 temp = (char *) alloca (strlen (result) + 1);
2474 strcpy (temp, result);
2475 xfree (result);
2476 error (temp);
2477 }
2478 }
2479 else
2480 {
2481 lisp_result = build_string (result);
2482 xfree (result);
2483 return lisp_result;
2484 }
2485}
2486
2487
2488DEFUN ("mac-filename-to-unix", Fmac_filename_to_unix, Smac_filename_to_unix, 1,
2489 1, 0,
2490 "Convert Macintosh filename to Unix form.")
2491 (mac_filename)
2492 Lisp_Object mac_filename;
2493{
2494 char unix_filename[MAXPATHLEN+1];
2495
2496 CHECK_STRING (mac_filename, 0);
2497
2498 if (mac_to_unix_pathname(XSTRING (mac_filename)->data, unix_filename,
2499 MAXPATHLEN))
2500 return build_string (unix_filename);
2501 else
2502 return Qnil;
2503}
2504
2505
2506DEFUN ("unix-filename-to-mac", Funix_filename_to_mac, Sunix_filename_to_mac, 1,
2507 1, 0,
2508 "Convert Unix filename to Mac form.")
2509 (unix_filename)
2510 Lisp_Object unix_filename;
2511{
2512 char mac_filename[MAXPATHLEN+1];
2513
2514 CHECK_STRING (unix_filename, 0);
2515
2516 if (unix_to_mac_pathname(XSTRING (unix_filename)->data, mac_filename,
2517 MAXPATHLEN))
2518 return build_string (mac_filename);
2519 else
2520 return Qnil;
2521}
2522
2523
2524/* set interprogram-paste-function to mac-paste-function in mac-win.el
2525 to enable Emacs to obtain the contents of the Mac clipboard. */
2526DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0,
2527 "Return the contents of the Mac clipboard as a string.")
2528 ()
2529{
2530 Lisp_Object value;
2531 Handle my_handle;
2532 long scrap_offset, rc, i;
2533
2534 my_handle = NewHandle (0); /* allocate 0-length data area */
2535
2536 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2537 if (rc < 0)
2538 return Qnil;
2539
2540 HLock (my_handle);
2541
2542 /* Emacs expects clipboard contents have Unix-style eol's */
2543 for (i = 0; i < rc; i++)
2544 if ((*my_handle)[i] == '\r')
2545 (*my_handle)[i] = '\n';
2546
2547 value = make_string (*my_handle, rc);
2548
2549 HUnlock (my_handle);
2550
2551 DisposeHandle (my_handle);
2552
2553 return value;
2554}
2555
2556
2557/* set interprogram-cut-function to mac-cut-function in mac-win.el
2558 to enable Emacs to write the top of the kill-ring to the Mac clipboard. */
2559DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0,
2560 "Put the value of the string parameter to the Mac clipboard.")
2561 (value, push)
2562 Lisp_Object value, push;
2563{
2564 char *buf;
2565 int len, i;
2566
2567 /* fixme: ignore the push flag for now */
2568
2569 CHECK_STRING (value, 0);
2570
2571 len = XSTRING (value)->size;
2572 buf = (char *) alloca (len);
2573 bcopy(XSTRING (value)->data, buf, len);
2574
2575 /* convert to Mac-style eol's before sending to clipboard */
2576 for (i = 0; i < len; i++)
2577 if (buf[i] == '\n')
2578 buf[i] = '\r';
2579
2580 ZeroScrap ();
2581 PutScrap (len, 'TEXT', buf);
2582
2583 return Qnil;
2584}
2585
2586
2587DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
2588 0, 1, 0,
2589 "Whether there is an owner for the given X Selection.\n\
2590The arg should be the name of the selection in question, typically one of\n\
2591the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
2592\(Those are literal upper-case symbol names, since that's what X expects.)\n\
2593For convenience, the symbol nil is the same as `PRIMARY',\n\
2594and t is the same as `SECONDARY'.")
2595 (selection)
2596 Lisp_Object selection;
2597{
2598 CHECK_SYMBOL (selection, 0);
2599
2600 /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
2601 if the clipboard currently has valid text format contents. */
2602
2603 if (EQ (selection, QCLIPBOARD))
2604 {
2605 Lisp_Object val = Qnil;
2606 Lisp_Object value;
2607 Handle my_handle;
2608 long rc, scrap_offset;
2609
2610 my_handle = NewHandle (0);
2611
2612 rc = GetScrap (my_handle, 'TEXT', &scrap_offset);
2613 if (rc >= 0)
2614 val = Qt;
2615
2616 DisposeHandle (my_handle);
2617
2618 return val;
2619 }
2620 return Qnil;
2621}
2622
2623
2624void
2625syms_of_mac ()
2626{
2627 QCLIPBOARD = intern ("CLIPBOARD");
2628 staticpro (&QCLIPBOARD);
2629
2630 defsubr (&Smac_paste_function);
2631 defsubr (&Smac_cut_function);
2632 defsubr (&Sx_selection_exists_p);
2633
2634 defsubr (&Sdo_applescript);
2635 defsubr (&Smac_filename_to_unix);
2636 defsubr (&Sunix_filename_to_mac);
2637}
diff --git a/mac/src/macfns.c b/mac/src/macfns.c
new file mode 100644
index 00000000000..bb3ba197cac
--- /dev/null
+++ b/mac/src/macfns.c
@@ -0,0 +1,9913 @@
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 double atof ();
78extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
79extern int quit_char;*/
80
81/* A definition of XColor for non-X frames. */
82#ifndef HAVE_X_WINDOWS
83typedef struct {
84 unsigned long pixel;
85 unsigned short red, green, blue;
86 char flags;
87 char pad;
88} XColor;
89#endif
90
91extern char *lispy_function_keys[];
92
93/* The gray bitmap `bitmaps/gray'. This is done because macterm.c uses
94 it, and including `bitmaps/gray' more than once is a problem when
95 config.h defines `static' as an empty replacement string. */
96
97int gray_bitmap_width = gray_width;
98int gray_bitmap_height = gray_height;
99unsigned char *gray_bitmap_bits = gray_bits;
100
101/* The name we're using in resource queries. */
102
103Lisp_Object Vx_resource_name;
104
105/* Non nil if no window manager is in use. */
106
107Lisp_Object Vx_no_window_manager;
108
109/* Non-zero means we're allowed to display a busy cursor. */
110
111int display_busy_cursor_p;
112
113/* The background and shape of the mouse pointer, and shape when not
114 over text or in the modeline. */
115
116Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
117Lisp_Object Vx_busy_pointer_shape;
118
119/* The shape when over mouse-sensitive text. */
120
121Lisp_Object Vx_sensitive_text_pointer_shape;
122
123/* Color of chars displayed in cursor box. */
124
125Lisp_Object Vx_cursor_fore_pixel;
126
127/* Nonzero if using Windows. */
128
129static int mac_in_use;
130
131/* Search path for bitmap files. */
132
133Lisp_Object Vx_bitmap_file_path;
134
135/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
136
137Lisp_Object Vx_pixel_size_width_font_regexp;
138
139/* Evaluate this expression to rebuild the section of syms_of_macfns
140 that initializes and staticpros the symbols declared below. Note
141 that Emacs 18 has a bug that keeps C-x C-e from being able to
142 evaluate this expression.
143
144(progn
145 ;; Accumulate a list of the symbols we want to initialize from the
146 ;; declarations at the top of the file.
147 (goto-char (point-min))
148 (search-forward "/\*&&& symbols declared here &&&*\/\n")
149 (let (symbol-list)
150 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
151 (setq symbol-list
152 (cons (buffer-substring (match-beginning 1) (match-end 1))
153 symbol-list))
154 (forward-line 1))
155 (setq symbol-list (nreverse symbol-list))
156 ;; Delete the section of syms_of_... where we initialize the symbols.
157 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
158 (let ((start (point)))
159 (while (looking-at "^ Q")
160 (forward-line 2))
161 (kill-region start (point)))
162 ;; Write a new symbol initialization section.
163 (while symbol-list
164 (insert (format " %s = intern (\"" (car symbol-list)))
165 (let ((start (point)))
166 (insert (substring (car symbol-list) 1))
167 (subst-char-in-region start (point) ?_ ?-))
168 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
169 (setq symbol-list (cdr symbol-list)))))
170
171 */
172
173/*&&& symbols declared here &&&*/
174Lisp_Object Qauto_raise;
175Lisp_Object Qauto_lower;
176Lisp_Object Qbar;
177Lisp_Object Qborder_color;
178Lisp_Object Qborder_width;
179Lisp_Object Qbox;
180Lisp_Object Qcursor_color;
181Lisp_Object Qcursor_type;
182Lisp_Object Qgeometry;
183Lisp_Object Qicon_left;
184Lisp_Object Qicon_top;
185Lisp_Object Qicon_type;
186Lisp_Object Qicon_name;
187Lisp_Object Qinternal_border_width;
188Lisp_Object Qleft;
189Lisp_Object Qright;
190Lisp_Object Qmouse_color;
191Lisp_Object Qnone;
192Lisp_Object Qparent_id;
193Lisp_Object Qscroll_bar_width;
194Lisp_Object Qsuppress_icon;
195Lisp_Object Qundefined_color;
196Lisp_Object Qvertical_scroll_bars;
197Lisp_Object Qvisibility;
198Lisp_Object Qwindow_id;
199Lisp_Object Qx_frame_parameter;
200Lisp_Object Qx_resource_name;
201Lisp_Object Quser_position;
202Lisp_Object Quser_size;
203Lisp_Object Qscreen_gamma;
204Lisp_Object Qline_spacing;
205Lisp_Object Qcenter;
206Lisp_Object Qhyper;
207Lisp_Object Qsuper;
208Lisp_Object Qmeta;
209Lisp_Object Qalt;
210Lisp_Object Qctrl;
211Lisp_Object Qcontrol;
212Lisp_Object Qshift;
213
214extern Lisp_Object Qtop;
215extern Lisp_Object Qdisplay;
216Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
217extern Lisp_Object Qtool_bar_lines;
218
219/* These are defined in frame.c. */
220extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
221extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
222extern Lisp_Object Qtool_bar_lines;
223
224extern Lisp_Object Vwindow_system_version;
225
226Lisp_Object Qface_set_after_frame_default;
227
228/* Functions in macterm.c. */
229extern void x_set_offset (struct frame *, int, int, int);
230extern void x_wm_set_icon_position (struct frame *, int, int);
231extern void x_display_cursor (struct window *, int, int, int, int, int);
232extern void x_set_window_size (struct frame *, int, int, int);
233extern void x_make_frame_visible (struct frame *);
234extern struct mac_display_info *x_term_init (Lisp_Object, char *, char *);
235extern struct font_info *x_get_font_info (FRAME_PTR, int);
236extern struct font_info *x_load_font (struct frame *, char *, int);
237extern void x_find_ccl_program (struct font_info *);
238extern struct font_info *x_query_font (struct frame *, char *);
239
240
241/* compare two strings ignoring case */
242
243static int
244stricmp (const char *s, const char *t)
245{
246 for ( ; tolower (*s) == tolower (*t); s++, t++)
247 if (*s == '\0')
248 return 0;
249 return tolower (*s) - tolower (*t);
250}
251
252/* compare two strings up to n characters, ignoring case */
253
254static int
255strnicmp (const char *s, const char *t, unsigned int n)
256{
257 for ( ; n-- > 0 && tolower (*s) == tolower (*t); s++, t++)
258 if (*s == '\0')
259 return 0;
260 return n == 0 ? 0 : tolower (*s) - tolower (*t);
261}
262
263
264/* Error if we are not running on Mac OS. */
265
266void
267check_mac ()
268{
269 if (! mac_in_use)
270 error ("Mac OS not in use or not initialized");
271}
272
273/* Nonzero if we can use mouse menus.
274 You should not call this unless HAVE_MENUS is defined. */
275
276int
277have_menus_p ()
278{
279 return mac_in_use;
280}
281
282/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
283 and checking validity for W32. */
284
285FRAME_PTR
286check_x_frame (frame)
287 Lisp_Object frame;
288{
289 FRAME_PTR f;
290
291 if (NILP (frame))
292 frame = selected_frame;
293 CHECK_LIVE_FRAME (frame, 0);
294 f = XFRAME (frame);
295 if (! FRAME_MAC_P (f))
296 error ("non-mac frame used");
297 return f;
298}
299
300/* Let the user specify an display with a frame.
301 nil stands for the selected frame--or, if that is not a mac frame,
302 the first display on the list. */
303
304static struct mac_display_info *
305check_x_display_info (frame)
306 Lisp_Object frame;
307{
308 if (NILP (frame))
309 {
310 struct frame *sf = XFRAME (selected_frame);
311
312 if (FRAME_MAC_P (sf) && FRAME_LIVE_P (sf))
313 return FRAME_MAC_DISPLAY_INFO (sf);
314 else
315 return &one_mac_display_info;
316 }
317 else if (STRINGP (frame))
318 return x_display_info_for_name (frame);
319 else
320 {
321 FRAME_PTR f;
322
323 CHECK_LIVE_FRAME (frame, 0);
324 f = XFRAME (frame);
325 if (! FRAME_MAC_P (f))
326 error ("non-mac frame used");
327 return FRAME_MAC_DISPLAY_INFO (f);
328 }
329}
330
331/* Return the Emacs frame-object corresponding to an mac window.
332 It could be the frame's main window or an icon window. */
333
334/* This function can be called during GC, so use GC_xxx type test macros. */
335
336struct frame *
337x_window_to_frame (dpyinfo, wdesc)
338 struct mac_display_info *dpyinfo;
339 WindowPtr wdesc;
340{
341 Lisp_Object tail, frame;
342 struct frame *f;
343
344 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
345 {
346 frame = XCAR (tail);
347 if (!GC_FRAMEP (frame))
348 continue;
349 f = XFRAME (frame);
350 if (!FRAME_W32_P (f) || FRAME_MAC_DISPLAY_INFO (f) != dpyinfo)
351 continue;
352 /*if (f->output_data.w32->busy_window == wdesc)
353 return f;*/
354
355 /* MAC_TODO: Check tooltips when supported. */
356 if (FRAME_MAC_WINDOW (f) == wdesc)
357 return f;
358 }
359 return 0;
360}
361
362
363
364/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
365 id, which is just an int that this section returns. Bitmaps are
366 reference counted so they can be shared among frames.
367
368 Bitmap indices are guaranteed to be > 0, so a negative number can
369 be used to indicate no bitmap.
370
371 If you use x_create_bitmap_from_data, then you must keep track of
372 the bitmaps yourself. That is, creating a bitmap from the same
373 data more than once will not be caught. */
374
375
376/* Functions to access the contents of a bitmap, given an id. */
377
378int
379x_bitmap_height (f, id)
380 FRAME_PTR f;
381 int id;
382{
383 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height;
384}
385
386int
387x_bitmap_width (f, id)
388 FRAME_PTR f;
389 int id;
390{
391 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width;
392}
393
394#if 0 /* MAC_TODO : not used anywhere (?) */
395int
396x_bitmap_pixmap (f, id)
397 FRAME_PTR f;
398 int id;
399{
400 return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
401}
402#endif
403
404/* Allocate a new bitmap record. Returns index of new record. */
405
406static int
407x_allocate_bitmap_record (f)
408 FRAME_PTR f;
409{
410 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
411 int i;
412
413 if (dpyinfo->bitmaps == NULL)
414 {
415 dpyinfo->bitmaps_size = 10;
416 dpyinfo->bitmaps = (struct mac_bitmap_record *)
417 xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
418 dpyinfo->bitmaps_last = 1;
419 return 1;
420 }
421
422 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
423 return ++dpyinfo->bitmaps_last;
424
425 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
426 if (dpyinfo->bitmaps[i].refcount == 0)
427 return i + 1;
428
429 dpyinfo->bitmaps_size *= 2;
430 dpyinfo->bitmaps = (struct mac_bitmap_record *)
431 xrealloc (dpyinfo->bitmaps,
432 dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
433 return ++dpyinfo->bitmaps_last;
434}
435
436/* Add one reference to the reference count of the bitmap with id
437 ID. */
438
439void
440x_reference_bitmap (f, id)
441 FRAME_PTR f;
442 int id;
443{
444 ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
445}
446
447/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at
448 BITS. */
449
450int
451x_create_bitmap_from_data (f, bits, width, height)
452 struct frame *f;
453 char *bits;
454 unsigned int width, height;
455{
456 struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
457 int id;
458
459 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
460
461 id = x_allocate_bitmap_record (f);
462
463 if (width % 16 != 0)
464 return -1;
465
466 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
467 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
468 return -1;
469
470 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
471
472 dpyinfo->bitmaps[id - 1].refcount = 1;
473 dpyinfo->bitmaps[id - 1].height = height;
474 dpyinfo->bitmaps[id - 1].width = width;
475
476 return id;
477}
478
479/* Create bitmap from file FILE for frame F. */
480
481int
482x_create_bitmap_from_file (f, file)
483 struct frame *f;
484 Lisp_Object file;
485{
486 return -1;
487#if 0 /* MAC_TODO : bitmap support */
488 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
489 unsigned int width, height;
490 HBITMAP bitmap;
491 int xhot, yhot, result, id;
492 Lisp_Object found;
493 int fd;
494 char *filename;
495 HINSTANCE hinst;
496
497 /* Look for an existing bitmap with the same name. */
498 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
499 {
500 if (dpyinfo->bitmaps[id].refcount
501 && dpyinfo->bitmaps[id].file
502 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
503 {
504 ++dpyinfo->bitmaps[id].refcount;
505 return id + 1;
506 }
507 }
508
509 /* Search bitmap-file-path for the file, if appropriate. */
510 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
511 if (fd < 0)
512 return -1;
513 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
514 if (fd == 0)
515 return -1;
516 emacs_close (fd);
517
518 filename = (char *) XSTRING (found)->data;
519
520 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
521
522 if (hinst == NULL)
523 return -1;
524
525
526 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
527 filename, &width, &height, &bitmap, &xhot, &yhot);
528 if (result != BitmapSuccess)
529 return -1;
530
531 id = x_allocate_bitmap_record (f);
532 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
533 dpyinfo->bitmaps[id - 1].refcount = 1;
534 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
535 dpyinfo->bitmaps[id - 1].depth = 1;
536 dpyinfo->bitmaps[id - 1].height = height;
537 dpyinfo->bitmaps[id - 1].width = width;
538 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
539
540 return id;
541#endif /* MAC_TODO */
542}
543
544/* Remove reference to bitmap with id number ID. */
545
546void
547x_destroy_bitmap (f, id)
548 FRAME_PTR f;
549 int id;
550{
551 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
552
553 if (id > 0)
554 {
555 --dpyinfo->bitmaps[id - 1].refcount;
556 if (dpyinfo->bitmaps[id - 1].refcount == 0)
557 {
558 BLOCK_INPUT;
559 dpyinfo->bitmaps[id - 1].bitmap_data = NULL;
560 UNBLOCK_INPUT;
561 }
562 }
563}
564
565/* Free all the bitmaps for the display specified by DPYINFO. */
566
567static void
568x_destroy_all_bitmaps (dpyinfo)
569 struct mac_display_info *dpyinfo;
570{
571 int i;
572 for (i = 0; i < dpyinfo->bitmaps_last; i++)
573 if (dpyinfo->bitmaps[i].refcount > 0)
574 xfree (dpyinfo->bitmaps[i].bitmap_data);
575 dpyinfo->bitmaps_last = 0;
576}
577
578/* Connect the frame-parameter names for W32 frames
579 to the ways of passing the parameter values to the window system.
580
581 The name of a parameter, as a Lisp symbol,
582 has an `x-frame-parameter' property which is an integer in Lisp
583 but can be interpreted as an `enum x_frame_parm' in C. */
584
585struct x_frame_parm_table
586{
587 char *name;
588 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
589};
590
591void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
592static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
593void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
594void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
595void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
596void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
597void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
598void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
599void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
600void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
601void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
602void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
603 Lisp_Object));
604void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
605void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
606void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
607void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
608 Lisp_Object));
609void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
610void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
611void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
612void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
613void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
614void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
615void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
616 Lisp_Object));
617void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
618 Lisp_Object));
619static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
620 Lisp_Object,
621 Lisp_Object,
622 char *, char *,
623 int));
624static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
625
626static struct x_frame_parm_table x_frame_parms[] =
627{
628 "auto-raise", x_set_autoraise,
629 "auto-lower", x_set_autolower,
630 "background-color", x_set_background_color,
631 "border-color", x_set_border_color,
632 "border-width", x_set_border_width,
633 "cursor-color", x_set_cursor_color,
634 "cursor-type", x_set_cursor_type,
635 "font", x_set_font,
636 "foreground-color", x_set_foreground_color,
637 "icon-name", x_set_icon_name,
638#if 0 /* MAC_TODO: no icons for Mac */
639 "icon-type", x_set_icon_type,
640#endif
641 "internal-border-width", x_set_internal_border_width,
642 "menu-bar-lines", x_set_menu_bar_lines,
643 "mouse-color", x_set_mouse_color,
644 "name", x_explicitly_set_name,
645 "scroll-bar-width", x_set_scroll_bar_width,
646 "title", x_set_title,
647 "unsplittable", x_set_unsplittable,
648 "vertical-scroll-bars", x_set_vertical_scroll_bars,
649 "visibility", x_set_visibility,
650 "tool-bar-lines", x_set_tool_bar_lines,
651#if 0 /* MAC_TODO: cannot set color of scroll bar on the Mac? */
652 "scroll-bar-foreground", x_set_scroll_bar_foreground,
653 "scroll-bar-background", x_set_scroll_bar_background,
654#endif
655 "screen-gamma", x_set_screen_gamma,
656 "line-spacing", x_set_line_spacing
657};
658
659/* Attach the `x-frame-parameter' properties to
660 the Lisp symbol names of parameters relevant to Mac. */
661
662void
663init_x_parm_symbols ()
664{
665 int i;
666
667 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
668 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
669 make_number (i));
670}
671
672/* Change the parameters of frame F as specified by ALIST.
673 If a parameter is not specially recognized, do nothing;
674 otherwise call the `x_set_...' function for that parameter. */
675
676void
677x_set_frame_parameters (f, alist)
678 FRAME_PTR f;
679 Lisp_Object alist;
680{
681 Lisp_Object tail;
682
683 /* If both of these parameters are present, it's more efficient to
684 set them both at once. So we wait until we've looked at the
685 entire list before we set them. */
686 int width, height;
687
688 /* Same here. */
689 Lisp_Object left, top;
690
691 /* Same with these. */
692 Lisp_Object icon_left, icon_top;
693
694 /* Record in these vectors all the parms specified. */
695 Lisp_Object *parms;
696 Lisp_Object *values;
697 int i, p;
698 int left_no_change = 0, top_no_change = 0;
699 int icon_left_no_change = 0, icon_top_no_change = 0;
700
701 struct gcpro gcpro1, gcpro2;
702
703 i = 0;
704 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
705 i++;
706
707 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
708 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
709
710 /* Extract parm names and values into those vectors. */
711
712 i = 0;
713 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
714 {
715 Lisp_Object elt;
716
717 elt = Fcar (tail);
718 parms[i] = Fcar (elt);
719 values[i] = Fcdr (elt);
720 i++;
721 }
722 /* TAIL and ALIST are not used again below here. */
723 alist = tail = Qnil;
724
725 GCPRO2 (*parms, *values);
726 gcpro1.nvars = i;
727 gcpro2.nvars = i;
728
729 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
730 because their values appear in VALUES and strings are not valid. */
731 top = left = Qunbound;
732 icon_left = icon_top = Qunbound;
733
734 /* Provide default values for HEIGHT and WIDTH. */
735 if (FRAME_NEW_WIDTH (f))
736 width = FRAME_NEW_WIDTH (f);
737 else
738 width = FRAME_WIDTH (f);
739
740 if (FRAME_NEW_HEIGHT (f))
741 height = FRAME_NEW_HEIGHT (f);
742 else
743 height = FRAME_HEIGHT (f);
744
745 /* Process foreground_color and background_color before anything else.
746 They are independent of other properties, but other properties (e.g.,
747 cursor_color) are dependent upon them. */
748 for (p = 0; p < i; p++)
749 {
750 Lisp_Object prop, val;
751
752 prop = parms[p];
753 val = values[p];
754 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
755 {
756 register Lisp_Object param_index, old_value;
757
758 param_index = Fget (prop, Qx_frame_parameter);
759 old_value = get_frame_param (f, prop);
760 store_frame_param (f, prop, val);
761 if (NATNUMP (param_index)
762 && (XFASTINT (param_index)
763 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
764 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
765 }
766 }
767
768 /* Now process them in reverse of specified order. */
769 for (i--; i >= 0; i--)
770 {
771 Lisp_Object prop, val;
772
773 prop = parms[i];
774 val = values[i];
775
776 if (EQ (prop, Qwidth) && NUMBERP (val))
777 width = XFASTINT (val);
778 else if (EQ (prop, Qheight) && NUMBERP (val))
779 height = XFASTINT (val);
780 else if (EQ (prop, Qtop))
781 top = val;
782 else if (EQ (prop, Qleft))
783 left = val;
784 else if (EQ (prop, Qicon_top))
785 icon_top = val;
786 else if (EQ (prop, Qicon_left))
787 icon_left = val;
788 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
789 /* Processed above. */
790 continue;
791 else
792 {
793 register Lisp_Object param_index, old_value;
794
795 param_index = Fget (prop, Qx_frame_parameter);
796 old_value = get_frame_param (f, prop);
797 store_frame_param (f, prop, val);
798 if (NATNUMP (param_index)
799 && (XFASTINT (param_index)
800 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
801 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
802 }
803 }
804
805 /* Don't die if just one of these was set. */
806 if (EQ (left, Qunbound))
807 {
808 left_no_change = 1;
809 if (f->output_data.mac->left_pos < 0)
810 left = Fcons (Qplus,
811 Fcons (make_number (f->output_data.mac->left_pos),
812 Qnil));
813 else
814 XSETINT (left, f->output_data.mac->left_pos);
815 }
816 if (EQ (top, Qunbound))
817 {
818 top_no_change = 1;
819 if (f->output_data.mac->top_pos < 0)
820 top = Fcons (Qplus,
821 Fcons (make_number (f->output_data.mac->top_pos), Qnil));
822 else
823 XSETINT (top, f->output_data.mac->top_pos);
824 }
825
826 /* If one of the icon positions was not set, preserve or default it. */
827 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
828 {
829 icon_left_no_change = 1;
830 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
831 if (NILP (icon_left))
832 XSETINT (icon_left, 0);
833 }
834 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
835 {
836 icon_top_no_change = 1;
837 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
838 if (NILP (icon_top))
839 XSETINT (icon_top, 0);
840 }
841
842 /* Don't set these parameters unless they've been explicitly
843 specified. The window might be mapped or resized while we're in
844 this function, and we don't want to override that unless the lisp
845 code has asked for it.
846
847 Don't set these parameters unless they actually differ from the
848 window's current parameters; the window may not actually exist
849 yet. */
850 {
851 Lisp_Object frame;
852
853 check_frame_size (f, &height, &width);
854
855 XSETFRAME (frame, f);
856
857 if (width != FRAME_WIDTH (f)
858 || height != FRAME_HEIGHT (f)
859 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
860 Fset_frame_size (frame, make_number (width), make_number (height));
861
862 if ((!NILP (left) || !NILP (top))
863 && ! (left_no_change && top_no_change)
864 && ! (NUMBERP (left) && XINT (left) == f->output_data.mac->left_pos
865 && NUMBERP (top) && XINT (top) == f->output_data.mac->top_pos))
866 {
867 int leftpos = 0;
868 int toppos = 0;
869
870 /* Record the signs. */
871 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
872 if (EQ (left, Qminus))
873 f->output_data.mac->size_hint_flags |= XNegative;
874 else if (INTEGERP (left))
875 {
876 leftpos = XINT (left);
877 if (leftpos < 0)
878 f->output_data.mac->size_hint_flags |= XNegative;
879 }
880 else if (CONSP (left) && EQ (XCAR (left), Qminus)
881 && CONSP (XCDR (left))
882 && INTEGERP (XCAR (XCDR (left))))
883 {
884 leftpos = - XINT (XCAR (XCDR (left)));
885 f->output_data.mac->size_hint_flags |= XNegative;
886 }
887 else if (CONSP (left) && EQ (XCAR (left), Qplus)
888 && CONSP (XCDR (left))
889 && INTEGERP (XCAR (XCDR (left))))
890 {
891 leftpos = XINT (XCAR (XCDR (left)));
892 }
893
894 if (EQ (top, Qminus))
895 f->output_data.mac->size_hint_flags |= YNegative;
896 else if (INTEGERP (top))
897 {
898 toppos = XINT (top);
899 if (toppos < 0)
900 f->output_data.mac->size_hint_flags |= YNegative;
901 }
902 else if (CONSP (top) && EQ (XCAR (top), Qminus)
903 && CONSP (XCDR (top))
904 && INTEGERP (XCAR (XCDR (top))))
905 {
906 toppos = - XINT (XCAR (XCDR (top)));
907 f->output_data.mac->size_hint_flags |= YNegative;
908 }
909 else if (CONSP (top) && EQ (XCAR (top), Qplus)
910 && CONSP (XCDR (top))
911 && INTEGERP (XCAR (XCDR (top))))
912 {
913 toppos = XINT (XCAR (XCDR (top)));
914 }
915
916
917 /* Store the numeric value of the position. */
918 f->output_data.mac->top_pos = toppos;
919 f->output_data.mac->left_pos = leftpos;
920
921 f->output_data.mac->win_gravity = NorthWestGravity;
922
923 /* Actually set that position, and convert to absolute. */
924 x_set_offset (f, leftpos, toppos, -1);
925 }
926
927 if ((!NILP (icon_left) || !NILP (icon_top))
928 && ! (icon_left_no_change && icon_top_no_change))
929 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
930 }
931
932 UNGCPRO;
933}
934
935/* Store the screen positions of frame F into XPTR and YPTR.
936 These are the positions of the containing window manager window,
937 not Emacs's own window. */
938
939void
940x_real_positions (f, xptr, yptr)
941 FRAME_PTR f;
942 int *xptr, *yptr;
943{
944 Point pt;
945 GrafPtr oldport;
946
947 SetPt (&pt,
948 f->output_data.mac->mWP->portRect.left,
949 f->output_data.mac->mWP->portRect.top);
950 GetPort (&oldport);
951 LocalToGlobal (&pt);
952 SetPort (oldport);
953
954 *xptr = pt.h;
955 *yptr = pt.v;
956}
957
958/* Insert a description of internally-recorded parameters of frame X
959 into the parameter alist *ALISTPTR that is to be given to the user.
960 Only parameters that are specific to Mac and whose values are not
961 correctly recorded in the frame's param_alist need to be considered
962 here. */
963
964void
965x_report_frame_params (f, alistptr)
966 struct frame *f;
967 Lisp_Object *alistptr;
968{
969 char buf[16];
970 Lisp_Object tem;
971
972 /* Represent negative positions (off the top or left screen edge)
973 in a way that Fmodify_frame_parameters will understand correctly. */
974 XSETINT (tem, f->output_data.mac->left_pos);
975 if (f->output_data.mac->left_pos >= 0)
976 store_in_alist (alistptr, Qleft, tem);
977 else
978 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
979
980 XSETINT (tem, f->output_data.mac->top_pos);
981 if (f->output_data.mac->top_pos >= 0)
982 store_in_alist (alistptr, Qtop, tem);
983 else
984 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
985
986 store_in_alist (alistptr, Qborder_width,
987 make_number (f->output_data.mac->border_width));
988 store_in_alist (alistptr, Qinternal_border_width,
989 make_number (f->output_data.mac->internal_border_width));
990 sprintf (buf, "%ld", (long) FRAME_MAC_WINDOW (f));
991 store_in_alist (alistptr, Qwindow_id,
992 build_string (buf));
993 store_in_alist (alistptr, Qicon_name, f->icon_name);
994 FRAME_SAMPLE_VISIBILITY (f);
995 store_in_alist (alistptr, Qvisibility,
996 (FRAME_VISIBLE_P (f) ? Qt
997 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
998 store_in_alist (alistptr, Qdisplay,
999 XCAR (FRAME_MAC_DISPLAY_INFO (f)->name_list_element));
1000}
1001
1002/* The default colors for the Mac color map */
1003typedef struct colormap_t
1004{
1005 unsigned long color;
1006 char *name;
1007} colormap_t;
1008
1009colormap_t mac_color_map[] =
1010{
1011 { RGB_TO_ULONG(255, 250, 250), "snow" },
1012 { RGB_TO_ULONG(248, 248, 255), "ghost white" },
1013 { RGB_TO_ULONG(248, 248, 255), "GhostWhite" },
1014 { RGB_TO_ULONG(245, 245, 245), "white smoke" },
1015 { RGB_TO_ULONG(245, 245, 245), "WhiteSmoke" },
1016 { RGB_TO_ULONG(220, 220, 220), "gainsboro" },
1017 { RGB_TO_ULONG(255, 250, 240), "floral white" },
1018 { RGB_TO_ULONG(255, 250, 240), "FloralWhite" },
1019 { RGB_TO_ULONG(253, 245, 230), "old lace" },
1020 { RGB_TO_ULONG(253, 245, 230), "OldLace" },
1021 { RGB_TO_ULONG(250, 240, 230), "linen" },
1022 { RGB_TO_ULONG(250, 235, 215), "antique white" },
1023 { RGB_TO_ULONG(250, 235, 215), "AntiqueWhite" },
1024 { RGB_TO_ULONG(255, 239, 213), "papaya whip" },
1025 { RGB_TO_ULONG(255, 239, 213), "PapayaWhip" },
1026 { RGB_TO_ULONG(255, 235, 205), "blanched almond" },
1027 { RGB_TO_ULONG(255, 235, 205), "BlanchedAlmond" },
1028 { RGB_TO_ULONG(255, 228, 196), "bisque" },
1029 { RGB_TO_ULONG(255, 218, 185), "peach puff" },
1030 { RGB_TO_ULONG(255, 218, 185), "PeachPuff" },
1031 { RGB_TO_ULONG(255, 222, 173), "navajo white" },
1032 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite" },
1033 { RGB_TO_ULONG(255, 228, 181), "moccasin" },
1034 { RGB_TO_ULONG(255, 248, 220), "cornsilk" },
1035 { RGB_TO_ULONG(255, 255, 240), "ivory" },
1036 { RGB_TO_ULONG(255, 250, 205), "lemon chiffon" },
1037 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon" },
1038 { RGB_TO_ULONG(255, 245, 238), "seashell" },
1039 { RGB_TO_ULONG(240, 255, 240), "honeydew" },
1040 { RGB_TO_ULONG(245, 255, 250), "mint cream" },
1041 { RGB_TO_ULONG(245, 255, 250), "MintCream" },
1042 { RGB_TO_ULONG(240, 255, 255), "azure" },
1043 { RGB_TO_ULONG(240, 248, 255), "alice blue" },
1044 { RGB_TO_ULONG(240, 248, 255), "AliceBlue" },
1045 { RGB_TO_ULONG(230, 230, 250), "lavender" },
1046 { RGB_TO_ULONG(255, 240, 245), "lavender blush" },
1047 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush" },
1048 { RGB_TO_ULONG(255, 228, 225), "misty rose" },
1049 { RGB_TO_ULONG(255, 228, 225), "MistyRose" },
1050 { RGB_TO_ULONG(255, 255, 255), "white" },
1051 { RGB_TO_ULONG(0 , 0 , 0 ), "black" },
1052 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate gray" },
1053 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGray" },
1054 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate grey" },
1055 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGrey" },
1056 { RGB_TO_ULONG(105, 105, 105), "dim gray" },
1057 { RGB_TO_ULONG(105, 105, 105), "DimGray" },
1058 { RGB_TO_ULONG(105, 105, 105), "dim grey" },
1059 { RGB_TO_ULONG(105, 105, 105), "DimGrey" },
1060 { RGB_TO_ULONG(112, 128, 144), "slate gray" },
1061 { RGB_TO_ULONG(112, 128, 144), "SlateGray" },
1062 { RGB_TO_ULONG(112, 128, 144), "slate grey" },
1063 { RGB_TO_ULONG(112, 128, 144), "SlateGrey" },
1064 { RGB_TO_ULONG(119, 136, 153), "light slate gray" },
1065 { RGB_TO_ULONG(119, 136, 153), "LightSlateGray" },
1066 { RGB_TO_ULONG(119, 136, 153), "light slate grey" },
1067 { RGB_TO_ULONG(119, 136, 153), "LightSlateGrey" },
1068 { RGB_TO_ULONG(190, 190, 190), "gray" },
1069 { RGB_TO_ULONG(190, 190, 190), "grey" },
1070 { RGB_TO_ULONG(211, 211, 211), "light grey" },
1071 { RGB_TO_ULONG(211, 211, 211), "LightGrey" },
1072 { RGB_TO_ULONG(211, 211, 211), "light gray" },
1073 { RGB_TO_ULONG(211, 211, 211), "LightGray" },
1074 { RGB_TO_ULONG(25 , 25 , 112), "midnight blue" },
1075 { RGB_TO_ULONG(25 , 25 , 112), "MidnightBlue" },
1076 { RGB_TO_ULONG(0 , 0 , 128), "navy" },
1077 { RGB_TO_ULONG(0 , 0 , 128), "navy blue" },
1078 { RGB_TO_ULONG(0 , 0 , 128), "NavyBlue" },
1079 { RGB_TO_ULONG(100, 149, 237), "cornflower blue" },
1080 { RGB_TO_ULONG(100, 149, 237), "CornflowerBlue" },
1081 { RGB_TO_ULONG(72 , 61 , 139), "dark slate blue" },
1082 { RGB_TO_ULONG(72 , 61 , 139), "DarkSlateBlue" },
1083 { RGB_TO_ULONG(106, 90 , 205), "slate blue" },
1084 { RGB_TO_ULONG(106, 90 , 205), "SlateBlue" },
1085 { RGB_TO_ULONG(123, 104, 238), "medium slate blue" },
1086 { RGB_TO_ULONG(123, 104, 238), "MediumSlateBlue" },
1087 { RGB_TO_ULONG(132, 112, 255), "light slate blue" },
1088 { RGB_TO_ULONG(132, 112, 255), "LightSlateBlue" },
1089 { RGB_TO_ULONG(0 , 0 , 205), "medium blue" },
1090 { RGB_TO_ULONG(0 , 0 , 205), "MediumBlue" },
1091 { RGB_TO_ULONG(65 , 105, 225), "royal blue" },
1092 { RGB_TO_ULONG(65 , 105, 225), "RoyalBlue" },
1093 { RGB_TO_ULONG(0 , 0 , 255), "blue" },
1094 { RGB_TO_ULONG(30 , 144, 255), "dodger blue" },
1095 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue" },
1096 { RGB_TO_ULONG(0 , 191, 255), "deep sky blue" },
1097 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue" },
1098 { RGB_TO_ULONG(135, 206, 235), "sky blue" },
1099 { RGB_TO_ULONG(135, 206, 235), "SkyBlue" },
1100 { RGB_TO_ULONG(135, 206, 250), "light sky blue" },
1101 { RGB_TO_ULONG(135, 206, 250), "LightSkyBlue" },
1102 { RGB_TO_ULONG(70 , 130, 180), "steel blue" },
1103 { RGB_TO_ULONG(70 , 130, 180), "SteelBlue" },
1104 { RGB_TO_ULONG(176, 196, 222), "light steel blue" },
1105 { RGB_TO_ULONG(176, 196, 222), "LightSteelBlue" },
1106 { RGB_TO_ULONG(173, 216, 230), "light blue" },
1107 { RGB_TO_ULONG(173, 216, 230), "LightBlue" },
1108 { RGB_TO_ULONG(176, 224, 230), "powder blue" },
1109 { RGB_TO_ULONG(176, 224, 230), "PowderBlue" },
1110 { RGB_TO_ULONG(175, 238, 238), "pale turquoise" },
1111 { RGB_TO_ULONG(175, 238, 238), "PaleTurquoise" },
1112 { RGB_TO_ULONG(0 , 206, 209), "dark turquoise" },
1113 { RGB_TO_ULONG(0 , 206, 209), "DarkTurquoise" },
1114 { RGB_TO_ULONG(72 , 209, 204), "medium turquoise" },
1115 { RGB_TO_ULONG(72 , 209, 204), "MediumTurquoise" },
1116 { RGB_TO_ULONG(64 , 224, 208), "turquoise" },
1117 { RGB_TO_ULONG(0 , 255, 255), "cyan" },
1118 { RGB_TO_ULONG(224, 255, 255), "light cyan" },
1119 { RGB_TO_ULONG(224, 255, 255), "LightCyan" },
1120 { RGB_TO_ULONG(95 , 158, 160), "cadet blue" },
1121 { RGB_TO_ULONG(95 , 158, 160), "CadetBlue" },
1122 { RGB_TO_ULONG(102, 205, 170), "medium aquamarine" },
1123 { RGB_TO_ULONG(102, 205, 170), "MediumAquamarine" },
1124 { RGB_TO_ULONG(127, 255, 212), "aquamarine" },
1125 { RGB_TO_ULONG(0 , 100, 0 ), "dark green" },
1126 { RGB_TO_ULONG(0 , 100, 0 ), "DarkGreen" },
1127 { RGB_TO_ULONG(85 , 107, 47 ), "dark olive green" },
1128 { RGB_TO_ULONG(85 , 107, 47 ), "DarkOliveGreen" },
1129 { RGB_TO_ULONG(143, 188, 143), "dark sea green" },
1130 { RGB_TO_ULONG(143, 188, 143), "DarkSeaGreen" },
1131 { RGB_TO_ULONG(46 , 139, 87 ), "sea green" },
1132 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen" },
1133 { RGB_TO_ULONG(60 , 179, 113), "medium sea green" },
1134 { RGB_TO_ULONG(60 , 179, 113), "MediumSeaGreen" },
1135 { RGB_TO_ULONG(32 , 178, 170), "light sea green" },
1136 { RGB_TO_ULONG(32 , 178, 170), "LightSeaGreen" },
1137 { RGB_TO_ULONG(152, 251, 152), "pale green" },
1138 { RGB_TO_ULONG(152, 251, 152), "PaleGreen" },
1139 { RGB_TO_ULONG(0 , 255, 127), "spring green" },
1140 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen" },
1141 { RGB_TO_ULONG(124, 252, 0 ), "lawn green" },
1142 { RGB_TO_ULONG(124, 252, 0 ), "LawnGreen" },
1143 { RGB_TO_ULONG(0 , 255, 0 ), "green" },
1144 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse" },
1145 { RGB_TO_ULONG(0 , 250, 154), "medium spring green" },
1146 { RGB_TO_ULONG(0 , 250, 154), "MediumSpringGreen" },
1147 { RGB_TO_ULONG(173, 255, 47 ), "green yellow" },
1148 { RGB_TO_ULONG(173, 255, 47 ), "GreenYellow" },
1149 { RGB_TO_ULONG(50 , 205, 50 ), "lime green" },
1150 { RGB_TO_ULONG(50 , 205, 50 ), "LimeGreen" },
1151 { RGB_TO_ULONG(154, 205, 50 ), "yellow green" },
1152 { RGB_TO_ULONG(154, 205, 50 ), "YellowGreen" },
1153 { RGB_TO_ULONG(34 , 139, 34 ), "forest green" },
1154 { RGB_TO_ULONG(34 , 139, 34 ), "ForestGreen" },
1155 { RGB_TO_ULONG(107, 142, 35 ), "olive drab" },
1156 { RGB_TO_ULONG(107, 142, 35 ), "OliveDrab" },
1157 { RGB_TO_ULONG(189, 183, 107), "dark khaki" },
1158 { RGB_TO_ULONG(189, 183, 107), "DarkKhaki" },
1159 { RGB_TO_ULONG(240, 230, 140), "khaki" },
1160 { RGB_TO_ULONG(238, 232, 170), "pale goldenrod" },
1161 { RGB_TO_ULONG(238, 232, 170), "PaleGoldenrod" },
1162 { RGB_TO_ULONG(250, 250, 210), "light goldenrod yellow" },
1163 { RGB_TO_ULONG(250, 250, 210), "LightGoldenrodYellow" },
1164 { RGB_TO_ULONG(255, 255, 224), "light yellow" },
1165 { RGB_TO_ULONG(255, 255, 224), "LightYellow" },
1166 { RGB_TO_ULONG(255, 255, 0 ), "yellow" },
1167 { RGB_TO_ULONG(255, 215, 0 ), "gold" },
1168 { RGB_TO_ULONG(238, 221, 130), "light goldenrod" },
1169 { RGB_TO_ULONG(238, 221, 130), "LightGoldenrod" },
1170 { RGB_TO_ULONG(218, 165, 32 ), "goldenrod" },
1171 { RGB_TO_ULONG(184, 134, 11 ), "dark goldenrod" },
1172 { RGB_TO_ULONG(184, 134, 11 ), "DarkGoldenrod" },
1173 { RGB_TO_ULONG(188, 143, 143), "rosy brown" },
1174 { RGB_TO_ULONG(188, 143, 143), "RosyBrown" },
1175 { RGB_TO_ULONG(205, 92 , 92 ), "indian red" },
1176 { RGB_TO_ULONG(205, 92 , 92 ), "IndianRed" },
1177 { RGB_TO_ULONG(139, 69 , 19 ), "saddle brown" },
1178 { RGB_TO_ULONG(139, 69 , 19 ), "SaddleBrown" },
1179 { RGB_TO_ULONG(160, 82 , 45 ), "sienna" },
1180 { RGB_TO_ULONG(205, 133, 63 ), "peru" },
1181 { RGB_TO_ULONG(222, 184, 135), "burlywood" },
1182 { RGB_TO_ULONG(245, 245, 220), "beige" },
1183 { RGB_TO_ULONG(245, 222, 179), "wheat" },
1184 { RGB_TO_ULONG(244, 164, 96 ), "sandy brown" },
1185 { RGB_TO_ULONG(244, 164, 96 ), "SandyBrown" },
1186 { RGB_TO_ULONG(210, 180, 140), "tan" },
1187 { RGB_TO_ULONG(210, 105, 30 ), "chocolate" },
1188 { RGB_TO_ULONG(178, 34 , 34 ), "firebrick" },
1189 { RGB_TO_ULONG(165, 42 , 42 ), "brown" },
1190 { RGB_TO_ULONG(233, 150, 122), "dark salmon" },
1191 { RGB_TO_ULONG(233, 150, 122), "DarkSalmon" },
1192 { RGB_TO_ULONG(250, 128, 114), "salmon" },
1193 { RGB_TO_ULONG(255, 160, 122), "light salmon" },
1194 { RGB_TO_ULONG(255, 160, 122), "LightSalmon" },
1195 { RGB_TO_ULONG(255, 165, 0 ), "orange" },
1196 { RGB_TO_ULONG(255, 140, 0 ), "dark orange" },
1197 { RGB_TO_ULONG(255, 140, 0 ), "DarkOrange" },
1198 { RGB_TO_ULONG(255, 127, 80 ), "coral" },
1199 { RGB_TO_ULONG(240, 128, 128), "light coral" },
1200 { RGB_TO_ULONG(240, 128, 128), "LightCoral" },
1201 { RGB_TO_ULONG(255, 99 , 71 ), "tomato" },
1202 { RGB_TO_ULONG(255, 69 , 0 ), "orange red" },
1203 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed" },
1204 { RGB_TO_ULONG(255, 0 , 0 ), "red" },
1205 { RGB_TO_ULONG(255, 105, 180), "hot pink" },
1206 { RGB_TO_ULONG(255, 105, 180), "HotPink" },
1207 { RGB_TO_ULONG(255, 20 , 147), "deep pink" },
1208 { RGB_TO_ULONG(255, 20 , 147), "DeepPink" },
1209 { RGB_TO_ULONG(255, 192, 203), "pink" },
1210 { RGB_TO_ULONG(255, 182, 193), "light pink" },
1211 { RGB_TO_ULONG(255, 182, 193), "LightPink" },
1212 { RGB_TO_ULONG(219, 112, 147), "pale violet red" },
1213 { RGB_TO_ULONG(219, 112, 147), "PaleVioletRed" },
1214 { RGB_TO_ULONG(176, 48 , 96 ), "maroon" },
1215 { RGB_TO_ULONG(199, 21 , 133), "medium violet red" },
1216 { RGB_TO_ULONG(199, 21 , 133), "MediumVioletRed" },
1217 { RGB_TO_ULONG(208, 32 , 144), "violet red" },
1218 { RGB_TO_ULONG(208, 32 , 144), "VioletRed" },
1219 { RGB_TO_ULONG(255, 0 , 255), "magenta" },
1220 { RGB_TO_ULONG(238, 130, 238), "violet" },
1221 { RGB_TO_ULONG(221, 160, 221), "plum" },
1222 { RGB_TO_ULONG(218, 112, 214), "orchid" },
1223 { RGB_TO_ULONG(186, 85 , 211), "medium orchid" },
1224 { RGB_TO_ULONG(186, 85 , 211), "MediumOrchid" },
1225 { RGB_TO_ULONG(153, 50 , 204), "dark orchid" },
1226 { RGB_TO_ULONG(153, 50 , 204), "DarkOrchid" },
1227 { RGB_TO_ULONG(148, 0 , 211), "dark violet" },
1228 { RGB_TO_ULONG(148, 0 , 211), "DarkViolet" },
1229 { RGB_TO_ULONG(138, 43 , 226), "blue violet" },
1230 { RGB_TO_ULONG(138, 43 , 226), "BlueViolet" },
1231 { RGB_TO_ULONG(160, 32 , 240), "purple" },
1232 { RGB_TO_ULONG(147, 112, 219), "medium purple" },
1233 { RGB_TO_ULONG(147, 112, 219), "MediumPurple" },
1234 { RGB_TO_ULONG(216, 191, 216), "thistle" },
1235 { RGB_TO_ULONG(255, 250, 250), "snow1" },
1236 { RGB_TO_ULONG(238, 233, 233), "snow2" },
1237 { RGB_TO_ULONG(205, 201, 201), "snow3" },
1238 { RGB_TO_ULONG(139, 137, 137), "snow4" },
1239 { RGB_TO_ULONG(255, 245, 238), "seashell1" },
1240 { RGB_TO_ULONG(238, 229, 222), "seashell2" },
1241 { RGB_TO_ULONG(205, 197, 191), "seashell3" },
1242 { RGB_TO_ULONG(139, 134, 130), "seashell4" },
1243 { RGB_TO_ULONG(255, 239, 219), "AntiqueWhite1" },
1244 { RGB_TO_ULONG(238, 223, 204), "AntiqueWhite2" },
1245 { RGB_TO_ULONG(205, 192, 176), "AntiqueWhite3" },
1246 { RGB_TO_ULONG(139, 131, 120), "AntiqueWhite4" },
1247 { RGB_TO_ULONG(255, 228, 196), "bisque1" },
1248 { RGB_TO_ULONG(238, 213, 183), "bisque2" },
1249 { RGB_TO_ULONG(205, 183, 158), "bisque3" },
1250 { RGB_TO_ULONG(139, 125, 107), "bisque4" },
1251 { RGB_TO_ULONG(255, 218, 185), "PeachPuff1" },
1252 { RGB_TO_ULONG(238, 203, 173), "PeachPuff2" },
1253 { RGB_TO_ULONG(205, 175, 149), "PeachPuff3" },
1254 { RGB_TO_ULONG(139, 119, 101), "PeachPuff4" },
1255 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite1" },
1256 { RGB_TO_ULONG(238, 207, 161), "NavajoWhite2" },
1257 { RGB_TO_ULONG(205, 179, 139), "NavajoWhite3" },
1258 { RGB_TO_ULONG(139, 121, 94), "NavajoWhite4" },
1259 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon1" },
1260 { RGB_TO_ULONG(238, 233, 191), "LemonChiffon2" },
1261 { RGB_TO_ULONG(205, 201, 165), "LemonChiffon3" },
1262 { RGB_TO_ULONG(139, 137, 112), "LemonChiffon4" },
1263 { RGB_TO_ULONG(255, 248, 220), "cornsilk1" },
1264 { RGB_TO_ULONG(238, 232, 205), "cornsilk2" },
1265 { RGB_TO_ULONG(205, 200, 177), "cornsilk3" },
1266 { RGB_TO_ULONG(139, 136, 120), "cornsilk4" },
1267 { RGB_TO_ULONG(255, 255, 240), "ivory1" },
1268 { RGB_TO_ULONG(238, 238, 224), "ivory2" },
1269 { RGB_TO_ULONG(205, 205, 193), "ivory3" },
1270 { RGB_TO_ULONG(139, 139, 131), "ivory4" },
1271 { RGB_TO_ULONG(240, 255, 240), "honeydew1" },
1272 { RGB_TO_ULONG(224, 238, 224), "honeydew2" },
1273 { RGB_TO_ULONG(193, 205, 193), "honeydew3" },
1274 { RGB_TO_ULONG(131, 139, 131), "honeydew4" },
1275 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush1" },
1276 { RGB_TO_ULONG(238, 224, 229), "LavenderBlush2" },
1277 { RGB_TO_ULONG(205, 193, 197), "LavenderBlush3" },
1278 { RGB_TO_ULONG(139, 131, 134), "LavenderBlush4" },
1279 { RGB_TO_ULONG(255, 228, 225), "MistyRose1" },
1280 { RGB_TO_ULONG(238, 213, 210), "MistyRose2" },
1281 { RGB_TO_ULONG(205, 183, 181), "MistyRose3" },
1282 { RGB_TO_ULONG(139, 125, 123), "MistyRose4" },
1283 { RGB_TO_ULONG(240, 255, 255), "azure1" },
1284 { RGB_TO_ULONG(224, 238, 238), "azure2" },
1285 { RGB_TO_ULONG(193, 205, 205), "azure3" },
1286 { RGB_TO_ULONG(131, 139, 139), "azure4" },
1287 { RGB_TO_ULONG(131, 111, 255), "SlateBlue1" },
1288 { RGB_TO_ULONG(122, 103, 238), "SlateBlue2" },
1289 { RGB_TO_ULONG(105, 89 , 205), "SlateBlue3" },
1290 { RGB_TO_ULONG(71 , 60 , 139), "SlateBlue4" },
1291 { RGB_TO_ULONG(72 , 118, 255), "RoyalBlue1" },
1292 { RGB_TO_ULONG(67 , 110, 238), "RoyalBlue2" },
1293 { RGB_TO_ULONG(58 , 95 , 205), "RoyalBlue3" },
1294 { RGB_TO_ULONG(39 , 64 , 139), "RoyalBlue4" },
1295 { RGB_TO_ULONG(0 , 0 , 255), "blue1" },
1296 { RGB_TO_ULONG(0 , 0 , 238), "blue2" },
1297 { RGB_TO_ULONG(0 , 0 , 205), "blue3" },
1298 { RGB_TO_ULONG(0 , 0 , 139), "blue4" },
1299 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue1" },
1300 { RGB_TO_ULONG(28 , 134, 238), "DodgerBlue2" },
1301 { RGB_TO_ULONG(24 , 116, 205), "DodgerBlue3" },
1302 { RGB_TO_ULONG(16 , 78 , 139), "DodgerBlue4" },
1303 { RGB_TO_ULONG(99 , 184, 255), "SteelBlue1" },
1304 { RGB_TO_ULONG(92 , 172, 238), "SteelBlue2" },
1305 { RGB_TO_ULONG(79 , 148, 205), "SteelBlue3" },
1306 { RGB_TO_ULONG(54 , 100, 139), "SteelBlue4" },
1307 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue1" },
1308 { RGB_TO_ULONG(0 , 178, 238), "DeepSkyBlue2" },
1309 { RGB_TO_ULONG(0 , 154, 205), "DeepSkyBlue3" },
1310 { RGB_TO_ULONG(0 , 104, 139), "DeepSkyBlue4" },
1311 { RGB_TO_ULONG(135, 206, 255), "SkyBlue1" },
1312 { RGB_TO_ULONG(126, 192, 238), "SkyBlue2" },
1313 { RGB_TO_ULONG(108, 166, 205), "SkyBlue3" },
1314 { RGB_TO_ULONG(74 , 112, 139), "SkyBlue4" },
1315 { RGB_TO_ULONG(176, 226, 255), "LightSkyBlue1" },
1316 { RGB_TO_ULONG(164, 211, 238), "LightSkyBlue2" },
1317 { RGB_TO_ULONG(141, 182, 205), "LightSkyBlue3" },
1318 { RGB_TO_ULONG(96 , 123, 139), "LightSkyBlue4" },
1319 { RGB_TO_ULONG(198, 226, 255), "SlateGray1" },
1320 { RGB_TO_ULONG(185, 211, 238), "SlateGray2" },
1321 { RGB_TO_ULONG(159, 182, 205), "SlateGray3" },
1322 { RGB_TO_ULONG(108, 123, 139), "SlateGray4" },
1323 { RGB_TO_ULONG(202, 225, 255), "LightSteelBlue1" },
1324 { RGB_TO_ULONG(188, 210, 238), "LightSteelBlue2" },
1325 { RGB_TO_ULONG(162, 181, 205), "LightSteelBlue3" },
1326 { RGB_TO_ULONG(110, 123, 139), "LightSteelBlue4" },
1327 { RGB_TO_ULONG(191, 239, 255), "LightBlue1" },
1328 { RGB_TO_ULONG(178, 223, 238), "LightBlue2" },
1329 { RGB_TO_ULONG(154, 192, 205), "LightBlue3" },
1330 { RGB_TO_ULONG(104, 131, 139), "LightBlue4" },
1331 { RGB_TO_ULONG(224, 255, 255), "LightCyan1" },
1332 { RGB_TO_ULONG(209, 238, 238), "LightCyan2" },
1333 { RGB_TO_ULONG(180, 205, 205), "LightCyan3" },
1334 { RGB_TO_ULONG(122, 139, 139), "LightCyan4" },
1335 { RGB_TO_ULONG(187, 255, 255), "PaleTurquoise1" },
1336 { RGB_TO_ULONG(174, 238, 238), "PaleTurquoise2" },
1337 { RGB_TO_ULONG(150, 205, 205), "PaleTurquoise3" },
1338 { RGB_TO_ULONG(102, 139, 139), "PaleTurquoise4" },
1339 { RGB_TO_ULONG(152, 245, 255), "CadetBlue1" },
1340 { RGB_TO_ULONG(142, 229, 238), "CadetBlue2" },
1341 { RGB_TO_ULONG(122, 197, 205), "CadetBlue3" },
1342 { RGB_TO_ULONG(83 , 134, 139), "CadetBlue4" },
1343 { RGB_TO_ULONG(0 , 245, 255), "turquoise1" },
1344 { RGB_TO_ULONG(0 , 229, 238), "turquoise2" },
1345 { RGB_TO_ULONG(0 , 197, 205), "turquoise3" },
1346 { RGB_TO_ULONG(0 , 134, 139), "turquoise4" },
1347 { RGB_TO_ULONG(0 , 255, 255), "cyan1" },
1348 { RGB_TO_ULONG(0 , 238, 238), "cyan2" },
1349 { RGB_TO_ULONG(0 , 205, 205), "cyan3" },
1350 { RGB_TO_ULONG(0 , 139, 139), "cyan4" },
1351 { RGB_TO_ULONG(151, 255, 255), "DarkSlateGray1" },
1352 { RGB_TO_ULONG(141, 238, 238), "DarkSlateGray2" },
1353 { RGB_TO_ULONG(121, 205, 205), "DarkSlateGray3" },
1354 { RGB_TO_ULONG(82 , 139, 139), "DarkSlateGray4" },
1355 { RGB_TO_ULONG(127, 255, 212), "aquamarine1" },
1356 { RGB_TO_ULONG(118, 238, 198), "aquamarine2" },
1357 { RGB_TO_ULONG(102, 205, 170), "aquamarine3" },
1358 { RGB_TO_ULONG(69 , 139, 116), "aquamarine4" },
1359 { RGB_TO_ULONG(193, 255, 193), "DarkSeaGreen1" },
1360 { RGB_TO_ULONG(180, 238, 180), "DarkSeaGreen2" },
1361 { RGB_TO_ULONG(155, 205, 155), "DarkSeaGreen3" },
1362 { RGB_TO_ULONG(105, 139, 105), "DarkSeaGreen4" },
1363 { RGB_TO_ULONG(84 , 255, 159), "SeaGreen1" },
1364 { RGB_TO_ULONG(78 , 238, 148), "SeaGreen2" },
1365 { RGB_TO_ULONG(67 , 205, 128), "SeaGreen3" },
1366 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen4" },
1367 { RGB_TO_ULONG(154, 255, 154), "PaleGreen1" },
1368 { RGB_TO_ULONG(144, 238, 144), "PaleGreen2" },
1369 { RGB_TO_ULONG(124, 205, 124), "PaleGreen3" },
1370 { RGB_TO_ULONG(84 , 139, 84 ), "PaleGreen4" },
1371 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen1" },
1372 { RGB_TO_ULONG(0 , 238, 118), "SpringGreen2" },
1373 { RGB_TO_ULONG(0 , 205, 102), "SpringGreen3" },
1374 { RGB_TO_ULONG(0 , 139, 69 ), "SpringGreen4" },
1375 { RGB_TO_ULONG(0 , 255, 0 ), "green1" },
1376 { RGB_TO_ULONG(0 , 238, 0 ), "green2" },
1377 { RGB_TO_ULONG(0 , 205, 0 ), "green3" },
1378 { RGB_TO_ULONG(0 , 139, 0 ), "green4" },
1379 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse1" },
1380 { RGB_TO_ULONG(118, 238, 0 ), "chartreuse2" },
1381 { RGB_TO_ULONG(102, 205, 0 ), "chartreuse3" },
1382 { RGB_TO_ULONG(69 , 139, 0 ), "chartreuse4" },
1383 { RGB_TO_ULONG(192, 255, 62 ), "OliveDrab1" },
1384 { RGB_TO_ULONG(179, 238, 58 ), "OliveDrab2" },
1385 { RGB_TO_ULONG(154, 205, 50 ), "OliveDrab3" },
1386 { RGB_TO_ULONG(105, 139, 34 ), "OliveDrab4" },
1387 { RGB_TO_ULONG(202, 255, 112), "DarkOliveGreen1" },
1388 { RGB_TO_ULONG(188, 238, 104), "DarkOliveGreen2" },
1389 { RGB_TO_ULONG(162, 205, 90 ), "DarkOliveGreen3" },
1390 { RGB_TO_ULONG(110, 139, 61 ), "DarkOliveGreen4" },
1391 { RGB_TO_ULONG(255, 246, 143), "khaki1" },
1392 { RGB_TO_ULONG(238, 230, 133), "khaki2" },
1393 { RGB_TO_ULONG(205, 198, 115), "khaki3" },
1394 { RGB_TO_ULONG(139, 134, 78 ), "khaki4" },
1395 { RGB_TO_ULONG(255, 236, 139), "LightGoldenrod1" },
1396 { RGB_TO_ULONG(238, 220, 130), "LightGoldenrod2" },
1397 { RGB_TO_ULONG(205, 190, 112), "LightGoldenrod3" },
1398 { RGB_TO_ULONG(139, 129, 76 ), "LightGoldenrod4" },
1399 { RGB_TO_ULONG(255, 255, 224), "LightYellow1" },
1400 { RGB_TO_ULONG(238, 238, 209), "LightYellow2" },
1401 { RGB_TO_ULONG(205, 205, 180), "LightYellow3" },
1402 { RGB_TO_ULONG(139, 139, 122), "LightYellow4" },
1403 { RGB_TO_ULONG(255, 255, 0 ), "yellow1" },
1404 { RGB_TO_ULONG(238, 238, 0 ), "yellow2" },
1405 { RGB_TO_ULONG(205, 205, 0 ), "yellow3" },
1406 { RGB_TO_ULONG(139, 139, 0 ), "yellow4" },
1407 { RGB_TO_ULONG(255, 215, 0 ), "gold1" },
1408 { RGB_TO_ULONG(238, 201, 0 ), "gold2" },
1409 { RGB_TO_ULONG(205, 173, 0 ), "gold3" },
1410 { RGB_TO_ULONG(139, 117, 0 ), "gold4" },
1411 { RGB_TO_ULONG(255, 193, 37 ), "goldenrod1" },
1412 { RGB_TO_ULONG(238, 180, 34 ), "goldenrod2" },
1413 { RGB_TO_ULONG(205, 155, 29 ), "goldenrod3" },
1414 { RGB_TO_ULONG(139, 105, 20 ), "goldenrod4" },
1415 { RGB_TO_ULONG(255, 185, 15 ), "DarkGoldenrod1" },
1416 { RGB_TO_ULONG(238, 173, 14 ), "DarkGoldenrod2" },
1417 { RGB_TO_ULONG(205, 149, 12 ), "DarkGoldenrod3" },
1418 { RGB_TO_ULONG(139, 101, 8 ), "DarkGoldenrod4" },
1419 { RGB_TO_ULONG(255, 193, 193), "RosyBrown1" },
1420 { RGB_TO_ULONG(238, 180, 180), "RosyBrown2" },
1421 { RGB_TO_ULONG(205, 155, 155), "RosyBrown3" },
1422 { RGB_TO_ULONG(139, 105, 105), "RosyBrown4" },
1423 { RGB_TO_ULONG(255, 106, 106), "IndianRed1" },
1424 { RGB_TO_ULONG(238, 99 , 99 ), "IndianRed2" },
1425 { RGB_TO_ULONG(205, 85 , 85 ), "IndianRed3" },
1426 { RGB_TO_ULONG(139, 58 , 58 ), "IndianRed4" },
1427 { RGB_TO_ULONG(255, 130, 71 ), "sienna1" },
1428 { RGB_TO_ULONG(238, 121, 66 ), "sienna2" },
1429 { RGB_TO_ULONG(205, 104, 57 ), "sienna3" },
1430 { RGB_TO_ULONG(139, 71 , 38 ), "sienna4" },
1431 { RGB_TO_ULONG(255, 211, 155), "burlywood1" },
1432 { RGB_TO_ULONG(238, 197, 145), "burlywood2" },
1433 { RGB_TO_ULONG(205, 170, 125), "burlywood3" },
1434 { RGB_TO_ULONG(139, 115, 85 ), "burlywood4" },
1435 { RGB_TO_ULONG(255, 231, 186), "wheat1" },
1436 { RGB_TO_ULONG(238, 216, 174), "wheat2" },
1437 { RGB_TO_ULONG(205, 186, 150), "wheat3" },
1438 { RGB_TO_ULONG(139, 126, 102), "wheat4" },
1439 { RGB_TO_ULONG(255, 165, 79 ), "tan1" },
1440 { RGB_TO_ULONG(238, 154, 73 ), "tan2" },
1441 { RGB_TO_ULONG(205, 133, 63 ), "tan3" },
1442 { RGB_TO_ULONG(139, 90 , 43 ), "tan4" },
1443 { RGB_TO_ULONG(255, 127, 36 ), "chocolate1" },
1444 { RGB_TO_ULONG(238, 118, 33 ), "chocolate2" },
1445 { RGB_TO_ULONG(205, 102, 29 ), "chocolate3" },
1446 { RGB_TO_ULONG(139, 69 , 19 ), "chocolate4" },
1447 { RGB_TO_ULONG(255, 48 , 48 ), "firebrick1" },
1448 { RGB_TO_ULONG(238, 44 , 44 ), "firebrick2" },
1449 { RGB_TO_ULONG(205, 38 , 38 ), "firebrick3" },
1450 { RGB_TO_ULONG(139, 26 , 26 ), "firebrick4" },
1451 { RGB_TO_ULONG(255, 64 , 64 ), "brown1" },
1452 { RGB_TO_ULONG(238, 59 , 59 ), "brown2" },
1453 { RGB_TO_ULONG(205, 51 , 51 ), "brown3" },
1454 { RGB_TO_ULONG(139, 35 , 35 ), "brown4" },
1455 { RGB_TO_ULONG(255, 140, 105), "salmon1" },
1456 { RGB_TO_ULONG(238, 130, 98 ), "salmon2" },
1457 { RGB_TO_ULONG(205, 112, 84 ), "salmon3" },
1458 { RGB_TO_ULONG(139, 76 , 57 ), "salmon4" },
1459 { RGB_TO_ULONG(255, 160, 122), "LightSalmon1" },
1460 { RGB_TO_ULONG(238, 149, 114), "LightSalmon2" },
1461 { RGB_TO_ULONG(205, 129, 98 ), "LightSalmon3" },
1462 { RGB_TO_ULONG(139, 87 , 66 ), "LightSalmon4" },
1463 { RGB_TO_ULONG(255, 165, 0 ), "orange1" },
1464 { RGB_TO_ULONG(238, 154, 0 ), "orange2" },
1465 { RGB_TO_ULONG(205, 133, 0 ), "orange3" },
1466 { RGB_TO_ULONG(139, 90 , 0 ), "orange4" },
1467 { RGB_TO_ULONG(255, 127, 0 ), "DarkOrange1" },
1468 { RGB_TO_ULONG(238, 118, 0 ), "DarkOrange2" },
1469 { RGB_TO_ULONG(205, 102, 0 ), "DarkOrange3" },
1470 { RGB_TO_ULONG(139, 69 , 0 ), "DarkOrange4" },
1471 { RGB_TO_ULONG(255, 114, 86 ), "coral1" },
1472 { RGB_TO_ULONG(238, 106, 80 ), "coral2" },
1473 { RGB_TO_ULONG(205, 91 , 69 ), "coral3" },
1474 { RGB_TO_ULONG(139, 62 , 47 ), "coral4" },
1475 { RGB_TO_ULONG(255, 99 , 71 ), "tomato1" },
1476 { RGB_TO_ULONG(238, 92 , 66 ), "tomato2" },
1477 { RGB_TO_ULONG(205, 79 , 57 ), "tomato3" },
1478 { RGB_TO_ULONG(139, 54 , 38 ), "tomato4" },
1479 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed1" },
1480 { RGB_TO_ULONG(238, 64 , 0 ), "OrangeRed2" },
1481 { RGB_TO_ULONG(205, 55 , 0 ), "OrangeRed3" },
1482 { RGB_TO_ULONG(139, 37 , 0 ), "OrangeRed4" },
1483 { RGB_TO_ULONG(255, 0 , 0 ), "red1" },
1484 { RGB_TO_ULONG(238, 0 , 0 ), "red2" },
1485 { RGB_TO_ULONG(205, 0 , 0 ), "red3" },
1486 { RGB_TO_ULONG(139, 0 , 0 ), "red4" },
1487 { RGB_TO_ULONG(255, 20 , 147), "DeepPink1" },
1488 { RGB_TO_ULONG(238, 18 , 137), "DeepPink2" },
1489 { RGB_TO_ULONG(205, 16 , 118), "DeepPink3" },
1490 { RGB_TO_ULONG(139, 10 , 80 ), "DeepPink4" },
1491 { RGB_TO_ULONG(255, 110, 180), "HotPink1" },
1492 { RGB_TO_ULONG(238, 106, 167), "HotPink2" },
1493 { RGB_TO_ULONG(205, 96 , 144), "HotPink3" },
1494 { RGB_TO_ULONG(139, 58 , 98 ), "HotPink4" },
1495 { RGB_TO_ULONG(255, 181, 197), "pink1" },
1496 { RGB_TO_ULONG(238, 169, 184), "pink2" },
1497 { RGB_TO_ULONG(205, 145, 158), "pink3" },
1498 { RGB_TO_ULONG(139, 99 , 108), "pink4" },
1499 { RGB_TO_ULONG(255, 174, 185), "LightPink1" },
1500 { RGB_TO_ULONG(238, 162, 173), "LightPink2" },
1501 { RGB_TO_ULONG(205, 140, 149), "LightPink3" },
1502 { RGB_TO_ULONG(139, 95 , 101), "LightPink4" },
1503 { RGB_TO_ULONG(255, 130, 171), "PaleVioletRed1" },
1504 { RGB_TO_ULONG(238, 121, 159), "PaleVioletRed2" },
1505 { RGB_TO_ULONG(205, 104, 137), "PaleVioletRed3" },
1506 { RGB_TO_ULONG(139, 71 , 93 ), "PaleVioletRed4" },
1507 { RGB_TO_ULONG(255, 52 , 179), "maroon1" },
1508 { RGB_TO_ULONG(238, 48 , 167), "maroon2" },
1509 { RGB_TO_ULONG(205, 41 , 144), "maroon3" },
1510 { RGB_TO_ULONG(139, 28 , 98 ), "maroon4" },
1511 { RGB_TO_ULONG(255, 62 , 150), "VioletRed1" },
1512 { RGB_TO_ULONG(238, 58 , 140), "VioletRed2" },
1513 { RGB_TO_ULONG(205, 50 , 120), "VioletRed3" },
1514 { RGB_TO_ULONG(139, 34 , 82 ), "VioletRed4" },
1515 { RGB_TO_ULONG(255, 0 , 255), "magenta1" },
1516 { RGB_TO_ULONG(238, 0 , 238), "magenta2" },
1517 { RGB_TO_ULONG(205, 0 , 205), "magenta3" },
1518 { RGB_TO_ULONG(139, 0 , 139), "magenta4" },
1519 { RGB_TO_ULONG(255, 131, 250), "orchid1" },
1520 { RGB_TO_ULONG(238, 122, 233), "orchid2" },
1521 { RGB_TO_ULONG(205, 105, 201), "orchid3" },
1522 { RGB_TO_ULONG(139, 71 , 137), "orchid4" },
1523 { RGB_TO_ULONG(255, 187, 255), "plum1" },
1524 { RGB_TO_ULONG(238, 174, 238), "plum2" },
1525 { RGB_TO_ULONG(205, 150, 205), "plum3" },
1526 { RGB_TO_ULONG(139, 102, 139), "plum4" },
1527 { RGB_TO_ULONG(224, 102, 255), "MediumOrchid1" },
1528 { RGB_TO_ULONG(209, 95 , 238), "MediumOrchid2" },
1529 { RGB_TO_ULONG(180, 82 , 205), "MediumOrchid3" },
1530 { RGB_TO_ULONG(122, 55 , 139), "MediumOrchid4" },
1531 { RGB_TO_ULONG(191, 62 , 255), "DarkOrchid1" },
1532 { RGB_TO_ULONG(178, 58 , 238), "DarkOrchid2" },
1533 { RGB_TO_ULONG(154, 50 , 205), "DarkOrchid3" },
1534 { RGB_TO_ULONG(104, 34 , 139), "DarkOrchid4" },
1535 { RGB_TO_ULONG(155, 48 , 255), "purple1" },
1536 { RGB_TO_ULONG(145, 44 , 238), "purple2" },
1537 { RGB_TO_ULONG(125, 38 , 205), "purple3" },
1538 { RGB_TO_ULONG(85 , 26 , 139), "purple4" },
1539 { RGB_TO_ULONG(171, 130, 255), "MediumPurple1" },
1540 { RGB_TO_ULONG(159, 121, 238), "MediumPurple2" },
1541 { RGB_TO_ULONG(137, 104, 205), "MediumPurple3" },
1542 { RGB_TO_ULONG(93 , 71 , 139), "MediumPurple4" },
1543 { RGB_TO_ULONG(255, 225, 255), "thistle1" },
1544 { RGB_TO_ULONG(238, 210, 238), "thistle2" },
1545 { RGB_TO_ULONG(205, 181, 205), "thistle3" },
1546 { RGB_TO_ULONG(139, 123, 139), "thistle4" },
1547 { RGB_TO_ULONG(0 , 0 , 0 ), "gray0" },
1548 { RGB_TO_ULONG(0 , 0 , 0 ), "grey0" },
1549 { RGB_TO_ULONG(3 , 3 , 3 ), "gray1" },
1550 { RGB_TO_ULONG(3 , 3 , 3 ), "grey1" },
1551 { RGB_TO_ULONG(5 , 5 , 5 ), "gray2" },
1552 { RGB_TO_ULONG(5 , 5 , 5 ), "grey2" },
1553 { RGB_TO_ULONG(8 , 8 , 8 ), "gray3" },
1554 { RGB_TO_ULONG(8 , 8 , 8 ), "grey3" },
1555 { RGB_TO_ULONG(10 , 10 , 10 ), "gray4" },
1556 { RGB_TO_ULONG(10 , 10 , 10 ), "grey4" },
1557 { RGB_TO_ULONG(13 , 13 , 13 ), "gray5" },
1558 { RGB_TO_ULONG(13 , 13 , 13 ), "grey5" },
1559 { RGB_TO_ULONG(15 , 15 , 15 ), "gray6" },
1560 { RGB_TO_ULONG(15 , 15 , 15 ), "grey6" },
1561 { RGB_TO_ULONG(18 , 18 , 18 ), "gray7" },
1562 { RGB_TO_ULONG(18 , 18 , 18 ), "grey7" },
1563 { RGB_TO_ULONG(20 , 20 , 20 ), "gray8" },
1564 { RGB_TO_ULONG(20 , 20 , 20 ), "grey8" },
1565 { RGB_TO_ULONG(23 , 23 , 23 ), "gray9" },
1566 { RGB_TO_ULONG(23 , 23 , 23 ), "grey9" },
1567 { RGB_TO_ULONG(26 , 26 , 26 ), "gray10" },
1568 { RGB_TO_ULONG(26 , 26 , 26 ), "grey10" },
1569 { RGB_TO_ULONG(28 , 28 , 28 ), "gray11" },
1570 { RGB_TO_ULONG(28 , 28 , 28 ), "grey11" },
1571 { RGB_TO_ULONG(31 , 31 , 31 ), "gray12" },
1572 { RGB_TO_ULONG(31 , 31 , 31 ), "grey12" },
1573 { RGB_TO_ULONG(33 , 33 , 33 ), "gray13" },
1574 { RGB_TO_ULONG(33 , 33 , 33 ), "grey13" },
1575 { RGB_TO_ULONG(36 , 36 , 36 ), "gray14" },
1576 { RGB_TO_ULONG(36 , 36 , 36 ), "grey14" },
1577 { RGB_TO_ULONG(38 , 38 , 38 ), "gray15" },
1578 { RGB_TO_ULONG(38 , 38 , 38 ), "grey15" },
1579 { RGB_TO_ULONG(41 , 41 , 41 ), "gray16" },
1580 { RGB_TO_ULONG(41 , 41 , 41 ), "grey16" },
1581 { RGB_TO_ULONG(43 , 43 , 43 ), "gray17" },
1582 { RGB_TO_ULONG(43 , 43 , 43 ), "grey17" },
1583 { RGB_TO_ULONG(46 , 46 , 46 ), "gray18" },
1584 { RGB_TO_ULONG(46 , 46 , 46 ), "grey18" },
1585 { RGB_TO_ULONG(48 , 48 , 48 ), "gray19" },
1586 { RGB_TO_ULONG(48 , 48 , 48 ), "grey19" },
1587 { RGB_TO_ULONG(51 , 51 , 51 ), "gray20" },
1588 { RGB_TO_ULONG(51 , 51 , 51 ), "grey20" },
1589 { RGB_TO_ULONG(54 , 54 , 54 ), "gray21" },
1590 { RGB_TO_ULONG(54 , 54 , 54 ), "grey21" },
1591 { RGB_TO_ULONG(56 , 56 , 56 ), "gray22" },
1592 { RGB_TO_ULONG(56 , 56 , 56 ), "grey22" },
1593 { RGB_TO_ULONG(59 , 59 , 59 ), "gray23" },
1594 { RGB_TO_ULONG(59 , 59 , 59 ), "grey23" },
1595 { RGB_TO_ULONG(61 , 61 , 61 ), "gray24" },
1596 { RGB_TO_ULONG(61 , 61 , 61 ), "grey24" },
1597 { RGB_TO_ULONG(64 , 64 , 64 ), "gray25" },
1598 { RGB_TO_ULONG(64 , 64 , 64 ), "grey25" },
1599 { RGB_TO_ULONG(66 , 66 , 66 ), "gray26" },
1600 { RGB_TO_ULONG(66 , 66 , 66 ), "grey26" },
1601 { RGB_TO_ULONG(69 , 69 , 69 ), "gray27" },
1602 { RGB_TO_ULONG(69 , 69 , 69 ), "grey27" },
1603 { RGB_TO_ULONG(71 , 71 , 71 ), "gray28" },
1604 { RGB_TO_ULONG(71 , 71 , 71 ), "grey28" },
1605 { RGB_TO_ULONG(74 , 74 , 74 ), "gray29" },
1606 { RGB_TO_ULONG(74 , 74 , 74 ), "grey29" },
1607 { RGB_TO_ULONG(77 , 77 , 77 ), "gray30" },
1608 { RGB_TO_ULONG(77 , 77 , 77 ), "grey30" },
1609 { RGB_TO_ULONG(79 , 79 , 79 ), "gray31" },
1610 { RGB_TO_ULONG(79 , 79 , 79 ), "grey31" },
1611 { RGB_TO_ULONG(82 , 82 , 82 ), "gray32" },
1612 { RGB_TO_ULONG(82 , 82 , 82 ), "grey32" },
1613 { RGB_TO_ULONG(84 , 84 , 84 ), "gray33" },
1614 { RGB_TO_ULONG(84 , 84 , 84 ), "grey33" },
1615 { RGB_TO_ULONG(87 , 87 , 87 ), "gray34" },
1616 { RGB_TO_ULONG(87 , 87 , 87 ), "grey34" },
1617 { RGB_TO_ULONG(89 , 89 , 89 ), "gray35" },
1618 { RGB_TO_ULONG(89 , 89 , 89 ), "grey35" },
1619 { RGB_TO_ULONG(92 , 92 , 92 ), "gray36" },
1620 { RGB_TO_ULONG(92 , 92 , 92 ), "grey36" },
1621 { RGB_TO_ULONG(94 , 94 , 94 ), "gray37" },
1622 { RGB_TO_ULONG(94 , 94 , 94 ), "grey37" },
1623 { RGB_TO_ULONG(97 , 97 , 97 ), "gray38" },
1624 { RGB_TO_ULONG(97 , 97 , 97 ), "grey38" },
1625 { RGB_TO_ULONG(99 , 99 , 99 ), "gray39" },
1626 { RGB_TO_ULONG(99 , 99 , 99 ), "grey39" },
1627 { RGB_TO_ULONG(102, 102, 102), "gray40" },
1628 { RGB_TO_ULONG(102, 102, 102), "grey40" },
1629 { RGB_TO_ULONG(105, 105, 105), "gray41" },
1630 { RGB_TO_ULONG(105, 105, 105), "grey41" },
1631 { RGB_TO_ULONG(107, 107, 107), "gray42" },
1632 { RGB_TO_ULONG(107, 107, 107), "grey42" },
1633 { RGB_TO_ULONG(110, 110, 110), "gray43" },
1634 { RGB_TO_ULONG(110, 110, 110), "grey43" },
1635 { RGB_TO_ULONG(112, 112, 112), "gray44" },
1636 { RGB_TO_ULONG(112, 112, 112), "grey44" },
1637 { RGB_TO_ULONG(115, 115, 115), "gray45" },
1638 { RGB_TO_ULONG(115, 115, 115), "grey45" },
1639 { RGB_TO_ULONG(117, 117, 117), "gray46" },
1640 { RGB_TO_ULONG(117, 117, 117), "grey46" },
1641 { RGB_TO_ULONG(120, 120, 120), "gray47" },
1642 { RGB_TO_ULONG(120, 120, 120), "grey47" },
1643 { RGB_TO_ULONG(122, 122, 122), "gray48" },
1644 { RGB_TO_ULONG(122, 122, 122), "grey48" },
1645 { RGB_TO_ULONG(125, 125, 125), "gray49" },
1646 { RGB_TO_ULONG(125, 125, 125), "grey49" },
1647 { RGB_TO_ULONG(127, 127, 127), "gray50" },
1648 { RGB_TO_ULONG(127, 127, 127), "grey50" },
1649 { RGB_TO_ULONG(130, 130, 130), "gray51" },
1650 { RGB_TO_ULONG(130, 130, 130), "grey51" },
1651 { RGB_TO_ULONG(133, 133, 133), "gray52" },
1652 { RGB_TO_ULONG(133, 133, 133), "grey52" },
1653 { RGB_TO_ULONG(135, 135, 135), "gray53" },
1654 { RGB_TO_ULONG(135, 135, 135), "grey53" },
1655 { RGB_TO_ULONG(138, 138, 138), "gray54" },
1656 { RGB_TO_ULONG(138, 138, 138), "grey54" },
1657 { RGB_TO_ULONG(140, 140, 140), "gray55" },
1658 { RGB_TO_ULONG(140, 140, 140), "grey55" },
1659 { RGB_TO_ULONG(143, 143, 143), "gray56" },
1660 { RGB_TO_ULONG(143, 143, 143), "grey56" },
1661 { RGB_TO_ULONG(145, 145, 145), "gray57" },
1662 { RGB_TO_ULONG(145, 145, 145), "grey57" },
1663 { RGB_TO_ULONG(148, 148, 148), "gray58" },
1664 { RGB_TO_ULONG(148, 148, 148), "grey58" },
1665 { RGB_TO_ULONG(150, 150, 150), "gray59" },
1666 { RGB_TO_ULONG(150, 150, 150), "grey59" },
1667 { RGB_TO_ULONG(153, 153, 153), "gray60" },
1668 { RGB_TO_ULONG(153, 153, 153), "grey60" },
1669 { RGB_TO_ULONG(156, 156, 156), "gray61" },
1670 { RGB_TO_ULONG(156, 156, 156), "grey61" },
1671 { RGB_TO_ULONG(158, 158, 158), "gray62" },
1672 { RGB_TO_ULONG(158, 158, 158), "grey62" },
1673 { RGB_TO_ULONG(161, 161, 161), "gray63" },
1674 { RGB_TO_ULONG(161, 161, 161), "grey63" },
1675 { RGB_TO_ULONG(163, 163, 163), "gray64" },
1676 { RGB_TO_ULONG(163, 163, 163), "grey64" },
1677 { RGB_TO_ULONG(166, 166, 166), "gray65" },
1678 { RGB_TO_ULONG(166, 166, 166), "grey65" },
1679 { RGB_TO_ULONG(168, 168, 168), "gray66" },
1680 { RGB_TO_ULONG(168, 168, 168), "grey66" },
1681 { RGB_TO_ULONG(171, 171, 171), "gray67" },
1682 { RGB_TO_ULONG(171, 171, 171), "grey67" },
1683 { RGB_TO_ULONG(173, 173, 173), "gray68" },
1684 { RGB_TO_ULONG(173, 173, 173), "grey68" },
1685 { RGB_TO_ULONG(176, 176, 176), "gray69" },
1686 { RGB_TO_ULONG(176, 176, 176), "grey69" },
1687 { RGB_TO_ULONG(179, 179, 179), "gray70" },
1688 { RGB_TO_ULONG(179, 179, 179), "grey70" },
1689 { RGB_TO_ULONG(181, 181, 181), "gray71" },
1690 { RGB_TO_ULONG(181, 181, 181), "grey71" },
1691 { RGB_TO_ULONG(184, 184, 184), "gray72" },
1692 { RGB_TO_ULONG(184, 184, 184), "grey72" },
1693 { RGB_TO_ULONG(186, 186, 186), "gray73" },
1694 { RGB_TO_ULONG(186, 186, 186), "grey73" },
1695 { RGB_TO_ULONG(189, 189, 189), "gray74" },
1696 { RGB_TO_ULONG(189, 189, 189), "grey74" },
1697 { RGB_TO_ULONG(191, 191, 191), "gray75" },
1698 { RGB_TO_ULONG(191, 191, 191), "grey75" },
1699 { RGB_TO_ULONG(194, 194, 194), "gray76" },
1700 { RGB_TO_ULONG(194, 194, 194), "grey76" },
1701 { RGB_TO_ULONG(196, 196, 196), "gray77" },
1702 { RGB_TO_ULONG(196, 196, 196), "grey77" },
1703 { RGB_TO_ULONG(199, 199, 199), "gray78" },
1704 { RGB_TO_ULONG(199, 199, 199), "grey78" },
1705 { RGB_TO_ULONG(201, 201, 201), "gray79" },
1706 { RGB_TO_ULONG(201, 201, 201), "grey79" },
1707 { RGB_TO_ULONG(204, 204, 204), "gray80" },
1708 { RGB_TO_ULONG(204, 204, 204), "grey80" },
1709 { RGB_TO_ULONG(207, 207, 207), "gray81" },
1710 { RGB_TO_ULONG(207, 207, 207), "grey81" },
1711 { RGB_TO_ULONG(209, 209, 209), "gray82" },
1712 { RGB_TO_ULONG(209, 209, 209), "grey82" },
1713 { RGB_TO_ULONG(212, 212, 212), "gray83" },
1714 { RGB_TO_ULONG(212, 212, 212), "grey83" },
1715 { RGB_TO_ULONG(214, 214, 214), "gray84" },
1716 { RGB_TO_ULONG(214, 214, 214), "grey84" },
1717 { RGB_TO_ULONG(217, 217, 217), "gray85" },
1718 { RGB_TO_ULONG(217, 217, 217), "grey85" },
1719 { RGB_TO_ULONG(219, 219, 219), "gray86" },
1720 { RGB_TO_ULONG(219, 219, 219), "grey86" },
1721 { RGB_TO_ULONG(222, 222, 222), "gray87" },
1722 { RGB_TO_ULONG(222, 222, 222), "grey87" },
1723 { RGB_TO_ULONG(224, 224, 224), "gray88" },
1724 { RGB_TO_ULONG(224, 224, 224), "grey88" },
1725 { RGB_TO_ULONG(227, 227, 227), "gray89" },
1726 { RGB_TO_ULONG(227, 227, 227), "grey89" },
1727 { RGB_TO_ULONG(229, 229, 229), "gray90" },
1728 { RGB_TO_ULONG(229, 229, 229), "grey90" },
1729 { RGB_TO_ULONG(232, 232, 232), "gray91" },
1730 { RGB_TO_ULONG(232, 232, 232), "grey91" },
1731 { RGB_TO_ULONG(235, 235, 235), "gray92" },
1732 { RGB_TO_ULONG(235, 235, 235), "grey92" },
1733 { RGB_TO_ULONG(237, 237, 237), "gray93" },
1734 { RGB_TO_ULONG(237, 237, 237), "grey93" },
1735 { RGB_TO_ULONG(240, 240, 240), "gray94" },
1736 { RGB_TO_ULONG(240, 240, 240), "grey94" },
1737 { RGB_TO_ULONG(242, 242, 242), "gray95" },
1738 { RGB_TO_ULONG(242, 242, 242), "grey95" },
1739 { RGB_TO_ULONG(245, 245, 245), "gray96" },
1740 { RGB_TO_ULONG(245, 245, 245), "grey96" },
1741 { RGB_TO_ULONG(247, 247, 247), "gray97" },
1742 { RGB_TO_ULONG(247, 247, 247), "grey97" },
1743 { RGB_TO_ULONG(250, 250, 250), "gray98" },
1744 { RGB_TO_ULONG(250, 250, 250), "grey98" },
1745 { RGB_TO_ULONG(252, 252, 252), "gray99" },
1746 { RGB_TO_ULONG(252, 252, 252), "grey99" },
1747 { RGB_TO_ULONG(255, 255, 255), "gray100" },
1748 { RGB_TO_ULONG(255, 255, 255), "grey100" },
1749 { RGB_TO_ULONG(169, 169, 169), "dark grey" },
1750 { RGB_TO_ULONG(169, 169, 169), "DarkGrey" },
1751 { RGB_TO_ULONG(169, 169, 169), "dark gray" },
1752 { RGB_TO_ULONG(169, 169, 169), "DarkGray" },
1753 { RGB_TO_ULONG(0 , 0 , 139), "dark blue" },
1754 { RGB_TO_ULONG(0 , 0 , 139), "DarkBlue" },
1755 { RGB_TO_ULONG(0 , 139, 139), "dark cyan" },
1756 { RGB_TO_ULONG(0 , 139, 139), "DarkCyan" },
1757 { RGB_TO_ULONG(139, 0 , 139), "dark magenta" },
1758 { RGB_TO_ULONG(139, 0 , 139), "DarkMagenta" },
1759 { RGB_TO_ULONG(139, 0 , 0 ), "dark red" },
1760 { RGB_TO_ULONG(139, 0 , 0 ), "DarkRed" },
1761 { RGB_TO_ULONG(144, 238, 144), "light green" },
1762 { RGB_TO_ULONG(144, 238, 144), "LightGreen" }
1763};
1764
1765unsigned long
1766mac_color_map_lookup (colorname)
1767 char *colorname;
1768{
1769 Lisp_Object ret = Qnil;
1770 int i;
1771
1772 BLOCK_INPUT;
1773
1774 for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++)
1775 if (stricmp (colorname, mac_color_map[i].name) == 0)
1776 {
1777 ret = mac_color_map[i].color;
1778 break;
1779 }
1780
1781 UNBLOCK_INPUT;
1782
1783 return ret;
1784}
1785
1786Lisp_Object
1787x_to_mac_color (colorname)
1788 char * colorname;
1789{
1790 register Lisp_Object tail, ret = Qnil;
1791
1792 BLOCK_INPUT;
1793
1794 if (colorname[0] == '#')
1795 {
1796 /* Could be an old-style RGB Device specification. */
1797 char *color;
1798 int size;
1799 color = colorname + 1;
1800
1801 size = strlen(color);
1802 if (size == 3 || size == 6 || size == 9 || size == 12)
1803 {
1804 unsigned long colorval;
1805 int i, pos;
1806 pos = 0;
1807 size /= 3;
1808 colorval = 0;
1809
1810 for (i = 0; i < 3; i++)
1811 {
1812 char *end;
1813 char t;
1814 unsigned long value;
1815
1816 /* The check for 'x' in the following conditional takes into
1817 account the fact that strtol allows a "0x" in front of
1818 our numbers, and we don't. */
1819 if (!isxdigit(color[0]) || color[1] == 'x')
1820 break;
1821 t = color[size];
1822 color[size] = '\0';
1823 value = strtoul(color, &end, 16);
1824 color[size] = t;
1825 if (errno == ERANGE || end - color != size)
1826 break;
1827 switch (size)
1828 {
1829 case 1:
1830 value = value * 0x10;
1831 break;
1832 case 2:
1833 break;
1834 case 3:
1835 value /= 0x10;
1836 break;
1837 case 4:
1838 value /= 0x100;
1839 break;
1840 }
1841 colorval |= (value << pos);
1842 pos += 0x8;
1843 if (i == 2)
1844 {
1845 UNBLOCK_INPUT;
1846 return (colorval);
1847 }
1848 color = end;
1849 }
1850 }
1851 }
1852 else if (strnicmp(colorname, "rgb:", 4) == 0)
1853 {
1854 char *color;
1855 unsigned long colorval;
1856 int i, pos;
1857 pos = 0;
1858
1859 colorval = 0;
1860 color = colorname + 4;
1861 for (i = 0; i < 3; i++)
1862 {
1863 char *end;
1864 unsigned long value;
1865
1866 /* The check for 'x' in the following conditional takes into
1867 account the fact that strtol allows a "0x" in front of
1868 our numbers, and we don't. */
1869 if (!isxdigit(color[0]) || color[1] == 'x')
1870 break;
1871 value = strtoul(color, &end, 16);
1872 if (errno == ERANGE)
1873 break;
1874 switch (end - color)
1875 {
1876 case 1:
1877 value = value * 0x10 + value;
1878 break;
1879 case 2:
1880 break;
1881 case 3:
1882 value /= 0x10;
1883 break;
1884 case 4:
1885 value /= 0x100;
1886 break;
1887 default:
1888 value = ULONG_MAX;
1889 }
1890 if (value == ULONG_MAX)
1891 break;
1892 colorval |= (value << pos);
1893 pos += 0x8;
1894 if (i == 2)
1895 {
1896 if (*end != '\0')
1897 break;
1898 UNBLOCK_INPUT;
1899 return (colorval);
1900 }
1901 if (*end != '/')
1902 break;
1903 color = end + 1;
1904 }
1905 }
1906 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1907 {
1908 /* This is an RGB Intensity specification. */
1909 char *color;
1910 unsigned long colorval;
1911 int i, pos;
1912 pos = 0;
1913
1914 colorval = 0;
1915 color = colorname + 5;
1916 for (i = 0; i < 3; i++)
1917 {
1918 char *end;
1919 double value;
1920 unsigned long val;
1921
1922 value = strtod(color, &end);
1923 if (errno == ERANGE)
1924 break;
1925 if (value < 0.0 || value > 1.0)
1926 break;
1927 val = (unsigned long)(0x100 * value);
1928 /* We used 0x100 instead of 0xFF to give an continuous
1929 range between 0.0 and 1.0 inclusive. The next statement
1930 fixes the 1.0 case. */
1931 if (val == 0x100)
1932 val = 0xFF;
1933 colorval |= (val << pos);
1934 pos += 0x8;
1935 if (i == 2)
1936 {
1937 if (*end != '\0')
1938 break;
1939 UNBLOCK_INPUT;
1940 return (colorval);
1941 }
1942 if (*end != '/')
1943 break;
1944 color = end + 1;
1945 }
1946 }
1947
1948 ret = mac_color_map_lookup (colorname);
1949
1950 UNBLOCK_INPUT;
1951 return ret;
1952}
1953
1954/* Gamma-correct COLOR on frame F. */
1955
1956void
1957gamma_correct (f, color)
1958 struct frame *f;
1959 unsigned long *color;
1960{
1961 if (f->gamma)
1962 {
1963 unsigned long red, green, blue;
1964
1965 red = pow (RED_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
1966 green = pow (GREEN_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
1967 blue = pow (BLUE_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
1968 *color = RGB_TO_ULONG (red, green, blue);
1969 }
1970}
1971
1972/* Decide if color named COLOR is valid for the display associated
1973 with the selected frame; if so, return the rgb values in COLOR_DEF.
1974 If ALLOC is nonzero, allocate a new colormap cell. */
1975
1976int
1977mac_defined_color (f, color, color_def, alloc)
1978 FRAME_PTR f;
1979 char *color;
1980 XColor *color_def;
1981 int alloc;
1982{
1983 register Lisp_Object tem;
1984 unsigned long mac_color_ref;
1985
1986 tem = x_to_mac_color (color);
1987
1988 if (!NILP (tem))
1989 {
1990 if (f)
1991 {
1992 /* Apply gamma correction. */
1993 mac_color_ref = XUINT (tem);
1994 gamma_correct (f, &mac_color_ref);
1995 XSETINT (tem, mac_color_ref);
1996 }
1997
1998 color_def->pixel = mac_color_ref;
1999 color_def->red = RED_FROM_ULONG (mac_color_ref);
2000 color_def->green = GREEN_FROM_ULONG (mac_color_ref);
2001 color_def->blue = BLUE_FROM_ULONG (mac_color_ref);
2002
2003 return 1;
2004 }
2005 else
2006 {
2007 return 0;
2008 }
2009}
2010
2011/* Given a string ARG naming a color, compute a pixel value from it
2012 suitable for screen F.
2013 If F is not a color screen, return DEF (default) regardless of what
2014 ARG says. */
2015
2016int
2017x_decode_color (f, arg, def)
2018 FRAME_PTR f;
2019 Lisp_Object arg;
2020 int def;
2021{
2022 XColor cdef;
2023
2024 CHECK_STRING (arg, 0);
2025
2026 if (strcmp (XSTRING (arg)->data, "black") == 0)
2027 return BLACK_PIX_DEFAULT (f);
2028 else if (strcmp (XSTRING (arg)->data, "white") == 0)
2029 return WHITE_PIX_DEFAULT (f);
2030
2031#if 0
2032 if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes
2033 * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1)
2034 return def;
2035#endif
2036
2037 if (mac_defined_color (f, XSTRING (arg)->data, &cdef, 1))
2038 return cdef.pixel;
2039
2040 /* defined_color failed; return an ultimate default. */
2041 return def;
2042}
2043
2044/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2045 the previous value of that parameter, NEW_VALUE is the new value. */
2046
2047static void
2048x_set_line_spacing (f, new_value, old_value)
2049 struct frame *f;
2050 Lisp_Object new_value, old_value;
2051{
2052 if (NILP (new_value))
2053 f->extra_line_spacing = 0;
2054 else if (NATNUMP (new_value))
2055 f->extra_line_spacing = XFASTINT (new_value);
2056 else
2057 Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
2058 Fcons (new_value, Qnil)));
2059 if (FRAME_VISIBLE_P (f))
2060 redraw_frame (f);
2061}
2062
2063
2064/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2065 the previous value of that parameter, NEW_VALUE is the new value. */
2066
2067static void
2068x_set_screen_gamma (f, new_value, old_value)
2069 struct frame *f;
2070 Lisp_Object new_value, old_value;
2071{
2072 if (NILP (new_value))
2073 f->gamma = 0;
2074 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2075 /* The value 0.4545 is the normal viewing gamma. */
2076 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2077 else
2078 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
2079 Fcons (new_value, Qnil)));
2080
2081 clear_face_cache (0);
2082}
2083
2084
2085/* Functions called only from `x_set_frame_param'
2086 to set individual parameters.
2087
2088 If FRAME_MAC_WINDOW (f) is 0,
2089 the frame is being created and its window does not exist yet.
2090 In that case, just record the parameter's new value
2091 in the standard place; do not attempt to change the window. */
2092
2093void
2094x_set_foreground_color (f, arg, oldval)
2095 struct frame *f;
2096 Lisp_Object arg, oldval;
2097{
2098 FRAME_FOREGROUND_PIXEL (f)
2099 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2100
2101 if (FRAME_MAC_WINDOW (f) != 0)
2102 {
2103 update_face_from_frame_parameter (f, Qforeground_color, arg);
2104 if (FRAME_VISIBLE_P (f))
2105 redraw_frame (f);
2106 }
2107}
2108
2109void
2110x_set_background_color (f, arg, oldval)
2111 struct frame *f;
2112 Lisp_Object arg, oldval;
2113{
2114 FRAME_BACKGROUND_PIXEL (f)
2115 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2116
2117 if (FRAME_MAC_WINDOW (f) != 0)
2118 {
2119 update_face_from_frame_parameter (f, Qbackground_color, arg);
2120
2121 if (FRAME_VISIBLE_P (f))
2122 redraw_frame (f);
2123 }
2124}
2125
2126void
2127x_set_mouse_color (f, arg, oldval)
2128 struct frame *f;
2129 Lisp_Object arg, oldval;
2130{
2131
2132 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2133 int count;
2134 int mask_color;
2135
2136 if (!EQ (Qnil, arg))
2137 f->output_data.mac->mouse_pixel
2138 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2139 mask_color = FRAME_BACKGROUND_PIXEL (f);
2140
2141 /* Don't let pointers be invisible. */
2142 if (mask_color == f->output_data.mac->mouse_pixel
2143 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2144 f->output_data.mac->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2145
2146#if 0 /* MAC_TODO : cursor changes */
2147 BLOCK_INPUT;
2148
2149 /* It's not okay to crash if the user selects a screwy cursor. */
2150 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2151
2152 if (!EQ (Qnil, Vx_pointer_shape))
2153 {
2154 CHECK_NUMBER (Vx_pointer_shape, 0);
2155 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2156 }
2157 else
2158 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2159 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2160
2161 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2162 {
2163 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
2164 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2165 XINT (Vx_nontext_pointer_shape));
2166 }
2167 else
2168 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2169 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2170
2171 if (!EQ (Qnil, Vx_busy_pointer_shape))
2172 {
2173 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2174 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2175 XINT (Vx_busy_pointer_shape));
2176 }
2177 else
2178 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2179 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2180
2181 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2182 if (!EQ (Qnil, Vx_mode_pointer_shape))
2183 {
2184 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
2185 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2186 XINT (Vx_mode_pointer_shape));
2187 }
2188 else
2189 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2190 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2191
2192 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2193 {
2194 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2195 cross_cursor
2196 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2197 XINT (Vx_sensitive_text_pointer_shape));
2198 }
2199 else
2200 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2201
2202 /* Check and report errors with the above calls. */
2203 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2204 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2205
2206 {
2207 XColor fore_color, back_color;
2208
2209 fore_color.pixel = f->output_data.w32->mouse_pixel;
2210 back_color.pixel = mask_color;
2211 XQueryColor (FRAME_W32_DISPLAY (f),
2212 DefaultColormap (FRAME_W32_DISPLAY (f),
2213 DefaultScreen (FRAME_W32_DISPLAY (f))),
2214 &fore_color);
2215 XQueryColor (FRAME_W32_DISPLAY (f),
2216 DefaultColormap (FRAME_W32_DISPLAY (f),
2217 DefaultScreen (FRAME_W32_DISPLAY (f))),
2218 &back_color);
2219 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2220 &fore_color, &back_color);
2221 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2222 &fore_color, &back_color);
2223 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2224 &fore_color, &back_color);
2225 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2226 &fore_color, &back_color);
2227 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2228 &fore_color, &back_color);
2229 }
2230
2231 if (FRAME_W32_WINDOW (f) != 0)
2232 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2233
2234 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2235 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2236 f->output_data.w32->text_cursor = cursor;
2237
2238 if (nontext_cursor != f->output_data.w32->nontext_cursor
2239 && f->output_data.w32->nontext_cursor != 0)
2240 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2241 f->output_data.w32->nontext_cursor = nontext_cursor;
2242
2243 if (busy_cursor != f->output_data.w32->busy_cursor
2244 && f->output_data.w32->busy_cursor != 0)
2245 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2246 f->output_data.w32->busy_cursor = busy_cursor;
2247
2248 if (mode_cursor != f->output_data.w32->modeline_cursor
2249 && f->output_data.w32->modeline_cursor != 0)
2250 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2251 f->output_data.w32->modeline_cursor = mode_cursor;
2252
2253 if (cross_cursor != f->output_data.w32->cross_cursor
2254 && f->output_data.w32->cross_cursor != 0)
2255 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2256 f->output_data.w32->cross_cursor = cross_cursor;
2257
2258 XFlush (FRAME_W32_DISPLAY (f));
2259 UNBLOCK_INPUT;
2260
2261 update_face_from_frame_parameter (f, Qmouse_color, arg);
2262#endif /* MAC_TODO */
2263}
2264
2265void
2266x_set_cursor_color (f, arg, oldval)
2267 struct frame *f;
2268 Lisp_Object arg, oldval;
2269{
2270 unsigned long fore_pixel;
2271
2272 if (!NILP (Vx_cursor_fore_pixel))
2273 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2274 WHITE_PIX_DEFAULT (f));
2275 else
2276 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2277 f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2278
2279 /* Make sure that the cursor color differs from the background color. */
2280 if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
2281 {
2282 f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel;
2283 if (f->output_data.mac->cursor_pixel == fore_pixel)
2284 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2285 }
2286 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2287
2288#if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */
2289 if (FRAME_MAC_WINDOW (f) != 0)
2290 {
2291 if (FRAME_VISIBLE_P (f))
2292 {
2293 x_display_cursor (f, 0);
2294 x_display_cursor (f, 1);
2295 }
2296 }
2297#endif
2298
2299 update_face_from_frame_parameter (f, Qcursor_color, arg);
2300}
2301
2302/* Set the border-color of frame F to pixel value PIX.
2303 Note that this does not fully take effect if done before
2304 F has an window. */
2305void
2306x_set_border_pixel (f, pix)
2307 struct frame *f;
2308 int pix;
2309{
2310 f->output_data.mac->border_pixel = pix;
2311
2312 if (FRAME_MAC_WINDOW (f) != 0 && f->output_data.mac->border_width > 0)
2313 {
2314 if (FRAME_VISIBLE_P (f))
2315 redraw_frame (f);
2316 }
2317}
2318
2319/* Set the border-color of frame F to value described by ARG.
2320 ARG can be a string naming a color.
2321 The border-color is used for the border that is drawn by the server.
2322 Note that this does not fully take effect if done before
2323 F has a window; it must be redone when the window is created. */
2324
2325void
2326x_set_border_color (f, arg, oldval)
2327 struct frame *f;
2328 Lisp_Object arg, oldval;
2329{
2330 int pix;
2331
2332 CHECK_STRING (arg, 0);
2333 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2334 x_set_border_pixel (f, pix);
2335 update_face_from_frame_parameter (f, Qborder_color, arg);
2336}
2337
2338/* Value is the internal representation of the specified cursor type
2339 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2340 of the bar cursor. */
2341
2342enum text_cursor_kinds
2343x_specified_cursor_type (arg, width)
2344 Lisp_Object arg;
2345 int *width;
2346{
2347 enum text_cursor_kinds type;
2348
2349 if (EQ (arg, Qbar))
2350 {
2351 type = BAR_CURSOR;
2352 *width = 2;
2353 }
2354 else if (CONSP (arg)
2355 && EQ (XCAR (arg), Qbar)
2356 && INTEGERP (XCDR (arg))
2357 && XINT (XCDR (arg)) >= 0)
2358 {
2359 type = BAR_CURSOR;
2360 *width = XINT (XCDR (arg));
2361 }
2362 else if (NILP (arg))
2363 type = NO_CURSOR;
2364 else
2365 /* Treat anything unknown as "box cursor".
2366 It was bad to signal an error; people have trouble fixing
2367 .Xdefaults with Emacs, when it has something bad in it. */
2368 type = FILLED_BOX_CURSOR;
2369
2370 return type;
2371}
2372
2373void
2374x_set_cursor_type (f, arg, oldval)
2375 FRAME_PTR f;
2376 Lisp_Object arg, oldval;
2377{
2378 int width;
2379
2380 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2381 f->output_data.mac->cursor_width = width;
2382
2383 /* Make sure the cursor gets redrawn. This is overkill, but how
2384 often do people change cursor types? */
2385 update_mode_lines++;
2386}
2387
2388#if 0 /* MAC_TODO: really no icon for Mac */
2389void
2390x_set_icon_type (f, arg, oldval)
2391 struct frame *f;
2392 Lisp_Object arg, oldval;
2393{
2394 int result;
2395
2396 if (NILP (arg) && NILP (oldval))
2397 return;
2398
2399 if (STRINGP (arg) && STRINGP (oldval)
2400 && EQ (Fstring_equal (oldval, arg), Qt))
2401 return;
2402
2403 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2404 return;
2405
2406 BLOCK_INPUT;
2407
2408 result = x_bitmap_icon (f, arg);
2409 if (result)
2410 {
2411 UNBLOCK_INPUT;
2412 error ("No icon window available");
2413 }
2414
2415 UNBLOCK_INPUT;
2416}
2417#endif
2418
2419/* Return non-nil if frame F wants a bitmap icon. */
2420
2421Lisp_Object
2422x_icon_type (f)
2423 FRAME_PTR f;
2424{
2425 Lisp_Object tem;
2426
2427 tem = assq_no_quit (Qicon_type, f->param_alist);
2428 if (CONSP (tem))
2429 return XCDR (tem);
2430 else
2431 return Qnil;
2432}
2433
2434void
2435x_set_icon_name (f, arg, oldval)
2436 struct frame *f;
2437 Lisp_Object arg, oldval;
2438{
2439 int result;
2440
2441 if (STRINGP (arg))
2442 {
2443 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2444 return;
2445 }
2446 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2447 return;
2448
2449 f->icon_name = arg;
2450
2451#if 0
2452 if (f->output_data.w32->icon_bitmap != 0)
2453 return;
2454
2455 BLOCK_INPUT;
2456
2457 result = x_text_icon (f,
2458 (char *) XSTRING ((!NILP (f->icon_name)
2459 ? f->icon_name
2460 : !NILP (f->title)
2461 ? f->title
2462 : f->name))->data);
2463
2464 if (result)
2465 {
2466 UNBLOCK_INPUT;
2467 error ("No icon window available");
2468 }
2469
2470 /* If the window was unmapped (and its icon was mapped),
2471 the new icon is not mapped, so map the window in its stead. */
2472 if (FRAME_VISIBLE_P (f))
2473 {
2474#ifdef USE_X_TOOLKIT
2475 XtPopup (f->output_data.w32->widget, XtGrabNone);
2476#endif
2477 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2478 }
2479
2480 XFlush (FRAME_W32_DISPLAY (f));
2481 UNBLOCK_INPUT;
2482#endif
2483}
2484
2485extern Lisp_Object x_new_font ();
2486extern Lisp_Object x_new_fontset();
2487
2488void
2489x_set_font (f, arg, oldval)
2490 struct frame *f;
2491 Lisp_Object arg, oldval;
2492{
2493 Lisp_Object result;
2494 Lisp_Object fontset_name;
2495 Lisp_Object frame;
2496
2497 CHECK_STRING (arg, 1);
2498
2499 fontset_name = Fquery_fontset (arg, Qnil);
2500
2501 BLOCK_INPUT;
2502 result = (STRINGP (fontset_name)
2503 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2504 : x_new_font (f, XSTRING (arg)->data));
2505 UNBLOCK_INPUT;
2506
2507 if (EQ (result, Qnil))
2508 error ("Font `%s' is not defined", XSTRING (arg)->data);
2509 else if (EQ (result, Qt))
2510 error ("The characters of the given font have varying widths");
2511 else if (STRINGP (result))
2512 {
2513 store_frame_param (f, Qfont, result);
2514 recompute_basic_faces (f);
2515 }
2516 else
2517 abort ();
2518
2519 do_pending_window_change (0);
2520
2521 /* Don't call `face-set-after-frame-default' when faces haven't been
2522 initialized yet. This is the case when called from
2523 Fx_create_frame. In that case, the X widget or window doesn't
2524 exist either, and we can end up in x_report_frame_params with a
2525 null widget which gives a segfault. */
2526 if (FRAME_FACE_CACHE (f))
2527 {
2528 XSETFRAME (frame, f);
2529 call1 (Qface_set_after_frame_default, frame);
2530 }
2531}
2532
2533void
2534x_set_border_width (f, arg, oldval)
2535 struct frame *f;
2536 Lisp_Object arg, oldval;
2537{
2538 CHECK_NUMBER (arg, 0);
2539
2540 if (XINT (arg) == f->output_data.mac->border_width)
2541 return;
2542
2543#if 0
2544 if (FRAME_MAC_WINDOW (f) != 0)
2545 error ("Cannot change the border width of a window");
2546#endif
2547
2548 f->output_data.mac->border_width = XINT (arg);
2549}
2550
2551void
2552x_set_internal_border_width (f, arg, oldval)
2553 struct frame *f;
2554 Lisp_Object arg, oldval;
2555{
2556 int old = f->output_data.mac->internal_border_width;
2557
2558 CHECK_NUMBER (arg, 0);
2559 f->output_data.mac->internal_border_width = XINT (arg);
2560 if (f->output_data.mac->internal_border_width < 0)
2561 f->output_data.mac->internal_border_width = 0;
2562
2563 if (f->output_data.mac->internal_border_width == old)
2564 return;
2565
2566 if (FRAME_MAC_WINDOW (f) != 0)
2567 {
2568 x_set_window_size (f, 0, f->width, f->height);
2569 SET_FRAME_GARBAGED (f);
2570 do_pending_window_change (0);
2571 }
2572}
2573
2574void
2575x_set_visibility (f, value, oldval)
2576 struct frame *f;
2577 Lisp_Object value, oldval;
2578{
2579 Lisp_Object frame;
2580 XSETFRAME (frame, f);
2581
2582 if (NILP (value))
2583 Fmake_frame_invisible (frame, Qt);
2584 else if (EQ (value, Qicon))
2585 Ficonify_frame (frame);
2586 else
2587 Fmake_frame_visible (frame);
2588}
2589
2590void
2591x_set_menu_bar_lines (f, value, oldval)
2592 struct frame *f;
2593 Lisp_Object value, oldval;
2594{
2595 int nlines;
2596 int olines = FRAME_MENU_BAR_LINES (f);
2597
2598 /* Right now, menu bars don't work properly in minibuf-only frames;
2599 most of the commands try to apply themselves to the minibuffer
2600 frame itself, and get an error because you can't switch buffers
2601 in or split the minibuffer window. */
2602 if (FRAME_MINIBUF_ONLY_P (f))
2603 return;
2604
2605 if (INTEGERP (value))
2606 nlines = XINT (value);
2607 else
2608 nlines = 0;
2609
2610 FRAME_MENU_BAR_LINES (f) = 0;
2611 if (nlines)
2612 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2613 else
2614 {
2615 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2616 free_frame_menubar (f);
2617 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2618
2619 /* Adjust the frame size so that the client (text) dimensions
2620 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2621 set correctly. */
2622 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2623 do_pending_window_change (0);
2624 }
2625 adjust_glyphs (f);
2626}
2627
2628/* Set the number of lines used for the tool bar of frame F to VALUE.
2629 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2630 is the old number of tool bar lines. This function changes the
2631 height of all windows on frame F to match the new tool bar height.
2632 The frame's height doesn't change. */
2633
2634void
2635x_set_tool_bar_lines (f, value, oldval)
2636 struct frame *f;
2637 Lisp_Object value, oldval;
2638{
2639 int delta, nlines;
2640
2641 /* Use VALUE only if an integer >= 0. */
2642 if (INTEGERP (value) && XINT (value) >= 0)
2643 nlines = XFASTINT (value);
2644 else
2645 nlines = 0;
2646
2647 /* Make sure we redisplay all windows in this frame. */
2648 ++windows_or_buffers_changed;
2649
2650 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2651 FRAME_TOOL_BAR_LINES (f) = nlines;
2652 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2653 do_pending_window_change (0);
2654 adjust_glyphs (f);
2655}
2656
2657
2658/* Change the name of frame F to NAME. If NAME is nil, set F's name to
2659 w32_id_name.
2660
2661 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2662 name; if NAME is a string, set F's name to NAME and set
2663 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2664
2665 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2666 suggesting a new name, which lisp code should override; if
2667 F->explicit_name is set, ignore the new name; otherwise, set it. */
2668
2669void
2670x_set_name (f, name, explicit)
2671 struct frame *f;
2672 Lisp_Object name;
2673 int explicit;
2674{
2675 /* Make sure that requests from lisp code override requests from
2676 Emacs redisplay code. */
2677 if (explicit)
2678 {
2679 /* If we're switching from explicit to implicit, we had better
2680 update the mode lines and thereby update the title. */
2681 if (f->explicit_name && NILP (name))
2682 update_mode_lines = 1;
2683
2684 f->explicit_name = ! NILP (name);
2685 }
2686 else if (f->explicit_name)
2687 return;
2688
2689 /* If NAME is nil, set the name to the w32_id_name. */
2690 if (NILP (name))
2691 {
2692 /* Check for no change needed in this very common case
2693 before we do any consing. */
2694 if (!strcmp (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name,
2695 XSTRING (f->name)->data))
2696 return;
2697 name = build_string (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name);
2698 }
2699 else
2700 CHECK_STRING (name, 0);
2701
2702 /* Don't change the name if it's already NAME. */
2703 if (! NILP (Fstring_equal (name, f->name)))
2704 return;
2705
2706 f->name = name;
2707
2708 /* For setting the frame title, the title parameter should override
2709 the name parameter. */
2710 if (! NILP (f->title))
2711 name = f->title;
2712
2713 if (FRAME_MAC_WINDOW (f))
2714 {
2715 if (STRING_MULTIBYTE (name))
2716#if 0 /* MAC_TODO: encoding title string */
2717 name = ENCODE_SYSTEM (name);
2718#else
2719 return;
2720#endif
2721
2722 BLOCK_INPUT;
2723
2724 {
2725 Str255 windowTitle;
2726 if (strlen (XSTRING (name)->data) < 255)
2727 {
2728 strcpy (windowTitle, XSTRING (name)->data);
2729 c2pstr (windowTitle);
2730 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2731 }
2732 }
2733
2734 UNBLOCK_INPUT;
2735 }
2736}
2737
2738/* This function should be called when the user's lisp code has
2739 specified a name for the frame; the name will override any set by the
2740 redisplay code. */
2741void
2742x_explicitly_set_name (f, arg, oldval)
2743 FRAME_PTR f;
2744 Lisp_Object arg, oldval;
2745{
2746 x_set_name (f, arg, 1);
2747}
2748
2749/* This function should be called by Emacs redisplay code to set the
2750 name; names set this way will never override names set by the user's
2751 lisp code. */
2752void
2753x_implicitly_set_name (f, arg, oldval)
2754 FRAME_PTR f;
2755 Lisp_Object arg, oldval;
2756{
2757 x_set_name (f, arg, 0);
2758}
2759
2760/* Change the title of frame F to NAME.
2761 If NAME is nil, use the frame name as the title.
2762
2763 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2764 name; if NAME is a string, set F's name to NAME and set
2765 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2766
2767 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2768 suggesting a new name, which lisp code should override; if
2769 F->explicit_name is set, ignore the new name; otherwise, set it. */
2770
2771void
2772x_set_title (f, name, old_name)
2773 struct frame *f;
2774 Lisp_Object name, old_name;
2775{
2776 /* Don't change the title if it's already NAME. */
2777 if (EQ (name, f->title))
2778 return;
2779
2780 update_mode_lines = 1;
2781
2782 f->title = name;
2783
2784 if (NILP (name))
2785 name = f->name;
2786
2787 if (FRAME_MAC_WINDOW (f))
2788 {
2789 if (STRING_MULTIBYTE (name))
2790#if 0 /* MAC_TODO: encoding title string */
2791 name = ENCODE_SYSTEM (name);
2792#else
2793 return;
2794#endif
2795
2796 BLOCK_INPUT;
2797
2798 {
2799 Str255 windowTitle;
2800 if (strlen (XSTRING (name)->data) < 255)
2801 {
2802 strcpy (windowTitle, XSTRING (name)->data);
2803 c2pstr (windowTitle);
2804 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2805 }
2806 }
2807
2808 UNBLOCK_INPUT;
2809 }
2810}
2811
2812void
2813x_set_autoraise (f, arg, oldval)
2814 struct frame *f;
2815 Lisp_Object arg, oldval;
2816{
2817 f->auto_raise = !EQ (Qnil, arg);
2818}
2819
2820void
2821x_set_autolower (f, arg, oldval)
2822 struct frame *f;
2823 Lisp_Object arg, oldval;
2824{
2825 f->auto_lower = !EQ (Qnil, arg);
2826}
2827
2828void
2829x_set_unsplittable (f, arg, oldval)
2830 struct frame *f;
2831 Lisp_Object arg, oldval;
2832{
2833 f->no_split = !NILP (arg);
2834}
2835
2836void
2837x_set_vertical_scroll_bars (f, arg, oldval)
2838 struct frame *f;
2839 Lisp_Object arg, oldval;
2840{
2841 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2842 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2843 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2844 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2845 {
2846 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2847 = (NILP (arg)
2848 ? vertical_scroll_bar_none
2849 : EQ (Qright, arg)
2850 ? vertical_scroll_bar_right
2851 : vertical_scroll_bar_left);
2852
2853 /* We set this parameter before creating the window for the
2854 frame, so we can get the geometry right from the start.
2855 However, if the window hasn't been created yet, we shouldn't
2856 call x_set_window_size. */
2857 if (FRAME_MAC_WINDOW (f))
2858 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2859 do_pending_window_change (0);
2860 }
2861}
2862
2863void
2864x_set_scroll_bar_width (f, arg, oldval)
2865 struct frame *f;
2866 Lisp_Object arg, oldval;
2867{
2868 /* Imitate X without X Toolkit */
2869
2870 int wid = FONT_WIDTH (f->output_data.mac->font);
2871
2872 if (NILP (arg))
2873 {
2874 /* Make the actual width at least 14 pixels and a multiple of a
2875 character width. */
2876 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
2877
2878 /* Use all of that space (aside from required margins) for the
2879 scroll bar. */
2880 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
2881
2882 if (FRAME_MAC_WINDOW (f))
2883 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2884 do_pending_window_change (0);
2885 }
2886 else if (INTEGERP (arg) && XINT (arg) > 0
2887 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2888 {
2889 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2890 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
2891
2892 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2893 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
2894 if (FRAME_MAC_WINDOW (f))
2895 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2896 do_pending_window_change (0);
2897 }
2898 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2899 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2900 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2901}
2902
2903/* Subroutines of creating an frame. */
2904
2905/* Make sure that Vx_resource_name is set to a reasonable value.
2906 Fix it up, or set it to `emacs' if it is too hopeless. */
2907
2908static void
2909validate_x_resource_name ()
2910{
2911 int len = 0;
2912 /* Number of valid characters in the resource name. */
2913 int good_count = 0;
2914 /* Number of invalid characters in the resource name. */
2915 int bad_count = 0;
2916 Lisp_Object new;
2917 int i;
2918
2919 if (STRINGP (Vx_resource_name))
2920 {
2921 unsigned char *p = XSTRING (Vx_resource_name)->data;
2922 int i;
2923
2924 len = STRING_BYTES (XSTRING (Vx_resource_name));
2925
2926 /* Only letters, digits, - and _ are valid in resource names.
2927 Count the valid characters and count the invalid ones. */
2928 for (i = 0; i < len; i++)
2929 {
2930 int c = p[i];
2931 if (! ((c >= 'a' && c <= 'z')
2932 || (c >= 'A' && c <= 'Z')
2933 || (c >= '0' && c <= '9')
2934 || c == '-' || c == '_'))
2935 bad_count++;
2936 else
2937 good_count++;
2938 }
2939 }
2940 else
2941 /* Not a string => completely invalid. */
2942 bad_count = 5, good_count = 0;
2943
2944 /* If name is valid already, return. */
2945 if (bad_count == 0)
2946 return;
2947
2948 /* If name is entirely invalid, or nearly so, use `emacs'. */
2949 if (good_count == 0
2950 || (good_count == 1 && bad_count > 0))
2951 {
2952 Vx_resource_name = build_string ("emacs");
2953 return;
2954 }
2955
2956 /* Name is partly valid. Copy it and replace the invalid characters
2957 with underscores. */
2958
2959 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2960
2961 for (i = 0; i < len; i++)
2962 {
2963 int c = XSTRING (new)->data[i];
2964 if (! ((c >= 'a' && c <= 'z')
2965 || (c >= 'A' && c <= 'Z')
2966 || (c >= '0' && c <= '9')
2967 || c == '-' || c == '_'))
2968 XSTRING (new)->data[i] = '_';
2969 }
2970}
2971
2972
2973#if 0 /* MAC_TODO: implement resource strings */
2974extern char *x_get_string_resource ();
2975
2976DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2977 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2978This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2979class, where INSTANCE is the name under which Emacs was invoked, or\n\
2980the name specified by the `-name' or `-rn' command-line arguments.\n\
2981\n\
2982The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2983class, respectively. You must specify both of them or neither.\n\
2984If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2985and the class is `Emacs.CLASS.SUBCLASS'.")
2986 (attribute, class, component, subclass)
2987 Lisp_Object attribute, class, component, subclass;
2988{
2989 register char *value;
2990 char *name_key;
2991 char *class_key;
2992
2993 CHECK_STRING (attribute, 0);
2994 CHECK_STRING (class, 0);
2995
2996 if (!NILP (component))
2997 CHECK_STRING (component, 1);
2998 if (!NILP (subclass))
2999 CHECK_STRING (subclass, 2);
3000 if (NILP (component) != NILP (subclass))
3001 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3002
3003 validate_x_resource_name ();
3004
3005 /* Allocate space for the components, the dots which separate them,
3006 and the final '\0'. Make them big enough for the worst case. */
3007 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
3008 + (STRINGP (component)
3009 ? STRING_BYTES (XSTRING (component)) : 0)
3010 + STRING_BYTES (XSTRING (attribute))
3011 + 3);
3012
3013 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3014 + STRING_BYTES (XSTRING (class))
3015 + (STRINGP (subclass)
3016 ? STRING_BYTES (XSTRING (subclass)) : 0)
3017 + 3);
3018
3019 /* Start with emacs.FRAMENAME for the name (the specific one)
3020 and with `Emacs' for the class key (the general one). */
3021 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3022 strcpy (class_key, EMACS_CLASS);
3023
3024 strcat (class_key, ".");
3025 strcat (class_key, XSTRING (class)->data);
3026
3027 if (!NILP (component))
3028 {
3029 strcat (class_key, ".");
3030 strcat (class_key, XSTRING (subclass)->data);
3031
3032 strcat (name_key, ".");
3033 strcat (name_key, XSTRING (component)->data);
3034 }
3035
3036 strcat (name_key, ".");
3037 strcat (name_key, XSTRING (attribute)->data);
3038
3039 value = x_get_string_resource (Qnil,
3040 name_key, class_key);
3041
3042 if (value != (char *) 0)
3043 return build_string (value);
3044 else
3045 return Qnil;
3046}
3047
3048/* Used when C code wants a resource value. */
3049
3050char *
3051x_get_resource_string (attribute, class)
3052 char *attribute, *class;
3053{
3054 char *name_key;
3055 char *class_key;
3056 struct frame *sf = SELECTED_FRAME ();
3057
3058 /* Allocate space for the components, the dots which separate them,
3059 and the final '\0'. */
3060 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3061 + strlen (attribute) + 2);
3062 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3063 + strlen (class) + 2);
3064
3065 sprintf (name_key, "%s.%s",
3066 XSTRING (Vinvocation_name)->data,
3067 attribute);
3068 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3069
3070 return x_get_string_resource (sf, name_key, class_key);
3071}
3072#endif
3073
3074/* Types we might convert a resource string into. */
3075enum resource_types
3076{
3077 RES_TYPE_NUMBER,
3078 RES_TYPE_FLOAT,
3079 RES_TYPE_BOOLEAN,
3080 RES_TYPE_STRING,
3081 RES_TYPE_SYMBOL
3082};
3083
3084/* Return the value of parameter PARAM.
3085
3086 First search ALIST, then Vdefault_frame_alist, then the X defaults
3087 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3088
3089 Convert the resource to the type specified by desired_type.
3090
3091 If no default is specified, return Qunbound. If you call
3092 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3093 and don't let it get stored in any Lisp-visible variables! */
3094
3095static Lisp_Object
3096mac_get_arg (alist, param, attribute, class, type)
3097 Lisp_Object alist, param;
3098 char *attribute;
3099 char *class;
3100 enum resource_types type;
3101{
3102 register Lisp_Object tem;
3103
3104 tem = Fassq (param, alist);
3105 if (EQ (tem, Qnil))
3106 tem = Fassq (param, Vdefault_frame_alist);
3107 if (EQ (tem, Qnil))
3108 {
3109
3110#if 0 /* MAC_TODO: search resource also */
3111 if (attribute)
3112 {
3113 tem = Fx_get_resource (build_string (attribute),
3114 build_string (class),
3115 Qnil, Qnil);
3116
3117 if (NILP (tem))
3118 return Qunbound;
3119
3120 switch (type)
3121 {
3122 case RES_TYPE_NUMBER:
3123 return make_number (atoi (XSTRING (tem)->data));
3124
3125 case RES_TYPE_FLOAT:
3126 return make_float (atof (XSTRING (tem)->data));
3127
3128 case RES_TYPE_BOOLEAN:
3129 tem = Fdowncase (tem);
3130 if (!strcmp (XSTRING (tem)->data, "on")
3131 || !strcmp (XSTRING (tem)->data, "true"))
3132 return Qt;
3133 else
3134 return Qnil;
3135
3136 case RES_TYPE_STRING:
3137 return tem;
3138
3139 case RES_TYPE_SYMBOL:
3140 /* As a special case, we map the values `true' and `on'
3141 to Qt, and `false' and `off' to Qnil. */
3142 {
3143 Lisp_Object lower;
3144 lower = Fdowncase (tem);
3145 if (!strcmp (XSTRING (lower)->data, "on")
3146 || !strcmp (XSTRING (lower)->data, "true"))
3147 return Qt;
3148 else if (!strcmp (XSTRING (lower)->data, "off")
3149 || !strcmp (XSTRING (lower)->data, "false"))
3150 return Qnil;
3151 else
3152 return Fintern (tem, Qnil);
3153 }
3154
3155 default:
3156 abort ();
3157 }
3158 }
3159 else
3160#endif
3161 return Qunbound;
3162 }
3163 return Fcdr (tem);
3164}
3165
3166/* Record in frame F the specified or default value according to ALIST
3167 of the parameter named PROP (a Lisp symbol).
3168 If no value is specified for PROP, look for an X default for XPROP
3169 on the frame named NAME.
3170 If that is not found either, use the value DEFLT. */
3171
3172static Lisp_Object
3173x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3174 struct frame *f;
3175 Lisp_Object alist;
3176 Lisp_Object prop;
3177 Lisp_Object deflt;
3178 char *xprop;
3179 char *xclass;
3180 enum resource_types type;
3181{
3182 Lisp_Object tem;
3183
3184 tem = mac_get_arg (alist, prop, xprop, xclass, type);
3185 if (EQ (tem, Qunbound))
3186 tem = deflt;
3187 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3188 return tem;
3189}
3190
3191DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3192 "Parse an X-style geometry string STRING.\n\
3193Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3194The properties returned may include `top', `left', `height', and `width'.\n\
3195The value of `left' or `top' may be an integer,\n\
3196or a list (+ N) meaning N pixels relative to top/left corner,\n\
3197or a list (- N) meaning -N pixels relative to bottom/right corner.")
3198 (string)
3199 Lisp_Object string;
3200{
3201 int geometry, x, y;
3202 unsigned int width, height;
3203 Lisp_Object result;
3204
3205 CHECK_STRING (string, 0);
3206
3207 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3208 &x, &y, &width, &height);
3209
3210 result = Qnil;
3211 if (geometry & XValue)
3212 {
3213 Lisp_Object element;
3214
3215 if (x >= 0 && (geometry & XNegative))
3216 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3217 else if (x < 0 && ! (geometry & XNegative))
3218 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3219 else
3220 element = Fcons (Qleft, make_number (x));
3221 result = Fcons (element, result);
3222 }
3223
3224 if (geometry & YValue)
3225 {
3226 Lisp_Object element;
3227
3228 if (y >= 0 && (geometry & YNegative))
3229 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3230 else if (y < 0 && ! (geometry & YNegative))
3231 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3232 else
3233 element = Fcons (Qtop, make_number (y));
3234 result = Fcons (element, result);
3235 }
3236
3237 if (geometry & WidthValue)
3238 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3239 if (geometry & HeightValue)
3240 result = Fcons (Fcons (Qheight, make_number (height)), result);
3241
3242 return result;
3243}
3244
3245/* Calculate the desired size and position of this window,
3246 and return the flags saying which aspects were specified.
3247
3248 This function does not make the coordinates positive. */
3249
3250#define DEFAULT_ROWS 40
3251#define DEFAULT_COLS 80
3252
3253static int
3254x_figure_window_size (f, parms)
3255 struct frame *f;
3256 Lisp_Object parms;
3257{
3258 register Lisp_Object tem0, tem1, tem2;
3259 long window_prompting = 0;
3260
3261 /* Default values if we fall through.
3262 Actually, if that happens we should get
3263 window manager prompting. */
3264 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3265 f->height = DEFAULT_ROWS;
3266 /* Window managers expect that if program-specified
3267 positions are not (0,0), they're intentional, not defaults. */
3268 f->output_data.mac->top_pos = 0;
3269 f->output_data.mac->left_pos = 0;
3270
3271 tem0 = mac_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3272 tem1 = mac_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3273 tem2 = mac_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3274 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3275 {
3276 if (!EQ (tem0, Qunbound))
3277 {
3278 CHECK_NUMBER (tem0, 0);
3279 f->height = XINT (tem0);
3280 }
3281 if (!EQ (tem1, Qunbound))
3282 {
3283 CHECK_NUMBER (tem1, 0);
3284 SET_FRAME_WIDTH (f, XINT (tem1));
3285 }
3286 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3287 window_prompting |= USSize;
3288 else
3289 window_prompting |= PSize;
3290 }
3291
3292 f->output_data.mac->vertical_scroll_bar_extra
3293 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3294 ? 0
3295 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3296 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3297 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
3298 f->output_data.mac->flags_areas_extra
3299 = FRAME_FLAGS_AREA_WIDTH (f);
3300 f->output_data.mac->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3301 f->output_data.mac->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3302
3303 tem0 = mac_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3304 tem1 = mac_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3305 tem2 = mac_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3306 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3307 {
3308 if (EQ (tem0, Qminus))
3309 {
3310 f->output_data.mac->top_pos = 0;
3311 window_prompting |= YNegative;
3312 }
3313 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3314 && CONSP (XCDR (tem0))
3315 && INTEGERP (XCAR (XCDR (tem0))))
3316 {
3317 f->output_data.mac->top_pos = - XINT (XCAR (XCDR (tem0)));
3318 window_prompting |= YNegative;
3319 }
3320 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3321 && CONSP (XCDR (tem0))
3322 && INTEGERP (XCAR (XCDR (tem0))))
3323 {
3324 f->output_data.mac->top_pos = XINT (XCAR (XCDR (tem0)));
3325 }
3326 else if (EQ (tem0, Qunbound))
3327 f->output_data.mac->top_pos = 0;
3328 else
3329 {
3330 CHECK_NUMBER (tem0, 0);
3331 f->output_data.mac->top_pos = XINT (tem0);
3332 if (f->output_data.mac->top_pos < 0)
3333 window_prompting |= YNegative;
3334 }
3335
3336 if (EQ (tem1, Qminus))
3337 {
3338 f->output_data.mac->left_pos = 0;
3339 window_prompting |= XNegative;
3340 }
3341 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3342 && CONSP (XCDR (tem1))
3343 && INTEGERP (XCAR (XCDR (tem1))))
3344 {
3345 f->output_data.mac->left_pos = - XINT (XCAR (XCDR (tem1)));
3346 window_prompting |= XNegative;
3347 }
3348 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3349 && CONSP (XCDR (tem1))
3350 && INTEGERP (XCAR (XCDR (tem1))))
3351 {
3352 f->output_data.mac->left_pos = XINT (XCAR (XCDR (tem1)));
3353 }
3354 else if (EQ (tem1, Qunbound))
3355 f->output_data.mac->left_pos = 0;
3356 else
3357 {
3358 CHECK_NUMBER (tem1, 0);
3359 f->output_data.mac->left_pos = XINT (tem1);
3360 if (f->output_data.mac->left_pos < 0)
3361 window_prompting |= XNegative;
3362 }
3363
3364 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3365 window_prompting |= USPosition;
3366 else
3367 window_prompting |= PPosition;
3368 }
3369
3370 return window_prompting;
3371}
3372
3373
3374#if 0
3375/* Create and set up the Mac window for frame F. */
3376
3377static void
3378mac_window (f, window_prompting, minibuffer_only)
3379 struct frame *f;
3380 long window_prompting;
3381 int minibuffer_only;
3382{
3383 Rect r;
3384
3385 BLOCK_INPUT;
3386
3387 /* Use the resource name as the top-level window name
3388 for looking up resources. Make a non-Lisp copy
3389 for the window manager, so GC relocation won't bother it.
3390
3391 Elsewhere we specify the window name for the window manager. */
3392
3393 {
3394 char *str = (char *) XSTRING (Vx_resource_name)->data;
3395 f->namebuf = (char *) xmalloc (strlen (str) + 1);
3396 strcpy (f->namebuf, str);
3397 }
3398
3399 SetRect (&r, f->output_data.mac->left_pos, f->output_data.mac->top_pos,
3400 f->output_data.mac->left_pos + PIXEL_WIDTH (f),
3401 f->output_data.mac->top_pos + PIXEL_HEIGHT (f));
3402 FRAME_MAC_WINDOW (f)
3403 = NewCWindow (NULL, &r, "\p", 1, zoomDocProc, (WindowPtr) -1, 1, (long) f->output_data.mac);
3404
3405 validate_x_resource_name ();
3406
3407 /* x_set_name normally ignores requests to set the name if the
3408 requested name is the same as the current name. This is the one
3409 place where that assumption isn't correct; f->name is set, but
3410 the server hasn't been told. */
3411 {
3412 Lisp_Object name;
3413 int explicit = f->explicit_name;
3414
3415 f->explicit_name = 0;
3416 name = f->name;
3417 f->name = Qnil;
3418 x_set_name (f, name, explicit);
3419 }
3420
3421 ShowWindow (FRAME_MAC_WINDOW (f));
3422
3423 UNBLOCK_INPUT;
3424
3425 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
3426 initialize_frame_menubar (f);
3427
3428 if (FRAME_MAC_WINDOW (f) == 0)
3429 error ("Unable to create window");
3430}
3431#endif
3432
3433/* Handle the icon stuff for this window. Perhaps later we might
3434 want an x_set_icon_position which can be called interactively as
3435 well. */
3436
3437static void
3438x_icon (f, parms)
3439 struct frame *f;
3440 Lisp_Object parms;
3441{
3442 Lisp_Object icon_x, icon_y;
3443
3444 /* Set the position of the icon. Note that Windows 95 groups all
3445 icons in the tray. */
3446 icon_x = mac_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
3447 icon_y = mac_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
3448 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
3449 {
3450 CHECK_NUMBER (icon_x, 0);
3451 CHECK_NUMBER (icon_y, 0);
3452 }
3453 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
3454 error ("Both left and top icon corners of icon must be specified");
3455
3456 BLOCK_INPUT;
3457
3458 if (! EQ (icon_x, Qunbound))
3459 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
3460
3461#if 0 /* TODO */
3462 /* Start up iconic or window? */
3463 x_wm_set_window_state
3464 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
3465 ? IconicState
3466 : NormalState));
3467
3468 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
3469 ? f->icon_name
3470 : f->name))->data);
3471#endif
3472
3473 UNBLOCK_INPUT;
3474}
3475
3476
3477static void
3478x_make_gc (f)
3479 struct frame *f;
3480{
3481 XGCValues gc_values;
3482
3483 BLOCK_INPUT;
3484
3485 /* Create the GC's of this frame.
3486 Note that many default values are used. */
3487
3488 /* Normal video */
3489 gc_values.font = f->output_data.mac->font;
3490 gc_values.foreground = f->output_data.mac->foreground_pixel;
3491 gc_values.background = f->output_data.mac->background_pixel;
3492 f->output_data.mac->normal_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3493 FRAME_MAC_WINDOW (f),
3494 GCFont | GCForeground | GCBackground,
3495 &gc_values);
3496
3497 /* Reverse video style. */
3498 gc_values.foreground = f->output_data.mac->background_pixel;
3499 gc_values.background = f->output_data.mac->foreground_pixel;
3500 f->output_data.mac->reverse_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3501 FRAME_MAC_WINDOW (f),
3502 GCFont | GCForeground | GCBackground,
3503 &gc_values);
3504
3505 /* Cursor has cursor-color background, background-color foreground. */
3506 gc_values.foreground = f->output_data.mac->background_pixel;
3507 gc_values.background = f->output_data.mac->cursor_pixel;
3508 f->output_data.mac->cursor_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3509 FRAME_MAC_WINDOW (f),
3510 GCFont | GCForeground | GCBackground,
3511 &gc_values);
3512
3513 /* Reliefs. */
3514 f->output_data.mac->white_relief.gc = 0;
3515 f->output_data.mac->black_relief.gc = 0;
3516
3517 UNBLOCK_INPUT;
3518}
3519
3520
3521DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
3522 1, 1, 0,
3523 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
3524Returns an Emacs frame object.\n\
3525ALIST is an alist of frame parameters.\n\
3526If the parameters specify that the frame should not have a minibuffer,\n\
3527and do not specify a specific minibuffer window to use,\n\
3528then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
3529be shared by the new frame.\n\
3530\n\
3531This function is an internal primitive--use `make-frame' instead.")
3532 (parms)
3533 Lisp_Object parms;
3534{
3535 struct frame *f;
3536 Lisp_Object frame, tem;
3537 Lisp_Object name;
3538 int minibuffer_only = 0;
3539 long window_prompting = 0;
3540 int width, height;
3541 int count = specpdl_ptr - specpdl;
3542 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3543 Lisp_Object display;
3544 struct mac_display_info *dpyinfo = NULL;
3545 Lisp_Object parent;
3546 struct kboard *kb;
3547 char x_frame_name[10];
3548 static int x_frame_count = 2; /* starts from 2 because terminal frame is F1 */
3549
3550 check_mac ();
3551
3552 /* Use this general default value to start with
3553 until we know if this frame has a specified name. */
3554 Vx_resource_name = Vinvocation_name;
3555
3556 display = mac_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
3557 if (EQ (display, Qunbound))
3558 display = Qnil;
3559 dpyinfo = check_x_display_info (display);
3560#ifdef MULTI_KBOARD
3561 kb = dpyinfo->kboard;
3562#else
3563 kb = &the_only_kboard;
3564#endif
3565
3566 name = mac_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
3567 if (!STRINGP (name)
3568 && ! EQ (name, Qunbound)
3569 && ! NILP (name))
3570 error ("Invalid frame name--not a string or nil");
3571
3572 if (STRINGP (name))
3573 Vx_resource_name = name;
3574
3575 /* See if parent window is specified. */
3576 parent = mac_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
3577 if (EQ (parent, Qunbound))
3578 parent = Qnil;
3579 if (! NILP (parent))
3580 CHECK_NUMBER (parent, 0);
3581
3582 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
3583 /* No need to protect DISPLAY because that's not used after passing
3584 it to make_frame_without_minibuffer. */
3585 frame = Qnil;
3586 GCPRO4 (parms, parent, name, frame);
3587 tem = mac_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
3588 if (EQ (tem, Qnone) || NILP (tem))
3589 f = make_frame_without_minibuffer (Qnil, kb, display);
3590 else if (EQ (tem, Qonly))
3591 {
3592 f = make_minibuffer_frame ();
3593 minibuffer_only = 1;
3594 }
3595 else if (WINDOWP (tem))
3596 f = make_frame_without_minibuffer (tem, kb, display);
3597 else
3598 f = make_frame (1);
3599
3600 if (EQ (name, Qunbound) || NILP (name))
3601 {
3602 sprintf (x_frame_name, "F%d", x_frame_count++);
3603 f->name = build_string (x_frame_name);
3604 f->explicit_name = 0;
3605 }
3606 else
3607 {
3608 f->name = name;
3609 f->explicit_name = 1;
3610 }
3611
3612 XSETFRAME (frame, f);
3613
3614 /* Note that X Windows does support scroll bars. */
3615 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
3616
3617 f->output_method = output_mac;
3618 f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output));
3619 bzero (f->output_data.mac, sizeof (struct mac_output));
3620 f->output_data.mac->fontset = -1;
3621 f->output_data.mac->scroll_bar_foreground_pixel = -1;
3622 f->output_data.mac->scroll_bar_background_pixel = -1;
3623
3624#if 0
3625 FRAME_FONTSET (f) = -1;
3626#endif
3627
3628 f->icon_name
3629 = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
3630 if (! STRINGP (f->icon_name))
3631 f->icon_name = Qnil;
3632
3633/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
3634#ifdef MULTI_KBOARD
3635 FRAME_KBOARD (f) = kb;
3636#endif
3637
3638 /* Specify the parent under which to make this window. */
3639
3640 if (!NILP (parent))
3641 {
3642 f->output_data.mac->parent_desc = (Window) parent;
3643 f->output_data.mac->explicit_parent = 1;
3644 }
3645 else
3646 {
3647 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3648 f->output_data.mac->explicit_parent = 0;
3649 }
3650
3651 /* Set the name; the functions to which we pass f expect the name to
3652 be set. */
3653 if (EQ (name, Qunbound) || NILP (name))
3654 {
3655 f->name = build_string (dpyinfo->mac_id_name);
3656 f->explicit_name = 0;
3657 }
3658 else
3659 {
3660 f->name = name;
3661 f->explicit_name = 1;
3662 /* use the frame's title when getting resources for this frame. */
3663 specbind (Qx_resource_name, name);
3664 }
3665
3666 /* Extract the window parameters from the supplied values
3667 that are needed to determine window geometry. */
3668 {
3669 Lisp_Object font;
3670
3671 font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
3672
3673 BLOCK_INPUT;
3674 /* First, try whatever font the caller has specified. */
3675 if (STRINGP (font))
3676 {
3677 tem = Fquery_fontset (font, Qnil);
3678 if (STRINGP (tem))
3679 font = x_new_fontset (f, XSTRING (tem)->data);
3680 else
3681 font = x_new_font (f, XSTRING (font)->data);
3682 }
3683 /* Try out a font which we hope has bold and italic variations. */
3684 if (! STRINGP (font))
3685 font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1");
3686 /* If those didn't work, look for something which will at least work. */
3687 if (!STRINGP (font))
3688 font = x_new_font (f, "-*-monaco-*-12-*-mac-roman");
3689 if (! STRINGP (font))
3690 font = x_new_font (f, "-*-courier-*-10-*-mac-roman");
3691 if (! STRINGP (font))
3692 error ("Cannot find any usable font");
3693 UNBLOCK_INPUT;
3694
3695 x_default_parameter (f, parms, Qfont, font,
3696 "font", "Font", RES_TYPE_STRING);
3697 }
3698
3699 x_default_parameter (f, parms, Qborder_width, make_number (0),
3700 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
3701 /* This defaults to 2 in order to match xterm. We recognize either
3702 internalBorderWidth or internalBorder (which is what xterm calls
3703 it). */
3704 if (NILP (Fassq (Qinternal_border_width, parms)))
3705 {
3706 Lisp_Object value;
3707
3708 value = mac_get_arg (parms, Qinternal_border_width,
3709 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
3710 if (! EQ (value, Qunbound))
3711 parms = Fcons (Fcons (Qinternal_border_width, value),
3712 parms);
3713 }
3714
3715 /* Default internalBorderWidth to 0 on Windows to match other programs. */
3716 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
3717 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
3718
3719 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
3720 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
3721
3722 /* Also do the stuff which must be set before the window exists. */
3723 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
3724 "foreground", "Foreground", RES_TYPE_STRING);
3725 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
3726 "background", "Background", RES_TYPE_STRING);
3727 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
3728 "pointerColor", "Foreground", RES_TYPE_STRING);
3729 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
3730 "cursorColor", "Foreground", RES_TYPE_STRING);
3731 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
3732 "borderColor", "BorderColor", RES_TYPE_STRING);
3733 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
3734 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
3735 x_default_parameter (f, parms, Qline_spacing, Qnil,
3736 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
3737
3738 /* Init faces before x_default_parameter is called for scroll-bar
3739 parameters because that function calls x_set_scroll_bar_width,
3740 which calls change_frame_size, which calls Fset_window_buffer,
3741 which runs hooks, which call Fvertical_motion. At the end, we
3742 end up in init_iterator with a null face cache, which should not
3743 happen. */
3744 init_frame_faces (f);
3745
3746 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
3747 "menuBar", "MenuBar", RES_TYPE_NUMBER);
3748 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
3749 "toolBar", "ToolBar", RES_TYPE_NUMBER);
3750#if 0
3751 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
3752 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
3753#endif
3754 x_default_parameter (f, parms, Qtitle, Qnil,
3755 "title", "Title", RES_TYPE_STRING);
3756
3757 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3758 window_prompting = x_figure_window_size (f, parms);
3759
3760 if (window_prompting & XNegative)
3761 {
3762 if (window_prompting & YNegative)
3763 f->output_data.mac->win_gravity = SouthEastGravity;
3764 else
3765 f->output_data.mac->win_gravity = NorthEastGravity;
3766 }
3767 else
3768 {
3769 if (window_prompting & YNegative)
3770 f->output_data.mac->win_gravity = SouthWestGravity;
3771 else
3772 f->output_data.mac->win_gravity = NorthWestGravity;
3773 }
3774
3775 f->output_data.mac->size_hint_flags = window_prompting;
3776
3777 tem = mac_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
3778 f->no_split = minibuffer_only || EQ (tem, Qt);
3779
3780 /* Create the window. Add the tool-bar height to the initial frame
3781 height so that the user gets a text display area of the size he
3782 specified with -g or via the registry. Later changes of the
3783 tool-bar height don't change the frame size. This is done so that
3784 users can create tall Emacs frames without having to guess how
3785 tall the tool-bar will get. */
3786 f->height += FRAME_TOOL_BAR_LINES (f);
3787
3788 /* mac_window (f, window_prompting, minibuffer_only); */
3789 make_mac_frame (f);
3790
3791 x_icon (f, parms);
3792
3793 x_make_gc (f);
3794
3795 /* Now consider the frame official. */
3796 FRAME_MAC_DISPLAY_INFO (f)->reference_count++;
3797 Vframe_list = Fcons (frame, Vframe_list);
3798
3799 /* We need to do this after creating the window, so that the
3800 icon-creation functions can say whose icon they're describing. */
3801 x_default_parameter (f, parms, Qicon_type, Qnil,
3802 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
3803
3804 x_default_parameter (f, parms, Qauto_raise, Qnil,
3805 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
3806 x_default_parameter (f, parms, Qauto_lower, Qnil,
3807 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
3808 x_default_parameter (f, parms, Qcursor_type, Qbox,
3809 "cursorType", "CursorType", RES_TYPE_SYMBOL);
3810 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
3811 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
3812
3813 /* Dimensions, especially f->height, must be done via change_frame_size.
3814 Change will not be effected unless different from the current
3815 f->height. */
3816
3817 width = f->width;
3818 height = f->height;
3819 f->height = 0;
3820 SET_FRAME_WIDTH (f, 0);
3821 change_frame_size (f, height, width, 1, 0, 0);
3822
3823 /* Set up faces after all frame parameters are known. */
3824 call1 (Qface_set_after_frame_default, frame);
3825
3826#if 0 /* MAC_TODO: when we have window manager hints */
3827 /* Tell the server what size and position, etc, we want, and how
3828 badly we want them. This should be done after we have the menu
3829 bar so that its size can be taken into account. */
3830 BLOCK_INPUT;
3831 x_wm_set_size_hint (f, window_prompting, 0);
3832 UNBLOCK_INPUT;
3833#endif
3834
3835 /* Make the window appear on the frame and enable display, unless
3836 the caller says not to. However, with explicit parent, Emacs
3837 cannot control visibility, so don't try. */
3838 if (! f->output_data.mac->explicit_parent)
3839 {
3840 Lisp_Object visibility;
3841
3842 visibility = mac_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
3843 if (EQ (visibility, Qunbound))
3844 visibility = Qt;
3845
3846#if 0 /* MAC_TODO: really no iconify on Mac */
3847 if (EQ (visibility, Qicon))
3848 x_iconify_frame (f);
3849 else
3850#endif
3851 if (! NILP (visibility))
3852 x_make_frame_visible (f);
3853 else
3854 /* Must have been Qnil. */
3855 ;
3856 }
3857
3858 UNGCPRO;
3859 return unbind_to (count, frame);
3860}
3861
3862/* FRAME is used only to get a handle on the X display. We don't pass the
3863 display info directly because we're called from frame.c, which doesn't
3864 know about that structure. */
3865Lisp_Object
3866x_get_focus_frame (frame)
3867 struct frame *frame;
3868{
3869 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
3870 Lisp_Object xfocus;
3871 if (! dpyinfo->x_focus_frame)
3872 return Qnil;
3873
3874 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
3875 return xfocus;
3876}
3877
3878DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
3879 "Internal function called by `color-defined-p', which see.")
3880 (color, frame)
3881 Lisp_Object color, frame;
3882{
3883 XColor foo;
3884 FRAME_PTR f = check_x_frame (frame);
3885
3886 CHECK_STRING (color, 1);
3887
3888 if (mac_defined_color (f, XSTRING (color)->data, &foo, 0))
3889 return Qt;
3890 else
3891 return Qnil;
3892}
3893
3894DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
3895 "Internal function called by `color-values', which see.")
3896 (color, frame)
3897 Lisp_Object color, frame;
3898{
3899 XColor foo;
3900 FRAME_PTR f = check_x_frame (frame);
3901
3902 CHECK_STRING (color, 1);
3903
3904 if (mac_defined_color (f, XSTRING (color)->data, &foo, 0))
3905 {
3906 Lisp_Object rgb[3];
3907
3908 rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8)
3909 | RED_FROM_ULONG (foo.pixel));
3910 rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8)
3911 | GREEN_FROM_ULONG (foo.pixel));
3912 rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8)
3913 | BLUE_FROM_ULONG (foo.pixel));
3914 return Flist (3, rgb);
3915 }
3916 else
3917 return Qnil;
3918}
3919
3920DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
3921 "Internal function called by `display-color-p', which see.")
3922 (display)
3923 Lisp_Object display;
3924{
3925 struct mac_display_info *dpyinfo = check_x_display_info (display);
3926
3927 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
3928 return Qnil;
3929
3930 return Qt;
3931}
3932
3933DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
3934 0, 1, 0,
3935 "Return t if the X display supports shades of gray.\n\
3936Note that color displays do support shades of gray.\n\
3937The optional argument DISPLAY specifies which display to ask about.\n\
3938DISPLAY should be either a frame or a display name (a string).\n\
3939If omitted or nil, that stands for the selected frame's display.")
3940 (display)
3941 Lisp_Object display;
3942{
3943 struct mac_display_info *dpyinfo = check_x_display_info (display);
3944
3945 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
3946 return Qnil;
3947
3948 return Qt;
3949}
3950
3951DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
3952 0, 1, 0,
3953 "Returns the width in pixels of the X display DISPLAY.\n\
3954The optional argument DISPLAY specifies which display to ask about.\n\
3955DISPLAY should be either a frame or a display name (a string).\n\
3956If omitted or nil, that stands for the selected frame's display.")
3957 (display)
3958 Lisp_Object display;
3959{
3960 struct mac_display_info *dpyinfo = check_x_display_info (display);
3961
3962 return make_number (dpyinfo->width);
3963}
3964
3965DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
3966 Sx_display_pixel_height, 0, 1, 0,
3967 "Returns the height in pixels of the X display DISPLAY.\n\
3968The optional argument DISPLAY specifies which display to ask about.\n\
3969DISPLAY should be either a frame or a display name (a string).\n\
3970If omitted or nil, that stands for the selected frame's display.")
3971 (display)
3972 Lisp_Object display;
3973{
3974 struct mac_display_info *dpyinfo = check_x_display_info (display);
3975
3976 return make_number (dpyinfo->height);
3977}
3978
3979DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
3980 0, 1, 0,
3981 "Returns the number of bitplanes of the display DISPLAY.\n\
3982The optional argument DISPLAY specifies which display to ask about.\n\
3983DISPLAY should be either a frame or a display name (a string).\n\
3984If omitted or nil, that stands for the selected frame's display.")
3985 (display)
3986 Lisp_Object display;
3987{
3988 struct mac_display_info *dpyinfo = check_x_display_info (display);
3989
3990 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
3991}
3992
3993DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
3994 0, 1, 0,
3995 "Returns the number of color cells of the display DISPLAY.\n\
3996The optional argument DISPLAY specifies which display to ask about.\n\
3997DISPLAY should be either a frame or a display name (a string).\n\
3998If omitted or nil, that stands for the selected frame's display.")
3999 (display)
4000 Lisp_Object display;
4001{
4002 struct mac_display_info *dpyinfo = check_x_display_info (display);
4003
4004 /* MAC_TODO: check whether this is right */
4005 return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits)));
4006}
4007
4008DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4009 Sx_server_max_request_size,
4010 0, 1, 0,
4011 "Returns the maximum request size of the server of display DISPLAY.\n\
4012The optional argument DISPLAY specifies which display to ask about.\n\
4013DISPLAY should be either a frame or a display name (a string).\n\
4014If omitted or nil, that stands for the selected frame's display.")
4015 (display)
4016 Lisp_Object display;
4017{
4018 struct mac_display_info *dpyinfo = check_x_display_info (display);
4019
4020 return make_number (1);
4021}
4022
4023DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
4024 "Returns the vendor ID string of the W32 system (Microsoft).\n\
4025The optional argument DISPLAY specifies which display to ask about.\n\
4026DISPLAY should be either a frame or a display name (a string).\n\
4027If omitted or nil, that stands for the selected frame's display.")
4028 (display)
4029 Lisp_Object display;
4030{
4031 return build_string ("Apple Computers");
4032}
4033
4034DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
4035 "Returns the version numbers of the server of display DISPLAY.\n\
4036The value is a list of three integers: the major and minor\n\
4037version numbers, and the vendor-specific release\n\
4038number. See also the function `x-server-vendor'.\n\n\
4039The optional argument DISPLAY specifies which display to ask about.\n\
4040DISPLAY should be either a frame or a display name (a string).\n\
4041If omitted or nil, that stands for the selected frame's display.")
4042 (display)
4043 Lisp_Object display;
4044{
4045 int mac_major_version, mac_minor_version;
4046 SInt32 response;
4047
4048 if (Gestalt (gestaltSystemVersion, &response) != noErr)
4049 error ("Cannot get Mac OS version");
4050
4051 mac_major_version = (response >> 8) & 0xf;
4052 mac_minor_version = (response >> 4) & 0xf;
4053
4054 return Fcons (make_number (mac_major_version),
4055 Fcons (make_number (mac_minor_version), Qnil));
4056}
4057
4058DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4059 "Returns the number of screens on the server of display DISPLAY.\n\
4060The optional argument DISPLAY specifies which display to ask about.\n\
4061DISPLAY should be either a frame or a display name (a string).\n\
4062If omitted or nil, that stands for the selected frame's display.")
4063 (display)
4064 Lisp_Object display;
4065{
4066 return make_number (1);
4067}
4068
4069DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
4070 "Returns the height in millimeters of the X display DISPLAY.\n\
4071The optional argument DISPLAY specifies which display to ask about.\n\
4072DISPLAY should be either a frame or a display name (a string).\n\
4073If omitted or nil, that stands for the selected frame's display.")
4074 (display)
4075 Lisp_Object display;
4076{
4077 /* MAC_TODO: this is an approximation, and only of the main display */
4078
4079 struct mac_display_info *dpyinfo = check_x_display_info (display);
4080 short h, v;
4081
4082 ScreenRes (&h, &v);
4083
4084 return make_number ((int) (v / 72.0 * 25.4));
4085}
4086
4087DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4088 "Returns the width in millimeters of the X display DISPLAY.\n\
4089The optional argument DISPLAY specifies which display to ask about.\n\
4090DISPLAY should be either a frame or a display name (a string).\n\
4091If omitted or nil, that stands for the selected frame's display.")
4092 (display)
4093 Lisp_Object display;
4094{
4095 /* MAC_TODO: this is an approximation, and only of the main display */
4096
4097 struct mac_display_info *dpyinfo = check_x_display_info (display);
4098 short h, v;
4099
4100 ScreenRes (&h, &v);
4101
4102 return make_number ((int) (h / 72.0 * 25.4));
4103}
4104
4105DEFUN ("x-display-backing-store", Fx_display_backing_store,
4106 Sx_display_backing_store, 0, 1, 0,
4107 "Returns an indication of whether display DISPLAY does backing store.\n\
4108The value may be `always', `when-mapped', or `not-useful'.\n\
4109The optional argument DISPLAY specifies which display to ask about.\n\
4110DISPLAY should be either a frame or a display name (a string).\n\
4111If omitted or nil, that stands for the selected frame's display.")
4112 (display)
4113 Lisp_Object display;
4114{
4115 return intern ("not-useful");
4116}
4117
4118DEFUN ("x-display-visual-class", Fx_display_visual_class,
4119 Sx_display_visual_class, 0, 1, 0,
4120 "Returns the visual class of the display DISPLAY.\n\
4121The value is one of the symbols `static-gray', `gray-scale',\n\
4122`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
4123The optional argument DISPLAY specifies which display to ask about.\n\
4124DISPLAY should be either a frame or a display name (a string).\n\
4125If omitted or nil, that stands for the selected frame's display.")
4126 (display)
4127 Lisp_Object display;
4128{
4129 struct mac_display_info *dpyinfo = check_x_display_info (display);
4130
4131#if 0
4132 switch (dpyinfo->visual->class)
4133 {
4134 case StaticGray: return (intern ("static-gray"));
4135 case GrayScale: return (intern ("gray-scale"));
4136 case StaticColor: return (intern ("static-color"));
4137 case PseudoColor: return (intern ("pseudo-color"));
4138 case TrueColor: return (intern ("true-color"));
4139 case DirectColor: return (intern ("direct-color"));
4140 default:
4141 error ("Display has an unknown visual class");
4142 }
4143#endif
4144
4145 error ("Display has an unknown visual class");
4146}
4147
4148DEFUN ("x-display-save-under", Fx_display_save_under,
4149 Sx_display_save_under, 0, 1, 0,
4150 "Returns t if the display DISPLAY supports the save-under feature.\n\
4151The optional argument DISPLAY specifies which display to ask about.\n\
4152DISPLAY should be either a frame or a display name (a string).\n\
4153If omitted or nil, that stands for the selected frame's display.")
4154 (display)
4155 Lisp_Object display;
4156{
4157 return Qnil;
4158}
4159
4160int
4161x_pixel_width (f)
4162 register struct frame *f;
4163{
4164 return PIXEL_WIDTH (f);
4165}
4166
4167int
4168x_pixel_height (f)
4169 register struct frame *f;
4170{
4171 return PIXEL_HEIGHT (f);
4172}
4173
4174int
4175x_char_width (f)
4176 register struct frame *f;
4177{
4178 return FONT_WIDTH (f->output_data.mac->font);
4179}
4180
4181int
4182x_char_height (f)
4183 register struct frame *f;
4184{
4185 return f->output_data.mac->line_height;
4186}
4187
4188int
4189x_screen_planes (f)
4190 register struct frame *f;
4191{
4192 return FRAME_MAC_DISPLAY_INFO (f)->n_planes;
4193}
4194
4195/* Return the display structure for the display named NAME.
4196 Open a new connection if necessary. */
4197
4198struct mac_display_info *
4199x_display_info_for_name (name)
4200 Lisp_Object name;
4201{
4202 Lisp_Object names;
4203 struct mac_display_info *dpyinfo;
4204
4205 CHECK_STRING (name, 0);
4206
4207 for (dpyinfo = &one_mac_display_info, names = x_display_name_list;
4208 dpyinfo;
4209 dpyinfo = dpyinfo->next, names = XCDR (names))
4210 {
4211 Lisp_Object tem;
4212 tem = Fstring_equal (XCAR (XCAR (names)), name);
4213 if (!NILP (tem))
4214 return dpyinfo;
4215 }
4216
4217 /* Use this general default value to start with. */
4218 Vx_resource_name = Vinvocation_name;
4219
4220 validate_x_resource_name ();
4221
4222 dpyinfo = x_term_init (name, (unsigned char *) 0,
4223 (char *) XSTRING (Vx_resource_name)->data);
4224
4225 if (dpyinfo == 0)
4226 error ("Cannot connect to server %s", XSTRING (name)->data);
4227
4228 mac_in_use = 1;
4229 XSETFASTINT (Vwindow_system_version, 3);
4230
4231 return dpyinfo;
4232}
4233
4234#if 0 /* MAC_TODO: implement network support */
4235DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
4236 1, 3, 0, "Open a connection to a server.\n\
4237DISPLAY is the name of the display to connect to.\n\
4238Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
4239If the optional third arg MUST-SUCCEED is non-nil,\n\
4240terminate Emacs if we can't open the connection.")
4241 (display, xrm_string, must_succeed)
4242 Lisp_Object display, xrm_string, must_succeed;
4243{
4244 unsigned char *xrm_option;
4245 struct mac_display_info *dpyinfo;
4246
4247 CHECK_STRING (display, 0);
4248 if (! NILP (xrm_string))
4249 CHECK_STRING (xrm_string, 1);
4250
4251 if (! EQ (Vwindow_system, intern ("mac")))
4252 error ("Not using Mac OS");
4253
4254 if (! NILP (xrm_string))
4255 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
4256 else
4257 xrm_option = (unsigned char *) 0;
4258
4259 validate_x_resource_name ();
4260
4261 /* This is what opens the connection and sets x_current_display.
4262 This also initializes many symbols, such as those used for input. */
4263 dpyinfo = mac_term_init (display, xrm_option,
4264 (char *) XSTRING (Vx_resource_name)->data);
4265
4266 if (dpyinfo == 0)
4267 {
4268 if (!NILP (must_succeed))
4269 fatal ("Cannot connect to server %s.\n",
4270 XSTRING (display)->data);
4271 else
4272 error ("Cannot connect to server %s", XSTRING (display)->data);
4273 }
4274
4275 mac_in_use = 1;
4276
4277 XSETFASTINT (Vwindow_system_version, 3);
4278 return Qnil;
4279}
4280
4281DEFUN ("x-close-connection", Fx_close_connection,
4282 Sx_close_connection, 1, 1, 0,
4283 "Close the connection to DISPLAY's server.\n\
4284For DISPLAY, specify either a frame or a display name (a string).\n\
4285If DISPLAY is nil, that stands for the selected frame's display.")
4286 (display)
4287 Lisp_Object display;
4288{
4289 struct mac_display_info *dpyinfo = check_x_display_info (display);
4290 int i;
4291
4292 if (dpyinfo->reference_count > 0)
4293 error ("Display still has frames on it");
4294
4295 BLOCK_INPUT;
4296 /* Free the fonts in the font table. */
4297 for (i = 0; i < dpyinfo->n_fonts; i++)
4298 if (dpyinfo->font_table[i].name)
4299 {
4300 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
4301 xfree (dpyinfo->font_table[i].full_name);
4302 xfree (dpyinfo->font_table[i].name);
4303 x_unload_font (dpyinfo, dpyinfo->font_table[i].font);
4304 }
4305 x_destroy_all_bitmaps (dpyinfo);
4306
4307 x_delete_display (dpyinfo);
4308 UNBLOCK_INPUT;
4309
4310 return Qnil;
4311}
4312#endif
4313
4314DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
4315 "Return the list of display names that Emacs has connections to.")
4316 ()
4317{
4318 Lisp_Object tail, result;
4319
4320 result = Qnil;
4321 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
4322 result = Fcons (XCAR (XCAR (tail)), result);
4323
4324 return result;
4325}
4326
4327DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
4328 "If ON is non-nil, report errors as soon as the erring request is made.\n\
4329If ON is nil, allow buffering of requests.\n\
4330This is a noop on W32 systems.\n\
4331The optional second argument DISPLAY specifies which display to act on.\n\
4332DISPLAY should be either a frame or a display name (a string).\n\
4333If DISPLAY is omitted or nil, that stands for the selected frame's display.")
4334 (on, display)
4335 Lisp_Object display, on;
4336{
4337 return Qnil;
4338}
4339
4340
4341/***********************************************************************
4342 Image types
4343 ***********************************************************************/
4344
4345/* Value is the number of elements of vector VECTOR. */
4346
4347#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
4348
4349/* List of supported image types. Use define_image_type to add new
4350 types. Use lookup_image_type to find a type for a given symbol. */
4351
4352static struct image_type *image_types;
4353
4354/* The symbol `image' which is the car of the lists used to represent
4355 images in Lisp. */
4356
4357extern Lisp_Object Qimage;
4358
4359/* The symbol `xbm' which is used as the type symbol for XBM images. */
4360
4361Lisp_Object Qxbm;
4362
4363/* Keywords. */
4364
4365extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
4366extern Lisp_Object QCdata;
4367Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
4368Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
4369Lisp_Object QCindex;
4370
4371/* Other symbols. */
4372
4373Lisp_Object Qlaplace;
4374
4375/* Time in seconds after which images should be removed from the cache
4376 if not displayed. */
4377
4378Lisp_Object Vimage_cache_eviction_delay;
4379
4380/* Function prototypes. */
4381
4382static void define_image_type P_ ((struct image_type *type));
4383static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
4384static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
4385static void x_laplace P_ ((struct frame *, struct image *));
4386static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
4387 Lisp_Object));
4388
4389
4390/* Define a new image type from TYPE. This adds a copy of TYPE to
4391 image_types and adds the symbol *TYPE->type to Vimage_types. */
4392
4393static void
4394define_image_type (type)
4395 struct image_type *type;
4396{
4397 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
4398 The initialized data segment is read-only. */
4399 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
4400 bcopy (type, p, sizeof *p);
4401 p->next = image_types;
4402 image_types = p;
4403 Vimage_types = Fcons (*p->type, Vimage_types);
4404}
4405
4406
4407/* Look up image type SYMBOL, and return a pointer to its image_type
4408 structure. Value is null if SYMBOL is not a known image type. */
4409
4410static INLINE struct image_type *
4411lookup_image_type (symbol)
4412 Lisp_Object symbol;
4413{
4414 struct image_type *type;
4415
4416 for (type = image_types; type; type = type->next)
4417 if (EQ (symbol, *type->type))
4418 break;
4419
4420 return type;
4421}
4422
4423
4424/* Value is non-zero if OBJECT is a valid Lisp image specification. A
4425 valid image specification is a list whose car is the symbol
4426 `image', and whose rest is a property list. The property list must
4427 contain a value for key `:type'. That value must be the name of a
4428 supported image type. The rest of the property list depends on the
4429 image type. */
4430
4431int
4432valid_image_p (object)
4433 Lisp_Object object;
4434{
4435 int valid_p = 0;
4436
4437 if (CONSP (object) && EQ (XCAR (object), Qimage))
4438 {
4439 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
4440 struct image_type *type = lookup_image_type (symbol);
4441
4442 if (type)
4443 valid_p = type->valid_p (object);
4444 }
4445
4446 return valid_p;
4447}
4448
4449
4450/* Log error message with format string FORMAT and argument ARG.
4451 Signaling an error, e.g. when an image cannot be loaded, is not a
4452 good idea because this would interrupt redisplay, and the error
4453 message display would lead to another redisplay. This function
4454 therefore simply displays a message. */
4455
4456static void
4457image_error (format, arg1, arg2)
4458 char *format;
4459 Lisp_Object arg1, arg2;
4460{
4461 add_to_log (format, arg1, arg2);
4462}
4463
4464
4465
4466/***********************************************************************
4467 Image specifications
4468 ***********************************************************************/
4469
4470enum image_value_type
4471{
4472 IMAGE_DONT_CHECK_VALUE_TYPE,
4473 IMAGE_STRING_VALUE,
4474 IMAGE_SYMBOL_VALUE,
4475 IMAGE_POSITIVE_INTEGER_VALUE,
4476 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
4477 IMAGE_ASCENT_VALUE,
4478 IMAGE_INTEGER_VALUE,
4479 IMAGE_FUNCTION_VALUE,
4480 IMAGE_NUMBER_VALUE,
4481 IMAGE_BOOL_VALUE
4482};
4483
4484/* Structure used when parsing image specifications. */
4485
4486struct image_keyword
4487{
4488 /* Name of keyword. */
4489 char *name;
4490
4491 /* The type of value allowed. */
4492 enum image_value_type type;
4493
4494 /* Non-zero means key must be present. */
4495 int mandatory_p;
4496
4497 /* Used to recognize duplicate keywords in a property list. */
4498 int count;
4499
4500 /* The value that was found. */
4501 Lisp_Object value;
4502};
4503
4504
4505static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
4506 int, Lisp_Object));
4507static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
4508
4509
4510/* Parse image spec SPEC according to KEYWORDS. A valid image spec
4511 has the format (image KEYWORD VALUE ...). One of the keyword/
4512 value pairs must be `:type TYPE'. KEYWORDS is a vector of
4513 image_keywords structures of size NKEYWORDS describing other
4514 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
4515
4516static int
4517parse_image_spec (spec, keywords, nkeywords, type)
4518 Lisp_Object spec;
4519 struct image_keyword *keywords;
4520 int nkeywords;
4521 Lisp_Object type;
4522{
4523 int i;
4524 Lisp_Object plist;
4525
4526 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
4527 return 0;
4528
4529 plist = XCDR (spec);
4530 while (CONSP (plist))
4531 {
4532 Lisp_Object key, value;
4533
4534 /* First element of a pair must be a symbol. */
4535 key = XCAR (plist);
4536 plist = XCDR (plist);
4537 if (!SYMBOLP (key))
4538 return 0;
4539
4540 /* There must follow a value. */
4541 if (!CONSP (plist))
4542 return 0;
4543 value = XCAR (plist);
4544 plist = XCDR (plist);
4545
4546 /* Find key in KEYWORDS. Error if not found. */
4547 for (i = 0; i < nkeywords; ++i)
4548 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
4549 break;
4550
4551 if (i == nkeywords)
4552 continue;
4553
4554 /* Record that we recognized the keyword. If a keywords
4555 was found more than once, it's an error. */
4556 keywords[i].value = value;
4557 ++keywords[i].count;
4558
4559 if (keywords[i].count > 1)
4560 return 0;
4561
4562 /* Check type of value against allowed type. */
4563 switch (keywords[i].type)
4564 {
4565 case IMAGE_STRING_VALUE:
4566 if (!STRINGP (value))
4567 return 0;
4568 break;
4569
4570 case IMAGE_SYMBOL_VALUE:
4571 if (!SYMBOLP (value))
4572 return 0;
4573 break;
4574
4575 case IMAGE_POSITIVE_INTEGER_VALUE:
4576 if (!INTEGERP (value) || XINT (value) <= 0)
4577 return 0;
4578 break;
4579
4580 case IMAGE_ASCENT_VALUE:
4581 if (SYMBOLP (value) && EQ (value, Qcenter))
4582 break;
4583 else if (INTEGERP (value)
4584 && XINT (value) >= 0
4585 && XINT (value) <= 100)
4586 break;
4587 return 0;
4588
4589 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
4590 if (!INTEGERP (value) || XINT (value) < 0)
4591 return 0;
4592 break;
4593
4594 case IMAGE_DONT_CHECK_VALUE_TYPE:
4595 break;
4596
4597 case IMAGE_FUNCTION_VALUE:
4598 value = indirect_function (value);
4599 if (SUBRP (value)
4600 || COMPILEDP (value)
4601 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
4602 break;
4603 return 0;
4604
4605 case IMAGE_NUMBER_VALUE:
4606 if (!INTEGERP (value) && !FLOATP (value))
4607 return 0;
4608 break;
4609
4610 case IMAGE_INTEGER_VALUE:
4611 if (!INTEGERP (value))
4612 return 0;
4613 break;
4614
4615 case IMAGE_BOOL_VALUE:
4616 if (!NILP (value) && !EQ (value, Qt))
4617 return 0;
4618 break;
4619
4620 default:
4621 abort ();
4622 break;
4623 }
4624
4625 if (EQ (key, QCtype) && !EQ (type, value))
4626 return 0;
4627 }
4628
4629 /* Check that all mandatory fields are present. */
4630 for (i = 0; i < nkeywords; ++i)
4631 if (keywords[i].mandatory_p && keywords[i].count == 0)
4632 return 0;
4633
4634 return NILP (plist);
4635}
4636
4637
4638/* Return the value of KEY in image specification SPEC. Value is nil
4639 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
4640 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
4641
4642static Lisp_Object
4643image_spec_value (spec, key, found)
4644 Lisp_Object spec, key;
4645 int *found;
4646{
4647 Lisp_Object tail;
4648
4649 xassert (valid_image_p (spec));
4650
4651 for (tail = XCDR (spec);
4652 CONSP (tail) && CONSP (XCDR (tail));
4653 tail = XCDR (XCDR (tail)))
4654 {
4655 if (EQ (XCAR (tail), key))
4656 {
4657 if (found)
4658 *found = 1;
4659 return XCAR (XCDR (tail));
4660 }
4661 }
4662
4663 if (found)
4664 *found = 0;
4665 return Qnil;
4666}
4667
4668
4669
4670
4671/***********************************************************************
4672 Image type independent image structures
4673 ***********************************************************************/
4674
4675static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
4676static void free_image P_ ((struct frame *f, struct image *img));
4677
4678
4679/* Allocate and return a new image structure for image specification
4680 SPEC. SPEC has a hash value of HASH. */
4681
4682static struct image *
4683make_image (spec, hash)
4684 Lisp_Object spec;
4685 unsigned hash;
4686{
4687 struct image *img = (struct image *) xmalloc (sizeof *img);
4688
4689 xassert (valid_image_p (spec));
4690 bzero (img, sizeof *img);
4691 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
4692 xassert (img->type != NULL);
4693 img->spec = spec;
4694 img->data.lisp_val = Qnil;
4695 img->ascent = DEFAULT_IMAGE_ASCENT;
4696 img->hash = hash;
4697 return img;
4698}
4699
4700
4701/* Free image IMG which was used on frame F, including its resources. */
4702
4703static void
4704free_image (f, img)
4705 struct frame *f;
4706 struct image *img;
4707{
4708 if (img)
4709 {
4710 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4711
4712 /* Remove IMG from the hash table of its cache. */
4713 if (img->prev)
4714 img->prev->next = img->next;
4715 else
4716 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
4717
4718 if (img->next)
4719 img->next->prev = img->prev;
4720
4721 c->images[img->id] = NULL;
4722
4723 /* Free resources, then free IMG. */
4724 img->type->free (f, img);
4725 xfree (img);
4726 }
4727}
4728
4729
4730/* Prepare image IMG for display on frame F. Must be called before
4731 drawing an image. */
4732
4733void
4734prepare_image_for_display (f, img)
4735 struct frame *f;
4736 struct image *img;
4737{
4738 EMACS_TIME t;
4739
4740 /* We're about to display IMG, so set its timestamp to `now'. */
4741 EMACS_GET_TIME (t);
4742 img->timestamp = EMACS_SECS (t);
4743
4744 /* If IMG doesn't have a pixmap yet, load it now, using the image
4745 type dependent loader function. */
4746 if (img->pixmap == 0 && !img->load_failed_p)
4747 img->load_failed_p = img->type->load (f, img) == 0;
4748}
4749
4750
4751/* Value is the number of pixels for the ascent of image IMG when
4752 drawn in face FACE. */
4753
4754int
4755image_ascent (img, face)
4756 struct image *img;
4757 struct face *face;
4758{
4759 int height = img->height + img->margin;
4760 int ascent;
4761
4762 if (img->ascent == CENTERED_IMAGE_ASCENT)
4763 {
4764 if (face->font)
4765 ascent = height / 2 - (FONT_DESCENT(face->font)
4766 - FONT_BASE(face->font)) / 2;
4767 else
4768 ascent = height / 2;
4769 }
4770 else
4771 ascent = height * img->ascent / 100.0;
4772
4773 return ascent;
4774}
4775
4776
4777
4778/***********************************************************************
4779 Helper functions for X image types
4780 ***********************************************************************/
4781
4782static void x_clear_image P_ ((struct frame *f, struct image *img));
4783static unsigned long x_alloc_image_color P_ ((struct frame *f,
4784 struct image *img,
4785 Lisp_Object color_name,
4786 unsigned long dflt));
4787
4788/* Free X resources of image IMG which is used on frame F. */
4789
4790static void
4791x_clear_image (f, img)
4792 struct frame *f;
4793 struct image *img;
4794{
4795#if 0 /* MAC_TODO: W32 image support */
4796
4797 if (img->pixmap)
4798 {
4799 BLOCK_INPUT;
4800 XFreePixmap (NULL, img->pixmap);
4801 img->pixmap = 0;
4802 UNBLOCK_INPUT;
4803 }
4804
4805 if (img->ncolors)
4806 {
4807 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
4808
4809 /* If display has an immutable color map, freeing colors is not
4810 necessary and some servers don't allow it. So don't do it. */
4811 if (class != StaticColor
4812 && class != StaticGray
4813 && class != TrueColor)
4814 {
4815 Colormap cmap;
4816 BLOCK_INPUT;
4817 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
4818 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
4819 img->ncolors, 0);
4820 UNBLOCK_INPUT;
4821 }
4822
4823 xfree (img->colors);
4824 img->colors = NULL;
4825 img->ncolors = 0;
4826 }
4827#endif
4828}
4829
4830
4831/* Allocate color COLOR_NAME for image IMG on frame F. If color
4832 cannot be allocated, use DFLT. Add a newly allocated color to
4833 IMG->colors, so that it can be freed again. Value is the pixel
4834 color. */
4835
4836static unsigned long
4837x_alloc_image_color (f, img, color_name, dflt)
4838 struct frame *f;
4839 struct image *img;
4840 Lisp_Object color_name;
4841 unsigned long dflt;
4842{
4843#if 0 /* MAC_TODO: allocing colors. */
4844 XColor color;
4845 unsigned long result;
4846
4847 xassert (STRINGP (color_name));
4848
4849 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
4850 {
4851 /* This isn't called frequently so we get away with simply
4852 reallocating the color vector to the needed size, here. */
4853 ++img->ncolors;
4854 img->colors =
4855 (unsigned long *) xrealloc (img->colors,
4856 img->ncolors * sizeof *img->colors);
4857 img->colors[img->ncolors - 1] = color.pixel;
4858 result = color.pixel;
4859 }
4860 else
4861 result = dflt;
4862 return result;
4863#endif
4864 return 0;
4865}
4866
4867
4868
4869/***********************************************************************
4870 Image Cache
4871 ***********************************************************************/
4872
4873static void cache_image P_ ((struct frame *f, struct image *img));
4874
4875
4876/* Return a new, initialized image cache that is allocated from the
4877 heap. Call free_image_cache to free an image cache. */
4878
4879struct image_cache *
4880make_image_cache ()
4881{
4882 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
4883 int size;
4884
4885 bzero (c, sizeof *c);
4886 c->size = 50;
4887 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
4888 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
4889 c->buckets = (struct image **) xmalloc (size);
4890 bzero (c->buckets, size);
4891 return c;
4892}
4893
4894
4895/* Free image cache of frame F. Be aware that X frames share images
4896 caches. */
4897
4898void
4899free_image_cache (f)
4900 struct frame *f;
4901{
4902 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4903 if (c)
4904 {
4905 int i;
4906
4907 /* Cache should not be referenced by any frame when freed. */
4908 xassert (c->refcount == 0);
4909
4910 for (i = 0; i < c->used; ++i)
4911 free_image (f, c->images[i]);
4912 xfree (c->images);
4913 xfree (c);
4914 xfree (c->buckets);
4915 FRAME_X_IMAGE_CACHE (f) = NULL;
4916 }
4917}
4918
4919
4920/* Clear image cache of frame F. FORCE_P non-zero means free all
4921 images. FORCE_P zero means clear only images that haven't been
4922 displayed for some time. Should be called from time to time to
4923 reduce the number of loaded images. If image-eviction-seconds is
4924 non-nil, this frees images in the cache which weren't displayed for
4925 at least that many seconds. */
4926
4927void
4928clear_image_cache (f, force_p)
4929 struct frame *f;
4930 int force_p;
4931{
4932 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4933
4934 if (c && INTEGERP (Vimage_cache_eviction_delay))
4935 {
4936 EMACS_TIME t;
4937 unsigned long old;
4938 int i, any_freed_p = 0;
4939
4940 EMACS_GET_TIME (t);
4941 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
4942
4943 for (i = 0; i < c->used; ++i)
4944 {
4945 struct image *img = c->images[i];
4946 if (img != NULL
4947 && (force_p
4948 || (img->timestamp > old)))
4949 {
4950 free_image (f, img);
4951 any_freed_p = 1;
4952 }
4953 }
4954
4955 /* We may be clearing the image cache because, for example,
4956 Emacs was iconified for a longer period of time. In that
4957 case, current matrices may still contain references to
4958 images freed above. So, clear these matrices. */
4959 if (any_freed_p)
4960 {
4961 clear_current_matrices (f);
4962 ++windows_or_buffers_changed;
4963 }
4964 }
4965}
4966
4967
4968DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
4969 0, 1, 0,
4970 "Clear the image cache of FRAME.\n\
4971FRAME nil or omitted means use the selected frame.\n\
4972FRAME t means clear the image caches of all frames.")
4973 (frame)
4974 Lisp_Object frame;
4975{
4976 if (EQ (frame, Qt))
4977 {
4978 Lisp_Object tail;
4979
4980 FOR_EACH_FRAME (tail, frame)
4981 if (FRAME_MAC_P (XFRAME (frame)))
4982 clear_image_cache (XFRAME (frame), 1);
4983 }
4984 else
4985 clear_image_cache (check_x_frame (frame), 1);
4986
4987 return Qnil;
4988}
4989
4990
4991/* Return the id of image with Lisp specification SPEC on frame F.
4992 SPEC must be a valid Lisp image specification (see valid_image_p). */
4993
4994int
4995lookup_image (f, spec)
4996 struct frame *f;
4997 Lisp_Object spec;
4998{
4999 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5000 struct image *img;
5001 int i;
5002 unsigned hash;
5003 struct gcpro gcpro1;
5004 EMACS_TIME now;
5005
5006 /* F must be a window-system frame, and SPEC must be a valid image
5007 specification. */
5008 xassert (FRAME_WINDOW_P (f));
5009 xassert (valid_image_p (spec));
5010
5011 GCPRO1 (spec);
5012
5013 /* Look up SPEC in the hash table of the image cache. */
5014 hash = sxhash (spec, 0);
5015 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
5016
5017 for (img = c->buckets[i]; img; img = img->next)
5018 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
5019 break;
5020
5021 /* If not found, create a new image and cache it. */
5022 if (img == NULL)
5023 {
5024 img = make_image (spec, hash);
5025 cache_image (f, img);
5026 img->load_failed_p = img->type->load (f, img) == 0;
5027 xassert (!interrupt_input_blocked);
5028
5029 /* If we can't load the image, and we don't have a width and
5030 height, use some arbitrary width and height so that we can
5031 draw a rectangle for it. */
5032 if (img->load_failed_p)
5033 {
5034 Lisp_Object value;
5035
5036 value = image_spec_value (spec, QCwidth, NULL);
5037 img->width = (INTEGERP (value)
5038 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
5039 value = image_spec_value (spec, QCheight, NULL);
5040 img->height = (INTEGERP (value)
5041 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
5042 }
5043 else
5044 {
5045 /* Handle image type independent image attributes
5046 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
5047 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
5048 Lisp_Object file;
5049
5050 ascent = image_spec_value (spec, QCascent, NULL);
5051 if (INTEGERP (ascent))
5052 img->ascent = XFASTINT (ascent);
5053 else if (EQ (ascent, Qcenter))
5054 img->ascent = CENTERED_IMAGE_ASCENT;
5055
5056 margin = image_spec_value (spec, QCmargin, NULL);
5057 if (INTEGERP (margin) && XINT (margin) >= 0)
5058 img->margin = XFASTINT (margin);
5059
5060 relief = image_spec_value (spec, QCrelief, NULL);
5061 if (INTEGERP (relief))
5062 {
5063 img->relief = XINT (relief);
5064 img->margin += abs (img->relief);
5065 }
5066
5067 /* Should we apply a Laplace edge-detection algorithm? */
5068 algorithm = image_spec_value (spec, QCalgorithm, NULL);
5069 if (img->pixmap && EQ (algorithm, Qlaplace))
5070 x_laplace (f, img);
5071
5072 /* Should we built a mask heuristically? */
5073 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
5074 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
5075 x_build_heuristic_mask (f, img, heuristic_mask);
5076 }
5077 }
5078
5079 /* We're using IMG, so set its timestamp to `now'. */
5080 EMACS_GET_TIME (now);
5081 img->timestamp = EMACS_SECS (now);
5082
5083 UNGCPRO;
5084
5085 /* Value is the image id. */
5086 return img->id;
5087}
5088
5089
5090/* Cache image IMG in the image cache of frame F. */
5091
5092static void
5093cache_image (f, img)
5094 struct frame *f;
5095 struct image *img;
5096{
5097 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5098 int i;
5099
5100 /* Find a free slot in c->images. */
5101 for (i = 0; i < c->used; ++i)
5102 if (c->images[i] == NULL)
5103 break;
5104
5105 /* If no free slot found, maybe enlarge c->images. */
5106 if (i == c->used && c->used == c->size)
5107 {
5108 c->size *= 2;
5109 c->images = (struct image **) xrealloc (c->images,
5110 c->size * sizeof *c->images);
5111 }
5112
5113 /* Add IMG to c->images, and assign IMG an id. */
5114 c->images[i] = img;
5115 img->id = i;
5116 if (i == c->used)
5117 ++c->used;
5118
5119 /* Add IMG to the cache's hash table. */
5120 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
5121 img->next = c->buckets[i];
5122 if (img->next)
5123 img->next->prev = img;
5124 img->prev = NULL;
5125 c->buckets[i] = img;
5126}
5127
5128
5129/* Call FN on every image in the image cache of frame F. Used to mark
5130 Lisp Objects in the image cache. */
5131
5132void
5133forall_images_in_image_cache (f, fn)
5134 struct frame *f;
5135 void (*fn) P_ ((struct image *img));
5136{
5137 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f))
5138 {
5139 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5140 if (c)
5141 {
5142 int i;
5143 for (i = 0; i < c->used; ++i)
5144 if (c->images[i])
5145 fn (c->images[i]);
5146 }
5147 }
5148}
5149
5150
5151
5152/***********************************************************************
5153 Mac support code
5154 ***********************************************************************/
5155
5156#if 0 /* MAC_TODO: Mac specific image code. */
5157
5158static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
5159 XImage **, Pixmap *));
5160static void x_destroy_x_image P_ ((XImage *));
5161static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
5162
5163
5164/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
5165 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
5166 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
5167 via xmalloc. Print error messages via image_error if an error
5168 occurs. Value is non-zero if successful. */
5169
5170static int
5171x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
5172 struct frame *f;
5173 int width, height, depth;
5174 XImage **ximg;
5175 Pixmap *pixmap;
5176{
5177#if 0 /* MAC_TODO: Image support for Mac */
5178 Display *display = FRAME_W32_DISPLAY (f);
5179 Screen *screen = FRAME_X_SCREEN (f);
5180 Window window = FRAME_W32_WINDOW (f);
5181
5182 xassert (interrupt_input_blocked);
5183
5184 if (depth <= 0)
5185 depth = DefaultDepthOfScreen (screen);
5186 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
5187 depth, ZPixmap, 0, NULL, width, height,
5188 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
5189 if (*ximg == NULL)
5190 {
5191 image_error ("Unable to allocate X image", Qnil, Qnil);
5192 return 0;
5193 }
5194
5195 /* Allocate image raster. */
5196 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
5197
5198 /* Allocate a pixmap of the same size. */
5199 *pixmap = XCreatePixmap (display, window, width, height, depth);
5200 if (*pixmap == 0)
5201 {
5202 x_destroy_x_image (*ximg);
5203 *ximg = NULL;
5204 image_error ("Unable to create X pixmap", Qnil, Qnil);
5205 return 0;
5206 }
5207#endif
5208 return 1;
5209}
5210
5211
5212/* Destroy XImage XIMG. Free XIMG->data. */
5213
5214static void
5215x_destroy_x_image (ximg)
5216 XImage *ximg;
5217{
5218 xassert (interrupt_input_blocked);
5219 if (ximg)
5220 {
5221 xfree (ximg->data);
5222 ximg->data = NULL;
5223 XDestroyImage (ximg);
5224 }
5225}
5226
5227
5228/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
5229 are width and height of both the image and pixmap. */
5230
5231static void
5232x_put_x_image (f, ximg, pixmap, width, height)
5233 struct frame *f;
5234 XImage *ximg;
5235 Pixmap pixmap;
5236{
5237 GC gc;
5238
5239 xassert (interrupt_input_blocked);
5240 gc = XCreateGC (NULL, pixmap, 0, NULL);
5241 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
5242 XFreeGC (NULL, gc);
5243}
5244
5245#endif
5246
5247
5248/***********************************************************************
5249 Searching files
5250 ***********************************************************************/
5251
5252static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5253
5254/* Find image file FILE. Look in data-directory, then
5255 x-bitmap-file-path. Value is the full name of the file found, or
5256 nil if not found. */
5257
5258static Lisp_Object
5259x_find_image_file (file)
5260 Lisp_Object file;
5261{
5262 Lisp_Object file_found, search_path;
5263 struct gcpro gcpro1, gcpro2;
5264 int fd;
5265
5266 file_found = Qnil;
5267 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
5268 GCPRO2 (file_found, search_path);
5269
5270 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
5271 fd = openp (search_path, file, "", &file_found, 0);
5272
5273 if (fd < 0)
5274 file_found = Qnil;
5275 else
5276 close (fd);
5277
5278 UNGCPRO;
5279 return file_found;
5280}
5281
5282
5283/***********************************************************************
5284 XBM images
5285 ***********************************************************************/
5286
5287static int xbm_load P_ ((struct frame *f, struct image *img));
5288static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
5289 Lisp_Object file));
5290static int xbm_image_p P_ ((Lisp_Object object));
5291static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
5292 unsigned char **));
5293
5294
5295/* Indices of image specification fields in xbm_format, below. */
5296
5297enum xbm_keyword_index
5298{
5299 XBM_TYPE,
5300 XBM_FILE,
5301 XBM_WIDTH,
5302 XBM_HEIGHT,
5303 XBM_DATA,
5304 XBM_FOREGROUND,
5305 XBM_BACKGROUND,
5306 XBM_ASCENT,
5307 XBM_MARGIN,
5308 XBM_RELIEF,
5309 XBM_ALGORITHM,
5310 XBM_HEURISTIC_MASK,
5311 XBM_LAST
5312};
5313
5314/* Vector of image_keyword structures describing the format
5315 of valid XBM image specifications. */
5316
5317static struct image_keyword xbm_format[XBM_LAST] =
5318{
5319 {":type", IMAGE_SYMBOL_VALUE, 1},
5320 {":file", IMAGE_STRING_VALUE, 0},
5321 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5322 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5323 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5324 {":foreground", IMAGE_STRING_VALUE, 0},
5325 {":background", IMAGE_STRING_VALUE, 0},
5326 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
5327 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5328 {":relief", IMAGE_INTEGER_VALUE, 0},
5329 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5330 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
5331};
5332
5333/* Structure describing the image type XBM. */
5334
5335static struct image_type xbm_type =
5336{
5337 &Qxbm,
5338 xbm_image_p,
5339 xbm_load,
5340 x_clear_image,
5341 NULL
5342};
5343
5344/* Tokens returned from xbm_scan. */
5345
5346enum xbm_token
5347{
5348 XBM_TK_IDENT = 256,
5349 XBM_TK_NUMBER
5350};
5351
5352
5353/* Return non-zero if OBJECT is a valid XBM-type image specification.
5354 A valid specification is a list starting with the symbol `image'
5355 The rest of the list is a property list which must contain an
5356 entry `:type xbm..
5357
5358 If the specification specifies a file to load, it must contain
5359 an entry `:file FILENAME' where FILENAME is a string.
5360
5361 If the specification is for a bitmap loaded from memory it must
5362 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
5363 WIDTH and HEIGHT are integers > 0. DATA may be:
5364
5365 1. a string large enough to hold the bitmap data, i.e. it must
5366 have a size >= (WIDTH + 7) / 8 * HEIGHT
5367
5368 2. a bool-vector of size >= WIDTH * HEIGHT
5369
5370 3. a vector of strings or bool-vectors, one for each line of the
5371 bitmap.
5372
5373 Both the file and data forms may contain the additional entries
5374 `:background COLOR' and `:foreground COLOR'. If not present,
5375 foreground and background of the frame on which the image is
5376 displayed, is used. */
5377
5378static int
5379xbm_image_p (object)
5380 Lisp_Object object;
5381{
5382 struct image_keyword kw[XBM_LAST];
5383
5384 bcopy (xbm_format, kw, sizeof kw);
5385 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
5386 return 0;
5387
5388 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
5389
5390 if (kw[XBM_FILE].count)
5391 {
5392 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
5393 return 0;
5394 }
5395 else
5396 {
5397 Lisp_Object data;
5398 int width, height;
5399
5400 /* Entries for `:width', `:height' and `:data' must be present. */
5401 if (!kw[XBM_WIDTH].count
5402 || !kw[XBM_HEIGHT].count
5403 || !kw[XBM_DATA].count)
5404 return 0;
5405
5406 data = kw[XBM_DATA].value;
5407 width = XFASTINT (kw[XBM_WIDTH].value);
5408 height = XFASTINT (kw[XBM_HEIGHT].value);
5409
5410 /* Check type of data, and width and height against contents of
5411 data. */
5412 if (VECTORP (data))
5413 {
5414 int i;
5415
5416 /* Number of elements of the vector must be >= height. */
5417 if (XVECTOR (data)->size < height)
5418 return 0;
5419
5420 /* Each string or bool-vector in data must be large enough
5421 for one line of the image. */
5422 for (i = 0; i < height; ++i)
5423 {
5424 Lisp_Object elt = XVECTOR (data)->contents[i];
5425
5426 if (STRINGP (elt))
5427 {
5428 if (XSTRING (elt)->size
5429 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
5430 return 0;
5431 }
5432 else if (BOOL_VECTOR_P (elt))
5433 {
5434 if (XBOOL_VECTOR (elt)->size < width)
5435 return 0;
5436 }
5437 else
5438 return 0;
5439 }
5440 }
5441 else if (STRINGP (data))
5442 {
5443 if (XSTRING (data)->size
5444 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
5445 return 0;
5446 }
5447 else if (BOOL_VECTOR_P (data))
5448 {
5449 if (XBOOL_VECTOR (data)->size < width * height)
5450 return 0;
5451 }
5452 else
5453 return 0;
5454 }
5455
5456 /* Baseline must be a value between 0 and 100 (a percentage). */
5457 if (kw[XBM_ASCENT].count
5458 && XFASTINT (kw[XBM_ASCENT].value) > 100)
5459 return 0;
5460
5461 return 1;
5462}
5463
5464
5465/* Scan a bitmap file. FP is the stream to read from. Value is
5466 either an enumerator from enum xbm_token, or a character for a
5467 single-character token, or 0 at end of file. If scanning an
5468 identifier, store the lexeme of the identifier in SVAL. If
5469 scanning a number, store its value in *IVAL. */
5470
5471static int
5472xbm_scan (fp, sval, ival)
5473 FILE *fp;
5474 char *sval;
5475 int *ival;
5476{
5477 int c;
5478
5479 /* Skip white space. */
5480 while ((c = fgetc (fp)) != EOF && isspace (c))
5481 ;
5482
5483 if (c == EOF)
5484 c = 0;
5485 else if (isdigit (c))
5486 {
5487 int value = 0, digit;
5488
5489 if (c == '0')
5490 {
5491 c = fgetc (fp);
5492 if (c == 'x' || c == 'X')
5493 {
5494 while ((c = fgetc (fp)) != EOF)
5495 {
5496 if (isdigit (c))
5497 digit = c - '0';
5498 else if (c >= 'a' && c <= 'f')
5499 digit = c - 'a' + 10;
5500 else if (c >= 'A' && c <= 'F')
5501 digit = c - 'A' + 10;
5502 else
5503 break;
5504 value = 16 * value + digit;
5505 }
5506 }
5507 else if (isdigit (c))
5508 {
5509 value = c - '0';
5510 while ((c = fgetc (fp)) != EOF
5511 && isdigit (c))
5512 value = 8 * value + c - '0';
5513 }
5514 }
5515 else
5516 {
5517 value = c - '0';
5518 while ((c = fgetc (fp)) != EOF
5519 && isdigit (c))
5520 value = 10 * value + c - '0';
5521 }
5522
5523 if (c != EOF)
5524 ungetc (c, fp);
5525 *ival = value;
5526 c = XBM_TK_NUMBER;
5527 }
5528 else if (isalpha (c) || c == '_')
5529 {
5530 *sval++ = c;
5531 while ((c = fgetc (fp)) != EOF
5532 && (isalnum (c) || c == '_'))
5533 *sval++ = c;
5534 *sval = 0;
5535 if (c != EOF)
5536 ungetc (c, fp);
5537 c = XBM_TK_IDENT;
5538 }
5539
5540 return c;
5541}
5542
5543
5544/* Replacement for XReadBitmapFileData which isn't available under old
5545 X versions. FILE is the name of the bitmap file to read. Set
5546 *WIDTH and *HEIGHT to the width and height of the image. Return in
5547 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
5548 successful. */
5549
5550static int
5551xbm_read_bitmap_file_data (file, width, height, data)
5552 char *file;
5553 int *width, *height;
5554 unsigned char **data;
5555{
5556 FILE *fp;
5557 char buffer[BUFSIZ];
5558 int padding_p = 0;
5559 int v10 = 0;
5560 int bytes_per_line, i, nbytes;
5561 unsigned char *p;
5562 int value;
5563 int LA1;
5564
5565#define match() \
5566 LA1 = xbm_scan (fp, buffer, &value)
5567
5568#define expect(TOKEN) \
5569 if (LA1 != (TOKEN)) \
5570 goto failure; \
5571 else \
5572 match ()
5573
5574#define expect_ident(IDENT) \
5575 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
5576 match (); \
5577 else \
5578 goto failure
5579
5580 fp = fopen (file, "r");
5581 if (fp == NULL)
5582 return 0;
5583
5584 *width = *height = -1;
5585 *data = NULL;
5586 LA1 = xbm_scan (fp, buffer, &value);
5587
5588 /* Parse defines for width, height and hot-spots. */
5589 while (LA1 == '#')
5590 {
5591 match ();
5592 expect_ident ("define");
5593 expect (XBM_TK_IDENT);
5594
5595 if (LA1 == XBM_TK_NUMBER);
5596 {
5597 char *p = strrchr (buffer, '_');
5598 p = p ? p + 1 : buffer;
5599 if (strcmp (p, "width") == 0)
5600 *width = value;
5601 else if (strcmp (p, "height") == 0)
5602 *height = value;
5603 }
5604 expect (XBM_TK_NUMBER);
5605 }
5606
5607 if (*width < 0 || *height < 0)
5608 goto failure;
5609
5610 /* Parse bits. Must start with `static'. */
5611 expect_ident ("static");
5612 if (LA1 == XBM_TK_IDENT)
5613 {
5614 if (strcmp (buffer, "unsigned") == 0)
5615 {
5616 match ();
5617 expect_ident ("char");
5618 }
5619 else if (strcmp (buffer, "short") == 0)
5620 {
5621 match ();
5622 v10 = 1;
5623 if (*width % 16 && *width % 16 < 9)
5624 padding_p = 1;
5625 }
5626 else if (strcmp (buffer, "char") == 0)
5627 match ();
5628 else
5629 goto failure;
5630 }
5631 else
5632 goto failure;
5633
5634 expect (XBM_TK_IDENT);
5635 expect ('[');
5636 expect (']');
5637 expect ('=');
5638 expect ('{');
5639
5640 bytes_per_line = (*width + 7) / 8 + padding_p;
5641 nbytes = bytes_per_line * *height;
5642 p = *data = (char *) xmalloc (nbytes);
5643
5644 if (v10)
5645 {
5646
5647 for (i = 0; i < nbytes; i += 2)
5648 {
5649 int val = value;
5650 expect (XBM_TK_NUMBER);
5651
5652 *p++ = val;
5653 if (!padding_p || ((i + 2) % bytes_per_line))
5654 *p++ = value >> 8;
5655
5656 if (LA1 == ',' || LA1 == '}')
5657 match ();
5658 else
5659 goto failure;
5660 }
5661 }
5662 else
5663 {
5664 for (i = 0; i < nbytes; ++i)
5665 {
5666 int val = value;
5667 expect (XBM_TK_NUMBER);
5668
5669 *p++ = val;
5670
5671 if (LA1 == ',' || LA1 == '}')
5672 match ();
5673 else
5674 goto failure;
5675 }
5676 }
5677
5678 fclose (fp);
5679 return 1;
5680
5681 failure:
5682
5683 fclose (fp);
5684 if (*data)
5685 {
5686 xfree (*data);
5687 *data = NULL;
5688 }
5689 return 0;
5690
5691#undef match
5692#undef expect
5693#undef expect_ident
5694}
5695
5696
5697/* Load XBM image IMG which will be displayed on frame F from file
5698 SPECIFIED_FILE. Value is non-zero if successful. */
5699
5700static int
5701xbm_load_image_from_file (f, img, specified_file)
5702 struct frame *f;
5703 struct image *img;
5704 Lisp_Object specified_file;
5705{
5706 int rc;
5707 unsigned char *data;
5708 int success_p = 0;
5709 Lisp_Object file;
5710 struct gcpro gcpro1;
5711
5712 xassert (STRINGP (specified_file));
5713 file = Qnil;
5714 GCPRO1 (file);
5715
5716 file = x_find_image_file (specified_file);
5717 if (!STRINGP (file))
5718 {
5719 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5720 UNGCPRO;
5721 return 0;
5722 }
5723
5724 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
5725 &img->height, &data);
5726 if (rc)
5727 {
5728 int depth = one_mac_display_info.n_cbits;
5729 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5730 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5731 Lisp_Object value;
5732
5733 xassert (img->width > 0 && img->height > 0);
5734
5735 /* Get foreground and background colors, maybe allocate colors. */
5736 value = image_spec_value (img->spec, QCforeground, NULL);
5737 if (!NILP (value))
5738 foreground = x_alloc_image_color (f, img, value, foreground);
5739
5740 value = image_spec_value (img->spec, QCbackground, NULL);
5741 if (!NILP (value))
5742 background = x_alloc_image_color (f, img, value, background);
5743
5744#if 0 /* MAC_TODO : Port image display to Mac */
5745 BLOCK_INPUT;
5746 img->pixmap
5747 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
5748 FRAME_W32_WINDOW (f),
5749 data,
5750 img->width, img->height,
5751 foreground, background,
5752 depth);
5753 xfree (data);
5754
5755 if (img->pixmap == 0)
5756 {
5757 x_clear_image (f, img);
5758 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
5759 }
5760 else
5761 success_p = 1;
5762
5763 UNBLOCK_INPUT;
5764#endif
5765 }
5766 else
5767 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
5768
5769 UNGCPRO;
5770 return success_p;
5771}
5772
5773
5774/* Fill image IMG which is used on frame F with pixmap data. Value is
5775 non-zero if successful. */
5776
5777static int
5778xbm_load (f, img)
5779 struct frame *f;
5780 struct image *img;
5781{
5782 int success_p = 0;
5783 Lisp_Object file_name;
5784
5785 xassert (xbm_image_p (img->spec));
5786
5787 /* If IMG->spec specifies a file name, create a non-file spec from it. */
5788 file_name = image_spec_value (img->spec, QCfile, NULL);
5789 if (STRINGP (file_name))
5790 success_p = xbm_load_image_from_file (f, img, file_name);
5791 else
5792 {
5793 struct image_keyword fmt[XBM_LAST];
5794 Lisp_Object data;
5795 int depth;
5796 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5797 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5798 char *bits;
5799 int parsed_p;
5800
5801 /* Parse the list specification. */
5802 bcopy (xbm_format, fmt, sizeof fmt);
5803 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
5804 xassert (parsed_p);
5805
5806 /* Get specified width, and height. */
5807 img->width = XFASTINT (fmt[XBM_WIDTH].value);
5808 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
5809 xassert (img->width > 0 && img->height > 0);
5810
5811 BLOCK_INPUT;
5812
5813 if (fmt[XBM_ASCENT].count)
5814 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
5815
5816 /* Get foreground and background colors, maybe allocate colors. */
5817 if (fmt[XBM_FOREGROUND].count)
5818 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
5819 foreground);
5820 if (fmt[XBM_BACKGROUND].count)
5821 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
5822 background);
5823
5824 /* Set bits to the bitmap image data. */
5825 data = fmt[XBM_DATA].value;
5826 if (VECTORP (data))
5827 {
5828 int i;
5829 char *p;
5830 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
5831
5832 p = bits = (char *) alloca (nbytes * img->height);
5833 for (i = 0; i < img->height; ++i, p += nbytes)
5834 {
5835 Lisp_Object line = XVECTOR (data)->contents[i];
5836 if (STRINGP (line))
5837 bcopy (XSTRING (line)->data, p, nbytes);
5838 else
5839 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
5840 }
5841 }
5842 else if (STRINGP (data))
5843 bits = XSTRING (data)->data;
5844 else
5845 bits = XBOOL_VECTOR (data)->data;
5846
5847#if 0 /* MAC_TODO : port Mac display code */
5848 /* Create the pixmap. */
5849 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
5850 img->pixmap
5851 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
5852 FRAME_W32_WINDOW (f),
5853 bits,
5854 img->width, img->height,
5855 foreground, background,
5856 depth);
5857#endif /* MAC_TODO */
5858
5859 if (img->pixmap)
5860 success_p = 1;
5861 else
5862 {
5863 image_error ("Unable to create pixmap for XBM image `%s'",
5864 img->spec, Qnil);
5865 x_clear_image (f, img);
5866 }
5867
5868 UNBLOCK_INPUT;
5869 }
5870
5871 return success_p;
5872}
5873
5874
5875
5876/***********************************************************************
5877 XPM images
5878 ***********************************************************************/
5879
5880#if HAVE_XPM
5881
5882static int xpm_image_p P_ ((Lisp_Object object));
5883static int xpm_load P_ ((struct frame *f, struct image *img));
5884static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
5885
5886#include "X11/xpm.h"
5887
5888/* The symbol `xpm' identifying XPM-format images. */
5889
5890Lisp_Object Qxpm;
5891
5892/* Indices of image specification fields in xpm_format, below. */
5893
5894enum xpm_keyword_index
5895{
5896 XPM_TYPE,
5897 XPM_FILE,
5898 XPM_DATA,
5899 XPM_ASCENT,
5900 XPM_MARGIN,
5901 XPM_RELIEF,
5902 XPM_ALGORITHM,
5903 XPM_HEURISTIC_MASK,
5904 XPM_COLOR_SYMBOLS,
5905 XPM_LAST
5906};
5907
5908/* Vector of image_keyword structures describing the format
5909 of valid XPM image specifications. */
5910
5911static struct image_keyword xpm_format[XPM_LAST] =
5912{
5913 {":type", IMAGE_SYMBOL_VALUE, 1},
5914 {":file", IMAGE_STRING_VALUE, 0},
5915 {":data", IMAGE_STRING_VALUE, 0},
5916 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
5917 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5918 {":relief", IMAGE_INTEGER_VALUE, 0},
5919 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5920 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5921 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
5922};
5923
5924/* Structure describing the image type XBM. */
5925
5926static struct image_type xpm_type =
5927{
5928 &Qxpm,
5929 xpm_image_p,
5930 xpm_load,
5931 x_clear_image,
5932 NULL
5933};
5934
5935
5936/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
5937 for XPM images. Such a list must consist of conses whose car and
5938 cdr are strings. */
5939
5940static int
5941xpm_valid_color_symbols_p (color_symbols)
5942 Lisp_Object color_symbols;
5943{
5944 while (CONSP (color_symbols))
5945 {
5946 Lisp_Object sym = XCAR (color_symbols);
5947 if (!CONSP (sym)
5948 || !STRINGP (XCAR (sym))
5949 || !STRINGP (XCDR (sym)))
5950 break;
5951 color_symbols = XCDR (color_symbols);
5952 }
5953
5954 return NILP (color_symbols);
5955}
5956
5957
5958/* Value is non-zero if OBJECT is a valid XPM image specification. */
5959
5960static int
5961xpm_image_p (object)
5962 Lisp_Object object;
5963{
5964 struct image_keyword fmt[XPM_LAST];
5965 bcopy (xpm_format, fmt, sizeof fmt);
5966 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
5967 /* Either `:file' or `:data' must be present. */
5968 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
5969 /* Either no `:color-symbols' or it's a list of conses
5970 whose car and cdr are strings. */
5971 && (fmt[XPM_COLOR_SYMBOLS].count == 0
5972 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
5973 && (fmt[XPM_ASCENT].count == 0
5974 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
5975}
5976
5977
5978/* Load image IMG which will be displayed on frame F. Value is
5979 non-zero if successful. */
5980
5981static int
5982xpm_load (f, img)
5983 struct frame *f;
5984 struct image *img;
5985{
5986 int rc, i;
5987 XpmAttributes attrs;
5988 Lisp_Object specified_file, color_symbols;
5989
5990 /* Configure the XPM lib. Use the visual of frame F. Allocate
5991 close colors. Return colors allocated. */
5992 bzero (&attrs, sizeof attrs);
5993 attrs.visual = FRAME_X_VISUAL (f);
5994 attrs.colormap = FRAME_X_COLORMAP (f);
5995 attrs.valuemask |= XpmVisual;
5996 attrs.valuemask |= XpmColormap;
5997 attrs.valuemask |= XpmReturnAllocPixels;
5998#ifdef XpmAllocCloseColors
5999 attrs.alloc_close_colors = 1;
6000 attrs.valuemask |= XpmAllocCloseColors;
6001#else
6002 attrs.closeness = 600;
6003 attrs.valuemask |= XpmCloseness;
6004#endif
6005
6006 /* If image specification contains symbolic color definitions, add
6007 these to `attrs'. */
6008 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
6009 if (CONSP (color_symbols))
6010 {
6011 Lisp_Object tail;
6012 XpmColorSymbol *xpm_syms;
6013 int i, size;
6014
6015 attrs.valuemask |= XpmColorSymbols;
6016
6017 /* Count number of symbols. */
6018 attrs.numsymbols = 0;
6019 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
6020 ++attrs.numsymbols;
6021
6022 /* Allocate an XpmColorSymbol array. */
6023 size = attrs.numsymbols * sizeof *xpm_syms;
6024 xpm_syms = (XpmColorSymbol *) alloca (size);
6025 bzero (xpm_syms, size);
6026 attrs.colorsymbols = xpm_syms;
6027
6028 /* Fill the color symbol array. */
6029 for (tail = color_symbols, i = 0;
6030 CONSP (tail);
6031 ++i, tail = XCDR (tail))
6032 {
6033 Lisp_Object name = XCAR (XCAR (tail));
6034 Lisp_Object color = XCDR (XCAR (tail));
6035 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
6036 strcpy (xpm_syms[i].name, XSTRING (name)->data);
6037 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
6038 strcpy (xpm_syms[i].value, XSTRING (color)->data);
6039 }
6040 }
6041
6042 /* Create a pixmap for the image, either from a file, or from a
6043 string buffer containing data in the same format as an XPM file. */
6044 BLOCK_INPUT;
6045 specified_file = image_spec_value (img->spec, QCfile, NULL);
6046 if (STRINGP (specified_file))
6047 {
6048 Lisp_Object file = x_find_image_file (specified_file);
6049 if (!STRINGP (file))
6050 {
6051 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6052 UNBLOCK_INPUT;
6053 return 0;
6054 }
6055
6056 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
6057 XSTRING (file)->data, &img->pixmap, &img->mask,
6058 &attrs);
6059 }
6060 else
6061 {
6062 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
6063 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
6064 XSTRING (buffer)->data,
6065 &img->pixmap, &img->mask,
6066 &attrs);
6067 }
6068 UNBLOCK_INPUT;
6069
6070 if (rc == XpmSuccess)
6071 {
6072 /* Remember allocated colors. */
6073 img->ncolors = attrs.nalloc_pixels;
6074 img->colors = (unsigned long *) xmalloc (img->ncolors
6075 * sizeof *img->colors);
6076 for (i = 0; i < attrs.nalloc_pixels; ++i)
6077 img->colors[i] = attrs.alloc_pixels[i];
6078
6079 img->width = attrs.width;
6080 img->height = attrs.height;
6081 xassert (img->width > 0 && img->height > 0);
6082
6083 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
6084 BLOCK_INPUT;
6085 XpmFreeAttributes (&attrs);
6086 UNBLOCK_INPUT;
6087 }
6088 else
6089 {
6090 switch (rc)
6091 {
6092 case XpmOpenFailed:
6093 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
6094 break;
6095
6096 case XpmFileInvalid:
6097 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
6098 break;
6099
6100 case XpmNoMemory:
6101 image_error ("Out of memory (%s)", img->spec, Qnil);
6102 break;
6103
6104 case XpmColorFailed:
6105 image_error ("Color allocation error (%s)", img->spec, Qnil);
6106 break;
6107
6108 default:
6109 image_error ("Unknown error (%s)", img->spec, Qnil);
6110 break;
6111 }
6112 }
6113
6114 return rc == XpmSuccess;
6115}
6116
6117#endif /* HAVE_XPM != 0 */
6118
6119
6120#if 0 /* MAC_TODO : Color tables on Mac. */
6121/***********************************************************************
6122 Color table
6123 ***********************************************************************/
6124
6125/* An entry in the color table mapping an RGB color to a pixel color. */
6126
6127struct ct_color
6128{
6129 int r, g, b;
6130 unsigned long pixel;
6131
6132 /* Next in color table collision list. */
6133 struct ct_color *next;
6134};
6135
6136/* The bucket vector size to use. Must be prime. */
6137
6138#define CT_SIZE 101
6139
6140/* Value is a hash of the RGB color given by R, G, and B. */
6141
6142#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
6143
6144/* The color hash table. */
6145
6146struct ct_color **ct_table;
6147
6148/* Number of entries in the color table. */
6149
6150int ct_colors_allocated;
6151
6152/* Function prototypes. */
6153
6154static void init_color_table P_ ((void));
6155static void free_color_table P_ ((void));
6156static unsigned long *colors_in_color_table P_ ((int *n));
6157static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
6158static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
6159
6160
6161/* Initialize the color table. */
6162
6163static void
6164init_color_table ()
6165{
6166 int size = CT_SIZE * sizeof (*ct_table);
6167 ct_table = (struct ct_color **) xmalloc (size);
6168 bzero (ct_table, size);
6169 ct_colors_allocated = 0;
6170}
6171
6172
6173/* Free memory associated with the color table. */
6174
6175static void
6176free_color_table ()
6177{
6178 int i;
6179 struct ct_color *p, *next;
6180
6181 for (i = 0; i < CT_SIZE; ++i)
6182 for (p = ct_table[i]; p; p = next)
6183 {
6184 next = p->next;
6185 xfree (p);
6186 }
6187
6188 xfree (ct_table);
6189 ct_table = NULL;
6190}
6191
6192
6193/* Value is a pixel color for RGB color R, G, B on frame F. If an
6194 entry for that color already is in the color table, return the
6195 pixel color of that entry. Otherwise, allocate a new color for R,
6196 G, B, and make an entry in the color table. */
6197
6198static unsigned long
6199lookup_rgb_color (f, r, g, b)
6200 struct frame *f;
6201 int r, g, b;
6202{
6203 unsigned hash = CT_HASH_RGB (r, g, b);
6204 int i = hash % CT_SIZE;
6205 struct ct_color *p;
6206
6207 for (p = ct_table[i]; p; p = p->next)
6208 if (p->r == r && p->g == g && p->b == b)
6209 break;
6210
6211 if (p == NULL)
6212 {
6213 COLORREF color;
6214 Colormap cmap;
6215 int rc;
6216
6217 color = RGB_TO_ULONG (r, g, b);
6218
6219 ++ct_colors_allocated;
6220
6221 p = (struct ct_color *) xmalloc (sizeof *p);
6222 p->r = r;
6223 p->g = g;
6224 p->b = b;
6225 p->pixel = color;
6226 p->next = ct_table[i];
6227 ct_table[i] = p;
6228 }
6229
6230 return p->pixel;
6231}
6232
6233
6234/* Look up pixel color PIXEL which is used on frame F in the color
6235 table. If not already present, allocate it. Value is PIXEL. */
6236
6237static unsigned long
6238lookup_pixel_color (f, pixel)
6239 struct frame *f;
6240 unsigned long pixel;
6241{
6242 int i = pixel % CT_SIZE;
6243 struct ct_color *p;
6244
6245 for (p = ct_table[i]; p; p = p->next)
6246 if (p->pixel == pixel)
6247 break;
6248
6249 if (p == NULL)
6250 {
6251 XColor color;
6252 Colormap cmap;
6253 int rc;
6254
6255 BLOCK_INPUT;
6256
6257 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6258 color.pixel = pixel;
6259 XQueryColor (NULL, cmap, &color);
6260 rc = x_alloc_nearest_color (f, cmap, &color);
6261 UNBLOCK_INPUT;
6262
6263 if (rc)
6264 {
6265 ++ct_colors_allocated;
6266
6267 p = (struct ct_color *) xmalloc (sizeof *p);
6268 p->r = color.red;
6269 p->g = color.green;
6270 p->b = color.blue;
6271 p->pixel = pixel;
6272 p->next = ct_table[i];
6273 ct_table[i] = p;
6274 }
6275 else
6276 return FRAME_FOREGROUND_PIXEL (f);
6277 }
6278 return p->pixel;
6279}
6280
6281
6282/* Value is a vector of all pixel colors contained in the color table,
6283 allocated via xmalloc. Set *N to the number of colors. */
6284
6285static unsigned long *
6286colors_in_color_table (n)
6287 int *n;
6288{
6289 int i, j;
6290 struct ct_color *p;
6291 unsigned long *colors;
6292
6293 if (ct_colors_allocated == 0)
6294 {
6295 *n = 0;
6296 colors = NULL;
6297 }
6298 else
6299 {
6300 colors = (unsigned long *) xmalloc (ct_colors_allocated
6301 * sizeof *colors);
6302 *n = ct_colors_allocated;
6303
6304 for (i = j = 0; i < CT_SIZE; ++i)
6305 for (p = ct_table[i]; p; p = p->next)
6306 colors[j++] = p->pixel;
6307 }
6308
6309 return colors;
6310}
6311
6312#endif /* MAC_TODO */
6313
6314
6315/***********************************************************************
6316 Algorithms
6317 ***********************************************************************/
6318
6319#if 0 /* MAC_TODO : Mac versions of low level algorithms */
6320static void x_laplace_write_row P_ ((struct frame *, long *,
6321 int, XImage *, int));
6322static void x_laplace_read_row P_ ((struct frame *, Colormap,
6323 XColor *, int, XImage *, int));
6324
6325
6326/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
6327 frame we operate on, CMAP is the color-map in effect, and WIDTH is
6328 the width of one row in the image. */
6329
6330static void
6331x_laplace_read_row (f, cmap, colors, width, ximg, y)
6332 struct frame *f;
6333 Colormap cmap;
6334 XColor *colors;
6335 int width;
6336 XImage *ximg;
6337 int y;
6338{
6339 int x;
6340
6341 for (x = 0; x < width; ++x)
6342 colors[x].pixel = XGetPixel (ximg, x, y);
6343
6344 XQueryColors (NULL, cmap, colors, width);
6345}
6346
6347
6348/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
6349 containing the pixel colors to write. F is the frame we are
6350 working on. */
6351
6352static void
6353x_laplace_write_row (f, pixels, width, ximg, y)
6354 struct frame *f;
6355 long *pixels;
6356 int width;
6357 XImage *ximg;
6358 int y;
6359{
6360 int x;
6361
6362 for (x = 0; x < width; ++x)
6363 XPutPixel (ximg, x, y, pixels[x]);
6364}
6365#endif
6366
6367/* Transform image IMG which is used on frame F with a Laplace
6368 edge-detection algorithm. The result is an image that can be used
6369 to draw disabled buttons, for example. */
6370
6371static void
6372x_laplace (f, img)
6373 struct frame *f;
6374 struct image *img;
6375{
6376#if 0 /* MAC_TODO : Mac version */
6377 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6378 XImage *ximg, *oimg;
6379 XColor *in[3];
6380 long *out;
6381 Pixmap pixmap;
6382 int x, y, i;
6383 long pixel;
6384 int in_y, out_y, rc;
6385 int mv2 = 45000;
6386
6387 BLOCK_INPUT;
6388
6389 /* Get the X image IMG->pixmap. */
6390 ximg = XGetImage (NULL, img->pixmap,
6391 0, 0, img->width, img->height, ~0, ZPixmap);
6392
6393 /* Allocate 3 input rows, and one output row of colors. */
6394 for (i = 0; i < 3; ++i)
6395 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
6396 out = (long *) alloca (img->width * sizeof (long));
6397
6398 /* Create an X image for output. */
6399 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
6400 &oimg, &pixmap);
6401
6402 /* Fill first two rows. */
6403 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
6404 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
6405 in_y = 2;
6406
6407 /* Write first row, all zeros. */
6408 init_color_table ();
6409 pixel = lookup_rgb_color (f, 0, 0, 0);
6410 for (x = 0; x < img->width; ++x)
6411 out[x] = pixel;
6412 x_laplace_write_row (f, out, img->width, oimg, 0);
6413 out_y = 1;
6414
6415 for (y = 2; y < img->height; ++y)
6416 {
6417 int rowa = y % 3;
6418 int rowb = (y + 2) % 3;
6419
6420 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
6421
6422 for (x = 0; x < img->width - 2; ++x)
6423 {
6424 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
6425 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
6426 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
6427
6428 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
6429 b & 0xffff);
6430 }
6431
6432 x_laplace_write_row (f, out, img->width, oimg, out_y++);
6433 }
6434
6435 /* Write last line, all zeros. */
6436 for (x = 0; x < img->width; ++x)
6437 out[x] = pixel;
6438 x_laplace_write_row (f, out, img->width, oimg, out_y);
6439
6440 /* Free the input image, and free resources of IMG. */
6441 XDestroyImage (ximg);
6442 x_clear_image (f, img);
6443
6444 /* Put the output image into pixmap, and destroy it. */
6445 x_put_x_image (f, oimg, pixmap, img->width, img->height);
6446 x_destroy_x_image (oimg);
6447
6448 /* Remember new pixmap and colors in IMG. */
6449 img->pixmap = pixmap;
6450 img->colors = colors_in_color_table (&img->ncolors);
6451 free_color_table ();
6452
6453 UNBLOCK_INPUT;
6454#endif /* MAC_TODO */
6455}
6456
6457
6458/* Build a mask for image IMG which is used on frame F. FILE is the
6459 name of an image file, for error messages. HOW determines how to
6460 determine the background color of IMG. If it is a list '(R G B)',
6461 with R, G, and B being integers >= 0, take that as the color of the
6462 background. Otherwise, determine the background color of IMG
6463 heuristically. Value is non-zero if successful. */
6464
6465static int
6466x_build_heuristic_mask (f, img, how)
6467 struct frame *f;
6468 struct image *img;
6469 Lisp_Object how;
6470{
6471#if 0 /* MAC_TODO : Mac version */
6472 Display *dpy = FRAME_W32_DISPLAY (f);
6473 XImage *ximg, *mask_img;
6474 int x, y, rc, look_at_corners_p;
6475 unsigned long bg;
6476
6477 BLOCK_INPUT;
6478
6479 /* Create an image and pixmap serving as mask. */
6480 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
6481 &mask_img, &img->mask);
6482 if (!rc)
6483 {
6484 UNBLOCK_INPUT;
6485 return 0;
6486 }
6487
6488 /* Get the X image of IMG->pixmap. */
6489 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
6490 ~0, ZPixmap);
6491
6492 /* Determine the background color of ximg. If HOW is `(R G B)'
6493 take that as color. Otherwise, try to determine the color
6494 heuristically. */
6495 look_at_corners_p = 1;
6496
6497 if (CONSP (how))
6498 {
6499 int rgb[3], i = 0;
6500
6501 while (i < 3
6502 && CONSP (how)
6503 && NATNUMP (XCAR (how)))
6504 {
6505 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
6506 how = XCDR (how);
6507 }
6508
6509 if (i == 3 && NILP (how))
6510 {
6511 char color_name[30];
6512 XColor exact, color;
6513 Colormap cmap;
6514
6515 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
6516
6517 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6518 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
6519 {
6520 bg = color.pixel;
6521 look_at_corners_p = 0;
6522 }
6523 }
6524 }
6525
6526 if (look_at_corners_p)
6527 {
6528 unsigned long corners[4];
6529 int i, best_count;
6530
6531 /* Get the colors at the corners of ximg. */
6532 corners[0] = XGetPixel (ximg, 0, 0);
6533 corners[1] = XGetPixel (ximg, img->width - 1, 0);
6534 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
6535 corners[3] = XGetPixel (ximg, 0, img->height - 1);
6536
6537 /* Choose the most frequently found color as background. */
6538 for (i = best_count = 0; i < 4; ++i)
6539 {
6540 int j, n;
6541
6542 for (j = n = 0; j < 4; ++j)
6543 if (corners[i] == corners[j])
6544 ++n;
6545
6546 if (n > best_count)
6547 bg = corners[i], best_count = n;
6548 }
6549 }
6550
6551 /* Set all bits in mask_img to 1 whose color in ximg is different
6552 from the background color bg. */
6553 for (y = 0; y < img->height; ++y)
6554 for (x = 0; x < img->width; ++x)
6555 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
6556
6557 /* Put mask_img into img->mask. */
6558 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6559 x_destroy_x_image (mask_img);
6560 XDestroyImage (ximg);
6561
6562 UNBLOCK_INPUT;
6563#endif /* MAC_TODO */
6564
6565 return 1;
6566}
6567
6568
6569
6570/***********************************************************************
6571 PBM (mono, gray, color)
6572 ***********************************************************************/
6573#ifdef HAVE_PBM
6574
6575static int pbm_image_p P_ ((Lisp_Object object));
6576static int pbm_load P_ ((struct frame *f, struct image *img));
6577static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
6578
6579/* The symbol `pbm' identifying images of this type. */
6580
6581Lisp_Object Qpbm;
6582
6583/* Indices of image specification fields in gs_format, below. */
6584
6585enum pbm_keyword_index
6586{
6587 PBM_TYPE,
6588 PBM_FILE,
6589 PBM_DATA,
6590 PBM_ASCENT,
6591 PBM_MARGIN,
6592 PBM_RELIEF,
6593 PBM_ALGORITHM,
6594 PBM_HEURISTIC_MASK,
6595 PBM_LAST
6596};
6597
6598/* Vector of image_keyword structures describing the format
6599 of valid user-defined image specifications. */
6600
6601static struct image_keyword pbm_format[PBM_LAST] =
6602{
6603 {":type", IMAGE_SYMBOL_VALUE, 1},
6604 {":file", IMAGE_STRING_VALUE, 0},
6605 {":data", IMAGE_STRING_VALUE, 0},
6606 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6607 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6608 {":relief", IMAGE_INTEGER_VALUE, 0},
6609 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6610 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6611};
6612
6613/* Structure describing the image type `pbm'. */
6614
6615static struct image_type pbm_type =
6616{
6617 &Qpbm,
6618 pbm_image_p,
6619 pbm_load,
6620 x_clear_image,
6621 NULL
6622};
6623
6624
6625/* Return non-zero if OBJECT is a valid PBM image specification. */
6626
6627static int
6628pbm_image_p (object)
6629 Lisp_Object object;
6630{
6631 struct image_keyword fmt[PBM_LAST];
6632
6633 bcopy (pbm_format, fmt, sizeof fmt);
6634
6635 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
6636 || (fmt[PBM_ASCENT].count
6637 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
6638 return 0;
6639
6640 /* Must specify either :data or :file. */
6641 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
6642}
6643
6644
6645/* Scan a decimal number from *S and return it. Advance *S while
6646 reading the number. END is the end of the string. Value is -1 at
6647 end of input. */
6648
6649static int
6650pbm_scan_number (s, end)
6651 unsigned char **s, *end;
6652{
6653 int c, val = -1;
6654
6655 while (*s < end)
6656 {
6657 /* Skip white-space. */
6658 while (*s < end && (c = *(*s)++, isspace (c)))
6659 ;
6660
6661 if (c == '#')
6662 {
6663 /* Skip comment to end of line. */
6664 while (*s < end && (c = *(*s)++, c != '\n'))
6665 ;
6666 }
6667 else if (isdigit (c))
6668 {
6669 /* Read decimal number. */
6670 val = c - '0';
6671 while (*s < end && (c = *(*s)++, isdigit (c)))
6672 val = 10 * val + c - '0';
6673 break;
6674 }
6675 else
6676 break;
6677 }
6678
6679 return val;
6680}
6681
6682
6683/* Read FILE into memory. Value is a pointer to a buffer allocated
6684 with xmalloc holding FILE's contents. Value is null if an error
6685 occured. *SIZE is set to the size of the file. */
6686
6687static char *
6688pbm_read_file (file, size)
6689 Lisp_Object file;
6690 int *size;
6691{
6692 FILE *fp = NULL;
6693 char *buf = NULL;
6694 struct stat st;
6695
6696 if (stat (XSTRING (file)->data, &st) == 0
6697 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
6698 && (buf = (char *) xmalloc (st.st_size),
6699 fread (buf, 1, st.st_size, fp) == st.st_size))
6700 {
6701 *size = st.st_size;
6702 fclose (fp);
6703 }
6704 else
6705 {
6706 if (fp)
6707 fclose (fp);
6708 if (buf)
6709 {
6710 xfree (buf);
6711 buf = NULL;
6712 }
6713 }
6714
6715 return buf;
6716}
6717
6718
6719/* Load PBM image IMG for use on frame F. */
6720
6721static int
6722pbm_load (f, img)
6723 struct frame *f;
6724 struct image *img;
6725{
6726 int raw_p, x, y;
6727 int width, height, max_color_idx = 0;
6728 XImage *ximg;
6729 Lisp_Object file, specified_file;
6730 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
6731 struct gcpro gcpro1;
6732 unsigned char *contents = NULL;
6733 unsigned char *end, *p;
6734 int size;
6735
6736 specified_file = image_spec_value (img->spec, QCfile, NULL);
6737 file = Qnil;
6738 GCPRO1 (file);
6739
6740 if (STRINGP (specified_file))
6741 {
6742 file = x_find_image_file (specified_file);
6743 if (!STRINGP (file))
6744 {
6745 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6746 UNGCPRO;
6747 return 0;
6748 }
6749
6750 contents = pbm_read_file (file, &size);
6751 if (contents == NULL)
6752 {
6753 image_error ("Error reading `%s'", file, Qnil);
6754 UNGCPRO;
6755 return 0;
6756 }
6757
6758 p = contents;
6759 end = contents + size;
6760 }
6761 else
6762 {
6763 Lisp_Object data;
6764 data = image_spec_value (img->spec, QCdata, NULL);
6765 p = XSTRING (data)->data;
6766 end = p + STRING_BYTES (XSTRING (data));
6767 }
6768
6769 /* Check magic number. */
6770 if (end - p < 2 || *p++ != 'P')
6771 {
6772 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
6773 error:
6774 xfree (contents);
6775 UNGCPRO;
6776 return 0;
6777 }
6778
6779 switch (*p++)
6780 {
6781 case '1':
6782 raw_p = 0, type = PBM_MONO;
6783 break;
6784
6785 case '2':
6786 raw_p = 0, type = PBM_GRAY;
6787 break;
6788
6789 case '3':
6790 raw_p = 0, type = PBM_COLOR;
6791 break;
6792
6793 case '4':
6794 raw_p = 1, type = PBM_MONO;
6795 break;
6796
6797 case '5':
6798 raw_p = 1, type = PBM_GRAY;
6799 break;
6800
6801 case '6':
6802 raw_p = 1, type = PBM_COLOR;
6803 break;
6804
6805 default:
6806 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
6807 goto error;
6808 }
6809
6810 /* Read width, height, maximum color-component. Characters
6811 starting with `#' up to the end of a line are ignored. */
6812 width = pbm_scan_number (&p, end);
6813 height = pbm_scan_number (&p, end);
6814
6815 if (type != PBM_MONO)
6816 {
6817 max_color_idx = pbm_scan_number (&p, end);
6818 if (raw_p && max_color_idx > 255)
6819 max_color_idx = 255;
6820 }
6821
6822 if (width < 0
6823 || height < 0
6824 || (type != PBM_MONO && max_color_idx < 0))
6825 goto error;
6826
6827 BLOCK_INPUT;
6828 if (!x_create_x_image_and_pixmap (f, width, height, 0,
6829 &ximg, &img->pixmap))
6830 {
6831 UNBLOCK_INPUT;
6832 goto error;
6833 }
6834
6835 /* Initialize the color hash table. */
6836 init_color_table ();
6837
6838 if (type == PBM_MONO)
6839 {
6840 int c = 0, g;
6841
6842 for (y = 0; y < height; ++y)
6843 for (x = 0; x < width; ++x)
6844 {
6845 if (raw_p)
6846 {
6847 if ((x & 7) == 0)
6848 c = *p++;
6849 g = c & 0x80;
6850 c <<= 1;
6851 }
6852 else
6853 g = pbm_scan_number (&p, end);
6854
6855 XPutPixel (ximg, x, y, (g
6856 ? FRAME_FOREGROUND_PIXEL (f)
6857 : FRAME_BACKGROUND_PIXEL (f)));
6858 }
6859 }
6860 else
6861 {
6862 for (y = 0; y < height; ++y)
6863 for (x = 0; x < width; ++x)
6864 {
6865 int r, g, b;
6866
6867 if (type == PBM_GRAY)
6868 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
6869 else if (raw_p)
6870 {
6871 r = *p++;
6872 g = *p++;
6873 b = *p++;
6874 }
6875 else
6876 {
6877 r = pbm_scan_number (&p, end);
6878 g = pbm_scan_number (&p, end);
6879 b = pbm_scan_number (&p, end);
6880 }
6881
6882 if (r < 0 || g < 0 || b < 0)
6883 {
6884 xfree (ximg->data);
6885 ximg->data = NULL;
6886 XDestroyImage (ximg);
6887 UNBLOCK_INPUT;
6888 image_error ("Invalid pixel value in image `%s'",
6889 img->spec, Qnil);
6890 goto error;
6891 }
6892
6893 /* RGB values are now in the range 0..max_color_idx.
6894 Scale this to the range 0..0xffff supported by X. */
6895 r = (double) r * 65535 / max_color_idx;
6896 g = (double) g * 65535 / max_color_idx;
6897 b = (double) b * 65535 / max_color_idx;
6898 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6899 }
6900 }
6901
6902 /* Store in IMG->colors the colors allocated for the image, and
6903 free the color table. */
6904 img->colors = colors_in_color_table (&img->ncolors);
6905 free_color_table ();
6906
6907 /* Put the image into a pixmap. */
6908 x_put_x_image (f, ximg, img->pixmap, width, height);
6909 x_destroy_x_image (ximg);
6910 UNBLOCK_INPUT;
6911
6912 img->width = width;
6913 img->height = height;
6914
6915 UNGCPRO;
6916 xfree (contents);
6917 return 1;
6918}
6919#endif /* HAVE_PBM */
6920
6921
6922/***********************************************************************
6923 PNG
6924 ***********************************************************************/
6925
6926#if HAVE_PNG
6927
6928#include <png.h>
6929
6930/* Function prototypes. */
6931
6932static int png_image_p P_ ((Lisp_Object object));
6933static int png_load P_ ((struct frame *f, struct image *img));
6934
6935/* The symbol `png' identifying images of this type. */
6936
6937Lisp_Object Qpng;
6938
6939/* Indices of image specification fields in png_format, below. */
6940
6941enum png_keyword_index
6942{
6943 PNG_TYPE,
6944 PNG_DATA,
6945 PNG_FILE,
6946 PNG_ASCENT,
6947 PNG_MARGIN,
6948 PNG_RELIEF,
6949 PNG_ALGORITHM,
6950 PNG_HEURISTIC_MASK,
6951 PNG_LAST
6952};
6953
6954/* Vector of image_keyword structures describing the format
6955 of valid user-defined image specifications. */
6956
6957static struct image_keyword png_format[PNG_LAST] =
6958{
6959 {":type", IMAGE_SYMBOL_VALUE, 1},
6960 {":data", IMAGE_STRING_VALUE, 0},
6961 {":file", IMAGE_STRING_VALUE, 0},
6962 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6963 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6964 {":relief", IMAGE_INTEGER_VALUE, 0},
6965 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6966 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6967};
6968
6969/* Structure describing the image type `png'. */
6970
6971static struct image_type png_type =
6972{
6973 &Qpng,
6974 png_image_p,
6975 png_load,
6976 x_clear_image,
6977 NULL
6978};
6979
6980
6981/* Return non-zero if OBJECT is a valid PNG image specification. */
6982
6983static int
6984png_image_p (object)
6985 Lisp_Object object;
6986{
6987 struct image_keyword fmt[PNG_LAST];
6988 bcopy (png_format, fmt, sizeof fmt);
6989
6990 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
6991 || (fmt[PNG_ASCENT].count
6992 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
6993 return 0;
6994
6995 /* Must specify either the :data or :file keyword. */
6996 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
6997}
6998
6999
7000/* Error and warning handlers installed when the PNG library
7001 is initialized. */
7002
7003static void
7004my_png_error (png_ptr, msg)
7005 png_struct *png_ptr;
7006 char *msg;
7007{
7008 xassert (png_ptr != NULL);
7009 image_error ("PNG error: %s", build_string (msg), Qnil);
7010 longjmp (png_ptr->jmpbuf, 1);
7011}
7012
7013
7014static void
7015my_png_warning (png_ptr, msg)
7016 png_struct *png_ptr;
7017 char *msg;
7018{
7019 xassert (png_ptr != NULL);
7020 image_error ("PNG warning: %s", build_string (msg), Qnil);
7021}
7022
7023/* Memory source for PNG decoding. */
7024
7025struct png_memory_storage
7026{
7027 unsigned char *bytes; /* The data */
7028 size_t len; /* How big is it? */
7029 int index; /* Where are we? */
7030};
7031
7032
7033/* Function set as reader function when reading PNG image from memory.
7034 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
7035 bytes from the input to DATA. */
7036
7037static void
7038png_read_from_memory (png_ptr, data, length)
7039 png_structp png_ptr;
7040 png_bytep data;
7041 png_size_t length;
7042{
7043 struct png_memory_storage *tbr
7044 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
7045
7046 if (length > tbr->len - tbr->index)
7047 png_error (png_ptr, "Read error");
7048
7049 bcopy (tbr->bytes + tbr->index, data, length);
7050 tbr->index = tbr->index + length;
7051}
7052
7053/* Load PNG image IMG for use on frame F. Value is non-zero if
7054 successful. */
7055
7056static int
7057png_load (f, img)
7058 struct frame *f;
7059 struct image *img;
7060{
7061 Lisp_Object file, specified_file;
7062 Lisp_Object specified_data;
7063 int x, y, i;
7064 XImage *ximg, *mask_img = NULL;
7065 struct gcpro gcpro1;
7066 png_struct *png_ptr = NULL;
7067 png_info *info_ptr = NULL, *end_info = NULL;
7068 FILE *fp = NULL;
7069 png_byte sig[8];
7070 png_byte *pixels = NULL;
7071 png_byte **rows = NULL;
7072 png_uint_32 width, height;
7073 int bit_depth, color_type, interlace_type;
7074 png_byte channels;
7075 png_uint_32 row_bytes;
7076 int transparent_p;
7077 char *gamma_str;
7078 double screen_gamma, image_gamma;
7079 int intent;
7080 struct png_memory_storage tbr; /* Data to be read */
7081
7082 /* Find out what file to load. */
7083 specified_file = image_spec_value (img->spec, QCfile, NULL);
7084 specified_data = image_spec_value (img->spec, QCdata, NULL);
7085 file = Qnil;
7086 GCPRO1 (file);
7087
7088 if (NILP (specified_data))
7089 {
7090 file = x_find_image_file (specified_file);
7091 if (!STRINGP (file))
7092 {
7093 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7094 UNGCPRO;
7095 return 0;
7096 }
7097
7098 /* Open the image file. */
7099 fp = fopen (XSTRING (file)->data, "rb");
7100 if (!fp)
7101 {
7102 image_error ("Cannot open image file `%s'", file, Qnil);
7103 UNGCPRO;
7104 fclose (fp);
7105 return 0;
7106 }
7107
7108 /* Check PNG signature. */
7109 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7110 || !png_check_sig (sig, sizeof sig))
7111 {
7112 image_error ("Not a PNG file:` %s'", file, Qnil);
7113 UNGCPRO;
7114 fclose (fp);
7115 return 0;
7116 }
7117 }
7118 else
7119 {
7120 /* Read from memory. */
7121 tbr.bytes = XSTRING (specified_data)->data;
7122 tbr.len = STRING_BYTES (XSTRING (specified_data));
7123 tbr.index = 0;
7124
7125 /* Check PNG signature. */
7126 if (tbr.len < sizeof sig
7127 || !png_check_sig (tbr.bytes, sizeof sig))
7128 {
7129 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
7130 UNGCPRO;
7131 return 0;
7132 }
7133
7134 /* Need to skip past the signature. */
7135 tbr.bytes += sizeof (sig);
7136 }
7137
7138 /* Initialize read and info structs for PNG lib. */
7139 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
7140 my_png_error, my_png_warning);
7141 if (!png_ptr)
7142 {
7143 if (fp) fclose (fp);
7144 UNGCPRO;
7145 return 0;
7146 }
7147
7148 info_ptr = png_create_info_struct (png_ptr);
7149 if (!info_ptr)
7150 {
7151 png_destroy_read_struct (&png_ptr, NULL, NULL);
7152 if (fp) fclose (fp);
7153 UNGCPRO;
7154 return 0;
7155 }
7156
7157 end_info = png_create_info_struct (png_ptr);
7158 if (!end_info)
7159 {
7160 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
7161 if (fp) fclose (fp);
7162 UNGCPRO;
7163 return 0;
7164 }
7165
7166 /* Set error jump-back. We come back here when the PNG library
7167 detects an error. */
7168 if (setjmp (png_ptr->jmpbuf))
7169 {
7170 error:
7171 if (png_ptr)
7172 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7173 xfree (pixels);
7174 xfree (rows);
7175 if (fp) fclose (fp);
7176 UNGCPRO;
7177 return 0;
7178 }
7179
7180 /* Read image info. */
7181 if (!NILP (specified_data))
7182 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
7183 else
7184 png_init_io (png_ptr, fp);
7185
7186 png_set_sig_bytes (png_ptr, sizeof sig);
7187 png_read_info (png_ptr, info_ptr);
7188 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
7189 &interlace_type, NULL, NULL);
7190
7191 /* If image contains simply transparency data, we prefer to
7192 construct a clipping mask. */
7193 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
7194 transparent_p = 1;
7195 else
7196 transparent_p = 0;
7197
7198 /* This function is easier to write if we only have to handle
7199 one data format: RGB or RGBA with 8 bits per channel. Let's
7200 transform other formats into that format. */
7201
7202 /* Strip more than 8 bits per channel. */
7203 if (bit_depth == 16)
7204 png_set_strip_16 (png_ptr);
7205
7206 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
7207 if available. */
7208 png_set_expand (png_ptr);
7209
7210 /* Convert grayscale images to RGB. */
7211 if (color_type == PNG_COLOR_TYPE_GRAY
7212 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7213 png_set_gray_to_rgb (png_ptr);
7214
7215 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
7216 gamma_str = getenv ("SCREEN_GAMMA");
7217 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
7218
7219 /* Tell the PNG lib to handle gamma correction for us. */
7220
7221#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
7222 if (png_get_sRGB (png_ptr, info_ptr, &intent))
7223 /* There is a special chunk in the image specifying the gamma. */
7224 png_set_sRGB (png_ptr, info_ptr, intent);
7225 else
7226#endif
7227 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
7228 /* Image contains gamma information. */
7229 png_set_gamma (png_ptr, screen_gamma, image_gamma);
7230 else
7231 /* Use a default of 0.5 for the image gamma. */
7232 png_set_gamma (png_ptr, screen_gamma, 0.5);
7233
7234 /* Handle alpha channel by combining the image with a background
7235 color. Do this only if a real alpha channel is supplied. For
7236 simple transparency, we prefer a clipping mask. */
7237 if (!transparent_p)
7238 {
7239 png_color_16 *image_background;
7240
7241 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
7242 /* Image contains a background color with which to
7243 combine the image. */
7244 png_set_background (png_ptr, image_background,
7245 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
7246 else
7247 {
7248 /* Image does not contain a background color with which
7249 to combine the image data via an alpha channel. Use
7250 the frame's background instead. */
7251 XColor color;
7252 Colormap cmap;
7253 png_color_16 frame_background;
7254
7255 BLOCK_INPUT;
7256 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
7257 color.pixel = FRAME_BACKGROUND_PIXEL (f);
7258 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
7259 UNBLOCK_INPUT;
7260
7261 bzero (&frame_background, sizeof frame_background);
7262 frame_background.red = color.red;
7263 frame_background.green = color.green;
7264 frame_background.blue = color.blue;
7265
7266 png_set_background (png_ptr, &frame_background,
7267 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7268 }
7269 }
7270
7271 /* Update info structure. */
7272 png_read_update_info (png_ptr, info_ptr);
7273
7274 /* Get number of channels. Valid values are 1 for grayscale images
7275 and images with a palette, 2 for grayscale images with transparency
7276 information (alpha channel), 3 for RGB images, and 4 for RGB
7277 images with alpha channel, i.e. RGBA. If conversions above were
7278 sufficient we should only have 3 or 4 channels here. */
7279 channels = png_get_channels (png_ptr, info_ptr);
7280 xassert (channels == 3 || channels == 4);
7281
7282 /* Number of bytes needed for one row of the image. */
7283 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
7284
7285 /* Allocate memory for the image. */
7286 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
7287 rows = (png_byte **) xmalloc (height * sizeof *rows);
7288 for (i = 0; i < height; ++i)
7289 rows[i] = pixels + i * row_bytes;
7290
7291 /* Read the entire image. */
7292 png_read_image (png_ptr, rows);
7293 png_read_end (png_ptr, info_ptr);
7294 if (fp)
7295 {
7296 fclose (fp);
7297 fp = NULL;
7298 }
7299
7300 BLOCK_INPUT;
7301
7302 /* Create the X image and pixmap. */
7303 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7304 &img->pixmap))
7305 {
7306 UNBLOCK_INPUT;
7307 goto error;
7308 }
7309
7310 /* Create an image and pixmap serving as mask if the PNG image
7311 contains an alpha channel. */
7312 if (channels == 4
7313 && !transparent_p
7314 && !x_create_x_image_and_pixmap (f, width, height, 1,
7315 &mask_img, &img->mask))
7316 {
7317 x_destroy_x_image (ximg);
7318 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
7319 img->pixmap = 0;
7320 UNBLOCK_INPUT;
7321 goto error;
7322 }
7323
7324 /* Fill the X image and mask from PNG data. */
7325 init_color_table ();
7326
7327 for (y = 0; y < height; ++y)
7328 {
7329 png_byte *p = rows[y];
7330
7331 for (x = 0; x < width; ++x)
7332 {
7333 unsigned r, g, b;
7334
7335 r = *p++ << 8;
7336 g = *p++ << 8;
7337 b = *p++ << 8;
7338 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7339
7340 /* An alpha channel, aka mask channel, associates variable
7341 transparency with an image. Where other image formats
7342 support binary transparency---fully transparent or fully
7343 opaque---PNG allows up to 254 levels of partial transparency.
7344 The PNG library implements partial transparency by combining
7345 the image with a specified background color.
7346
7347 I'm not sure how to handle this here nicely: because the
7348 background on which the image is displayed may change, for
7349 real alpha channel support, it would be necessary to create
7350 a new image for each possible background.
7351
7352 What I'm doing now is that a mask is created if we have
7353 boolean transparency information. Otherwise I'm using
7354 the frame's background color to combine the image with. */
7355
7356 if (channels == 4)
7357 {
7358 if (mask_img)
7359 XPutPixel (mask_img, x, y, *p > 0);
7360 ++p;
7361 }
7362 }
7363 }
7364
7365 /* Remember colors allocated for this image. */
7366 img->colors = colors_in_color_table (&img->ncolors);
7367 free_color_table ();
7368
7369 /* Clean up. */
7370 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7371 xfree (rows);
7372 xfree (pixels);
7373
7374 img->width = width;
7375 img->height = height;
7376
7377 /* Put the image into the pixmap, then free the X image and its buffer. */
7378 x_put_x_image (f, ximg, img->pixmap, width, height);
7379 x_destroy_x_image (ximg);
7380
7381 /* Same for the mask. */
7382 if (mask_img)
7383 {
7384 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7385 x_destroy_x_image (mask_img);
7386 }
7387
7388 UNBLOCK_INPUT;
7389 UNGCPRO;
7390 return 1;
7391}
7392
7393#endif /* HAVE_PNG != 0 */
7394
7395
7396
7397/***********************************************************************
7398 JPEG
7399 ***********************************************************************/
7400
7401#if HAVE_JPEG
7402
7403/* Work around a warning about HAVE_STDLIB_H being redefined in
7404 jconfig.h. */
7405#ifdef HAVE_STDLIB_H
7406#define HAVE_STDLIB_H_1
7407#undef HAVE_STDLIB_H
7408#endif /* HAVE_STLIB_H */
7409
7410#include <jpeglib.h>
7411#include <jerror.h>
7412#include <setjmp.h>
7413
7414#ifdef HAVE_STLIB_H_1
7415#define HAVE_STDLIB_H 1
7416#endif
7417
7418static int jpeg_image_p P_ ((Lisp_Object object));
7419static int jpeg_load P_ ((struct frame *f, struct image *img));
7420
7421/* The symbol `jpeg' identifying images of this type. */
7422
7423Lisp_Object Qjpeg;
7424
7425/* Indices of image specification fields in gs_format, below. */
7426
7427enum jpeg_keyword_index
7428{
7429 JPEG_TYPE,
7430 JPEG_DATA,
7431 JPEG_FILE,
7432 JPEG_ASCENT,
7433 JPEG_MARGIN,
7434 JPEG_RELIEF,
7435 JPEG_ALGORITHM,
7436 JPEG_HEURISTIC_MASK,
7437 JPEG_LAST
7438};
7439
7440/* Vector of image_keyword structures describing the format
7441 of valid user-defined image specifications. */
7442
7443static struct image_keyword jpeg_format[JPEG_LAST] =
7444{
7445 {":type", IMAGE_SYMBOL_VALUE, 1},
7446 {":data", IMAGE_STRING_VALUE, 0},
7447 {":file", IMAGE_STRING_VALUE, 0},
7448 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7449 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7450 {":relief", IMAGE_INTEGER_VALUE, 0},
7451 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7452 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7453};
7454
7455/* Structure describing the image type `jpeg'. */
7456
7457static struct image_type jpeg_type =
7458{
7459 &Qjpeg,
7460 jpeg_image_p,
7461 jpeg_load,
7462 x_clear_image,
7463 NULL
7464};
7465
7466
7467/* Return non-zero if OBJECT is a valid JPEG image specification. */
7468
7469static int
7470jpeg_image_p (object)
7471 Lisp_Object object;
7472{
7473 struct image_keyword fmt[JPEG_LAST];
7474
7475 bcopy (jpeg_format, fmt, sizeof fmt);
7476
7477 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
7478 || (fmt[JPEG_ASCENT].count
7479 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
7480 return 0;
7481
7482 /* Must specify either the :data or :file keyword. */
7483 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
7484}
7485
7486
7487struct my_jpeg_error_mgr
7488{
7489 struct jpeg_error_mgr pub;
7490 jmp_buf setjmp_buffer;
7491};
7492
7493static void
7494my_error_exit (cinfo)
7495 j_common_ptr cinfo;
7496{
7497 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
7498 longjmp (mgr->setjmp_buffer, 1);
7499}
7500
7501/* Init source method for JPEG data source manager. Called by
7502 jpeg_read_header() before any data is actually read. See
7503 libjpeg.doc from the JPEG lib distribution. */
7504
7505static void
7506our_init_source (cinfo)
7507 j_decompress_ptr cinfo;
7508{
7509}
7510
7511
7512/* Fill input buffer method for JPEG data source manager. Called
7513 whenever more data is needed. We read the whole image in one step,
7514 so this only adds a fake end of input marker at the end. */
7515
7516static boolean
7517our_fill_input_buffer (cinfo)
7518 j_decompress_ptr cinfo;
7519{
7520 /* Insert a fake EOI marker. */
7521 struct jpeg_source_mgr *src = cinfo->src;
7522 static JOCTET buffer[2];
7523
7524 buffer[0] = (JOCTET) 0xFF;
7525 buffer[1] = (JOCTET) JPEG_EOI;
7526
7527 src->next_input_byte = buffer;
7528 src->bytes_in_buffer = 2;
7529 return TRUE;
7530}
7531
7532
7533/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
7534 is the JPEG data source manager. */
7535
7536static void
7537our_skip_input_data (cinfo, num_bytes)
7538 j_decompress_ptr cinfo;
7539 long num_bytes;
7540{
7541 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
7542
7543 if (src)
7544 {
7545 if (num_bytes > src->bytes_in_buffer)
7546 ERREXIT (cinfo, JERR_INPUT_EOF);
7547
7548 src->bytes_in_buffer -= num_bytes;
7549 src->next_input_byte += num_bytes;
7550 }
7551}
7552
7553
7554/* Method to terminate data source. Called by
7555 jpeg_finish_decompress() after all data has been processed. */
7556
7557static void
7558our_term_source (cinfo)
7559 j_decompress_ptr cinfo;
7560{
7561}
7562
7563
7564/* Set up the JPEG lib for reading an image from DATA which contains
7565 LEN bytes. CINFO is the decompression info structure created for
7566 reading the image. */
7567
7568static void
7569jpeg_memory_src (cinfo, data, len)
7570 j_decompress_ptr cinfo;
7571 JOCTET *data;
7572 unsigned int len;
7573{
7574 struct jpeg_source_mgr *src;
7575
7576 if (cinfo->src == NULL)
7577 {
7578 /* First time for this JPEG object? */
7579 cinfo->src = (struct jpeg_source_mgr *)
7580 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
7581 sizeof (struct jpeg_source_mgr));
7582 src = (struct jpeg_source_mgr *) cinfo->src;
7583 src->next_input_byte = data;
7584 }
7585
7586 src = (struct jpeg_source_mgr *) cinfo->src;
7587 src->init_source = our_init_source;
7588 src->fill_input_buffer = our_fill_input_buffer;
7589 src->skip_input_data = our_skip_input_data;
7590 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
7591 src->term_source = our_term_source;
7592 src->bytes_in_buffer = len;
7593 src->next_input_byte = data;
7594}
7595
7596
7597/* Load image IMG for use on frame F. Patterned after example.c
7598 from the JPEG lib. */
7599
7600static int
7601jpeg_load (f, img)
7602 struct frame *f;
7603 struct image *img;
7604{
7605 struct jpeg_decompress_struct cinfo;
7606 struct my_jpeg_error_mgr mgr;
7607 Lisp_Object file, specified_file;
7608 Lisp_Object specified_data;
7609 FILE *fp = NULL;
7610 JSAMPARRAY buffer;
7611 int row_stride, x, y;
7612 XImage *ximg = NULL;
7613 int rc;
7614 unsigned long *colors;
7615 int width, height;
7616 struct gcpro gcpro1;
7617
7618 /* Open the JPEG file. */
7619 specified_file = image_spec_value (img->spec, QCfile, NULL);
7620 specified_data = image_spec_value (img->spec, QCdata, NULL);
7621 file = Qnil;
7622 GCPRO1 (file);
7623
7624 if (NILP (specified_data))
7625 {
7626 file = x_find_image_file (specified_file);
7627 if (!STRINGP (file))
7628 {
7629 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7630 UNGCPRO;
7631 return 0;
7632 }
7633
7634 fp = fopen (XSTRING (file)->data, "r");
7635 if (fp == NULL)
7636 {
7637 image_error ("Cannot open `%s'", file, Qnil);
7638 UNGCPRO;
7639 return 0;
7640 }
7641 }
7642
7643 /* Customize libjpeg's error handling to call my_error_exit when an
7644 error is detected. This function will perform a longjmp. */
7645 mgr.pub.error_exit = my_error_exit;
7646 cinfo.err = jpeg_std_error (&mgr.pub);
7647
7648 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
7649 {
7650 if (rc == 1)
7651 {
7652 /* Called from my_error_exit. Display a JPEG error. */
7653 char buffer[JMSG_LENGTH_MAX];
7654 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
7655 image_error ("Error reading JPEG image `%s': %s", img->spec,
7656 build_string (buffer));
7657 }
7658
7659 /* Close the input file and destroy the JPEG object. */
7660 if (fp)
7661 fclose (fp);
7662 jpeg_destroy_decompress (&cinfo);
7663
7664 BLOCK_INPUT;
7665
7666 /* If we already have an XImage, free that. */
7667 x_destroy_x_image (ximg);
7668
7669 /* Free pixmap and colors. */
7670 x_clear_image (f, img);
7671
7672 UNBLOCK_INPUT;
7673 UNGCPRO;
7674 return 0;
7675 }
7676
7677 /* Create the JPEG decompression object. Let it read from fp.
7678 Read the JPEG image header. */
7679 jpeg_create_decompress (&cinfo);
7680
7681 if (NILP (specified_data))
7682 jpeg_stdio_src (&cinfo, fp);
7683 else
7684 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
7685 STRING_BYTES (XSTRING (specified_data)));
7686
7687 jpeg_read_header (&cinfo, TRUE);
7688
7689 /* Customize decompression so that color quantization will be used.
7690 Start decompression. */
7691 cinfo.quantize_colors = TRUE;
7692 jpeg_start_decompress (&cinfo);
7693 width = img->width = cinfo.output_width;
7694 height = img->height = cinfo.output_height;
7695
7696 BLOCK_INPUT;
7697
7698 /* Create X image and pixmap. */
7699 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7700 &img->pixmap))
7701 {
7702 UNBLOCK_INPUT;
7703 longjmp (mgr.setjmp_buffer, 2);
7704 }
7705
7706 /* Allocate colors. When color quantization is used,
7707 cinfo.actual_number_of_colors has been set with the number of
7708 colors generated, and cinfo.colormap is a two-dimensional array
7709 of color indices in the range 0..cinfo.actual_number_of_colors.
7710 No more than 255 colors will be generated. */
7711 {
7712 int i, ir, ig, ib;
7713
7714 if (cinfo.out_color_components > 2)
7715 ir = 0, ig = 1, ib = 2;
7716 else if (cinfo.out_color_components > 1)
7717 ir = 0, ig = 1, ib = 0;
7718 else
7719 ir = 0, ig = 0, ib = 0;
7720
7721 /* Use the color table mechanism because it handles colors that
7722 cannot be allocated nicely. Such colors will be replaced with
7723 a default color, and we don't have to care about which colors
7724 can be freed safely, and which can't. */
7725 init_color_table ();
7726 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
7727 * sizeof *colors);
7728
7729 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
7730 {
7731 /* Multiply RGB values with 255 because X expects RGB values
7732 in the range 0..0xffff. */
7733 int r = cinfo.colormap[ir][i] << 8;
7734 int g = cinfo.colormap[ig][i] << 8;
7735 int b = cinfo.colormap[ib][i] << 8;
7736 colors[i] = lookup_rgb_color (f, r, g, b);
7737 }
7738
7739 /* Remember those colors actually allocated. */
7740 img->colors = colors_in_color_table (&img->ncolors);
7741 free_color_table ();
7742 }
7743
7744 /* Read pixels. */
7745 row_stride = width * cinfo.output_components;
7746 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
7747 row_stride, 1);
7748 for (y = 0; y < height; ++y)
7749 {
7750 jpeg_read_scanlines (&cinfo, buffer, 1);
7751 for (x = 0; x < cinfo.output_width; ++x)
7752 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
7753 }
7754
7755 /* Clean up. */
7756 jpeg_finish_decompress (&cinfo);
7757 jpeg_destroy_decompress (&cinfo);
7758 if (fp)
7759 fclose (fp);
7760
7761 /* Put the image into the pixmap. */
7762 x_put_x_image (f, ximg, img->pixmap, width, height);
7763 x_destroy_x_image (ximg);
7764 UNBLOCK_INPUT;
7765 UNGCPRO;
7766 return 1;
7767}
7768
7769#endif /* HAVE_JPEG */
7770
7771
7772
7773/***********************************************************************
7774 TIFF
7775 ***********************************************************************/
7776
7777#if HAVE_TIFF
7778
7779#include <tiffio.h>
7780
7781static int tiff_image_p P_ ((Lisp_Object object));
7782static int tiff_load P_ ((struct frame *f, struct image *img));
7783
7784/* The symbol `tiff' identifying images of this type. */
7785
7786Lisp_Object Qtiff;
7787
7788/* Indices of image specification fields in tiff_format, below. */
7789
7790enum tiff_keyword_index
7791{
7792 TIFF_TYPE,
7793 TIFF_DATA,
7794 TIFF_FILE,
7795 TIFF_ASCENT,
7796 TIFF_MARGIN,
7797 TIFF_RELIEF,
7798 TIFF_ALGORITHM,
7799 TIFF_HEURISTIC_MASK,
7800 TIFF_LAST
7801};
7802
7803/* Vector of image_keyword structures describing the format
7804 of valid user-defined image specifications. */
7805
7806static struct image_keyword tiff_format[TIFF_LAST] =
7807{
7808 {":type", IMAGE_SYMBOL_VALUE, 1},
7809 {":data", IMAGE_STRING_VALUE, 0},
7810 {":file", IMAGE_STRING_VALUE, 0},
7811 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7812 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7813 {":relief", IMAGE_INTEGER_VALUE, 0},
7814 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7815 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7816};
7817
7818/* Structure describing the image type `tiff'. */
7819
7820static struct image_type tiff_type =
7821{
7822 &Qtiff,
7823 tiff_image_p,
7824 tiff_load,
7825 x_clear_image,
7826 NULL
7827};
7828
7829
7830/* Return non-zero if OBJECT is a valid TIFF image specification. */
7831
7832static int
7833tiff_image_p (object)
7834 Lisp_Object object;
7835{
7836 struct image_keyword fmt[TIFF_LAST];
7837 bcopy (tiff_format, fmt, sizeof fmt);
7838
7839 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
7840 || (fmt[TIFF_ASCENT].count
7841 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
7842 return 0;
7843
7844 /* Must specify either the :data or :file keyword. */
7845 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
7846}
7847
7848
7849/* Reading from a memory buffer for TIFF images Based on the PNG
7850 memory source, but we have to provide a lot of extra functions.
7851 Blah.
7852
7853 We really only need to implement read and seek, but I am not
7854 convinced that the TIFF library is smart enough not to destroy
7855 itself if we only hand it the function pointers we need to
7856 override. */
7857
7858typedef struct
7859{
7860 unsigned char *bytes;
7861 size_t len;
7862 int index;
7863}
7864tiff_memory_source;
7865
7866static size_t
7867tiff_read_from_memory (data, buf, size)
7868 thandle_t data;
7869 tdata_t buf;
7870 tsize_t size;
7871{
7872 tiff_memory_source *src = (tiff_memory_source *) data;
7873
7874 if (size > src->len - src->index)
7875 return (size_t) -1;
7876 bcopy (src->bytes + src->index, buf, size);
7877 src->index += size;
7878 return size;
7879}
7880
7881static size_t
7882tiff_write_from_memory (data, buf, size)
7883 thandle_t data;
7884 tdata_t buf;
7885 tsize_t size;
7886{
7887 return (size_t) -1;
7888}
7889
7890static toff_t
7891tiff_seek_in_memory (data, off, whence)
7892 thandle_t data;
7893 toff_t off;
7894 int whence;
7895{
7896 tiff_memory_source *src = (tiff_memory_source *) data;
7897 int idx;
7898
7899 switch (whence)
7900 {
7901 case SEEK_SET: /* Go from beginning of source. */
7902 idx = off;
7903 break;
7904
7905 case SEEK_END: /* Go from end of source. */
7906 idx = src->len + off;
7907 break;
7908
7909 case SEEK_CUR: /* Go from current position. */
7910 idx = src->index + off;
7911 break;
7912
7913 default: /* Invalid `whence'. */
7914 return -1;
7915 }
7916
7917 if (idx > src->len || idx < 0)
7918 return -1;
7919
7920 src->index = idx;
7921 return src->index;
7922}
7923
7924static int
7925tiff_close_memory (data)
7926 thandle_t data;
7927{
7928 /* NOOP */
7929 return 0;
7930}
7931
7932static int
7933tiff_mmap_memory (data, pbase, psize)
7934 thandle_t data;
7935 tdata_t *pbase;
7936 toff_t *psize;
7937{
7938 /* It is already _IN_ memory. */
7939 return 0;
7940}
7941
7942static void
7943tiff_unmap_memory (data, base, size)
7944 thandle_t data;
7945 tdata_t base;
7946 toff_t size;
7947{
7948 /* We don't need to do this. */
7949}
7950
7951static toff_t
7952tiff_size_of_memory (data)
7953 thandle_t data;
7954{
7955 return ((tiff_memory_source *) data)->len;
7956}
7957
7958/* Load TIFF image IMG for use on frame F. Value is non-zero if
7959 successful. */
7960
7961static int
7962tiff_load (f, img)
7963 struct frame *f;
7964 struct image *img;
7965{
7966 Lisp_Object file, specified_file;
7967 Lisp_Object specified_data;
7968 TIFF *tiff;
7969 int width, height, x, y;
7970 uint32 *buf;
7971 int rc;
7972 XImage *ximg;
7973 struct gcpro gcpro1;
7974 tiff_memory_source memsrc;
7975
7976 specified_file = image_spec_value (img->spec, QCfile, NULL);
7977 specified_data = image_spec_value (img->spec, QCdata, NULL);
7978 file = Qnil;
7979 GCPRO1 (file);
7980
7981 if (NILP (specified_data))
7982 {
7983 /* Read from a file */
7984 file = x_find_image_file (specified_file);
7985 if (!STRINGP (file))
7986 {
7987 image_error ("Cannot find image file `%s'", file, Qnil);
7988 UNGCPRO;
7989 return 0;
7990 }
7991
7992 /* Try to open the image file. */
7993 tiff = TIFFOpen (XSTRING (file)->data, "r");
7994 if (tiff == NULL)
7995 {
7996 image_error ("Cannot open `%s'", file, Qnil);
7997 UNGCPRO;
7998 return 0;
7999 }
8000 }
8001 else
8002 {
8003 /* Memory source! */
8004 memsrc.bytes = XSTRING (specified_data)->data;
8005 memsrc.len = STRING_BYTES (XSTRING (specified_data));
8006 memsrc.index = 0;
8007
8008 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
8009 (TIFFReadWriteProc) tiff_read_from_memory,
8010 (TIFFReadWriteProc) tiff_write_from_memory,
8011 tiff_seek_in_memory,
8012 tiff_close_memory,
8013 tiff_size_of_memory,
8014 tiff_mmap_memory,
8015 tiff_unmap_memory);
8016
8017 if (!tiff)
8018 {
8019 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
8020 UNGCPRO;
8021 return 0;
8022 }
8023 }
8024
8025 /* Get width and height of the image, and allocate a raster buffer
8026 of width x height 32-bit values. */
8027 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8028 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8029 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
8030
8031 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8032 TIFFClose (tiff);
8033 if (!rc)
8034 {
8035 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
8036 xfree (buf);
8037 UNGCPRO;
8038 return 0;
8039 }
8040
8041 BLOCK_INPUT;
8042
8043 /* Create the X image and pixmap. */
8044 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8045 {
8046 UNBLOCK_INPUT;
8047 xfree (buf);
8048 UNGCPRO;
8049 return 0;
8050 }
8051
8052 /* Initialize the color table. */
8053 init_color_table ();
8054
8055 /* Process the pixel raster. Origin is in the lower-left corner. */
8056 for (y = 0; y < height; ++y)
8057 {
8058 uint32 *row = buf + y * width;
8059
8060 for (x = 0; x < width; ++x)
8061 {
8062 uint32 abgr = row[x];
8063 int r = TIFFGetR (abgr) << 8;
8064 int g = TIFFGetG (abgr) << 8;
8065 int b = TIFFGetB (abgr) << 8;
8066 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
8067 }
8068 }
8069
8070 /* Remember the colors allocated for the image. Free the color table. */
8071 img->colors = colors_in_color_table (&img->ncolors);
8072 free_color_table ();
8073
8074 /* Put the image into the pixmap, then free the X image and its buffer. */
8075 x_put_x_image (f, ximg, img->pixmap, width, height);
8076 x_destroy_x_image (ximg);
8077 xfree (buf);
8078 UNBLOCK_INPUT;
8079
8080 img->width = width;
8081 img->height = height;
8082
8083 UNGCPRO;
8084 return 1;
8085}
8086
8087#endif /* HAVE_TIFF != 0 */
8088
8089
8090
8091/***********************************************************************
8092 GIF
8093 ***********************************************************************/
8094
8095#if HAVE_GIF
8096
8097#include <gif_lib.h>
8098
8099static int gif_image_p P_ ((Lisp_Object object));
8100static int gif_load P_ ((struct frame *f, struct image *img));
8101
8102/* The symbol `gif' identifying images of this type. */
8103
8104Lisp_Object Qgif;
8105
8106/* Indices of image specification fields in gif_format, below. */
8107
8108enum gif_keyword_index
8109{
8110 GIF_TYPE,
8111 GIF_DATA,
8112 GIF_FILE,
8113 GIF_ASCENT,
8114 GIF_MARGIN,
8115 GIF_RELIEF,
8116 GIF_ALGORITHM,
8117 GIF_HEURISTIC_MASK,
8118 GIF_IMAGE,
8119 GIF_LAST
8120};
8121
8122/* Vector of image_keyword structures describing the format
8123 of valid user-defined image specifications. */
8124
8125static struct image_keyword gif_format[GIF_LAST] =
8126{
8127 {":type", IMAGE_SYMBOL_VALUE, 1},
8128 {":data", IMAGE_STRING_VALUE, 0},
8129 {":file", IMAGE_STRING_VALUE, 0},
8130 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8131 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8132 {":relief", IMAGE_INTEGER_VALUE, 0},
8133 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8134 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8135 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
8136};
8137
8138/* Structure describing the image type `gif'. */
8139
8140static struct image_type gif_type =
8141{
8142 &Qgif,
8143 gif_image_p,
8144 gif_load,
8145 x_clear_image,
8146 NULL
8147};
8148
8149/* Return non-zero if OBJECT is a valid GIF image specification. */
8150
8151static int
8152gif_image_p (object)
8153 Lisp_Object object;
8154{
8155 struct image_keyword fmt[GIF_LAST];
8156 bcopy (gif_format, fmt, sizeof fmt);
8157
8158 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
8159 || (fmt[GIF_ASCENT].count
8160 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
8161 return 0;
8162
8163 /* Must specify either the :data or :file keyword. */
8164 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
8165}
8166
8167/* Reading a GIF image from memory
8168 Based on the PNG memory stuff to a certain extent. */
8169
8170typedef struct
8171{
8172 unsigned char *bytes;
8173 size_t len;
8174 int index;
8175}
8176gif_memory_source;
8177
8178/* Make the current memory source available to gif_read_from_memory.
8179 It's done this way because not all versions of libungif support
8180 a UserData field in the GifFileType structure. */
8181static gif_memory_source *current_gif_memory_src;
8182
8183static int
8184gif_read_from_memory (file, buf, len)
8185 GifFileType *file;
8186 GifByteType *buf;
8187 int len;
8188{
8189 gif_memory_source *src = current_gif_memory_src;
8190
8191 if (len > src->len - src->index)
8192 return -1;
8193
8194 bcopy (src->bytes + src->index, buf, len);
8195 src->index += len;
8196 return len;
8197}
8198
8199
8200/* Load GIF image IMG for use on frame F. Value is non-zero if
8201 successful. */
8202
8203static int
8204gif_load (f, img)
8205 struct frame *f;
8206 struct image *img;
8207{
8208 Lisp_Object file, specified_file;
8209 Lisp_Object specified_data;
8210 int rc, width, height, x, y, i;
8211 XImage *ximg;
8212 ColorMapObject *gif_color_map;
8213 unsigned long pixel_colors[256];
8214 GifFileType *gif;
8215 struct gcpro gcpro1;
8216 Lisp_Object image;
8217 int ino, image_left, image_top, image_width, image_height;
8218 gif_memory_source memsrc;
8219 unsigned char *raster;
8220
8221 specified_file = image_spec_value (img->spec, QCfile, NULL);
8222 specified_data = image_spec_value (img->spec, QCdata, NULL);
8223 file = Qnil;
8224 GCPRO1 (file);
8225
8226 if (NILP (specified_data))
8227 {
8228 file = x_find_image_file (specified_file);
8229 if (!STRINGP (file))
8230 {
8231 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8232 UNGCPRO;
8233 return 0;
8234 }
8235
8236 /* Open the GIF file. */
8237 gif = DGifOpenFileName (XSTRING (file)->data);
8238 if (gif == NULL)
8239 {
8240 image_error ("Cannot open `%s'", file, Qnil);
8241 UNGCPRO;
8242 return 0;
8243 }
8244 }
8245 else
8246 {
8247 /* Read from memory! */
8248 current_gif_memory_src = &memsrc;
8249 memsrc.bytes = XSTRING (specified_data)->data;
8250 memsrc.len = STRING_BYTES (XSTRING (specified_data));
8251 memsrc.index = 0;
8252
8253 gif = DGifOpen(&memsrc, gif_read_from_memory);
8254 if (!gif)
8255 {
8256 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
8257 UNGCPRO;
8258 return 0;
8259 }
8260 }
8261
8262 /* Read entire contents. */
8263 rc = DGifSlurp (gif);
8264 if (rc == GIF_ERROR)
8265 {
8266 image_error ("Error reading `%s'", img->spec, Qnil);
8267 DGifCloseFile (gif);
8268 UNGCPRO;
8269 return 0;
8270 }
8271
8272 image = image_spec_value (img->spec, QCindex, NULL);
8273 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8274 if (ino >= gif->ImageCount)
8275 {
8276 image_error ("Invalid image number `%s' in image `%s'",
8277 image, img->spec);
8278 DGifCloseFile (gif);
8279 UNGCPRO;
8280 return 0;
8281 }
8282
8283 width = img->width = gif->SWidth;
8284 height = img->height = gif->SHeight;
8285
8286 BLOCK_INPUT;
8287
8288 /* Create the X image and pixmap. */
8289 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8290 {
8291 UNBLOCK_INPUT;
8292 DGifCloseFile (gif);
8293 UNGCPRO;
8294 return 0;
8295 }
8296
8297 /* Allocate colors. */
8298 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
8299 if (!gif_color_map)
8300 gif_color_map = gif->SColorMap;
8301 init_color_table ();
8302 bzero (pixel_colors, sizeof pixel_colors);
8303
8304 for (i = 0; i < gif_color_map->ColorCount; ++i)
8305 {
8306 int r = gif_color_map->Colors[i].Red << 8;
8307 int g = gif_color_map->Colors[i].Green << 8;
8308 int b = gif_color_map->Colors[i].Blue << 8;
8309 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
8310 }
8311
8312 img->colors = colors_in_color_table (&img->ncolors);
8313 free_color_table ();
8314
8315 /* Clear the part of the screen image that are not covered by
8316 the image from the GIF file. Full animated GIF support
8317 requires more than can be done here (see the gif89 spec,
8318 disposal methods). Let's simply assume that the part
8319 not covered by a sub-image is in the frame's background color. */
8320 image_top = gif->SavedImages[ino].ImageDesc.Top;
8321 image_left = gif->SavedImages[ino].ImageDesc.Left;
8322 image_width = gif->SavedImages[ino].ImageDesc.Width;
8323 image_height = gif->SavedImages[ino].ImageDesc.Height;
8324
8325 for (y = 0; y < image_top; ++y)
8326 for (x = 0; x < width; ++x)
8327 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8328
8329 for (y = image_top + image_height; y < height; ++y)
8330 for (x = 0; x < width; ++x)
8331 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8332
8333 for (y = image_top; y < image_top + image_height; ++y)
8334 {
8335 for (x = 0; x < image_left; ++x)
8336 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8337 for (x = image_left + image_width; x < width; ++x)
8338 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8339 }
8340
8341 /* Read the GIF image into the X image. We use a local variable
8342 `raster' here because RasterBits below is a char *, and invites
8343 problems with bytes >= 0x80. */
8344 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
8345
8346 if (gif->SavedImages[ino].ImageDesc.Interlace)
8347 {
8348 static int interlace_start[] = {0, 4, 2, 1};
8349 static int interlace_increment[] = {8, 8, 4, 2};
8350 int pass, inc;
8351 int row = interlace_start[0];
8352
8353 pass = 0;
8354
8355 for (y = 0; y < image_height; y++)
8356 {
8357 if (row >= image_height)
8358 {
8359 row = interlace_start[++pass];
8360 while (row >= image_height)
8361 row = interlace_start[++pass];
8362 }
8363
8364 for (x = 0; x < image_width; x++)
8365 {
8366 int i = raster[(y * image_width) + x];
8367 XPutPixel (ximg, x + image_left, row + image_top,
8368 pixel_colors[i]);
8369 }
8370
8371 row += interlace_increment[pass];
8372 }
8373 }
8374 else
8375 {
8376 for (y = 0; y < image_height; ++y)
8377 for (x = 0; x < image_width; ++x)
8378 {
8379 int i = raster[y* image_width + x];
8380 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
8381 }
8382 }
8383
8384 DGifCloseFile (gif);
8385
8386 /* Put the image into the pixmap, then free the X image and its buffer. */
8387 x_put_x_image (f, ximg, img->pixmap, width, height);
8388 x_destroy_x_image (ximg);
8389 UNBLOCK_INPUT;
8390
8391 UNGCPRO;
8392 return 1;
8393}
8394
8395#endif /* HAVE_GIF != 0 */
8396
8397
8398
8399/***********************************************************************
8400 Ghostscript
8401 ***********************************************************************/
8402
8403#ifdef HAVE_GHOSTSCRIPT
8404static int gs_image_p P_ ((Lisp_Object object));
8405static int gs_load P_ ((struct frame *f, struct image *img));
8406static void gs_clear_image P_ ((struct frame *f, struct image *img));
8407
8408/* The symbol `postscript' identifying images of this type. */
8409
8410Lisp_Object Qpostscript;
8411
8412/* Keyword symbols. */
8413
8414Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8415
8416/* Indices of image specification fields in gs_format, below. */
8417
8418enum gs_keyword_index
8419{
8420 GS_TYPE,
8421 GS_PT_WIDTH,
8422 GS_PT_HEIGHT,
8423 GS_FILE,
8424 GS_LOADER,
8425 GS_BOUNDING_BOX,
8426 GS_ASCENT,
8427 GS_MARGIN,
8428 GS_RELIEF,
8429 GS_ALGORITHM,
8430 GS_HEURISTIC_MASK,
8431 GS_LAST
8432};
8433
8434/* Vector of image_keyword structures describing the format
8435 of valid user-defined image specifications. */
8436
8437static struct image_keyword gs_format[GS_LAST] =
8438{
8439 {":type", IMAGE_SYMBOL_VALUE, 1},
8440 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8441 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8442 {":file", IMAGE_STRING_VALUE, 1},
8443 {":loader", IMAGE_FUNCTION_VALUE, 0},
8444 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8445 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8446 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8447 {":relief", IMAGE_INTEGER_VALUE, 0},
8448 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8449 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8450};
8451
8452/* Structure describing the image type `ghostscript'. */
8453
8454static struct image_type gs_type =
8455{
8456 &Qpostscript,
8457 gs_image_p,
8458 gs_load,
8459 gs_clear_image,
8460 NULL
8461};
8462
8463
8464/* Free X resources of Ghostscript image IMG which is used on frame F. */
8465
8466static void
8467gs_clear_image (f, img)
8468 struct frame *f;
8469 struct image *img;
8470{
8471 /* IMG->data.ptr_val may contain a recorded colormap. */
8472 xfree (img->data.ptr_val);
8473 x_clear_image (f, img);
8474}
8475
8476
8477/* Return non-zero if OBJECT is a valid Ghostscript image
8478 specification. */
8479
8480static int
8481gs_image_p (object)
8482 Lisp_Object object;
8483{
8484 struct image_keyword fmt[GS_LAST];
8485 Lisp_Object tem;
8486 int i;
8487
8488 bcopy (gs_format, fmt, sizeof fmt);
8489
8490 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
8491 || (fmt[GS_ASCENT].count
8492 && XFASTINT (fmt[GS_ASCENT].value) > 100))
8493 return 0;
8494
8495 /* Bounding box must be a list or vector containing 4 integers. */
8496 tem = fmt[GS_BOUNDING_BOX].value;
8497 if (CONSP (tem))
8498 {
8499 for (i = 0; i < 4; ++i, tem = XCDR (tem))
8500 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
8501 return 0;
8502 if (!NILP (tem))
8503 return 0;
8504 }
8505 else if (VECTORP (tem))
8506 {
8507 if (XVECTOR (tem)->size != 4)
8508 return 0;
8509 for (i = 0; i < 4; ++i)
8510 if (!INTEGERP (XVECTOR (tem)->contents[i]))
8511 return 0;
8512 }
8513 else
8514 return 0;
8515
8516 return 1;
8517}
8518
8519
8520/* Load Ghostscript image IMG for use on frame F. Value is non-zero
8521 if successful. */
8522
8523static int
8524gs_load (f, img)
8525 struct frame *f;
8526 struct image *img;
8527{
8528 char buffer[100];
8529 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
8530 struct gcpro gcpro1, gcpro2;
8531 Lisp_Object frame;
8532 double in_width, in_height;
8533 Lisp_Object pixel_colors = Qnil;
8534
8535 /* Compute pixel size of pixmap needed from the given size in the
8536 image specification. Sizes in the specification are in pt. 1 pt
8537 = 1/72 in, xdpi and ydpi are stored in the frame's X display
8538 info. */
8539 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
8540 in_width = XFASTINT (pt_width) / 72.0;
8541 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
8542 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
8543 in_height = XFASTINT (pt_height) / 72.0;
8544 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
8545
8546 /* Create the pixmap. */
8547 BLOCK_INPUT;
8548 xassert (img->pixmap == 0);
8549 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8550 img->width, img->height,
8551 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
8552 UNBLOCK_INPUT;
8553
8554 if (!img->pixmap)
8555 {
8556 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8557 return 0;
8558 }
8559
8560 /* Call the loader to fill the pixmap. It returns a process object
8561 if successful. We do not record_unwind_protect here because
8562 other places in redisplay like calling window scroll functions
8563 don't either. Let the Lisp loader use `unwind-protect' instead. */
8564 GCPRO2 (window_and_pixmap_id, pixel_colors);
8565
8566 sprintf (buffer, "%lu %lu",
8567 (unsigned long) FRAME_W32_WINDOW (f),
8568 (unsigned long) img->pixmap);
8569 window_and_pixmap_id = build_string (buffer);
8570
8571 sprintf (buffer, "%lu %lu",
8572 FRAME_FOREGROUND_PIXEL (f),
8573 FRAME_BACKGROUND_PIXEL (f));
8574 pixel_colors = build_string (buffer);
8575
8576 XSETFRAME (frame, f);
8577 loader = image_spec_value (img->spec, QCloader, NULL);
8578 if (NILP (loader))
8579 loader = intern ("gs-load-image");
8580
8581 img->data.lisp_val = call6 (loader, frame, img->spec,
8582 make_number (img->width),
8583 make_number (img->height),
8584 window_and_pixmap_id,
8585 pixel_colors);
8586 UNGCPRO;
8587 return PROCESSP (img->data.lisp_val);
8588}
8589
8590
8591/* Kill the Ghostscript process that was started to fill PIXMAP on
8592 frame F. Called from XTread_socket when receiving an event
8593 telling Emacs that Ghostscript has finished drawing. */
8594
8595void
8596x_kill_gs_process (pixmap, f)
8597 Pixmap pixmap;
8598 struct frame *f;
8599{
8600 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8601 int class, i;
8602 struct image *img;
8603
8604 /* Find the image containing PIXMAP. */
8605 for (i = 0; i < c->used; ++i)
8606 if (c->images[i]->pixmap == pixmap)
8607 break;
8608
8609 /* Kill the GS process. We should have found PIXMAP in the image
8610 cache and its image should contain a process object. */
8611 xassert (i < c->used);
8612 img = c->images[i];
8613 xassert (PROCESSP (img->data.lisp_val));
8614 Fkill_process (img->data.lisp_val, Qnil);
8615 img->data.lisp_val = Qnil;
8616
8617 /* On displays with a mutable colormap, figure out the colors
8618 allocated for the image by looking at the pixels of an XImage for
8619 img->pixmap. */
8620 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8621 if (class != StaticColor && class != StaticGray && class != TrueColor)
8622 {
8623 XImage *ximg;
8624
8625 BLOCK_INPUT;
8626
8627 /* Try to get an XImage for img->pixmep. */
8628 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
8629 0, 0, img->width, img->height, ~0, ZPixmap);
8630 if (ximg)
8631 {
8632 int x, y;
8633
8634 /* Initialize the color table. */
8635 init_color_table ();
8636
8637 /* For each pixel of the image, look its color up in the
8638 color table. After having done so, the color table will
8639 contain an entry for each color used by the image. */
8640 for (y = 0; y < img->height; ++y)
8641 for (x = 0; x < img->width; ++x)
8642 {
8643 unsigned long pixel = XGetPixel (ximg, x, y);
8644 lookup_pixel_color (f, pixel);
8645 }
8646
8647 /* Record colors in the image. Free color table and XImage. */
8648 img->colors = colors_in_color_table (&img->ncolors);
8649 free_color_table ();
8650 XDestroyImage (ximg);
8651
8652#if 0 /* This doesn't seem to be the case. If we free the colors
8653 here, we get a BadAccess later in x_clear_image when
8654 freeing the colors. */
8655 /* We have allocated colors once, but Ghostscript has also
8656 allocated colors on behalf of us. So, to get the
8657 reference counts right, free them once. */
8658 if (img->ncolors)
8659 {
8660 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
8661 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
8662 img->colors, img->ncolors, 0);
8663 }
8664#endif
8665 }
8666 else
8667 image_error ("Cannot get X image of `%s'; colors will not be freed",
8668 img->spec, Qnil);
8669
8670 UNBLOCK_INPUT;
8671 }
8672}
8673
8674#endif /* HAVE_GHOSTSCRIPT */
8675
8676
8677/***********************************************************************
8678 Window properties
8679 ***********************************************************************/
8680
8681DEFUN ("x-change-window-property", Fx_change_window_property,
8682 Sx_change_window_property, 2, 3, 0,
8683 "Change window property PROP to VALUE on the X window of FRAME.\n\
8684PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
8685selected frame. Value is VALUE.")
8686 (prop, value, frame)
8687 Lisp_Object frame, prop, value;
8688{
8689#if 0 /* MAC_TODO : port window properties to Mac */
8690 struct frame *f = check_x_frame (frame);
8691 Atom prop_atom;
8692
8693 CHECK_STRING (prop, 1);
8694 CHECK_STRING (value, 2);
8695
8696 BLOCK_INPUT;
8697 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
8698 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8699 prop_atom, XA_STRING, 8, PropModeReplace,
8700 XSTRING (value)->data, XSTRING (value)->size);
8701
8702 /* Make sure the property is set when we return. */
8703 XFlush (FRAME_W32_DISPLAY (f));
8704 UNBLOCK_INPUT;
8705
8706#endif /* MAC_TODO */
8707
8708 return value;
8709}
8710
8711
8712DEFUN ("x-delete-window-property", Fx_delete_window_property,
8713 Sx_delete_window_property, 1, 2, 0,
8714 "Remove window property PROP from X window of FRAME.\n\
8715FRAME nil or omitted means use the selected frame. Value is PROP.")
8716 (prop, frame)
8717 Lisp_Object prop, frame;
8718{
8719#if 0 /* MAC_TODO : port window properties to Mac */
8720
8721 struct frame *f = check_x_frame (frame);
8722 Atom prop_atom;
8723
8724 CHECK_STRING (prop, 1);
8725 BLOCK_INPUT;
8726 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
8727 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
8728
8729 /* Make sure the property is removed when we return. */
8730 XFlush (FRAME_W32_DISPLAY (f));
8731 UNBLOCK_INPUT;
8732#endif /* MAC_TODO */
8733
8734 return prop;
8735}
8736
8737
8738DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
8739 1, 2, 0,
8740 "Value is the value of window property PROP on FRAME.\n\
8741If FRAME is nil or omitted, use the selected frame. Value is nil\n\
8742if FRAME hasn't a property with name PROP or if PROP has no string\n\
8743value.")
8744 (prop, frame)
8745 Lisp_Object prop, frame;
8746{
8747#if 0 /* MAC_TODO : port window properties to Mac */
8748
8749 struct frame *f = check_x_frame (frame);
8750 Atom prop_atom;
8751 int rc;
8752 Lisp_Object prop_value = Qnil;
8753 char *tmp_data = NULL;
8754 Atom actual_type;
8755 int actual_format;
8756 unsigned long actual_size, bytes_remaining;
8757
8758 CHECK_STRING (prop, 1);
8759 BLOCK_INPUT;
8760 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
8761 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8762 prop_atom, 0, 0, False, XA_STRING,
8763 &actual_type, &actual_format, &actual_size,
8764 &bytes_remaining, (unsigned char **) &tmp_data);
8765 if (rc == Success)
8766 {
8767 int size = bytes_remaining;
8768
8769 XFree (tmp_data);
8770 tmp_data = NULL;
8771
8772 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8773 prop_atom, 0, bytes_remaining,
8774 False, XA_STRING,
8775 &actual_type, &actual_format,
8776 &actual_size, &bytes_remaining,
8777 (unsigned char **) &tmp_data);
8778 if (rc == Success)
8779 prop_value = make_string (tmp_data, size);
8780
8781 XFree (tmp_data);
8782 }
8783
8784 UNBLOCK_INPUT;
8785
8786 return prop_value;
8787
8788#endif /* MAC_TODO */
8789 return Qnil;
8790}
8791
8792
8793
8794/***********************************************************************
8795 Busy cursor
8796 ***********************************************************************/
8797
8798/* If non-null, an asynchronous timer that, when it expires, displays
8799 a busy cursor on all frames. */
8800
8801static struct atimer *busy_cursor_atimer;
8802
8803/* Non-zero means a busy cursor is currently shown. */
8804
8805static int busy_cursor_shown_p;
8806
8807/* Number of seconds to wait before displaying a busy cursor. */
8808
8809static Lisp_Object Vbusy_cursor_delay;
8810
8811/* Default number of seconds to wait before displaying a busy
8812 cursor. */
8813
8814#define DEFAULT_BUSY_CURSOR_DELAY 1
8815
8816/* Function prototypes. */
8817
8818static void show_busy_cursor P_ ((struct atimer *));
8819static void hide_busy_cursor P_ ((void));
8820
8821
8822/* Cancel a currently active busy-cursor timer, and start a new one. */
8823
8824void
8825start_busy_cursor ()
8826{
8827#if 0 /* MAC_TODO: cursor shape changes. */
8828 EMACS_TIME delay;
8829 int secs, usecs = 0;
8830
8831 cancel_busy_cursor ();
8832
8833 if (INTEGERP (Vbusy_cursor_delay)
8834 && XINT (Vbusy_cursor_delay) > 0)
8835 secs = XFASTINT (Vbusy_cursor_delay);
8836 else if (FLOATP (Vbusy_cursor_delay)
8837 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
8838 {
8839 Lisp_Object tem;
8840 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
8841 secs = XFASTINT (tem);
8842 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
8843 }
8844 else
8845 secs = DEFAULT_BUSY_CURSOR_DELAY;
8846
8847 EMACS_SET_SECS_USECS (delay, secs, usecs);
8848 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
8849 show_busy_cursor, NULL);
8850#endif
8851}
8852
8853
8854/* Cancel the busy cursor timer if active, hide a busy cursor if
8855 shown. */
8856
8857void
8858cancel_busy_cursor ()
8859{
8860 if (busy_cursor_atimer)
8861 {
8862 cancel_atimer (busy_cursor_atimer);
8863 busy_cursor_atimer = NULL;
8864 }
8865
8866 if (busy_cursor_shown_p)
8867 hide_busy_cursor ();
8868}
8869
8870
8871/* Timer function of busy_cursor_atimer. TIMER is equal to
8872 busy_cursor_atimer.
8873
8874 Display a busy cursor on all frames by mapping the frames'
8875 busy_window. Set the busy_p flag in the frames' output_data.x
8876 structure to indicate that a busy cursor is shown on the
8877 frames. */
8878
8879static void
8880show_busy_cursor (timer)
8881 struct atimer *timer;
8882{
8883#if 0 /* MAC_TODO: cursor shape changes. */
8884 /* The timer implementation will cancel this timer automatically
8885 after this function has run. Set busy_cursor_atimer to null
8886 so that we know the timer doesn't have to be canceled. */
8887 busy_cursor_atimer = NULL;
8888
8889 if (!busy_cursor_shown_p)
8890 {
8891 Lisp_Object rest, frame;
8892
8893 BLOCK_INPUT;
8894
8895 FOR_EACH_FRAME (rest, frame)
8896 if (FRAME_X_P (XFRAME (frame)))
8897 {
8898 struct frame *f = XFRAME (frame);
8899
8900 f->output_data.w32->busy_p = 1;
8901
8902 if (!f->output_data.w32->busy_window)
8903 {
8904 unsigned long mask = CWCursor;
8905 XSetWindowAttributes attrs;
8906
8907 attrs.cursor = f->output_data.w32->busy_cursor;
8908
8909 f->output_data.w32->busy_window
8910 = XCreateWindow (FRAME_X_DISPLAY (f),
8911 FRAME_OUTER_WINDOW (f),
8912 0, 0, 32000, 32000, 0, 0,
8913 InputOnly,
8914 CopyFromParent,
8915 mask, &attrs);
8916 }
8917
8918 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
8919 XFlush (FRAME_X_DISPLAY (f));
8920 }
8921
8922 busy_cursor_shown_p = 1;
8923 UNBLOCK_INPUT;
8924 }
8925#endif
8926}
8927
8928
8929/* Hide the busy cursor on all frames, if it is currently shown. */
8930
8931static void
8932hide_busy_cursor ()
8933{
8934#if 0 /* MAC_TODO: cursor shape changes. */
8935 if (busy_cursor_shown_p)
8936 {
8937 Lisp_Object rest, frame;
8938
8939 BLOCK_INPUT;
8940 FOR_EACH_FRAME (rest, frame)
8941 {
8942 struct frame *f = XFRAME (frame);
8943
8944 if (FRAME_X_P (f)
8945 /* Watch out for newly created frames. */
8946 && f->output_data.x->busy_window)
8947 {
8948 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
8949 /* Sync here because XTread_socket looks at the busy_p flag
8950 that is reset to zero below. */
8951 XSync (FRAME_X_DISPLAY (f), False);
8952 f->output_data.x->busy_p = 0;
8953 }
8954 }
8955
8956 busy_cursor_shown_p = 0;
8957 UNBLOCK_INPUT;
8958 }
8959#endif
8960}
8961
8962
8963
8964/***********************************************************************
8965 Tool tips
8966 ***********************************************************************/
8967
8968static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
8969 Lisp_Object));
8970
8971/* The frame of a currently visible tooltip, or null. */
8972
8973struct frame *tip_frame;
8974
8975/* If non-nil, a timer started that hides the last tooltip when it
8976 fires. */
8977
8978Lisp_Object tip_timer;
8979Window tip_window;
8980
8981/* Create a frame for a tooltip on the display described by DPYINFO.
8982 PARMS is a list of frame parameters. Value is the frame. */
8983
8984static Lisp_Object
8985x_create_tip_frame (dpyinfo, parms)
8986 struct w32_display_info *dpyinfo;
8987 Lisp_Object parms;
8988{
8989#if 0 /* MAC_TODO : Mac version */
8990 struct frame *f;
8991 Lisp_Object frame, tem;
8992 Lisp_Object name;
8993 long window_prompting = 0;
8994 int width, height;
8995 int count = specpdl_ptr - specpdl;
8996 struct gcpro gcpro1, gcpro2, gcpro3;
8997 struct kboard *kb;
8998
8999 check_x ();
9000
9001 /* Use this general default value to start with until we know if
9002 this frame has a specified name. */
9003 Vx_resource_name = Vinvocation_name;
9004
9005#ifdef MULTI_KBOARD
9006 kb = dpyinfo->kboard;
9007#else
9008 kb = &the_only_kboard;
9009#endif
9010
9011 /* Get the name of the frame to use for resource lookup. */
9012 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
9013 if (!STRINGP (name)
9014 && !EQ (name, Qunbound)
9015 && !NILP (name))
9016 error ("Invalid frame name--not a string or nil");
9017 Vx_resource_name = name;
9018
9019 frame = Qnil;
9020 GCPRO3 (parms, name, frame);
9021 tip_frame = f = make_frame (1);
9022 XSETFRAME (frame, f);
9023 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
9024
9025 f->output_method = output_w32;
9026 f->output_data.w32 =
9027 (struct w32_output *) xmalloc (sizeof (struct w32_output));
9028 bzero (f->output_data.w32, sizeof (struct w32_output));
9029#if 0
9030 f->output_data.w32->icon_bitmap = -1;
9031#endif
9032 f->output_data.w32->fontset = -1;
9033 f->icon_name = Qnil;
9034
9035#ifdef MULTI_KBOARD
9036 FRAME_KBOARD (f) = kb;
9037#endif
9038 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9039 f->output_data.w32->explicit_parent = 0;
9040
9041 /* Set the name; the functions to which we pass f expect the name to
9042 be set. */
9043 if (EQ (name, Qunbound) || NILP (name))
9044 {
9045 f->name = build_string (dpyinfo->x_id_name);
9046 f->explicit_name = 0;
9047 }
9048 else
9049 {
9050 f->name = name;
9051 f->explicit_name = 1;
9052 /* use the frame's title when getting resources for this frame. */
9053 specbind (Qx_resource_name, name);
9054 }
9055
9056 /* Extract the window parameters from the supplied values
9057 that are needed to determine window geometry. */
9058 {
9059 Lisp_Object font;
9060
9061 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
9062
9063 BLOCK_INPUT;
9064 /* First, try whatever font the caller has specified. */
9065 if (STRINGP (font))
9066 {
9067 tem = Fquery_fontset (font, Qnil);
9068 if (STRINGP (tem))
9069 font = x_new_fontset (f, XSTRING (tem)->data);
9070 else
9071 font = x_new_font (f, XSTRING (font)->data);
9072 }
9073
9074 /* Try out a font which we hope has bold and italic variations. */
9075 if (!STRINGP (font))
9076 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
9077 if (!STRINGP (font))
9078 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9079 if (! STRINGP (font))
9080 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9081 if (! STRINGP (font))
9082 /* This was formerly the first thing tried, but it finds too many fonts
9083 and takes too long. */
9084 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
9085 /* If those didn't work, look for something which will at least work. */
9086 if (! STRINGP (font))
9087 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
9088 UNBLOCK_INPUT;
9089 if (! STRINGP (font))
9090 font = build_string ("fixed");
9091
9092 x_default_parameter (f, parms, Qfont, font,
9093 "font", "Font", RES_TYPE_STRING);
9094 }
9095
9096 x_default_parameter (f, parms, Qborder_width, make_number (2),
9097 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
9098
9099 /* This defaults to 2 in order to match xterm. We recognize either
9100 internalBorderWidth or internalBorder (which is what xterm calls
9101 it). */
9102 if (NILP (Fassq (Qinternal_border_width, parms)))
9103 {
9104 Lisp_Object value;
9105
9106 value = w32_get_arg (parms, Qinternal_border_width,
9107 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
9108 if (! EQ (value, Qunbound))
9109 parms = Fcons (Fcons (Qinternal_border_width, value),
9110 parms);
9111 }
9112
9113 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
9114 "internalBorderWidth", "internalBorderWidth",
9115 RES_TYPE_NUMBER);
9116
9117 /* Also do the stuff which must be set before the window exists. */
9118 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
9119 "foreground", "Foreground", RES_TYPE_STRING);
9120 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
9121 "background", "Background", RES_TYPE_STRING);
9122 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
9123 "pointerColor", "Foreground", RES_TYPE_STRING);
9124 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
9125 "cursorColor", "Foreground", RES_TYPE_STRING);
9126 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
9127 "borderColor", "BorderColor", RES_TYPE_STRING);
9128
9129 /* Init faces before x_default_parameter is called for scroll-bar
9130 parameters because that function calls x_set_scroll_bar_width,
9131 which calls change_frame_size, which calls Fset_window_buffer,
9132 which runs hooks, which call Fvertical_motion. At the end, we
9133 end up in init_iterator with a null face cache, which should not
9134 happen. */
9135 init_frame_faces (f);
9136
9137 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9138 window_prompting = x_figure_window_size (f, parms);
9139
9140 if (window_prompting & XNegative)
9141 {
9142 if (window_prompting & YNegative)
9143 f->output_data.w32->win_gravity = SouthEastGravity;
9144 else
9145 f->output_data.w32->win_gravity = NorthEastGravity;
9146 }
9147 else
9148 {
9149 if (window_prompting & YNegative)
9150 f->output_data.w32->win_gravity = SouthWestGravity;
9151 else
9152 f->output_data.w32->win_gravity = NorthWestGravity;
9153 }
9154
9155 f->output_data.w32->size_hint_flags = window_prompting;
9156 {
9157 XSetWindowAttributes attrs;
9158 unsigned long mask;
9159
9160 BLOCK_INPUT;
9161 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
9162 /* Window managers looks at the override-redirect flag to
9163 determine whether or net to give windows a decoration (Xlib
9164 3.2.8). */
9165 attrs.override_redirect = True;
9166 attrs.save_under = True;
9167 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
9168 /* Arrange for getting MapNotify and UnmapNotify events. */
9169 attrs.event_mask = StructureNotifyMask;
9170 tip_window
9171 = FRAME_W32_WINDOW (f)
9172 = XCreateWindow (FRAME_W32_DISPLAY (f),
9173 FRAME_W32_DISPLAY_INFO (f)->root_window,
9174 /* x, y, width, height */
9175 0, 0, 1, 1,
9176 /* Border. */
9177 1,
9178 CopyFromParent, InputOutput, CopyFromParent,
9179 mask, &attrs);
9180 UNBLOCK_INPUT;
9181 }
9182
9183 x_make_gc (f);
9184
9185 x_default_parameter (f, parms, Qauto_raise, Qnil,
9186 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9187 x_default_parameter (f, parms, Qauto_lower, Qnil,
9188 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9189 x_default_parameter (f, parms, Qcursor_type, Qbox,
9190 "cursorType", "CursorType", RES_TYPE_SYMBOL);
9191
9192 /* Dimensions, especially f->height, must be done via change_frame_size.
9193 Change will not be effected unless different from the current
9194 f->height. */
9195 width = f->width;
9196 height = f->height;
9197 f->height = 0;
9198 SET_FRAME_WIDTH (f, 0);
9199 change_frame_size (f, height, width, 1, 0, 0);
9200
9201 f->no_split = 1;
9202
9203 UNGCPRO;
9204
9205 /* It is now ok to make the frame official even if we get an error
9206 below. And the frame needs to be on Vframe_list or making it
9207 visible won't work. */
9208 Vframe_list = Fcons (frame, Vframe_list);
9209
9210 /* Now that the frame is official, it counts as a reference to
9211 its display. */
9212 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
9213
9214 return unbind_to (count, frame);
9215#endif /* MAC_TODO */
9216 return Qnil;
9217}
9218
9219
9220DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
9221 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
9222A tooltip window is a small X window displaying STRING at\n\
9223the current mouse position.\n\
9224FRAME nil or omitted means use the selected frame.\n\
9225PARMS is an optional list of frame parameters which can be\n\
9226used to change the tooltip's appearance.\n\
9227Automatically hide the tooltip after TIMEOUT seconds.\n\
9228TIMEOUT nil means use the default timeout of 5 seconds.")
9229 (string, frame, parms, timeout)
9230 Lisp_Object string, frame, parms, timeout;
9231{
9232 struct frame *f;
9233 struct window *w;
9234 Window root, child;
9235 Lisp_Object buffer;
9236 struct buffer *old_buffer;
9237 struct text_pos pos;
9238 int i, width, height;
9239 int root_x, root_y, win_x, win_y;
9240 unsigned pmask;
9241 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
9242 int old_windows_or_buffers_changed = windows_or_buffers_changed;
9243 int count = specpdl_ptr - specpdl;
9244
9245 specbind (Qinhibit_redisplay, Qt);
9246
9247 GCPRO4 (string, parms, frame, timeout);
9248
9249 CHECK_STRING (string, 0);
9250 f = check_x_frame (frame);
9251 if (NILP (timeout))
9252 timeout = make_number (5);
9253 else
9254 CHECK_NATNUM (timeout, 2);
9255
9256 /* Hide a previous tip, if any. */
9257 Fx_hide_tip ();
9258
9259 /* Add default values to frame parameters. */
9260 if (NILP (Fassq (Qname, parms)))
9261 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
9262 if (NILP (Fassq (Qinternal_border_width, parms)))
9263 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
9264 if (NILP (Fassq (Qborder_width, parms)))
9265 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
9266 if (NILP (Fassq (Qborder_color, parms)))
9267 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
9268 if (NILP (Fassq (Qbackground_color, parms)))
9269 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
9270 parms);
9271
9272 /* Create a frame for the tooltip, and record it in the global
9273 variable tip_frame. */
9274 frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms);
9275 tip_frame = f = XFRAME (frame);
9276
9277 /* Set up the frame's root window. Currently we use a size of 80
9278 columns x 40 lines. If someone wants to show a larger tip, he
9279 will loose. I don't think this is a realistic case. */
9280 w = XWINDOW (FRAME_ROOT_WINDOW (f));
9281 w->left = w->top = make_number (0);
9282 w->width = 80;
9283 w->height = 40;
9284 adjust_glyphs (f);
9285 w->pseudo_window_p = 1;
9286
9287 /* Display the tooltip text in a temporary buffer. */
9288 buffer = Fget_buffer_create (build_string (" *tip*"));
9289 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
9290 old_buffer = current_buffer;
9291 set_buffer_internal_1 (XBUFFER (buffer));
9292 Ferase_buffer ();
9293 Finsert (make_number (1), &string);
9294 clear_glyph_matrix (w->desired_matrix);
9295 clear_glyph_matrix (w->current_matrix);
9296 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
9297 try_window (FRAME_ROOT_WINDOW (f), pos);
9298
9299 /* Compute width and height of the tooltip. */
9300 width = height = 0;
9301 for (i = 0; i < w->desired_matrix->nrows; ++i)
9302 {
9303 struct glyph_row *row = &w->desired_matrix->rows[i];
9304 struct glyph *last;
9305 int row_width;
9306
9307 /* Stop at the first empty row at the end. */
9308 if (!row->enabled_p || !row->displays_text_p)
9309 break;
9310
9311 /* Let the row go over the full width of the frame. */
9312 row->full_width_p = 1;
9313
9314 /* There's a glyph at the end of rows that is use to place
9315 the cursor there. Don't include the width of this glyph. */
9316 if (row->used[TEXT_AREA])
9317 {
9318 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
9319 row_width = row->pixel_width - last->pixel_width;
9320 }
9321 else
9322 row_width = row->pixel_width;
9323
9324 height += row->height;
9325 width = max (width, row_width);
9326 }
9327
9328 /* Add the frame's internal border to the width and height the X
9329 window should have. */
9330 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9331 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9332
9333 /* Move the tooltip window where the mouse pointer is. Resize and
9334 show it. */
9335#if 0 /* MAC_TODO : Mac specifics */
9336 BLOCK_INPUT;
9337 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
9338 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
9339 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9340 root_x + 5, root_y - height - 5, width, height);
9341 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
9342 UNBLOCK_INPUT;
9343#endif /* MAC_TODO */
9344
9345 /* Draw into the window. */
9346 w->must_be_updated_p = 1;
9347 update_single_window (w, 1);
9348
9349 /* Restore original current buffer. */
9350 set_buffer_internal_1 (old_buffer);
9351 windows_or_buffers_changed = old_windows_or_buffers_changed;
9352
9353 /* Let the tip disappear after timeout seconds. */
9354 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
9355 intern ("x-hide-tip"));
9356
9357 UNGCPRO;
9358 return unbind_to (count, Qnil);
9359}
9360
9361DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
9362 "Hide the current tooltip window, if there is any.\n\
9363Value is t is tooltip was open, nil otherwise.")
9364 ()
9365{
9366 int count = specpdl_ptr - specpdl;
9367 int deleted_p = 0;
9368
9369 specbind (Qinhibit_redisplay, Qt);
9370
9371 if (!NILP (tip_timer))
9372 {
9373 call1 (intern ("cancel-timer"), tip_timer);
9374 tip_timer = Qnil;
9375 }
9376
9377 if (tip_frame)
9378 {
9379 Lisp_Object frame;
9380
9381 XSETFRAME (frame, tip_frame);
9382 Fdelete_frame (frame, Qt);
9383 tip_frame = NULL;
9384 deleted_p = 1;
9385 }
9386
9387 return unbind_to (count, deleted_p ? Qt : Qnil);
9388}
9389
9390
9391
9392/***********************************************************************
9393 File selection dialog
9394 ***********************************************************************/
9395
9396#if 0 /* MAC_TODO: can standard file dialog */
9397extern Lisp_Object Qfile_name_history;
9398
9399DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
9400 "Read file name, prompting with PROMPT in directory DIR.\n\
9401Use a file selection dialog.\n\
9402Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
9403specified. Don't let the user enter a file name in the file\n\
9404selection dialog's entry field, if MUSTMATCH is non-nil.")
9405 (prompt, dir, default_filename, mustmatch)
9406 Lisp_Object prompt, dir, default_filename, mustmatch;
9407{
9408 struct frame *f = SELECTED_FRAME ();
9409 Lisp_Object file = Qnil;
9410 int count = specpdl_ptr - specpdl;
9411 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
9412 char filename[MAX_PATH + 1];
9413 char init_dir[MAX_PATH + 1];
9414 int use_dialog_p = 1;
9415
9416 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
9417 CHECK_STRING (prompt, 0);
9418 CHECK_STRING (dir, 1);
9419
9420 /* Create the dialog with PROMPT as title, using DIR as initial
9421 directory and using "*" as pattern. */
9422 dir = Fexpand_file_name (dir, Qnil);
9423 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
9424 init_dir[MAX_PATH] = '\0';
9425 unixtodos_filename (init_dir);
9426
9427 if (STRINGP (default_filename))
9428 {
9429 char *file_name_only;
9430 char *full_path_name = XSTRING (default_filename)->data;
9431
9432 unixtodos_filename (full_path_name);
9433
9434 file_name_only = strrchr (full_path_name, '\\');
9435 if (!file_name_only)
9436 file_name_only = full_path_name;
9437 else
9438 {
9439 file_name_only++;
9440
9441 /* If default_file_name is a directory, don't use the open
9442 file dialog, as it does not support selecting
9443 directories. */
9444 if (!(*file_name_only))
9445 use_dialog_p = 0;
9446 }
9447
9448 strncpy (filename, file_name_only, MAX_PATH);
9449 filename[MAX_PATH] = '\0';
9450 }
9451 else
9452 filename[0] = '\0';
9453
9454 if (use_dialog_p)
9455 {
9456 OPENFILENAME file_details;
9457 char *filename_file;
9458
9459 /* Prevent redisplay. */
9460 specbind (Qinhibit_redisplay, Qt);
9461 BLOCK_INPUT;
9462
9463 bzero (&file_details, sizeof (file_details));
9464 file_details.lStructSize = sizeof (file_details);
9465 file_details.hwndOwner = FRAME_W32_WINDOW (f);
9466 file_details.lpstrFile = filename;
9467 file_details.nMaxFile = sizeof (filename);
9468 file_details.lpstrInitialDir = init_dir;
9469 file_details.lpstrTitle = XSTRING (prompt)->data;
9470 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
9471
9472 if (!NILP (mustmatch))
9473 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
9474
9475 if (GetOpenFileName (&file_details))
9476 {
9477 dostounix_filename (filename);
9478 file = build_string (filename);
9479 }
9480 else
9481 file = Qnil;
9482
9483 UNBLOCK_INPUT;
9484 file = unbind_to (count, file);
9485 }
9486 /* Open File dialog will not allow folders to be selected, so resort
9487 to minibuffer completing reads for directories. */
9488 else
9489 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
9490 dir, mustmatch, dir, Qfile_name_history,
9491 default_filename, Qnil);
9492
9493 UNGCPRO;
9494
9495 /* Make "Cancel" equivalent to C-g. */
9496 if (NILP (file))
9497 Fsignal (Qquit, Qnil);
9498
9499 return unbind_to (count, file);
9500}
9501#endif
9502
9503
9504
9505/***********************************************************************
9506 Tests
9507 ***********************************************************************/
9508
9509#if GLYPH_DEBUG
9510
9511DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
9512 "Value is non-nil if SPEC is a valid image specification.")
9513 (spec)
9514 Lisp_Object spec;
9515{
9516 return valid_image_p (spec) ? Qt : Qnil;
9517}
9518
9519
9520DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
9521 (spec)
9522 Lisp_Object spec;
9523{
9524 int id = -1;
9525
9526 if (valid_image_p (spec))
9527 id = lookup_image (SELECTED_FRAME (), spec);
9528
9529 debug_print (spec);
9530 return make_number (id);
9531}
9532
9533#endif /* GLYPH_DEBUG != 0 */
9534
9535
9536
9537void
9538syms_of_macfns ()
9539{
9540 /* Certainly running on Mac. */
9541 mac_in_use = 1;
9542
9543 /* The section below is built by the lisp expression at the top of the file,
9544 just above where these variables are declared. */
9545 /*&&& init symbols here &&&*/
9546 Qauto_raise = intern ("auto-raise");
9547 staticpro (&Qauto_raise);
9548 Qauto_lower = intern ("auto-lower");
9549 staticpro (&Qauto_lower);
9550 Qbar = intern ("bar");
9551 staticpro (&Qbar);
9552 Qborder_color = intern ("border-color");
9553 staticpro (&Qborder_color);
9554 Qborder_width = intern ("border-width");
9555 staticpro (&Qborder_width);
9556 Qbox = intern ("box");
9557 staticpro (&Qbox);
9558 Qcursor_color = intern ("cursor-color");
9559 staticpro (&Qcursor_color);
9560 Qcursor_type = intern ("cursor-type");
9561 staticpro (&Qcursor_type);
9562 Qgeometry = intern ("geometry");
9563 staticpro (&Qgeometry);
9564 Qicon_left = intern ("icon-left");
9565 staticpro (&Qicon_left);
9566 Qicon_top = intern ("icon-top");
9567 staticpro (&Qicon_top);
9568 Qicon_type = intern ("icon-type");
9569 staticpro (&Qicon_type);
9570 Qicon_name = intern ("icon-name");
9571 staticpro (&Qicon_name);
9572 Qinternal_border_width = intern ("internal-border-width");
9573 staticpro (&Qinternal_border_width);
9574 Qleft = intern ("left");
9575 staticpro (&Qleft);
9576 Qright = intern ("right");
9577 staticpro (&Qright);
9578 Qmouse_color = intern ("mouse-color");
9579 staticpro (&Qmouse_color);
9580 Qnone = intern ("none");
9581 staticpro (&Qnone);
9582 Qparent_id = intern ("parent-id");
9583 staticpro (&Qparent_id);
9584 Qscroll_bar_width = intern ("scroll-bar-width");
9585 staticpro (&Qscroll_bar_width);
9586 Qsuppress_icon = intern ("suppress-icon");
9587 staticpro (&Qsuppress_icon);
9588 Qundefined_color = intern ("undefined-color");
9589 staticpro (&Qundefined_color);
9590 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
9591 staticpro (&Qvertical_scroll_bars);
9592 Qvisibility = intern ("visibility");
9593 staticpro (&Qvisibility);
9594 Qwindow_id = intern ("window-id");
9595 staticpro (&Qwindow_id);
9596 Qx_frame_parameter = intern ("x-frame-parameter");
9597 staticpro (&Qx_frame_parameter);
9598 Qx_resource_name = intern ("x-resource-name");
9599 staticpro (&Qx_resource_name);
9600 Quser_position = intern ("user-position");
9601 staticpro (&Quser_position);
9602 Quser_size = intern ("user-size");
9603 staticpro (&Quser_size);
9604 Qscreen_gamma = intern ("screen-gamma");
9605 staticpro (&Qscreen_gamma);
9606 Qline_spacing = intern ("line-spacing");
9607 staticpro (&Qline_spacing);
9608 Qcenter = intern ("center");
9609 staticpro (&Qcenter);
9610 /* This is the end of symbol initialization. */
9611
9612 Qhyper = intern ("hyper");
9613 staticpro (&Qhyper);
9614 Qsuper = intern ("super");
9615 staticpro (&Qsuper);
9616 Qmeta = intern ("meta");
9617 staticpro (&Qmeta);
9618 Qalt = intern ("alt");
9619 staticpro (&Qalt);
9620 Qctrl = intern ("ctrl");
9621 staticpro (&Qctrl);
9622 Qcontrol = intern ("control");
9623 staticpro (&Qcontrol);
9624 Qshift = intern ("shift");
9625 staticpro (&Qshift);
9626
9627 /* Text property `display' should be nonsticky by default. */
9628 Vtext_property_default_nonsticky
9629 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
9630
9631
9632 Qlaplace = intern ("laplace");
9633 staticpro (&Qlaplace);
9634
9635 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
9636 staticpro (&Qface_set_after_frame_default);
9637
9638 Fput (Qundefined_color, Qerror_conditions,
9639 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
9640 Fput (Qundefined_color, Qerror_message,
9641 build_string ("Undefined color"));
9642
9643 init_x_parm_symbols ();
9644
9645 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
9646 "List of directories to search for bitmap files for w32.");
9647 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
9648
9649 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
9650 "The shape of the pointer when over text.\n\
9651Changing the value does not affect existing frames\n\
9652unless you set the mouse color.");
9653 Vx_pointer_shape = Qnil;
9654
9655 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
9656 "The name Emacs uses to look up resources; for internal use only.\n\
9657`x-get-resource' uses this as the first component of the instance name\n\
9658when requesting resource values.\n\
9659Emacs initially sets `x-resource-name' to the name under which Emacs\n\
9660was invoked, or to the value specified with the `-name' or `-rn'\n\
9661switches, if present.");
9662 Vx_resource_name = Qnil;
9663
9664 Vx_nontext_pointer_shape = Qnil;
9665
9666 Vx_mode_pointer_shape = Qnil;
9667
9668 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
9669 "The shape of the pointer when Emacs is busy.\n\
9670This variable takes effect when you create a new frame\n\
9671or when you set the mouse color.");
9672 Vx_busy_pointer_shape = Qnil;
9673
9674 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
9675 "Non-zero means Emacs displays a busy cursor on window systems.");
9676 display_busy_cursor_p = 1;
9677
9678 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
9679 "*Seconds to wait before displaying a busy-cursor.\n\
9680Value must be an integer or float.");
9681 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
9682
9683 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
9684 &Vx_sensitive_text_pointer_shape,
9685 "The shape of the pointer when over mouse-sensitive text.\n\
9686This variable takes effect when you create a new frame\n\
9687or when you set the mouse color.");
9688 Vx_sensitive_text_pointer_shape = Qnil;
9689
9690 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
9691 "A string indicating the foreground color of the cursor box.");
9692 Vx_cursor_fore_pixel = Qnil;
9693
9694 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
9695 "Non-nil if no window manager is in use.\n\
9696Emacs doesn't try to figure this out; this is always nil\n\
9697unless you set it to something else.");
9698 /* We don't have any way to find this out, so set it to nil
9699 and maybe the user would like to set it to t. */
9700 Vx_no_window_manager = Qnil;
9701
9702 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
9703 &Vx_pixel_size_width_font_regexp,
9704 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
9705\n\
9706Since Emacs gets width of a font matching with this regexp from\n\
9707PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
9708such a font. This is especially effective for such large fonts as\n\
9709Chinese, Japanese, and Korean.");
9710 Vx_pixel_size_width_font_regexp = Qnil;
9711
9712 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
9713 "Time after which cached images are removed from the cache.\n\
9714When an image has not been displayed this many seconds, remove it\n\
9715from the image cache. Value must be an integer or nil with nil\n\
9716meaning don't clear the cache.");
9717 Vimage_cache_eviction_delay = make_number (30 * 60);
9718
9719#if 0 /* MAC_TODO: implement get X resource */
9720 defsubr (&Sx_get_resource);
9721#endif
9722 defsubr (&Sx_change_window_property);
9723 defsubr (&Sx_delete_window_property);
9724 defsubr (&Sx_window_property);
9725 defsubr (&Sxw_display_color_p);
9726 defsubr (&Sx_display_grayscale_p);
9727 defsubr (&Sxw_color_defined_p);
9728 defsubr (&Sxw_color_values);
9729 defsubr (&Sx_server_max_request_size);
9730 defsubr (&Sx_server_vendor);
9731 defsubr (&Sx_server_version);
9732 defsubr (&Sx_display_pixel_width);
9733 defsubr (&Sx_display_pixel_height);
9734 defsubr (&Sx_display_mm_width);
9735 defsubr (&Sx_display_mm_height);
9736 defsubr (&Sx_display_screens);
9737 defsubr (&Sx_display_planes);
9738 defsubr (&Sx_display_color_cells);
9739 defsubr (&Sx_display_visual_class);
9740 defsubr (&Sx_display_backing_store);
9741 defsubr (&Sx_display_save_under);
9742#if 0 /* MAC_TODO: implement XParseGeometry */
9743 defsubr (&Sx_parse_geometry);
9744#endif
9745 defsubr (&Sx_create_frame);
9746#if 0 /* MAC_TODO: implement network support */
9747 defsubr (&Sx_open_connection);
9748 defsubr (&Sx_close_connection);
9749#endif
9750 defsubr (&Sx_display_list);
9751 defsubr (&Sx_synchronize);
9752
9753 /* Setting callback functions for fontset handler. */
9754 get_font_info_func = x_get_font_info;
9755
9756#if 0 /* This function pointer doesn't seem to be used anywhere.
9757 And the pointer assigned has the wrong type, anyway. */
9758 list_fonts_func = x_list_fonts;
9759#endif
9760
9761 load_font_func = x_load_font;
9762 find_ccl_program_func = x_find_ccl_program;
9763 query_font_func = x_query_font;
9764
9765 set_frame_fontset_func = x_set_font;
9766 check_window_system_func = check_mac;
9767
9768#if 0 /* MAC_TODO: Image support for Mac Images. */
9769 Qxbm = intern ("xbm");
9770 staticpro (&Qxbm);
9771 QCtype = intern (":type");
9772 staticpro (&QCtype);
9773 QCalgorithm = intern (":algorithm");
9774 staticpro (&QCalgorithm);
9775 QCheuristic_mask = intern (":heuristic-mask");
9776 staticpro (&QCheuristic_mask);
9777 QCcolor_symbols = intern (":color-symbols");
9778 staticpro (&QCcolor_symbols);
9779 QCascent = intern (":ascent");
9780 staticpro (&QCascent);
9781 QCmargin = intern (":margin");
9782 staticpro (&QCmargin);
9783 QCrelief = intern (":relief");
9784 staticpro (&QCrelief);
9785 Qpostscript = intern ("postscript");
9786 staticpro (&Qpostscript);
9787 QCloader = intern (":loader");
9788 staticpro (&QCloader);
9789 QCbounding_box = intern (":bounding-box");
9790 staticpro (&QCbounding_box);
9791 QCpt_width = intern (":pt-width");
9792 staticpro (&QCpt_width);
9793 QCpt_height = intern (":pt-height");
9794 staticpro (&QCpt_height);
9795 QCindex = intern (":index");
9796 staticpro (&QCindex);
9797 Qpbm = intern ("pbm");
9798 staticpro (&Qpbm);
9799
9800#if HAVE_XPM
9801 Qxpm = intern ("xpm");
9802 staticpro (&Qxpm);
9803#endif
9804
9805#if HAVE_JPEG
9806 Qjpeg = intern ("jpeg");
9807 staticpro (&Qjpeg);
9808#endif
9809
9810#if HAVE_TIFF
9811 Qtiff = intern ("tiff");
9812 staticpro (&Qtiff);
9813#endif
9814
9815#if HAVE_GIF
9816 Qgif = intern ("gif");
9817 staticpro (&Qgif);
9818#endif
9819
9820#if HAVE_PNG
9821 Qpng = intern ("png");
9822 staticpro (&Qpng);
9823#endif
9824
9825 defsubr (&Sclear_image_cache);
9826
9827#if GLYPH_DEBUG
9828 defsubr (&Simagep);
9829 defsubr (&Slookup_image);
9830#endif
9831#endif /* MAC_TODO */
9832
9833 busy_cursor_atimer = NULL;
9834 busy_cursor_shown_p = 0;
9835
9836 defsubr (&Sx_show_tip);
9837 defsubr (&Sx_hide_tip);
9838 staticpro (&tip_timer);
9839 tip_timer = Qnil;
9840
9841#if 0 /* MAC_TODO */
9842 defsubr (&Sx_file_dialog);
9843#endif
9844}
9845
9846
9847void
9848init_xfns ()
9849{
9850 image_types = NULL;
9851 Vimage_types = Qnil;
9852
9853 define_image_type (&xbm_type);
9854#if 0 /* NTEMACS_TODO : Image support for W32 */
9855 define_image_type (&gs_type);
9856 define_image_type (&pbm_type);
9857
9858#if HAVE_XPM
9859 define_image_type (&xpm_type);
9860#endif
9861
9862#if HAVE_JPEG
9863 define_image_type (&jpeg_type);
9864#endif
9865
9866#if HAVE_TIFF
9867 define_image_type (&tiff_type);
9868#endif
9869
9870#if HAVE_GIF
9871 define_image_type (&gif_type);
9872#endif
9873
9874#if HAVE_PNG
9875 define_image_type (&png_type);
9876#endif
9877#endif /* NTEMACS_TODO */
9878}
9879
9880#undef abort
9881
9882#if 0
9883void
9884w32_abort()
9885{
9886 int button;
9887 button = MessageBox (NULL,
9888 "A fatal error has occurred!\n\n"
9889 "Select Abort to exit, Retry to debug, Ignore to continue",
9890 "Emacs Abort Dialog",
9891 MB_ICONEXCLAMATION | MB_TASKMODAL
9892 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
9893 switch (button)
9894 {
9895 case IDRETRY:
9896 DebugBreak ();
9897 break;
9898 case IDIGNORE:
9899 break;
9900 case IDABORT:
9901 default:
9902 abort ();
9903 break;
9904 }
9905}
9906
9907/* For convenience when debugging. */
9908int
9909w32_last_error()
9910{
9911 return GetLastError ();
9912}
9913#endif
diff --git a/mac/src/macmenu.c b/mac/src/macmenu.c
new file mode 100644
index 00000000000..ac697cf7490
--- /dev/null
+++ b/mac/src/macmenu.c
@@ -0,0 +1,2206 @@
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
37#include <MacTypes.h>
38#include <Menus.h>
39#include <QuickDraw.h>
40#include <ToolUtils.h>
41#include <Fonts.h>
42#include <Controls.h>
43#include <Windows.h>
44#include <Events.h>
45#if defined (__MRC__) || defined (CODEWARRIOR_VERSION_6)
46#include <ControlDefinitions.h>
47#endif
48
49/* This may include sys/types.h, and that somehow loses
50 if this is not done before the other system files. */
51#include "macterm.h"
52
53/* Load sys/types.h if not already loaded.
54 In some systems loading it twice is suicidal. */
55#ifndef makedev
56#include <sys/types.h>
57#endif
58
59#include "dispextern.h"
60
61#define POPUP_SUBMENU_ID 235
62#define MIN_MENU_ID 256
63#define MIN_SUBMENU_ID 1
64
65#define DIALOG_WINDOW_RESOURCE 130
66
67#define HAVE_DIALOGS 1
68
69#undef HAVE_MULTILINGUAL_MENU
70
71/******************************************************************/
72/* Definitions copied from lwlib.h */
73
74typedef void * XtPointer;
75
76#define True 1
77#define False 0
78
79enum button_type
80{
81 BUTTON_TYPE_NONE,
82 BUTTON_TYPE_TOGGLE,
83 BUTTON_TYPE_RADIO
84};
85
86typedef struct _widget_value
87{
88 /* name of widget */
89 char* name;
90 /* value (meaning depend on widget type) */
91 char* value;
92 /* keyboard equivalent. no implications for XtTranslations */
93 char* key;
94 /* Help string or null if none. */
95 char *help;
96 /* true if enabled */
97 Boolean enabled;
98 /* true if selected */
99 Boolean selected;
100 /* The type of a button. */
101 enum button_type button_type;
102 /* true if menu title */
103 Boolean title;
104#if 0
105 /* true if was edited (maintained by get_value) */
106 Boolean edited;
107 /* true if has changed (maintained by lw library) */
108 change_type change;
109 /* true if this widget itself has changed,
110 but not counting the other widgets found in the `next' field. */
111 change_type this_one_change;
112#endif
113 /* Contents of the sub-widgets, also selected slot for checkbox */
114 struct _widget_value* contents;
115 /* data passed to callback */
116 XtPointer call_data;
117 /* next one in the list */
118 struct _widget_value* next;
119#if 0
120 /* slot for the toolkit dependent part. Always initialize to NULL. */
121 void* toolkit_data;
122 /* tell us if we should free the toolkit data slot when freeing the
123 widget_value itself. */
124 Boolean free_toolkit_data;
125
126 /* we resource the widget_value structures; this points to the next
127 one on the free list if this one has been deallocated.
128 */
129 struct _widget_value *free_list;
130#endif
131} widget_value;
132
133/* Assumed by other routines to zero area returned. */
134#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
135 0, (sizeof (widget_value)))
136#define free_widget_value(wv) xfree (wv)
137
138/******************************************************************/
139
140#define min(x,y) (((x) < (y)) ? (x) : (y))
141#define max(x,y) (((x) > (y)) ? (x) : (y))
142
143#ifndef TRUE
144#define TRUE 1
145#define FALSE 0
146#endif /* no TRUE */
147
148Lisp_Object Vmenu_updating_frame;
149
150Lisp_Object Qdebug_on_next_call;
151
152extern Lisp_Object Qmenu_bar;
153extern Lisp_Object Qmouse_click, Qevent_kind;
154
155extern Lisp_Object QCtoggle, QCradio;
156
157extern Lisp_Object Voverriding_local_map;
158extern Lisp_Object Voverriding_local_map_menu_flag;
159
160extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
161
162extern Lisp_Object Qmenu_bar_update_hook;
163
164void set_frame_menubar ();
165
166static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
167 Lisp_Object, Lisp_Object, Lisp_Object,
168 Lisp_Object, Lisp_Object));
169static Lisp_Object mac_dialog_show ();
170static Lisp_Object mac_menu_show ();
171
172static void keymap_panes ();
173static void single_keymap_panes ();
174static void single_menu_item ();
175static void list_of_panes ();
176static void list_of_items ();
177
178static void fill_submenu (MenuHandle, widget_value *, int);
179static void fill_menubar (widget_value *);
180
181
182/* This holds a Lisp vector that holds the results of decoding
183 the keymaps or alist-of-alists that specify a menu.
184
185 It describes the panes and items within the panes.
186
187 Each pane is described by 3 elements in the vector:
188 t, the pane name, the pane's prefix key.
189 Then follow the pane's items, with 5 elements per item:
190 the item string, the enable flag, the item's value,
191 the definition, and the equivalent keyboard key's description string.
192
193 In some cases, multiple levels of menus may be described.
194 A single vector slot containing nil indicates the start of a submenu.
195 A single vector slot containing lambda indicates the end of a submenu.
196 The submenu follows a menu item which is the way to reach the submenu.
197
198 A single vector slot containing quote indicates that the
199 following items should appear on the right of a dialog box.
200
201 Using a Lisp vector to hold this information while we decode it
202 takes care of protecting all the data from GC. */
203
204#define MENU_ITEMS_PANE_NAME 1
205#define MENU_ITEMS_PANE_PREFIX 2
206#define MENU_ITEMS_PANE_LENGTH 3
207
208enum menu_item_idx
209{
210 MENU_ITEMS_ITEM_NAME = 0,
211 MENU_ITEMS_ITEM_ENABLE,
212 MENU_ITEMS_ITEM_VALUE,
213 MENU_ITEMS_ITEM_EQUIV_KEY,
214 MENU_ITEMS_ITEM_DEFINITION,
215 MENU_ITEMS_ITEM_TYPE,
216 MENU_ITEMS_ITEM_SELECTED,
217 MENU_ITEMS_ITEM_HELP,
218 MENU_ITEMS_ITEM_LENGTH
219};
220
221static Lisp_Object menu_items;
222
223/* Number of slots currently allocated in menu_items. */
224static int menu_items_allocated;
225
226/* This is the index in menu_items of the first empty slot. */
227static int menu_items_used;
228
229/* The number of panes currently recorded in menu_items,
230 excluding those within submenus. */
231static int menu_items_n_panes;
232
233/* Current depth within submenus. */
234static int menu_items_submenu_depth;
235
236/* Flag which when set indicates a dialog or menu has been posted by
237 Xt on behalf of one of the widget sets. */
238static int popup_activated_flag;
239
240static int next_menubar_widget_id;
241
242/* This is set nonzero after the user activates the menu bar, and set
243 to zero again after the menu bars are redisplayed by prepare_menu_bar.
244 While it is nonzero, all calls to set_frame_menubar go deep.
245
246 I don't understand why this is needed, but it does seem to be
247 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
248
249int pending_menu_activation;
250
251/* Initialize the menu_items structure if we haven't already done so.
252 Also mark it as currently empty. */
253
254static void
255init_menu_items ()
256{
257 if (NILP (menu_items))
258 {
259 menu_items_allocated = 60;
260 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
261 }
262
263 menu_items_used = 0;
264 menu_items_n_panes = 0;
265 menu_items_submenu_depth = 0;
266}
267
268/* Call at the end of generating the data in menu_items.
269 This fills in the number of items in the last pane. */
270
271static void
272finish_menu_items ()
273{
274}
275
276/* Call when finished using the data for the current menu
277 in menu_items. */
278
279static void
280discard_menu_items ()
281{
282 /* Free the structure if it is especially large.
283 Otherwise, hold on to it, to save time. */
284 if (menu_items_allocated > 200)
285 {
286 menu_items = Qnil;
287 menu_items_allocated = 0;
288 }
289}
290
291/* Make the menu_items vector twice as large. */
292
293static void
294grow_menu_items ()
295{
296 Lisp_Object old;
297 int old_size = menu_items_allocated;
298 old = menu_items;
299
300 menu_items_allocated *= 2;
301 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
302 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
303 old_size * sizeof (Lisp_Object));
304}
305
306/* Begin a submenu. */
307
308static void
309push_submenu_start ()
310{
311 if (menu_items_used + 1 > menu_items_allocated)
312 grow_menu_items ();
313
314 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
315 menu_items_submenu_depth++;
316}
317
318/* End a submenu. */
319
320static void
321push_submenu_end ()
322{
323 if (menu_items_used + 1 > menu_items_allocated)
324 grow_menu_items ();
325
326 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
327 menu_items_submenu_depth--;
328}
329
330/* Indicate boundary between left and right. */
331
332static void
333push_left_right_boundary ()
334{
335 if (menu_items_used + 1 > menu_items_allocated)
336 grow_menu_items ();
337
338 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
339}
340
341/* Start a new menu pane in menu_items..
342 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
343
344static void
345push_menu_pane (name, prefix_vec)
346 Lisp_Object name, prefix_vec;
347{
348 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
349 grow_menu_items ();
350
351 if (menu_items_submenu_depth == 0)
352 menu_items_n_panes++;
353 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
354 XVECTOR (menu_items)->contents[menu_items_used++] = name;
355 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
356}
357
358/* Push one menu item into the current pane. NAME is the string to
359 display. ENABLE if non-nil means this item can be selected. KEY
360 is the key generated by choosing this item, or nil if this item
361 doesn't really have a definition. DEF is the definition of this
362 item. EQUIV is the textual description of the keyboard equivalent
363 for this item (or nil if none). TYPE is the type of this menu
364 item, one of nil, `toggle' or `radio'. */
365
366static void
367push_menu_item (name, enable, key, def, equiv, type, selected, help)
368 Lisp_Object name, enable, key, def, equiv, type, selected, help;
369{
370 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
371 grow_menu_items ();
372
373 XVECTOR (menu_items)->contents[menu_items_used++] = name;
374 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
375 XVECTOR (menu_items)->contents[menu_items_used++] = key;
376 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
377 XVECTOR (menu_items)->contents[menu_items_used++] = def;
378 XVECTOR (menu_items)->contents[menu_items_used++] = type;
379 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
380 XVECTOR (menu_items)->contents[menu_items_used++] = help;
381}
382
383/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
384 and generate menu panes for them in menu_items.
385 If NOTREAL is nonzero,
386 don't bother really computing whether an item is enabled. */
387
388static void
389keymap_panes (keymaps, nmaps, notreal)
390 Lisp_Object *keymaps;
391 int nmaps;
392 int notreal;
393{
394 int mapno;
395
396 init_menu_items ();
397
398 /* Loop over the given keymaps, making a pane for each map.
399 But don't make a pane that is empty--ignore that map instead.
400 P is the number of panes we have made so far. */
401 for (mapno = 0; mapno < nmaps; mapno++)
402 single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
403
404 finish_menu_items ();
405}
406
407/* This is a recursive subroutine of keymap_panes.
408 It handles one keymap, KEYMAP.
409 The other arguments are passed along
410 or point to local variables of the previous function.
411 If NOTREAL is nonzero, only check for equivalent key bindings, don't
412 evaluate expressions in menu items and don't make any menu.
413
414 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
415
416static void
417single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
418 Lisp_Object keymap;
419 Lisp_Object pane_name;
420 Lisp_Object prefix;
421 int notreal;
422 int maxdepth;
423{
424 Lisp_Object pending_maps = Qnil;
425 Lisp_Object tail, item;
426 struct gcpro gcpro1, gcpro2;
427
428 if (maxdepth <= 0)
429 return;
430
431 push_menu_pane (pane_name, prefix);
432
433 for (tail = keymap; CONSP (tail); tail = XCDR (tail))
434 {
435 GCPRO2 (keymap, pending_maps);
436 /* Look at each key binding, and if it is a menu item add it
437 to this menu. */
438 item = XCAR (tail);
439 if (CONSP (item))
440 single_menu_item (XCAR (item), XCDR (item),
441 &pending_maps, notreal, maxdepth);
442 else if (VECTORP (item))
443 {
444 /* Loop over the char values represented in the vector. */
445 int len = XVECTOR (item)->size;
446 int c;
447 for (c = 0; c < len; c++)
448 {
449 Lisp_Object character;
450 XSETFASTINT (character, c);
451 single_menu_item (character, XVECTOR (item)->contents[c],
452 &pending_maps, notreal, maxdepth);
453 }
454 }
455 UNGCPRO;
456 }
457
458 /* Process now any submenus which want to be panes at this level. */
459 while (!NILP (pending_maps))
460 {
461 Lisp_Object elt, eltcdr, string;
462 elt = Fcar (pending_maps);
463 eltcdr = XCDR (elt);
464 string = XCAR (eltcdr);
465 /* We no longer discard the @ from the beginning of the string here.
466 Instead, we do this in mac_menu_show. */
467 single_keymap_panes (Fcar (elt), string,
468 XCDR (eltcdr), notreal, maxdepth - 1);
469 pending_maps = Fcdr (pending_maps);
470 }
471}
472
473/* This is a subroutine of single_keymap_panes that handles one
474 keymap entry.
475 KEY is a key in a keymap and ITEM is its binding.
476 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
477 separate panes.
478 If NOTREAL is nonzero, only check for equivalent key bindings, don't
479 evaluate expressions in menu items and don't make any menu.
480 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
481
482static void
483single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
484 Lisp_Object key, item;
485 Lisp_Object *pending_maps_ptr;
486 int maxdepth, notreal;
487{
488 Lisp_Object map, item_string, enabled;
489 struct gcpro gcpro1, gcpro2;
490 int res;
491
492 /* Parse the menu item and leave the result in item_properties. */
493 GCPRO2 (key, item);
494 res = parse_menu_item (item, notreal, 0);
495 UNGCPRO;
496 if (!res)
497 return; /* Not a menu item. */
498
499 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
500
501 if (notreal)
502 {
503 /* We don't want to make a menu, just traverse the keymaps to
504 precompute equivalent key bindings. */
505 if (!NILP (map))
506 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
507 return;
508 }
509
510 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
511 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
512
513 if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
514 {
515 if (!NILP (enabled))
516 /* An enabled separate pane. Remember this to handle it later. */
517 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
518 *pending_maps_ptr);
519 return;
520 }
521
522 push_menu_item (item_string, enabled, key,
523 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
524 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
525 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
526 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
527 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
528
529 /* Display a submenu using the toolkit. */
530 if (! (NILP (map) || NILP (enabled)))
531 {
532 push_submenu_start ();
533 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
534 push_submenu_end ();
535 }
536}
537
538/* Push all the panes and items of a menu described by the
539 alist-of-alists MENU.
540 This handles old-fashioned calls to x-popup-menu. */
541
542static void
543list_of_panes (menu)
544 Lisp_Object menu;
545{
546 Lisp_Object tail;
547
548 init_menu_items ();
549
550 for (tail = menu; !NILP (tail); tail = Fcdr (tail))
551 {
552 Lisp_Object elt, pane_name, pane_data;
553 elt = Fcar (tail);
554 pane_name = Fcar (elt);
555 CHECK_STRING (pane_name, 0);
556 push_menu_pane (pane_name, Qnil);
557 pane_data = Fcdr (elt);
558 CHECK_CONS (pane_data, 0);
559 list_of_items (pane_data);
560 }
561
562 finish_menu_items ();
563}
564
565/* Push the items in a single pane defined by the alist PANE. */
566
567static void
568list_of_items (pane)
569 Lisp_Object pane;
570{
571 Lisp_Object tail, item, item1;
572
573 for (tail = pane; !NILP (tail); tail = Fcdr (tail))
574 {
575 item = Fcar (tail);
576 if (STRINGP (item))
577 push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
578 else if (NILP (item))
579 push_left_right_boundary ();
580 else
581 {
582 CHECK_CONS (item, 0);
583 item1 = Fcar (item);
584 CHECK_STRING (item1, 1);
585 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
586 }
587 }
588}
589
590DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
591 "Pop up a deck-of-cards menu and return user's selection.\n\
592POSITION is a position specification. This is either a mouse button event\n\
593or a list ((XOFFSET YOFFSET) WINDOW)\n\
594where XOFFSET and YOFFSET are positions in pixels from the top left\n\
595corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\
596This controls the position of the center of the first line\n\
597in the first pane of the menu, not the top left of the menu as a whole.\n\
598If POSITION is t, it means to use the current mouse position.\n\
599\n\
600MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\
601The menu items come from key bindings that have a menu string as well as\n\
602a definition; actually, the \"definition\" in such a key binding looks like\n\
603\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\
604the keymap as a top-level element.\n\n\
605If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.\n\
606Otherwise, REAL-DEFINITION should be a valid key binding definition.\n\
607\n\
608You can also use a list of keymaps as MENU.\n\
609 Then each keymap makes a separate pane.\n\
610When MENU is a keymap or a list of keymaps, the return value\n\
611is a list of events.\n\n\
612\n\
613Alternatively, you can specify a menu of multiple panes\n\
614 with a list of the form (TITLE PANE1 PANE2...),\n\
615where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
616Each ITEM is normally a cons cell (STRING . VALUE);\n\
617but a string can appear as an item--that makes a nonselectable line\n\
618in the menu.\n\
619With this form of menu, the return value is VALUE from the chosen item.\n\
620\n\
621If POSITION is nil, don't display the menu at all, just precalculate the\n\
622cached information about equivalent key sequences.")
623 (position, menu)
624 Lisp_Object position, menu;
625{
626 Lisp_Object keymap, tem;
627 int xpos, ypos;
628 Lisp_Object title;
629 char *error_name;
630 Lisp_Object selection;
631 FRAME_PTR f;
632 Lisp_Object x, y, window;
633 int keymaps = 0;
634 int for_click = 0;
635 struct gcpro gcpro1;
636
637#ifdef HAVE_MENUS
638 if (! NILP (position))
639 {
640 check_mac ();
641
642 /* Decode the first argument: find the window and the coordinates. */
643 if (EQ (position, Qt)
644 || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
645 {
646 /* Use the mouse's current position. */
647 FRAME_PTR new_f = SELECTED_FRAME ();
648 Lisp_Object bar_window;
649 enum scroll_bar_part part;
650 unsigned long time;
651
652 if (mouse_position_hook)
653 (*mouse_position_hook) (&new_f, 1, &bar_window,
654 &part, &x, &y, &time);
655 if (new_f != 0)
656 XSETFRAME (window, new_f);
657 else
658 {
659 window = selected_window;
660 XSETFASTINT (x, 0);
661 XSETFASTINT (y, 0);
662 }
663 }
664 else
665 {
666 tem = Fcar (position);
667 if (CONSP (tem))
668 {
669 window = Fcar (Fcdr (position));
670 x = Fcar (tem);
671 y = Fcar (Fcdr (tem));
672 }
673 else
674 {
675 for_click = 1;
676 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
677 window = Fcar (tem); /* POSN_WINDOW (tem) */
678 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
679 x = Fcar (tem);
680 y = Fcdr (tem);
681 }
682 }
683
684 CHECK_NUMBER (x, 0);
685 CHECK_NUMBER (y, 0);
686
687 /* Decode where to put the menu. */
688
689 if (FRAMEP (window))
690 {
691 f = XFRAME (window);
692 xpos = 0;
693 ypos = 0;
694 }
695 else if (WINDOWP (window))
696 {
697 CHECK_LIVE_WINDOW (window, 0);
698 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
699
700 xpos = (FONT_WIDTH (FRAME_FONT (f))
701 * XFASTINT (XWINDOW (window)->left));
702 ypos = (FRAME_LINE_HEIGHT (f)
703 * XFASTINT (XWINDOW (window)->top));
704 }
705 else
706 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
707 but I don't want to make one now. */
708 CHECK_WINDOW (window, 0);
709
710 xpos += XINT (x);
711 ypos += XINT (y);
712
713 XSETFRAME (Vmenu_updating_frame, f);
714 }
715 Vmenu_updating_frame = Qnil;
716#endif /* HAVE_MENUS */
717
718 title = Qnil;
719 GCPRO1 (title);
720
721 /* Decode the menu items from what was specified. */
722
723 keymap = Fkeymapp (menu);
724 tem = Qnil;
725 if (CONSP (menu))
726 tem = Fkeymapp (Fcar (menu));
727 if (!NILP (keymap))
728 {
729 /* We were given a keymap. Extract menu info from the keymap. */
730 Lisp_Object prompt;
731 keymap = get_keymap (menu);
732
733 /* Extract the detailed info to make one pane. */
734 keymap_panes (&menu, 1, NILP (position));
735
736 /* Search for a string appearing directly as an element of the keymap.
737 That string is the title of the menu. */
738 prompt = map_prompt (keymap);
739 if (NILP (title) && !NILP (prompt))
740 title = prompt;
741
742 /* Make that be the pane title of the first pane. */
743 if (!NILP (prompt) && menu_items_n_panes >= 0)
744 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
745
746 keymaps = 1;
747 }
748 else if (!NILP (tem))
749 {
750 /* We were given a list of keymaps. */
751 int nmaps = XFASTINT (Flength (menu));
752 Lisp_Object *maps
753 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
754 int i;
755
756 title = Qnil;
757
758 /* The first keymap that has a prompt string
759 supplies the menu title. */
760 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
761 {
762 Lisp_Object prompt;
763
764 maps[i++] = keymap = get_keymap (Fcar (tem));
765
766 prompt = map_prompt (keymap);
767 if (NILP (title) && !NILP (prompt))
768 title = prompt;
769 }
770
771 /* Extract the detailed info to make one pane. */
772 keymap_panes (maps, nmaps, NILP (position));
773
774 /* Make the title be the pane title of the first pane. */
775 if (!NILP (title) && menu_items_n_panes >= 0)
776 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
777
778 keymaps = 1;
779 }
780 else
781 {
782 /* We were given an old-fashioned menu. */
783 title = Fcar (menu);
784 CHECK_STRING (title, 1);
785
786 list_of_panes (Fcdr (menu));
787
788 keymaps = 0;
789 }
790
791 if (NILP (position))
792 {
793 discard_menu_items ();
794 UNGCPRO;
795 return Qnil;
796 }
797
798#ifdef HAVE_MENUS
799 /* Display them in a menu. */
800 BLOCK_INPUT;
801
802 selection = mac_menu_show (f, xpos, ypos, for_click,
803 keymaps, title, &error_name);
804 UNBLOCK_INPUT;
805
806 discard_menu_items ();
807
808 UNGCPRO;
809#endif /* HAVE_MENUS */
810
811 if (error_name) error (error_name);
812 return selection;
813}
814
815#ifdef HAVE_MENUS
816
817DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
818 "Pop up a dialog box and return user's selection.\n\
819POSITION specifies which frame to use.\n\
820This is normally a mouse button event or a window or frame.\n\
821If POSITION is t, it means to use the frame the mouse is on.\n\
822The dialog box appears in the middle of the specified frame.\n\
823\n\
824CONTENTS specifies the alternatives to display in the dialog box.\n\
825It is a list of the form (TITLE ITEM1 ITEM2...).\n\
826Each ITEM is a cons cell (STRING . VALUE).\n\
827The return value is VALUE from the chosen item.\n\n\
828An ITEM may also be just a string--that makes a nonselectable item.\n\
829An ITEM may also be nil--that means to put all preceding items\n\
830on the left of the dialog box and all following items on the right.\n\
831\(By default, approximately half appear on each side.)")
832 (position, contents)
833 Lisp_Object position, contents;
834{
835 FRAME_PTR f;
836 Lisp_Object window;
837
838 check_mac ();
839
840 /* Decode the first argument: find the window or frame to use. */
841 if (EQ (position, Qt)
842 || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
843 {
844#if 0 /* Using the frame the mouse is on may not be right. */
845 /* Use the mouse's current position. */
846 FRAME_PTR new_f = SELECTED_FRAME ();
847 Lisp_Object bar_window;
848 int part;
849 unsigned long time;
850 Lisp_Object x, y;
851
852 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
853
854 if (new_f != 0)
855 XSETFRAME (window, new_f);
856 else
857 window = selected_window;
858#endif
859 window = selected_window;
860 }
861 else if (CONSP (position))
862 {
863 Lisp_Object tem;
864 tem = Fcar (position);
865 if (CONSP (tem))
866 window = Fcar (Fcdr (position));
867 else
868 {
869 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
870 window = Fcar (tem); /* POSN_WINDOW (tem) */
871 }
872 }
873 else if (WINDOWP (position) || FRAMEP (position))
874 window = position;
875 else
876 window = Qnil;
877
878 /* Decode where to put the menu. */
879
880 if (FRAMEP (window))
881 f = XFRAME (window);
882 else if (WINDOWP (window))
883 {
884 CHECK_LIVE_WINDOW (window, 0);
885 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
886 }
887 else
888 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
889 but I don't want to make one now. */
890 CHECK_WINDOW (window, 0);
891
892#ifndef HAVE_DIALOGS
893 /* Display a menu with these alternatives
894 in the middle of frame F. */
895 {
896 Lisp_Object x, y, frame, newpos;
897 XSETFRAME (frame, f);
898 XSETINT (x, x_pixel_width (f) / 2);
899 XSETINT (y, x_pixel_height (f) / 2);
900 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
901
902 return Fx_popup_menu (newpos,
903 Fcons (Fcar (contents), Fcons (contents, Qnil)));
904 }
905#else /* HAVE_DIALOGS */
906 {
907 Lisp_Object title;
908 char *error_name;
909 Lisp_Object selection;
910
911 /* Decode the dialog items from what was specified. */
912 title = Fcar (contents);
913 CHECK_STRING (title, 1);
914
915 list_of_panes (Fcons (contents, Qnil));
916
917 /* Display them in a dialog box. */
918 BLOCK_INPUT;
919 selection = mac_dialog_show (f, 0, title, &error_name);
920 UNBLOCK_INPUT;
921
922 discard_menu_items ();
923
924 if (error_name) error (error_name);
925 return selection;
926 }
927#endif /* HAVE_DIALOGS */
928}
929
930/* Activate the menu bar of frame F.
931 This is called from keyboard.c when it gets the
932 menu_bar_activate_event out of the Emacs event queue.
933
934 To activate the menu bar, we signal to the input thread that it can
935 return from the WM_INITMENU message, allowing the normal Windows
936 processing of the menus.
937
938 But first we recompute the menu bar contents (the whole tree).
939
940 This way we can safely execute Lisp code. */
941
942void
943x_activate_menubar (f)
944 FRAME_PTR f;
945{
946 SInt32 menu_choice;
947 extern Point saved_menu_event_location;
948
949 set_frame_menubar (f, 0, 1);
950 BLOCK_INPUT;
951
952 menu_choice = MenuSelect (saved_menu_event_location);
953 do_menu_choice (menu_choice);
954
955 UNBLOCK_INPUT;
956}
957
958/* This callback is called from the menu bar pulldown menu
959 when the user makes a selection.
960 Figure out what the user chose
961 and put the appropriate events into the keyboard buffer. */
962
963void
964menubar_selection_callback (FRAME_PTR f, int client_data)
965{
966 Lisp_Object prefix, entry;
967 Lisp_Object vector;
968 Lisp_Object *subprefix_stack;
969 int submenu_depth = 0;
970 int i;
971
972 if (!f)
973 return;
974 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
975 vector = f->menu_bar_vector;
976 prefix = Qnil;
977 i = 0;
978 while (i < f->menu_bar_items_used)
979 {
980 if (EQ (XVECTOR (vector)->contents[i], Qnil))
981 {
982 subprefix_stack[submenu_depth++] = prefix;
983 prefix = entry;
984 i++;
985 }
986 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
987 {
988 prefix = subprefix_stack[--submenu_depth];
989 i++;
990 }
991 else if (EQ (XVECTOR (vector)->contents[i], Qt))
992 {
993 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
994 i += MENU_ITEMS_PANE_LENGTH;
995 }
996 else
997 {
998 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
999 if (client_data == i)
1000 {
1001 int j;
1002 struct input_event buf;
1003 Lisp_Object frame;
1004
1005 XSETFRAME (frame, f);
1006 buf.kind = MENU_BAR_EVENT;
1007 buf.frame_or_window = frame;
1008 buf.arg = frame;
1009 kbd_buffer_store_event (&buf);
1010
1011 for (j = 0; j < submenu_depth; j++)
1012 if (!NILP (subprefix_stack[j]))
1013 {
1014 buf.kind = MENU_BAR_EVENT;
1015 buf.frame_or_window = frame;
1016 buf.arg = subprefix_stack[j];
1017 kbd_buffer_store_event (&buf);
1018 }
1019
1020 if (!NILP (prefix))
1021 {
1022 buf.kind = MENU_BAR_EVENT;
1023 buf.frame_or_window = frame;
1024 buf.arg = prefix;
1025 kbd_buffer_store_event (&buf);
1026 }
1027
1028 buf.kind = MENU_BAR_EVENT;
1029 buf.frame_or_window = frame;
1030 buf.arg = entry;
1031 kbd_buffer_store_event (&buf);
1032
1033#if 0
1034 /* Queue this to recompute possibly updated menubar. */
1035 buf.kind = menu_bar_activate_event;
1036 buf.frame_or_window = frame;
1037 buf.arg = Qnil;
1038 kbd_buffer_store_event (&buf);
1039#endif
1040
1041 return;
1042 }
1043 i += MENU_ITEMS_ITEM_LENGTH;
1044 }
1045 }
1046}
1047
1048/* Allocate a widget_value, blocking input. */
1049
1050widget_value *
1051xmalloc_widget_value ()
1052{
1053 widget_value *value;
1054
1055 BLOCK_INPUT;
1056 value = malloc_widget_value ();
1057 UNBLOCK_INPUT;
1058
1059 return value;
1060}
1061
1062/* This recursively calls free_widget_value on the tree of widgets.
1063 It must free all data that was malloc'ed for these widget_values.
1064 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1065 must be left alone. */
1066
1067void
1068free_menubar_widget_value_tree (wv)
1069 widget_value *wv;
1070{
1071 if (! wv) return;
1072
1073 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1074
1075 if (wv->contents && (wv->contents != (widget_value*)1))
1076 {
1077 free_menubar_widget_value_tree (wv->contents);
1078 wv->contents = (widget_value *) 0xDEADBEEF;
1079 }
1080 if (wv->next)
1081 {
1082 free_menubar_widget_value_tree (wv->next);
1083 wv->next = (widget_value *) 0xDEADBEEF;
1084 }
1085 BLOCK_INPUT;
1086 free_widget_value (wv);
1087 UNBLOCK_INPUT;
1088}
1089
1090/* Return a tree of widget_value structures for a menu bar item
1091 whose event type is ITEM_KEY (with string ITEM_NAME)
1092 and whose contents come from the list of keymaps MAPS. */
1093
1094static widget_value *
1095single_submenu (item_key, item_name, maps)
1096 Lisp_Object item_key, item_name, maps;
1097{
1098 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1099 int i;
1100 int submenu_depth = 0;
1101 Lisp_Object length;
1102 int len;
1103 Lisp_Object *mapvec;
1104 widget_value **submenu_stack;
1105 int previous_items = menu_items_used;
1106 int top_level_items = 0;
1107
1108 length = Flength (maps);
1109 len = XINT (length);
1110
1111 /* Convert the list MAPS into a vector MAPVEC. */
1112 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1113 for (i = 0; i < len; i++)
1114 {
1115 mapvec[i] = Fcar (maps);
1116 maps = Fcdr (maps);
1117 }
1118
1119 menu_items_n_panes = 0;
1120
1121 /* Loop over the given keymaps, making a pane for each map.
1122 But don't make a pane that is empty--ignore that map instead. */
1123 for (i = 0; i < len; i++)
1124 {
1125 if (SYMBOLP (mapvec[i])
1126 || (CONSP (mapvec[i])
1127 && NILP (Fkeymapp (mapvec[i]))))
1128 {
1129 /* Here we have a command at top level in the menu bar
1130 as opposed to a submenu. */
1131 top_level_items = 1;
1132 push_menu_pane (Qnil, Qnil);
1133 push_menu_item (item_name, Qt, item_key, mapvec[i],
1134 Qnil, Qnil, Qnil, Qnil);
1135 }
1136 else
1137 single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
1138 }
1139
1140 /* Create a tree of widget_value objects
1141 representing the panes and their items. */
1142
1143 submenu_stack
1144 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1145 wv = xmalloc_widget_value ();
1146 wv->name = "menu";
1147 wv->value = 0;
1148 wv->enabled = 1;
1149 wv->button_type = BUTTON_TYPE_NONE;
1150 first_wv = wv;
1151 save_wv = 0;
1152 prev_wv = 0;
1153
1154 /* Loop over all panes and items made during this call
1155 and construct a tree of widget_value objects.
1156 Ignore the panes and items made by previous calls to
1157 single_submenu, even though those are also in menu_items. */
1158 i = previous_items;
1159 while (i < menu_items_used)
1160 {
1161 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1162 {
1163 submenu_stack[submenu_depth++] = save_wv;
1164 save_wv = prev_wv;
1165 prev_wv = 0;
1166 i++;
1167 }
1168 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1169 {
1170 prev_wv = save_wv;
1171 save_wv = submenu_stack[--submenu_depth];
1172 i++;
1173 }
1174 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1175 && submenu_depth != 0)
1176 i += MENU_ITEMS_PANE_LENGTH;
1177 /* Ignore a nil in the item list.
1178 It's meaningful only for dialog boxes. */
1179 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1180 i += 1;
1181 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1182 {
1183 /* Create a new pane. */
1184 Lisp_Object pane_name, prefix;
1185 char *pane_string;
1186 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1187 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1188#ifndef HAVE_MULTILINGUAL_MENU
1189 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1190 pane_name = string_make_unibyte (pane_name);
1191#endif
1192 pane_string = (NILP (pane_name)
1193 ? "" : (char *) XSTRING (pane_name)->data);
1194 /* If there is just one top-level pane, put all its items directly
1195 under the top-level menu. */
1196 if (menu_items_n_panes == 1)
1197 pane_string = "";
1198
1199 /* If the pane has a meaningful name,
1200 make the pane a top-level menu item
1201 with its items as a submenu beneath it. */
1202 if (strcmp (pane_string, ""))
1203 {
1204 wv = xmalloc_widget_value ();
1205 if (save_wv)
1206 save_wv->next = wv;
1207 else
1208 first_wv->contents = wv;
1209 wv->name = pane_string;
1210 /* Ignore the @ that means "separate pane".
1211 This is a kludge, but this isn't worth more time. */
1212 if (!NILP (prefix) && wv->name[0] == '@')
1213 wv->name++;
1214 wv->value = 0;
1215 wv->enabled = 1;
1216 wv->button_type = BUTTON_TYPE_NONE;
1217 }
1218 save_wv = wv;
1219 prev_wv = 0;
1220 i += MENU_ITEMS_PANE_LENGTH;
1221 }
1222 else
1223 {
1224 /* Create a new item within current pane. */
1225 Lisp_Object item_name, enable, descrip, def, type, selected;
1226 Lisp_Object help;
1227
1228 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1229 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1230 descrip
1231 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1232 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
1233 type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
1234 selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
1235 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
1236
1237#ifndef HAVE_MULTILINGUAL_MENU
1238 if (STRING_MULTIBYTE (item_name))
1239 item_name = string_make_unibyte (item_name);
1240 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1241 descrip = string_make_unibyte (descrip);
1242#endif
1243
1244 wv = xmalloc_widget_value ();
1245 if (prev_wv)
1246 prev_wv->next = wv;
1247 else
1248 save_wv->contents = wv;
1249
1250 wv->name = (char *) XSTRING (item_name)->data;
1251 if (!NILP (descrip))
1252 wv->key = (char *) XSTRING (descrip)->data;
1253 wv->value = 0;
1254 /* The EMACS_INT cast avoids a warning. There's no problem
1255 as long as pointers have enough bits to hold small integers. */
1256 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1257 wv->enabled = !NILP (enable);
1258
1259 if (NILP (type))
1260 wv->button_type = BUTTON_TYPE_NONE;
1261 else if (EQ (type, QCradio))
1262 wv->button_type = BUTTON_TYPE_RADIO;
1263 else if (EQ (type, QCtoggle))
1264 wv->button_type = BUTTON_TYPE_TOGGLE;
1265 else
1266 abort ();
1267
1268 wv->selected = !NILP (selected);
1269 if (STRINGP (help))
1270 wv->help = (char *) XSTRING (help)->data;
1271 else
1272 wv->help = NULL;
1273
1274 prev_wv = wv;
1275
1276 i += MENU_ITEMS_ITEM_LENGTH;
1277 }
1278 }
1279
1280 /* If we have just one "menu item"
1281 that was originally a button, return it by itself. */
1282 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
1283 {
1284 wv = first_wv->contents;
1285 free_widget_value (first_wv);
1286 return wv;
1287 }
1288
1289 return first_wv;
1290}
1291
1292/* Set the contents of the menubar widgets of frame F.
1293 The argument FIRST_TIME is currently ignored;
1294 it is set the first time this is called, from initialize_frame_menubar. */
1295
1296void
1297set_frame_menubar (f, first_time, deep_p)
1298 FRAME_PTR f;
1299 int first_time;
1300 int deep_p;
1301{
1302 int menubar_widget = f->output_data.mac->menubar_widget;
1303 Lisp_Object items;
1304 widget_value *wv, *first_wv, *prev_wv = 0;
1305 int i;
1306
1307 XSETFRAME (Vmenu_updating_frame, f);
1308
1309 wv = xmalloc_widget_value ();
1310 wv->name = "menubar";
1311 wv->value = 0;
1312 wv->enabled = 1;
1313 wv->button_type = BUTTON_TYPE_NONE;
1314 first_wv = wv;
1315
1316 {
1317 /* Make a widget-value tree representing the entire menu trees. */
1318
1319 struct buffer *prev = current_buffer;
1320 Lisp_Object buffer;
1321 int specpdl_count = specpdl_ptr - specpdl;
1322 int previous_menu_items_used = f->menu_bar_items_used;
1323 Lisp_Object *previous_items
1324 = (Lisp_Object *) alloca (previous_menu_items_used
1325 * sizeof (Lisp_Object));
1326
1327 /* If we are making a new widget, its contents are empty,
1328 do always reinitialize them. */
1329 if (! menubar_widget)
1330 previous_menu_items_used = 0;
1331
1332 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1333 specbind (Qinhibit_quit, Qt);
1334 /* Don't let the debugger step into this code
1335 because it is not reentrant. */
1336 specbind (Qdebug_on_next_call, Qnil);
1337
1338 record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
1339 if (NILP (Voverriding_local_map_menu_flag))
1340 {
1341 specbind (Qoverriding_terminal_local_map, Qnil);
1342 specbind (Qoverriding_local_map, Qnil);
1343 }
1344
1345 set_buffer_internal_1 (XBUFFER (buffer));
1346
1347 /* Run the Lucid hook. */
1348 call1 (Vrun_hooks, Qactivate_menubar_hook);
1349 /* If it has changed current-menubar from previous value,
1350 really recompute the menubar from the value. */
1351 if (! NILP (Vlucid_menu_bar_dirty_flag))
1352 call0 (Qrecompute_lucid_menubar);
1353 safe_run_hooks (Qmenu_bar_update_hook);
1354 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1355
1356 items = FRAME_MENU_BAR_ITEMS (f);
1357
1358 inhibit_garbage_collection ();
1359
1360 /* Save the frame's previous menu bar contents data. */
1361 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1362 previous_menu_items_used * sizeof (Lisp_Object));
1363
1364 /* Fill in the current menu bar contents. */
1365 menu_items = f->menu_bar_vector;
1366 menu_items_allocated = XVECTOR (menu_items)->size;
1367 init_menu_items ();
1368 for (i = 0; i < XVECTOR (items)->size; i += 4)
1369 {
1370 Lisp_Object key, string, maps;
1371
1372 key = XVECTOR (items)->contents[i];
1373 string = XVECTOR (items)->contents[i + 1];
1374 maps = XVECTOR (items)->contents[i + 2];
1375 if (NILP (string))
1376 break;
1377
1378 wv = single_submenu (key, string, maps);
1379 if (prev_wv)
1380 prev_wv->next = wv;
1381 else
1382 first_wv->contents = wv;
1383 /* Don't set wv->name here; GC during the loop might relocate it. */
1384 wv->enabled = 1;
1385 wv->button_type = BUTTON_TYPE_NONE;
1386 prev_wv = wv;
1387 }
1388
1389 finish_menu_items ();
1390
1391 set_buffer_internal_1 (prev);
1392 unbind_to (specpdl_count, Qnil);
1393
1394 /* If there has been no change in the Lisp-level contents
1395 of the menu bar, skip redisplaying it. Just exit. */
1396
1397 for (i = 0; i < previous_menu_items_used; i++)
1398 if (menu_items_used == i
1399 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1400 break;
1401 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1402 {
1403 free_menubar_widget_value_tree (first_wv);
1404 menu_items = Qnil;
1405
1406 return;
1407 }
1408
1409 /* Now GC cannot happen during the lifetime of the widget_value,
1410 so it's safe to store data from a Lisp_String. */
1411 wv = first_wv->contents;
1412 for (i = 0; i < XVECTOR (items)->size; i += 4)
1413 {
1414 Lisp_Object string;
1415 string = XVECTOR (items)->contents[i + 1];
1416 if (NILP (string))
1417 break;
1418 wv->name = (char *) XSTRING (string)->data;
1419 wv = wv->next;
1420 }
1421
1422 f->menu_bar_vector = menu_items;
1423 f->menu_bar_items_used = menu_items_used;
1424 menu_items = Qnil;
1425 }
1426
1427 /* Create or update the menu bar widget. */
1428
1429 BLOCK_INPUT;
1430
1431 f->output_data.mac->menubar_widget = NULL; /* always NULL on Mac */
1432
1433 {
1434 int i = MIN_MENU_ID;
1435 MenuHandle menu = GetMenuHandle (i);
1436 while (menu != NULL)
1437 {
1438 DeleteMenu (i);
1439 DisposeMenu (menu);
1440 menu = GetMenuHandle (++i);
1441 }
1442
1443 i = MIN_SUBMENU_ID;
1444 menu = GetMenuHandle (i);
1445 while (menu != NULL)
1446 {
1447 DeleteMenu (i);
1448 DisposeMenu (menu);
1449 menu = GetMenuHandle (++i);
1450 }
1451 }
1452
1453 fill_menubar (first_wv->contents);
1454
1455 DrawMenuBar ();
1456
1457 free_menubar_widget_value_tree (first_wv);
1458
1459 UNBLOCK_INPUT;
1460}
1461
1462/* Called from Fx_create_frame to create the initial menubar of a
1463 frame before it is mapped, so that the window is mapped with the
1464 menubar already there instead of us tacking it on later and
1465 thrashing the window after it is visible. */
1466
1467void
1468initialize_frame_menubar (f)
1469 FRAME_PTR f;
1470{
1471 /* This function is called before the first chance to redisplay
1472 the frame. It has to be, so the frame will have the right size. */
1473 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1474 set_frame_menubar (f, 1, 1);
1475}
1476
1477/* Get rid of the menu bar of frame F, and free its storage.
1478 This is used when deleting a frame, and when turning off the menu bar. */
1479
1480void
1481free_frame_menubar (f)
1482 FRAME_PTR f;
1483{
1484 /* Nothing to do since set_frame_menubar disposes of menus before
1485 installing new ones. */
1486}
1487
1488
1489/* mac_menu_show actually displays a menu using the panes and items in
1490 menu_items and returns the value selected from it; we assume input
1491 is blocked by the caller. */
1492
1493/* F is the frame the menu is for.
1494 X and Y are the frame-relative specified position,
1495 relative to the inside upper left corner of the frame F.
1496 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1497 KEYMAPS is 1 if this menu was specified with keymaps;
1498 in that case, we return a list containing the chosen item's value
1499 and perhaps also the pane's prefix.
1500 TITLE is the specified menu title.
1501 ERROR is a place to store an error message string in case of failure.
1502 (We return nil on failure, but the value doesn't actually matter.) */
1503
1504static Lisp_Object
1505mac_menu_show (f, x, y, for_click, keymaps, title, error)
1506 FRAME_PTR f;
1507 int x;
1508 int y;
1509 int for_click;
1510 int keymaps;
1511 Lisp_Object title;
1512 char **error;
1513{
1514 int i;
1515 int menu_item_selection;
1516 MenuHandle menu;
1517 Point pos;
1518 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1519 widget_value **submenu_stack
1520 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1521 Lisp_Object *subprefix_stack
1522 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1523 int submenu_depth = 0;
1524 int first_pane;
1525 int next_release_must_exit = 0;
1526
1527 *error = NULL;
1528
1529 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1530 {
1531 *error = "Empty menu";
1532 return Qnil;
1533 }
1534
1535 /* Create a tree of widget_value objects
1536 representing the panes and their items. */
1537 wv = xmalloc_widget_value ();
1538 wv->name = "menu";
1539 wv->value = 0;
1540 wv->enabled = 1;
1541 wv->button_type = BUTTON_TYPE_NONE;
1542 first_wv = wv;
1543 first_pane = 1;
1544
1545 /* Loop over all panes and items, filling in the tree. */
1546 i = 0;
1547 while (i < menu_items_used)
1548 {
1549 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1550 {
1551 submenu_stack[submenu_depth++] = save_wv;
1552 save_wv = prev_wv;
1553 prev_wv = 0;
1554 first_pane = 1;
1555 i++;
1556 }
1557 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1558 {
1559 prev_wv = save_wv;
1560 save_wv = submenu_stack[--submenu_depth];
1561 first_pane = 0;
1562 i++;
1563 }
1564 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1565 && submenu_depth != 0)
1566 i += MENU_ITEMS_PANE_LENGTH;
1567 /* Ignore a nil in the item list.
1568 It's meaningful only for dialog boxes. */
1569 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1570 i += 1;
1571 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1572 {
1573 /* Create a new pane. */
1574 Lisp_Object pane_name, prefix;
1575 char *pane_string;
1576 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1577 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1578#ifndef HAVE_MULTILINGUAL_MENU
1579 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1580 pane_name = string_make_unibyte (pane_name);
1581#endif
1582 pane_string = (NILP (pane_name)
1583 ? "" : (char *) XSTRING (pane_name)->data);
1584 /* If there is just one top-level pane, put all its items directly
1585 under the top-level menu. */
1586 if (menu_items_n_panes == 1)
1587 pane_string = "";
1588
1589 /* If the pane has a meaningful name,
1590 make the pane a top-level menu item
1591 with its items as a submenu beneath it. */
1592 if (!keymaps && strcmp (pane_string, ""))
1593 {
1594 wv = xmalloc_widget_value ();
1595 if (save_wv)
1596 save_wv->next = wv;
1597 else
1598 first_wv->contents = wv;
1599 wv->name = pane_string;
1600 if (keymaps && !NILP (prefix))
1601 wv->name++;
1602 wv->value = 0;
1603 wv->enabled = 1;
1604 wv->button_type = BUTTON_TYPE_NONE;
1605 save_wv = wv;
1606 prev_wv = 0;
1607 }
1608 else if (first_pane)
1609 {
1610 save_wv = wv;
1611 prev_wv = 0;
1612 }
1613 first_pane = 0;
1614 i += MENU_ITEMS_PANE_LENGTH;
1615 }
1616 else
1617 {
1618 /* Create a new item within current pane. */
1619 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1620
1621 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1622 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1623 descrip
1624 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1625 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
1626 type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
1627 selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
1628 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
1629
1630#ifndef HAVE_MULTILINGUAL_MENU
1631 if (STRING_MULTIBYTE (item_name))
1632 item_name = string_make_unibyte (item_name);
1633 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1634 descrip = string_make_unibyte (descrip);
1635#endif
1636
1637 wv = xmalloc_widget_value ();
1638 if (prev_wv)
1639 prev_wv->next = wv;
1640 else
1641 save_wv->contents = wv;
1642 wv->name = (char *) XSTRING (item_name)->data;
1643 if (!NILP (descrip))
1644 wv->key = (char *) XSTRING (descrip)->data;
1645 wv->value = 0;
1646 /* Use the contents index as call_data, since we are
1647 restricted to 16-bits.. */
1648 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
1649 wv->enabled = !NILP (enable);
1650
1651 if (NILP (type))
1652 wv->button_type = BUTTON_TYPE_NONE;
1653 else if (EQ (type, QCtoggle))
1654 wv->button_type = BUTTON_TYPE_TOGGLE;
1655 else if (EQ (type, QCradio))
1656 wv->button_type = BUTTON_TYPE_RADIO;
1657 else
1658 abort ();
1659
1660 wv->selected = !NILP (selected);
1661
1662 if (STRINGP (help))
1663 wv->help = (char *) XSTRING (help)->data;
1664 else
1665 wv->help = NULL;
1666
1667 prev_wv = wv;
1668
1669 i += MENU_ITEMS_ITEM_LENGTH;
1670 }
1671 }
1672
1673 /* Deal with the title, if it is non-nil. */
1674 if (!NILP (title))
1675 {
1676 widget_value *wv_title = xmalloc_widget_value ();
1677 widget_value *wv_sep = xmalloc_widget_value ();
1678
1679 /* Maybe replace this separator with a bitmap or owner-draw item
1680 so that it looks better. Having two separators looks odd. */
1681 wv_sep->name = "--";
1682 wv_sep->next = first_wv->contents;
1683
1684#ifndef HAVE_MULTILINGUAL_MENU
1685 if (STRING_MULTIBYTE (title))
1686 title = string_make_unibyte (title);
1687#endif
1688 wv_title->name = (char *) XSTRING (title)->data;
1689 wv_title->enabled = True;
1690 wv_title->button_type = BUTTON_TYPE_NONE;
1691 wv_title->next = wv_sep;
1692 first_wv->contents = wv_title;
1693 }
1694
1695 /* Actually create the menu. */
1696 menu = NewMenu (POPUP_SUBMENU_ID, "\p");
1697 fill_submenu (menu, first_wv->contents, 0);
1698
1699 /* Adjust coordinates to be root-window-relative. */
1700 pos.h = x;
1701 pos.v = y;
1702 SetPort (FRAME_MAC_WINDOW (f));
1703 LocalToGlobal (&pos);
1704
1705 /* No selection has been chosen yet. */
1706 menu_item_selection = 0;
1707
1708 InsertMenu (menu, -1);
1709
1710 /* Display the menu. */
1711 menu_item_selection = LoWord (PopUpMenuSelect (menu, pos.v, pos.h, 0));
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
new file mode 100644
index 00000000000..194af28b91d
--- /dev/null
+++ b/mac/src/macterm.c
@@ -0,0 +1,12446 @@
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 "coding.h"
94
95#ifdef HAVE_UNISTD_H
96#include <unistd.h>
97#endif
98
99#ifndef USE_X_TOOLKIT
100#define x_any_window_to_frame x_window_to_frame
101#define x_top_window_to_frame x_window_to_frame
102#endif
103
104#ifndef min
105#define min(a,b) ((a) < (b) ? (a) : (b))
106#endif
107#ifndef max
108#define max(a,b) ((a) > (b) ? (a) : (b))
109#endif
110
111#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
112
113
114/* Bitmaps for truncated lines. */
115
116enum bitmap_type
117{
118 NO_BITMAP,
119 LEFT_TRUNCATION_BITMAP,
120 RIGHT_TRUNCATION_BITMAP,
121 OVERLAY_ARROW_BITMAP,
122 CONTINUED_LINE_BITMAP,
123 CONTINUATION_LINE_BITMAP,
124 ZV_LINE_BITMAP
125};
126
127/* Bitmap drawn to indicate lines not displaying text if
128 `indicate-empty-lines' is non-nil. */
129
130#define zv_width 8
131#define zv_height 8
132static unsigned char zv_bits[] = {
133 0x00, 0x00, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00};
134
135/* An arrow like this: `<-'. */
136
137#define left_width 8
138#define left_height 8
139static unsigned char left_bits[] = {
140 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
141
142/* Right truncation arrow bitmap `->'. */
143
144#define right_width 8
145#define right_height 8
146static unsigned char right_bits[] = {
147 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
148
149/* Marker for continued lines. */
150
151#define continued_width 8
152#define continued_height 8
153static unsigned char continued_bits[] = {
154 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
155
156/* Marker for continuation lines. */
157
158#define continuation_width 8
159#define continuation_height 8
160static unsigned char continuation_bits[] = {
161 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
162
163/* Overlay arrow bitmap. */
164
165#if 0
166/* A bomb. */
167#define ov_width 8
168#define ov_height 8
169static unsigned char ov_bits[] = {
170 0x0c, 0x10, 0x3c, 0x7e, 0x5e, 0x5e, 0x46, 0x3c};
171#else
172/* A triangular arrow. */
173#define ov_width 8
174#define ov_height 8
175static unsigned char ov_bits[] = {
176 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0};
177#endif
178
179extern Lisp_Object Qhelp_echo;
180
181
182/* Non-zero means Emacs uses toolkit scroll bars. */
183
184int x_toolkit_scroll_bars_p;
185
186/* If a string, XTread_socket generates an event to display that string.
187 (The display is done in read_char.) */
188
189static Lisp_Object help_echo;
190static Lisp_Object help_echo_window;
191static Lisp_Object help_echo_object;
192static int help_echo_pos;
193
194/* Temporary variable for XTread_socket. */
195
196static Lisp_Object previous_help_echo;
197
198/* Non-zero means that a HELP_EVENT has been generated since Emacs
199 start. */
200
201static int any_help_event_p;
202
203/* Non-zero means draw block and hollow cursor as wide as the glyph
204 under it. For example, if a block cursor is over a tab, it will be
205 drawn as wide as that tab on the display. */
206
207int x_stretch_cursor_p;
208
209/* This is a chain of structures for all the X displays currently in
210 use. */
211
212struct x_display_info *x_display_list;
213
214/* This is a list of cons cells, each of the form (NAME
215 . FONT-LIST-CACHE), one for each element of x_display_list and in
216 the same order. NAME is the name of the frame. FONT-LIST-CACHE
217 records previous values returned by x-list-fonts. */
218
219Lisp_Object x_display_name_list;
220
221/* This is display since Mac does not support multiple ones. */
222struct mac_display_info one_mac_display_info;
223
224/* Frame being updated by update_frame. This is declared in term.c.
225 This is set by update_begin and looked at by all the XT functions.
226 It is zero while not inside an update. In that case, the XT
227 functions assume that `selected_frame' is the frame to apply to. */
228
229extern struct frame *updating_frame;
230
231extern int waiting_for_input;
232
233/* This is a frame waiting to be auto-raised, within XTread_socket. */
234
235struct frame *pending_autoraise_frame;
236
237/* Nominal cursor position -- where to draw output.
238 HPOS and VPOS are window relative glyph matrix coordinates.
239 X and Y are window relative pixel coordinates. */
240
241struct cursor_pos output_cursor;
242
243/* Non-zero means user is interacting with a toolkit scroll bar. */
244
245static int toolkit_scroll_bar_interaction;
246
247/* Mouse movement.
248
249 Formerly, we used PointerMotionHintMask (in standard_event_mask)
250 so that we would have to call XQueryPointer after each MotionNotify
251 event to ask for another such event. However, this made mouse tracking
252 slow, and there was a bug that made it eventually stop.
253
254 Simply asking for MotionNotify all the time seems to work better.
255
256 In order to avoid asking for motion events and then throwing most
257 of them away or busy-polling the server for mouse positions, we ask
258 the server for pointer motion hints. This means that we get only
259 one event per group of mouse movements. "Groups" are delimited by
260 other kinds of events (focus changes and button clicks, for
261 example), or by XQueryPointer calls; when one of these happens, we
262 get another MotionNotify event the next time the mouse moves. This
263 is at least as efficient as getting motion events when mouse
264 tracking is on, and I suspect only negligibly worse when tracking
265 is off. */
266
267/* Where the mouse was last time we reported a mouse event. */
268
269FRAME_PTR last_mouse_frame;
270static Rect last_mouse_glyph;
271static Lisp_Object last_mouse_press_frame;
272
273/* The scroll bar in which the last X motion event occurred.
274
275 If the last X motion event occurred in a scroll bar, we set this so
276 XTmouse_position can know whether to report a scroll bar motion or
277 an ordinary motion.
278
279 If the last X motion event didn't occur in a scroll bar, we set
280 this to Qnil, to tell XTmouse_position to return an ordinary motion
281 event. */
282
283static Lisp_Object last_mouse_scroll_bar;
284
285/* This is a hack. We would really prefer that XTmouse_position would
286 return the time associated with the position it returns, but there
287 doesn't seem to be any way to wrest the time-stamp from the server
288 along with the position query. So, we just keep track of the time
289 of the last movement we received, and return that in hopes that
290 it's somewhat accurate. */
291
292static Time last_mouse_movement_time;
293
294enum mouse_tracking_type {
295 mouse_tracking_none,
296 mouse_tracking_mouse_movement,
297 mouse_tracking_scroll_bar
298};
299
300enum mouse_tracking_type mouse_tracking_in_progress = mouse_tracking_none;
301
302struct scroll_bar *tracked_scroll_bar = NULL;
303
304/* Incremented by XTread_socket whenever it really tries to read
305 events. */
306
307#ifdef __STDC__
308static int volatile input_signal_count;
309#else
310static int input_signal_count;
311#endif
312
313/* Used locally within XTread_socket. */
314
315static int x_noop_count;
316
317/* Initial values of argv and argc. */
318
319extern char **initial_argv;
320extern int initial_argc;
321
322extern Lisp_Object Vcommand_line_args, Vsystem_name;
323
324/* Tells if a window manager is present or not. */
325
326extern Lisp_Object Vx_no_window_manager;
327
328extern Lisp_Object Qface, Qmouse_face;
329
330extern int errno;
331
332/* A mask of extra modifier bits to put into every keyboard char. */
333
334extern int extra_keyboard_modifiers;
335
336static Lisp_Object Qvendor_specific_keysyms;
337
338#if 0
339extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
340#endif
341
342extern Lisp_Object x_icon_type P_ ((struct frame *));
343
344
345#if __MRC__
346QDGlobals qd; /* QuickDraw global information structure. */
347#endif
348
349
350/* Enumeration for overriding/changing the face to use for drawing
351 glyphs in x_draw_glyphs. */
352
353enum draw_glyphs_face
354{
355 DRAW_NORMAL_TEXT,
356 DRAW_INVERSE_VIDEO,
357 DRAW_CURSOR,
358 DRAW_MOUSE_FACE,
359 DRAW_IMAGE_RAISED,
360 DRAW_IMAGE_SUNKEN
361};
362
363struct frame * x_window_to_frame (struct mac_display_info *, WindowPtr);
364struct mac_display_info *mac_display_info_for_display (Display *);
365static void x_update_window_end P_ ((struct window *, int, int));
366static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
367void x_delete_display P_ ((struct x_display_info *));
368static unsigned int x_mac_to_emacs_modifiers P_ ((struct x_display_info *,
369 unsigned short));
370static int fast_find_position P_ ((struct window *, int, int *, int *,
371 int *, int *));
372static void set_output_cursor P_ ((struct cursor_pos *));
373static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
374 int *, int *, int *));
375static void note_mode_line_highlight P_ ((struct window *, int, int));
376static void note_mouse_highlight P_ ((struct frame *, int, int));
377static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
378static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
379static void show_mouse_face P_ ((struct x_display_info *,
380 enum draw_glyphs_face));
381void clear_mouse_face P_ ((struct mac_display_info *));
382static int x_io_error_quitter P_ ((Display *));
383int x_catch_errors P_ ((Display *));
384void x_uncatch_errors P_ ((Display *, int));
385void x_lower_frame P_ ((struct frame *));
386void x_scroll_bar_clear P_ ((struct frame *));
387int x_had_errors_p P_ ((Display *));
388void x_wm_set_size_hint P_ ((struct frame *, long, int));
389void x_raise_frame P_ ((struct frame *));
390void x_set_window_size P_ ((struct frame *, int, int, int));
391void x_wm_set_window_state P_ ((struct frame *, int));
392void x_wm_set_icon_pixmap P_ ((struct frame *, int));
393void x_initialize P_ ((void));
394static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
395static int x_compute_min_glyph_bounds P_ ((struct frame *));
396enum text_cursor_kinds x_specified_cursor_type P_ ((Lisp_Object, int *));
397static void x_draw_phys_cursor_glyph P_ ((struct window *,
398 struct glyph_row *,
399 enum draw_glyphs_face));
400static void x_update_end P_ ((struct frame *));
401static void XTframe_up_to_date P_ ((struct frame *));
402static void XTreassert_line_highlight P_ ((int, int));
403static void x_change_line_highlight P_ ((int, int, int, int));
404static void XTset_terminal_modes P_ ((void));
405static void XTreset_terminal_modes P_ ((void));
406static void XTcursor_to P_ ((int, int, int, int));
407static void x_write_glyphs P_ ((struct glyph *, int));
408static void x_clear_end_of_line P_ ((int));
409static void x_clear_frame P_ ((void));
410static void x_clear_cursor P_ ((struct window *));
411static void frame_highlight P_ ((struct frame *));
412static void frame_unhighlight P_ ((struct frame *));
413static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
414static void XTframe_rehighlight P_ ((struct frame *));
415static void x_frame_rehighlight P_ ((struct x_display_info *));
416static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
417static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
418static int x_intersect_rectangles P_ ((Rect *, Rect *, Rect *));
419static void expose_frame P_ ((struct frame *, int, int, int, int));
420static void expose_window_tree P_ ((struct window *, Rect *));
421static void expose_window P_ ((struct window *, Rect *));
422static void expose_area P_ ((struct window *, struct glyph_row *,
423 XRectangle *, enum glyph_row_area));
424static void expose_line P_ ((struct window *, struct glyph_row *,
425 XRectangle *));
426void x_display_cursor (struct window *, int, int, int, int, int);
427void x_update_cursor P_ ((struct frame *, int));
428static void x_update_cursor_in_window_tree P_ ((struct window *, int));
429static void x_update_window_cursor P_ ((struct window *, int));
430static void x_erase_phys_cursor P_ ((struct window *));
431void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
432static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
433 enum bitmap_type));
434
435static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
436 GC, int));
437static int x_phys_cursor_in_rect_p P_ ((struct window *, Rect *));
438static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
439static void note_overwritten_text_cursor P_ ((struct window *, int, int));
440static void x_flush P_ ((struct frame *f));
441static void x_update_begin P_ ((struct frame *));
442static void x_update_window_begin P_ ((struct window *));
443static void x_draw_vertical_border P_ ((struct window *));
444static void x_after_update_window_line P_ ((struct glyph_row *));
445static INLINE void take_vertical_position_into_account P_ ((struct it *));
446static void x_produce_stretch_glyph P_ ((struct it *));
447
448static void activate_scroll_bars (FRAME_PTR);
449static void deactivate_scroll_bars (FRAME_PTR);
450
451extern int image_ascent (struct image *, struct face *);
452void x_set_offset (struct frame *, int, int, int);
453int x_bitmap_icon (struct frame *, Lisp_Object);
454void x_make_frame_visible (struct frame *);
455
456extern void window_scroll (Lisp_Object, int, int, int);
457
458/* Defined in macmenu.h. */
459extern void menubar_selection_callback (FRAME_PTR, int);
460extern void set_frame_menubar (FRAME_PTR, int, int);
461
462/* X display function emulation */
463
464/* Structure borrowed from Xlib.h to represent two-byte characters in
465 dumpglyphs. */
466
467typedef struct {
468 unsigned char byte1;
469 unsigned char byte2;
470} XChar2b;
471
472static void
473XFreePixmap (display, pixmap)
474 Display *display;
475 Pixmap pixmap;
476{
477 PixMap *p = (PixMap *) pixmap;
478
479 xfree (p->baseAddr);
480 xfree (p);
481}
482
483
484/* Set foreground color for subsequent QuickDraw commands. Assume
485 graphic port has already been set. */
486
487static void
488mac_set_forecolor (unsigned long color)
489{
490 RGBColor fg_color;
491
492 fg_color.red = RED_FROM_ULONG (color) * 256;
493 fg_color.green = GREEN_FROM_ULONG (color) * 256;
494 fg_color.blue = BLUE_FROM_ULONG (color) * 256;
495
496 RGBForeColor (&fg_color);
497}
498
499
500/* Set background color for subsequent QuickDraw commands. Assume
501 graphic port has already been set. */
502
503static void
504mac_set_backcolor (unsigned long color)
505{
506 RGBColor bg_color;
507
508 bg_color.red = RED_FROM_ULONG (color) * 256;
509 bg_color.green = GREEN_FROM_ULONG (color) * 256;
510 bg_color.blue = BLUE_FROM_ULONG (color) * 256;
511
512 RGBBackColor (&bg_color);
513}
514
515/* Set foreground and background color for subsequent QuickDraw
516 commands. Assume that the graphic port has already been set. */
517
518static void
519mac_set_colors (GC gc)
520{
521 mac_set_forecolor (gc->foreground);
522 mac_set_backcolor (gc->background);
523}
524
525/* Mac version of XDrawLine. */
526
527static void
528XDrawLine (display, w, gc, x1, y1, x2, y2)
529 Display *display;
530 WindowPtr w;
531 GC gc;
532 int x1, y1, x2, y2;
533{
534 SetPort (w);
535 mac_set_colors (gc);
536
537 MoveTo (x1, y1);
538 LineTo (x2, y2);
539}
540
541/* Mac version of XClearArea. */
542
543static void
544XClearArea (display, w, x, y, width, height, exposures)
545 Display *display;
546 WindowPtr w;
547 int x, y;
548 unsigned int width, height;
549 int exposures;
550{
551 struct mac_output *mwp = (mac_output *) GetWRefCon (w);
552 Rect r;
553 XGCValues xgc;
554
555 xgc.foreground = mwp->foreground_pixel;
556 xgc.background = mwp->background_pixel;
557
558 SetPort (w);
559 mac_set_colors (&xgc);
560 SetRect (&r, x, y, x + width, y + height);
561
562 EraseRect (&r);
563}
564
565/* Mac version of XClearWindow. */
566
567static void
568XClearWindow (display, w)
569 Display *display;
570 WindowPtr w;
571{
572 struct mac_output *mwp = (mac_output *) GetWRefCon (w);
573 XGCValues xgc;
574
575 xgc.foreground = mwp->foreground_pixel;
576 xgc.background = mwp->background_pixel;
577
578 SetPort (w);
579 mac_set_colors (&xgc);
580
581 EraseRect (&(w->portRect));
582}
583
584
585/* Mac replacement for XCopyArea. */
586
587static void
588mac_draw_bitmap (display, w, gc, x, y, bitmap)
589 Display *display;
590 WindowPtr w;
591 GC gc;
592 int x, y;
593 BitMap *bitmap;
594{
595 Rect r;
596
597 SetPort (w);
598 mac_set_colors (gc);
599 SetRect (&r, x, y, x + bitmap->bounds.right, y + bitmap->bounds.bottom);
600
601 CopyBits (bitmap, &(w->portBits), &(bitmap->bounds), &r, srcCopy, 0);
602}
603
604
605/* Mac replacement for XSetClipRectangles. */
606
607static void
608mac_set_clip_rectangle (display, w, r)
609 Display *display;
610 WindowPtr w;
611 Rect *r;
612{
613 SetPort (w);
614
615 ClipRect (r);
616}
617
618
619/* Mac replacement for XSetClipMask. */
620
621static void
622mac_reset_clipping (display, w)
623 Display *display;
624 WindowPtr w;
625{
626 Rect r;
627
628 SetPort (w);
629
630 SetRect (&r, -32767, -32767, 32767, 32767);
631 ClipRect (&r);
632}
633
634
635/* Mac replacement for XCreateBitmapFromBitmapData. */
636
637static void
638mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h)
639 BitMap *bitmap;
640 char *bits;
641 int w, h;
642{
643 int bytes_per_row, i, j;
644
645 bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */
646 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h);
647 if (!bitmap->baseAddr)
648 abort ();
649
650 bzero (bitmap->baseAddr, bitmap->rowBytes * h);
651 for (i = 0; i < h; i++)
652 for (j = 0; j < w; j++)
653 if (BitTst (bits, i * w + j))
654 BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j);
655
656 SetRect (&(bitmap->bounds), 0, 0, w, h);
657}
658
659
660static void
661mac_free_bitmap (bitmap)
662 BitMap *bitmap;
663{
664 xfree (bitmap->baseAddr);
665}
666
667/* Mac replacement for XFillRectangle. */
668
669static void
670XFillRectangle (display, w, gc, x, y, width, height)
671 Display *display;
672 WindowPtr w;
673 GC gc;
674 int x, y;
675 unsigned int width, height;
676{
677 Rect r;
678
679 SetPort (w);
680 mac_set_colors (gc);
681 SetRect (&r, x, y, x + width, y + height);
682
683 PaintRect (&r); /* using foreground color of gc */
684}
685
686
687/* Mac replacement for XDrawRectangle: dest is a window. */
688
689static void
690mac_draw_rectangle (display, w, gc, x, y, width, height)
691 Display *display;
692 WindowPtr w;
693 GC gc;
694 int x, y;
695 unsigned int width, height;
696{
697 Rect r;
698
699 SetPort (w);
700 mac_set_colors (gc);
701 SetRect (&r, x, y, x + width + 1, y + height + 1);
702
703 FrameRect (&r); /* using foreground color of gc */
704}
705
706
707/* Mac replacement for XDrawRectangle: dest is a Pixmap. */
708
709static void
710mac_draw_rectangle_to_pixmap (display, p, gc, x, y, width, height)
711 Display *display;
712 Pixmap p;
713 GC gc;
714 int x, y;
715 unsigned int width, height;
716{
717#if 0 /* MAC_TODO: draw a rectangle in a PixMap */
718 Rect r;
719
720 SetPort (w);
721 mac_set_colors (gc);
722 SetRect (&r, x, y, x + width, y + height);
723
724 FrameRect (&r); /* using foreground color of gc */
725#endif
726}
727
728
729static void
730mac_draw_string_common (display, w, gc, x, y, buf, nchars, mode,
731 bytes_per_char)
732 Display *display;
733 WindowPtr w;
734 GC gc;
735 int x, y;
736 char *buf;
737 int nchars, mode, bytes_per_char;
738{
739 SetPort (w);
740 mac_set_colors (gc);
741
742 TextFont (gc->font->mac_fontnum);
743 TextSize (gc->font->mac_fontsize);
744 TextFace (gc->font->mac_fontface);
745 TextMode (mode);
746
747 MoveTo (x, y);
748 DrawText (buf, 0, nchars * bytes_per_char);
749}
750
751
752/* Mac replacement for XDrawString. */
753
754static void
755XDrawString (display, w, gc, x, y, buf, nchars)
756 Display *display;
757 WindowPtr w;
758 GC gc;
759 int x, y;
760 char *buf;
761 int nchars;
762{
763 mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcOr, 1);
764}
765
766
767/* Mac replacement for XDrawString16. */
768
769static void
770XDrawString16 (display, w, gc, x, y, buf, nchars)
771 Display *display;
772 WindowPtr w;
773 GC gc;
774 int x, y;
775 XChar2b *buf;
776 int nchars;
777{
778 mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcOr,
779 2);
780}
781
782
783/* Mac replacement for XDrawImageString. */
784
785static void
786XDrawImageString (display, w, gc, x, y, buf, nchars)
787 Display *display;
788 WindowPtr w;
789 GC gc;
790 int x, y;
791 char *buf;
792 int nchars;
793{
794 mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcCopy, 1);
795}
796
797
798/* Mac replacement for XDrawString16. */
799
800static void
801XDrawImageString16 (display, w, gc, x, y, buf, nchars)
802 Display *display;
803 WindowPtr w;
804 GC gc;
805 int x, y;
806 XChar2b *buf;
807 int nchars;
808{
809 mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcCopy,
810 2);
811}
812
813
814/* Mac replacement for XCopyArea: dest must be window. */
815
816static void
817mac_copy_area (display, src, dest, gc, src_x, src_y, width, height, dest_x,
818 dest_y)
819 Display *display;
820 Pixmap src;
821 WindowPtr dest;
822 GC gc;
823 int src_x, src_y;
824 unsigned int width, height;
825 int dest_x, dest_y;
826{
827 Rect src_r, dest_r;
828
829 SetPort (dest);
830 mac_set_colors (gc);
831
832 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
833 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
834
835 CopyBits ((BitMap *) src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0);
836}
837
838
839/* Convert a pair of local coordinates to global (screen) coordinates.
840 Assume graphic port has been properly set. */
841static void
842local_to_global_coord (short *h, short *v)
843{
844 Point p;
845
846 p.h = *h;
847 p.v = *v;
848
849 LocalToGlobal (&p);
850
851 *h = p.h;
852 *v = p.v;
853}
854
855
856/* Mac replacement for XCopyArea: used only for scrolling. */
857
858static void
859mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y)
860 Display *display;
861 WindowPtr w;
862 GC gc;
863 int src_x, src_y;
864 unsigned int width, height;
865 int dest_x, dest_y;
866{
867 Rect src_r, dest_r;
868
869 SetPort (w);
870 mac_set_colors (gc);
871
872 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
873 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height);
874
875 /* Need to use global coordinates and screenBits since src and dest
876 areas overlap in general. */
877 local_to_global_coord (&src_r.left, &src_r.top);
878 local_to_global_coord (&src_r.right, &src_r.bottom);
879 local_to_global_coord (&dest_r.left, &dest_r.top);
880 local_to_global_coord (&dest_r.right, &dest_r.bottom);
881
882 CopyBits (&qd.screenBits, &qd.screenBits, &src_r, &dest_r, srcCopy, 0);
883}
884
885
886/* Mac replacement for XCopyArea: dest must be Pixmap. */
887
888static void
889mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height,
890 dest_x, dest_y)
891 Display *display;
892 Pixmap src;
893 Pixmap dest;
894 GC gc;
895 int src_x, src_y;
896 unsigned int width, height;
897 int dest_x, dest_y;
898{
899 Rect src_r, dest_r;
900 int src_right = ((PixMap *) src)->bounds.right;
901 int src_bottom = ((PixMap *) src)->bounds.bottom;
902 int w = src_right - src_x;
903 int h = src_bottom - src_y;
904
905 mac_set_colors (gc);
906
907 SetRect (&src_r, src_x, src_y, src_right, src_bottom);
908 SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h);
909
910 CopyBits ((BitMap *) src, (BitMap *) dest, &src_r, &dest_r, srcCopy, 0);
911}
912
913
914/* Mac replacement for XChangeGC. */
915
916static void
917XChangeGC (void * ignore, XGCValues* gc, unsigned long mask,
918 XGCValues *xgcv)
919{
920 if (mask & GCForeground)
921 gc->foreground = xgcv->foreground;
922 if (mask & GCBackground)
923 gc->background = xgcv->background;
924 if (mask & GCFont)
925 gc->font = xgcv->font;
926}
927
928
929/* Mac replacement for XCreateGC. */
930
931XGCValues *
932XCreateGC (void * ignore, Window window, unsigned long mask,
933 XGCValues *xgcv)
934{
935 XGCValues *gc = (XGCValues *) xmalloc (sizeof (XGCValues));
936 bzero (gc, sizeof (XGCValues));
937
938 XChangeGC (ignore, gc, mask, xgcv);
939
940 return gc;
941}
942
943
944/* Used in xfaces.c. */
945
946void
947XFreeGC (display, gc)
948 Display *display;
949 GC gc;
950{
951 xfree (gc);
952}
953
954
955/* Mac replacement for XGetGCValues. */
956
957static void
958XGetGCValues (void* ignore, XGCValues *gc,
959 unsigned long mask, XGCValues *xgcv)
960{
961 XChangeGC (ignore, xgcv, mask, gc);
962}
963
964
965/* Mac replacement for XSetForeground. */
966
967static void
968XSetForeground (display, gc, color)
969 Display *display;
970 GC gc;
971 unsigned long color;
972{
973 gc->foreground = color;
974}
975
976
977/* Mac replacement for XSetFont. */
978
979static void
980XSetFont (display, gc, font)
981 Display *display;
982 GC gc;
983 XFontStruct *font;
984{
985 gc->font = font;
986}
987
988
989static void
990XTextExtents16 (XFontStruct *font, XChar2b *text, int nchars,
991 int *direction,int *font_ascent,
992 int *font_descent, XCharStruct *cs)
993{
994 /* MAC_TODO: Use GetTextMetrics to do this and inline it below. */
995}
996
997
998/* x_sync is a no-op on Mac. */
999void
1000x_sync (f)
1001 void *f;
1002{
1003}
1004
1005
1006/* Flush display of frame F, or of all frames if F is null. */
1007
1008void
1009x_flush (f)
1010 struct frame *f;
1011{
1012#if 0 /* Nothing to do for Mac OS (needed in OS X perhaps?). */
1013 BLOCK_INPUT;
1014 if (f == NULL)
1015 {
1016 Lisp_Object rest, frame;
1017 FOR_EACH_FRAME (rest, frame)
1018 x_flush (XFRAME (frame));
1019 }
1020 else if (FRAME_X_P (f))
1021 XFlush (FRAME_MAC_DISPLAY (f));
1022 UNBLOCK_INPUT;
1023#endif
1024}
1025
1026
1027/* Remove calls to XFlush by defining XFlush to an empty replacement.
1028 Calls to XFlush should be unnecessary because the X output buffer
1029 is flushed automatically as needed by calls to XPending,
1030 XNextEvent, or XWindowEvent according to the XFlush man page.
1031 XTread_socket calls XPending. Removing XFlush improves
1032 performance. */
1033
1034#define XFlush(DISPLAY) (void) 0
1035
1036
1037/* Return the struct mac_display_info corresponding to DPY. There's
1038 only one. */
1039
1040struct mac_display_info *
1041mac_display_info_for_display (dpy)
1042 Display *dpy;
1043{
1044 return &one_mac_display_info;
1045}
1046
1047
1048
1049/***********************************************************************
1050 Starting and ending an update
1051 ***********************************************************************/
1052
1053/* Start an update of frame F. This function is installed as a hook
1054 for update_begin, i.e. it is called when update_begin is called.
1055 This function is called prior to calls to x_update_window_begin for
1056 each window being updated. Currently, there is nothing to do here
1057 because all interesting stuff is done on a window basis. */
1058
1059void
1060x_update_begin (f)
1061 struct frame *f;
1062{
1063 /* Nothing to do. */
1064}
1065
1066
1067/* Start update of window W. Set the global variable updated_window
1068 to the window being updated and set output_cursor to the cursor
1069 position of W. */
1070
1071void
1072x_update_window_begin (w)
1073 struct window *w;
1074{
1075 struct frame *f = XFRAME (WINDOW_FRAME (w));
1076 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f);
1077
1078 updated_window = w;
1079 set_output_cursor (&w->cursor);
1080
1081 BLOCK_INPUT;
1082
1083 if (f == display_info->mouse_face_mouse_frame)
1084 {
1085 /* Don't do highlighting for mouse motion during the update. */
1086 display_info->mouse_face_defer = 1;
1087
1088 /* If F needs to be redrawn, simply forget about any prior mouse
1089 highlighting. */
1090 if (FRAME_GARBAGED_P (f))
1091 display_info->mouse_face_window = Qnil;
1092
1093#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
1094 their mouse_face_p flag set, which means that they are always
1095 unequal to rows in a desired matrix which never have that
1096 flag set. So, rows containing mouse-face glyphs are never
1097 scrolled, and we don't have to switch the mouse highlight off
1098 here to prevent it from being scrolled. */
1099
1100 /* Can we tell that this update does not affect the window
1101 where the mouse highlight is? If so, no need to turn off.
1102 Likewise, don't do anything if the frame is garbaged;
1103 in that case, the frame's current matrix that we would use
1104 is all wrong, and we will redisplay that line anyway. */
1105 if (!NILP (display_info->mouse_face_window)
1106 && w == XWINDOW (display_info->mouse_face_window))
1107 {
1108 int i;
1109
1110 for (i = 0; i < w->desired_matrix->nrows; ++i)
1111 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
1112 break;
1113
1114 if (i < w->desired_matrix->nrows)
1115 clear_mouse_face (display_info);
1116 }
1117#endif /* 0 */
1118 }
1119
1120 UNBLOCK_INPUT;
1121}
1122
1123
1124/* Draw a vertical window border to the right of window W if W doesn't
1125 have vertical scroll bars. */
1126
1127static void
1128x_draw_vertical_border (w)
1129 struct window *w;
1130{
1131 struct frame *f = XFRAME (WINDOW_FRAME (w));
1132
1133 /* Redraw borders between horizontally adjacent windows. Don't
1134 do it for frames with vertical scroll bars because either the
1135 right scroll bar of a window, or the left scroll bar of its
1136 neighbor will suffice as a border. */
1137 if (!WINDOW_RIGHTMOST_P (w)
1138 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
1139 {
1140 int x0, x1, y0, y1;
1141
1142 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
1143 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
1144 y1 -= 1;
1145
1146 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1147 f->output_data.mac->normal_gc, x1, y0, x1, y1);
1148 }
1149}
1150
1151
1152/* End update of window W (which is equal to updated_window).
1153
1154 Draw vertical borders between horizontally adjacent windows, and
1155 display W's cursor if CURSOR_ON_P is non-zero.
1156
1157 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
1158 glyphs in mouse-face were overwritten. In that case we have to
1159 make sure that the mouse-highlight is properly redrawn.
1160
1161 W may be a menu bar pseudo-window in case we don't have X toolkit
1162 support. Such windows don't have a cursor, so don't display it
1163 here. */
1164
1165void
1166x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
1167 struct window *w;
1168 int cursor_on_p, mouse_face_overwritten_p;
1169{
1170 if (!w->pseudo_window_p)
1171 {
1172 struct mac_display_info *dpyinfo
1173 = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
1174
1175 BLOCK_INPUT;
1176
1177 /* If a row with mouse-face was overwritten, arrange for
1178 XTframe_up_to_date to redisplay the mouse highlight. */
1179 if (mouse_face_overwritten_p)
1180 {
1181 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1182 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1183 dpyinfo->mouse_face_window = Qnil;
1184 }
1185
1186 if (cursor_on_p)
1187 x_display_and_set_cursor (w, 1, output_cursor.hpos,
1188 output_cursor.vpos,
1189 output_cursor.x, output_cursor.y);
1190
1191 x_draw_vertical_border (w);
1192 UNBLOCK_INPUT;
1193 }
1194
1195 updated_window = NULL;
1196}
1197
1198
1199/* End update of frame F. This function is installed as a hook in
1200 update_end. */
1201
1202void
1203x_update_end (f)
1204 struct frame *f;
1205{
1206 /* Reset the background color of Mac OS Window to that of the frame after
1207 update so that it is used by Mac Toolbox to clear the update region before
1208 an update event is generated. */
1209 SetPort (FRAME_MAC_WINDOW (f));
1210 mac_set_backcolor (FRAME_BACKGROUND_PIXEL (f));
1211
1212 /* Mouse highlight may be displayed again. */
1213 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0;
1214
1215 BLOCK_INPUT;
1216 XFlush (FRAME_MAC_DISPLAY (f));
1217 UNBLOCK_INPUT;
1218}
1219
1220
1221/* This function is called from various places in xdisp.c whenever a
1222 complete update has been performed. The global variable
1223 updated_window is not available here. */
1224
1225void
1226XTframe_up_to_date (f)
1227 struct frame *f;
1228{
1229 if (FRAME_X_P (f))
1230 {
1231 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1232
1233 if (dpyinfo->mouse_face_deferred_gc
1234 || f == dpyinfo->mouse_face_mouse_frame)
1235 {
1236 BLOCK_INPUT;
1237 if (dpyinfo->mouse_face_mouse_frame)
1238 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1239 dpyinfo->mouse_face_mouse_x,
1240 dpyinfo->mouse_face_mouse_y);
1241 dpyinfo->mouse_face_deferred_gc = 0;
1242 UNBLOCK_INPUT;
1243 }
1244 }
1245}
1246
1247
1248/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1249 arrow bitmaps, or clear the areas where they would be displayed
1250 before DESIRED_ROW is made current. The window being updated is
1251 found in updated_window. This function It is called from
1252 update_window_line only if it is known that there are differences
1253 between bitmaps to be drawn between current row and DESIRED_ROW. */
1254
1255void
1256x_after_update_window_line (desired_row)
1257 struct glyph_row *desired_row;
1258{
1259 struct window *w = updated_window;
1260
1261 xassert (w);
1262
1263 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1264 {
1265 BLOCK_INPUT;
1266 x_draw_row_bitmaps (w, desired_row);
1267
1268 /* When a window has disappeared, make sure that no rest of
1269 full-width rows stays visible in the internal border. */
1270 if (windows_or_buffers_changed)
1271 {
1272 struct frame *f = XFRAME (w->frame);
1273 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
1274 int height = desired_row->visible_height;
1275 int x = (window_box_right (w, -1)
1276 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
1277 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1278
1279 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1280 x, y, width, height, 0);
1281 }
1282
1283 UNBLOCK_INPUT;
1284 }
1285}
1286
1287
1288/* Draw the bitmap WHICH in one of the areas to the left or right of
1289 window W. ROW is the glyph row for which to display the bitmap; it
1290 determines the vertical position at which the bitmap has to be
1291 drawn. */
1292
1293static void
1294x_draw_bitmap (w, row, which)
1295 struct window *w;
1296 struct glyph_row *row;
1297 enum bitmap_type which;
1298{
1299 struct frame *f = XFRAME (WINDOW_FRAME (w));
1300 Display *display = FRAME_MAC_DISPLAY (f);
1301 WindowPtr window = FRAME_MAC_WINDOW (f);
1302 int x, y, wd, h, dy;
1303 unsigned char *bits;
1304 BitMap bitmap;
1305 XGCValues gcv;
1306 struct face *face;
1307
1308 /* Must clip because of partially visible lines. */
1309 x_clip_to_row (w, row, 1);
1310
1311 switch (which)
1312 {
1313 case LEFT_TRUNCATION_BITMAP:
1314 wd = left_width;
1315 h = left_height;
1316 bits = left_bits;
1317 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
1318 - wd
1319 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
1320 break;
1321
1322 case OVERLAY_ARROW_BITMAP:
1323 wd = left_width;
1324 h = left_height;
1325 bits = ov_bits;
1326 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
1327 - wd
1328 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
1329 break;
1330
1331 case RIGHT_TRUNCATION_BITMAP:
1332 wd = right_width;
1333 h = right_height;
1334 bits = right_bits;
1335 x = window_box_right (w, -1);
1336 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
1337 break;
1338
1339 case CONTINUED_LINE_BITMAP:
1340 wd = right_width;
1341 h = right_height;
1342 bits = continued_bits;
1343 x = window_box_right (w, -1);
1344 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
1345 break;
1346
1347 case CONTINUATION_LINE_BITMAP:
1348 wd = continuation_width;
1349 h = continuation_height;
1350 bits = continuation_bits;
1351 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
1352 - wd
1353 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
1354 break;
1355
1356 case ZV_LINE_BITMAP:
1357 wd = zv_width;
1358 h = zv_height;
1359 bits = zv_bits;
1360 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
1361 - wd
1362 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
1363 break;
1364
1365 default:
1366 abort ();
1367 }
1368
1369 /* Convert to frame coordinates. Set dy to the offset in the row to
1370 start drawing the bitmap. */
1371 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
1372 dy = (row->height - h) / 2;
1373
1374 /* Draw the bitmap. I believe these small pixmaps can be cached
1375 by the server. */
1376 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
1377
1378 mac_create_bitmap_from_bitmap_data (&bitmap, bits, wd, h);
1379 gcv.foreground = face->foreground;
1380 gcv.background = face->background;
1381
1382 mac_draw_bitmap (display, window, &gcv, x, y + dy, &bitmap);
1383
1384 mac_free_bitmap (&bitmap);
1385 mac_reset_clipping (display, window);
1386}
1387
1388
1389/* Draw flags bitmaps for glyph row ROW on window W. Call this
1390 function with input blocked. */
1391
1392static void
1393x_draw_row_bitmaps (w, row)
1394 struct window *w;
1395 struct glyph_row *row;
1396{
1397 struct frame *f = XFRAME (w->frame);
1398 enum bitmap_type bitmap;
1399 struct face *face;
1400 int header_line_height = -1;
1401
1402 xassert (interrupt_input_blocked);
1403
1404 /* If row is completely invisible, because of vscrolling, we
1405 don't have to draw anything. */
1406 if (row->visible_height <= 0)
1407 return;
1408
1409 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
1410 PREPARE_FACE_FOR_DISPLAY (f, face);
1411
1412 /* Decide which bitmap to draw at the left side. */
1413 if (row->overlay_arrow_p)
1414 bitmap = OVERLAY_ARROW_BITMAP;
1415 else if (row->truncated_on_left_p)
1416 bitmap = LEFT_TRUNCATION_BITMAP;
1417 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
1418 bitmap = CONTINUATION_LINE_BITMAP;
1419 else if (row->indicate_empty_line_p)
1420 bitmap = ZV_LINE_BITMAP;
1421 else
1422 bitmap = NO_BITMAP;
1423
1424 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
1425 the flags area. */
1426 if (bitmap == NO_BITMAP
1427 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
1428 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
1429 {
1430 /* If W has a vertical border to its left, don't draw over it. */
1431 int border = ((XFASTINT (w->left) > 0
1432 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
1433 ? 1 : 0);
1434 int left = window_box_left (w, -1);
1435
1436 if (header_line_height < 0)
1437 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
1438
1439#if 0 /* MAC_TODO: stipple */
1440 /* In case the same realized face is used for bitmap areas and
1441 for something displayed in the text (e.g. face `region' on
1442 mono-displays, the fill style may have been changed to
1443 FillSolid in x_draw_glyph_string_background. */
1444 if (face->stipple)
1445 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1446 else
1447 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
1448
1449 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1450 face->gc,
1451 (left
1452 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
1453 + border),
1454 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
1455 row->y)),
1456 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
1457 row->visible_height);
1458 if (!face->stipple)
1459 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
1460#endif
1461 {
1462 XGCValues gcv;
1463 gcv.foreground = face->background;
1464 XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1465 &gcv,
1466 (left
1467 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
1468 + border),
1469 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
1470 row->y)),
1471 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
1472 row->visible_height);
1473 }
1474
1475 }
1476
1477 /* Draw the left bitmap. */
1478 if (bitmap != NO_BITMAP)
1479 x_draw_bitmap (w, row, bitmap);
1480
1481 /* Decide which bitmap to draw at the right side. */
1482 if (row->truncated_on_right_p)
1483 bitmap = RIGHT_TRUNCATION_BITMAP;
1484 else if (row->continued_p)
1485 bitmap = CONTINUED_LINE_BITMAP;
1486 else
1487 bitmap = NO_BITMAP;
1488
1489 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
1490 the flags area. */
1491 if (bitmap == NO_BITMAP
1492 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
1493 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
1494 {
1495 int right = window_box_right (w, -1);
1496
1497 if (header_line_height < 0)
1498 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
1499
1500#if 0 /* MAC_TODO: stipple */
1501 /* In case the same realized face is used for bitmap areas and
1502 for something displayed in the text (e.g. face `region' on
1503 mono-displays, the fill style may have been changed to
1504 FillSolid in x_draw_glyph_string_background. */
1505 if (face->stipple)
1506 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1507 else
1508 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
1509 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1510 face->gc,
1511 right,
1512 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
1513 row->y)),
1514 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
1515 row->visible_height);
1516 if (!face->stipple)
1517 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
1518#endif
1519 {
1520 XGCValues gcv;
1521 gcv.foreground = face->background;
1522 XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
1523 &gcv,
1524 right,
1525 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
1526 row->y)),
1527 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
1528 row->visible_height);
1529 }
1530
1531 }
1532
1533 /* Draw the right bitmap. */
1534 if (bitmap != NO_BITMAP)
1535 x_draw_bitmap (w, row, bitmap);
1536}
1537
1538
1539/***********************************************************************
1540 Line Highlighting
1541 ***********************************************************************/
1542
1543/* External interface to control of standout mode. Not used for X
1544 frames. Aborts when called. */
1545
1546void
1547XTreassert_line_highlight (new, vpos)
1548 int new, vpos;
1549{
1550 abort ();
1551}
1552
1553
1554/* Call this when about to modify line at position VPOS and change
1555 whether it is highlighted. Not used for X frames. Aborts when
1556 called. */
1557
1558void
1559x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1560 int new_highlight, vpos, y, first_unused_hpos;
1561{
1562 abort ();
1563}
1564
1565
1566/* This is called when starting Emacs and when restarting after
1567 suspend. When starting Emacs, no X window is mapped. And nothing
1568 must be done to Emacs's own window if it is suspended (though that
1569 rarely happens). */
1570
1571void
1572XTset_terminal_modes ()
1573{
1574}
1575
1576/* This is called when exiting or suspending Emacs. Exiting will make
1577 the X-windows go away, and suspending requires no action. */
1578
1579void
1580XTreset_terminal_modes ()
1581{
1582}
1583
1584
1585
1586/***********************************************************************
1587 Output Cursor
1588 ***********************************************************************/
1589
1590/* Set the global variable output_cursor to CURSOR. All cursor
1591 positions are relative to updated_window. */
1592
1593static void
1594set_output_cursor (cursor)
1595 struct cursor_pos *cursor;
1596{
1597 output_cursor.hpos = cursor->hpos;
1598 output_cursor.vpos = cursor->vpos;
1599 output_cursor.x = cursor->x;
1600 output_cursor.y = cursor->y;
1601}
1602
1603
1604/* Set a nominal cursor position.
1605
1606 HPOS and VPOS are column/row positions in a window glyph matrix. X
1607 and Y are window text area relative pixel positions.
1608
1609 If this is done during an update, updated_window will contain the
1610 window that is being updated and the position is the future output
1611 cursor position for that window. If updated_window is null, use
1612 selected_window and display the cursor at the given position. */
1613
1614void
1615XTcursor_to (vpos, hpos, y, x)
1616 int vpos, hpos, y, x;
1617{
1618 struct window *w;
1619
1620 /* If updated_window is not set, work on selected_window. */
1621 if (updated_window)
1622 w = updated_window;
1623 else
1624 w = XWINDOW (selected_window);
1625
1626 /* Set the output cursor. */
1627 output_cursor.hpos = hpos;
1628 output_cursor.vpos = vpos;
1629 output_cursor.x = x;
1630 output_cursor.y = y;
1631
1632 /* If not called as part of an update, really display the cursor.
1633 This will also set the cursor position of W. */
1634 if (updated_window == NULL)
1635 {
1636 BLOCK_INPUT;
1637 x_display_cursor (w, 1, hpos, vpos, x, y);
1638 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
1639 UNBLOCK_INPUT;
1640 }
1641}
1642
1643
1644
1645/***********************************************************************
1646 Display Iterator
1647 ***********************************************************************/
1648
1649/* Function prototypes of this page. */
1650
1651static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1652 struct glyph *,
1653 XChar2b *,
1654 int *));
1655static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1656 int, XChar2b *, int));
1657static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1658static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1659static void x_append_glyph P_ ((struct it *));
1660static void x_append_composite_glyph P_ ((struct it *));
1661static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1662 int, int, double));
1663static void x_produce_glyphs P_ ((struct it *));
1664static void x_produce_image_glyph P_ ((struct it *it));
1665
1666
1667/* Return a pointer to per-char metric information in FONT of a
1668 character pointed by B which is a pointer to an XChar2b. */
1669
1670#define PER_CHAR_METRIC(font, b) \
1671 ((font)->per_char \
1672 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1673 + (((font)->min_byte1 || (font)->max_byte1) \
1674 ? (((b)->byte1 - (font)->min_byte1) \
1675 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1676 : 0)) \
1677 : &((font)->max_bounds))
1678
1679
1680/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1681 is not contained in the font. */
1682
1683static INLINE XCharStruct *
1684x_per_char_metric (font, char2b)
1685 XFontStruct *font;
1686 XChar2b *char2b;
1687{
1688 /* The result metric information. */
1689 XCharStruct *pcm = NULL;
1690
1691 xassert (font && char2b);
1692
1693 if (font->per_char != NULL)
1694 {
1695 if (font->min_byte1 == 0 && font->max_byte1 == 0)
1696 {
1697 /* min_char_or_byte2 specifies the linear character index
1698 corresponding to the first element of the per_char array,
1699 max_char_or_byte2 is the index of the last character. A
1700 character with non-zero CHAR2B->byte1 is not in the font.
1701 A character with byte2 less than min_char_or_byte2 or
1702 greater max_char_or_byte2 is not in the font. */
1703 if (char2b->byte1 == 0
1704 && char2b->byte2 >= font->min_char_or_byte2
1705 && char2b->byte2 <= font->max_char_or_byte2)
1706 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
1707 }
1708 else
1709 {
1710 /* If either min_byte1 or max_byte1 are nonzero, both
1711 min_char_or_byte2 and max_char_or_byte2 are less than
1712 256, and the 2-byte character index values corresponding
1713 to the per_char array element N (counting from 0) are:
1714
1715 byte1 = N/D + min_byte1
1716 byte2 = N\D + min_char_or_byte2
1717
1718 where:
1719
1720 D = max_char_or_byte2 - min_char_or_byte2 + 1
1721 / = integer division
1722 \ = integer modulus */
1723 if (char2b->byte1 >= font->min_byte1
1724 && char2b->byte1 <= font->max_byte1
1725 && char2b->byte2 >= font->min_char_or_byte2
1726 && char2b->byte2 <= font->max_char_or_byte2)
1727 {
1728 pcm = (font->per_char
1729 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1730 * (char2b->byte1 - font->min_byte1))
1731 + (char2b->byte2 - font->min_char_or_byte2));
1732 }
1733 }
1734 }
1735 else
1736 {
1737 /* If the per_char pointer is null, all glyphs between the first
1738 and last character indexes inclusive have the same
1739 information, as given by both min_bounds and max_bounds. */
1740 if (char2b->byte2 >= font->min_char_or_byte2
1741 && char2b->byte2 <= font->max_char_or_byte2)
1742 pcm = &font->max_bounds;
1743 }
1744
1745 return ((pcm == NULL
1746 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
1747 ? NULL : pcm);
1748}
1749
1750
1751/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1752 the two-byte form of C. Encoding is returned in *CHAR2B. */
1753
1754static INLINE void
1755x_encode_char (c, char2b, font_info)
1756 int c;
1757 XChar2b *char2b;
1758 struct font_info *font_info;
1759{
1760 int charset = CHAR_CHARSET (c);
1761 XFontStruct *font = font_info->font;
1762
1763 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1764 This may be either a program in a special encoder language or a
1765 fixed encoding. */
1766 if (font_info->font_encoder)
1767 {
1768 /* It's a program. */
1769 struct ccl_program *ccl = font_info->font_encoder;
1770
1771 if (CHARSET_DIMENSION (charset) == 1)
1772 {
1773 ccl->reg[0] = charset;
1774 ccl->reg[1] = char2b->byte2;
1775 }
1776 else
1777 {
1778 ccl->reg[0] = charset;
1779 ccl->reg[1] = char2b->byte1;
1780 ccl->reg[2] = char2b->byte2;
1781 }
1782
1783 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1784
1785 /* We assume that MSBs are appropriately set/reset by CCL
1786 program. */
1787 if (font->max_byte1 == 0) /* 1-byte font */
1788 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
1789 else
1790 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1791 }
1792 else if (font_info->encoding[charset])
1793 {
1794 /* Fixed encoding scheme. See fontset.h for the meaning of the
1795 encoding numbers. */
1796 int enc = font_info->encoding[charset];
1797
1798 if ((enc == 1 || enc == 2)
1799 && CHARSET_DIMENSION (charset) == 2)
1800 char2b->byte1 |= 0x80;
1801
1802 if (enc == 1 || enc == 3)
1803 char2b->byte2 |= 0x80;
1804
1805 if (enc == 4)
1806 {
1807 int sjis1, sjis2;
1808
1809 ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2);
1810 char2b->byte1 = sjis1;
1811 char2b->byte2 = sjis2;
1812 }
1813 }
1814}
1815
1816
1817/* Get face and two-byte form of character C in face FACE_ID on frame
1818 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1819 means we want to display multibyte text. Value is a pointer to a
1820 realized face that is ready for display. */
1821
1822static INLINE struct face *
1823x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1824 struct frame *f;
1825 int c, face_id;
1826 XChar2b *char2b;
1827 int multibyte_p;
1828{
1829 struct face *face = FACE_FROM_ID (f, face_id);
1830
1831 if (!multibyte_p)
1832 {
1833 /* Unibyte case. We don't have to encode, but we have to make
1834 sure to use a face suitable for unibyte. */
1835 char2b->byte1 = 0;
1836 char2b->byte2 = c;
1837 face_id = FACE_FOR_CHAR (f, face, c);
1838 face = FACE_FROM_ID (f, face_id);
1839 }
1840 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1841 {
1842 /* Case of ASCII in a face known to fit ASCII. */
1843 char2b->byte1 = 0;
1844 char2b->byte2 = c;
1845 }
1846 else
1847 {
1848 int c1, c2, charset;
1849
1850 /* Split characters into bytes. If c2 is -1 afterwards, C is
1851 really a one-byte character so that byte1 is zero. */
1852 SPLIT_CHAR (c, charset, c1, c2);
1853 if (c2 > 0)
1854 char2b->byte1 = c1, char2b->byte2 = c2;
1855 else
1856 char2b->byte1 = 0, char2b->byte2 = c1;
1857
1858 /* Maybe encode the character in *CHAR2B. */
1859 if (face->font != NULL)
1860 {
1861 struct font_info *font_info
1862 = FONT_INFO_FROM_ID (f, face->font_info_id);
1863 if (font_info)
1864 x_encode_char (c, char2b, font_info);
1865 }
1866 }
1867
1868 /* Make sure X resources of the face are allocated. */
1869 xassert (face != NULL);
1870 PREPARE_FACE_FOR_DISPLAY (f, face);
1871
1872 return face;
1873}
1874
1875
1876/* Get face and two-byte form of character glyph GLYPH on frame F.
1877 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
1878 a pointer to a realized face that is ready for display. */
1879
1880static INLINE struct face *
1881x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
1882 struct frame *f;
1883 struct glyph *glyph;
1884 XChar2b *char2b;
1885 int *two_byte_p;
1886{
1887 struct face *face;
1888
1889 xassert (glyph->type == CHAR_GLYPH);
1890 face = FACE_FROM_ID (f, glyph->face_id);
1891
1892 if (two_byte_p)
1893 *two_byte_p = 0;
1894
1895 if (!glyph->multibyte_p)
1896 {
1897 /* Unibyte case. We don't have to encode, but we have to make
1898 sure to use a face suitable for unibyte. */
1899 char2b->byte1 = 0;
1900 char2b->byte2 = glyph->u.ch;
1901 }
1902 else if (glyph->u.ch < 128
1903 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
1904 {
1905 /* Case of ASCII in a face known to fit ASCII. */
1906 char2b->byte1 = 0;
1907 char2b->byte2 = glyph->u.ch;
1908 }
1909 else
1910 {
1911 int c1, c2, charset;
1912
1913 /* Split characters into bytes. If c2 is -1 afterwards, C is
1914 really a one-byte character so that byte1 is zero. */
1915 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
1916 if (c2 > 0)
1917 char2b->byte1 = c1, char2b->byte2 = c2;
1918 else
1919 char2b->byte1 = 0, char2b->byte2 = c1;
1920
1921 /* Maybe encode the character in *CHAR2B. */
1922 if (charset != CHARSET_ASCII)
1923 {
1924 struct font_info *font_info
1925 = FONT_INFO_FROM_ID (f, face->font_info_id);
1926 if (font_info)
1927 {
1928 x_encode_char (glyph->u.ch, char2b, font_info);
1929 if (two_byte_p)
1930 *two_byte_p
1931 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
1932 }
1933 }
1934 }
1935
1936 /* Make sure X resources of the face are allocated. */
1937 xassert (face != NULL);
1938 PREPARE_FACE_FOR_DISPLAY (f, face);
1939 return face;
1940}
1941
1942
1943/* Store one glyph for IT->char_to_display in IT->glyph_row.
1944 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1945
1946static INLINE void
1947x_append_glyph (it)
1948 struct it *it;
1949{
1950 struct glyph *glyph;
1951 enum glyph_row_area area = it->area;
1952
1953 xassert (it->glyph_row);
1954 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1955
1956 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1957 if (glyph < it->glyph_row->glyphs[area + 1])
1958 {
1959 glyph->charpos = CHARPOS (it->position);
1960 glyph->object = it->object;
1961 glyph->pixel_width = it->pixel_width;
1962 glyph->voffset = it->voffset;
1963 glyph->type = CHAR_GLYPH;
1964 glyph->multibyte_p = it->multibyte_p;
1965 glyph->left_box_line_p = it->start_of_box_run_p;
1966 glyph->right_box_line_p = it->end_of_box_run_p;
1967 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1968 || it->phys_descent > it->descent);
1969 glyph->padding_p = 0;
1970 glyph->glyph_not_available_p = it->glyph_not_available_p;
1971 glyph->face_id = it->face_id;
1972 glyph->u.ch = it->char_to_display;
1973 ++it->glyph_row->used[area];
1974 }
1975}
1976
1977/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1978 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1979
1980static INLINE void
1981x_append_composite_glyph (it)
1982 struct it *it;
1983{
1984 struct glyph *glyph;
1985 enum glyph_row_area area = it->area;
1986
1987 xassert (it->glyph_row);
1988
1989 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1990 if (glyph < it->glyph_row->glyphs[area + 1])
1991 {
1992 glyph->charpos = CHARPOS (it->position);
1993 glyph->object = it->object;
1994 glyph->pixel_width = it->pixel_width;
1995 glyph->voffset = it->voffset;
1996 glyph->type = COMPOSITE_GLYPH;
1997 glyph->multibyte_p = it->multibyte_p;
1998 glyph->left_box_line_p = it->start_of_box_run_p;
1999 glyph->right_box_line_p = it->end_of_box_run_p;
2000 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
2001 || it->phys_descent > it->descent);
2002 glyph->padding_p = 0;
2003 glyph->glyph_not_available_p = 0;
2004 glyph->face_id = it->face_id;
2005 glyph->u.cmp_id = it->cmp_id;
2006 ++it->glyph_row->used[area];
2007 }
2008}
2009
2010
2011/* Change IT->ascent and IT->height according to the setting of
2012 IT->voffset. */
2013
2014static INLINE void
2015take_vertical_position_into_account (it)
2016 struct it *it;
2017{
2018 if (it->voffset)
2019 {
2020 if (it->voffset < 0)
2021 /* Increase the ascent so that we can display the text higher
2022 in the line. */
2023 it->ascent += abs (it->voffset);
2024 else
2025 /* Increase the descent so that we can display the text lower
2026 in the line. */
2027 it->descent += it->voffset;
2028 }
2029}
2030
2031
2032/* Produce glyphs/get display metrics for the image IT is loaded with.
2033 See the description of struct display_iterator in dispextern.h for
2034 an overview of struct display_iterator. */
2035
2036static void
2037x_produce_image_glyph (it)
2038 struct it *it;
2039{
2040 struct image *img;
2041 struct face *face;
2042
2043 xassert (it->what == IT_IMAGE);
2044
2045 face = FACE_FROM_ID (it->f, it->face_id);
2046 img = IMAGE_FROM_ID (it->f, it->image_id);
2047 xassert (img);
2048
2049 /* Make sure X resources of the face and image are loaded. */
2050 PREPARE_FACE_FOR_DISPLAY (it->f, face);
2051 prepare_image_for_display (it->f, img);
2052
2053 it->ascent = it->phys_ascent = image_ascent (img, face);
2054 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
2055 it->pixel_width = img->width + 2 * img->margin;
2056
2057 it->nglyphs = 1;
2058
2059 if (face->box != FACE_NO_BOX)
2060 {
2061 it->ascent += face->box_line_width;
2062 it->descent += face->box_line_width;
2063
2064 if (it->start_of_box_run_p)
2065 it->pixel_width += face->box_line_width;
2066 if (it->end_of_box_run_p)
2067 it->pixel_width += face->box_line_width;
2068 }
2069
2070 take_vertical_position_into_account (it);
2071
2072 if (it->glyph_row)
2073 {
2074 struct glyph *glyph;
2075 enum glyph_row_area area = it->area;
2076
2077 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
2078 if (glyph < it->glyph_row->glyphs[area + 1])
2079 {
2080 glyph->charpos = CHARPOS (it->position);
2081 glyph->object = it->object;
2082 glyph->pixel_width = it->pixel_width;
2083 glyph->voffset = it->voffset;
2084 glyph->type = IMAGE_GLYPH;
2085 glyph->multibyte_p = it->multibyte_p;
2086 glyph->left_box_line_p = it->start_of_box_run_p;
2087 glyph->right_box_line_p = it->end_of_box_run_p;
2088 glyph->overlaps_vertically_p = 0;
2089 glyph->padding_p = 0;
2090 glyph->glyph_not_available_p = 0;
2091 glyph->face_id = it->face_id;
2092 glyph->u.img_id = img->id;
2093 ++it->glyph_row->used[area];
2094 }
2095 }
2096}
2097
2098
2099/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
2100 of the glyph, WIDTH and HEIGHT are the width and height of the
2101 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
2102 ascent of the glyph (0 <= ASCENT <= 1). */
2103
2104static void
2105x_append_stretch_glyph (it, object, width, height, ascent)
2106 struct it *it;
2107 Lisp_Object object;
2108 int width, height;
2109 double ascent;
2110{
2111 struct glyph *glyph;
2112 enum glyph_row_area area = it->area;
2113
2114 xassert (ascent >= 0 && ascent <= 1);
2115
2116 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
2117 if (glyph < it->glyph_row->glyphs[area + 1])
2118 {
2119 glyph->charpos = CHARPOS (it->position);
2120 glyph->object = object;
2121 glyph->pixel_width = width;
2122 glyph->voffset = it->voffset;
2123 glyph->type = STRETCH_GLYPH;
2124 glyph->multibyte_p = it->multibyte_p;
2125 glyph->left_box_line_p = it->start_of_box_run_p;
2126 glyph->right_box_line_p = it->end_of_box_run_p;
2127 glyph->overlaps_vertically_p = 0;
2128 glyph->padding_p = 0;
2129 glyph->glyph_not_available_p = 0;
2130 glyph->face_id = it->face_id;
2131 glyph->u.stretch.ascent = height * ascent;
2132 glyph->u.stretch.height = height;
2133 ++it->glyph_row->used[area];
2134 }
2135}
2136
2137
2138/* Produce a stretch glyph for iterator IT. IT->object is the value
2139 of the glyph property displayed. The value must be a list
2140 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
2141 being recognized:
2142
2143 1. `:width WIDTH' specifies that the space should be WIDTH *
2144 canonical char width wide. WIDTH may be an integer or floating
2145 point number.
2146
2147 2. `:relative-width FACTOR' specifies that the width of the stretch
2148 should be computed from the width of the first character having the
2149 `glyph' property, and should be FACTOR times that width.
2150
2151 3. `:align-to HPOS' specifies that the space should be wide enough
2152 to reach HPOS, a value in canonical character units.
2153
2154 Exactly one of the above pairs must be present.
2155
2156 4. `:height HEIGHT' specifies that the height of the stretch produced
2157 should be HEIGHT, measured in canonical character units.
2158
2159 5. `:relative-height FACTOR' specifies that the height of the the
2160 stretch should be FACTOR times the height of the characters having
2161 the glyph property.
2162
2163 Either none or exactly one of 4 or 5 must be present.
2164
2165 6. `:ascent ASCENT' specifies that ASCENT percent of the height
2166 of the stretch should be used for the ascent of the stretch.
2167 ASCENT must be in the range 0 <= ASCENT <= 100. */
2168
2169#define NUMVAL(X) \
2170 ((INTEGERP (X) || FLOATP (X)) \
2171 ? XFLOATINT (X) \
2172 : - 1)
2173
2174
2175static void
2176x_produce_stretch_glyph (it)
2177 struct it *it;
2178{
2179 /* (space :width WIDTH :height HEIGHT. */
2180#if GLYPH_DEBUG
2181 extern Lisp_Object Qspace;
2182#endif
2183 extern Lisp_Object QCwidth, QCheight, QCascent;
2184 extern Lisp_Object QCrelative_width, QCrelative_height;
2185 extern Lisp_Object QCalign_to;
2186 Lisp_Object prop, plist;
2187 double width = 0, height = 0, ascent = 0;
2188 struct face *face = FACE_FROM_ID (it->f, it->face_id);
2189 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
2190
2191 PREPARE_FACE_FOR_DISPLAY (it->f, face);
2192
2193 /* List should start with `space'. */
2194 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
2195 plist = XCDR (it->object);
2196
2197 /* Compute the width of the stretch. */
2198 if (prop = Fplist_get (plist, QCwidth),
2199 NUMVAL (prop) > 0)
2200 /* Absolute width `:width WIDTH' specified and valid. */
2201 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
2202 else if (prop = Fplist_get (plist, QCrelative_width),
2203 NUMVAL (prop) > 0)
2204 {
2205 /* Relative width `:relative-width FACTOR' specified and valid.
2206 Compute the width of the characters having the `glyph'
2207 property. */
2208 struct it it2;
2209 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
2210
2211 it2 = *it;
2212 if (it->multibyte_p)
2213 {
2214 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
2215 - IT_BYTEPOS (*it));
2216 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
2217 }
2218 else
2219 it2.c = *p, it2.len = 1;
2220
2221 it2.glyph_row = NULL;
2222 it2.what = IT_CHARACTER;
2223 x_produce_glyphs (&it2);
2224 width = NUMVAL (prop) * it2.pixel_width;
2225 }
2226 else if (prop = Fplist_get (plist, QCalign_to),
2227 NUMVAL (prop) > 0)
2228 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
2229 else
2230 /* Nothing specified -> width defaults to canonical char width. */
2231 width = CANON_X_UNIT (it->f);
2232
2233 /* Compute height. */
2234 if (prop = Fplist_get (plist, QCheight),
2235 NUMVAL (prop) > 0)
2236 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
2237 else if (prop = Fplist_get (plist, QCrelative_height),
2238 NUMVAL (prop) > 0)
2239 height = FONT_HEIGHT (font) * NUMVAL (prop);
2240 else
2241 height = FONT_HEIGHT (font);
2242
2243 /* Compute percentage of height used for ascent. If
2244 `:ascent ASCENT' is present and valid, use that. Otherwise,
2245 derive the ascent from the font in use. */
2246 if (prop = Fplist_get (plist, QCascent),
2247 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
2248 ascent = NUMVAL (prop) / 100.0;
2249 else
2250 ascent = (double) font->ascent / FONT_HEIGHT (font);
2251
2252 if (width <= 0)
2253 width = 1;
2254 if (height <= 0)
2255 height = 1;
2256
2257 if (it->glyph_row)
2258 {
2259 Lisp_Object object = it->stack[it->sp - 1].string;
2260 if (!STRINGP (object))
2261 object = it->w->buffer;
2262 x_append_stretch_glyph (it, object, width, height, ascent);
2263 }
2264
2265 it->pixel_width = width;
2266 it->ascent = it->phys_ascent = height * ascent;
2267 it->descent = it->phys_descent = height - it->ascent;
2268 it->nglyphs = 1;
2269
2270 if (face->box != FACE_NO_BOX)
2271 {
2272 it->ascent += face->box_line_width;
2273 it->descent += face->box_line_width;
2274
2275 if (it->start_of_box_run_p)
2276 it->pixel_width += face->box_line_width;
2277 if (it->end_of_box_run_p)
2278 it->pixel_width += face->box_line_width;
2279 }
2280
2281 take_vertical_position_into_account (it);
2282}
2283
2284/* Return proper value to be used as baseline offset of font that has
2285 ASCENT and DESCENT to draw characters by the font at the vertical
2286 center of the line of frame F.
2287
2288 Here, out task is to find the value of BOFF in the following figure;
2289
2290 -------------------------+-----------+-
2291 -+-+---------+-+ | |
2292 | | | | | |
2293 | | | | F_ASCENT F_HEIGHT
2294 | | | ASCENT | |
2295 HEIGHT | | | | |
2296 | | |-|-+------+-----------|------- baseline
2297 | | | | BOFF | |
2298 | |---------|-+-+ | |
2299 | | | DESCENT | |
2300 -+-+---------+-+ F_DESCENT |
2301 -------------------------+-----------+-
2302
2303 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
2304 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
2305 DESCENT = FONT->descent
2306 HEIGHT = FONT_HEIGHT (FONT)
2307 F_DESCENT = (F->output_data.x->font->descent
2308 - F->output_data.x->baseline_offset)
2309 F_HEIGHT = FRAME_LINE_HEIGHT (F)
2310*/
2311
2312#define VCENTER_BASELINE_OFFSET(FONT, F) \
2313 ((FONT)->descent \
2314 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
2315 - ((F)->output_data.mac->font->descent - (F)->output_data.mac->baseline_offset))
2316
2317/* Produce glyphs/get display metrics for the display element IT is
2318 loaded with. See the description of struct display_iterator in
2319 dispextern.h for an overview of struct display_iterator. */
2320
2321void
2322x_produce_glyphs (it)
2323 struct it *it;
2324{
2325 it->glyph_not_available_p = 0;
2326
2327 if (it->what == IT_CHARACTER)
2328 {
2329 XChar2b char2b;
2330 XFontStruct *font;
2331 struct face *face = FACE_FROM_ID (it->f, it->face_id);
2332 XCharStruct *pcm;
2333 int font_not_found_p;
2334 struct font_info *font_info;
2335 int boff; /* baseline offset */
2336
2337 /* Maybe translate single-byte characters to multibyte, or the
2338 other way. */
2339 it->char_to_display = it->c;
2340 if (!ASCII_BYTE_P (it->c))
2341 {
2342 if (unibyte_display_via_language_environment
2343 && SINGLE_BYTE_CHAR_P (it->c)
2344 && (it->c >= 0240
2345 || !NILP (Vnonascii_translation_table)))
2346 {
2347 it->char_to_display = unibyte_char_to_multibyte (it->c);
2348 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2349 face = FACE_FROM_ID (it->f, it->face_id);
2350 }
2351 else if (!SINGLE_BYTE_CHAR_P (it->c)
2352 && !it->multibyte_p)
2353 {
2354 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
2355 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2356 face = FACE_FROM_ID (it->f, it->face_id);
2357 }
2358 }
2359
2360 /* Get font to use. Encode IT->char_to_display. */
2361 x_get_char_face_and_encoding (it->f, it->char_to_display,
2362 it->face_id, &char2b,
2363 it->multibyte_p);
2364 font = face->font;
2365
2366 /* When no suitable font found, use the default font. */
2367 font_not_found_p = font == NULL;
2368 if (font_not_found_p)
2369 {
2370 font = FRAME_FONT (it->f);
2371 boff = it->f->output_data.mac->baseline_offset;
2372 font_info = NULL;
2373 }
2374 else
2375 {
2376 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2377 boff = font_info->baseline_offset;
2378 if (font_info->vertical_centering)
2379 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2380 }
2381
2382 if (it->char_to_display >= ' '
2383 && (!it->multibyte_p || it->char_to_display < 128))
2384 {
2385 /* Either unibyte or ASCII. */
2386 int stretched_p;
2387
2388 it->nglyphs = 1;
2389
2390 pcm = x_per_char_metric (font, &char2b);
2391 it->ascent = font->ascent + boff;
2392 it->descent = font->descent - boff;
2393
2394 if (pcm)
2395 {
2396 it->phys_ascent = pcm->ascent + boff;
2397 it->phys_descent = pcm->descent - boff;
2398 it->pixel_width = pcm->width;
2399 }
2400 else
2401 {
2402 it->glyph_not_available_p = 1;
2403 it->phys_ascent = font->ascent + boff;
2404 it->phys_descent = font->descent - boff;
2405 it->pixel_width = FONT_WIDTH (font);
2406 }
2407
2408 /* If this is a space inside a region of text with
2409 `space-width' property, change its width. */
2410 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
2411 if (stretched_p)
2412 it->pixel_width *= XFLOATINT (it->space_width);
2413
2414 /* If face has a box, add the box thickness to the character
2415 height. If character has a box line to the left and/or
2416 right, add the box line width to the character's width. */
2417 if (face->box != FACE_NO_BOX)
2418 {
2419 int thick = face->box_line_width;
2420
2421 it->ascent += thick;
2422 it->descent += thick;
2423
2424 if (it->start_of_box_run_p)
2425 it->pixel_width += thick;
2426 if (it->end_of_box_run_p)
2427 it->pixel_width += thick;
2428 }
2429
2430 /* If face has an overline, add the height of the overline
2431 (1 pixel) and a 1 pixel margin to the character height. */
2432 if (face->overline_p)
2433 it->ascent += 2;
2434
2435 take_vertical_position_into_account (it);
2436
2437 /* If we have to actually produce glyphs, do it. */
2438 if (it->glyph_row)
2439 {
2440 if (stretched_p)
2441 {
2442 /* Translate a space with a `space-width' property
2443 into a stretch glyph. */
2444 double ascent = (double) font->ascent / FONT_HEIGHT (font);
2445 x_append_stretch_glyph (it, it->object, it->pixel_width,
2446 it->ascent + it->descent, ascent);
2447 }
2448 else
2449 x_append_glyph (it);
2450
2451 /* If characters with lbearing or rbearing are displayed
2452 in this line, record that fact in a flag of the
2453 glyph row. This is used to optimize X output code. */
2454 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
2455 it->glyph_row->contains_overlapping_glyphs_p = 1;
2456 }
2457 }
2458 else if (it->char_to_display == '\n')
2459 {
2460 /* A newline has no width but we need the height of the line. */
2461 it->pixel_width = 0;
2462 it->nglyphs = 0;
2463 it->ascent = it->phys_ascent = font->ascent + boff;
2464 it->descent = it->phys_descent = font->descent - boff;
2465
2466 if (face->box != FACE_NO_BOX)
2467 {
2468 int thick = face->box_line_width;
2469 it->ascent += thick;
2470 it->descent += thick;
2471 }
2472 }
2473 else if (it->char_to_display == '\t')
2474 {
2475 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
2476 int x = it->current_x + it->continuation_lines_width;
2477 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2478
2479 it->pixel_width = next_tab_x - x;
2480 it->nglyphs = 1;
2481 it->ascent = it->phys_ascent = font->ascent + boff;
2482 it->descent = it->phys_descent = font->descent - boff;
2483
2484 if (it->glyph_row)
2485 {
2486 double ascent = (double) it->ascent / (it->ascent + it->descent);
2487 x_append_stretch_glyph (it, it->object, it->pixel_width,
2488 it->ascent + it->descent, ascent);
2489 }
2490 }
2491 else
2492 {
2493 /* A multi-byte character. Assume that the display width of the
2494 character is the width of the character multiplied by the
2495 width of the font. */
2496
2497 /* If we found a font, this font should give us the right
2498 metrics. If we didn't find a font, use the frame's
2499 default font and calculate the width of the character
2500 from the charset width; this is what old redisplay code
2501 did. */
2502 pcm = x_per_char_metric (font, &char2b);
2503 if (font_not_found_p || !pcm)
2504 {
2505 int charset = CHAR_CHARSET (it->char_to_display);
2506
2507 it->glyph_not_available_p = 1;
2508 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2509 * CHARSET_WIDTH (charset));
2510 it->phys_ascent = font->ascent + boff;
2511 it->phys_descent = font->descent - boff;
2512 }
2513 else
2514 {
2515 it->pixel_width = pcm->width;
2516 it->phys_ascent = pcm->ascent + boff;
2517 it->phys_descent = pcm->descent - boff;
2518 if (it->glyph_row
2519 && (pcm->lbearing < 0
2520 || pcm->rbearing > pcm->width))
2521 it->glyph_row->contains_overlapping_glyphs_p = 1;
2522 }
2523 it->nglyphs = 1;
2524 it->ascent = font->ascent + boff;
2525 it->descent = font->descent - boff;
2526 if (face->box != FACE_NO_BOX)
2527 {
2528 int thick = face->box_line_width;
2529 it->ascent += thick;
2530 it->descent += thick;
2531
2532 if (it->start_of_box_run_p)
2533 it->pixel_width += thick;
2534 if (it->end_of_box_run_p)
2535 it->pixel_width += thick;
2536 }
2537
2538 /* If face has an overline, add the height of the overline
2539 (1 pixel) and a 1 pixel margin to the character height. */
2540 if (face->overline_p)
2541 it->ascent += 2;
2542
2543 take_vertical_position_into_account (it);
2544
2545 if (it->glyph_row)
2546 x_append_glyph (it);
2547 }
2548 }
2549 else if (it->what == IT_COMPOSITION)
2550 {
2551 /* Note: A composition is represented as one glyph in the
2552 glyph matrix. There are no padding glyphs. */
2553 XChar2b char2b;
2554 XFontStruct *font;
2555 struct face *face = FACE_FROM_ID (it->f, it->face_id);
2556 XCharStruct *pcm;
2557 int font_not_found_p;
2558 struct font_info *font_info;
2559 int boff; /* baseline offset */
2560 struct composition *cmp = composition_table[it->cmp_id];
2561
2562 /* Maybe translate single-byte characters to multibyte. */
2563 it->char_to_display = it->c;
2564 if (unibyte_display_via_language_environment
2565 && SINGLE_BYTE_CHAR_P (it->c)
2566 && (it->c >= 0240
2567 || (it->c >= 0200
2568 && !NILP (Vnonascii_translation_table))))
2569 {
2570 it->char_to_display = unibyte_char_to_multibyte (it->c);
2571 }
2572
2573 /* Get face and font to use. Encode IT->char_to_display. */
2574 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2575 face = FACE_FROM_ID (it->f, it->face_id);
2576 x_get_char_face_and_encoding (it->f, it->char_to_display,
2577 it->face_id, &char2b, it->multibyte_p);
2578 font = face->font;
2579
2580 /* When no suitable font found, use the default font. */
2581 font_not_found_p = font == NULL;
2582 if (font_not_found_p)
2583 {
2584 font = FRAME_FONT (it->f);
2585 boff = it->f->output_data.mac->baseline_offset;
2586 font_info = NULL;
2587 }
2588 else
2589 {
2590 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2591 boff = font_info->baseline_offset;
2592 if (font_info->vertical_centering)
2593 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2594 }
2595
2596 /* There are no padding glyphs, so there is only one glyph to
2597 produce for the composition. Important is that pixel_width,
2598 ascent and descent are the values of what is drawn by
2599 draw_glyphs (i.e. the values of the overall glyphs composed). */
2600 it->nglyphs = 1;
2601
2602 /* If we have not yet calculated pixel size data of glyphs of
2603 the composition for the current face font, calculate them
2604 now. Theoretically, we have to check all fonts for the
2605 glyphs, but that requires much time and memory space. So,
2606 here we check only the font of the first glyph. This leads
2607 to incorrect display very rarely, and C-l (recenter) can
2608 correct the display anyway. */
2609 if (cmp->font != (void *) font)
2610 {
2611 /* Ascent and descent of the font of the first character of
2612 this composition (adjusted by baseline offset). Ascent
2613 and descent of overall glyphs should not be less than
2614 them respectively. */
2615 int font_ascent = font->ascent + boff;
2616 int font_descent = font->descent - boff;
2617 /* Bounding box of the overall glyphs. */
2618 int leftmost, rightmost, lowest, highest;
2619 int i, width, ascent, descent;
2620
2621 cmp->font = (void *) font;
2622
2623 /* Initialize the bounding box. */
2624 pcm = x_per_char_metric (font, &char2b);
2625 if (pcm)
2626 {
2627 width = pcm->width;
2628 ascent = pcm->ascent;
2629 descent = pcm->descent;
2630 }
2631 else
2632 {
2633 width = FONT_WIDTH (font);
2634 ascent = font->ascent;
2635 descent = font->descent;
2636 }
2637
2638 rightmost = width;
2639 lowest = - descent + boff;
2640 highest = ascent + boff;
2641 leftmost = 0;
2642
2643 if (font_info
2644 && font_info->default_ascent
2645 && CHAR_TABLE_P (Vuse_default_ascent)
2646 && !NILP (Faref (Vuse_default_ascent,
2647 make_number (it->char_to_display))))
2648 highest = font_info->default_ascent + boff;
2649
2650 /* Draw the first glyph at the normal position. It may be
2651 shifted to right later if some other glyphs are drawn at
2652 the left. */
2653 cmp->offsets[0] = 0;
2654 cmp->offsets[1] = boff;
2655
2656 /* Set cmp->offsets for the remaining glyphs. */
2657 for (i = 1; i < cmp->glyph_len; i++)
2658 {
2659 int left, right, btm, top;
2660 int ch = COMPOSITION_GLYPH (cmp, i);
2661 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2662
2663 face = FACE_FROM_ID (it->f, face_id);
2664 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2665 it->multibyte_p);
2666 font = face->font;
2667 if (font == NULL)
2668 {
2669 font = FRAME_FONT (it->f);
2670 boff = it->f->output_data.mac->baseline_offset;
2671 font_info = NULL;
2672 }
2673 else
2674 {
2675 font_info
2676 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2677 boff = font_info->baseline_offset;
2678 if (font_info->vertical_centering)
2679 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2680 }
2681
2682 pcm = x_per_char_metric (font, &char2b);
2683 if (pcm)
2684 {
2685 width = pcm->width;
2686 ascent = pcm->ascent;
2687 descent = pcm->descent;
2688 }
2689 else
2690 {
2691 width = FONT_WIDTH (font);
2692 ascent = font->ascent;
2693 descent = font->descent;
2694 }
2695
2696 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2697 {
2698 /* Relative composition with or without
2699 alternate chars. */
2700 left = (leftmost + rightmost - width) / 2;
2701 btm = - descent + boff;
2702 if (font_info && font_info->relative_compose
2703 && (! CHAR_TABLE_P (Vignore_relative_composition)
2704 || NILP (Faref (Vignore_relative_composition,
2705 make_number (ch)))))
2706 {
2707
2708 if (- descent >= font_info->relative_compose)
2709 /* One extra pixel between two glyphs. */
2710 btm = highest + 1;
2711 else if (ascent <= 0)
2712 /* One extra pixel between two glyphs. */
2713 btm = lowest - 1 - ascent - descent;
2714 }
2715 }
2716 else
2717 {
2718 /* A composition rule is specified by an integer
2719 value that encodes global and new reference
2720 points (GREF and NREF). GREF and NREF are
2721 specified by numbers as below:
2722
2723 0---1---2 -- ascent
2724 | |
2725 | |
2726 | |
2727 9--10--11 -- center
2728 | |
2729 ---3---4---5--- baseline
2730 | |
2731 6---7---8 -- descent
2732 */
2733 int rule = COMPOSITION_RULE (cmp, i);
2734 int gref, nref, grefx, grefy, nrefx, nrefy;
2735
2736 COMPOSITION_DECODE_RULE (rule, gref, nref);
2737 grefx = gref % 3, nrefx = nref % 3;
2738 grefy = gref / 3, nrefy = nref / 3;
2739
2740 left = (leftmost
2741 + grefx * (rightmost - leftmost) / 2
2742 - nrefx * width / 2);
2743 btm = ((grefy == 0 ? highest
2744 : grefy == 1 ? 0
2745 : grefy == 2 ? lowest
2746 : (highest + lowest) / 2)
2747 - (nrefy == 0 ? ascent + descent
2748 : nrefy == 1 ? descent - boff
2749 : nrefy == 2 ? 0
2750 : (ascent + descent) / 2));
2751 }
2752
2753 cmp->offsets[i * 2] = left;
2754 cmp->offsets[i * 2 + 1] = btm + descent;
2755
2756 /* Update the bounding box of the overall glyphs. */
2757 right = left + width;
2758 top = btm + descent + ascent;
2759 if (left < leftmost)
2760 leftmost = left;
2761 if (right > rightmost)
2762 rightmost = right;
2763 if (top > highest)
2764 highest = top;
2765 if (btm < lowest)
2766 lowest = btm;
2767 }
2768
2769 /* If there are glyphs whose x-offsets are negative,
2770 shift all glyphs to the right and make all x-offsets
2771 non-negative. */
2772 if (leftmost < 0)
2773 {
2774 for (i = 0; i < cmp->glyph_len; i++)
2775 cmp->offsets[i * 2] -= leftmost;
2776 rightmost -= leftmost;
2777 }
2778
2779 cmp->pixel_width = rightmost;
2780 cmp->ascent = highest;
2781 cmp->descent = - lowest;
2782 if (cmp->ascent < font_ascent)
2783 cmp->ascent = font_ascent;
2784 if (cmp->descent < font_descent)
2785 cmp->descent = font_descent;
2786 }
2787
2788 it->pixel_width = cmp->pixel_width;
2789 it->ascent = it->phys_ascent = cmp->ascent;
2790 it->descent = it->phys_descent = cmp->descent;
2791
2792 if (face->box != FACE_NO_BOX)
2793 {
2794 int thick = face->box_line_width;
2795 it->ascent += thick;
2796 it->descent += thick;
2797
2798 if (it->start_of_box_run_p)
2799 it->pixel_width += thick;
2800 if (it->end_of_box_run_p)
2801 it->pixel_width += thick;
2802 }
2803
2804 /* If face has an overline, add the height of the overline
2805 (1 pixel) and a 1 pixel margin to the character height. */
2806 if (face->overline_p)
2807 it->ascent += 2;
2808
2809 take_vertical_position_into_account (it);
2810
2811 if (it->glyph_row)
2812 x_append_composite_glyph (it);
2813 }
2814 else if (it->what == IT_IMAGE)
2815 x_produce_image_glyph (it);
2816 else if (it->what == IT_STRETCH)
2817 x_produce_stretch_glyph (it);
2818
2819 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2820 because this isn't true for images with `:ascent 100'. */
2821 xassert (it->ascent >= 0 && it->descent >= 0);
2822 if (it->area == TEXT_AREA)
2823 it->current_x += it->pixel_width;
2824
2825 it->descent += it->extra_line_spacing;
2826
2827 it->max_ascent = max (it->max_ascent, it->ascent);
2828 it->max_descent = max (it->max_descent, it->descent);
2829 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2830 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
2831}
2832
2833
2834/* Estimate the pixel height of the mode or top line on frame F.
2835 FACE_ID specifies what line's height to estimate. */
2836
2837int
2838x_estimate_mode_line_height (f, face_id)
2839 struct frame *f;
2840 enum face_id face_id;
2841{
2842 int height = 1;
2843
2844 /* This function is called so early when Emacs starts that the face
2845 cache and mode line face are not yet initialized. */
2846 if (FRAME_FACE_CACHE (f))
2847 {
2848 struct face *face = FACE_FROM_ID (f, face_id);
2849 if (face)
2850 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2851 }
2852
2853 return height;
2854}
2855
2856
2857/***********************************************************************
2858 Glyph display
2859 ***********************************************************************/
2860
2861/* A sequence of glyphs to be drawn in the same face.
2862
2863 This data structure is not really completely X specific, so it
2864 could possibly, at least partially, be useful for other systems. It
2865 is currently not part of the external redisplay interface because
2866 it's not clear what other systems will need. */
2867
2868struct glyph_string
2869{
2870 /* X-origin of the string. */
2871 int x;
2872
2873 /* Y-origin and y-position of the base line of this string. */
2874 int y, ybase;
2875
2876 /* The width of the string, not including a face extension. */
2877 int width;
2878
2879 /* The width of the string, including a face extension. */
2880 int background_width;
2881
2882 /* The height of this string. This is the height of the line this
2883 string is drawn in, and can be different from the height of the
2884 font the string is drawn in. */
2885 int height;
2886
2887 /* Number of pixels this string overwrites in front of its x-origin.
2888 This number is zero if the string has an lbearing >= 0; it is
2889 -lbearing, if the string has an lbearing < 0. */
2890 int left_overhang;
2891
2892 /* Number of pixels this string overwrites past its right-most
2893 nominal x-position, i.e. x + width. Zero if the string's
2894 rbearing is <= its nominal width, rbearing - width otherwise. */
2895 int right_overhang;
2896
2897 /* The frame on which the glyph string is drawn. */
2898 struct frame *f;
2899
2900 /* The window on which the glyph string is drawn. */
2901 struct window *w;
2902
2903 /* X display and window for convenience. */
2904 Display *display;
2905 Window window;
2906
2907 /* The glyph row for which this string was built. It determines the
2908 y-origin and height of the string. */
2909 struct glyph_row *row;
2910
2911 /* The area within row. */
2912 enum glyph_row_area area;
2913
2914 /* Characters to be drawn, and number of characters. */
2915 XChar2b *char2b;
2916 int nchars;
2917
2918 /* A face-override for drawing cursors, mouse face and similar. */
2919 enum draw_glyphs_face hl;
2920
2921 /* Face in which this string is to be drawn. */
2922 struct face *face;
2923
2924 /* Font in which this string is to be drawn. */
2925 XFontStruct *font;
2926
2927 /* Font info for this string. */
2928 struct font_info *font_info;
2929
2930 /* Non-null means this string describes (part of) a composition.
2931 All characters from char2b are drawn composed. */
2932 struct composition *cmp;
2933
2934 /* Index of this glyph string's first character in the glyph
2935 definition of CMP. If this is zero, this glyph string describes
2936 the first character of a composition. */
2937 int gidx;
2938
2939 /* 1 means this glyph strings face has to be drawn to the right end
2940 of the window's drawing area. */
2941 unsigned extends_to_end_of_line_p : 1;
2942
2943 /* 1 means the background of this string has been drawn. */
2944 unsigned background_filled_p : 1;
2945
2946 /* 1 means glyph string must be drawn with 16-bit functions. */
2947 unsigned two_byte_p : 1;
2948
2949 /* 1 means that the original font determined for drawing this glyph
2950 string could not be loaded. The member `font' has been set to
2951 the frame's default font in this case. */
2952 unsigned font_not_found_p : 1;
2953
2954 /* 1 means that the face in which this glyph string is drawn has a
2955 stipple pattern. */
2956 unsigned stippled_p : 1;
2957
2958 /* 1 means only the foreground of this glyph string must be drawn,
2959 and we should use the physical height of the line this glyph
2960 string appears in as clip rect. */
2961 unsigned for_overlaps_p : 1;
2962
2963 /* The GC to use for drawing this glyph string. */
2964 GC gc;
2965
2966 /* A pointer to the first glyph in the string. This glyph
2967 corresponds to char2b[0]. Needed to draw rectangles if
2968 font_not_found_p is 1. */
2969 struct glyph *first_glyph;
2970
2971 /* Image, if any. */
2972 struct image *img;
2973
2974 struct glyph_string *next, *prev;
2975};
2976
2977
2978#if 0
2979
2980static void
2981x_dump_glyph_string (s)
2982 struct glyph_string *s;
2983{
2984 fprintf (stderr, "glyph string\n");
2985 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2986 s->x, s->y, s->width, s->height);
2987 fprintf (stderr, " ybase = %d\n", s->ybase);
2988 fprintf (stderr, " hl = %d\n", s->hl);
2989 fprintf (stderr, " left overhang = %d, right = %d\n",
2990 s->left_overhang, s->right_overhang);
2991 fprintf (stderr, " nchars = %d\n", s->nchars);
2992 fprintf (stderr, " extends to end of line = %d\n",
2993 s->extends_to_end_of_line_p);
2994 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2995 fprintf (stderr, " bg width = %d\n", s->background_width);
2996}
2997
2998#endif /* GLYPH_DEBUG */
2999
3000
3001
3002static void x_append_glyph_string_lists P_ ((struct glyph_string **,
3003 struct glyph_string **,
3004 struct glyph_string *,
3005 struct glyph_string *));
3006static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
3007 struct glyph_string **,
3008 struct glyph_string *,
3009 struct glyph_string *));
3010static void x_append_glyph_string P_ ((struct glyph_string **,
3011 struct glyph_string **,
3012 struct glyph_string *));
3013static int x_left_overwritten P_ ((struct glyph_string *));
3014static int x_left_overwriting P_ ((struct glyph_string *));
3015static int x_right_overwritten P_ ((struct glyph_string *));
3016static int x_right_overwriting P_ ((struct glyph_string *));
3017static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
3018 int));
3019static void x_init_glyph_string P_ ((struct glyph_string *,
3020 XChar2b *, struct window *,
3021 struct glyph_row *,
3022 enum glyph_row_area, int,
3023 enum draw_glyphs_face));
3024static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
3025 enum glyph_row_area, int, int,
3026 enum draw_glyphs_face, int *, int *, int));
3027static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
3028static void x_set_glyph_string_gc P_ ((struct glyph_string *));
3029static void x_draw_glyph_string_background P_ ((struct glyph_string *,
3030 int));
3031static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
3032static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
3033static void x_draw_glyph_string_box P_ ((struct glyph_string *));
3034static void x_draw_glyph_string P_ ((struct glyph_string *));
3035static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
3036static void x_set_cursor_gc P_ ((struct glyph_string *));
3037static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
3038static void x_set_mouse_face_gc P_ ((struct glyph_string *));
3039static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
3040 int *, int *));
3041static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
3042static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
3043 unsigned long *, double, int));
3044static void x_setup_relief_color P_ ((struct frame *, struct relief *,
3045 double, int, unsigned long));
3046static void x_setup_relief_colors P_ ((struct glyph_string *));
3047static void x_draw_image_glyph_string P_ ((struct glyph_string *));
3048static void x_draw_image_relief P_ ((struct glyph_string *));
3049static void x_draw_image_foreground P_ ((struct glyph_string *));
3050static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
3051static void x_fill_image_glyph_string P_ ((struct glyph_string *));
3052static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
3053 int, int, int));
3054static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
3055 int, int, int, int, XRectangle *));
3056static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
3057 int, int, int, XRectangle *));
3058static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
3059 enum glyph_row_area));
3060static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
3061 struct glyph_row *,
3062 enum glyph_row_area, int, int));
3063
3064#if GLYPH_DEBUG
3065static void x_check_font P_ ((struct frame *, XFontStruct *));
3066#endif
3067
3068
3069/* Append the list of glyph strings with head H and tail T to the list
3070 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
3071
3072static INLINE void
3073x_append_glyph_string_lists (head, tail, h, t)
3074 struct glyph_string **head, **tail;
3075 struct glyph_string *h, *t;
3076{
3077 if (h)
3078 {
3079 if (*head)
3080 (*tail)->next = h;
3081 else
3082 *head = h;
3083 h->prev = *tail;
3084 *tail = t;
3085 }
3086}
3087
3088
3089/* Prepend the list of glyph strings with head H and tail T to the
3090 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
3091 result. */
3092
3093static INLINE void
3094x_prepend_glyph_string_lists (head, tail, h, t)
3095 struct glyph_string **head, **tail;
3096 struct glyph_string *h, *t;
3097{
3098 if (h)
3099 {
3100 if (*head)
3101 (*head)->prev = t;
3102 else
3103 *tail = t;
3104 t->next = *head;
3105 *head = h;
3106 }
3107}
3108
3109
3110/* Append glyph string S to the list with head *HEAD and tail *TAIL.
3111 Set *HEAD and *TAIL to the resulting list. */
3112
3113static INLINE void
3114x_append_glyph_string (head, tail, s)
3115 struct glyph_string **head, **tail;
3116 struct glyph_string *s;
3117{
3118 s->next = s->prev = NULL;
3119 x_append_glyph_string_lists (head, tail, s, s);
3120}
3121
3122
3123/* Set S->gc to a suitable GC for drawing glyph string S in cursor
3124 face. */
3125
3126static void
3127x_set_cursor_gc (s)
3128 struct glyph_string *s;
3129{
3130 if (s->font == FRAME_FONT (s->f)
3131 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
3132 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
3133 && !s->cmp)
3134 s->gc = s->f->output_data.mac->cursor_gc;
3135 else
3136 {
3137 /* Cursor on non-default face: must merge. */
3138 XGCValues xgcv;
3139 unsigned long mask;
3140
3141 xgcv.background = s->f->output_data.mac->cursor_pixel;
3142 xgcv.foreground = s->face->background;
3143
3144 /* If the glyph would be invisible, try a different foreground. */
3145 if (xgcv.foreground == xgcv.background)
3146 xgcv.foreground = s->face->foreground;
3147 if (xgcv.foreground == xgcv.background)
3148 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel;
3149 if (xgcv.foreground == xgcv.background)
3150 xgcv.foreground = s->face->foreground;
3151
3152 /* Make sure the cursor is distinct from text in this face. */
3153 if (xgcv.background == s->face->background
3154 && xgcv.foreground == s->face->foreground)
3155 {
3156 xgcv.background = s->face->foreground;
3157 xgcv.foreground = s->face->background;
3158 }
3159
3160 IF_DEBUG (x_check_font (s->f, s->font));
3161 xgcv.font = s->font;
3162 mask = GCForeground | GCBackground | GCFont;
3163
3164 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
3165 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
3166 mask, &xgcv);
3167 else
3168 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
3169 = XCreateGC (s->display, s->window, mask, &xgcv);
3170
3171 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
3172 }
3173}
3174
3175
3176/* Set up S->gc of glyph string S for drawing text in mouse face. */
3177
3178static void
3179x_set_mouse_face_gc (s)
3180 struct glyph_string *s;
3181{
3182 int face_id;
3183 struct face *face;
3184
3185 /* What face has to be used for the mouse face? */
3186 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
3187 face = FACE_FROM_ID (s->f, face_id);
3188 if (s->first_glyph->type == CHAR_GLYPH)
3189 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
3190 else
3191 face_id = FACE_FOR_CHAR (s->f, face, 0);
3192 s->face = FACE_FROM_ID (s->f, face_id);
3193 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
3194
3195 /* If font in this face is same as S->font, use it. */
3196 if (s->font == s->face->font)
3197 s->gc = s->face->gc;
3198 else
3199 {
3200 /* Otherwise construct scratch_cursor_gc with values from FACE
3201 but font FONT. */
3202 XGCValues xgcv;
3203 unsigned long mask;
3204
3205 xgcv.background = s->face->background;
3206 xgcv.foreground = s->face->foreground;
3207 IF_DEBUG (x_check_font (s->f, s->font));
3208 xgcv.font = s->font;
3209 mask = GCForeground | GCBackground | GCFont;
3210
3211 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc)
3212 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc,
3213 mask, &xgcv);
3214 else
3215 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc
3216 = XCreateGC (s->display, s->window, mask, &xgcv);
3217
3218 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc;
3219 }
3220
3221 xassert (s->gc != 0);
3222}
3223
3224
3225/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
3226 Faces to use in the mode line have already been computed when the
3227 matrix was built, so there isn't much to do, here. */
3228
3229static INLINE void
3230x_set_mode_line_face_gc (s)
3231 struct glyph_string *s;
3232{
3233 s->gc = s->face->gc;
3234}
3235
3236
3237/* Set S->gc of glyph string S for drawing that glyph string. Set
3238 S->stippled_p to a non-zero value if the face of S has a stipple
3239 pattern. */
3240
3241static INLINE void
3242x_set_glyph_string_gc (s)
3243 struct glyph_string *s;
3244{
3245 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
3246
3247 if (s->hl == DRAW_NORMAL_TEXT)
3248 {
3249 s->gc = s->face->gc;
3250 s->stippled_p = s->face->stipple != 0;
3251 }
3252 else if (s->hl == DRAW_INVERSE_VIDEO)
3253 {
3254 x_set_mode_line_face_gc (s);
3255 s->stippled_p = s->face->stipple != 0;
3256 }
3257 else if (s->hl == DRAW_CURSOR)
3258 {
3259 x_set_cursor_gc (s);
3260 s->stippled_p = 0;
3261 }
3262 else if (s->hl == DRAW_MOUSE_FACE)
3263 {
3264 x_set_mouse_face_gc (s);
3265 s->stippled_p = s->face->stipple != 0;
3266 }
3267 else if (s->hl == DRAW_IMAGE_RAISED
3268 || s->hl == DRAW_IMAGE_SUNKEN)
3269 {
3270 s->gc = s->face->gc;
3271 s->stippled_p = s->face->stipple != 0;
3272 }
3273 else
3274 {
3275 s->gc = s->face->gc;
3276 s->stippled_p = s->face->stipple != 0;
3277 }
3278
3279 /* GC must have been set. */
3280 xassert (s->gc != 0);
3281}
3282
3283
3284/* Return in *R the clipping rectangle for glyph string S. */
3285
3286static void
3287x_get_glyph_string_clip_rect (s, r)
3288 struct glyph_string *s;
3289 Rect *r;
3290{
3291 int r_height, r_width;
3292
3293 if (s->row->full_width_p)
3294 {
3295 /* Draw full-width. X coordinates are relative to S->w->left. */
3296 int canon_x = CANON_X_UNIT (s->f);
3297
3298 r->left = WINDOW_LEFT_MARGIN (s->w) * canon_x;
3299 r_width = XFASTINT (s->w->width) * canon_x;
3300
3301 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
3302 {
3303 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
3304 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
3305 r->left -= width;
3306 }
3307
3308 r->left += FRAME_INTERNAL_BORDER_WIDTH (s->f);
3309
3310 /* Unless displaying a mode or menu bar line, which are always
3311 fully visible, clip to the visible part of the row. */
3312 if (s->w->pseudo_window_p)
3313 r_height = s->row->visible_height;
3314 else
3315 r_height = s->height;
3316 }
3317 else
3318 {
3319 /* This is a text line that may be partially visible. */
3320 r->left = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
3321 r_width = window_box_width (s->w, s->area);
3322 r_height = s->row->visible_height;
3323 }
3324
3325 /* Don't use S->y for clipping because it doesn't take partially
3326 visible lines into account. For example, it can be negative for
3327 partially visible lines at the top of a window. */
3328 if (!s->row->full_width_p
3329 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
3330 r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
3331 else
3332 r->top = max (0, s->row->y);
3333
3334 /* If drawing a tool-bar window, draw it over the internal border
3335 at the top of the window. */
3336 if (s->w == XWINDOW (s->f->tool_bar_window))
3337 r->top -= s->f->output_data.mac->internal_border_width;
3338
3339 /* If S draws overlapping rows, it's sufficient to use the top and
3340 bottom of the window for clipping because this glyph string
3341 intentionally draws over other lines. */
3342 if (s->for_overlaps_p)
3343 {
3344 r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
3345 r_height = window_text_bottom_y (s->w) - r->top;
3346 }
3347
3348 r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top);
3349
3350 r->bottom = r->top + r_height;
3351 r->right = r->left + r_width;
3352}
3353
3354
3355/* Set clipping for output of glyph string S. S may be part of a mode
3356 line or menu if we don't have X toolkit support. */
3357
3358static INLINE void
3359x_set_glyph_string_clipping (s)
3360 struct glyph_string *s;
3361{
3362 Rect r;
3363 x_get_glyph_string_clip_rect (s, &r);
3364 mac_set_clip_rectangle (s->display, s->window, &r);
3365}
3366
3367
3368/* Compute left and right overhang of glyph string S. If S is a glyph
3369 string for a composition, assume overhangs don't exist. */
3370
3371static INLINE void
3372x_compute_glyph_string_overhangs (s)
3373 struct glyph_string *s;
3374{
3375 if (s->cmp == NULL
3376 && s->first_glyph->type == CHAR_GLYPH)
3377 {
3378 XCharStruct cs;
3379 int direction, font_ascent, font_descent;
3380 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
3381 &font_ascent, &font_descent, &cs);
3382 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
3383 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
3384 }
3385}
3386
3387
3388/* Compute overhangs and x-positions for glyph string S and its
3389 predecessors, or successors. X is the starting x-position for S.
3390 BACKWARD_P non-zero means process predecessors. */
3391
3392static void
3393x_compute_overhangs_and_x (s, x, backward_p)
3394 struct glyph_string *s;
3395 int x;
3396 int backward_p;
3397{
3398 if (backward_p)
3399 {
3400 while (s)
3401 {
3402 x_compute_glyph_string_overhangs (s);
3403 x -= s->width;
3404 s->x = x;
3405 s = s->prev;
3406 }
3407 }
3408 else
3409 {
3410 while (s)
3411 {
3412 x_compute_glyph_string_overhangs (s);
3413 s->x = x;
3414 x += s->width;
3415 s = s->next;
3416 }
3417 }
3418}
3419
3420
3421/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
3422 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
3423 assumed to be zero. */
3424
3425void
3426x_get_glyph_overhangs (glyph, f, left, right)
3427 struct glyph *glyph;
3428 struct frame *f;
3429 int *left, *right;
3430{
3431 *left = *right = 0;
3432
3433 if (glyph->type == CHAR_GLYPH)
3434 {
3435 XFontStruct *font;
3436 struct face *face;
3437 struct font_info *font_info;
3438 XChar2b char2b;
3439 XCharStruct *pcm;
3440
3441 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
3442 font = face->font;
3443 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
3444 if (font
3445 && (pcm = x_per_char_metric (font, &char2b)))
3446 {
3447 if (pcm->rbearing > pcm->width)
3448 *right = pcm->rbearing - pcm->width;
3449 if (pcm->lbearing < 0)
3450 *left = -pcm->lbearing;
3451 }
3452 }
3453}
3454
3455
3456/* Return the index of the first glyph preceding glyph string S that
3457 is overwritten by S because of S's left overhang. Value is -1
3458 if no glyphs are overwritten. */
3459
3460static int
3461x_left_overwritten (s)
3462 struct glyph_string *s;
3463{
3464 int k;
3465
3466 if (s->left_overhang)
3467 {
3468 int x = 0, i;
3469 struct glyph *glyphs = s->row->glyphs[s->area];
3470 int first = s->first_glyph - glyphs;
3471
3472 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
3473 x -= glyphs[i].pixel_width;
3474
3475 k = i + 1;
3476 }
3477 else
3478 k = -1;
3479
3480 return k;
3481}
3482
3483
3484/* Return the index of the first glyph preceding glyph string S that
3485 is overwriting S because of its right overhang. Value is -1 if no
3486 glyph in front of S overwrites S. */
3487
3488static int
3489x_left_overwriting (s)
3490 struct glyph_string *s;
3491{
3492 int i, k, x;
3493 struct glyph *glyphs = s->row->glyphs[s->area];
3494 int first = s->first_glyph - glyphs;
3495
3496 k = -1;
3497 x = 0;
3498 for (i = first - 1; i >= 0; --i)
3499 {
3500 int left, right;
3501 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3502 if (x + right > 0)
3503 k = i;
3504 x -= glyphs[i].pixel_width;
3505 }
3506
3507 return k;
3508}
3509
3510
3511/* Return the index of the last glyph following glyph string S that is
3512 not overwritten by S because of S's right overhang. Value is -1 if
3513 no such glyph is found. */
3514
3515static int
3516x_right_overwritten (s)
3517 struct glyph_string *s;
3518{
3519 int k = -1;
3520
3521 if (s->right_overhang)
3522 {
3523 int x = 0, i;
3524 struct glyph *glyphs = s->row->glyphs[s->area];
3525 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
3526 int end = s->row->used[s->area];
3527
3528 for (i = first; i < end && s->right_overhang > x; ++i)
3529 x += glyphs[i].pixel_width;
3530
3531 k = i;
3532 }
3533
3534 return k;
3535}
3536
3537
3538/* Return the index of the last glyph following glyph string S that
3539 overwrites S because of its left overhang. Value is negative
3540 if no such glyph is found. */
3541
3542static int
3543x_right_overwriting (s)
3544 struct glyph_string *s;
3545{
3546 int i, k, x;
3547 int end = s->row->used[s->area];
3548 struct glyph *glyphs = s->row->glyphs[s->area];
3549 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
3550
3551 k = -1;
3552 x = 0;
3553 for (i = first; i < end; ++i)
3554 {
3555 int left, right;
3556 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3557 if (x - left < 0)
3558 k = i;
3559 x += glyphs[i].pixel_width;
3560 }
3561
3562 return k;
3563}
3564
3565
3566/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3567
3568static INLINE void
3569x_clear_glyph_string_rect (s, x, y, w, h)
3570 struct glyph_string *s;
3571 int x, y, w, h;
3572{
3573 XGCValues xgcv;
3574
3575 xgcv.foreground = s->gc->background;
3576 XFillRectangle (s->display, s->window, &xgcv, x, y, w, h);
3577}
3578
3579
3580/* Draw the background of glyph_string S. If S->background_filled_p
3581 is non-zero don't draw it. FORCE_P non-zero means draw the
3582 background even if it wouldn't be drawn normally. This is used
3583 when a string preceding S draws into the background of S, or S
3584 contains the first component of a composition. */
3585
3586static void
3587x_draw_glyph_string_background (s, force_p)
3588 struct glyph_string *s;
3589 int force_p;
3590{
3591 /* Nothing to do if background has already been drawn or if it
3592 shouldn't be drawn in the first place. */
3593 if (!s->background_filled_p)
3594 {
3595#if 0 /* MAC_TODO: stipple */
3596 if (s->stippled_p)
3597 {
3598 /* Fill background with a stipple pattern. */
3599 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3600 XFillRectangle (s->display, s->window, s->gc, s->x,
3601 s->y + s->face->box_line_width,
3602 s->background_width,
3603 s->height - 2 * s->face->box_line_width);
3604 XSetFillStyle (s->display, s->gc, FillSolid);
3605 s->background_filled_p = 1;
3606 }
3607 else
3608#endif
3609 if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3610 || s->font_not_found_p
3611 || s->extends_to_end_of_line_p
3612 || force_p)
3613 {
3614 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3615 s->background_width,
3616 s->height - 2 * s->face->box_line_width);
3617 s->background_filled_p = 1;
3618 }
3619 }
3620}
3621
3622
3623/* Draw the foreground of glyph string S. */
3624
3625static void
3626x_draw_glyph_string_foreground (s)
3627 struct glyph_string *s;
3628{
3629 int i, x;
3630
3631 /* If first glyph of S has a left box line, start drawing the text
3632 of S to the right of that box line. */
3633 if (s->face->box != FACE_NO_BOX
3634 && s->first_glyph->left_box_line_p)
3635 x = s->x + s->face->box_line_width;
3636 else
3637 x = s->x;
3638
3639 /* Draw characters of S as rectangles if S's font could not be
3640 loaded. */
3641 if (s->font_not_found_p)
3642 {
3643 for (i = 0; i < s->nchars; ++i)
3644 {
3645 struct glyph *g = s->first_glyph + i;
3646 mac_draw_rectangle (s->display, s->window,
3647 s->gc, x, s->y, g->pixel_width - 1,
3648 s->height - 1);
3649 x += g->pixel_width;
3650 }
3651 }
3652 else
3653 {
3654 char *char1b = (char *) s->char2b;
3655 int boff = s->font_info->baseline_offset;
3656
3657 if (s->font_info->vertical_centering)
3658 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3659
3660 /* If we can use 8-bit functions, condense S->char2b. */
3661 if (!s->two_byte_p)
3662 for (i = 0; i < s->nchars; ++i)
3663 char1b[i] = s->char2b[i].byte2;
3664
3665 /* Draw text with XDrawString if background has already been
3666 filled. Otherwise, use XDrawImageString. (Note that
3667 XDrawImageString is usually faster than XDrawString.) Always
3668 use XDrawImageString when drawing the cursor so that there is
3669 no chance that characters under a box cursor are invisible. */
3670 if (s->for_overlaps_p
3671 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3672 {
3673 /* Draw characters with 16-bit or 8-bit functions. */
3674 if (s->two_byte_p)
3675 XDrawString16 (s->display, s->window, s->gc, x,
3676 s->ybase - boff, s->char2b, s->nchars);
3677 else
3678 XDrawString (s->display, s->window, s->gc, x,
3679 s->ybase - boff, char1b, s->nchars);
3680 }
3681 else
3682 {
3683 if (s->two_byte_p)
3684 XDrawImageString16 (s->display, s->window, s->gc, x,
3685 s->ybase - boff, s->char2b, s->nchars);
3686 else
3687 XDrawImageString (s->display, s->window, s->gc, x,
3688 s->ybase - boff, char1b, s->nchars);
3689 }
3690 }
3691}
3692
3693/* Draw the foreground of composite glyph string S. */
3694
3695static void
3696x_draw_composite_glyph_string_foreground (s)
3697 struct glyph_string *s;
3698{
3699 int i, x;
3700
3701 /* If first glyph of S has a left box line, start drawing the text
3702 of S to the right of that box line. */
3703 if (s->face->box != FACE_NO_BOX
3704 && s->first_glyph->left_box_line_p)
3705 x = s->x + s->face->box_line_width;
3706 else
3707 x = s->x;
3708
3709 /* S is a glyph string for a composition. S->gidx is the index of
3710 the first character drawn for glyphs of this composition.
3711 S->gidx == 0 means we are drawing the very first character of
3712 this composition. */
3713
3714 /* Draw a rectangle for the composition if the font for the very
3715 first character of the composition could not be loaded. */
3716 if (s->font_not_found_p)
3717 {
3718 if (s->gidx == 0)
3719 mac_draw_rectangle (s->display, s->window, s->gc, x, s->y,
3720 s->width - 1, s->height - 1);
3721 }
3722 else
3723 {
3724 for (i = 0; i < s->nchars; i++, ++s->gidx)
3725 XDrawString16 (s->display, s->window, s->gc,
3726 x + s->cmp->offsets[s->gidx * 2],
3727 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3728 s->char2b + i, 1);
3729 }
3730}
3731
3732
3733#ifdef USE_X_TOOLKIT
3734
3735static struct frame *x_frame_of_widget P_ ((Widget));
3736
3737
3738/* Return the frame on which widget WIDGET is used.. Abort if frame
3739 cannot be determined. */
3740
3741static struct frame *
3742x_frame_of_widget (widget)
3743 Widget widget;
3744{
3745 struct x_display_info *dpyinfo;
3746 Lisp_Object tail;
3747 struct frame *f;
3748
3749 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3750
3751 /* Find the top-level shell of the widget. Note that this function
3752 can be called when the widget is not yet realized, so XtWindow
3753 (widget) == 0. That's the reason we can't simply use
3754 x_any_window_to_frame. */
3755 while (!XtIsTopLevelShell (widget))
3756 widget = XtParent (widget);
3757
3758 /* Look for a frame with that top-level widget. Allocate the color
3759 on that frame to get the right gamma correction value. */
3760 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3761 if (GC_FRAMEP (XCAR (tail))
3762 && (f = XFRAME (XCAR (tail)),
3763 (f->output_data.nothing != 1
3764 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3765 && f->output_data.x->widget == widget)
3766 return f;
3767
3768 abort ();
3769}
3770
3771
3772/* Allocate the color COLOR->pixel on the screen and display of
3773 widget WIDGET in colormap CMAP. If an exact match cannot be
3774 allocated, try the nearest color available. Value is non-zero
3775 if successful. This is called from lwlib. */
3776
3777int
3778x_alloc_nearest_color_for_widget (widget, cmap, color)
3779 Widget widget;
3780 Colormap cmap;
3781 XColor *color;
3782{
3783 struct frame *f = x_frame_of_widget (widget);
3784 return x_alloc_nearest_color (f, cmap, color);
3785}
3786
3787
3788#endif /* USE_X_TOOLKIT */
3789
3790#if 0
3791
3792/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3793 CMAP. If an exact match can't be allocated, try the nearest color
3794 available. Value is non-zero if successful. Set *COLOR to the
3795 color allocated. */
3796
3797int
3798x_alloc_nearest_color (f, cmap, color)
3799 struct frame *f;
3800 Colormap cmap;
3801 XColor *color;
3802{
3803 Display *display = FRAME_X_DISPLAY (f);
3804 Screen *screen = FRAME_X_SCREEN (f);
3805 int rc;
3806
3807 gamma_correct (f, color);
3808 rc = XAllocColor (display, cmap, color);
3809 if (rc == 0)
3810 {
3811 /* If we got to this point, the colormap is full, so we're going
3812 to try to get the next closest color. The algorithm used is
3813 a least-squares matching, which is what X uses for closest
3814 color matching with StaticColor visuals. */
3815 int nearest, i;
3816 unsigned long nearest_delta = ~0;
3817 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3818 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3819
3820 for (i = 0; i < ncells; ++i)
3821 cells[i].pixel = i;
3822 XQueryColors (display, cmap, cells, ncells);
3823
3824 for (nearest = i = 0; i < ncells; ++i)
3825 {
3826 long dred = (color->red >> 8) - (cells[i].red >> 8);
3827 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3828 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3829 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3830
3831 if (delta < nearest_delta)
3832 {
3833 nearest = i;
3834 nearest_delta = delta;
3835 }
3836 }
3837
3838 color->red = cells[nearest].red;
3839 color->green = cells[nearest].green;
3840 color->blue = cells[nearest].blue;
3841 rc = XAllocColor (display, cmap, color);
3842 }
3843
3844#ifdef DEBUG_X_COLORS
3845 if (rc)
3846 register_color (color->pixel);
3847#endif /* DEBUG_X_COLORS */
3848
3849 return rc;
3850}
3851
3852
3853/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3854 It's necessary to do this instead of just using PIXEL directly to
3855 get color reference counts right. */
3856
3857unsigned long
3858x_copy_color (f, pixel)
3859 struct frame *f;
3860 unsigned long pixel;
3861{
3862 XColor color;
3863
3864 color.pixel = pixel;
3865 BLOCK_INPUT;
3866 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3867 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3868 UNBLOCK_INPUT;
3869#ifdef DEBUG_X_COLORS
3870 register_color (pixel);
3871#endif
3872 return color.pixel;
3873}
3874
3875
3876/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3877 It's necessary to do this instead of just using PIXEL directly to
3878 get color reference counts right. */
3879
3880unsigned long
3881x_copy_dpy_color (dpy, cmap, pixel)
3882 Display *dpy;
3883 Colormap cmap;
3884 unsigned long pixel;
3885{
3886 XColor color;
3887
3888 color.pixel = pixel;
3889 BLOCK_INPUT;
3890 XQueryColor (dpy, cmap, &color);
3891 XAllocColor (dpy, cmap, &color);
3892 UNBLOCK_INPUT;
3893#ifdef DEBUG_X_COLORS
3894 register_color (pixel);
3895#endif
3896 return color.pixel;
3897}
3898
3899#endif
3900
3901/* Allocate a color which is lighter or darker than *COLOR by FACTOR
3902 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3903 If this produces the same color as COLOR, try a color where all RGB
3904 values have DELTA added. Return the allocated color in *COLOR.
3905 DISPLAY is the X display, CMAP is the colormap to operate on.
3906 Value is non-zero if successful. */
3907
3908static int
3909mac_alloc_lighter_color (f, color, factor, delta)
3910 struct frame *f;
3911 unsigned long *color;
3912 double factor;
3913 int delta;
3914{
3915 unsigned long new;
3916
3917 /* Change RGB values by specified FACTOR. Avoid overflow! */
3918 xassert (factor >= 0);
3919 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))),
3920 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))),
3921 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color))));
3922 if (new == *color)
3923 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))),
3924 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))),
3925 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color)))));
3926
3927 /* MAC_TODO: Map to palette and retry with delta if same? */
3928 /* MAC_TODO: Free colors (if using palette)? */
3929
3930 if (new == *color)
3931 return 0;
3932
3933 *color = new;
3934
3935 return 1;
3936}
3937
3938
3939/* Set up the foreground color for drawing relief lines of glyph
3940 string S. RELIEF is a pointer to a struct relief containing the GC
3941 with which lines will be drawn. Use a color that is FACTOR or
3942 DELTA lighter or darker than the relief's background which is found
3943 in S->f->output_data.x->relief_background. If such a color cannot
3944 be allocated, use DEFAULT_PIXEL, instead. */
3945
3946static void
3947x_setup_relief_color (f, relief, factor, delta, default_pixel)
3948 struct frame *f;
3949 struct relief *relief;
3950 double factor;
3951 int delta;
3952 unsigned long default_pixel;
3953{
3954 XGCValues xgcv;
3955 struct mac_output *di = f->output_data.mac;
3956 unsigned long mask = GCForeground;
3957 unsigned long pixel;
3958 unsigned long background = di->relief_background;
3959 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
3960
3961 /* MAC_TODO: Free colors (if using palette)? */
3962
3963 /* Allocate new color. */
3964 xgcv.foreground = default_pixel;
3965 pixel = background;
3966 if (mac_alloc_lighter_color (f, &pixel, factor, delta))
3967 {
3968 relief->allocated_p = 1;
3969 xgcv.foreground = relief->pixel = pixel;
3970 }
3971
3972 if (relief->gc == 0)
3973 {
3974#if 0 /* MAC_TODO: stipple */
3975 xgcv.stipple = dpyinfo->gray;
3976 mask |= GCStipple;
3977#endif
3978 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv);
3979 }
3980 else
3981 XChangeGC (NULL, relief->gc, mask, &xgcv);
3982}
3983
3984
3985/* Set up colors for the relief lines around glyph string S. */
3986
3987static void
3988x_setup_relief_colors (s)
3989 struct glyph_string *s;
3990{
3991 struct mac_output *di = s->f->output_data.mac;
3992 unsigned long color;
3993
3994 if (s->face->use_box_color_for_shadows_p)
3995 color = s->face->box_color;
3996 else
3997 {
3998 XGCValues xgcv;
3999
4000 /* Get the background color of the face. */
4001 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
4002 color = xgcv.background;
4003 }
4004
4005 if (di->white_relief.gc == 0
4006 || color != di->relief_background)
4007 {
4008 di->relief_background = color;
4009 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
4010 WHITE_PIX_DEFAULT (s->f));
4011 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
4012 BLACK_PIX_DEFAULT (s->f));
4013 }
4014}
4015
4016
4017/* Draw a relief on frame F inside the rectangle given by LEFT_X,
4018 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
4019 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
4020 relief. LEFT_P non-zero means draw a relief on the left side of
4021 the rectangle. RIGHT_P non-zero means draw a relief on the right
4022 side of the rectangle. CLIP_RECT is the clipping rectangle to use
4023 when drawing. */
4024
4025static void
4026x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
4027 raised_p, left_p, right_p, clip_rect)
4028 struct frame *f;
4029 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
4030 Rect *clip_rect;
4031{
4032 int i;
4033 GC gc;
4034
4035 if (raised_p)
4036 gc = f->output_data.mac->white_relief.gc;
4037 else
4038 gc = f->output_data.mac->black_relief.gc;
4039 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect);
4040
4041 /* Top. */
4042 for (i = 0; i < width; ++i)
4043 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4044 left_x + i * left_p, top_y + i,
4045 right_x + 1 - i * right_p, top_y + i);
4046
4047 /* Left. */
4048 if (left_p)
4049 for (i = 0; i < width; ++i)
4050 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4051 left_x + i, top_y + i, left_x + i, bottom_y - i);
4052
4053 mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
4054 if (raised_p)
4055 gc = f->output_data.mac->black_relief.gc;
4056 else
4057 gc = f->output_data.mac->white_relief.gc;
4058 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect);
4059
4060 /* Bottom. */
4061 for (i = 0; i < width; ++i)
4062 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4063 left_x + i * left_p, bottom_y - i,
4064 right_x + 1 - i * right_p, bottom_y - i);
4065
4066 /* Right. */
4067 if (right_p)
4068 for (i = 0; i < width; ++i)
4069 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc,
4070 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
4071
4072 mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
4073}
4074
4075
4076/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
4077 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
4078 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
4079 left side of the rectangle. RIGHT_P non-zero means draw a line
4080 on the right side of the rectangle. CLIP_RECT is the clipping
4081 rectangle to use when drawing. */
4082
4083static void
4084x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4085 left_p, right_p, clip_rect)
4086 struct glyph_string *s;
4087 int left_x, top_y, right_x, bottom_y, left_p, right_p;
4088 Rect *clip_rect;
4089{
4090 XGCValues xgcv;
4091
4092 xgcv.foreground = s->face->box_color;
4093 mac_set_clip_rectangle (s->display, s->window, clip_rect);
4094
4095 /* Top. */
4096 XFillRectangle (s->display, s->window, &xgcv,
4097 left_x, top_y, right_x - left_x, width);
4098
4099 /* Left. */
4100 if (left_p)
4101 XFillRectangle (s->display, s->window, &xgcv,
4102 left_x, top_y, width, bottom_y - top_y);
4103
4104 /* Bottom. */
4105 XFillRectangle (s->display, s->window, &xgcv,
4106 left_x, bottom_y - width, right_x - left_x, width);
4107
4108 /* Right. */
4109 if (right_p)
4110 XFillRectangle (s->display, s->window, &xgcv,
4111 right_x - width, top_y, width, bottom_y - top_y);
4112
4113 mac_reset_clipping (s->display, s->window);
4114}
4115
4116
4117/* Draw a box around glyph string S. */
4118
4119static void
4120x_draw_glyph_string_box (s)
4121 struct glyph_string *s;
4122{
4123 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
4124 int left_p, right_p;
4125 struct glyph *last_glyph;
4126 Rect clip_rect;
4127
4128 last_x = window_box_right (s->w, s->area);
4129 if (s->row->full_width_p
4130 && !s->w->pseudo_window_p)
4131 {
4132 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
4133 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
4134 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
4135 }
4136
4137 /* The glyph that may have a right box line. */
4138 last_glyph = (s->cmp || s->img
4139 ? s->first_glyph
4140 : s->first_glyph + s->nchars - 1);
4141
4142 width = s->face->box_line_width;
4143 raised_p = s->face->box == FACE_RAISED_BOX;
4144 left_x = s->x;
4145 right_x = ((s->row->full_width_p
4146 ? last_x - 1
4147 : min (last_x, s->x + s->background_width) - 1));
4148 top_y = s->y;
4149 bottom_y = top_y + s->height - 1;
4150
4151 left_p = (s->first_glyph->left_box_line_p
4152 || (s->hl == DRAW_MOUSE_FACE
4153 && (s->prev == NULL
4154 || s->prev->hl != s->hl)));
4155 right_p = (last_glyph->right_box_line_p
4156 || (s->hl == DRAW_MOUSE_FACE
4157 && (s->next == NULL
4158 || s->next->hl != s->hl)));
4159
4160 x_get_glyph_string_clip_rect (s, &clip_rect);
4161
4162 if (s->face->box == FACE_SIMPLE_BOX)
4163 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4164 left_p, right_p, &clip_rect);
4165 else
4166 {
4167 x_setup_relief_colors (s);
4168 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4169 width, raised_p, left_p, right_p, &clip_rect);
4170 }
4171}
4172
4173
4174/* Draw foreground of image glyph string S. */
4175
4176static void
4177x_draw_image_foreground (s)
4178 struct glyph_string *s;
4179{
4180 int x;
4181 int y = s->ybase - image_ascent (s->img, s->face);
4182
4183 /* If first glyph of S has a left box line, start drawing it to the
4184 right of that line. */
4185 if (s->face->box != FACE_NO_BOX
4186 && s->first_glyph->left_box_line_p)
4187 x = s->x + s->face->box_line_width;
4188 else
4189 x = s->x;
4190
4191 /* If there is a margin around the image, adjust x- and y-position
4192 by that margin. */
4193 if (s->img->margin)
4194 {
4195 x += s->img->margin;
4196 y += s->img->margin;
4197 }
4198
4199 if (s->img->pixmap)
4200 {
4201#if 0 /* MAC_TODO: image mask */
4202 if (s->img->mask)
4203 {
4204 /* We can't set both a clip mask and use XSetClipRectangles
4205 because the latter also sets a clip mask. We also can't
4206 trust on the shape extension to be available
4207 (XShapeCombineRegion). So, compute the rectangle to draw
4208 manually. */
4209 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4210 | GCFunction);
4211 XGCValues xgcv;
4212 XRectangle clip_rect, image_rect, r;
4213
4214 xgcv.clip_mask = s->img->mask;
4215 xgcv.clip_x_origin = x;
4216 xgcv.clip_y_origin = y;
4217 xgcv.function = GXcopy;
4218 XChangeGC (s->display, s->gc, mask, &xgcv);
4219
4220 x_get_glyph_string_clip_rect (s, &clip_rect);
4221 image_rect.x = x;
4222 image_rect.y = y;
4223 image_rect.width = s->img->width;
4224 image_rect.height = s->img->height;
4225 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4226 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4227 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4228 }
4229 else
4230#endif
4231 {
4232 mac_copy_area (s->display, s->img->pixmap, s->window, s->gc,
4233 0, 0, s->img->width, s->img->height, x, y);
4234
4235 /* When the image has a mask, we can expect that at
4236 least part of a mouse highlight or a block cursor will
4237 be visible. If the image doesn't have a mask, make
4238 a block cursor visible by drawing a rectangle around
4239 the image. I believe it's looking better if we do
4240 nothing here for mouse-face. */
4241 if (s->hl == DRAW_CURSOR)
4242 mac_draw_rectangle (s->display, s->window, s->gc, x, y,
4243 s->img->width - 1, s->img->height - 1);
4244 }
4245 }
4246 else
4247 /* Draw a rectangle if image could not be loaded. */
4248 mac_draw_rectangle (s->display, s->window, s->gc, x, y,
4249 s->img->width - 1, s->img->height - 1);
4250}
4251
4252
4253/* Draw a relief around the image glyph string S. */
4254
4255static void
4256x_draw_image_relief (s)
4257 struct glyph_string *s;
4258{
4259 int x0, y0, x1, y1, thick, raised_p;
4260 Rect r;
4261 int x;
4262 int y = s->ybase - image_ascent (s->img, s->face);
4263
4264 /* If first glyph of S has a left box line, start drawing it to the
4265 right of that line. */
4266 if (s->face->box != FACE_NO_BOX
4267 && s->first_glyph->left_box_line_p)
4268 x = s->x + s->face->box_line_width;
4269 else
4270 x = s->x;
4271
4272 /* If there is a margin around the image, adjust x- and y-position
4273 by that margin. */
4274 if (s->img->margin)
4275 {
4276 x += s->img->margin;
4277 y += s->img->margin;
4278 }
4279
4280 if (s->hl == DRAW_IMAGE_SUNKEN
4281 || s->hl == DRAW_IMAGE_RAISED)
4282 {
4283 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
4284 raised_p = s->hl == DRAW_IMAGE_RAISED;
4285 }
4286 else
4287 {
4288 thick = abs (s->img->relief);
4289 raised_p = s->img->relief > 0;
4290 }
4291
4292 x0 = x - thick;
4293 y0 = y - thick;
4294 x1 = x + s->img->width + thick - 1;
4295 y1 = y + s->img->height + thick - 1;
4296
4297 x_setup_relief_colors (s);
4298 x_get_glyph_string_clip_rect (s, &r);
4299 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4300}
4301
4302
4303/* Draw the foreground of image glyph string S to PIXMAP. */
4304
4305static void
4306x_draw_image_foreground_1 (s, pixmap)
4307 struct glyph_string *s;
4308 Pixmap pixmap;
4309{
4310 int x;
4311 int y = s->ybase - s->y - image_ascent (s->img, s->face);
4312
4313 /* If first glyph of S has a left box line, start drawing it to the
4314 right of that line. */
4315 if (s->face->box != FACE_NO_BOX
4316 && s->first_glyph->left_box_line_p)
4317 x = s->face->box_line_width;
4318 else
4319 x = 0;
4320
4321 /* If there is a margin around the image, adjust x- and y-position
4322 by that margin. */
4323 if (s->img->margin)
4324 {
4325 x += s->img->margin;
4326 y += s->img->margin;
4327 }
4328
4329 if (s->img->pixmap)
4330 {
4331#if 0 /* MAC_TODO: image mask */
4332 if (s->img->mask)
4333 {
4334 /* We can't set both a clip mask and use XSetClipRectangles
4335 because the latter also sets a clip mask. We also can't
4336 trust on the shape extension to be available
4337 (XShapeCombineRegion). So, compute the rectangle to draw
4338 manually. */
4339 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4340 | GCFunction);
4341 XGCValues xgcv;
4342
4343 xgcv.clip_mask = s->img->mask;
4344 xgcv.clip_x_origin = x;
4345 xgcv.clip_y_origin = y;
4346 xgcv.function = GXcopy;
4347 XChangeGC (s->display, s->gc, mask, &xgcv);
4348
4349 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4350 0, 0, s->img->width, s->img->height, x, y);
4351 XSetClipMask (s->display, s->gc, None);
4352 }
4353 else
4354#endif
4355 {
4356 mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc,
4357 0, 0, s->img->width, s->img->height, x, y);
4358
4359 /* When the image has a mask, we can expect that at
4360 least part of a mouse highlight or a block cursor will
4361 be visible. If the image doesn't have a mask, make
4362 a block cursor visible by drawing a rectangle around
4363 the image. I believe it's looking better if we do
4364 nothing here for mouse-face. */
4365 if (s->hl == DRAW_CURSOR)
4366 mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y,
4367 s->img->width - 1, s->img->height - 1);
4368 }
4369 }
4370 else
4371 /* Draw a rectangle if image could not be loaded. */
4372 mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y,
4373 s->img->width - 1, s->img->height - 1);
4374}
4375
4376
4377/* Draw part of the background of glyph string S. X, Y, W, and H
4378 give the rectangle to draw. */
4379
4380static void
4381x_draw_glyph_string_bg_rect (s, x, y, w, h)
4382 struct glyph_string *s;
4383 int x, y, w, h;
4384{
4385#if 0 /* MAC_TODO: stipple */
4386 if (s->stippled_p)
4387 {
4388 /* Fill background with a stipple pattern. */
4389 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4390 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4391 XSetFillStyle (s->display, s->gc, FillSolid);
4392 }
4393 else
4394#endif
4395 x_clear_glyph_string_rect (s, x, y, w, h);
4396}
4397
4398
4399/* Draw image glyph string S.
4400
4401 s->y
4402 s->x +-------------------------
4403 | s->face->box
4404 |
4405 | +-------------------------
4406 | | s->img->margin
4407 | |
4408 | | +-------------------
4409 | | | the image
4410
4411 */
4412
4413static void
4414x_draw_image_glyph_string (s)
4415 struct glyph_string *s;
4416{
4417 int x, y;
4418 int box_line_width = s->face->box_line_width;
4419 int margin = s->img->margin;
4420 int height;
4421 Pixmap pixmap = 0;
4422
4423 height = s->height - 2 * box_line_width;
4424
4425 /* Fill background with face under the image. Do it only if row is
4426 taller than image or if image has a clip mask to reduce
4427 flickering. */
4428 s->stippled_p = s->face->stipple != 0;
4429 if (height > s->img->height
4430 || margin
4431#if 0 /* MAC_TODO: image mask */
4432 || s->img->mask
4433#endif
4434 || s->img->pixmap == 0
4435 || s->width != s->background_width)
4436 {
4437 if (box_line_width && s->first_glyph->left_box_line_p)
4438 x = s->x + box_line_width;
4439 else
4440 x = s->x;
4441
4442 y = s->y + box_line_width;
4443
4444#if 0 /* MAC_TODO: image mask */
4445 if (s->img->mask)
4446 {
4447 /* Create a pixmap as large as the glyph string Fill it with
4448 the background color. Copy the image to it, using its
4449 mask. Copy the temporary pixmap to the display. */
4450 Screen *screen = FRAME_X_SCREEN (s->f);
4451 int depth = DefaultDepthOfScreen (screen);
4452
4453 /* Create a pixmap as large as the glyph string. */
4454 pixmap = XCreatePixmap (s->display, s->window,
4455 s->background_width,
4456 s->height, depth);
4457
4458 /* Don't clip in the following because we're working on the
4459 pixmap. */
4460 XSetClipMask (s->display, s->gc, None);
4461
4462 /* Fill the pixmap with the background color/stipple. */
4463 if (s->stippled_p)
4464 {
4465 /* Fill background with a stipple pattern. */
4466 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4467 XFillRectangle (s->display, pixmap, s->gc,
4468 0, 0, s->background_width, s->height);
4469 XSetFillStyle (s->display, s->gc, FillSolid);
4470 }
4471 else
4472 {
4473 XGCValues xgcv;
4474 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4475 &xgcv);
4476 XSetForeground (s->display, s->gc, xgcv.background);
4477 XFillRectangle (s->display, pixmap, s->gc,
4478 0, 0, s->background_width, s->height);
4479 XSetForeground (s->display, s->gc, xgcv.foreground);
4480 }
4481 }
4482 else
4483#endif
4484 /* Implementation idea: Is it possible to construct a mask?
4485 We could look at the color at the margins of the image, and
4486 say that this color is probably the background color of the
4487 image. */
4488 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4489
4490 s->background_filled_p = 1;
4491 }
4492
4493 /* Draw the foreground. */
4494 if (pixmap != 0)
4495 {
4496 x_draw_image_foreground_1 (s, pixmap);
4497 x_set_glyph_string_clipping (s);
4498 mac_copy_area (s->display, pixmap, s->window, s->gc,
4499 0, 0, s->background_width, s->height, s->x, s->y);
4500 XFreePixmap (s->display, pixmap);
4501 }
4502 else
4503 x_draw_image_foreground (s);
4504
4505 /* If we must draw a relief around the image, do it. */
4506 if (s->img->relief
4507 || s->hl == DRAW_IMAGE_RAISED
4508 || s->hl == DRAW_IMAGE_SUNKEN)
4509 x_draw_image_relief (s);
4510}
4511
4512
4513/* Draw stretch glyph string S. */
4514
4515static void
4516x_draw_stretch_glyph_string (s)
4517 struct glyph_string *s;
4518{
4519 xassert (s->first_glyph->type == STRETCH_GLYPH);
4520 s->stippled_p = s->face->stipple != 0;
4521
4522 if (s->hl == DRAW_CURSOR
4523 && !x_stretch_cursor_p)
4524 {
4525 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4526 as wide as the stretch glyph. */
4527 int width = min (CANON_X_UNIT (s->f), s->background_width);
4528
4529 /* Draw cursor. */
4530 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
4531
4532 /* Clear rest using the GC of the original non-cursor face. */
4533 if (width < s->background_width)
4534 {
4535 GC gc = s->face->gc;
4536 int x = s->x + width, y = s->y;
4537 int w = s->background_width - width, h = s->height;
4538 Rect r;
4539
4540 x_get_glyph_string_clip_rect (s, &r);
4541 mac_set_clip_rectangle (s->display, s->window, &r);
4542
4543#if 0 /* MAC_TODO: stipple */
4544 if (s->face->stipple)
4545 {
4546 /* Fill background with a stipple pattern. */
4547 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4548 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4549 XSetFillStyle (s->display, gc, FillSolid);
4550 }
4551 else
4552#endif
4553 {
4554 XGCValues xgcv;
4555 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4556 XSetForeground (s->display, gc, xgcv.background);
4557 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4558 XSetForeground (s->display, gc, xgcv.foreground);
4559 }
4560 }
4561 }
4562 else
4563 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4564 s->height);
4565
4566 s->background_filled_p = 1;
4567}
4568
4569
4570/* Draw glyph string S. */
4571
4572static void
4573x_draw_glyph_string (s)
4574 struct glyph_string *s;
4575{
4576 /* If S draws into the background of its successor, draw the
4577 background of the successor first so that S can draw into it.
4578 This makes S->next use XDrawString instead of XDrawImageString. */
4579 if (s->next && s->right_overhang && !s->for_overlaps_p)
4580 {
4581 xassert (s->next->img == NULL);
4582 x_set_glyph_string_gc (s->next);
4583 x_set_glyph_string_clipping (s->next);
4584 x_draw_glyph_string_background (s->next, 1);
4585 }
4586
4587 /* Set up S->gc, set clipping and draw S. */
4588 x_set_glyph_string_gc (s);
4589 x_set_glyph_string_clipping (s);
4590
4591 switch (s->first_glyph->type)
4592 {
4593 case IMAGE_GLYPH:
4594 x_draw_image_glyph_string (s);
4595 break;
4596
4597 case STRETCH_GLYPH:
4598 x_draw_stretch_glyph_string (s);
4599 break;
4600
4601 case CHAR_GLYPH:
4602 if (s->for_overlaps_p)
4603 s->background_filled_p = 1;
4604 else
4605 x_draw_glyph_string_background (s, 0);
4606 x_draw_glyph_string_foreground (s);
4607 break;
4608
4609 case COMPOSITE_GLYPH:
4610 if (s->for_overlaps_p || s->gidx > 0)
4611 s->background_filled_p = 1;
4612 else
4613 x_draw_glyph_string_background (s, 1);
4614 x_draw_composite_glyph_string_foreground (s);
4615 break;
4616
4617 default:
4618 abort ();
4619 }
4620
4621 if (!s->for_overlaps_p)
4622 {
4623 /* Draw underline. */
4624 if (s->face->underline_p)
4625 {
4626 unsigned long h = 1;
4627 unsigned long dy = s->height - h;
4628
4629 if (s->face->underline_defaulted_p)
4630 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4631 s->width, h);
4632 else
4633 {
4634 XGCValues xgcv;
4635 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4636 XSetForeground (s->display, s->gc, s->face->underline_color);
4637 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4638 s->width, h);
4639 XSetForeground (s->display, s->gc, xgcv.foreground);
4640 }
4641 }
4642
4643 /* Draw overline. */
4644 if (s->face->overline_p)
4645 {
4646 unsigned long dy = 0, h = 1;
4647
4648 if (s->face->overline_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->overline_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 strike-through. */
4663 if (s->face->strike_through_p)
4664 {
4665 unsigned long h = 1;
4666 unsigned long dy = (s->height - h) / 2;
4667
4668 if (s->face->strike_through_color_defaulted_p)
4669 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4670 s->width, h);
4671 else
4672 {
4673 XGCValues xgcv;
4674 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4675 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4676 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4677 s->width, h);
4678 XSetForeground (s->display, s->gc, xgcv.foreground);
4679 }
4680 }
4681
4682 /* Draw relief. */
4683 if (s->face->box != FACE_NO_BOX)
4684 x_draw_glyph_string_box (s);
4685 }
4686
4687 /* Reset clipping. */
4688 mac_reset_clipping (s->display, s->window);
4689}
4690
4691
4692static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4693 struct face **, int));
4694
4695
4696/* Fill glyph string S with composition components specified by S->cmp.
4697
4698 FACES is an array of faces for all components of this composition.
4699 S->gidx is the index of the first component for S.
4700 OVERLAPS_P non-zero means S should draw the foreground only, and
4701 use its physical height for clipping.
4702
4703 Value is the index of a component not in S. */
4704
4705static int
4706x_fill_composite_glyph_string (s, faces, overlaps_p)
4707 struct glyph_string *s;
4708 struct face **faces;
4709 int overlaps_p;
4710{
4711 int i;
4712
4713 xassert (s);
4714
4715 s->for_overlaps_p = overlaps_p;
4716
4717 s->face = faces[s->gidx];
4718 s->font = s->face->font;
4719 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4720
4721 /* For all glyphs of this composition, starting at the offset
4722 S->gidx, until we reach the end of the definition or encounter a
4723 glyph that requires the different face, add it to S. */
4724 ++s->nchars;
4725 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4726 ++s->nchars;
4727
4728 /* All glyph strings for the same composition has the same width,
4729 i.e. the width set for the first component of the composition. */
4730
4731 s->width = s->first_glyph->pixel_width;
4732
4733 /* If the specified font could not be loaded, use the frame's
4734 default font, but record the fact that we couldn't load it in
4735 the glyph string so that we can draw rectangles for the
4736 characters of the glyph string. */
4737 if (s->font == NULL)
4738 {
4739 s->font_not_found_p = 1;
4740 s->font = FRAME_FONT (s->f);
4741 }
4742
4743 /* Adjust base line for subscript/superscript text. */
4744 s->ybase += s->first_glyph->voffset;
4745
4746 xassert (s->face && s->face->gc);
4747
4748 /* This glyph string must always be drawn with 16-bit functions. */
4749 s->two_byte_p = 1;
4750
4751 return s->gidx + s->nchars;
4752}
4753
4754
4755/* Fill glyph string S from a sequence of character glyphs.
4756
4757 FACE_ID is the face id of the string. START is the index of the
4758 first glyph to consider, END is the index of the last + 1.
4759 OVERLAPS_P non-zero means S should draw the foreground only, and
4760 use its physical height for clipping.
4761
4762 Value is the index of the first glyph not in S. */
4763
4764static int
4765x_fill_glyph_string (s, face_id, start, end, overlaps_p)
4766 struct glyph_string *s;
4767 int face_id;
4768 int start, end, overlaps_p;
4769{
4770 struct glyph *glyph, *last;
4771 int voffset;
4772 int glyph_not_available_p;
4773
4774 xassert (s->f == XFRAME (s->w->frame));
4775 xassert (s->nchars == 0);
4776 xassert (start >= 0 && end > start);
4777
4778 s->for_overlaps_p = overlaps_p,
4779 glyph = s->row->glyphs[s->area] + start;
4780 last = s->row->glyphs[s->area] + end;
4781 voffset = glyph->voffset;
4782
4783 glyph_not_available_p = glyph->glyph_not_available_p;
4784
4785 while (glyph < last
4786 && glyph->type == CHAR_GLYPH
4787 && glyph->voffset == voffset
4788 /* Same face id implies same font, nowadays. */
4789 && glyph->face_id == face_id
4790 && glyph->glyph_not_available_p == glyph_not_available_p)
4791 {
4792 int two_byte_p;
4793
4794 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
4795 s->char2b + s->nchars,
4796 &two_byte_p);
4797 s->two_byte_p = two_byte_p;
4798 ++s->nchars;
4799 xassert (s->nchars <= end - start);
4800 s->width += glyph->pixel_width;
4801 ++glyph;
4802 }
4803
4804 s->font = s->face->font;
4805 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4806
4807 /* If the specified font could not be loaded, use the frame's font,
4808 but record the fact that we couldn't load it in
4809 S->font_not_found_p so that we can draw rectangles for the
4810 characters of the glyph string. */
4811 if (s->font == NULL || glyph_not_available_p)
4812 {
4813 s->font_not_found_p = 1;
4814 s->font = FRAME_FONT (s->f);
4815 }
4816
4817 /* Adjust base line for subscript/superscript text. */
4818 s->ybase += voffset;
4819
4820 xassert (s->face && s->face->gc);
4821 return glyph - s->row->glyphs[s->area];
4822}
4823
4824
4825/* Fill glyph string S from image glyph S->first_glyph. */
4826
4827static void
4828x_fill_image_glyph_string (s)
4829 struct glyph_string *s;
4830{
4831 xassert (s->first_glyph->type == IMAGE_GLYPH);
4832 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
4833 xassert (s->img);
4834 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
4835 s->font = s->face->font;
4836 s->width = s->first_glyph->pixel_width;
4837
4838 /* Adjust base line for subscript/superscript text. */
4839 s->ybase += s->first_glyph->voffset;
4840}
4841
4842
4843/* Fill glyph string S from a sequence of stretch glyphs.
4844
4845 ROW is the glyph row in which the glyphs are found, AREA is the
4846 area within the row. START is the index of the first glyph to
4847 consider, END is the index of the last + 1.
4848
4849 Value is the index of the first glyph not in S. */
4850
4851static int
4852x_fill_stretch_glyph_string (s, row, area, start, end)
4853 struct glyph_string *s;
4854 struct glyph_row *row;
4855 enum glyph_row_area area;
4856 int start, end;
4857{
4858 struct glyph *glyph, *last;
4859 int voffset, face_id;
4860
4861 xassert (s->first_glyph->type == STRETCH_GLYPH);
4862
4863 glyph = s->row->glyphs[s->area] + start;
4864 last = s->row->glyphs[s->area] + end;
4865 face_id = glyph->face_id;
4866 s->face = FACE_FROM_ID (s->f, face_id);
4867 s->font = s->face->font;
4868 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4869 s->width = glyph->pixel_width;
4870 voffset = glyph->voffset;
4871
4872 for (++glyph;
4873 (glyph < last
4874 && glyph->type == STRETCH_GLYPH
4875 && glyph->voffset == voffset
4876 && glyph->face_id == face_id);
4877 ++glyph)
4878 s->width += glyph->pixel_width;
4879
4880 /* Adjust base line for subscript/superscript text. */
4881 s->ybase += voffset;
4882
4883 xassert (s->face && s->face->gc);
4884 return glyph - s->row->glyphs[s->area];
4885}
4886
4887
4888/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4889 of XChar2b structures for S; it can't be allocated in
4890 x_init_glyph_string because it must be allocated via `alloca'. W
4891 is the window on which S is drawn. ROW and AREA are the glyph row
4892 and area within the row from which S is constructed. START is the
4893 index of the first glyph structure covered by S. HL is a
4894 face-override for drawing S. */
4895
4896static void
4897x_init_glyph_string (s, char2b, w, row, area, start, hl)
4898 struct glyph_string *s;
4899 XChar2b *char2b;
4900 struct window *w;
4901 struct glyph_row *row;
4902 enum glyph_row_area area;
4903 int start;
4904 enum draw_glyphs_face hl;
4905{
4906 bzero (s, sizeof *s);
4907 s->w = w;
4908 s->f = XFRAME (w->frame);
4909 s->display = FRAME_MAC_DISPLAY (s->f);
4910 s->window = FRAME_MAC_WINDOW (s->f);
4911 s->char2b = char2b;
4912 s->hl = hl;
4913 s->row = row;
4914 s->area = area;
4915 s->first_glyph = row->glyphs[area] + start;
4916 s->height = row->height;
4917 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4918
4919 /* Display the internal border below the tool-bar window. */
4920 if (s->w == XWINDOW (s->f->tool_bar_window))
4921 s->y -= s->f->output_data.mac->internal_border_width;
4922
4923 s->ybase = s->y + row->ascent;
4924}
4925
4926
4927/* Set background width of glyph string S. START is the index of the
4928 first glyph following S. LAST_X is the right-most x-position + 1
4929 in the drawing area. */
4930
4931static INLINE void
4932x_set_glyph_string_background_width (s, start, last_x)
4933 struct glyph_string *s;
4934 int start;
4935 int last_x;
4936{
4937 /* If the face of this glyph string has to be drawn to the end of
4938 the drawing area, set S->extends_to_end_of_line_p. */
4939 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4940
4941 if (start == s->row->used[s->area]
4942 && s->hl == DRAW_NORMAL_TEXT
4943 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4944 || s->face->background != default_face->background
4945 || s->face->stipple != default_face->stipple))
4946 s->extends_to_end_of_line_p = 1;
4947
4948 /* If S extends its face to the end of the line, set its
4949 background_width to the distance to the right edge of the drawing
4950 area. */
4951 if (s->extends_to_end_of_line_p)
4952 s->background_width = last_x - s->x + 1;
4953 else
4954 s->background_width = s->width;
4955}
4956
4957
4958/* Add a glyph string for a stretch glyph to the list of strings
4959 between HEAD and TAIL. START is the index of the stretch glyph in
4960 row area AREA of glyph row ROW. END is the index of the last glyph
4961 in that glyph row area. X is the current output position assigned
4962 to the new glyph string constructed. HL overrides that face of the
4963 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4964 is the right-most x-position of the drawing area. */
4965
4966/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4967 and below -- keep them on one line. */
4968#define BUILD_STRETCH_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 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
4974 x_append_glyph_string (&HEAD, &TAIL, s); \
4975 s->x = (X); \
4976 } \
4977 while (0)
4978
4979
4980/* Add a glyph string for an image glyph to the list of strings
4981 between HEAD and TAIL. START is the index of the image glyph in
4982 row area AREA of glyph row ROW. END is the index of the last glyph
4983 in that glyph row area. X is the current output position assigned
4984 to the new glyph string constructed. HL overrides that face of the
4985 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4986 is the right-most x-position of the drawing area. */
4987
4988#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
4989 do \
4990 { \
4991 s = (struct glyph_string *) alloca (sizeof *s); \
4992 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4993 x_fill_image_glyph_string (s); \
4994 x_append_glyph_string (&HEAD, &TAIL, s); \
4995 ++START; \
4996 s->x = (X); \
4997 } \
4998 while (0)
4999
5000
5001/* Add a glyph string for a sequence of character glyphs to the list
5002 of strings between HEAD and TAIL. START is the index of the first
5003 glyph in row area AREA of glyph row ROW that is part of the new
5004 glyph string. END is the index of the last glyph in that glyph row
5005 area. X is the current output position assigned to the new glyph
5006 string constructed. HL overrides that face of the glyph; e.g. it
5007 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
5008 right-most x-position of the drawing area. */
5009
5010#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
5011 do \
5012 { \
5013 int c, face_id; \
5014 XChar2b *char2b; \
5015 \
5016 c = (ROW)->glyphs[AREA][START].u.ch; \
5017 face_id = (ROW)->glyphs[AREA][START].face_id; \
5018 \
5019 s = (struct glyph_string *) alloca (sizeof *s); \
5020 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
5021 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
5022 x_append_glyph_string (&HEAD, &TAIL, s); \
5023 s->x = (X); \
5024 START = x_fill_glyph_string (s, face_id, START, END, \
5025 OVERLAPS_P); \
5026 } \
5027 while (0)
5028
5029
5030/* Add a glyph string for a composite sequence to the list of strings
5031 between HEAD and TAIL. START is the index of the first glyph in
5032 row area AREA of glyph row ROW that is part of the new glyph
5033 string. END is the index of the last glyph in that glyph row area.
5034 X is the current output position assigned to the new glyph string
5035 constructed. HL overrides that face of the glyph; e.g. it is
5036 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
5037 x-position of the drawing area. */
5038
5039#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
5040 do { \
5041 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
5042 int face_id = (ROW)->glyphs[AREA][START].face_id; \
5043 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
5044 struct composition *cmp = composition_table[cmp_id]; \
5045 int glyph_len = cmp->glyph_len; \
5046 XChar2b *char2b; \
5047 struct face **faces; \
5048 struct glyph_string *first_s = NULL; \
5049 int n; \
5050 \
5051 base_face = base_face->ascii_face; \
5052 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
5053 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
5054 /* At first, fill in `char2b' and `faces'. */ \
5055 for (n = 0; n < glyph_len; n++) \
5056 { \
5057 int c = COMPOSITION_GLYPH (cmp, n); \
5058 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
5059 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
5060 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
5061 this_face_id, char2b + n, 1); \
5062 } \
5063 \
5064 /* Make glyph_strings for each glyph sequence that is drawable by \
5065 the same face, and append them to HEAD/TAIL. */ \
5066 for (n = 0; n < cmp->glyph_len;) \
5067 { \
5068 s = (struct glyph_string *) alloca (sizeof *s); \
5069 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
5070 x_append_glyph_string (&(HEAD), &(TAIL), s); \
5071 s->cmp = cmp; \
5072 s->gidx = n; \
5073 s->x = (X); \
5074 \
5075 if (n == 0) \
5076 first_s = s; \
5077 \
5078 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
5079 } \
5080 \
5081 ++START; \
5082 s = first_s; \
5083 } while (0)
5084
5085
5086/* Build a list of glyph strings between HEAD and TAIL for the glyphs
5087 of AREA of glyph row ROW on window W between indices START and END.
5088 HL overrides the face for drawing glyph strings, e.g. it is
5089 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
5090 x-positions of the drawing area.
5091
5092 This is an ugly monster macro construct because we must use alloca
5093 to allocate glyph strings (because x_draw_glyphs can be called
5094 asynchronously). */
5095
5096#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
5097 do \
5098 { \
5099 HEAD = TAIL = NULL; \
5100 while (START < END) \
5101 { \
5102 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
5103 switch (first_glyph->type) \
5104 { \
5105 case CHAR_GLYPH: \
5106 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
5107 TAIL, HL, X, LAST_X, \
5108 OVERLAPS_P); \
5109 break; \
5110 \
5111 case COMPOSITE_GLYPH: \
5112 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5113 HEAD, TAIL, HL, X, LAST_X,\
5114 OVERLAPS_P); \
5115 break; \
5116 \
5117 case STRETCH_GLYPH: \
5118 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5119 HEAD, TAIL, HL, X, LAST_X); \
5120 break; \
5121 \
5122 case IMAGE_GLYPH: \
5123 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5124 TAIL, HL, X, LAST_X); \
5125 break; \
5126 \
5127 default: \
5128 abort (); \
5129 } \
5130 \
5131 x_set_glyph_string_background_width (s, START, LAST_X); \
5132 (X) += s->width; \
5133 } \
5134 } \
5135 while (0)
5136
5137
5138/* Draw glyphs between START and END in AREA of ROW on window W,
5139 starting at x-position X. X is relative to AREA in W. HL is a
5140 face-override with the following meaning:
5141
5142 DRAW_NORMAL_TEXT draw normally
5143 DRAW_CURSOR draw in cursor face
5144 DRAW_MOUSE_FACE draw in mouse face.
5145 DRAW_INVERSE_VIDEO draw in mode line face
5146 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5147 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5148
5149 If REAL_START is non-null, return in *REAL_START the real starting
5150 position for display. This can be different from START in case
5151 overlapping glyphs must be displayed. If REAL_END is non-null,
5152 return in *REAL_END the real end position for display. This can be
5153 different from END in case overlapping glyphs must be displayed.
5154
5155 If OVERLAPS_P is non-zero, draw only the foreground of characters
5156 and clip to the physical height of ROW.
5157
5158 Value is the x-position reached, relative to AREA of W. */
5159
5160static int
5161x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
5162 overlaps_p)
5163 struct window *w;
5164 int x;
5165 struct glyph_row *row;
5166 enum glyph_row_area area;
5167 int start, end;
5168 enum draw_glyphs_face hl;
5169 int *real_start, *real_end;
5170 int overlaps_p;
5171{
5172 struct glyph_string *head, *tail;
5173 struct glyph_string *s;
5174 int last_x, area_width;
5175 int x_reached;
5176 int i, j;
5177
5178 /* Let's rather be paranoid than getting a SEGV. */
5179 start = max (0, start);
5180 end = min (end, row->used[area]);
5181 if (real_start)
5182 *real_start = start;
5183 if (real_end)
5184 *real_end = end;
5185
5186 /* Translate X to frame coordinates. Set last_x to the right
5187 end of the drawing area. */
5188 if (row->full_width_p)
5189 {
5190 /* X is relative to the left edge of W, without scroll bars
5191 or flag areas. */
5192 struct frame *f = XFRAME (w->frame);
5193 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
5194 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
5195
5196 x += window_left_x;
5197 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5198 last_x = window_left_x + area_width;
5199
5200 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5201 {
5202 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
5203 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5204 last_x += width;
5205 else
5206 x -= width;
5207 }
5208
5209 x += FRAME_INTERNAL_BORDER_WIDTH (f);
5210 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
5211 }
5212 else
5213 {
5214 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5215 area_width = window_box_width (w, area);
5216 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
5217 }
5218
5219 /* Build a doubly-linked list of glyph_string structures between
5220 head and tail from what we have to draw. Note that the macro
5221 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5222 the reason we use a separate variable `i'. */
5223 i = start;
5224 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5225 overlaps_p);
5226 if (tail)
5227 x_reached = tail->x + tail->background_width;
5228 else
5229 x_reached = x;
5230
5231 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5232 the row, redraw some glyphs in front or following the glyph
5233 strings built above. */
5234 if (!overlaps_p && row->contains_overlapping_glyphs_p)
5235 {
5236 int dummy_x = 0;
5237 struct glyph_string *h, *t;
5238
5239 /* Compute overhangs for all glyph strings. */
5240 for (s = head; s; s = s->next)
5241 x_compute_glyph_string_overhangs (s);
5242
5243 /* Prepend glyph strings for glyphs in front of the first glyph
5244 string that are overwritten because of the first glyph
5245 string's left overhang. The background of all strings
5246 prepended must be drawn because the first glyph string
5247 draws over it. */
5248 i = x_left_overwritten (head);
5249 if (i >= 0)
5250 {
5251 j = i;
5252 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
5253 DRAW_NORMAL_TEXT, dummy_x, last_x,
5254 overlaps_p);
5255 start = i;
5256 if (real_start)
5257 *real_start = start;
5258 x_compute_overhangs_and_x (t, head->x, 1);
5259 x_prepend_glyph_string_lists (&head, &tail, h, t);
5260 }
5261
5262 /* Prepend glyph strings for glyphs in front of the first glyph
5263 string that overwrite that glyph string because of their
5264 right overhang. For these strings, only the foreground must
5265 be drawn, because it draws over the glyph string at `head'.
5266 The background must not be drawn because this would overwrite
5267 right overhangs of preceding glyphs for which no glyph
5268 strings exist. */
5269 i = x_left_overwriting (head);
5270 if (i >= 0)
5271 {
5272 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
5273 DRAW_NORMAL_TEXT, dummy_x, last_x,
5274 overlaps_p);
5275 for (s = h; s; s = s->next)
5276 s->background_filled_p = 1;
5277 if (real_start)
5278 *real_start = i;
5279 x_compute_overhangs_and_x (t, head->x, 1);
5280 x_prepend_glyph_string_lists (&head, &tail, h, t);
5281 }
5282
5283 /* Append glyphs strings for glyphs following the last glyph
5284 string tail that are overwritten by tail. The background of
5285 these strings has to be drawn because tail's foreground draws
5286 over it. */
5287 i = x_right_overwritten (tail);
5288 if (i >= 0)
5289 {
5290 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
5291 DRAW_NORMAL_TEXT, x, last_x,
5292 overlaps_p);
5293 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5294 x_append_glyph_string_lists (&head, &tail, h, t);
5295 if (real_end)
5296 *real_end = i;
5297 }
5298
5299 /* Append glyph strings for glyphs following the last glyph
5300 string tail that overwrite tail. The foreground of such
5301 glyphs has to be drawn because it writes into the background
5302 of tail. The background must not be drawn because it could
5303 paint over the foreground of following glyphs. */
5304 i = x_right_overwriting (tail);
5305 if (i >= 0)
5306 {
5307 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
5308 DRAW_NORMAL_TEXT, x, last_x,
5309 overlaps_p);
5310 for (s = h; s; s = s->next)
5311 s->background_filled_p = 1;
5312 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5313 x_append_glyph_string_lists (&head, &tail, h, t);
5314 if (real_end)
5315 *real_end = i;
5316 }
5317 }
5318
5319 /* Draw all strings. */
5320 for (s = head; s; s = s->next)
5321 x_draw_glyph_string (s);
5322
5323 /* Value is the x-position up to which drawn, relative to AREA of W.
5324 This doesn't include parts drawn because of overhangs. */
5325 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5326 if (!row->full_width_p)
5327 {
5328 if (area > LEFT_MARGIN_AREA)
5329 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5330 if (area > TEXT_AREA)
5331 x_reached -= window_box_width (w, TEXT_AREA);
5332 }
5333 return x_reached;
5334}
5335
5336
5337/* Fix the display of area AREA of overlapping row ROW in window W. */
5338
5339void
5340x_fix_overlapping_area (w, row, area)
5341 struct window *w;
5342 struct glyph_row *row;
5343 enum glyph_row_area area;
5344{
5345 int i, x;
5346
5347 BLOCK_INPUT;
5348
5349 if (area == LEFT_MARGIN_AREA)
5350 x = 0;
5351 else if (area == TEXT_AREA)
5352 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5353 else
5354 x = (window_box_width (w, LEFT_MARGIN_AREA)
5355 + window_box_width (w, TEXT_AREA));
5356
5357 for (i = 0; i < row->used[area];)
5358 {
5359 if (row->glyphs[area][i].overlaps_vertically_p)
5360 {
5361 int start = i, start_x = x;
5362
5363 do
5364 {
5365 x += row->glyphs[area][i].pixel_width;
5366 ++i;
5367 }
5368 while (i < row->used[area]
5369 && row->glyphs[area][i].overlaps_vertically_p);
5370
5371 x_draw_glyphs (w, start_x, row, area, start, i,
5372 (row->inverse_p
5373 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5374 NULL, NULL, 1);
5375 }
5376 else
5377 {
5378 x += row->glyphs[area][i].pixel_width;
5379 ++i;
5380 }
5381 }
5382
5383 UNBLOCK_INPUT;
5384}
5385
5386
5387/* Output LEN glyphs starting at START at the nominal cursor position.
5388 Advance the nominal cursor over the text. The global variable
5389 updated_window contains the window being updated, updated_row is
5390 the glyph row being updated, and updated_area is the area of that
5391 row being updated. */
5392
5393void
5394x_write_glyphs (start, len)
5395 struct glyph *start;
5396 int len;
5397{
5398 int x, hpos, real_start, real_end;
5399
5400 xassert (updated_window && updated_row);
5401 BLOCK_INPUT;
5402
5403 /* Write glyphs. */
5404
5405 hpos = start - updated_row->glyphs[updated_area];
5406 x = x_draw_glyphs (updated_window, output_cursor.x,
5407 updated_row, updated_area,
5408 hpos, hpos + len,
5409 (updated_row->inverse_p
5410 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5411 &real_start, &real_end, 0);
5412
5413 /* If we drew over the cursor, note that it is not visible any more. */
5414 note_overwritten_text_cursor (updated_window, real_start,
5415 real_end - real_start);
5416
5417 UNBLOCK_INPUT;
5418
5419 /* Advance the output cursor. */
5420 output_cursor.hpos += len;
5421 output_cursor.x = x;
5422}
5423
5424
5425/* Insert LEN glyphs from START at the nominal cursor position. */
5426
5427void
5428x_insert_glyphs (start, len)
5429 struct glyph *start;
5430 register int len;
5431{
5432 struct frame *f;
5433 struct window *w;
5434 int line_height, shift_by_width, shifted_region_width;
5435 struct glyph_row *row;
5436 struct glyph *glyph;
5437 int frame_x, frame_y, hpos, real_start, real_end;
5438
5439 xassert (updated_window && updated_row);
5440 BLOCK_INPUT;
5441 w = updated_window;
5442 f = XFRAME (WINDOW_FRAME (w));
5443
5444 /* Get the height of the line we are in. */
5445 row = updated_row;
5446 line_height = row->height;
5447
5448 /* Get the width of the glyphs to insert. */
5449 shift_by_width = 0;
5450 for (glyph = start; glyph < start + len; ++glyph)
5451 shift_by_width += glyph->pixel_width;
5452
5453 /* Get the width of the region to shift right. */
5454 shifted_region_width = (window_box_width (w, updated_area)
5455 - output_cursor.x
5456 - shift_by_width);
5457
5458 /* Shift right. */
5459 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
5460 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5461
5462 mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
5463 f->output_data.mac->normal_gc,
5464 frame_x, frame_y,
5465 shifted_region_width, line_height,
5466 frame_x + shift_by_width, frame_y);
5467
5468 /* Write the glyphs. */
5469 hpos = start - row->glyphs[updated_area];
5470 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
5471 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
5472 note_overwritten_text_cursor (w, real_start, real_end - real_start);
5473
5474 /* Advance the output cursor. */
5475 output_cursor.hpos += len;
5476 output_cursor.x += shift_by_width;
5477 UNBLOCK_INPUT;
5478}
5479
5480
5481/* Delete N glyphs at the nominal cursor position. Not implemented
5482 for X frames. */
5483
5484void
5485x_delete_glyphs (n)
5486 register int n;
5487{
5488 abort ();
5489}
5490
5491
5492/* Erase the current text line from the nominal cursor position
5493 (inclusive) to pixel column TO_X (exclusive). The idea is that
5494 everything from TO_X onward is already erased.
5495
5496 TO_X is a pixel position relative to updated_area of
5497 updated_window. TO_X == -1 means clear to the end of this area. */
5498
5499void
5500x_clear_end_of_line (to_x)
5501 int to_x;
5502{
5503 struct frame *f;
5504 struct window *w = updated_window;
5505 int max_x, min_y, max_y;
5506 int from_x, from_y, to_y;
5507
5508 xassert (updated_window && updated_row);
5509 f = XFRAME (w->frame);
5510
5511 if (updated_row->full_width_p)
5512 {
5513 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5514 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5515 && !w->pseudo_window_p)
5516 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
5517 }
5518 else
5519 max_x = window_box_width (w, updated_area);
5520 max_y = window_text_bottom_y (w);
5521
5522 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5523 of window. For TO_X > 0, truncate to end of drawing area. */
5524 if (to_x == 0)
5525 return;
5526 else if (to_x < 0)
5527 to_x = max_x;
5528 else
5529 to_x = min (to_x, max_x);
5530
5531 to_y = min (max_y, output_cursor.y + updated_row->height);
5532
5533 /* Notice if the cursor will be cleared by this operation. */
5534 if (!updated_row->full_width_p)
5535 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
5536
5537 from_x = output_cursor.x;
5538
5539 /* Translate to frame coordinates. */
5540 if (updated_row->full_width_p)
5541 {
5542 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5543 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5544 }
5545 else
5546 {
5547 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5548 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5549 }
5550
5551 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
5552 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5553 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5554
5555 /* Prevent inadvertently clearing to end of the X window. */
5556 if (to_x > from_x && to_y > from_y)
5557 {
5558 BLOCK_INPUT;
5559 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
5560 from_x, from_y, to_x - from_x, to_y - from_y,
5561 0);
5562 UNBLOCK_INPUT;
5563 }
5564}
5565
5566
5567/* Clear entire frame. If updating_frame is non-null, clear that
5568 frame. Otherwise clear the selected frame. */
5569
5570void
5571x_clear_frame ()
5572{
5573 struct frame *f;
5574
5575 if (updating_frame)
5576 f = updating_frame;
5577 else
5578 f = SELECTED_FRAME ();
5579
5580 /* Clearing the frame will erase any cursor, so mark them all as no
5581 longer visible. */
5582 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5583 output_cursor.hpos = output_cursor.vpos = 0;
5584 output_cursor.x = -1;
5585
5586 /* We don't set the output cursor here because there will always
5587 follow an explicit cursor_to. */
5588 BLOCK_INPUT;
5589 XClearWindow (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f));
5590
5591#if 0 /* Clearing frame on Mac OS clears scroll bars. */
5592 /* We have to clear the scroll bars, too. If we have changed
5593 colors or something like that, then they should be notified. */
5594 x_scroll_bar_clear (f);
5595#endif
5596
5597 XFlush (FRAME_MAC_DISPLAY (f));
5598 UNBLOCK_INPUT;
5599}
5600
5601
5602
5603/* Invert the middle quarter of the frame for .15 sec. */
5604
5605/* We use the select system call to do the waiting, so we have to make
5606 sure it's available. If it isn't, we just won't do visual bells. */
5607
5608#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5609
5610/* Subtract the `struct timeval' values X and Y, storing the result in
5611 *RESULT. Return 1 if the difference is negative, otherwise 0. */
5612
5613static int
5614timeval_subtract (result, x, y)
5615 struct timeval *result, x, y;
5616{
5617 /* Perform the carry for the later subtraction by updating y. This
5618 is safer because on some systems the tv_sec member is unsigned. */
5619 if (x.tv_usec < y.tv_usec)
5620 {
5621 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5622 y.tv_usec -= 1000000 * nsec;
5623 y.tv_sec += nsec;
5624 }
5625
5626 if (x.tv_usec - y.tv_usec > 1000000)
5627 {
5628 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5629 y.tv_usec += 1000000 * nsec;
5630 y.tv_sec -= nsec;
5631 }
5632
5633 /* Compute the time remaining to wait. tv_usec is certainly
5634 positive. */
5635 result->tv_sec = x.tv_sec - y.tv_sec;
5636 result->tv_usec = x.tv_usec - y.tv_usec;
5637
5638 /* Return indication of whether the result should be considered
5639 negative. */
5640 return x.tv_sec < y.tv_sec;
5641}
5642
5643void
5644XTflash (f)
5645 struct frame *f;
5646{
5647 BLOCK_INPUT;
5648
5649 FlashMenuBar (0);
5650
5651 {
5652 struct timeval wakeup;
5653
5654 EMACS_GET_TIME (wakeup);
5655
5656 /* Compute time to wait until, propagating carry from usecs. */
5657 wakeup.tv_usec += 150000;
5658 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5659 wakeup.tv_usec %= 1000000;
5660
5661 /* Keep waiting until past the time wakeup. */
5662 while (1)
5663 {
5664 struct timeval timeout;
5665
5666 EMACS_GET_TIME (timeout);
5667
5668 /* In effect, timeout = wakeup - timeout.
5669 Break if result would be negative. */
5670 if (timeval_subtract (&timeout, wakeup, timeout))
5671 break;
5672
5673 /* Try to wait that long--but we might wake up sooner. */
5674 select (0, NULL, NULL, NULL, &timeout);
5675 }
5676 }
5677
5678 FlashMenuBar (0);
5679
5680 UNBLOCK_INPUT;
5681}
5682
5683#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
5684
5685
5686/* Make audible bell. */
5687
5688void
5689XTring_bell ()
5690{
5691 struct frame *f = SELECTED_FRAME ();
5692
5693#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5694 if (visible_bell)
5695 XTflash (f);
5696 else
5697#endif
5698 {
5699 BLOCK_INPUT;
5700 SysBeep (1);
5701 XFlush (FRAME_MAC_DISPLAY (f));
5702 UNBLOCK_INPUT;
5703 }
5704}
5705
5706
5707
5708/* Specify how many text lines, from the top of the window,
5709 should be affected by insert-lines and delete-lines operations.
5710 This, and those operations, are used only within an update
5711 that is bounded by calls to x_update_begin and x_update_end. */
5712
5713void
5714XTset_terminal_window (n)
5715 register int n;
5716{
5717 /* This function intentionally left blank. */
5718}
5719
5720
5721
5722/***********************************************************************
5723 Line Dance
5724 ***********************************************************************/
5725
5726/* Perform an insert-lines or delete-lines operation, inserting N
5727 lines or deleting -N lines at vertical position VPOS. */
5728
5729void
5730x_ins_del_lines (vpos, n)
5731 int vpos, n;
5732{
5733 abort ();
5734}
5735
5736
5737/* Scroll part of the display as described by RUN. */
5738
5739void
5740x_scroll_run (w, run)
5741 struct window *w;
5742 struct run *run;
5743{
5744 struct frame *f = XFRAME (w->frame);
5745 int x, y, width, height, from_y, to_y, bottom_y;
5746
5747 /* Get frame-relative bounding box of the text display area of W,
5748 without mode lines. Include in this box the flags areas to the
5749 left and right of W. */
5750 window_box (w, -1, &x, &y, &width, &height);
5751 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5752 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
5753
5754 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5755 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5756 bottom_y = y + height;
5757
5758 if (to_y < from_y)
5759 {
5760 /* Scrolling up. Make sure we don't copy part of the mode
5761 line at the bottom. */
5762 if (from_y + run->height > bottom_y)
5763 height = bottom_y - from_y;
5764 else
5765 height = run->height;
5766 }
5767 else
5768 {
5769 /* Scolling down. Make sure we don't copy over the mode line.
5770 at the bottom. */
5771 if (to_y + run->height > bottom_y)
5772 height = bottom_y - to_y;
5773 else
5774 height = run->height;
5775 }
5776
5777 BLOCK_INPUT;
5778
5779 /* Cursor off. Will be switched on again in x_update_window_end. */
5780 updated_window = w;
5781 x_clear_cursor (w);
5782
5783 mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
5784 f->output_data.mac->normal_gc,
5785 x, from_y,
5786 width, height,
5787 x, to_y);
5788
5789 UNBLOCK_INPUT;
5790}
5791
5792
5793
5794/***********************************************************************
5795 Exposure Events
5796 ***********************************************************************/
5797
5798/* Redisplay an exposed area of frame F. X and Y are the upper-left
5799 corner of the exposed rectangle. W and H are width and height of
5800 the exposed area. All are pixel values. W or H zero means redraw
5801 the entire frame. */
5802
5803static void
5804expose_frame (f, x, y, w, h)
5805 struct frame *f;
5806 int x, y, w, h;
5807{
5808 Rect r;
5809
5810 TRACE ((stderr, "expose_frame "));
5811
5812 /* No need to redraw if frame will be redrawn soon. */
5813 if (FRAME_GARBAGED_P (f))
5814 {
5815 TRACE ((stderr, " garbaged\n"));
5816 return;
5817 }
5818
5819 /* MAC_TODO: this is a kludge, but if scroll bars are not activated
5820 or deactivated here, for unknown reasons, activated scroll bars
5821 are shown in deactivated frames in some instances. */
5822 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
5823 activate_scroll_bars (f);
5824 else
5825 deactivate_scroll_bars (f);
5826
5827 /* If basic faces haven't been realized yet, there is no point in
5828 trying to redraw anything. This can happen when we get an expose
5829 event while Emacs is starting, e.g. by moving another window. */
5830 if (FRAME_FACE_CACHE (f) == NULL
5831 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5832 {
5833 TRACE ((stderr, " no faces\n"));
5834 return;
5835 }
5836
5837 if (w == 0 || h == 0)
5838 {
5839 r.left = r.top = 0;
5840 r.right = CANON_X_UNIT (f) * f->width;
5841 r.bottom = CANON_Y_UNIT (f) * f->height;
5842 }
5843 else
5844 {
5845 r.left = x;
5846 r.top = y;
5847 r.right = x + w;
5848 r.bottom = y + h;
5849 }
5850
5851 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom));
5852 expose_window_tree (XWINDOW (f->root_window), &r);
5853
5854 if (WINDOWP (f->tool_bar_window))
5855 {
5856 struct window *w = XWINDOW (f->tool_bar_window);
5857 Rect window_rect;
5858 Rect intersection_rect;
5859 int window_x, window_y, window_width, window_height;
5860
5861
5862 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5863 window_rect.left = window_x;
5864 window_rect.top = window_y;
5865 window_rect.right = window_x + window_width;
5866 window_rect.bottom = window_y + window_height;
5867
5868 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5869 expose_window (w, &intersection_rect);
5870 }
5871
5872#ifndef USE_X_TOOLKIT
5873 if (WINDOWP (f->menu_bar_window))
5874 {
5875 struct window *w = XWINDOW (f->menu_bar_window);
5876 Rect window_rect;
5877 Rect intersection_rect;
5878 int window_x, window_y, window_width, window_height;
5879
5880
5881 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5882 window_rect.left = window_x;
5883 window_rect.top = window_y;
5884 window_rect.right = window_x + window_width;
5885 window_rect.bottom = window_y + window_height;
5886
5887 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5888 expose_window (w, &intersection_rect);
5889 }
5890#endif /* not USE_X_TOOLKIT */
5891}
5892
5893
5894/* Redraw (parts) of all windows in the window tree rooted at W that
5895 intersect R. R contains frame pixel coordinates. */
5896
5897static void
5898expose_window_tree (w, r)
5899 struct window *w;
5900 Rect *r;
5901{
5902 while (w)
5903 {
5904 if (!NILP (w->hchild))
5905 expose_window_tree (XWINDOW (w->hchild), r);
5906 else if (!NILP (w->vchild))
5907 expose_window_tree (XWINDOW (w->vchild), r);
5908 else
5909 {
5910 Rect window_rect;
5911 Rect intersection_rect;
5912 struct frame *f = XFRAME (w->frame);
5913 int window_x, window_y, window_width, window_height;
5914
5915 /* Frame-relative pixel rectangle of W. */
5916 window_box (w, -1, &window_x, &window_y, &window_width,
5917 &window_height);
5918 window_rect.left
5919 = (window_x
5920 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
5921 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_Y_UNIT (f));
5922 window_rect.top = window_y;
5923 window_rect.right = window_rect.left
5924 + (window_width
5925 + FRAME_X_FLAGS_AREA_WIDTH (f)
5926 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5927 window_rect.bottom = window_rect.top
5928 + window_height + CURRENT_MODE_LINE_HEIGHT (w);
5929
5930 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5931 expose_window (w, &intersection_rect);
5932 }
5933
5934 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5935 }
5936}
5937
5938
5939/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5940 which intersects rectangle R. R is in window-relative coordinates. */
5941
5942static void
5943expose_area (w, row, r, area)
5944 struct window *w;
5945 struct glyph_row *row;
5946 Rect *r;
5947 enum glyph_row_area area;
5948{
5949 int x;
5950 struct glyph *first = row->glyphs[area];
5951 struct glyph *end = row->glyphs[area] + row->used[area];
5952 struct glyph *last;
5953 int first_x;
5954
5955 /* Set x to the window-relative start position for drawing glyphs of
5956 AREA. The first glyph of the text area can be partially visible.
5957 The first glyphs of other areas cannot. */
5958 if (area == LEFT_MARGIN_AREA)
5959 x = 0;
5960 else if (area == TEXT_AREA)
5961 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5962 else
5963 x = (window_box_width (w, LEFT_MARGIN_AREA)
5964 + window_box_width (w, TEXT_AREA));
5965
5966 if (area == TEXT_AREA && row->fill_line_p)
5967 /* If row extends face to end of line write the whole line. */
5968 x_draw_glyphs (w, x, row, area,
5969 0, row->used[area],
5970 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5971 NULL, NULL, 0);
5972 else
5973 {
5974 /* Find the first glyph that must be redrawn. */
5975 while (first < end
5976 && x + first->pixel_width < r->left)
5977 {
5978 x += first->pixel_width;
5979 ++first;
5980 }
5981
5982 /* Find the last one. */
5983 last = first;
5984 first_x = x;
5985 while (last < end
5986 && x < r->right)
5987 {
5988 x += last->pixel_width;
5989 ++last;
5990 }
5991
5992 /* Repaint. */
5993 if (last > first)
5994 x_draw_glyphs (w, first_x, row, area,
5995 first - row->glyphs[area],
5996 last - row->glyphs[area],
5997 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5998 NULL, NULL, 0);
5999 }
6000}
6001
6002
6003/* Redraw the parts of the glyph row ROW on window W intersecting
6004 rectangle R. R is in window-relative coordinates. */
6005
6006static void
6007expose_line (w, row, r)
6008 struct window *w;
6009 struct glyph_row *row;
6010 Rect *r;
6011{
6012 xassert (row->enabled_p);
6013
6014 if (row->mode_line_p || w->pseudo_window_p)
6015 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
6016 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
6017 NULL, NULL, 0);
6018 else
6019 {
6020 if (row->used[LEFT_MARGIN_AREA])
6021 expose_area (w, row, r, LEFT_MARGIN_AREA);
6022 if (row->used[TEXT_AREA])
6023 expose_area (w, row, r, TEXT_AREA);
6024 if (row->used[RIGHT_MARGIN_AREA])
6025 expose_area (w, row, r, RIGHT_MARGIN_AREA);
6026 x_draw_row_bitmaps (w, row);
6027 }
6028}
6029
6030
6031/* Return non-zero if W's cursor intersects rectangle R. */
6032
6033static int
6034x_phys_cursor_in_rect_p (w, r)
6035 struct window *w;
6036 Rect *r;
6037{
6038 Rect cr, result;
6039 struct glyph *cursor_glyph;
6040
6041 cursor_glyph = get_phys_cursor_glyph (w);
6042 if (cursor_glyph)
6043 {
6044 cr.left = w->phys_cursor.x;
6045 cr.top = w->phys_cursor.y;
6046 cr.right = cr.left + cursor_glyph->pixel_width;
6047 cr.bottom = cr.top + w->phys_cursor_height;
6048 return x_intersect_rectangles (&cr, r, &result);
6049 }
6050 else
6051 return 0;
6052}
6053
6054
6055/* Redraw a rectangle of window W. R is a rectangle in window
6056 relative coordinates. Call this function with input blocked. */
6057
6058static void
6059expose_window (w, r)
6060 struct window *w;
6061 Rect *r;
6062{
6063 struct glyph_row *row;
6064 int y;
6065 int yb = window_text_bottom_y (w);
6066 int cursor_cleared_p;
6067
6068 /* If window is not yet fully initialized, do nothing. This can
6069 happen when toolkit scroll bars are used and a window is split.
6070 Reconfiguring the scroll bar will generate an expose for a newly
6071 created window. */
6072 if (w->current_matrix == NULL)
6073 return;
6074
6075 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6076 r->left, r->top, r->right, r->bottom));
6077
6078 /* Convert to window coordinates. */
6079 r->left = FRAME_TO_WINDOW_PIXEL_X (w, r->left);
6080 r->top = FRAME_TO_WINDOW_PIXEL_Y (w, r->top);
6081 r->right = FRAME_TO_WINDOW_PIXEL_X (w, r->right);
6082 r->bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r->bottom);
6083
6084 /* Turn off the cursor. */
6085 if (!w->pseudo_window_p
6086 && x_phys_cursor_in_rect_p (w, r))
6087 {
6088 x_clear_cursor (w);
6089 cursor_cleared_p = 1;
6090 }
6091 else
6092 cursor_cleared_p = 0;
6093
6094 /* Find the first row intersecting the rectangle R. */
6095 row = w->current_matrix->rows;
6096 y = 0;
6097 while (row->enabled_p
6098 && y < yb
6099 && y + row->height < r->top)
6100 {
6101 y += row->height;
6102 ++row;
6103 }
6104
6105 /* Display the text in the rectangle, one text line at a time. */
6106 while (row->enabled_p
6107 && y < yb
6108 && y < r->bottom)
6109 {
6110 expose_line (w, row, r);
6111 y += row->height;
6112 ++row;
6113 }
6114
6115 /* Display the mode line if there is one. */
6116 if (WINDOW_WANTS_MODELINE_P (w)
6117 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6118 row->enabled_p)
6119 && row->y < r->bottom)
6120 expose_line (w, row, r);
6121
6122 if (!w->pseudo_window_p)
6123 {
6124 /* Draw border between windows. */
6125 x_draw_vertical_border (w);
6126
6127 /* Turn the cursor on again. */
6128 if (cursor_cleared_p)
6129 x_update_window_cursor (w, 1);
6130 }
6131
6132 /* Display scroll bar for this window. */
6133 if (!NILP (w->vertical_scroll_bar))
6134 {
6135 ControlHandle ch
6136 = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar));
6137
6138 Draw1Control (ch);
6139 }
6140}
6141
6142
6143/* Determine the intersection of two rectangles R1 and R2. Return
6144 the intersection in *RESULT. Value is non-zero if RESULT is not
6145 empty. */
6146
6147static int
6148x_intersect_rectangles (r1, r2, result)
6149 Rect *r1, *r2, *result;
6150{
6151 Rect *left, *right;
6152 Rect *upper, *lower;
6153 int intersection_p = 0;
6154
6155 /* Rerrange so that R1 is the left-most rectangle. */
6156 if (r1->left < r2->left)
6157 left = r1, right = r2;
6158 else
6159 left = r2, right = r1;
6160
6161 /* X0 of the intersection is right.x0, if this is inside R1,
6162 otherwise there is no intersection. */
6163 if (right->left <= left->right)
6164 {
6165 result->left = right->left;
6166
6167 /* The right end of the intersection is the minimum of the
6168 the right ends of left and right. */
6169 result->right = min (left->right, right->right);
6170
6171 /* Same game for Y. */
6172 if (r1->top < r2->top)
6173 upper = r1, lower = r2;
6174 else
6175 upper = r2, lower = r1;
6176
6177 /* The upper end of the intersection is lower.y0, if this is inside
6178 of upper. Otherwise, there is no intersection. */
6179 if (lower->top <= upper->bottom)
6180 {
6181 result->top = lower->top;
6182
6183 /* The lower end of the intersection is the minimum of the lower
6184 ends of upper and lower. */
6185 result->bottom = min (lower->bottom, upper->bottom);
6186 intersection_p = 1;
6187 }
6188 }
6189
6190 return intersection_p;
6191}
6192
6193
6194
6195
6196
6197static void
6198frame_highlight (f)
6199 struct frame *f;
6200{
6201 x_update_cursor (f, 1);
6202}
6203
6204static void
6205frame_unhighlight (f)
6206 struct frame *f;
6207{
6208 x_update_cursor (f, 1);
6209}
6210
6211/* The focus has changed. Update the frames as necessary to reflect
6212 the new situation. Note that we can't change the selected frame
6213 here, because the Lisp code we are interrupting might become confused.
6214 Each event gets marked with the frame in which it occurred, so the
6215 Lisp code can tell when the switch took place by examining the events. */
6216
6217static void
6218x_new_focus_frame (dpyinfo, frame)
6219 struct x_display_info *dpyinfo;
6220 struct frame *frame;
6221{
6222 struct frame *old_focus = dpyinfo->x_focus_frame;
6223
6224 if (frame != dpyinfo->x_focus_frame)
6225 {
6226 /* Set this before calling other routines, so that they see
6227 the correct value of x_focus_frame. */
6228 dpyinfo->x_focus_frame = frame;
6229
6230 if (old_focus && old_focus->auto_lower)
6231 x_lower_frame (old_focus);
6232
6233#if 0
6234 selected_frame = frame;
6235 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6236 selected_frame);
6237 Fselect_window (selected_frame->selected_window);
6238 choose_minibuf_frame ();
6239#endif /* ! 0 */
6240
6241 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6242 pending_autoraise_frame = dpyinfo->x_focus_frame;
6243 else
6244 pending_autoraise_frame = 0;
6245 }
6246
6247 x_frame_rehighlight (dpyinfo);
6248}
6249
6250/* Handle an event saying the mouse has moved out of an Emacs frame. */
6251
6252static void
6253x_mouse_leave (dpyinfo)
6254 struct x_display_info *dpyinfo;
6255{
6256 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
6257}
6258
6259/* The focus has changed, or we have redirected a frame's focus to
6260 another frame (this happens when a frame uses a surrogate
6261 mini-buffer frame). Shift the highlight as appropriate.
6262
6263 The FRAME argument doesn't necessarily have anything to do with which
6264 frame is being highlighted or un-highlighted; we only use it to find
6265 the appropriate X display info. */
6266
6267void
6268XTframe_rehighlight (frame)
6269 struct frame *frame;
6270{
6271 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6272}
6273
6274static void
6275x_frame_rehighlight (dpyinfo)
6276 struct x_display_info *dpyinfo;
6277{
6278 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6279
6280 if (dpyinfo->x_focus_frame)
6281 {
6282 dpyinfo->x_highlight_frame
6283 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6284 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6285 : dpyinfo->x_focus_frame);
6286 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
6287 {
6288 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6289 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
6290 }
6291 }
6292 else
6293 dpyinfo->x_highlight_frame = 0;
6294
6295 if (dpyinfo->x_highlight_frame != old_highlight)
6296 {
6297 if (old_highlight)
6298 frame_unhighlight (old_highlight);
6299 if (dpyinfo->x_highlight_frame)
6300 frame_highlight (dpyinfo->x_highlight_frame);
6301 }
6302}
6303
6304
6305
6306/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
6307
6308#if 0
6309/* Initialize mode_switch_bit and modifier_meaning. */
6310static void
6311x_find_modifier_meanings (dpyinfo)
6312 struct x_display_info *dpyinfo;
6313{
6314 int min_code, max_code;
6315 KeySym *syms;
6316 int syms_per_code;
6317 XModifierKeymap *mods;
6318
6319 dpyinfo->meta_mod_mask = 0;
6320 dpyinfo->shift_lock_mask = 0;
6321 dpyinfo->alt_mod_mask = 0;
6322 dpyinfo->super_mod_mask = 0;
6323 dpyinfo->hyper_mod_mask = 0;
6324
6325#ifdef HAVE_X11R4
6326 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
6327#else
6328 min_code = dpyinfo->display->min_keycode;
6329 max_code = dpyinfo->display->max_keycode;
6330#endif
6331
6332 syms = XGetKeyboardMapping (dpyinfo->display,
6333 min_code, max_code - min_code + 1,
6334 &syms_per_code);
6335 mods = XGetModifierMapping (dpyinfo->display);
6336
6337 /* Scan the modifier table to see which modifier bits the Meta and
6338 Alt keysyms are on. */
6339 {
6340 int row, col; /* The row and column in the modifier table. */
6341
6342 for (row = 3; row < 8; row++)
6343 for (col = 0; col < mods->max_keypermod; col++)
6344 {
6345 KeyCode code
6346 = mods->modifiermap[(row * mods->max_keypermod) + col];
6347
6348 /* Zeroes are used for filler. Skip them. */
6349 if (code == 0)
6350 continue;
6351
6352 /* Are any of this keycode's keysyms a meta key? */
6353 {
6354 int code_col;
6355
6356 for (code_col = 0; code_col < syms_per_code; code_col++)
6357 {
6358 int sym = syms[((code - min_code) * syms_per_code) + code_col];
6359
6360 switch (sym)
6361 {
6362 case XK_Meta_L:
6363 case XK_Meta_R:
6364 dpyinfo->meta_mod_mask |= (1 << row);
6365 break;
6366
6367 case XK_Alt_L:
6368 case XK_Alt_R:
6369 dpyinfo->alt_mod_mask |= (1 << row);
6370 break;
6371
6372 case XK_Hyper_L:
6373 case XK_Hyper_R:
6374 dpyinfo->hyper_mod_mask |= (1 << row);
6375 break;
6376
6377 case XK_Super_L:
6378 case XK_Super_R:
6379 dpyinfo->super_mod_mask |= (1 << row);
6380 break;
6381
6382 case XK_Shift_Lock:
6383 /* Ignore this if it's not on the lock modifier. */
6384 if ((1 << row) == LockMask)
6385 dpyinfo->shift_lock_mask = LockMask;
6386 break;
6387 }
6388 }
6389 }
6390 }
6391 }
6392
6393 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
6394 if (! dpyinfo->meta_mod_mask)
6395 {
6396 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6397 dpyinfo->alt_mod_mask = 0;
6398 }
6399
6400 /* If some keys are both alt and meta,
6401 make them just meta, not alt. */
6402 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
6403 {
6404 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
6405 }
6406
6407 XFree ((char *) syms);
6408 XFreeModifiermap (mods);
6409}
6410
6411#endif
6412
6413/* Convert between the modifier bits X uses and the modifier bits
6414 Emacs uses. */
6415
6416static unsigned int
6417x_mac_to_emacs_modifiers (dpyinfo, state)
6418 struct x_display_info *dpyinfo;
6419 unsigned short state;
6420{
6421 return (((state & shiftKey) ? shift_modifier : 0)
6422 | ((state & controlKey) ? ctrl_modifier : 0)
6423 | ((state & cmdKey) ? meta_modifier : 0)
6424 | ((state & optionKey) ? alt_modifier : 0));
6425}
6426
6427#if 0
6428static unsigned short
6429x_emacs_to_x_modifiers (dpyinfo, state)
6430 struct x_display_info *dpyinfo;
6431 unsigned int state;
6432{
6433 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6434 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6435 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6436 | ((state & shift_modifier) ? ShiftMask : 0)
6437 | ((state & ctrl_modifier) ? ControlMask : 0)
6438 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
6439}
6440#endif
6441
6442/* Convert a keysym to its name. */
6443
6444char *
6445x_get_keysym_name (keysym)
6446 int keysym;
6447{
6448 char *value;
6449
6450 BLOCK_INPUT;
6451#if 0
6452 value = XKeysymToString (keysym);
6453#else
6454 value = 0;
6455#endif
6456 UNBLOCK_INPUT;
6457
6458 return value;
6459}
6460
6461
6462
6463/* Mouse clicks and mouse movement. Rah. */
6464
6465/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6466 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6467 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6468 not force the value into range. */
6469
6470void
6471pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
6472 FRAME_PTR f;
6473 register int pix_x, pix_y;
6474 register int *x, *y;
6475 Rect *bounds;
6476 int noclip;
6477{
6478 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
6479 even for negative values. */
6480 if (pix_x < 0)
6481 pix_x -= FONT_WIDTH ((f)->output_data.mac->font) - 1;
6482 if (pix_y < 0)
6483 pix_y -= (f)->output_data.mac->line_height - 1;
6484
6485 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6486 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6487
6488 if (bounds)
6489 {
6490 bounds->left = CHAR_TO_PIXEL_COL (f, pix_x);
6491 bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y);
6492 bounds->right = bounds->left + FONT_WIDTH (f->output_data.mac->font);
6493 bounds->bottom = bounds->top + f->output_data.mac->line_height;
6494 }
6495
6496 if (!noclip)
6497 {
6498 if (pix_x < 0)
6499 pix_x = 0;
6500 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6501 pix_x = FRAME_WINDOW_WIDTH (f);
6502
6503 if (pix_y < 0)
6504 pix_y = 0;
6505 else if (pix_y > f->height)
6506 pix_y = f->height;
6507 }
6508
6509 *x = pix_x;
6510 *y = pix_y;
6511}
6512
6513
6514/* Given HPOS/VPOS in the current matrix of W, return corresponding
6515 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6516 can't tell the positions because W's display is not up to date,
6517 return 0. */
6518
6519static int
6520glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6521 struct window *w;
6522 int hpos, vpos;
6523 int *frame_x, *frame_y;
6524{
6525 int success_p;
6526
6527 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6528 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6529
6530 if (display_completed)
6531 {
6532 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6533 struct glyph *glyph = row->glyphs[TEXT_AREA];
6534 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6535
6536 *frame_y = row->y;
6537 *frame_x = row->x;
6538 while (glyph < end)
6539 {
6540 *frame_x += glyph->pixel_width;
6541 ++glyph;
6542 }
6543
6544 success_p = 1;
6545 }
6546 else
6547 {
6548 *frame_y = *frame_x = 0;
6549 success_p = 0;
6550 }
6551
6552 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6553 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6554 return success_p;
6555}
6556
6557
6558/* Prepare a mouse-event in *RESULT for placement in the input queue.
6559
6560 If the event is a button press, then note that we have grabbed
6561 the mouse. */
6562
6563static Lisp_Object
6564construct_mouse_click (result, event, f)
6565 struct input_event *result;
6566 EventRecord *event;
6567 struct frame *f;
6568{
6569 Point mouseLoc;
6570
6571 result->kind = mouse_click;
6572 result->code = 0; /* only one mouse button */
6573 result->timestamp = event->when;
6574 result->modifiers = event->what == mouseDown ? down_modifier : up_modifier;
6575
6576 mouseLoc = event->where;
6577 SetPort (FRAME_MAC_WINDOW (f));
6578 GlobalToLocal (&mouseLoc);
6579 XSETINT (result->x, mouseLoc.h);
6580 XSETINT (result->y, mouseLoc.v);
6581
6582 XSETFRAME (result->frame_or_window, f);
6583
6584 result->arg = Qnil;
6585 return Qnil;
6586}
6587
6588
6589/* Function to report a mouse movement to the mainstream Emacs code.
6590 The input handler calls this.
6591
6592 We have received a mouse movement event, which is given in *event.
6593 If the mouse is over a different glyph than it was last time, tell
6594 the mainstream emacs code by setting mouse_moved. If not, ask for
6595 another motion event, so we can check again the next time it moves. */
6596
6597static Point last_mouse_motion_position;
6598static Lisp_Object last_mouse_motion_frame;
6599
6600static void
6601note_mouse_movement (frame, pos)
6602 FRAME_PTR frame;
6603 Point *pos;
6604{
6605 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */
6606 last_mouse_motion_position = *pos;
6607 XSETFRAME (last_mouse_motion_frame, frame);
6608
6609 if (!PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect))
6610 {
6611 frame->mouse_moved = 1;
6612 last_mouse_scroll_bar = Qnil;
6613 note_mouse_highlight (frame, -1, -1);
6614 }
6615 /* Has the mouse moved off the glyph it was on at the last sighting? */
6616 else if (pos->h < last_mouse_glyph.left
6617 || pos->h >= last_mouse_glyph.right
6618 || pos->v < last_mouse_glyph.top
6619 || pos->v >= last_mouse_glyph.bottom)
6620 {
6621 frame->mouse_moved = 1;
6622 last_mouse_scroll_bar = Qnil;
6623 note_mouse_highlight (frame, pos->h, pos->v);
6624 }
6625}
6626
6627/* This is used for debugging, to turn off note_mouse_highlight. */
6628
6629int disable_mouse_highlight;
6630
6631
6632
6633/************************************************************************
6634 Mouse Face
6635 ************************************************************************/
6636
6637/* Find the glyph under window-relative coordinates X/Y in window W.
6638 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6639 strings. Return in *HPOS and *VPOS the row and column number of
6640 the glyph found. Return in *AREA the glyph area containing X.
6641 Value is a pointer to the glyph found or null if X/Y is not on
6642 text, or we can't tell because W's current matrix is not up to
6643 date. */
6644
6645static struct glyph *
6646x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6647 struct window *w;
6648 int x, y;
6649 int *hpos, *vpos, *area;
6650{
6651 struct glyph *glyph, *end;
6652 struct glyph_row *row = NULL;
6653 int x0, i, left_area_width;
6654
6655 /* Find row containing Y. Give up if some row is not enabled. */
6656 for (i = 0; i < w->current_matrix->nrows; ++i)
6657 {
6658 row = MATRIX_ROW (w->current_matrix, i);
6659 if (!row->enabled_p)
6660 return NULL;
6661 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6662 break;
6663 }
6664
6665 *vpos = i;
6666 *hpos = 0;
6667
6668 /* Give up if Y is not in the window. */
6669 if (i == w->current_matrix->nrows)
6670 return NULL;
6671
6672 /* Get the glyph area containing X. */
6673 if (w->pseudo_window_p)
6674 {
6675 *area = TEXT_AREA;
6676 x0 = 0;
6677 }
6678 else
6679 {
6680 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6681 if (x < left_area_width)
6682 {
6683 *area = LEFT_MARGIN_AREA;
6684 x0 = 0;
6685 }
6686 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6687 {
6688 *area = TEXT_AREA;
6689 x0 = row->x + left_area_width;
6690 }
6691 else
6692 {
6693 *area = RIGHT_MARGIN_AREA;
6694 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6695 }
6696 }
6697
6698 /* Find glyph containing X. */
6699 glyph = row->glyphs[*area];
6700 end = glyph + row->used[*area];
6701 while (glyph < end)
6702 {
6703 if (x < x0 + glyph->pixel_width)
6704 {
6705 if (w->pseudo_window_p)
6706 break;
6707 else if (BUFFERP (glyph->object))
6708 break;
6709 }
6710
6711 x0 += glyph->pixel_width;
6712 ++glyph;
6713 }
6714
6715 if (glyph == end)
6716 return NULL;
6717
6718 *hpos = glyph - row->glyphs[*area];
6719 return glyph;
6720}
6721
6722
6723/* Convert frame-relative x/y to coordinates relative to window W.
6724 Takes pseudo-windows into account. */
6725
6726static void
6727frame_to_window_pixel_xy (w, x, y)
6728 struct window *w;
6729 int *x, *y;
6730{
6731 if (w->pseudo_window_p)
6732 {
6733 /* A pseudo-window is always full-width, and starts at the
6734 left edge of the frame, plus a frame border. */
6735 struct frame *f = XFRAME (w->frame);
6736 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6737 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6738 }
6739 else
6740 {
6741 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6742 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6743 }
6744}
6745
6746
6747/* Take proper action when mouse has moved to the mode or top line of
6748 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6749 mode line. X is relative to the start of the text display area of
6750 W, so the width of bitmap areas and scroll bars must be subtracted
6751 to get a position relative to the start of the mode line. */
6752
6753static void
6754note_mode_line_highlight (w, x, mode_line_p)
6755 struct window *w;
6756 int x, mode_line_p;
6757{
6758 struct frame *f = XFRAME (w->frame);
6759 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6760 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6761 struct glyph_row *row;
6762
6763 if (mode_line_p)
6764 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6765 else
6766 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
6767
6768 if (row->enabled_p)
6769 {
6770 struct glyph *glyph, *end;
6771 Lisp_Object help, map;
6772 int x0;
6773
6774 /* Find the glyph under X. */
6775 glyph = row->glyphs[TEXT_AREA];
6776 end = glyph + row->used[TEXT_AREA];
6777 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
6778 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
6779 while (glyph < end
6780 && x >= x0 + glyph->pixel_width)
6781 {
6782 x0 += glyph->pixel_width;
6783 ++glyph;
6784 }
6785
6786 if (glyph < end
6787 && STRINGP (glyph->object)
6788 && XSTRING (glyph->object)->intervals
6789 && glyph->charpos >= 0
6790 && glyph->charpos < XSTRING (glyph->object)->size)
6791 {
6792 /* If we're on a string with `help-echo' text property,
6793 arrange for the help to be displayed. This is done by
6794 setting the global variable help_echo to the help string. */
6795 help = Fget_text_property (make_number (glyph->charpos),
6796 Qhelp_echo, glyph->object);
6797 if (!NILP (help))
6798 {
6799 help_echo = help;
6800 XSETWINDOW (help_echo_window, w);
6801 help_echo_object = glyph->object;
6802 help_echo_pos = glyph->charpos;
6803 }
6804
6805 /* Change the mouse pointer according to what is under X/Y. */
6806 map = Fget_text_property (make_number (glyph->charpos),
6807 Qlocal_map, glyph->object);
6808 if (!NILP (Fkeymapp (map)))
6809 cursor = f->output_data.mac->nontext_cursor;
6810 else
6811 {
6812 map = Fget_text_property (make_number (glyph->charpos),
6813 Qkeymap, glyph->object);
6814 if (!NILP (Fkeymapp (map)))
6815 cursor = f->output_data.mac->nontext_cursor;
6816 }
6817 }
6818 }
6819
6820#if 0 /* MAC_TODO: mouse cursor */
6821 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6822#endif
6823}
6824
6825
6826/* Take proper action when the mouse has moved to position X, Y on
6827 frame F as regards highlighting characters that have mouse-face
6828 properties. Also de-highlighting chars where the mouse was before.
6829 X and Y can be negative or out of range. */
6830
6831static void
6832note_mouse_highlight (f, x, y)
6833 struct frame *f;
6834 int x, y;
6835{
6836 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6837 int portion;
6838 Lisp_Object window;
6839 struct window *w;
6840
6841 /* When a menu is active, don't highlight because this looks odd. */
6842#ifdef USE_X_TOOLKIT
6843 if (popup_activated ())
6844 return;
6845#endif
6846
6847 if (disable_mouse_highlight
6848 || !f->glyphs_initialized_p)
6849 return;
6850
6851 dpyinfo->mouse_face_mouse_x = x;
6852 dpyinfo->mouse_face_mouse_y = y;
6853 dpyinfo->mouse_face_mouse_frame = f;
6854
6855 if (dpyinfo->mouse_face_defer)
6856 return;
6857
6858 if (gc_in_progress)
6859 {
6860 dpyinfo->mouse_face_deferred_gc = 1;
6861 return;
6862 }
6863
6864 /* Which window is that in? */
6865 window = window_from_coordinates (f, x, y, &portion, 1);
6866
6867 /* If we were displaying active text in another window, clear that. */
6868 if (! EQ (window, dpyinfo->mouse_face_window))
6869 clear_mouse_face (dpyinfo);
6870
6871 /* Not on a window -> return. */
6872 if (!WINDOWP (window))
6873 return;
6874
6875 /* Convert to window-relative pixel coordinates. */
6876 w = XWINDOW (window);
6877 frame_to_window_pixel_xy (w, &x, &y);
6878
6879 /* Handle tool-bar window differently since it doesn't display a
6880 buffer. */
6881 if (EQ (window, f->tool_bar_window))
6882 {
6883 note_tool_bar_highlight (f, x, y);
6884 return;
6885 }
6886
6887 if (portion == 1 || portion == 3)
6888 {
6889 /* Mouse is on the mode or top line. */
6890 note_mode_line_highlight (w, x, portion == 1);
6891 return;
6892 }
6893#if 0 /* MAC_TODO: mouse cursor */
6894 else
6895 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6896 f->output_data.x->text_cursor);
6897#endif
6898
6899 /* Are we in a window whose display is up to date?
6900 And verify the buffer's text has not changed. */
6901 if (/* Within text portion of the window. */
6902 portion == 0
6903 && EQ (w->window_end_valid, w->buffer)
6904 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6905 && (XFASTINT (w->last_overlay_modified)
6906 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
6907 {
6908 int hpos, vpos, pos, i, area;
6909 struct glyph *glyph;
6910
6911 /* Find the glyph under X/Y. */
6912 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6913
6914 /* Clear mouse face if X/Y not over text. */
6915 if (glyph == NULL
6916 || area != TEXT_AREA
6917 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
6918 {
6919 clear_mouse_face (dpyinfo);
6920 return;
6921 }
6922
6923 pos = glyph->charpos;
6924 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6925
6926 /* Check for mouse-face and help-echo. */
6927 {
6928 Lisp_Object mouse_face, overlay, position;
6929 Lisp_Object *overlay_vec;
6930 int len, noverlays;
6931 struct buffer *obuf;
6932 int obegv, ozv;
6933
6934 /* If we get an out-of-range value, return now; avoid an error. */
6935 if (pos > BUF_Z (XBUFFER (w->buffer)))
6936 return;
6937
6938 /* Make the window's buffer temporarily current for
6939 overlays_at and compute_char_face. */
6940 obuf = current_buffer;
6941 current_buffer = XBUFFER (w->buffer);
6942 obegv = BEGV;
6943 ozv = ZV;
6944 BEGV = BEG;
6945 ZV = Z;
6946
6947 /* Is this char mouse-active or does it have help-echo? */
6948 XSETINT (position, pos);
6949
6950 /* Put all the overlays we want in a vector in overlay_vec.
6951 Store the length in len. If there are more than 10, make
6952 enough space for all, and try again. */
6953 len = 10;
6954 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6955 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6956 if (noverlays > len)
6957 {
6958 len = noverlays;
6959 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6960 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6961 }
6962
6963 /* Sort overlays into increasing priority order. */
6964 noverlays = sort_overlays (overlay_vec, noverlays, w);
6965
6966 /* Check mouse-face highlighting. */
6967 if (! (EQ (window, dpyinfo->mouse_face_window)
6968 && vpos >= dpyinfo->mouse_face_beg_row
6969 && vpos <= dpyinfo->mouse_face_end_row
6970 && (vpos > dpyinfo->mouse_face_beg_row
6971 || hpos >= dpyinfo->mouse_face_beg_col)
6972 && (vpos < dpyinfo->mouse_face_end_row
6973 || hpos < dpyinfo->mouse_face_end_col
6974 || dpyinfo->mouse_face_past_end)))
6975 {
6976 /* Clear the display of the old active region, if any. */
6977 clear_mouse_face (dpyinfo);
6978
6979 /* Find the highest priority overlay that has a mouse-face prop. */
6980 overlay = Qnil;
6981 for (i = noverlays - 1; i >= 0; --i)
6982 {
6983 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6984 if (!NILP (mouse_face))
6985 {
6986 overlay = overlay_vec[i];
6987 break;
6988 }
6989 }
6990
6991 /* If no overlay applies, get a text property. */
6992 if (NILP (overlay))
6993 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6994
6995 /* Handle the overlay case. */
6996 if (! NILP (overlay))
6997 {
6998 /* Find the range of text around this char that
6999 should be active. */
7000 Lisp_Object before, after;
7001 int ignore;
7002
7003 before = Foverlay_start (overlay);
7004 after = Foverlay_end (overlay);
7005 /* Record this as the current active region. */
7006 fast_find_position (w, XFASTINT (before),
7007 &dpyinfo->mouse_face_beg_col,
7008 &dpyinfo->mouse_face_beg_row,
7009 &dpyinfo->mouse_face_beg_x,
7010 &dpyinfo->mouse_face_beg_y);
7011 dpyinfo->mouse_face_past_end
7012 = !fast_find_position (w, XFASTINT (after),
7013 &dpyinfo->mouse_face_end_col,
7014 &dpyinfo->mouse_face_end_row,
7015 &dpyinfo->mouse_face_end_x,
7016 &dpyinfo->mouse_face_end_y);
7017 dpyinfo->mouse_face_window = window;
7018 dpyinfo->mouse_face_face_id
7019 = face_at_buffer_position (w, pos, 0, 0,
7020 &ignore, pos + 1, 1);
7021
7022 /* Display it as active. */
7023 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7024 }
7025 /* Handle the text property case. */
7026 else if (! NILP (mouse_face))
7027 {
7028 /* Find the range of text around this char that
7029 should be active. */
7030 Lisp_Object before, after, beginning, end;
7031 int ignore;
7032
7033 beginning = Fmarker_position (w->start);
7034 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
7035 - XFASTINT (w->window_end_pos)));
7036 before
7037 = Fprevious_single_property_change (make_number (pos + 1),
7038 Qmouse_face,
7039 w->buffer, beginning);
7040 after
7041 = Fnext_single_property_change (position, Qmouse_face,
7042 w->buffer, end);
7043 /* Record this as the current active region. */
7044 fast_find_position (w, XFASTINT (before),
7045 &dpyinfo->mouse_face_beg_col,
7046 &dpyinfo->mouse_face_beg_row,
7047 &dpyinfo->mouse_face_beg_x,
7048 &dpyinfo->mouse_face_beg_y);
7049 dpyinfo->mouse_face_past_end
7050 = !fast_find_position (w, XFASTINT (after),
7051 &dpyinfo->mouse_face_end_col,
7052 &dpyinfo->mouse_face_end_row,
7053 &dpyinfo->mouse_face_end_x,
7054 &dpyinfo->mouse_face_end_y);
7055 dpyinfo->mouse_face_window = window;
7056 dpyinfo->mouse_face_face_id
7057 = face_at_buffer_position (w, pos, 0, 0,
7058 &ignore, pos + 1, 1);
7059
7060 /* Display it as active. */
7061 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7062 }
7063 }
7064
7065 /* Look for a `help-echo' property. */
7066 {
7067 Lisp_Object help, overlay;
7068
7069 /* Check overlays first. */
7070 help = Qnil;
7071 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7072 {
7073 overlay = overlay_vec[i];
7074 help = Foverlay_get (overlay, Qhelp_echo);
7075 }
7076
7077 if (!NILP (help))
7078 {
7079 help_echo = help;
7080 help_echo_window = window;
7081 help_echo_object = overlay;
7082 help_echo_pos = pos;
7083 }
7084 else
7085 {
7086 /* Try text properties. */
7087 if ((STRINGP (glyph->object)
7088 && glyph->charpos >= 0
7089 && glyph->charpos < XSTRING (glyph->object)->size)
7090 || (BUFFERP (glyph->object)
7091 && glyph->charpos >= BEGV
7092 && glyph->charpos < ZV))
7093 help = Fget_text_property (make_number (glyph->charpos),
7094 Qhelp_echo, glyph->object);
7095
7096 if (!NILP (help))
7097 {
7098 help_echo = help;
7099 help_echo_window = window;
7100 help_echo_object = glyph->object;
7101 help_echo_pos = glyph->charpos;
7102 }
7103 }
7104 }
7105
7106 BEGV = obegv;
7107 ZV = ozv;
7108 current_buffer = obuf;
7109 }
7110 }
7111}
7112
7113static void
7114redo_mouse_highlight ()
7115{
7116 if (!NILP (last_mouse_motion_frame)
7117 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7118 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7119 last_mouse_motion_position.h,
7120 last_mouse_motion_position.v);
7121}
7122
7123
7124
7125/***********************************************************************
7126 Tool-bars
7127 ***********************************************************************/
7128
7129static int x_tool_bar_item P_ ((struct frame *, int, int,
7130 struct glyph **, int *, int *, int *));
7131
7132/* Tool-bar item index of the item on which a mouse button was pressed
7133 or -1. */
7134
7135static int last_tool_bar_item;
7136
7137
7138/* Get information about the tool-bar item at position X/Y on frame F.
7139 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7140 the current matrix of the tool-bar window of F, or NULL if not
7141 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
7142 item in F->current_tool_bar_items. Value is
7143
7144 -1 if X/Y is not on a tool-bar item
7145 0 if X/Y is on the same item that was highlighted before.
7146 1 otherwise. */
7147
7148static int
7149x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
7150 struct frame *f;
7151 int x, y;
7152 struct glyph **glyph;
7153 int *hpos, *vpos, *prop_idx;
7154{
7155 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7156 struct window *w = XWINDOW (f->tool_bar_window);
7157 int area;
7158
7159 /* Find the glyph under X/Y. */
7160 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
7161 if (*glyph == NULL)
7162 return -1;
7163
7164 /* Get the start of this tool-bar item's properties in
7165 f->current_tool_bar_items. */
7166 if (!tool_bar_item_info (f, *glyph, prop_idx))
7167 return -1;
7168
7169 /* Is mouse on the highlighted item? */
7170 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
7171 && *vpos >= dpyinfo->mouse_face_beg_row
7172 && *vpos <= dpyinfo->mouse_face_end_row
7173 && (*vpos > dpyinfo->mouse_face_beg_row
7174 || *hpos >= dpyinfo->mouse_face_beg_col)
7175 && (*vpos < dpyinfo->mouse_face_end_row
7176 || *hpos < dpyinfo->mouse_face_end_col
7177 || dpyinfo->mouse_face_past_end))
7178 return 0;
7179
7180 return 1;
7181}
7182
7183
7184/* Handle mouse button event on the tool-bar of frame F, at
7185 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7186 or ButtonRelase. */
7187
7188static void
7189x_handle_tool_bar_click (f, button_event)
7190 struct frame *f;
7191 EventRecord *button_event;
7192{
7193 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7194 struct window *w = XWINDOW (f->tool_bar_window);
7195 int hpos, vpos, prop_idx;
7196 struct glyph *glyph;
7197 Lisp_Object enabled_p;
7198 int x = button_event->where.h;
7199 int y = button_event->where.v;
7200
7201 /* If not on the highlighted tool-bar item, return. */
7202 frame_to_window_pixel_xy (w, &x, &y);
7203 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
7204 return;
7205
7206 /* If item is disabled, do nothing. */
7207 enabled_p = (XVECTOR (f->current_tool_bar_items)
7208 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
7209 if (NILP (enabled_p))
7210 return;
7211
7212 if (button_event->what == mouseDown)
7213 {
7214 /* Show item in pressed state. */
7215 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7216 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
7217 last_tool_bar_item = prop_idx;
7218 }
7219 else
7220 {
7221 Lisp_Object key, frame;
7222 struct input_event event;
7223
7224 /* Show item in released state. */
7225 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7226 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7227
7228 key = (XVECTOR (f->current_tool_bar_items)
7229 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
7230
7231 XSETFRAME (frame, f);
7232 event.kind = TOOL_BAR_EVENT;
7233 event.frame_or_window = frame;
7234 event.arg = frame;
7235 kbd_buffer_store_event (&event);
7236
7237 event.kind = TOOL_BAR_EVENT;
7238 event.frame_or_window = frame;
7239 event.arg = key;
7240 event.modifiers = x_mac_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7241 button_event->modifiers);
7242 kbd_buffer_store_event (&event);
7243 last_tool_bar_item = -1;
7244 }
7245}
7246
7247
7248/* Possibly highlight a tool-bar item on frame F when mouse moves to
7249 tool-bar window-relative coordinates X/Y. Called from
7250 note_mouse_highlight. */
7251
7252static void
7253note_tool_bar_highlight (f, x, y)
7254 struct frame *f;
7255 int x, y;
7256{
7257 Lisp_Object window = f->tool_bar_window;
7258 struct window *w = XWINDOW (window);
7259 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7260 int hpos, vpos;
7261 struct glyph *glyph;
7262 struct glyph_row *row;
7263 int i;
7264 Lisp_Object enabled_p;
7265 int prop_idx;
7266 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
7267 int mouse_down_p, rc;
7268
7269 /* Function note_mouse_highlight is called with negative x(y
7270 values when mouse moves outside of the frame. */
7271 if (x <= 0 || y <= 0)
7272 {
7273 clear_mouse_face (dpyinfo);
7274 return;
7275 }
7276
7277 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
7278 if (rc < 0)
7279 {
7280 /* Not on tool-bar item. */
7281 clear_mouse_face (dpyinfo);
7282 return;
7283 }
7284 else if (rc == 0)
7285 /* On same tool-bar item as before. */
7286 goto set_help_echo;
7287
7288 clear_mouse_face (dpyinfo);
7289
7290 /* Mouse is down, but on different tool-bar item? */
7291 mouse_down_p = (dpyinfo->grabbed
7292 && f == last_mouse_frame
7293 && FRAME_LIVE_P (f));
7294 if (mouse_down_p
7295 && last_tool_bar_item != prop_idx)
7296 return;
7297
7298 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7299 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7300
7301 /* If tool-bar item is not enabled, don't highlight it. */
7302 enabled_p = (XVECTOR (f->current_tool_bar_items)
7303 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
7304 if (!NILP (enabled_p))
7305 {
7306 /* Compute the x-position of the glyph. In front and past the
7307 image is a space. We include this is the highlighted area. */
7308 row = MATRIX_ROW (w->current_matrix, vpos);
7309 for (i = x = 0; i < hpos; ++i)
7310 x += row->glyphs[TEXT_AREA][i].pixel_width;
7311
7312 /* Record this as the current active region. */
7313 dpyinfo->mouse_face_beg_col = hpos;
7314 dpyinfo->mouse_face_beg_row = vpos;
7315 dpyinfo->mouse_face_beg_x = x;
7316 dpyinfo->mouse_face_beg_y = row->y;
7317 dpyinfo->mouse_face_past_end = 0;
7318
7319 dpyinfo->mouse_face_end_col = hpos + 1;
7320 dpyinfo->mouse_face_end_row = vpos;
7321 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7322 dpyinfo->mouse_face_end_y = row->y;
7323 dpyinfo->mouse_face_window = window;
7324 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
7325
7326 /* Display it as active. */
7327 show_mouse_face (dpyinfo, draw);
7328 dpyinfo->mouse_face_image_state = draw;
7329 }
7330
7331 set_help_echo:
7332
7333 /* Set help_echo to a help string.to display for this tool-bar item.
7334 XTread_socket does the rest. */
7335 help_echo_object = help_echo_window = Qnil;
7336 help_echo_pos = -1;
7337 help_echo = (XVECTOR (f->current_tool_bar_items)
7338 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
7339 if (NILP (help_echo))
7340 help_echo = (XVECTOR (f->current_tool_bar_items)
7341 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
7342}
7343
7344
7345
7346/* Find the glyph matrix position of buffer position POS in window W.
7347 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7348 current glyphs must be up to date. If POS is above window start
7349 return (0, 0, 0, 0). If POS is after end of W, return end of
7350 last line in W. */
7351
7352static int
7353fast_find_position (w, pos, hpos, vpos, x, y)
7354 struct window *w;
7355 int pos;
7356 int *hpos, *vpos, *x, *y;
7357{
7358 int i;
7359 int lastcol;
7360 int maybe_next_line_p = 0;
7361 int line_start_position;
7362 int yb = window_text_bottom_y (w);
7363 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
7364 struct glyph_row *best_row = row;
7365 int row_vpos = 0, best_row_vpos = 0;
7366 int current_x;
7367
7368 while (row->y < yb)
7369 {
7370 if (row->used[TEXT_AREA])
7371 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7372 else
7373 line_start_position = 0;
7374
7375 if (line_start_position > pos)
7376 break;
7377 /* If the position sought is the end of the buffer,
7378 don't include the blank lines at the bottom of the window. */
7379 else if (line_start_position == pos
7380 && pos == BUF_ZV (XBUFFER (w->buffer)))
7381 {
7382 maybe_next_line_p = 1;
7383 break;
7384 }
7385 else if (line_start_position > 0)
7386 {
7387 best_row = row;
7388 best_row_vpos = row_vpos;
7389 }
7390
7391 if (row->y + row->height >= yb)
7392 break;
7393
7394 ++row;
7395 ++row_vpos;
7396 }
7397
7398 /* Find the right column within BEST_ROW. */
7399 lastcol = 0;
7400 current_x = best_row->x;
7401 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
7402 {
7403 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7404 int charpos;
7405
7406 charpos = glyph->charpos;
7407 if (charpos == pos)
7408 {
7409 *hpos = i;
7410 *vpos = best_row_vpos;
7411 *x = current_x;
7412 *y = best_row->y;
7413 return 1;
7414 }
7415 else if (charpos > pos)
7416 break;
7417 else if (charpos > 0)
7418 lastcol = i;
7419
7420 current_x += glyph->pixel_width;
7421 }
7422
7423 /* If we're looking for the end of the buffer,
7424 and we didn't find it in the line we scanned,
7425 use the start of the following line. */
7426 if (maybe_next_line_p)
7427 {
7428 ++best_row;
7429 ++best_row_vpos;
7430 lastcol = 0;
7431 current_x = best_row->x;
7432 }
7433
7434 *vpos = best_row_vpos;
7435 *hpos = lastcol + 1;
7436 *x = current_x;
7437 *y = best_row->y;
7438 return 0;
7439}
7440
7441
7442/* Display the active region described by mouse_face_*
7443 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7444
7445static void
7446show_mouse_face (dpyinfo, draw)
7447 struct mac_display_info *dpyinfo;
7448 enum draw_glyphs_face draw;
7449{
7450 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
7451 struct frame *f = XFRAME (WINDOW_FRAME (w));
7452 int i;
7453 int cursor_off_p = 0;
7454 struct cursor_pos saved_cursor;
7455
7456 saved_cursor = output_cursor;
7457
7458 /* If window is in the process of being destroyed, don't bother
7459 to do anything. */
7460 if (w->current_matrix == NULL)
7461 goto set_x_cursor;
7462
7463 /* Recognize when we are called to operate on rows that don't exist
7464 anymore. This can happen when a window is split. */
7465 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7466 goto set_x_cursor;
7467
7468 set_output_cursor (&w->phys_cursor);
7469
7470 /* Note that mouse_face_beg_row etc. are window relative. */
7471 for (i = dpyinfo->mouse_face_beg_row;
7472 i <= dpyinfo->mouse_face_end_row;
7473 i++)
7474 {
7475 int start_hpos, end_hpos, start_x;
7476 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7477
7478 /* Don't do anything if row doesn't have valid contents. */
7479 if (!row->enabled_p)
7480 continue;
7481
7482 /* For all but the first row, the highlight starts at column 0. */
7483 if (i == dpyinfo->mouse_face_beg_row)
7484 {
7485 start_hpos = dpyinfo->mouse_face_beg_col;
7486 start_x = dpyinfo->mouse_face_beg_x;
7487 }
7488 else
7489 {
7490 start_hpos = 0;
7491 start_x = 0;
7492 }
7493
7494 if (i == dpyinfo->mouse_face_end_row)
7495 end_hpos = dpyinfo->mouse_face_end_col;
7496 else
7497 end_hpos = row->used[TEXT_AREA];
7498
7499 /* If the cursor's in the text we are about to rewrite, turn the
7500 cursor off. */
7501 if (!w->pseudo_window_p
7502 && i == output_cursor.vpos
7503 && output_cursor.hpos >= start_hpos - 1
7504 && output_cursor.hpos <= end_hpos)
7505 {
7506 x_update_window_cursor (w, 0);
7507 cursor_off_p = 1;
7508 }
7509
7510 if (end_hpos > start_hpos)
7511 {
7512 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7513 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7514 start_hpos, end_hpos, draw, NULL, NULL, 0);
7515 }
7516 }
7517
7518 /* If we turned the cursor off, turn it back on. */
7519 if (cursor_off_p)
7520 x_display_cursor (w, 1,
7521 output_cursor.hpos, output_cursor.vpos,
7522 output_cursor.x, output_cursor.y);
7523
7524 output_cursor = saved_cursor;
7525
7526 set_x_cursor:
7527#if 0 /* MAC_TODO: mouse cursor */
7528 /* Change the mouse cursor. */
7529 if (draw == DRAW_NORMAL_TEXT)
7530 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7531 f->output_data.x->text_cursor);
7532 else if (draw == DRAW_MOUSE_FACE)
7533 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7534 f->output_data.x->cross_cursor);
7535 else
7536 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7537 f->output_data.x->nontext_cursor);
7538#endif
7539 ;
7540}
7541
7542/* Clear out the mouse-highlighted active region.
7543 Redraw it un-highlighted first. */
7544
7545void
7546clear_mouse_face (dpyinfo)
7547 struct mac_display_info *dpyinfo;
7548{
7549 if (tip_frame)
7550 return;
7551
7552 if (! NILP (dpyinfo->mouse_face_window))
7553 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7554
7555 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7556 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7557 dpyinfo->mouse_face_window = Qnil;
7558}
7559
7560
7561/* Clear any mouse-face on window W. This function is part of the
7562 redisplay interface, and is called from try_window_id and similar
7563 functions to ensure the mouse-highlight is off. */
7564
7565void
7566x_clear_mouse_face (w)
7567 struct window *w;
7568{
7569 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame));
7570 Lisp_Object window;
7571
7572 XSETWINDOW (window, w);
7573 if (EQ (window, dpyinfo->mouse_face_window))
7574 clear_mouse_face (dpyinfo);
7575}
7576
7577
7578/* Just discard the mouse face information for frame F, if any.
7579 This is used when the size of F is changed. */
7580
7581static void
7582cancel_mouse_face (f)
7583 FRAME_PTR f;
7584{
7585 Lisp_Object window;
7586 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
7587
7588 window = dpyinfo->mouse_face_window;
7589 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7590 {
7591 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7592 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7593 dpyinfo->mouse_face_window = Qnil;
7594 }
7595}
7596
7597static struct scroll_bar *x_window_to_scroll_bar ();
7598static void x_scroll_bar_report_motion ();
7599
7600/* Return the current position of the mouse.
7601 *fp should be a frame which indicates which display to ask about.
7602
7603 If the mouse movement started in a scroll bar, set *fp, *bar_window,
7604 and *part to the frame, window, and scroll bar part that the mouse
7605 is over. Set *x and *y to the portion and whole of the mouse's
7606 position on the scroll bar.
7607
7608 If the mouse movement started elsewhere, set *fp to the frame the
7609 mouse is on, *bar_window to nil, and *x and *y to the character cell
7610 the mouse is over.
7611
7612 Set *time to the server time-stamp for the time at which the mouse
7613 was at this position.
7614
7615 Don't store anything if we don't have a valid set of values to report.
7616
7617 This clears the mouse_moved flag, so we can wait for the next mouse
7618 movement. */
7619
7620void
7621XTmouse_position (fp, insist, bar_window, part, x, y, time)
7622 FRAME_PTR *fp;
7623 int insist;
7624 Lisp_Object *bar_window;
7625 enum scroll_bar_part *part;
7626 Lisp_Object *x, *y;
7627 unsigned long *time;
7628{
7629 Point mouse_pos;
7630 int ignore1, ignore2;
7631 WindowPtr wp = FrontWindow ();
7632 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
7633 Lisp_Object frame, tail;
7634
7635 BLOCK_INPUT;
7636
7637 if (! NILP (last_mouse_scroll_bar) && insist == 0)
7638 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
7639 else
7640 {
7641 /* Clear the mouse-moved flag for every frame on this display. */
7642 FOR_EACH_FRAME (tail, frame)
7643 XFRAME (frame)->mouse_moved = 0;
7644
7645 last_mouse_scroll_bar = Qnil;
7646
7647 SetPort (wp);
7648 GetMouse (&mouse_pos);
7649
7650 pixel_to_glyph_coords (f, mouse_pos.h, mouse_pos.v, &ignore1, &ignore2,
7651 &last_mouse_glyph, insist);
7652
7653 *bar_window = Qnil;
7654 *part = scroll_bar_handle;
7655 *fp = f;
7656 XSETINT (*x, mouse_pos.h);
7657 XSETINT (*y, mouse_pos.v);
7658 *time = last_mouse_movement_time;
7659 }
7660
7661 UNBLOCK_INPUT;
7662}
7663
7664
7665/************************************************************************
7666 Scroll bars, general
7667 ************************************************************************/
7668
7669/* Create a scroll bar and return the scroll bar vector for it. W is
7670 the Emacs window on which to create the scroll bar. TOP, LEFT,
7671 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
7672 scroll bar. */
7673
7674static struct scroll_bar *
7675x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
7676 struct window *w;
7677 int top, left, width, height, disp_top, disp_height;
7678{
7679 struct frame *f = XFRAME (w->frame);
7680 struct scroll_bar *bar
7681 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
7682 Rect r;
7683 ControlHandle ch;
7684
7685 BLOCK_INPUT;
7686
7687 r.left = left;
7688 r.top = disp_top;
7689 r.right = left + width;
7690 r.bottom = disp_top + disp_height;
7691
7692 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0, scrollBarProc,
7693 0L);
7694 SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch);
7695 SetControlReference (ch, (long) bar);
7696
7697 XSETWINDOW (bar->window, w);
7698 XSETINT (bar->top, top);
7699 XSETINT (bar->left, left);
7700 XSETINT (bar->width, width);
7701 XSETINT (bar->height, height);
7702 XSETINT (bar->start, 0);
7703 XSETINT (bar->end, 0);
7704 bar->dragging = Qnil;
7705
7706 /* Add bar to its frame's list of scroll bars. */
7707 bar->next = FRAME_SCROLL_BARS (f);
7708 bar->prev = Qnil;
7709 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
7710 if (!NILP (bar->next))
7711 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
7712
7713 UNBLOCK_INPUT;
7714 return bar;
7715}
7716
7717
7718/* Draw BAR's handle in the proper position.
7719
7720 If the handle is already drawn from START to END, don't bother
7721 redrawing it, unless REBUILD is non-zero; in that case, always
7722 redraw it. (REBUILD is handy for drawing the handle after expose
7723 events.)
7724
7725 Normally, we want to constrain the start and end of the handle to
7726 fit inside its rectangle, but if the user is dragging the scroll
7727 bar handle, we want to let them drag it down all the way, so that
7728 the bar's top is as far down as it goes; otherwise, there's no way
7729 to move to the very end of the buffer. */
7730
7731static void
7732x_scroll_bar_set_handle (bar, start, end, rebuild)
7733 struct scroll_bar *bar;
7734 int start, end;
7735 int rebuild;
7736{
7737 int dragging = ! NILP (bar->dragging);
7738 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
7739 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7740
7741 /* If the display is already accurate, do nothing. */
7742 if (! rebuild
7743 && start == XINT (bar->start)
7744 && end == XINT (bar->end))
7745 return;
7746
7747 BLOCK_INPUT;
7748
7749 {
7750 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
7751 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
7752 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
7753
7754 /* Make sure the values are reasonable, and try to preserve
7755 the distance between start and end. */
7756 {
7757 int length = end - start;
7758
7759 if (start < 0)
7760 start = 0;
7761 else if (start > top_range)
7762 start = top_range;
7763 end = start + length;
7764
7765 if (end < start)
7766 end = start;
7767 else if (end > top_range && ! dragging)
7768 end = top_range;
7769 }
7770
7771 /* Store the adjusted setting in the scroll bar. */
7772 XSETINT (bar->start, start);
7773 XSETINT (bar->end, end);
7774
7775 /* Clip the end position, just for display. */
7776 if (end > top_range)
7777 end = top_range;
7778
7779 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
7780 below top positions, to make sure the handle is always at least
7781 that many pixels tall. */
7782 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
7783
7784 SetControlMinimum (ch, 0);
7785 /* Don't inadvertently activate deactivated scroll bars */
7786 if (GetControlMaximum (ch) != -1)
7787 SetControlMaximum (ch,
7788 VERTICAL_SCROLL_BAR_TOP_RANGE (f,
7789 XINT (bar->height))
7790 - 1);
7791 SetControlValue (ch, start);
7792#if 0 /* MAC_TODO: detect Appearance Manager 1.1 before use. */
7793 SetControlViewSize (ch, end);
7794#endif
7795 }
7796
7797 UNBLOCK_INPUT;
7798}
7799
7800
7801/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
7802 nil. */
7803
7804static void
7805x_scroll_bar_remove (bar)
7806 struct scroll_bar *bar;
7807{
7808 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7809
7810 BLOCK_INPUT;
7811
7812 /* Destroy the Mac scroll bar control */
7813 DisposeControl (SCROLL_BAR_CONTROL_HANDLE (bar));
7814
7815 /* Disassociate this scroll bar from its window. */
7816 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
7817
7818 UNBLOCK_INPUT;
7819}
7820
7821
7822/* Set the handle of the vertical scroll bar for WINDOW to indicate
7823 that we are displaying PORTION characters out of a total of WHOLE
7824 characters, starting at POSITION. If WINDOW has no scroll bar,
7825 create one. */
7826
7827static void
7828XTset_vertical_scroll_bar (w, portion, whole, position)
7829 struct window *w;
7830 int portion, whole, position;
7831{
7832 struct frame *f = XFRAME (w->frame);
7833 struct scroll_bar *bar;
7834 int top, height, left, sb_left, width, sb_width, disp_top, disp_height;
7835 int window_x, window_y, window_width, window_height;
7836
7837 /* Get window dimensions. */
7838 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
7839 top = window_y;
7840 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
7841 height = window_height;
7842
7843 /* Compute the left edge of the scroll bar area. */
7844 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7845 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
7846 else
7847 left = XFASTINT (w->left);
7848 left *= CANON_X_UNIT (f);
7849 left += FRAME_INTERNAL_BORDER_WIDTH (f);
7850
7851 /* Compute the width of the scroll bar which might be less than
7852 the width of the area reserved for the scroll bar. */
7853 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
7854 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
7855 else
7856 sb_width = width;
7857
7858 /* Compute the left edge of the scroll bar. */
7859 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7860 sb_left = left + width - sb_width - (width - sb_width) / 2;
7861 else
7862 sb_left = left + (width - sb_width) / 2;
7863
7864 /* Adjustments according to Inside Macintosh to make it look nice */
7865 disp_top = top;
7866 disp_height = height;
7867 if (disp_top == 0)
7868 {
7869 disp_top = -1;
7870 disp_height++;
7871 }
7872 else if (disp_top == PIXEL_HEIGHT (f) - 16)
7873 {
7874 disp_top++;
7875 disp_height--;
7876 }
7877
7878 if (sb_left + sb_width == PIXEL_WIDTH (f))
7879 sb_left++;
7880
7881 /* Does the scroll bar exist yet? */
7882 if (NILP (w->vertical_scroll_bar))
7883 {
7884 BLOCK_INPUT;
7885 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
7886 left, top, width, height, 0);
7887 UNBLOCK_INPUT;
7888 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top,
7889 disp_height);
7890 XSETVECTOR (w->vertical_scroll_bar, bar);
7891 }
7892 else
7893 {
7894 /* It may just need to be moved and resized. */
7895 ControlHandle ch;
7896
7897 bar = XSCROLL_BAR (w->vertical_scroll_bar);
7898 ch = SCROLL_BAR_CONTROL_HANDLE (bar);
7899
7900 BLOCK_INPUT;
7901
7902 /* If already correctly positioned, do nothing. */
7903 if (XINT (bar->left) == sb_left
7904 && XINT (bar->top) == top
7905 && XINT (bar->width) == sb_width
7906 && XINT (bar->height) == height)
7907 Draw1Control (ch);
7908 else
7909 {
7910 if (sb_left + sb_width >= PIXEL_WIDTH (f))
7911 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
7912 sb_left - 1, top, 1, height, 0);
7913
7914 HideControl (ch);
7915 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top);
7916 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7917 disp_height);
7918 ShowControl (ch);
7919
7920 /* Remember new settings. */
7921 XSETINT (bar->left, sb_left);
7922 XSETINT (bar->top, top);
7923 XSETINT (bar->width, sb_width);
7924 XSETINT (bar->height, height);
7925 }
7926
7927 UNBLOCK_INPUT;
7928 }
7929
7930 /* Set the scroll bar's current state, unless we're currently being
7931 dragged. */
7932 if (NILP (bar->dragging))
7933 {
7934 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
7935
7936 if (whole == 0)
7937 x_scroll_bar_set_handle (bar, 0, top_range, 0);
7938 else
7939 {
7940 int start = ((double) position * top_range) / whole;
7941 int end = ((double) (position + portion) * top_range) / whole;
7942 x_scroll_bar_set_handle (bar, start, end, 0);
7943 }
7944 }
7945}
7946
7947
7948/* The following three hooks are used when we're doing a thorough
7949 redisplay of the frame. We don't explicitly know which scroll bars
7950 are going to be deleted, because keeping track of when windows go
7951 away is a real pain - "Can you say set-window-configuration, boys
7952 and girls?" Instead, we just assert at the beginning of redisplay
7953 that *all* scroll bars are to be removed, and then save a scroll bar
7954 from the fiery pit when we actually redisplay its window. */
7955
7956/* Arrange for all scroll bars on FRAME to be removed at the next call
7957 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
7958 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
7959
7960static void
7961XTcondemn_scroll_bars (frame)
7962 FRAME_PTR frame;
7963{
7964 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
7965 while (! NILP (FRAME_SCROLL_BARS (frame)))
7966 {
7967 Lisp_Object bar;
7968 bar = FRAME_SCROLL_BARS (frame);
7969 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
7970 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
7971 XSCROLL_BAR (bar)->prev = Qnil;
7972 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
7973 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
7974 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
7975 }
7976}
7977
7978/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
7979 Note that WINDOW isn't necessarily condemned at all. */
7980static void
7981XTredeem_scroll_bar (window)
7982 struct window *window;
7983{
7984 struct scroll_bar *bar;
7985
7986 /* We can't redeem this window's scroll bar if it doesn't have one. */
7987 if (NILP (window->vertical_scroll_bar))
7988 abort ();
7989
7990 bar = XSCROLL_BAR (window->vertical_scroll_bar);
7991
7992 /* Unlink it from the condemned list. */
7993 {
7994 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
7995
7996 if (NILP (bar->prev))
7997 {
7998 /* If the prev pointer is nil, it must be the first in one of
7999 the lists. */
8000 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
8001 /* It's not condemned. Everything's fine. */
8002 return;
8003 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8004 window->vertical_scroll_bar))
8005 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
8006 else
8007 /* If its prev pointer is nil, it must be at the front of
8008 one or the other! */
8009 abort ();
8010 }
8011 else
8012 XSCROLL_BAR (bar->prev)->next = bar->next;
8013
8014 if (! NILP (bar->next))
8015 XSCROLL_BAR (bar->next)->prev = bar->prev;
8016
8017 bar->next = FRAME_SCROLL_BARS (f);
8018 bar->prev = Qnil;
8019 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
8020 if (! NILP (bar->next))
8021 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
8022 }
8023}
8024
8025/* Remove all scroll bars on FRAME that haven't been saved since the
8026 last call to `*condemn_scroll_bars_hook'. */
8027
8028static void
8029XTjudge_scroll_bars (f)
8030 FRAME_PTR f;
8031{
8032 Lisp_Object bar, next;
8033
8034 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
8035
8036 /* Clear out the condemned list now so we won't try to process any
8037 more events on the hapless scroll bars. */
8038 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
8039
8040 for (; ! NILP (bar); bar = next)
8041 {
8042 struct scroll_bar *b = XSCROLL_BAR (bar);
8043
8044 x_scroll_bar_remove (b);
8045
8046 next = b->next;
8047 b->next = b->prev = Qnil;
8048 }
8049
8050 /* Now there should be no references to the condemned scroll bars,
8051 and they should get garbage-collected. */
8052}
8053
8054
8055static void
8056activate_scroll_bars (frame)
8057 FRAME_PTR frame;
8058{
8059 Lisp_Object bar;
8060 ControlHandle ch;
8061
8062 bar = FRAME_SCROLL_BARS (frame);
8063 while (! NILP (bar))
8064 {
8065 ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar));
8066 SetControlMaximum (ch,
8067 VERTICAL_SCROLL_BAR_TOP_RANGE (frame,
8068 XINT (XSCROLL_BAR (bar)
8069 ->height)) - 1);
8070
8071 bar = XSCROLL_BAR (bar)->next;
8072 }
8073}
8074
8075
8076static void
8077deactivate_scroll_bars (frame)
8078 FRAME_PTR frame;
8079{
8080 Lisp_Object bar;
8081 ControlHandle ch;
8082
8083 bar = FRAME_SCROLL_BARS (frame);
8084 while (! NILP (bar))
8085 {
8086 ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar));
8087 SetControlMaximum (ch, XINT (-1));
8088
8089 bar = XSCROLL_BAR (bar)->next;
8090 }
8091}
8092
8093/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8094 is set to something other than no_event, it is enqueued.
8095
8096 This may be called from a signal handler, so we have to ignore GC
8097 mark bits. */
8098
8099static void
8100x_scroll_bar_handle_click (bar, part_code, er, bufp)
8101 struct scroll_bar *bar;
8102 int part_code;
8103 EventRecord *er;
8104 struct input_event *bufp;
8105{
8106 if (! GC_WINDOWP (bar->window))
8107 abort ();
8108
8109 bufp->kind = scroll_bar_click;
8110 bufp->frame_or_window = bar->window;
8111 bufp->arg = Qnil;
8112
8113 bar->dragging = Qnil;
8114
8115 switch (part_code)
8116 {
8117 case kControlUpButtonPart:
8118 bufp->part = scroll_bar_up_arrow;
8119 break;
8120 case kControlDownButtonPart:
8121 bufp->part = scroll_bar_down_arrow;
8122 break;
8123 case kControlPageUpPart:
8124 bufp->part = scroll_bar_above_handle;
8125 break;
8126 case kControlPageDownPart:
8127 bufp->part = scroll_bar_below_handle;
8128 break;
8129 case kControlIndicatorPart:
8130 if (er->what == mouseDown)
8131 bar->dragging = make_number (0);
8132 XSETVECTOR (last_mouse_scroll_bar, bar);
8133 bufp->part = scroll_bar_handle;
8134 break;
8135 }
8136}
8137
8138
8139/* Handle some mouse motion while someone is dragging the scroll bar.
8140
8141 This may be called from a signal handler, so we have to ignore GC
8142 mark bits. */
8143
8144static void
8145x_scroll_bar_note_movement (bar, y_pos, t)
8146 struct scroll_bar *bar;
8147 int y_pos;
8148 Time t;
8149{
8150 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8151
8152 last_mouse_movement_time = t;
8153
8154 f->mouse_moved = 1;
8155 XSETVECTOR (last_mouse_scroll_bar, bar);
8156
8157 /* If we're dragging the bar, display it. */
8158 if (! GC_NILP (bar->dragging))
8159 {
8160 /* Where should the handle be now? */
8161 int new_start = y_pos - 24;
8162
8163 if (new_start != XINT (bar->start))
8164 {
8165 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
8166
8167 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
8168 }
8169 }
8170}
8171
8172
8173/* Return information to the user about the current position of the
8174 mouse on the scroll bar. */
8175
8176static void
8177x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8178 FRAME_PTR *fp;
8179 Lisp_Object *bar_window;
8180 enum scroll_bar_part *part;
8181 Lisp_Object *x, *y;
8182 unsigned long *time;
8183{
8184 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
8185 WindowPtr wp = FrontWindow ();
8186 Point mouse_pos;
8187 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
8188 int win_y, top_range;
8189
8190 SetPort (wp);
8191 GetMouse (&mouse_pos);
8192
8193 win_y = mouse_pos.v - XINT (bar->top);
8194 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
8195
8196 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8197
8198 win_y -= 24;
8199
8200 if (! NILP (bar->dragging))
8201 win_y -= XINT (bar->dragging);
8202
8203 if (win_y < 0)
8204 win_y = 0;
8205 if (win_y > top_range)
8206 win_y = top_range;
8207
8208 *fp = f;
8209 *bar_window = bar->window;
8210
8211 if (! NILP (bar->dragging))
8212 *part = scroll_bar_handle;
8213 else if (win_y < XINT (bar->start))
8214 *part = scroll_bar_above_handle;
8215 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8216 *part = scroll_bar_handle;
8217 else
8218 *part = scroll_bar_below_handle;
8219
8220 XSETINT (*x, win_y);
8221 XSETINT (*y, top_range);
8222
8223 f->mouse_moved = 0;
8224 last_mouse_scroll_bar = Qnil;
8225
8226 *time = last_mouse_movement_time;
8227}
8228
8229/***********************************************************************
8230 Text Cursor
8231 ***********************************************************************/
8232
8233/* Note if the text cursor of window W has been overwritten by a
8234 drawing operation that outputs N glyphs starting at HPOS in the
8235 line given by output_cursor.vpos. N < 0 means all the rest of the
8236 line after HPOS has been written. */
8237
8238static void
8239note_overwritten_text_cursor (w, hpos, n)
8240 struct window *w;
8241 int hpos, n;
8242{
8243 if (updated_area == TEXT_AREA
8244 && output_cursor.vpos == w->phys_cursor.vpos
8245 && hpos <= w->phys_cursor.hpos
8246 && (n < 0
8247 || hpos + n > w->phys_cursor.hpos))
8248 w->phys_cursor_on_p = 0;
8249}
8250
8251
8252/* Set clipping for output in glyph row ROW. W is the window in which
8253 we operate. GC is the graphics context to set clipping in.
8254 WHOLE_LINE_P non-zero means include the areas used for truncation
8255 mark display and alike in the clipping rectangle.
8256
8257 ROW may be a text row or, e.g., a mode line. Text rows must be
8258 clipped to the interior of the window dedicated to text display,
8259 mode lines must be clipped to the whole window. */
8260
8261static void
8262x_clip_to_row (w, row, gc, whole_line_p)
8263 struct window *w;
8264 struct glyph_row *row;
8265 GC gc;
8266 int whole_line_p;
8267{
8268 struct frame *f = XFRAME (WINDOW_FRAME (w));
8269 Rect clip_rect;
8270 int window_x, window_y, window_width, window_height;
8271
8272 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
8273
8274 clip_rect.left = WINDOW_TO_FRAME_PIXEL_X (w, 0);
8275 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
8276 clip_rect.top = max (clip_rect.top, window_y);
8277 clip_rect.right = clip_rect.left + window_width;
8278 clip_rect.bottom = clip_rect.top + row->visible_height;
8279
8280 /* If clipping to the whole line, including trunc marks, extend
8281 the rectangle to the left and increase its width. */
8282 if (whole_line_p)
8283 {
8284 clip_rect.left -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
8285 clip_rect.right += FRAME_X_FLAGS_AREA_WIDTH (f);
8286 }
8287
8288 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), &clip_rect);
8289}
8290
8291
8292/* Draw a hollow box cursor on window W in glyph row ROW. */
8293
8294static void
8295x_draw_hollow_cursor (w, row)
8296 struct window *w;
8297 struct glyph_row *row;
8298{
8299 struct frame *f = XFRAME (WINDOW_FRAME (w));
8300 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
8301 Display *dpy = FRAME_MAC_DISPLAY (f);
8302 int x, y, wd, h;
8303 XGCValues xgcv;
8304 struct glyph *cursor_glyph;
8305 GC gc;
8306
8307 /* Compute frame-relative coordinates from window-relative
8308 coordinates. */
8309 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8310 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
8311 + row->ascent - w->phys_cursor_ascent);
8312 h = row->height - 1;
8313
8314 /* Get the glyph the cursor is on. If we can't tell because
8315 the current matrix is invalid or such, give up. */
8316 cursor_glyph = get_phys_cursor_glyph (w);
8317 if (cursor_glyph == NULL)
8318 return;
8319
8320 /* Compute the width of the rectangle to draw. If on a stretch
8321 glyph, and `x-stretch-block-cursor' is nil, don't draw a
8322 rectangle as wide as the glyph, but use a canonical character
8323 width instead. */
8324 wd = cursor_glyph->pixel_width - 1;
8325 if (cursor_glyph->type == STRETCH_GLYPH
8326 && !x_stretch_cursor_p)
8327 wd = min (CANON_X_UNIT (f), wd);
8328
8329 /* The foreground of cursor_gc is typically the same as the normal
8330 background color, which can cause the cursor box to be invisible. */
8331 xgcv.foreground = f->output_data.mac->cursor_pixel;
8332 if (dpyinfo->scratch_cursor_gc)
8333 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
8334 else
8335 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f),
8336 GCForeground, &xgcv);
8337 gc = dpyinfo->scratch_cursor_gc;
8338
8339 /* Set clipping, draw the rectangle, and reset clipping again. */
8340 x_clip_to_row (w, row, gc, 0);
8341 mac_draw_rectangle (dpy, FRAME_MAC_WINDOW (f), gc, x, y, wd, h);
8342 mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f));
8343}
8344
8345
8346/* Draw a bar cursor on window W in glyph row ROW.
8347
8348 Implementation note: One would like to draw a bar cursor with an
8349 angle equal to the one given by the font property XA_ITALIC_ANGLE.
8350 Unfortunately, I didn't find a font yet that has this property set.
8351 --gerd. */
8352
8353static void
8354x_draw_bar_cursor (w, row, width)
8355 struct window *w;
8356 struct glyph_row *row;
8357 int width;
8358{
8359 /* If cursor hpos is out of bounds, don't draw garbage. This can
8360 happen in mini-buffer windows when switching between echo area
8361 glyphs and mini-buffer. */
8362 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
8363 {
8364 struct frame *f = XFRAME (w->frame);
8365 struct glyph *cursor_glyph;
8366 GC gc;
8367 int x;
8368 unsigned long mask;
8369 XGCValues xgcv;
8370 Display *dpy;
8371 Window window;
8372
8373 cursor_glyph = get_phys_cursor_glyph (w);
8374 if (cursor_glyph == NULL)
8375 return;
8376
8377 xgcv.background = f->output_data.mac->cursor_pixel;
8378 xgcv.foreground = f->output_data.mac->cursor_pixel;
8379 mask = GCForeground | GCBackground;
8380 dpy = FRAME_MAC_DISPLAY (f);
8381 window = FRAME_MAC_WINDOW (f);
8382 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
8383
8384 if (gc)
8385 XChangeGC (dpy, gc, mask, &xgcv);
8386 else
8387 {
8388 gc = XCreateGC (dpy, window, mask, &xgcv);
8389 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
8390 }
8391
8392 if (width < 0)
8393 width = f->output_data.mac->cursor_width;
8394
8395 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8396 x_clip_to_row (w, row, gc, 0);
8397 XFillRectangle (dpy, window, gc,
8398 x,
8399 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
8400 min (cursor_glyph->pixel_width, width),
8401 row->height);
8402 mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f));
8403 }
8404}
8405
8406
8407/* Clear the cursor of window W to background color, and mark the
8408 cursor as not shown. This is used when the text where the cursor
8409 is is about to be rewritten. */
8410
8411static void
8412x_clear_cursor (w)
8413 struct window *w;
8414{
8415 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
8416 x_update_window_cursor (w, 0);
8417}
8418
8419
8420/* Draw the cursor glyph of window W in glyph row ROW. See the
8421 comment of x_draw_glyphs for the meaning of HL. */
8422
8423static void
8424x_draw_phys_cursor_glyph (w, row, hl)
8425 struct window *w;
8426 struct glyph_row *row;
8427 enum draw_glyphs_face hl;
8428{
8429 /* If cursor hpos is out of bounds, don't draw garbage. This can
8430 happen in mini-buffer windows when switching between echo area
8431 glyphs and mini-buffer. */
8432 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
8433 {
8434 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
8435 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
8436 hl, 0, 0, 0);
8437
8438 /* When we erase the cursor, and ROW is overlapped by other
8439 rows, make sure that these overlapping parts of other rows
8440 are redrawn. */
8441 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
8442 {
8443 if (row > w->current_matrix->rows
8444 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
8445 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
8446
8447 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
8448 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
8449 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
8450 }
8451 }
8452}
8453
8454
8455/* Erase the image of a cursor of window W from the screen. */
8456
8457static void
8458x_erase_phys_cursor (w)
8459 struct window *w;
8460{
8461 struct frame *f = XFRAME (w->frame);
8462 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8463 int hpos = w->phys_cursor.hpos;
8464 int vpos = w->phys_cursor.vpos;
8465 int mouse_face_here_p = 0;
8466 struct glyph_matrix *active_glyphs = w->current_matrix;
8467 struct glyph_row *cursor_row;
8468 struct glyph *cursor_glyph;
8469 enum draw_glyphs_face hl;
8470
8471 /* No cursor displayed or row invalidated => nothing to do on the
8472 screen. */
8473 if (w->phys_cursor_type == NO_CURSOR)
8474 goto mark_cursor_off;
8475
8476 /* VPOS >= active_glyphs->nrows means that window has been resized.
8477 Don't bother to erase the cursor. */
8478 if (vpos >= active_glyphs->nrows)
8479 goto mark_cursor_off;
8480
8481 /* If row containing cursor is marked invalid, there is nothing we
8482 can do. */
8483 cursor_row = MATRIX_ROW (active_glyphs, vpos);
8484 if (!cursor_row->enabled_p)
8485 goto mark_cursor_off;
8486
8487 /* This can happen when the new row is shorter than the old one.
8488 In this case, either x_draw_glyphs or clear_end_of_line
8489 should have cleared the cursor. Note that we wouldn't be
8490 able to erase the cursor in this case because we don't have a
8491 cursor glyph at hand. */
8492 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
8493 goto mark_cursor_off;
8494
8495 /* If the cursor is in the mouse face area, redisplay that when
8496 we clear the cursor. */
8497 if (! NILP (dpyinfo->mouse_face_window)
8498 && w == XWINDOW (dpyinfo->mouse_face_window)
8499 && (vpos > dpyinfo->mouse_face_beg_row
8500 || (vpos == dpyinfo->mouse_face_beg_row
8501 && hpos >= dpyinfo->mouse_face_beg_col))
8502 && (vpos < dpyinfo->mouse_face_end_row
8503 || (vpos == dpyinfo->mouse_face_end_row
8504 && hpos < dpyinfo->mouse_face_end_col))
8505 /* Don't redraw the cursor's spot in mouse face if it is at the
8506 end of a line (on a newline). The cursor appears there, but
8507 mouse highlighting does not. */
8508 && cursor_row->used[TEXT_AREA] > hpos)
8509 mouse_face_here_p = 1;
8510
8511 /* Maybe clear the display under the cursor. */
8512 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
8513 {
8514 int x;
8515 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
8516
8517 cursor_glyph = get_phys_cursor_glyph (w);
8518 if (cursor_glyph == NULL)
8519 goto mark_cursor_off;
8520
8521 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
8522
8523 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
8524 x,
8525 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
8526 cursor_row->y)),
8527 cursor_glyph->pixel_width,
8528 cursor_row->visible_height,
8529 0);
8530 }
8531
8532 /* Erase the cursor by redrawing the character underneath it. */
8533 if (mouse_face_here_p)
8534 hl = DRAW_MOUSE_FACE;
8535 else if (cursor_row->inverse_p)
8536 hl = DRAW_INVERSE_VIDEO;
8537 else
8538 hl = DRAW_NORMAL_TEXT;
8539 x_draw_phys_cursor_glyph (w, cursor_row, hl);
8540
8541 mark_cursor_off:
8542 w->phys_cursor_on_p = 0;
8543 w->phys_cursor_type = NO_CURSOR;
8544}
8545
8546
8547/* Display or clear cursor of window W. If ON is zero, clear the
8548 cursor. If it is non-zero, display the cursor. If ON is nonzero,
8549 where to put the cursor is specified by HPOS, VPOS, X and Y. */
8550
8551void
8552x_display_and_set_cursor (w, on, hpos, vpos, x, y)
8553 struct window *w;
8554 int on, hpos, vpos, x, y;
8555{
8556 struct frame *f = XFRAME (w->frame);
8557 int new_cursor_type;
8558 int new_cursor_width;
8559 struct glyph_matrix *current_glyphs;
8560 struct glyph_row *glyph_row;
8561 struct glyph *glyph;
8562
8563 /* This is pointless on invisible frames, and dangerous on garbaged
8564 windows and frames; in the latter case, the frame or window may
8565 be in the midst of changing its size, and x and y may be off the
8566 window. */
8567 if (! FRAME_VISIBLE_P (f)
8568 || FRAME_GARBAGED_P (f)
8569 || vpos >= w->current_matrix->nrows
8570 || hpos >= w->current_matrix->matrix_w)
8571 return;
8572
8573 /* If cursor is off and we want it off, return quickly. */
8574 if (!on && !w->phys_cursor_on_p)
8575 return;
8576
8577 current_glyphs = w->current_matrix;
8578 glyph_row = MATRIX_ROW (current_glyphs, vpos);
8579 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
8580
8581 /* If cursor row is not enabled, we don't really know where to
8582 display the cursor. */
8583 if (!glyph_row->enabled_p)
8584 {
8585 w->phys_cursor_on_p = 0;
8586 return;
8587 }
8588
8589 xassert (interrupt_input_blocked);
8590
8591 /* Set new_cursor_type to the cursor we want to be displayed. In a
8592 mini-buffer window, we want the cursor only to appear if we are
8593 reading input from this window. For the selected window, we want
8594 the cursor type given by the frame parameter. If explicitly
8595 marked off, draw no cursor. In all other cases, we want a hollow
8596 box cursor. */
8597 new_cursor_width = -1;
8598 if (cursor_in_echo_area
8599 && FRAME_HAS_MINIBUF_P (f)
8600 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
8601 {
8602 if (w == XWINDOW (echo_area_window))
8603 new_cursor_type = FRAME_DESIRED_CURSOR (f);
8604 else
8605 new_cursor_type = HOLLOW_BOX_CURSOR;
8606 }
8607 else
8608 {
8609 if (w != XWINDOW (selected_window)
8610 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
8611 {
8612 extern int cursor_in_non_selected_windows;
8613
8614 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
8615 new_cursor_type = NO_CURSOR;
8616 else
8617 new_cursor_type = HOLLOW_BOX_CURSOR;
8618 }
8619 else if (w->cursor_off_p)
8620 new_cursor_type = NO_CURSOR;
8621 else
8622 {
8623 struct buffer *b = XBUFFER (w->buffer);
8624
8625 if (EQ (b->cursor_type, Qt))
8626 new_cursor_type = FRAME_DESIRED_CURSOR (f);
8627 else
8628 new_cursor_type = x_specified_cursor_type (b->cursor_type,
8629 &new_cursor_width);
8630 }
8631 }
8632
8633 /* If cursor is currently being shown and we don't want it to be or
8634 it is in the wrong place, or the cursor type is not what we want,
8635 erase it. */
8636 if (w->phys_cursor_on_p
8637 && (!on
8638 || w->phys_cursor.x != x
8639 || w->phys_cursor.y != y
8640 || new_cursor_type != w->phys_cursor_type))
8641 x_erase_phys_cursor (w);
8642
8643 /* If the cursor is now invisible and we want it to be visible,
8644 display it. */
8645 if (on && !w->phys_cursor_on_p)
8646 {
8647 w->phys_cursor_ascent = glyph_row->ascent;
8648 w->phys_cursor_height = glyph_row->height;
8649
8650 /* Set phys_cursor_.* before x_draw_.* is called because some
8651 of them may need the information. */
8652 w->phys_cursor.x = x;
8653 w->phys_cursor.y = glyph_row->y;
8654 w->phys_cursor.hpos = hpos;
8655 w->phys_cursor.vpos = vpos;
8656 w->phys_cursor_type = new_cursor_type;
8657 w->phys_cursor_on_p = 1;
8658
8659 switch (new_cursor_type)
8660 {
8661 case HOLLOW_BOX_CURSOR:
8662 x_draw_hollow_cursor (w, glyph_row);
8663 break;
8664
8665 case FILLED_BOX_CURSOR:
8666 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
8667 break;
8668
8669 case BAR_CURSOR:
8670 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
8671 break;
8672
8673 case NO_CURSOR:
8674 break;
8675
8676 default:
8677 abort ();
8678 }
8679
8680#ifdef HAVE_X_I18N
8681 if (w == XWINDOW (f->selected_window))
8682 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
8683 xic_set_preeditarea (w, x, y);
8684#endif
8685 }
8686
8687#ifndef XFlush
8688 if (updating_frame != f)
8689 XFlush (FRAME_X_DISPLAY (f));
8690#endif
8691}
8692
8693
8694/* Display the cursor on window W, or clear it. X and Y are window
8695 relative pixel coordinates. HPOS and VPOS are glyph matrix
8696 positions. If W is not the selected window, display a hollow
8697 cursor. ON non-zero means display the cursor at X, Y which
8698 correspond to HPOS, VPOS, otherwise it is cleared. */
8699
8700void
8701x_display_cursor (w, on, hpos, vpos, x, y)
8702 struct window *w;
8703 int on, hpos, vpos, x, y;
8704{
8705 BLOCK_INPUT;
8706 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
8707 UNBLOCK_INPUT;
8708}
8709
8710
8711/* Display the cursor on window W, or clear it, according to ON_P.
8712 Don't change the cursor's position. */
8713
8714void
8715x_update_cursor (f, on_p)
8716 struct frame *f;
8717{
8718 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
8719}
8720
8721
8722/* Call x_update_window_cursor with parameter ON_P on all leaf windows
8723 in the window tree rooted at W. */
8724
8725static void
8726x_update_cursor_in_window_tree (w, on_p)
8727 struct window *w;
8728 int on_p;
8729{
8730 while (w)
8731 {
8732 if (!NILP (w->hchild))
8733 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
8734 else if (!NILP (w->vchild))
8735 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
8736 else
8737 x_update_window_cursor (w, on_p);
8738
8739 w = NILP (w->next) ? 0 : XWINDOW (w->next);
8740 }
8741}
8742
8743
8744/* Switch the display of W's cursor on or off, according to the value
8745 of ON. */
8746
8747static void
8748x_update_window_cursor (w, on)
8749 struct window *w;
8750 int on;
8751{
8752 /* Don't update cursor in windows whose frame is in the process
8753 of being deleted. */
8754 if (w->current_matrix)
8755 {
8756 BLOCK_INPUT;
8757 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
8758 w->phys_cursor.x, w->phys_cursor.y);
8759 UNBLOCK_INPUT;
8760 }
8761}
8762
8763
8764#if 0 /* MAC_TODO: no icon and X error handling (?) */
8765/* Icons. */
8766
8767/* Refresh bitmap kitchen sink icon for frame F
8768 when we get an expose event for it. */
8769
8770void
8771refreshicon (f)
8772 struct frame *f;
8773{
8774 /* Normally, the window manager handles this function. */
8775}
8776
8777/* Make the x-window of frame F use the gnu icon bitmap. */
8778
8779int
8780x_bitmap_icon (f, file)
8781 struct frame *f;
8782 Lisp_Object file;
8783{
8784 int bitmap_id;
8785
8786 if (FRAME_X_WINDOW (f) == 0)
8787 return 1;
8788
8789 /* Free up our existing icon bitmap if any. */
8790 if (f->output_data.x->icon_bitmap > 0)
8791 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
8792 f->output_data.x->icon_bitmap = 0;
8793
8794 if (STRINGP (file))
8795 bitmap_id = x_create_bitmap_from_file (f, file);
8796 else
8797 {
8798 /* Create the GNU bitmap if necessary. */
8799 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
8800 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
8801 = x_create_bitmap_from_data (f, gnu_bits,
8802 gnu_width, gnu_height);
8803
8804 /* The first time we create the GNU bitmap,
8805 this increments the ref-count one extra time.
8806 As a result, the GNU bitmap is never freed.
8807 That way, we don't have to worry about allocating it again. */
8808 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
8809
8810 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
8811 }
8812
8813 x_wm_set_icon_pixmap (f, bitmap_id);
8814 f->output_data.x->icon_bitmap = bitmap_id;
8815
8816 return 0;
8817}
8818
8819
8820/* Make the x-window of frame F use a rectangle with text.
8821 Use ICON_NAME as the text. */
8822
8823int
8824x_text_icon (f, icon_name)
8825 struct frame *f;
8826 char *icon_name;
8827{
8828 if (FRAME_X_WINDOW (f) == 0)
8829 return 1;
8830
8831#ifdef HAVE_X11R4
8832 {
8833 XTextProperty text;
8834 text.value = (unsigned char *) icon_name;
8835 text.encoding = XA_STRING;
8836 text.format = 8;
8837 text.nitems = strlen (icon_name);
8838#ifdef USE_X_TOOLKIT
8839 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
8840 &text);
8841#else /* not USE_X_TOOLKIT */
8842 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
8843#endif /* not USE_X_TOOLKIT */
8844 }
8845#else /* not HAVE_X11R4 */
8846 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
8847#endif /* not HAVE_X11R4 */
8848
8849 if (f->output_data.x->icon_bitmap > 0)
8850 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
8851 f->output_data.x->icon_bitmap = 0;
8852 x_wm_set_icon_pixmap (f, 0);
8853
8854 return 0;
8855}
8856
8857#define X_ERROR_MESSAGE_SIZE 200
8858
8859/* If non-nil, this should be a string.
8860 It means catch X errors and store the error message in this string. */
8861
8862static Lisp_Object x_error_message_string;
8863
8864/* An X error handler which stores the error message in
8865 x_error_message_string. This is called from x_error_handler if
8866 x_catch_errors is in effect. */
8867
8868static void
8869x_error_catcher (display, error)
8870 Display *display;
8871 XErrorEvent *error;
8872{
8873 XGetErrorText (display, error->error_code,
8874 XSTRING (x_error_message_string)->data,
8875 X_ERROR_MESSAGE_SIZE);
8876}
8877
8878/* Begin trapping X errors for display DPY. Actually we trap X errors
8879 for all displays, but DPY should be the display you are actually
8880 operating on.
8881
8882 After calling this function, X protocol errors no longer cause
8883 Emacs to exit; instead, they are recorded in the string
8884 stored in x_error_message_string.
8885
8886 Calling x_check_errors signals an Emacs error if an X error has
8887 occurred since the last call to x_catch_errors or x_check_errors.
8888
8889 Calling x_uncatch_errors resumes the normal error handling. */
8890
8891void x_check_errors ();
8892static Lisp_Object x_catch_errors_unwind ();
8893
8894int
8895x_catch_errors (dpy)
8896 Display *dpy;
8897{
8898 int count = specpdl_ptr - specpdl;
8899
8900 /* Make sure any errors from previous requests have been dealt with. */
8901 XSync (dpy, False);
8902
8903 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
8904
8905 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
8906 XSTRING (x_error_message_string)->data[0] = 0;
8907
8908 return count;
8909}
8910
8911/* Unbind the binding that we made to check for X errors. */
8912
8913static Lisp_Object
8914x_catch_errors_unwind (old_val)
8915 Lisp_Object old_val;
8916{
8917 x_error_message_string = old_val;
8918 return Qnil;
8919}
8920
8921/* If any X protocol errors have arrived since the last call to
8922 x_catch_errors or x_check_errors, signal an Emacs error using
8923 sprintf (a buffer, FORMAT, the x error message text) as the text. */
8924
8925void
8926x_check_errors (dpy, format)
8927 Display *dpy;
8928 char *format;
8929{
8930 /* Make sure to catch any errors incurred so far. */
8931 XSync (dpy, False);
8932
8933 if (XSTRING (x_error_message_string)->data[0])
8934 error (format, XSTRING (x_error_message_string)->data);
8935}
8936
8937/* Nonzero if we had any X protocol errors
8938 since we did x_catch_errors on DPY. */
8939
8940int
8941x_had_errors_p (dpy)
8942 Display *dpy;
8943{
8944 /* Make sure to catch any errors incurred so far. */
8945 XSync (dpy, False);
8946
8947 return XSTRING (x_error_message_string)->data[0] != 0;
8948}
8949
8950/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
8951
8952void
8953x_clear_errors (dpy)
8954 Display *dpy;
8955{
8956 XSTRING (x_error_message_string)->data[0] = 0;
8957}
8958
8959/* Stop catching X protocol errors and let them make Emacs die.
8960 DPY should be the display that was passed to x_catch_errors.
8961 COUNT should be the value that was returned by
8962 the corresponding call to x_catch_errors. */
8963
8964void
8965x_uncatch_errors (dpy, count)
8966 Display *dpy;
8967 int count;
8968{
8969 unbind_to (count, Qnil);
8970}
8971
8972#if 0
8973static unsigned int x_wire_count;
8974x_trace_wire ()
8975{
8976 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
8977}
8978#endif /* ! 0 */
8979
8980
8981/* Handle SIGPIPE, which can happen when the connection to a server
8982 simply goes away. SIGPIPE is handled by x_connection_signal.
8983 Don't need to do anything, because the write which caused the
8984 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
8985 which will do the appropriate cleanup for us. */
8986
8987static SIGTYPE
8988x_connection_signal (signalnum) /* If we don't have an argument, */
8989 int signalnum; /* some compilers complain in signal calls. */
8990{
8991#ifdef USG
8992 /* USG systems forget handlers when they are used;
8993 must reestablish each time */
8994 signal (signalnum, x_connection_signal);
8995#endif /* USG */
8996}
8997
8998/* Handling X errors. */
8999
9000/* Handle the loss of connection to display DISPLAY. */
9001
9002static SIGTYPE
9003x_connection_closed (display, error_message)
9004 Display *display;
9005 char *error_message;
9006{
9007 struct x_display_info *dpyinfo = x_display_info_for_display (display);
9008 Lisp_Object frame, tail;
9009
9010 /* Indicate that this display is dead. */
9011
9012#if 0 /* Closing the display caused a bus error on OpenWindows. */
9013#ifdef USE_X_TOOLKIT
9014 XtCloseDisplay (display);
9015#endif
9016#endif
9017
9018 if (dpyinfo)
9019 dpyinfo->display = 0;
9020
9021 /* First delete frames whose mini-buffers are on frames
9022 that are on the dead display. */
9023 FOR_EACH_FRAME (tail, frame)
9024 {
9025 Lisp_Object minibuf_frame;
9026 minibuf_frame
9027 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
9028 if (FRAME_X_P (XFRAME (frame))
9029 && FRAME_X_P (XFRAME (minibuf_frame))
9030 && ! EQ (frame, minibuf_frame)
9031 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
9032 Fdelete_frame (frame, Qt);
9033 }
9034
9035 /* Now delete all remaining frames on the dead display.
9036 We are now sure none of these is used as the mini-buffer
9037 for another frame that we need to delete. */
9038 FOR_EACH_FRAME (tail, frame)
9039 if (FRAME_X_P (XFRAME (frame))
9040 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
9041 {
9042 /* Set this to t so that Fdelete_frame won't get confused
9043 trying to find a replacement. */
9044 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
9045 Fdelete_frame (frame, Qt);
9046 }
9047
9048 if (dpyinfo)
9049 x_delete_display (dpyinfo);
9050
9051 if (x_display_list == 0)
9052 {
9053 fprintf (stderr, "%s\n", error_message);
9054 shut_down_emacs (0, 0, Qnil);
9055 exit (70);
9056 }
9057
9058 /* Ordinary stack unwind doesn't deal with these. */
9059#ifdef SIGIO
9060 sigunblock (sigmask (SIGIO));
9061#endif
9062 sigunblock (sigmask (SIGALRM));
9063 TOTALLY_UNBLOCK_INPUT;
9064
9065 clear_waiting_for_input ();
9066 error ("%s", error_message);
9067}
9068
9069/* This is the usual handler for X protocol errors.
9070 It kills all frames on the display that we got the error for.
9071 If that was the only one, it prints an error message and kills Emacs. */
9072
9073static void
9074x_error_quitter (display, error)
9075 Display *display;
9076 XErrorEvent *error;
9077{
9078 char buf[256], buf1[356];
9079
9080 /* Note that there is no real way portable across R3/R4 to get the
9081 original error handler. */
9082
9083 XGetErrorText (display, error->error_code, buf, sizeof (buf));
9084 sprintf (buf1, "X protocol error: %s on protocol request %d",
9085 buf, error->request_code);
9086 x_connection_closed (display, buf1);
9087}
9088
9089/* This is the first-level handler for X protocol errors.
9090 It calls x_error_quitter or x_error_catcher. */
9091
9092static int
9093x_error_handler (display, error)
9094 Display *display;
9095 XErrorEvent *error;
9096{
9097 if (! NILP (x_error_message_string))
9098 x_error_catcher (display, error);
9099 else
9100 x_error_quitter (display, error);
9101 return 0;
9102}
9103
9104/* This is the handler for X IO errors, always.
9105 It kills all frames on the display that we lost touch with.
9106 If that was the only one, it prints an error message and kills Emacs. */
9107
9108static int
9109x_io_error_quitter (display)
9110 Display *display;
9111{
9112 char buf[256];
9113
9114 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
9115 x_connection_closed (display, buf);
9116 return 0;
9117}
9118#endif
9119
9120/* Changing the font of the frame. */
9121
9122/* Give frame F the font named FONTNAME as its default font, and
9123 return the full name of that font. FONTNAME may be a wildcard
9124 pattern; in that case, we choose some font that fits the pattern.
9125 The return value shows which font we chose. */
9126
9127Lisp_Object
9128x_new_font (f, fontname)
9129 struct frame *f;
9130 register char *fontname;
9131{
9132 struct font_info *fontp
9133 = FS_LOAD_FONT (f, 0, fontname, -1);
9134
9135 if (!fontp)
9136 return Qnil;
9137
9138 f->output_data.mac->font = (XFontStruct *) (fontp->font);
9139 f->output_data.mac->baseline_offset = fontp->baseline_offset;
9140 f->output_data.mac->fontset = -1;
9141
9142 /* Compute the scroll bar width in character columns. */
9143 if (f->scroll_bar_pixel_width > 0)
9144 {
9145 int wid = FONT_WIDTH (f->output_data.mac->font);
9146 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
9147 }
9148 else
9149 {
9150 int wid = FONT_WIDTH (f->output_data.mac->font);
9151 f->scroll_bar_cols = (14 + wid - 1) / wid;
9152 }
9153
9154 /* Now make the frame display the given font. */
9155 if (FRAME_MAC_WINDOW (f) != 0)
9156 {
9157 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc,
9158 f->output_data.mac->font);
9159 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc,
9160 f->output_data.mac->font);
9161 XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc,
9162 f->output_data.mac->font);
9163
9164 frame_update_line_height (f);
9165 x_set_window_size (f, 0, f->width, f->height);
9166 }
9167 else
9168 /* If we are setting a new frame's font for the first time, there
9169 are no faces yet, so this font's height is the line height. */
9170 f->output_data.mac->line_height = FONT_HEIGHT (f->output_data.mac->font);
9171
9172 return build_string (fontp->full_name);
9173}
9174
9175/* Give frame F the fontset named FONTSETNAME as its default font, and
9176 return the full name of that fontset. FONTSETNAME may be a
9177 wildcard pattern; in that case, we choose some fontset that fits
9178 the pattern. The return value shows which fontset we chose. */
9179
9180Lisp_Object
9181x_new_fontset (f, fontsetname)
9182 struct frame *f;
9183 char *fontsetname;
9184{
9185 int fontset = fs_query_fontset (build_string (fontsetname), 0);
9186 Lisp_Object result;
9187
9188 if (fontset < 0)
9189 return Qnil;
9190
9191 if (f->output_data.mac->fontset == fontset)
9192 /* This fontset is already set in frame F. There's nothing more
9193 to do. */
9194 return fontset_name (fontset);
9195
9196 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
9197
9198 if (!STRINGP (result))
9199 /* Can't load ASCII font. */
9200 return Qnil;
9201
9202 /* Since x_new_font doesn't update any fontset information, do it
9203 now. */
9204 f->output_data.mac->fontset = fontset;
9205
9206#ifdef HAVE_X_I18N
9207 if (FRAME_XIC (f)
9208 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
9209 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
9210#endif
9211
9212 return build_string (fontsetname);
9213}
9214
9215#if 0 /* MAC_TODO: inline input methods for Mac */
9216
9217/***********************************************************************
9218 X Input Methods
9219 ***********************************************************************/
9220
9221#ifdef HAVE_X_I18N
9222
9223#ifdef HAVE_X11R6
9224
9225/* XIM destroy callback function, which is called whenever the
9226 connection to input method XIM dies. CLIENT_DATA contains a
9227 pointer to the x_display_info structure corresponding to XIM. */
9228
9229static void
9230xim_destroy_callback (xim, client_data, call_data)
9231 XIM xim;
9232 XPointer client_data;
9233 XPointer call_data;
9234{
9235 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
9236 Lisp_Object frame, tail;
9237
9238 BLOCK_INPUT;
9239
9240 /* No need to call XDestroyIC.. */
9241 FOR_EACH_FRAME (tail, frame)
9242 {
9243 struct frame *f = XFRAME (frame);
9244 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
9245 {
9246 FRAME_XIC (f) = NULL;
9247 if (FRAME_XIC_FONTSET (f))
9248 {
9249 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
9250 FRAME_XIC_FONTSET (f) = NULL;
9251 }
9252 }
9253 }
9254
9255 /* No need to call XCloseIM. */
9256 dpyinfo->xim = NULL;
9257 XFree (dpyinfo->xim_styles);
9258 UNBLOCK_INPUT;
9259}
9260
9261#endif /* HAVE_X11R6 */
9262
9263/* Open the connection to the XIM server on display DPYINFO.
9264 RESOURCE_NAME is the resource name Emacs uses. */
9265
9266static void
9267xim_open_dpy (dpyinfo, resource_name)
9268 struct x_display_info *dpyinfo;
9269 char *resource_name;
9270{
9271#ifdef USE_XIM
9272 XIM xim;
9273
9274 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
9275 dpyinfo->xim = xim;
9276
9277 if (xim)
9278 {
9279#ifdef HAVE_X11R6
9280 XIMCallback destroy;
9281#endif
9282
9283 /* Get supported styles and XIM values. */
9284 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
9285
9286#ifdef HAVE_X11R6
9287 destroy.callback = xim_destroy_callback;
9288 destroy.client_data = (XPointer)dpyinfo;
9289 /* This isn't prptotyped in OSF 5.0. */
9290 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
9291#endif
9292 }
9293
9294#else /* not USE_XIM */
9295 dpyinfo->xim = NULL;
9296#endif /* not USE_XIM */
9297}
9298
9299
9300#ifdef HAVE_X11R6_XIM
9301
9302struct xim_inst_t
9303{
9304 struct x_display_info *dpyinfo;
9305 char *resource_name;
9306};
9307
9308/* XIM instantiate callback function, which is called whenever an XIM
9309 server is available. DISPLAY is teh display of the XIM.
9310 CLIENT_DATA contains a pointer to an xim_inst_t structure created
9311 when the callback was registered. */
9312
9313static void
9314xim_instantiate_callback (display, client_data, call_data)
9315 Display *display;
9316 XPointer client_data;
9317 XPointer call_data;
9318{
9319 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
9320 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
9321
9322 /* We don't support multiple XIM connections. */
9323 if (dpyinfo->xim)
9324 return;
9325
9326 xim_open_dpy (dpyinfo, xim_inst->resource_name);
9327
9328 /* Create XIC for the existing frames on the same display, as long
9329 as they have no XIC. */
9330 if (dpyinfo->xim && dpyinfo->reference_count > 0)
9331 {
9332 Lisp_Object tail, frame;
9333
9334 BLOCK_INPUT;
9335 FOR_EACH_FRAME (tail, frame)
9336 {
9337 struct frame *f = XFRAME (frame);
9338
9339 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
9340 if (FRAME_XIC (f) == NULL)
9341 {
9342 create_frame_xic (f);
9343 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
9344 xic_set_statusarea (f);
9345 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
9346 {
9347 struct window *w = XWINDOW (f->selected_window);
9348 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
9349 }
9350 }
9351 }
9352
9353 UNBLOCK_INPUT;
9354 }
9355}
9356
9357#endif /* HAVE_X11R6_XIM */
9358
9359
9360/* Open a connection to the XIM server on display DPYINFO.
9361 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
9362 connection only at the first time. On X11R6, open the connection
9363 in the XIM instantiate callback function. */
9364
9365static void
9366xim_initialize (dpyinfo, resource_name)
9367 struct x_display_info *dpyinfo;
9368 char *resource_name;
9369{
9370#ifdef USE_XIM
9371#ifdef HAVE_X11R6_XIM
9372 struct xim_inst_t *xim_inst;
9373 int len;
9374
9375 dpyinfo->xim = NULL;
9376 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
9377 xim_inst->dpyinfo = dpyinfo;
9378 len = strlen (resource_name);
9379 xim_inst->resource_name = (char *) xmalloc (len + 1);
9380 bcopy (resource_name, xim_inst->resource_name, len + 1);
9381 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
9382 resource_name, EMACS_CLASS,
9383 xim_instantiate_callback,
9384 /* Fixme: This is XPointer in
9385 XFree86 but (XPointer *) on
9386 Tru64, at least. */
9387 (XPointer) xim_inst);
9388#else /* not HAVE_X11R6_XIM */
9389 dpyinfo->xim = NULL;
9390 xim_open_dpy (dpyinfo, resource_name);
9391#endif /* not HAVE_X11R6_XIM */
9392
9393#else /* not USE_XIM */
9394 dpyinfo->xim = NULL;
9395#endif /* not USE_XIM */
9396}
9397
9398
9399/* Close the connection to the XIM server on display DPYINFO. */
9400
9401static void
9402xim_close_dpy (dpyinfo)
9403 struct x_display_info *dpyinfo;
9404{
9405#ifdef USE_XIM
9406#ifdef HAVE_X11R6_XIM
9407 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
9408 NULL, EMACS_CLASS,
9409 xim_instantiate_callback, NULL);
9410#endif /* not HAVE_X11R6_XIM */
9411 XCloseIM (dpyinfo->xim);
9412 dpyinfo->xim = NULL;
9413 XFree (dpyinfo->xim_styles);
9414#endif /* USE_XIM */
9415}
9416
9417#endif /* not HAVE_X11R6_XIM */
9418
9419#endif
9420
9421/* Calculate the absolute position in frame F
9422 from its current recorded position values and gravity. */
9423
9424static void
9425x_calc_absolute_position (f)
9426 struct frame *f;
9427{
9428 Point pt;
9429 int flags = f->output_data.mac->size_hint_flags;
9430
9431 pt.h = pt.v = 0;
9432
9433 /* Find the position of the outside upper-left corner of
9434 the inner window, with respect to the outer window. */
9435 if (f->output_data.mac->parent_desc != FRAME_MAC_DISPLAY_INFO (f)->root_window)
9436 {
9437 GrafPtr savePort;
9438 GetPort (&savePort);
9439 SetPort (FRAME_MAC_WINDOW (f));
9440 SetPt(&pt, FRAME_MAC_WINDOW (f)->portRect.left, FRAME_MAC_WINDOW (f)->portRect.top);
9441 LocalToGlobal (&pt);
9442 SetPort (savePort);
9443 }
9444
9445 /* Treat negative positions as relative to the leftmost bottommost
9446 position that fits on the screen. */
9447 if (flags & XNegative)
9448 f->output_data.mac->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width
9449 - 2 * f->output_data.mac->border_width - pt.h
9450 - PIXEL_WIDTH (f)
9451 + f->output_data.mac->left_pos);
9452 /* NTEMACS_TODO: Subtract menubar height? */
9453 if (flags & YNegative)
9454 f->output_data.mac->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height
9455 - 2 * f->output_data.mac->border_width - pt.v
9456 - PIXEL_HEIGHT (f)
9457 + f->output_data.mac->top_pos);
9458 /* The left_pos and top_pos
9459 are now relative to the top and left screen edges,
9460 so the flags should correspond. */
9461 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
9462}
9463
9464/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
9465 to really change the position, and 0 when calling from
9466 x_make_frame_visible (in that case, XOFF and YOFF are the current
9467 position values). It is -1 when calling from x_set_frame_parameters,
9468 which means, do adjust for borders but don't change the gravity. */
9469
9470void
9471x_set_offset (f, xoff, yoff, change_gravity)
9472 struct frame *f;
9473 register int xoff, yoff;
9474 int change_gravity;
9475{
9476 if (change_gravity > 0)
9477 {
9478 f->output_data.mac->top_pos = yoff;
9479 f->output_data.mac->left_pos = xoff;
9480 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
9481 if (xoff < 0)
9482 f->output_data.mac->size_hint_flags |= XNegative;
9483 if (yoff < 0)
9484 f->output_data.mac->size_hint_flags |= YNegative;
9485 f->output_data.mac->win_gravity = NorthWestGravity;
9486 }
9487 x_calc_absolute_position (f);
9488
9489 BLOCK_INPUT;
9490 x_wm_set_size_hint (f, (long) 0, 0);
9491
9492 MoveWindow (f->output_data.mac->mWP, xoff + 6, yoff + 42, false);
9493
9494 UNBLOCK_INPUT;
9495}
9496
9497/* Call this to change the size of frame F's x-window.
9498 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
9499 for this size change and subsequent size changes.
9500 Otherwise we leave the window gravity unchanged. */
9501
9502void
9503x_set_window_size (f, change_gravity, cols, rows)
9504 struct frame *f;
9505 int change_gravity;
9506 int cols, rows;
9507{
9508 int pixelwidth, pixelheight;
9509
9510 check_frame_size (f, &rows, &cols);
9511 f->output_data.mac->vertical_scroll_bar_extra
9512 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
9513 ? 0
9514 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
9515 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
9516 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
9517 f->output_data.mac->flags_areas_extra
9518 = FRAME_FLAGS_AREA_WIDTH (f);
9519 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
9520 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
9521
9522 f->output_data.mac->win_gravity = NorthWestGravity;
9523 x_wm_set_size_hint (f, (long) 0, 0);
9524
9525 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0);
9526
9527 /* Now, strictly speaking, we can't be sure that this is accurate,
9528 but the window manager will get around to dealing with the size
9529 change request eventually, and we'll hear how it went when the
9530 ConfigureNotify event gets here.
9531
9532 We could just not bother storing any of this information here,
9533 and let the ConfigureNotify event set everything up, but that
9534 might be kind of confusing to the Lisp code, since size changes
9535 wouldn't be reported in the frame parameters until some random
9536 point in the future when the ConfigureNotify event arrives.
9537
9538 We pass 1 for DELAY since we can't run Lisp code inside of
9539 a BLOCK_INPUT. */
9540 change_frame_size (f, rows, cols, 0, 1, 0);
9541 PIXEL_WIDTH (f) = pixelwidth;
9542 PIXEL_HEIGHT (f) = pixelheight;
9543
9544 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
9545 receive in the ConfigureNotify event; if we get what we asked
9546 for, then the event won't cause the screen to become garbaged, so
9547 we have to make sure to do it here. */
9548 SET_FRAME_GARBAGED (f);
9549
9550 XFlush (FRAME_X_DISPLAY (f));
9551
9552 /* If cursor was outside the new size, mark it as off. */
9553 mark_window_cursors_off (XWINDOW (f->root_window));
9554
9555 /* Clear out any recollection of where the mouse highlighting was,
9556 since it might be in a place that's outside the new frame size.
9557 Actually checking whether it is outside is a pain in the neck,
9558 so don't try--just let the highlighting be done afresh with new size. */
9559 cancel_mouse_face (f);
9560}
9561
9562/* Mouse warping. */
9563
9564void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
9565
9566void
9567x_set_mouse_position (f, x, y)
9568 struct frame *f;
9569 int x, y;
9570{
9571 int pix_x, pix_y;
9572
9573 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.mac->font) / 2;
9574 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.mac->line_height / 2;
9575
9576 if (pix_x < 0) pix_x = 0;
9577 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
9578
9579 if (pix_y < 0) pix_y = 0;
9580 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
9581
9582 x_set_mouse_pixel_position (f, pix_x, pix_y);
9583}
9584
9585/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
9586
9587void
9588x_set_mouse_pixel_position (f, pix_x, pix_y)
9589 struct frame *f;
9590 int pix_x, pix_y;
9591{
9592#if 0 /* MAC_TODO: CursorDeviceMoveTo is non-Carbon */
9593 BLOCK_INPUT;
9594
9595 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
9596 0, 0, 0, 0, pix_x, pix_y);
9597 UNBLOCK_INPUT;
9598#endif
9599}
9600
9601/* focus shifting, raising and lowering. */
9602
9603static void
9604x_focus_on_frame (f)
9605 struct frame *f;
9606{
9607#if 0 /* This proves to be unpleasant. */
9608 x_raise_frame (f);
9609#endif
9610#if 0
9611 /* I don't think that the ICCCM allows programs to do things like this
9612 without the interaction of the window manager. Whatever you end up
9613 doing with this code, do it to x_unfocus_frame too. */
9614 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9615 RevertToPointerRoot, CurrentTime);
9616#endif /* ! 0 */
9617}
9618
9619static void
9620x_unfocus_frame (f)
9621 struct frame *f;
9622{
9623#if 0
9624 /* Look at the remarks in x_focus_on_frame. */
9625 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
9626 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
9627 RevertToPointerRoot, CurrentTime);
9628#endif /* ! 0 */
9629}
9630
9631/* Raise frame F. */
9632
9633void
9634x_raise_frame (f)
9635 struct frame *f;
9636{
9637 if (f->async_visible)
9638 SelectWindow (FRAME_MAC_WINDOW (f));
9639}
9640
9641/* Lower frame F. */
9642
9643void
9644x_lower_frame (f)
9645 struct frame *f;
9646{
9647 if (f->async_visible)
9648 SendBehind (FRAME_MAC_WINDOW (f), nil);
9649}
9650
9651void
9652XTframe_raise_lower (f, raise_flag)
9653 FRAME_PTR f;
9654 int raise_flag;
9655{
9656 if (raise_flag)
9657 x_raise_frame (f);
9658 else
9659 x_lower_frame (f);
9660}
9661
9662/* Change of visibility. */
9663
9664/* This tries to wait until the frame is really visible.
9665 However, if the window manager asks the user where to position
9666 the frame, this will return before the user finishes doing that.
9667 The frame will not actually be visible at that time,
9668 but it will become visible later when the window manager
9669 finishes with it. */
9670
9671void
9672x_make_frame_visible (f)
9673 struct frame *f;
9674{
9675 Lisp_Object type;
9676 int original_top, original_left;
9677
9678 BLOCK_INPUT;
9679
9680 if (! FRAME_VISIBLE_P (f))
9681 {
9682 /* We test FRAME_GARBAGED_P here to make sure we don't
9683 call x_set_offset a second time
9684 if we get to x_make_frame_visible a second time
9685 before the window gets really visible. */
9686 if (! FRAME_ICONIFIED_P (f)
9687 && ! f->output_data.mac->asked_for_visible)
9688 x_set_offset (f, f->output_data.mac->left_pos,
9689 f->output_data.mac->top_pos, 0);
9690
9691 f->output_data.mac->asked_for_visible = 1;
9692
9693 ShowWindow (FRAME_MAC_WINDOW (f));
9694 }
9695
9696 XFlush (FRAME_MAC_DISPLAY (f));
9697
9698 /* Synchronize to ensure Emacs knows the frame is visible
9699 before we do anything else. We do this loop with input not blocked
9700 so that incoming events are handled. */
9701 {
9702 Lisp_Object frame;
9703 int count;
9704
9705 /* This must come after we set COUNT. */
9706 UNBLOCK_INPUT;
9707
9708 XSETFRAME (frame, f);
9709
9710 /* Wait until the frame is visible. Process X events until a
9711 MapNotify event has been seen, or until we think we won't get a
9712 MapNotify at all.. */
9713 for (count = input_signal_count + 10;
9714 input_signal_count < count && !FRAME_VISIBLE_P (f);)
9715 {
9716 /* Force processing of queued events. */
9717 x_sync (f);
9718
9719 /* Machines that do polling rather than SIGIO have been
9720 observed to go into a busy-wait here. So we'll fake an
9721 alarm signal to let the handler know that there's something
9722 to be read. We used to raise a real alarm, but it seems
9723 that the handler isn't always enabled here. This is
9724 probably a bug. */
9725 if (input_polling_used ())
9726 {
9727 /* It could be confusing if a real alarm arrives while
9728 processing the fake one. Turn it off and let the
9729 handler reset it. */
9730 extern void poll_for_input_1 P_ ((void));
9731 int old_poll_suppress_count = poll_suppress_count;
9732 poll_suppress_count = 1;
9733 poll_for_input_1 ();
9734 poll_suppress_count = old_poll_suppress_count;
9735 }
9736
9737 /* See if a MapNotify event has been processed. */
9738 FRAME_SAMPLE_VISIBILITY (f);
9739 }
9740 }
9741}
9742
9743/* Change from mapped state to withdrawn state. */
9744
9745/* Make the frame visible (mapped and not iconified). */
9746
9747void
9748x_make_frame_invisible (f)
9749 struct frame *f;
9750{
9751 /* Don't keep the highlight on an invisible frame. */
9752 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f)
9753 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0;
9754
9755 BLOCK_INPUT;
9756
9757 HideWindow (FRAME_MAC_WINDOW (f));
9758
9759 /* We can't distinguish this from iconification
9760 just by the event that we get from the server.
9761 So we can't win using the usual strategy of letting
9762 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
9763 and synchronize with the server to make sure we agree. */
9764 f->visible = 0;
9765 FRAME_ICONIFIED_P (f) = 0;
9766 f->async_visible = 0;
9767 f->async_iconified = 0;
9768
9769 UNBLOCK_INPUT;
9770}
9771
9772/* Change window state from mapped to iconified. */
9773
9774void
9775x_iconify_frame (f)
9776 struct frame *f;
9777{
9778#if 0 /* MAC_TODO: really no iconify on Mac */
9779 int result;
9780 Lisp_Object type;
9781
9782 /* Don't keep the highlight on an invisible frame. */
9783 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
9784 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9785
9786 if (f->async_iconified)
9787 return;
9788
9789 BLOCK_INPUT;
9790
9791 FRAME_SAMPLE_VISIBILITY (f);
9792
9793 type = x_icon_type (f);
9794 if (!NILP (type))
9795 x_bitmap_icon (f, type);
9796
9797#ifdef USE_X_TOOLKIT
9798
9799 if (! FRAME_VISIBLE_P (f))
9800 {
9801 if (! EQ (Vx_no_window_manager, Qt))
9802 x_wm_set_window_state (f, IconicState);
9803 /* This was XtPopup, but that did nothing for an iconified frame. */
9804 XtMapWidget (f->output_data.x->widget);
9805 /* The server won't give us any event to indicate
9806 that an invisible frame was changed to an icon,
9807 so we have to record it here. */
9808 f->iconified = 1;
9809 f->visible = 1;
9810 f->async_iconified = 1;
9811 f->async_visible = 0;
9812 UNBLOCK_INPUT;
9813 return;
9814 }
9815
9816 result = XIconifyWindow (FRAME_X_DISPLAY (f),
9817 XtWindow (f->output_data.x->widget),
9818 DefaultScreen (FRAME_X_DISPLAY (f)));
9819 UNBLOCK_INPUT;
9820
9821 if (!result)
9822 error ("Can't notify window manager of iconification");
9823
9824 f->async_iconified = 1;
9825 f->async_visible = 0;
9826
9827
9828 BLOCK_INPUT;
9829 XFlush (FRAME_X_DISPLAY (f));
9830 UNBLOCK_INPUT;
9831#else /* not USE_X_TOOLKIT */
9832
9833 /* Make sure the X server knows where the window should be positioned,
9834 in case the user deiconifies with the window manager. */
9835 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
9836 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
9837
9838 /* Since we don't know which revision of X we're running, we'll use both
9839 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
9840
9841 /* X11R4: send a ClientMessage to the window manager using the
9842 WM_CHANGE_STATE type. */
9843 {
9844 XEvent message;
9845
9846 message.xclient.window = FRAME_X_WINDOW (f);
9847 message.xclient.type = ClientMessage;
9848 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
9849 message.xclient.format = 32;
9850 message.xclient.data.l[0] = IconicState;
9851
9852 if (! XSendEvent (FRAME_X_DISPLAY (f),
9853 DefaultRootWindow (FRAME_X_DISPLAY (f)),
9854 False,
9855 SubstructureRedirectMask | SubstructureNotifyMask,
9856 &message))
9857 {
9858 UNBLOCK_INPUT_RESIGNAL;
9859 error ("Can't notify window manager of iconification");
9860 }
9861 }
9862
9863 /* X11R3: set the initial_state field of the window manager hints to
9864 IconicState. */
9865 x_wm_set_window_state (f, IconicState);
9866
9867 if (!FRAME_VISIBLE_P (f))
9868 {
9869 /* If the frame was withdrawn, before, we must map it. */
9870 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
9871 }
9872
9873 f->async_iconified = 1;
9874 f->async_visible = 0;
9875
9876 XFlush (FRAME_X_DISPLAY (f));
9877 UNBLOCK_INPUT;
9878#endif /* not USE_X_TOOLKIT */
9879#endif
9880}
9881
9882/* Destroy the X window of frame F. */
9883
9884void
9885x_destroy_window (f)
9886 struct frame *f;
9887{
9888 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
9889
9890 BLOCK_INPUT;
9891
9892 DisposeWindow (FRAME_MAC_WINDOW (f));
9893
9894 free_frame_menubar (f);
9895 free_frame_faces (f);
9896
9897 xfree (f->output_data.mac);
9898 f->output_data.mac = 0;
9899 if (f == dpyinfo->x_focus_frame)
9900 dpyinfo->x_focus_frame = 0;
9901 if (f == dpyinfo->x_focus_event_frame)
9902 dpyinfo->x_focus_event_frame = 0;
9903 if (f == dpyinfo->x_highlight_frame)
9904 dpyinfo->x_highlight_frame = 0;
9905
9906 dpyinfo->reference_count--;
9907
9908 if (f == dpyinfo->mouse_face_mouse_frame)
9909 {
9910 dpyinfo->mouse_face_beg_row
9911 = dpyinfo->mouse_face_beg_col = -1;
9912 dpyinfo->mouse_face_end_row
9913 = dpyinfo->mouse_face_end_col = -1;
9914 dpyinfo->mouse_face_window = Qnil;
9915 dpyinfo->mouse_face_deferred_gc = 0;
9916 dpyinfo->mouse_face_mouse_frame = 0;
9917 }
9918
9919 UNBLOCK_INPUT;
9920}
9921
9922/* Setting window manager hints. */
9923
9924/* Set the normal size hints for the window manager, for frame F.
9925 FLAGS is the flags word to use--or 0 meaning preserve the flags
9926 that the window now has.
9927 If USER_POSITION is nonzero, we set the USPosition
9928 flag (this is useful when FLAGS is 0). */
9929
9930void
9931x_wm_set_size_hint (f, flags, user_position)
9932 struct frame *f;
9933 long flags;
9934 int user_position;
9935{
9936#if 0 /* MAC_TODO: connect this to the Appearance Manager */
9937 XSizeHints size_hints;
9938
9939#ifdef USE_X_TOOLKIT
9940 Arg al[2];
9941 int ac = 0;
9942 Dimension widget_width, widget_height;
9943 Window window = XtWindow (f->output_data.x->widget);
9944#else /* not USE_X_TOOLKIT */
9945 Window window = FRAME_X_WINDOW (f);
9946#endif /* not USE_X_TOOLKIT */
9947
9948 /* Setting PMaxSize caused various problems. */
9949 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
9950
9951 size_hints.x = f->output_data.x->left_pos;
9952 size_hints.y = f->output_data.x->top_pos;
9953
9954#ifdef USE_X_TOOLKIT
9955 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
9956 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
9957 XtGetValues (f->output_data.x->widget, al, ac);
9958 size_hints.height = widget_height;
9959 size_hints.width = widget_width;
9960#else /* not USE_X_TOOLKIT */
9961 size_hints.height = PIXEL_HEIGHT (f);
9962 size_hints.width = PIXEL_WIDTH (f);
9963#endif /* not USE_X_TOOLKIT */
9964
9965 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
9966 size_hints.height_inc = f->output_data.x->line_height;
9967 size_hints.max_width
9968 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
9969 size_hints.max_height
9970 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
9971
9972 /* Calculate the base and minimum sizes.
9973
9974 (When we use the X toolkit, we don't do it here.
9975 Instead we copy the values that the widgets are using, below.) */
9976#ifndef USE_X_TOOLKIT
9977 {
9978 int base_width, base_height;
9979 int min_rows = 0, min_cols = 0;
9980
9981 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
9982 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
9983
9984 check_frame_size (f, &min_rows, &min_cols);
9985
9986 /* The window manager uses the base width hints to calculate the
9987 current number of rows and columns in the frame while
9988 resizing; min_width and min_height aren't useful for this
9989 purpose, since they might not give the dimensions for a
9990 zero-row, zero-column frame.
9991
9992 We use the base_width and base_height members if we have
9993 them; otherwise, we set the min_width and min_height members
9994 to the size for a zero x zero frame. */
9995
9996#ifdef HAVE_X11R4
9997 size_hints.flags |= PBaseSize;
9998 size_hints.base_width = base_width;
9999 size_hints.base_height = base_height;
10000 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
10001 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
10002#else
10003 size_hints.min_width = base_width;
10004 size_hints.min_height = base_height;
10005#endif
10006 }
10007
10008 /* If we don't need the old flags, we don't need the old hint at all. */
10009 if (flags)
10010 {
10011 size_hints.flags |= flags;
10012 goto no_read;
10013 }
10014#endif /* not USE_X_TOOLKIT */
10015
10016 {
10017 XSizeHints hints; /* Sometimes I hate X Windows... */
10018 long supplied_return;
10019 int value;
10020
10021#ifdef HAVE_X11R4
10022 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
10023 &supplied_return);
10024#else
10025 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
10026#endif
10027
10028#ifdef USE_X_TOOLKIT
10029 size_hints.base_height = hints.base_height;
10030 size_hints.base_width = hints.base_width;
10031 size_hints.min_height = hints.min_height;
10032 size_hints.min_width = hints.min_width;
10033#endif
10034
10035 if (flags)
10036 size_hints.flags |= flags;
10037 else
10038 {
10039 if (value == 0)
10040 hints.flags = 0;
10041 if (hints.flags & PSize)
10042 size_hints.flags |= PSize;
10043 if (hints.flags & PPosition)
10044 size_hints.flags |= PPosition;
10045 if (hints.flags & USPosition)
10046 size_hints.flags |= USPosition;
10047 if (hints.flags & USSize)
10048 size_hints.flags |= USSize;
10049 }
10050 }
10051
10052#ifndef USE_X_TOOLKIT
10053 no_read:
10054#endif
10055
10056#ifdef PWinGravity
10057 size_hints.win_gravity = f->output_data.x->win_gravity;
10058 size_hints.flags |= PWinGravity;
10059
10060 if (user_position)
10061 {
10062 size_hints.flags &= ~ PPosition;
10063 size_hints.flags |= USPosition;
10064 }
10065#endif /* PWinGravity */
10066
10067#ifdef HAVE_X11R4
10068 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
10069#else
10070 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
10071#endif
10072#endif /* MACTODO */
10073}
10074
10075#if 0 /* MACTODO: hide application instead of iconify? */
10076/* Used for IconicState or NormalState */
10077
10078void
10079x_wm_set_window_state (f, state)
10080 struct frame *f;
10081 int state;
10082{
10083#ifdef USE_X_TOOLKIT
10084 Arg al[1];
10085
10086 XtSetArg (al[0], XtNinitialState, state);
10087 XtSetValues (f->output_data.x->widget, al, 1);
10088#else /* not USE_X_TOOLKIT */
10089 Window window = FRAME_X_WINDOW (f);
10090
10091 f->output_data.x->wm_hints.flags |= StateHint;
10092 f->output_data.x->wm_hints.initial_state = state;
10093
10094 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
10095#endif /* not USE_X_TOOLKIT */
10096}
10097
10098void
10099x_wm_set_icon_pixmap (f, pixmap_id)
10100 struct frame *f;
10101 int pixmap_id;
10102{
10103 Pixmap icon_pixmap;
10104
10105#ifndef USE_X_TOOLKIT
10106 Window window = FRAME_X_WINDOW (f);
10107#endif
10108
10109 if (pixmap_id > 0)
10110 {
10111 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
10112 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
10113 }
10114 else
10115 {
10116 /* It seems there is no way to turn off use of an icon pixmap.
10117 The following line does it, only if no icon has yet been created,
10118 for some window managers. But with mwm it crashes.
10119 Some people say it should clear the IconPixmapHint bit in this case,
10120 but that doesn't work, and the X consortium said it isn't the
10121 right thing at all. Since there is no way to win,
10122 best to explicitly give up. */
10123#if 0
10124 f->output_data.x->wm_hints.icon_pixmap = None;
10125#else
10126 return;
10127#endif
10128 }
10129
10130#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
10131
10132 {
10133 Arg al[1];
10134 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
10135 XtSetValues (f->output_data.x->widget, al, 1);
10136 }
10137
10138#else /* not USE_X_TOOLKIT */
10139
10140 f->output_data.x->wm_hints.flags |= IconPixmapHint;
10141 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
10142
10143#endif /* not USE_X_TOOLKIT */
10144}
10145
10146#endif
10147
10148void
10149x_wm_set_icon_position (f, icon_x, icon_y)
10150 struct frame *f;
10151 int icon_x, icon_y;
10152{
10153#if 0 /* MAC_TODO: no icons on Mac */
10154#ifdef USE_X_TOOLKIT
10155 Window window = XtWindow (f->output_data.x->widget);
10156#else
10157 Window window = FRAME_X_WINDOW (f);
10158#endif
10159
10160 f->output_data.x->wm_hints.flags |= IconPositionHint;
10161 f->output_data.x->wm_hints.icon_x = icon_x;
10162 f->output_data.x->wm_hints.icon_y = icon_y;
10163
10164 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
10165#endif
10166}
10167
10168
10169/***********************************************************************
10170 Fonts
10171 ***********************************************************************/
10172
10173/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
10174
10175struct font_info *
10176x_get_font_info (f, font_idx)
10177 FRAME_PTR f;
10178 int font_idx;
10179{
10180 return (FRAME_MAC_FONT_TABLE (f) + font_idx);
10181}
10182
10183/* the global font name table */
10184char **font_name_table = NULL;
10185int font_name_table_size = 0;
10186int font_name_count = 0;
10187
10188/* compare two strings ignoring case */
10189static int
10190stricmp (const char *s, const char *t)
10191{
10192 for ( ; tolower (*s) == tolower (*t); s++, t++)
10193 if (*s == '\0')
10194 return 0;
10195 return tolower (*s) - tolower (*t);
10196}
10197
10198/* compare two strings ignoring case and handling wildcard */
10199static int
10200wildstrieq (char *s1, char *s2)
10201{
10202 if (strcmp (s1, "*") == 0 || strcmp (s2, "*") == 0)
10203 return true;
10204
10205 return stricmp (s1, s2) == 0;
10206}
10207
10208/* Assume parameter 1 is fully qualified, no wildcards. */
10209static int
10210mac_font_pattern_match (fontname, pattern)
10211 char * fontname;
10212 char * pattern;
10213{
10214 char *regex = (char *) alloca (strlen (pattern) * 2);
10215 char *font_name_copy = (char *) alloca (strlen (fontname) + 1);
10216 char *ptr;
10217
10218 /* Copy fontname so we can modify it during comparison. */
10219 strcpy (font_name_copy, fontname);
10220
10221 ptr = regex;
10222 *ptr++ = '^';
10223
10224 /* Turn pattern into a regexp and do a regexp match. */
10225 for (; *pattern; pattern++)
10226 {
10227 if (*pattern == '?')
10228 *ptr++ = '.';
10229 else if (*pattern == '*')
10230 {
10231 *ptr++ = '.';
10232 *ptr++ = '*';
10233 }
10234 else
10235 *ptr++ = *pattern;
10236 }
10237 *ptr = '$';
10238 *(ptr + 1) = '\0';
10239
10240 return (fast_c_string_match_ignore_case (build_string (regex),
10241 font_name_copy) >= 0);
10242}
10243
10244/* Two font specs are considered to match if their foundry, family,
10245 weight, slant, and charset match. */
10246static int
10247mac_font_match (char *mf, char *xf)
10248{
10249 char m_foundry[50], m_family[50], m_weight[20], m_slant[2], m_charset[20];
10250 char x_foundry[50], x_family[50], x_weight[20], x_slant[2], x_charset[20];
10251
10252 if (sscanf (mf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s",
10253 m_foundry, m_family, m_weight, m_slant, m_charset) != 5)
10254 return mac_font_pattern_match (mf, xf);
10255
10256 if (sscanf (xf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s",
10257 x_foundry, x_family, x_weight, x_slant, x_charset) != 5)
10258 return mac_font_pattern_match (mf, xf);
10259
10260 return (wildstrieq (m_foundry, x_foundry)
10261 && wildstrieq (m_family, x_family)
10262 && wildstrieq (m_weight, x_weight)
10263 && wildstrieq (m_slant, x_slant)
10264 && wildstrieq (m_charset, x_charset))
10265 || mac_font_pattern_match (mf, xf);
10266}
10267
10268
10269static char *
10270mac_to_x_fontname (char *name, int size, Style style, short scriptcode)
10271{
10272 char foundry[32], family[32], cs[32];
10273 char xf[255], *result, *p;
10274
10275 if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3)
10276 {
10277 strcpy(foundry, "Apple");
10278 strcpy(family, name);
10279
10280 switch (scriptcode)
10281 {
10282 case smTradChinese:
10283 strcpy(cs, "big5-0");
10284 break;
10285 case smSimpChinese:
10286 strcpy(cs, "gb2312-0");
10287 break;
10288 case smJapanese:
10289 strcpy(cs, "jisx0208.1983-sjis");
10290 break;
10291 case smKorean:
10292 strcpy(cs, "ksc5601-0");
10293 break;
10294 default:
10295 strcpy(cs, "mac-roman");
10296 break;
10297 }
10298 }
10299
10300 sprintf(xf, "-%s-%s-%s-%c-normal--%d-%d-75-75-m-%d-%s",
10301 foundry, family, style & bold ? "bold" : "medium",
10302 style & italic ? 'i' : 'r', size, size * 10, size * 10, cs);
10303
10304 result = (char *) xmalloc (strlen (xf) + 1);
10305 strcpy (result, xf);
10306 for (p = result; *p; p++)
10307 *p = tolower(*p);
10308 return result;
10309}
10310
10311
10312/* Convert an X font spec to the corresponding mac font name, which
10313 can then be passed to GetFNum after conversion to a Pascal string.
10314 For ordinary Mac fonts, this should just be their names, like
10315 "monaco", "Taipei", etc. Fonts converted from the GNU intlfonts
10316 collection contain their charset designation in their names, like
10317 "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both types of font
10318 names are handled accordingly. */
10319static void
10320x_font_name_to_mac_font_name (char *xf, char *mf)
10321{
10322 char foundry[32], family[32], weight[20], slant[2], cs[32];
10323
10324 strcpy (mf, "");
10325
10326 if (sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
10327 foundry, family, weight, slant, cs) != 5 &&
10328 sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s",
10329 foundry, family, weight, slant, cs) != 5)
10330 return;
10331
10332 if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312-0") == 0
10333 || strcmp (cs, "jisx0208.1983-sjis") == 0
10334 || strcmp (cs, "ksc5601-0") == 0 || strcmp (cs, "mac-roman") == 0)
10335 strcpy(mf, family);
10336 else
10337 sprintf(mf, "%s-%s-%s", foundry, family, cs);
10338}
10339
10340
10341/* Sets up the table font_name_table to contain the list of all
10342 monospace fonts in the system the first time the table is used so
10343 that the Resource Manager need not be accessed every time this
10344 information is needed. */
10345
10346static void
10347init_font_name_table ()
10348{
10349 GrafPtr port;
10350 SInt16 fontnum, old_fontnum;
10351 int num_mac_fonts = CountResources('FOND');
10352 int i, j;
10353 Handle font_handle, font_handle_2;
10354 short id, scriptcode;
10355 ResType type;
10356 Str32 name;
10357 struct FontAssoc *fat;
10358 struct AsscEntry *assc_entry;
10359
10360 GetPort (&port); /* save the current font number used */
10361 old_fontnum = port->txFont;
10362
10363 for (i = 1; i <= num_mac_fonts; i++) /* loop to get all available fonts */
10364 {
10365 font_handle = GetIndResource ('FOND', i);
10366 if (!font_handle)
10367 continue;
10368
10369 GetResInfo (font_handle, &id, &type, name);
10370 GetFNum (name, &fontnum);
10371 p2cstr (name);
10372 if (fontnum == 0)
10373 continue;
10374
10375 TextFont (fontnum);
10376 scriptcode = FontToScript (fontnum);
10377 do
10378 {
10379 HLock (font_handle);
10380
10381 if (GetResourceSizeOnDisk (font_handle) >= sizeof (struct FamRec))
10382 {
10383 fat = (struct FontAssoc *) (*font_handle
10384 + sizeof (struct FamRec));
10385 assc_entry = (struct AsscEntry *) (*font_handle
10386 + sizeof (struct FamRec)
10387 + sizeof (struct FontAssoc));
10388
10389 for (j = 0; j <= fat->numAssoc; j++, assc_entry++)
10390 {
10391 if (font_name_table_size == 0)
10392 {
10393 font_name_table_size = 16;
10394 font_name_table = (char **)
10395 xmalloc (font_name_table_size * sizeof (char *));
10396 }
10397 else if (font_name_count >= font_name_table_size)
10398 {
10399 font_name_table_size += 16;
10400 font_name_table = (char **)
10401 xrealloc (font_name_table,
10402 font_name_table_size * sizeof (char *));
10403 }
10404 font_name_table[font_name_count++]
10405 = mac_to_x_fontname (name,
10406 assc_entry->fontSize,
10407 assc_entry->fontStyle,
10408 scriptcode);
10409 }
10410 }
10411
10412 HUnlock (font_handle);
10413 font_handle_2 = GetNextFOND (font_handle);
10414 ReleaseResource (font_handle);
10415 font_handle = font_handle_2;
10416 }
10417 while (ResError () == noErr && font_handle);
10418 }
10419
10420 TextFont (old_fontnum);
10421}
10422
10423
10424/* Return a list of at most MAXNAMES font specs matching the one in
10425 PATTERN. Note that each '*' in the PATTERN matches exactly one
10426 field of the font spec, unlike X in which an '*' in a font spec can
10427 match a number of fields. The result is in the Mac implementation
10428 all fonts must be specified by a font spec with all 13 fields
10429 (although many of these can be "*'s"). */
10430
10431Lisp_Object
10432x_list_fonts (struct frame *f,
10433 Lisp_Object pattern,
10434 int size,
10435 int maxnames)
10436{
10437 char *ptnstr;
10438 Lisp_Object newlist = Qnil;
10439 int n_fonts = 0;
10440 int i;
10441
10442 if (font_name_table == NULL) /* Initialize when first used. */
10443 init_font_name_table ();
10444
10445 ptnstr = XSTRING (pattern)->data;
10446
10447 /* Scan and matching bitmap fonts. */
10448 for (i = 0; i < font_name_count; i++)
10449 {
10450 if (mac_font_pattern_match (font_name_table[i], ptnstr))
10451 {
10452 newlist = Fcons (build_string (font_name_table[i]), newlist);
10453
10454 n_fonts++;
10455 if (n_fonts >= maxnames)
10456 break;
10457 }
10458 }
10459
10460 /* MAC_TODO: add code for matching outline fonts here */
10461
10462 return newlist;
10463}
10464
10465
10466#if GLYPH_DEBUG
10467
10468/* Check that FONT is valid on frame F. It is if it can be found in
10469 F's font table. */
10470
10471static void
10472x_check_font (f, font)
10473 struct frame *f;
10474 XFontStruct *font;
10475{
10476 int i;
10477 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10478
10479 xassert (font != NULL);
10480
10481 for (i = 0; i < dpyinfo->n_fonts; i++)
10482 if (dpyinfo->font_table[i].name
10483 && font == dpyinfo->font_table[i].font)
10484 break;
10485
10486 xassert (i < dpyinfo->n_fonts);
10487}
10488
10489#endif /* GLYPH_DEBUG != 0 */
10490
10491
10492/* Set *W to the minimum width, *H to the minimum font height of FONT.
10493 Note: There are (broken) X fonts out there with invalid XFontStruct
10494 min_bounds contents. For example, handa@etl.go.jp reports that
10495 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
10496 have font->min_bounds.width == 0. */
10497
10498static INLINE void
10499x_font_min_bounds (font, w, h)
10500 MacFontStruct *font;
10501 int *w, *h;
10502{
10503 *h = FONT_HEIGHT (font);
10504 *w = font->min_bounds.width;
10505
10506 /* Try to handle the case where FONT->min_bounds has invalid
10507 contents. Since the only font known to have invalid min_bounds
10508 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
10509 if (*w <= 0)
10510 *w = font->max_bounds.width;
10511}
10512
10513
10514/* Compute the smallest character width and smallest font height over
10515 all fonts available on frame F. Set the members smallest_char_width
10516 and smallest_font_height in F's x_display_info structure to
10517 the values computed. Value is non-zero if smallest_font_height or
10518 smallest_char_width become smaller than they were before. */
10519
10520static int
10521x_compute_min_glyph_bounds (f)
10522 struct frame *f;
10523{
10524 int i;
10525 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10526 MacFontStruct *font;
10527 int old_width = dpyinfo->smallest_char_width;
10528 int old_height = dpyinfo->smallest_font_height;
10529
10530 dpyinfo->smallest_font_height = 100000;
10531 dpyinfo->smallest_char_width = 100000;
10532
10533 for (i = 0; i < dpyinfo->n_fonts; ++i)
10534 if (dpyinfo->font_table[i].name)
10535 {
10536 struct font_info *fontp = dpyinfo->font_table + i;
10537 int w, h;
10538
10539 font = (MacFontStruct *) fontp->font;
10540 xassert (font != (MacFontStruct *) ~0);
10541 x_font_min_bounds (font, &w, &h);
10542
10543 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
10544 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
10545 }
10546
10547 xassert (dpyinfo->smallest_char_width > 0
10548 && dpyinfo->smallest_font_height > 0);
10549
10550 return (dpyinfo->n_fonts == 1
10551 || dpyinfo->smallest_char_width < old_width
10552 || dpyinfo->smallest_font_height < old_height);
10553}
10554
10555
10556/* Determine whether given string is a fully-specified XLFD: all 14
10557 fields are present, none is '*'. */
10558
10559static int
10560is_fully_specified_xlfd (char *p)
10561{
10562 int i;
10563 char *q;
10564
10565 if (*p != '-')
10566 return 0;
10567
10568 for (i = 0; i < 13; i++)
10569 {
10570 q = strchr (p + 1, '-');
10571 if (q == NULL)
10572 return 0;
10573 if (q - p == 2 && *(p + 1) == '*')
10574 return 0;
10575 p = q;
10576 }
10577
10578 if (strchr (p + 1, '-') != NULL)
10579 return 0;
10580
10581 if (*(p + 1) == '*' && *(p + 2) == '\0')
10582 return 0;
10583
10584 return 1;
10585}
10586
10587
10588const int kDefaultFontSize = 9;
10589
10590
10591/* MacLoadQueryFont creates and returns an internal representation for
10592 a font in a MacFontStruct struct (similar in function to
10593 XLoadQueryFont in X). There is really no concept corresponding to
10594 "loading" a font on the Mac. But we check its existence and find
10595 the font number and all other information for it and store them in
10596 the returned MacFontStruct. */
10597
10598static MacFontStruct *
10599XLoadQueryFont (Display *dpy, char *fontname)
10600{
10601 int i, size, is_two_byte_font, char_width;
10602 char *name;
10603 GrafPtr port;
10604 SInt16 old_fontnum, old_fontsize;
10605 Style old_fontface;
10606 Str32 mfontname;
10607 SInt16 fontnum;
10608 Style fontface = normal;
10609 MacFontStruct *font;
10610 FontInfo the_fontinfo;
10611 char s_weight[7], c_slant;
10612
10613 if (is_fully_specified_xlfd (fontname))
10614 name = fontname;
10615 else
10616 {
10617 for (i = 0; i < font_name_count; i++)
10618 if (mac_font_pattern_match (font_name_table[i], fontname))
10619 break;
10620
10621 if (i >= font_name_count)
10622 return NULL;
10623
10624 name = font_name_table[i];
10625 }
10626
10627 GetPort (&port); /* save the current font number used */
10628 old_fontnum = port->txFont;
10629 old_fontsize = port->txSize;
10630 old_fontface = port->txFace;
10631
10632 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%d-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &size) != 1)
10633 size = kDefaultFontSize;
10634
10635 if (sscanf (name, "-%*[^-]-%*[^-]-%6[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", s_weight) == 1)
10636 if (strcmp (s_weight, "bold") == 0)
10637 fontface |= bold;
10638
10639 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &c_slant) == 1)
10640 if (c_slant == 'i')
10641 fontface |= italic;
10642
10643 x_font_name_to_mac_font_name (name, mfontname);
10644 c2pstr (mfontname);
10645 GetFNum (mfontname, &fontnum);
10646 if (fontnum == 0)
10647 return NULL;
10648
10649 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct));
10650
10651 font->fontname = (char *) xmalloc (strlen (name) + 1);
10652 bcopy (name, font->fontname, strlen (name) + 1);
10653
10654 font->mac_fontnum = fontnum;
10655 font->mac_fontsize = size;
10656 font->mac_fontface = fontface;
10657 font->mac_scriptcode = FontToScript (fontnum);
10658
10659 is_two_byte_font = font->mac_scriptcode == smJapanese ||
10660 font->mac_scriptcode == smTradChinese ||
10661 font->mac_scriptcode == smSimpChinese ||
10662 font->mac_scriptcode == smKorean;
10663
10664 TextFont (fontnum);
10665 TextSize (size);
10666 TextFace (fontface);
10667
10668 GetFontInfo (&the_fontinfo);
10669
10670 font->ascent = the_fontinfo.ascent;
10671 font->descent = the_fontinfo.descent;
10672
10673 font->min_byte1 = 0;
10674 if (is_two_byte_font)
10675 font->max_byte1 = 1;
10676 else
10677 font->max_byte1 = 0;
10678 font->min_char_or_byte2 = 0x20;
10679 font->max_char_or_byte2 = 0xff;
10680
10681 if (is_two_byte_font)
10682 {
10683 /* Use the width of an "ideographic space" of that font because
10684 the_fontinfo.widMax returns the wrong width for some fonts. */
10685 switch (font->mac_scriptcode)
10686 {
10687 case smJapanese:
10688 char_width = StringWidth("\p\x81\x40");
10689 break;
10690 case smTradChinese:
10691 char_width = StringWidth("\p\xa1\x40");
10692 break;
10693 case smSimpChinese:
10694 char_width = StringWidth("\p\xa1\xa1");
10695 break;
10696 case smKorean:
10697 char_width = StringWidth("\p\xa1\xa1");
10698 break;
10699 }
10700 }
10701 else
10702 /* Do this instead of use the_fontinfo.widMax, which incorrectly
10703 returns 15 for 12-point Monaco! */
10704 char_width = CharWidth ('m');
10705
10706 font->max_bounds.rbearing = char_width;
10707 font->max_bounds.lbearing = 0;
10708 font->max_bounds.width = char_width;
10709 font->max_bounds.ascent = the_fontinfo.ascent;
10710 font->max_bounds.descent = the_fontinfo.descent;
10711
10712 font->min_bounds = font->max_bounds;
10713
10714 if (is_two_byte_font || CharWidth ('m') == CharWidth ('i'))
10715 font->per_char = NULL;
10716 else
10717 {
10718 font->per_char = (XCharStruct *)
10719 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1));
10720 {
10721 int c;
10722
10723 for (c = 0x20; c <= 0xff; c++)
10724 {
10725 font->per_char[c - 0x20] = font->max_bounds;
10726 font->per_char[c - 0x20].width = CharWidth (c);
10727 }
10728 }
10729 }
10730
10731 TextFont (old_fontnum); /* restore previous font number, size and face */
10732 TextSize (old_fontsize);
10733 TextFace (old_fontface);
10734
10735 return font;
10736}
10737
10738
10739/* Load font named FONTNAME of the size SIZE for frame F, and return a
10740 pointer to the structure font_info while allocating it dynamically.
10741 If SIZE is 0, load any size of font.
10742 If loading is failed, return NULL. */
10743
10744struct font_info *
10745x_load_font (f, fontname, size)
10746 struct frame *f;
10747 register char *fontname;
10748 int size;
10749{
10750 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10751 Lisp_Object font_names;
10752
10753 /* Get a list of all the fonts that match this name. Once we
10754 have a list of matching fonts, we compare them against the fonts
10755 we already have by comparing names. */
10756 font_names = x_list_fonts (f, build_string (fontname), size, 1);
10757
10758 if (!NILP (font_names))
10759 {
10760 Lisp_Object tail;
10761 int i;
10762
10763 for (i = 0; i < dpyinfo->n_fonts; i++)
10764 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
10765 if (dpyinfo->font_table[i].name
10766 && (!strcmp (dpyinfo->font_table[i].name,
10767 XSTRING (XCAR (tail))->data)
10768 || !strcmp (dpyinfo->font_table[i].full_name,
10769 XSTRING (XCAR (tail))->data)))
10770 return (dpyinfo->font_table + i);
10771 }
10772
10773 /* Load the font and add it to the table. */
10774 {
10775 char *full_name;
10776 struct MacFontStruct *font;
10777 struct font_info *fontp;
10778 unsigned long value;
10779 int i;
10780
10781 /* If we have found fonts by x_list_font, load one of them. If
10782 not, we still try to load a font by the name given as FONTNAME
10783 because XListFonts (called in x_list_font) of some X server has
10784 a bug of not finding a font even if the font surely exists and
10785 is loadable by XLoadQueryFont. */
10786 if (size > 0 && !NILP (font_names))
10787 fontname = (char *) XSTRING (XCAR (font_names))->data;
10788
10789 font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname);
10790 if (!font)
10791 return NULL;
10792
10793 /* Find a free slot in the font table. */
10794 for (i = 0; i < dpyinfo->n_fonts; ++i)
10795 if (dpyinfo->font_table[i].name == NULL)
10796 break;
10797
10798 /* If no free slot found, maybe enlarge the font table. */
10799 if (i == dpyinfo->n_fonts
10800 && dpyinfo->n_fonts == dpyinfo->font_table_size)
10801 {
10802 int sz;
10803 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
10804 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
10805 dpyinfo->font_table
10806 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
10807 }
10808
10809 fontp = dpyinfo->font_table + i;
10810 if (i == dpyinfo->n_fonts)
10811 ++dpyinfo->n_fonts;
10812
10813 /* Now fill in the slots of *FONTP. */
10814 BLOCK_INPUT;
10815 fontp->font = font;
10816 fontp->font_idx = i;
10817 fontp->name = (char *) xmalloc (strlen (font->fontname) + 1);
10818 bcopy (font->fontname, fontp->name, strlen (font->fontname) + 1);
10819
10820 fontp->full_name = fontp->name;
10821
10822 fontp->size = font->max_bounds.width;
10823 fontp->height = FONT_HEIGHT (font);
10824 {
10825 /* For some font, ascent and descent in max_bounds field is
10826 larger than the above value. */
10827 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
10828 if (max_height > fontp->height)
10829 fontp->height = max_height;
10830 }
10831
10832 /* The slot `encoding' specifies how to map a character
10833 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
10834 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
10835 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
10836 2:0xA020..0xFF7F). For the moment, we don't know which charset
10837 uses this font. So, we set information in fontp->encoding[1]
10838 which is never used by any charset. If mapping can't be
10839 decided, set FONT_ENCODING_NOT_DECIDED. */
10840 if (font->mac_scriptcode == smJapanese)
10841 fontp->encoding[1] = 4;
10842 else
10843 {
10844 fontp->encoding[1]
10845 = (font->max_byte1 == 0
10846 /* 1-byte font */
10847 ? (font->min_char_or_byte2 < 0x80
10848 ? (font->max_char_or_byte2 < 0x80
10849 ? 0 /* 0x20..0x7F */
10850 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
10851 : 1) /* 0xA0..0xFF */
10852 /* 2-byte font */
10853 : (font->min_byte1 < 0x80
10854 ? (font->max_byte1 < 0x80
10855 ? (font->min_char_or_byte2 < 0x80
10856 ? (font->max_char_or_byte2 < 0x80
10857 ? 0 /* 0x2020..0x7F7F */
10858 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
10859 : 3) /* 0x20A0..0x7FFF */
10860 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
10861 : (font->min_char_or_byte2 < 0x80
10862 ? (font->max_char_or_byte2 < 0x80
10863 ? 2 /* 0xA020..0xFF7F */
10864 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
10865 : 1))); /* 0xA0A0..0xFFFF */
10866 }
10867
10868#if 0 /* MAC_TODO: fill these out with more reasonably values */
10869 fontp->baseline_offset
10870 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
10871 ? (long) value : 0);
10872 fontp->relative_compose
10873 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
10874 ? (long) value : 0);
10875 fontp->default_ascent
10876 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
10877 ? (long) value : 0);
10878#else
10879 fontp->baseline_offset = 0;
10880 fontp->relative_compose = 0;
10881 fontp->default_ascent = 0;
10882#endif
10883
10884 /* Set global flag fonts_changed_p to non-zero if the font loaded
10885 has a character with a smaller width than any other character
10886 before, or if the font loaded has a smalle>r height than any
10887 other font loaded before. If this happens, it will make a
10888 glyph matrix reallocation necessary. */
10889 fonts_changed_p = x_compute_min_glyph_bounds (f);
10890 UNBLOCK_INPUT;
10891 return fontp;
10892 }
10893}
10894
10895
10896/* Return a pointer to struct font_info of a font named FONTNAME for
10897 frame F. If no such font is loaded, return NULL. */
10898
10899struct font_info *
10900x_query_font (f, fontname)
10901 struct frame *f;
10902 register char *fontname;
10903{
10904 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
10905 int i;
10906
10907 for (i = 0; i < dpyinfo->n_fonts; i++)
10908 if (dpyinfo->font_table[i].name
10909 && (!strcmp (dpyinfo->font_table[i].name, fontname)
10910 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
10911 return (dpyinfo->font_table + i);
10912 return NULL;
10913}
10914
10915
10916/* Find a CCL program for a font specified by FONTP, and set the member
10917 `encoder' of the structure. */
10918
10919void
10920x_find_ccl_program (fontp)
10921 struct font_info *fontp;
10922{
10923 Lisp_Object list, elt;
10924
10925 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
10926 {
10927 elt = XCAR (list);
10928 if (CONSP (elt)
10929 && STRINGP (XCAR (elt))
10930 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
10931 >= 0))
10932 break;
10933 }
10934 if (! NILP (list))
10935 {
10936 struct ccl_program *ccl
10937 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
10938
10939 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
10940 xfree (ccl);
10941 else
10942 fontp->font_encoder = ccl;
10943 }
10944}
10945
10946
10947
10948/***********************************************************************
10949 Initialization
10950 ***********************************************************************/
10951
10952#ifdef USE_X_TOOLKIT
10953static XrmOptionDescRec emacs_options[] = {
10954 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
10955 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
10956
10957 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
10958 XrmoptionSepArg, NULL},
10959 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
10960
10961 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
10962 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
10963 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
10964 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
10965 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
10966 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
10967 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
10968};
10969#endif /* USE_X_TOOLKIT */
10970
10971static int x_initialized;
10972
10973#ifdef MULTI_KBOARD
10974/* Test whether two display-name strings agree up to the dot that separates
10975 the screen number from the server number. */
10976static int
10977same_x_server (name1, name2)
10978 char *name1, *name2;
10979{
10980 int seen_colon = 0;
10981 unsigned char *system_name = XSTRING (Vsystem_name)->data;
10982 int system_name_length = strlen (system_name);
10983 int length_until_period = 0;
10984
10985 while (system_name[length_until_period] != 0
10986 && system_name[length_until_period] != '.')
10987 length_until_period++;
10988
10989 /* Treat `unix' like an empty host name. */
10990 if (! strncmp (name1, "unix:", 5))
10991 name1 += 4;
10992 if (! strncmp (name2, "unix:", 5))
10993 name2 += 4;
10994 /* Treat this host's name like an empty host name. */
10995 if (! strncmp (name1, system_name, system_name_length)
10996 && name1[system_name_length] == ':')
10997 name1 += system_name_length;
10998 if (! strncmp (name2, system_name, system_name_length)
10999 && name2[system_name_length] == ':')
11000 name2 += system_name_length;
11001 /* Treat this host's domainless name like an empty host name. */
11002 if (! strncmp (name1, system_name, length_until_period)
11003 && name1[length_until_period] == ':')
11004 name1 += length_until_period;
11005 if (! strncmp (name2, system_name, length_until_period)
11006 && name2[length_until_period] == ':')
11007 name2 += length_until_period;
11008
11009 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
11010 {
11011 if (*name1 == ':')
11012 seen_colon++;
11013 if (seen_colon && *name1 == '.')
11014 return 1;
11015 }
11016 return (seen_colon
11017 && (*name1 == '.' || *name1 == '\0')
11018 && (*name2 == '.' || *name2 == '\0'));
11019}
11020#endif
11021
11022struct mac_display_info *
11023x_term_init (display_name, xrm_option, resource_name)
11024 Lisp_Object display_name;
11025 char *xrm_option;
11026 char *resource_name;
11027{
11028 if (!x_initialized)
11029 {
11030 x_initialize ();
11031 x_initialized = 1;
11032 }
11033
11034 return &one_mac_display_info;
11035}
11036
11037/* Set up use of X before we make the first connection. */
11038
11039static struct redisplay_interface x_redisplay_interface =
11040{
11041 x_produce_glyphs,
11042 x_write_glyphs,
11043 x_insert_glyphs,
11044 x_clear_end_of_line,
11045 x_scroll_run,
11046 x_after_update_window_line,
11047 x_update_window_begin,
11048 x_update_window_end,
11049 XTcursor_to,
11050 x_flush,
11051 x_clear_mouse_face,
11052 x_get_glyph_overhangs,
11053 x_fix_overlapping_area
11054};
11055
11056
11057/* The Mac Event loop code */
11058
11059#include <Events.h>
11060#include <Quickdraw.h>
11061#include <Balloons.h>
11062#include <Devices.h>
11063#include <Fonts.h>
11064#include <Gestalt.h>
11065#include <Menus.h>
11066#include <Processes.h>
11067#include <Sound.h>
11068#include <ToolUtils.h>
11069#include <TextUtils.h>
11070#include <Dialogs.h>
11071#include <Script.h>
11072#include <Scrap.h>
11073#include <Types.h>
11074#include <TextEncodingConverter.h>
11075#include <Resources.h>
11076
11077#if __MWERKS__
11078#include <unix.h>
11079#endif
11080
11081#define M_APPLE 128
11082#define I_ABOUT 1
11083
11084#define WINDOW_RESOURCE 128
11085#define TERM_WINDOW_RESOURCE 129
11086
11087#define DEFAULT_NUM_COLS 80
11088
11089#define MIN_DOC_SIZE 64
11090#define MAX_DOC_SIZE 32767
11091
11092/* sleep time for WaitNextEvent */
11093#define WNE_SLEEP_AT_SUSPEND 10
11094#define WNE_SLEEP_AT_RESUME 1
11095
11096/* true when cannot handle any Mac OS events */
11097static int handling_window_update = 0;
11098
11099/* the flag appl_is_suspended is used both for determining the sleep
11100 time to be passed to WaitNextEvent and whether the cursor should be
11101 drawn when updating the display. The cursor is turned off when
11102 Emacs is suspended. Redrawing it is unnecessary and what needs to
11103 be done depends on whether the cursor lies inside or outside the
11104 redraw region. So we might as well skip drawing it when Emacs is
11105 suspended. */
11106static Boolean app_is_suspended = false;
11107static long app_sleep_time = WNE_SLEEP_AT_RESUME;
11108
11109#define EXTRA_STACK_ALLOC (256 * 1024)
11110
11111#define ARGV_STRING_LIST_ID 129
11112#define ABOUT_ALERT_ID 128
11113
11114Boolean terminate_flag = false;
11115
11116/* true if using command key as meta key */
11117Lisp_Object Vmac_command_key_is_meta;
11118
11119/* convert input from Mac keyboard (assumed to be in Mac Roman coding)
11120 to this text encoding */
11121int mac_keyboard_text_encoding;
11122int current_mac_keyboard_text_encoding = kTextEncodingMacRoman;
11123
11124/* Set in term/mac-win.el to indicate that event loop can now generate
11125 drag and drop events. */
11126Lisp_Object Vmac_ready_for_drag_n_drop;
11127
11128Lisp_Object drag_and_drop_file_list;
11129
11130Point saved_menu_event_location;
11131
11132/* Apple Events */
11133static void init_required_apple_events(void);
11134static pascal OSErr do_ae_open_application(const AppleEvent *, AppleEvent *, long);
11135static pascal OSErr do_ae_print_documents(const AppleEvent *, AppleEvent *, long);
11136static pascal OSErr do_ae_open_documents(AppleEvent *, AppleEvent *, long);
11137static pascal OSErr do_ae_quit_application(AppleEvent *, AppleEvent *, long);
11138
11139extern void init_emacs_passwd_dir ();
11140extern int emacs_main (int, char **, char **);
11141extern void check_alarm ();
11142
11143extern void initialize_applescript();
11144extern void terminate_applescript();
11145
11146
11147static void
11148do_get_menus (void)
11149{
11150 Handle menubar_handle;
11151 MenuHandle menu_handle;
11152
11153 menubar_handle = GetNewMBar (128);
11154 if(menubar_handle == NULL)
11155 abort ();
11156 SetMenuBar (menubar_handle);
11157 DrawMenuBar ();
11158
11159 menu_handle = GetMenuHandle (M_APPLE);
11160 if(menu_handle != NULL)
11161 AppendResMenu (menu_handle,'DRVR');
11162 else
11163 abort ();
11164}
11165
11166
11167static void
11168do_init_managers (void)
11169{
11170 InitGraf (&qd.thePort);
11171 InitFonts ();
11172 FlushEvents (everyEvent, 0);
11173 InitWindows ();
11174 InitMenus ();
11175 TEInit ();
11176 InitDialogs (NULL);
11177 InitCursor ();
11178
11179 /* set up some extra stack space for use by emacs */
11180 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC));
11181
11182 /* MaxApplZone must be called for AppleScript to execute more
11183 complicated scripts */
11184 MaxApplZone ();
11185 MoreMasters ();
11186}
11187
11188
11189static void
11190do_window_update (WindowPtr win)
11191{
11192 struct mac_output *mwp = (mac_output *) GetWRefCon (win);
11193 struct frame *f = mwp->mFP;
11194
11195 if (f)
11196 {
11197 if (f->async_visible == 0)
11198 {
11199 f->async_visible = 1;
11200 f->async_iconified = 0;
11201 SET_FRAME_GARBAGED (f);
11202
11203 /* An update event is equivalent to MapNotify on X, so report
11204 visibility changes properly. */
11205 if (! NILP(Vframe_list) && ! NILP (XCDR (Vframe_list)))
11206 /* Force a redisplay sooner or later to update the
11207 frame titles in case this is the second frame. */
11208 record_asynch_buffer_change ();
11209 }
11210 else
11211 {
11212 BeginUpdate (win);
11213 handling_window_update = 1;
11214
11215 expose_frame (f, 0, 0, 0, 0);
11216
11217 handling_window_update = 0;
11218 EndUpdate (win);
11219 }
11220 }
11221}
11222
11223static void
11224do_window_activate (WindowPtr win)
11225{
11226 mac_output *mwp = (mac_output *) GetWRefCon (win);
11227 struct frame *f = mwp->mFP;
11228
11229 if (f)
11230 {
11231 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f);
11232 activate_scroll_bars (f);
11233 }
11234}
11235
11236static void
11237do_window_deactivate (WindowPtr win)
11238{
11239 mac_output *mwp = (mac_output *) GetWRefCon (win);
11240 struct frame *f = mwp->mFP;
11241
11242 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
11243 {
11244 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0);
11245 deactivate_scroll_bars (f);
11246 }
11247}
11248
11249static void
11250do_app_resume ()
11251{
11252 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
11253 struct frame *f = mwp->mFP;
11254
11255 if (f)
11256 {
11257 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f);
11258 activate_scroll_bars (f);
11259 }
11260
11261 app_is_suspended = false;
11262 app_sleep_time = WNE_SLEEP_AT_RESUME;
11263}
11264
11265static void
11266do_app_suspend ()
11267{
11268 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
11269 struct frame *f = mwp->mFP;
11270
11271 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
11272 {
11273 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0);
11274 deactivate_scroll_bars (f);
11275 }
11276
11277 app_is_suspended = true;
11278 app_sleep_time = WNE_SLEEP_AT_SUSPEND;
11279}
11280
11281
11282static void
11283do_mouse_moved (Point mouse_pos)
11284{
11285 WindowPtr wp = FrontWindow ();
11286 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
11287
11288 SetPort (wp);
11289 GlobalToLocal (&mouse_pos);
11290
11291 note_mouse_movement (f, &mouse_pos);
11292}
11293
11294
11295static void
11296do_os_event (EventRecord *erp)
11297{
11298 switch((erp->message >> 24) & 0x000000FF)
11299 {
11300 case suspendResumeMessage:
11301 if((erp->message & resumeFlag) == 1)
11302 do_app_resume ();
11303 else
11304 do_app_suspend ();
11305 break;
11306
11307 case mouseMovedMessage:
11308 do_mouse_moved (erp->where);
11309 break;
11310 }
11311}
11312
11313static void
11314do_events (EventRecord *erp)
11315{
11316 switch (erp->what)
11317 {
11318 case updateEvt:
11319 do_window_update ((WindowPtr) erp->message);
11320 break;
11321
11322 case osEvt:
11323 do_os_event (erp);
11324 break;
11325
11326 case activateEvt:
11327 if ((erp->modifiers & activeFlag) != 0)
11328 do_window_activate ((WindowPtr) erp->message);
11329 else
11330 do_window_deactivate ((WindowPtr) erp->message);
11331 break;
11332 }
11333}
11334
11335static void
11336do_apple_menu (SInt16 menu_item)
11337{
11338 Str255 item_name;
11339 SInt16 da_driver_refnum;
11340
11341 if (menu_item == I_ABOUT)
11342 NoteAlert (ABOUT_ALERT_ID, NULL);
11343 else
11344 {
11345 GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name);
11346 da_driver_refnum = OpenDeskAcc (item_name);
11347 }
11348}
11349
11350void
11351do_menu_choice (SInt32 menu_choice)
11352{
11353 SInt16 menu_id, menu_item;
11354
11355 menu_id = HiWord (menu_choice);
11356 menu_item = LoWord (menu_choice);
11357
11358 if (menu_id == 0)
11359 return;
11360
11361 switch (menu_id)
11362 {
11363 case M_APPLE:
11364 do_apple_menu (menu_item);
11365 break;
11366
11367 default:
11368 {
11369 WindowPtr wp = FrontWindow ();
11370 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
11371 MenuHandle menu = GetMenuHandle (menu_id);
11372 if (menu)
11373 {
11374 UInt32 refcon;
11375
11376 GetMenuItemRefCon (menu, menu_item, &refcon);
11377 menubar_selection_callback (f, refcon);
11378 }
11379 }
11380 }
11381
11382 HiliteMenu (0);
11383}
11384
11385
11386/* Handle drags in size box. Based on code contributed by Ben
11387 Mesander and IM - Window Manager A. */
11388
11389static void
11390do_grow_window (WindowPtr w, EventRecord *e)
11391{
11392 long grow_size;
11393 Rect limit_rect;
11394 int rows, columns;
11395 mac_output *mwp = (mac_output *) GetWRefCon (w);
11396 struct frame *f = mwp->mFP;
11397
11398 SetRect(&limit_rect, MIN_DOC_SIZE, MIN_DOC_SIZE, MAX_DOC_SIZE, MAX_DOC_SIZE);
11399
11400 grow_size = GrowWindow (w, e->where, &limit_rect);
11401
11402 /* see if it really changed size */
11403 if (grow_size != 0)
11404 {
11405 rows = PIXEL_TO_CHAR_HEIGHT (f, HiWord (grow_size));
11406 columns = PIXEL_TO_CHAR_WIDTH (f, LoWord (grow_size));
11407
11408 x_set_window_size (f, 0, columns, rows);
11409 }
11410}
11411
11412
11413/* Handle clicks in zoom box. Calculation of "standard state" based
11414 on code in IM - Window Manager A and code contributed by Ben
11415 Mesander. The standard state of an Emacs window is 80-characters
11416 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
11417
11418static void
11419do_zoom_window (WindowPtr w, int zoom_in_or_out)
11420{
11421 GrafPtr save_port;
11422 Rect zoom_rect, port_rect;
11423 Point top_left;
11424 int w_title_height, columns, rows, width, height, dummy, x, y;
11425 mac_output *mwp = (mac_output *) GetWRefCon (w);
11426 struct frame *f = mwp->mFP;
11427
11428 GetPort (&save_port);
11429 SetPort (w);
11430 EraseRect (&(w->portRect)); /* erase to avoid flicker */
11431 if (zoom_in_or_out == inZoomOut)
11432 {
11433 SetPt(&top_left, w->portRect.left, w->portRect.top);
11434 LocalToGlobal (&top_left);
11435
11436 /* calculate height of window's title bar */
11437 w_title_height = top_left.v - 1
11438 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight();
11439
11440 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
11441 zoom_rect = qd.screenBits.bounds;
11442 zoom_rect.top += w_title_height;
11443 InsetRect (&zoom_rect, 8, 4); /* not too tight */
11444
11445 zoom_rect.right = zoom_rect.left
11446 + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
11447
11448 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState = zoom_rect;
11449 }
11450
11451 ZoomWindow (w, zoom_in_or_out, w == FrontWindow());
11452
11453 /* retrieve window size and update application values */
11454 port_rect = w->portRect;
11455 rows = PIXEL_TO_CHAR_HEIGHT (f, port_rect.bottom - port_rect.top);
11456 columns = PIXEL_TO_CHAR_WIDTH (f, port_rect.right - port_rect.left);
11457 x_set_window_size (mwp->mFP, 0, columns, rows);
11458
11459 SetPort (save_port);
11460}
11461
11462
11463/* Intialize AppleEvent dispatcher table for the required events. */
11464void
11465init_required_apple_events ()
11466{
11467 OSErr err;
11468 long result;
11469
11470 /* Make sure we have apple events before starting. */
11471 err = Gestalt (gestaltAppleEventsAttr, &result);
11472 if (err != noErr)
11473 abort ();
11474
11475 if (!(result & (1 << gestaltAppleEventsPresent)))
11476 abort ();
11477
11478 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
11479 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_open_application),
11480 0L, false);
11481 if (err != noErr)
11482 abort ();
11483
11484 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
11485 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_open_documents),
11486 0L, false);
11487 if (err != noErr)
11488 abort ();
11489
11490 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
11491 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_print_documents),
11492 0L, false);
11493 if (err != noErr)
11494 abort ();
11495
11496 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
11497 NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_quit_application),
11498 0L, false);
11499 if (err != noErr)
11500 abort ();
11501}
11502
11503
11504/* Open Application Apple Event */
11505static pascal OSErr
11506do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon)
11507{
11508 return noErr;
11509}
11510
11511
11512/* Defined in mac.c. */
11513extern int
11514path_from_vol_dir_name (char *, int, short, long, char *);
11515
11516
11517/* Called when we receive an AppleEvent with an ID of
11518 "kAEOpenDocuments". This routine gets the direct parameter,
11519 extracts the FSSpecs in it, and puts their names on a list. */
11520static pascal OSErr
11521do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
11522{
11523 OSErr err, err2;
11524 AEDesc the_desc;
11525 AEKeyword keyword;
11526 DescType actual_type;
11527 Size actual_size;
11528
11529 err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc);
11530 if (err != noErr)
11531 goto descriptor_error_exit;
11532
11533 /* Check to see that we got all of the required parameters from the
11534 event descriptor. For an 'odoc' event this should just be the
11535 file list. */
11536 err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
11537 &actual_type, (Ptr) &keyword,
11538 sizeof (keyword), &actual_size);
11539 /* No error means that we found some unused parameters.
11540 errAEDescNotFound means that there are no more parameters. If we
11541 get an error code other than that, flag it. */
11542 if ((err == noErr) || (err != errAEDescNotFound))
11543 {
11544 err = errAEEventNotHandled;
11545 goto error_exit;
11546 }
11547 err = noErr;
11548
11549 /* Got all the parameters we need. Now, go through the direct
11550 object list and parse it up. */
11551 {
11552 long num_files_to_open;
11553
11554 err = AECountItems (&the_desc, &num_files_to_open);
11555 if (err == noErr)
11556 {
11557 int i;
11558
11559 /* AE file list is one based so just use that for indexing here. */
11560 for (i = 1; (err == noErr) && (i <= num_files_to_open); i++) {
11561 FSSpec fs;
11562 Str255 path_name, unix_path_name;
11563
11564 err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type,
11565 (Ptr) &fs, sizeof (fs), &actual_size);
11566 if (err != noErr) break;
11567
11568 if (path_from_vol_dir_name (path_name, 255, fs.vRefNum, fs.parID,
11569 fs.name) &&
11570 mac_to_unix_pathname (path_name, unix_path_name, 255))
11571 drag_and_drop_file_list = Fcons (build_string (unix_path_name),
11572 drag_and_drop_file_list);
11573 }
11574 }
11575 }
11576
11577error_exit:
11578 /* Nuke the coerced file list in any case */
11579 err2 = AEDisposeDesc(&the_desc);
11580
11581descriptor_error_exit:
11582 /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */
11583 return err;
11584}
11585
11586
11587/* Print Document Apple Event */
11588static pascal OSErr
11589do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon)
11590{
11591 return errAEEventNotHandled;
11592}
11593
11594
11595static pascal OSErr
11596do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon)
11597{
11598 /* FixMe: Do we need an unwind-protect or something here? And what
11599 do we do about unsaved files. Currently just forces quit rather
11600 than doing recursive callback to get user input. */
11601
11602 terminate_flag = true;
11603
11604 /* Fkill_emacs doesn't return. We have to return. (TI) */
11605 return noErr;
11606}
11607
11608
11609#if __profile__
11610void
11611profiler_exit_proc ()
11612{
11613 ProfilerDump ("\pEmacs.prof");
11614 ProfilerTerm ();
11615}
11616#endif
11617
11618/* These few functions implement Emacs as a normal Mac application
11619 (almost): set up the the heap and the Toolbox, handle necessary
11620 system events plus a few simple menu events. They also set up
11621 Emacs's access to functions defined in the rest of this file.
11622 Emacs uses function hooks to perform all its terminal I/O. A
11623 complete list of these functions appear in termhooks.h. For what
11624 they do, read the comments there and see also w32term.c and
11625 xterm.c. What's noticeably missing here is the event loop, which
11626 is normally present in most Mac application. After performing the
11627 necessary Mac initializations, main passes off control to
11628 emacs_main (corresponding to main in emacs.c). Emacs_main calls
11629 mac_read_socket (defined further below) to read input. This is
11630 where WaitNextEvent is called to process Mac events. This is also
11631 where check_alarm in sysdep.c is called to simulate alarm signals.
11632 This makes the cursor jump back to its correct position after
11633 briefly jumping to that of the matching parenthesis, print useful
11634 hints and prompts in the minibuffer after the user stops typing for
11635 a wait, etc. */
11636
11637#undef main
11638int
11639main (void)
11640{
11641#if __profile__ /* is the profiler on? */
11642 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200))
11643 exit(1);
11644#endif
11645
11646#if __MWERKS__
11647 /* set creator and type for files created by MSL */
11648 _fcreator = 'EMAx';
11649 _ftype = 'TEXT';
11650#endif
11651
11652 do_init_managers ();
11653
11654 do_get_menus ();
11655
11656 init_emacs_passwd_dir ();
11657
11658 init_environ ();
11659
11660 initialize_applescript ();
11661
11662 init_required_apple_events ();
11663
11664 {
11665 char **argv;
11666 int argc = 0;
11667
11668 /* set up argv array from STR# resource */
11669 get_string_list (&argv, ARGV_STRING_LIST_ID);
11670 while (argv[argc])
11671 argc++;
11672
11673 /* free up AppleScript resources on exit */
11674 atexit (terminate_applescript);
11675
11676#if __profile__ /* is the profiler on? */
11677 atexit (profiler_exit_proc);
11678#endif
11679
11680 /* 3rd param "envp" never used in emacs_main */
11681 (void) emacs_main (argc, argv, 0);
11682 }
11683
11684 /* Never reached - real exit in Fkill_emacs */
11685 return 0;
11686}
11687
11688
11689/* Table for translating Mac keycode to X keysym values. Contributed
11690 by Sudhir Shenoy. */
11691static unsigned char keycode_to_xkeysym_table[] = {
11692/* 0x00 - 0x3f */
11693 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11694 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11695 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11696 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11697/* 0x40 */
11698 0, '\xae' /* kp. */, 0, '\xaa' /* kp* */,
11699 0, '\xab' /* kp+ */, 0, '\x7f' /* kp_clr */,
11700 0, 0, 0, '\xaf' /* kp/ */,
11701 '\x8d' /* kp_ent */, 0, '\xad' /* kp- */, 0,
11702/* 0x50 */
11703 0, '\xbd' /* kp= */, '\xb0' /* kp0 */, '\xb1' /* kp1 */,
11704 '\xb2' /* kp2 */, '\xb3' /* kp3 */, '\xb4' /* kp4 */, '\xb5' /* kp5 */,
11705 '\xb6' /* kp6 */, '\xb7' /* kp7 */, 0, '\xb8' /* kp8 */,
11706 '\xb9' /* kp9 */, 0, 0, 0,
11707/* 0x60 */
11708 '\xc2' /* F5 */, '\xc3' /* F6 */, '\xc4' /* F7 */, '\xc0' /* F3 */,
11709 '\xc5' /* F8 */, '\xc6' /* F9 */, 0, '\xc8' /* F11 */,
11710 0, '\xca' /* F13 */, 0, '\xcb' /* F14 */,
11711 0, '\xc7' /* F10 */, 0, '\xc9' /* F12 */,
11712/* 0x70 */
11713 0, '\xcc' /* F15 */, '\x9e' /* ins */, '\x95' /* home */,
11714 '\x9a' /* pgup */, '\x9f' /* del */, '\xc1' /* F4 */, '\x9c' /* end */,
11715 '\xbf' /* F2 */, '\x9b' /* pgdown */, '\xbe' /* F1 */, '\x51' /* left */,
11716 '\x53' /* right */, '\x54' /* down */, '\x52' /* up */, 0
11717};
11718
11719static int
11720keycode_to_xkeysym (int keyCode, int *xKeySym)
11721{
11722 *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f];
11723 return *xKeySym != 0;
11724}
11725
11726/* Emacs calls this whenever it wants to read an input event from the
11727 user. */
11728int
11729XTread_socket (int sd, struct input_event *bufp, int numchars, int expected)
11730{
11731 int count = 0;
11732 EventRecord er;
11733 int the_modifiers;
11734 EventMask event_mask;
11735
11736 if (interrupt_input_blocked)
11737 {
11738 interrupt_input_pending = 1;
11739 return -1;
11740 }
11741
11742 interrupt_input_pending = 0;
11743 BLOCK_INPUT;
11744
11745 /* So people can tell when we have read the available input. */
11746 input_signal_count++;
11747
11748 if (numchars <= 0)
11749 abort ();
11750
11751 /* Don't poll for events to process (specifically updateEvt) if
11752 window update currently already in progress. A call to redisplay
11753 (in do_window_update) can be preempted by another call to
11754 redisplay, causing blank regions to be left on the screen and the
11755 cursor to be left at strange places. */
11756 if (handling_window_update)
11757 {
11758 UNBLOCK_INPUT;
11759 return 0;
11760 }
11761
11762 if (terminate_flag)
11763 Fkill_emacs (make_number (1));
11764
11765 /* It is necessary to set this (additional) argument slot of an
11766 event to nil because keyboard.c protects incompletely processed
11767 event from being garbage collected by placing them in the
11768 kbd_buffer_gcpro vector. */
11769 bufp->arg = Qnil;
11770
11771 event_mask = everyEvent;
11772 if (NILP (Vmac_ready_for_drag_n_drop))
11773 event_mask -= highLevelEventMask;
11774
11775 if (WaitNextEvent (event_mask, &er, (expected ? app_sleep_time : 0L), NULL))
11776 switch (er.what)
11777 {
11778 case mouseDown:
11779 case mouseUp:
11780 {
11781 WindowPtr window_ptr = FrontWindow ();
11782 SInt16 part_code;
11783
11784 if (mouse_tracking_in_progress == mouse_tracking_scroll_bar
11785 && er.what == mouseUp)
11786 {
11787 struct mac_output *mwp = (mac_output *) GetWRefCon (window_ptr);
11788 Point mouse_loc = er.where;
11789
11790 /* Convert to local coordinates of new window. */
11791 SetPort (window_ptr);
11792 GlobalToLocal (&mouse_loc);
11793
11794 bufp->code = 0; /* only one mouse button */
11795 bufp->kind = scroll_bar_click;
11796 bufp->frame_or_window = tracked_scroll_bar->window;
11797 bufp->part = scroll_bar_handle;
11798 bufp->modifiers = up_modifier;
11799 bufp->timestamp = er.when * (1000 / 60);
11800 /* ticks to milliseconds */
11801
11802 XSETINT (bufp->x, tracked_scroll_bar->left + 2);
11803 XSETINT (bufp->y, mouse_loc.v - 24);
11804 tracked_scroll_bar->dragging = Qnil;
11805 mouse_tracking_in_progress = mouse_tracking_none;
11806 tracked_scroll_bar = NULL;
11807 count++;
11808 break;
11809 }
11810
11811 part_code = FindWindow (er.where, &window_ptr);
11812
11813 switch (part_code)
11814 {
11815 case inMenuBar:
11816 {
11817 struct frame *f = ((mac_output *)
11818 GetWRefCon (FrontWindow ()))->mFP;
11819 saved_menu_event_location = er.where;
11820 bufp->kind = menu_bar_activate_event;
11821 XSETFRAME (bufp->frame_or_window, f);
11822 count++;
11823 }
11824 break;
11825
11826 case inContent:
11827 if (window_ptr != FrontWindow ())
11828 SelectWindow (window_ptr);
11829 else
11830 {
11831 int control_part_code;
11832 ControlHandle ch;
11833 struct mac_output *mwp = (mac_output *)
11834 GetWRefCon (window_ptr);
11835 Point mouse_loc = er.where;
11836
11837 /* convert to local coordinates of new window */
11838 SetPort (window_ptr);
11839 GlobalToLocal (&mouse_loc);
11840 control_part_code = FindControl (mouse_loc, window_ptr, &ch);
11841
11842 bufp->code = 0; /* only one mouse button */
11843 XSETINT (bufp->x, mouse_loc.h);
11844 XSETINT (bufp->y, mouse_loc.v);
11845 bufp->timestamp = er.when * (1000 / 60);
11846 /* ticks to milliseconds */
11847
11848 if (control_part_code != 0)
11849 {
11850 struct scroll_bar *bar = (struct scroll_bar *)
11851 GetControlReference (ch);
11852 x_scroll_bar_handle_click (bar, control_part_code, &er,
11853 bufp);
11854 if (er.what == mouseDown
11855 && control_part_code == kControlIndicatorPart)
11856 {
11857 mouse_tracking_in_progress = mouse_tracking_scroll_bar;
11858 tracked_scroll_bar = bar;
11859 }
11860 else
11861 {
11862 mouse_tracking_in_progress = mouse_tracking_none;
11863 tracked_scroll_bar = NULL;
11864 }
11865 }
11866 else
11867 {
11868 bufp->kind = mouse_click;
11869 XSETFRAME (bufp->frame_or_window, mwp->mFP);
11870 if (er.what == mouseDown)
11871 mouse_tracking_in_progress = mouse_tracking_mouse_movement;
11872 else
11873 mouse_tracking_in_progress = mouse_tracking_none;
11874 }
11875
11876 switch (er.what)
11877 {
11878 case mouseDown:
11879 bufp->modifiers = down_modifier;
11880 break;
11881 case mouseUp:
11882 bufp->modifiers = up_modifier;
11883 break;
11884 }
11885
11886 count++;
11887 }
11888 break;
11889
11890 case inDrag:
11891 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
11892 break;
11893
11894 case inGoAway:
11895 if (TrackGoAway (window_ptr, er.where))
11896 {
11897 bufp->kind = delete_window_event;
11898 XSETFRAME (bufp->frame_or_window,
11899 ((mac_output *) GetWRefCon (window_ptr))->mFP);
11900 count++;
11901 }
11902 break;
11903
11904 /* window resize handling added --ben */
11905 case inGrow:
11906 do_grow_window(window_ptr, &er);
11907 break;
11908
11909 /* window zoom handling added --ben */
11910 case inZoomIn:
11911 case inZoomOut:
11912 if (TrackBox (window_ptr, er.where, part_code))
11913 do_zoom_window (window_ptr, part_code);
11914 break;
11915
11916 default:
11917 break;
11918 }
11919 }
11920 break;
11921
11922 case updateEvt:
11923 case osEvt:
11924 case activateEvt:
11925 do_events (&er);
11926 break;
11927
11928 case keyDown:
11929 case autoKey:
11930 {
11931 int keycode = (er.message & keyCodeMask) >> 8;
11932 int xkeysym;
11933
11934 ObscureCursor ();
11935
11936 if (keycode == 0x33) /* delete key (charCode translated to 0x8) */
11937 {
11938 bufp->code = 0x7f;
11939 bufp->kind = ascii_keystroke;
11940 }
11941 else if (keycode_to_xkeysym (keycode, &xkeysym))
11942 {
11943 bufp->code = 0xff00 | xkeysym;
11944 bufp->kind = non_ascii_keystroke;
11945 }
11946 else
11947 {
11948 if (er.modifiers
11949 & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey))
11950 {
11951 /* This code comes from Keyboard Resource, Appendix
11952 C of IM - Text. This is necessary since shift is
11953 ignored in KCHR table translation when option or
11954 command is pressed. */
11955 int new_modifiers = er.modifiers & 0xf600;
11956 /* mask off option and command */
11957 int new_keycode = keycode | new_modifiers;
11958 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
11959 unsigned long some_state = 0;
11960 bufp->code = KeyTranslate (kchr_ptr, new_keycode,
11961 &some_state) & 0xff;
11962 }
11963 else
11964 bufp->code = er.message & charCodeMask;
11965 bufp->kind = ascii_keystroke;
11966 }
11967 }
11968
11969 /* If variable mac-convert-keyboard-input-to-latin-1 is non-nil,
11970 convert non-ASCII characters typed at the Mac keyboard
11971 (presumed to be in the Mac Roman encoding) to iso-latin-1
11972 encoding before they are passed to Emacs. This enables the
11973 Mac keyboard to be used to enter non-ASCII iso-latin-1
11974 characters directly. */
11975 if (mac_keyboard_text_encoding != kTextEncodingMacRoman
11976 && bufp->kind == ascii_keystroke && bufp->code >= 128)
11977 {
11978 static TECObjectRef converter = NULL;
11979 OSStatus the_err = noErr;
11980 OSStatus convert_status = noErr;
11981
11982 if (converter == NULL)
11983 {
11984 the_err = TECCreateConverter (&converter,
11985 kTextEncodingMacRoman,
11986 mac_keyboard_text_encoding);
11987 current_mac_keyboard_text_encoding = mac_keyboard_text_encoding;
11988 }
11989 else if (mac_keyboard_text_encoding != current_mac_keyboard_text_encoding)
11990 {
11991 /* Free the converter for the current encoding before
11992 creating a new one. */
11993 TECDisposeConverter (converter);
11994 the_err = TECCreateConverter (&converter,
11995 kTextEncodingMacRoman,
11996 mac_keyboard_text_encoding);
11997 current_mac_keyboard_text_encoding = mac_keyboard_text_encoding;
11998 }
11999
12000 if (the_err == noErr)
12001 {
12002 unsigned char ch = bufp->code;
12003 ByteCount actual_input_length, actual_output_length;
12004 unsigned char outch;
12005
12006 convert_status = TECConvertText (converter, &ch, 1,
12007 &actual_input_length,
12008 &outch, 1,
12009 &actual_output_length);
12010 if (convert_status == noErr
12011 && actual_input_length == 1
12012 && actual_output_length == 1)
12013 bufp->code = outch;
12014 }
12015 }
12016
12017 the_modifiers = 0;
12018 if (er.modifiers & shiftKey)
12019 the_modifiers |= shift_modifier;
12020 if (er.modifiers & controlKey)
12021 the_modifiers |= ctrl_modifier;
12022 /* use option or command key as meta depending on value of
12023 mac-command-key-is-meta */
12024 if (er.modifiers
12025 & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey))
12026 the_modifiers |= meta_modifier;
12027 bufp->modifiers = the_modifiers;
12028
12029 {
12030 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ());
12031 XSETFRAME (bufp->frame_or_window, mwp->mFP);
12032 }
12033
12034 bufp->timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
12035
12036 count++;
12037 break;
12038
12039 case kHighLevelEvent:
12040 drag_and_drop_file_list = Qnil;
12041
12042 AEProcessAppleEvent(&er);
12043
12044 /* Build a drag_n_drop type event as is done in
12045 constuct_drag_n_drop in w32term.c. */
12046 if (!NILP (drag_and_drop_file_list))
12047 {
12048 struct frame *f;
12049 WindowPtr wp;
12050 Lisp_Object frame;
12051
12052 wp = FrontWindow ();
12053 if (!wp)
12054 f = NULL;
12055 else
12056 f = ((mac_output *) GetWRefCon (wp))->mFP;
12057
12058 bufp->kind = drag_n_drop;
12059 bufp->code = 0;
12060 bufp->timestamp = er.when * (1000 / 60);
12061 /* ticks to milliseconds */
12062 bufp->modifiers = 0;
12063
12064 XSETINT (bufp->x, 0);
12065 XSETINT (bufp->y, 0);
12066
12067 XSETFRAME (frame, f);
12068 bufp->frame_or_window = Fcons (frame, drag_and_drop_file_list);
12069
12070 /* Regardless of whether Emacs was suspended or in the
12071 foreground, ask it to redraw its entire screen.
12072 Otherwise parts of the screen can be left in an
12073 inconsistent state. */
12074 if (wp)
12075 InvalRect (&(wp->portRect));
12076
12077 count++;
12078 }
12079
12080 default:
12081 break;
12082 }
12083
12084 /* If the focus was just given to an autoraising frame,
12085 raise it now. */
12086 /* ??? This ought to be able to handle more than one such frame. */
12087 if (pending_autoraise_frame)
12088 {
12089 x_raise_frame (pending_autoraise_frame);
12090 pending_autoraise_frame = 0;
12091 }
12092
12093 check_alarm (); /* simulate the handling of a SIGALRM */
12094
12095 {
12096 static Point old_mouse_pos = { -1, -1 };
12097
12098 if (app_is_suspended)
12099 {
12100 old_mouse_pos.h = -1;
12101 old_mouse_pos.v = -1;
12102 }
12103 else
12104 {
12105 Point mouse_pos;
12106 WindowPtr wp = FrontWindow ();
12107 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP;
12108 Lisp_Object bar;
12109 struct scroll_bar *sb;
12110
12111 SetPort (wp);
12112 GetMouse (&mouse_pos);
12113
12114 if (!EqualPt (mouse_pos, old_mouse_pos))
12115 {
12116 if (mouse_tracking_in_progress == mouse_tracking_scroll_bar
12117 && tracked_scroll_bar)
12118 x_scroll_bar_note_movement (tracked_scroll_bar,
12119 mouse_pos.v
12120 - XINT (tracked_scroll_bar->top),
12121 TickCount() * (1000 / 60));
12122 else
12123 note_mouse_movement (f, &mouse_pos);
12124
12125 old_mouse_pos = mouse_pos;
12126 }
12127 }
12128 }
12129
12130 UNBLOCK_INPUT;
12131
12132 return count;
12133}
12134
12135
12136/* Need to override CodeWarrior's input function so no conversion is
12137 done on newlines Otherwise compiled functions in .elc files will be
12138 read incorrectly. Defined in ...:MSL C:MSL
12139 Common:Source:buffer_io.c. */
12140#ifdef __MWERKS__
12141void
12142__convert_to_newlines (unsigned char * p, size_t * n)
12143{
12144#pragma unused(p,n)
12145}
12146
12147void
12148__convert_from_newlines (unsigned char * p, size_t * n)
12149{
12150#pragma unused(p,n)
12151}
12152#endif
12153
12154
12155/* Initialize the struct pointed to by MW to represent a new COLS x
12156 ROWS Macintosh window, using font with name FONTNAME and size
12157 FONTSIZE. */
12158void
12159NewMacWindow (FRAME_PTR fp)
12160{
12161 mac_output *mwp;
12162 static int making_terminal_window = 1;
12163
12164 mwp = fp->output_data.mac;
12165
12166 if (making_terminal_window)
12167 {
12168 if (!(mwp->mWP = GetNewCWindow (TERM_WINDOW_RESOURCE, NULL,
12169 (WindowPtr) -1)))
12170 abort ();
12171 making_terminal_window = 0;
12172 }
12173 else
12174 if (!(mwp->mWP = GetNewCWindow (WINDOW_RESOURCE, NULL, (WindowPtr) -1)))
12175 abort ();
12176
12177
12178 SetWRefCon (mwp->mWP, (long) mwp);
12179 /* so that update events can find this mac_output struct */
12180 mwp->mFP = fp; /* point back to emacs frame */
12181
12182 SetPort (mwp->mWP);
12183
12184 mwp->fontset = -1;
12185
12186 SizeWindow (mwp->mWP, mwp->pixel_width, mwp->pixel_height, false);
12187 ShowWindow (mwp->mWP);
12188
12189}
12190
12191
12192void make_mac_frame (struct frame *f)
12193{
12194 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
12195 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right;
12196
12197 NewMacWindow(f);
12198 f->output_data.mac->background_pixel = 0xffffff;
12199 f->output_data.mac->foreground_pixel = 0;
12200
12201 f->output_data.mac->cursor_pixel = 0;
12202 f->output_data.mac->border_pixel = 0x00ff00;
12203 f->output_data.mac->mouse_pixel = 0xff00ff;
12204 f->output_data.mac->cursor_foreground_pixel = 0x0000ff;
12205
12206 f->output_data.mac->desired_cursor = FILLED_BOX_CURSOR;
12207
12208 f->output_data.mac->fontset = -1;
12209 f->output_data.mac->scroll_bar_foreground_pixel = -1;
12210 f->output_data.mac->scroll_bar_background_pixel = -1;
12211 f->output_data.mac->left_pos = 4;
12212 f->output_data.mac->top_pos = 4;
12213 f->output_data.mac->border_width = 0;
12214 f->output_data.mac->explicit_parent = 0;
12215
12216 f->output_data.mac->internal_border_width = 0;
12217
12218 f->output_method = output_mac;
12219
12220 f->auto_raise = 1;
12221 f->auto_lower = 1;
12222
12223 f->new_width = 0;
12224 f->new_height = 0;
12225}
12226
12227void make_mac_terminal_frame (struct frame *f)
12228{
12229 Lisp_Object frame;
12230
12231 XSETFRAME (frame, f);
12232
12233 f->output_method = output_mac;
12234 f->output_data.mac = (struct mac_output *)
12235 xmalloc (sizeof (struct mac_output));
12236 bzero (f->output_data.mac, sizeof (struct mac_output));
12237 f->output_data.mac->fontset = -1;
12238 f->output_data.mac->scroll_bar_foreground_pixel = -1;
12239 f->output_data.mac->scroll_bar_background_pixel = -1;
12240
12241 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f);
12242
12243 f->width = 96;
12244 f->height = 4;
12245
12246 make_mac_frame (f);
12247
12248 Fmodify_frame_parameters (frame,
12249 Fcons (Fcons (Qfont,
12250 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil));
12251 Fmodify_frame_parameters (frame,
12252 Fcons (Fcons (Qforeground_color,
12253 build_string ("black")), Qnil));
12254 Fmodify_frame_parameters (frame,
12255 Fcons (Fcons (Qbackground_color,
12256 build_string ("white")), Qnil));
12257}
12258
12259void
12260mac_initialize_display_info ()
12261{
12262 struct mac_display_info *dpyinfo = &one_mac_display_info;
12263 GDHandle main_device_handle;
12264
12265 bzero (dpyinfo, sizeof (*dpyinfo));
12266
12267 /* Put it on x_display_name_list. */
12268 x_display_name_list = Fcons (Fcons (build_string ("Mac"), Qnil),
12269 x_display_name_list);
12270 dpyinfo->name_list_element = XCAR (x_display_name_list);
12271
12272 main_device_handle = LMGetMainDevice();
12273
12274 dpyinfo->reference_count = 0;
12275 dpyinfo->resx = 75.0;
12276 dpyinfo->resy = 75.0;
12277 dpyinfo->n_planes = 1;
12278 dpyinfo->n_cbits = 16;
12279 dpyinfo->height = (**main_device_handle).gdRect.bottom;
12280 dpyinfo->width = (**main_device_handle).gdRect.right;
12281 dpyinfo->grabbed = 0;
12282 dpyinfo->root_window = NULL;
12283
12284 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12285 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
12286 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
12287 dpyinfo->mouse_face_window = Qnil;
12288
12289}
12290
12291void
12292x_initialize ()
12293{
12294 rif = &x_redisplay_interface;
12295
12296 clear_frame_hook = x_clear_frame;
12297 ins_del_lines_hook = x_ins_del_lines;
12298 change_line_highlight_hook = x_change_line_highlight;
12299 delete_glyphs_hook = x_delete_glyphs;
12300 ring_bell_hook = XTring_bell;
12301 reset_terminal_modes_hook = XTreset_terminal_modes;
12302 set_terminal_modes_hook = XTset_terminal_modes;
12303 update_begin_hook = x_update_begin;
12304 update_end_hook = x_update_end;
12305 set_terminal_window_hook = XTset_terminal_window;
12306 read_socket_hook = XTread_socket;
12307 frame_up_to_date_hook = XTframe_up_to_date;
12308 reassert_line_highlight_hook = XTreassert_line_highlight;
12309 mouse_position_hook = XTmouse_position;
12310 frame_rehighlight_hook = XTframe_rehighlight;
12311 frame_raise_lower_hook = XTframe_raise_lower;
12312
12313 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12314 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12315 redeem_scroll_bar_hook = XTredeem_scroll_bar;
12316 judge_scroll_bars_hook = XTjudge_scroll_bars;
12317
12318 estimate_mode_line_height_hook = x_estimate_mode_line_height;
12319
12320 scroll_region_ok = 1; /* we'll scroll partial frames */
12321 char_ins_del_ok = 0; /* just as fast to write the line */
12322 line_ins_del_ok = 1; /* we'll just blt 'em */
12323 fast_clear_end_of_line = 1; /* X does this well */
12324 memory_below_frame = 0; /* we don't remember what scrolls
12325 off the bottom */
12326 baud_rate = 19200;
12327
12328 x_noop_count = 0;
12329 last_tool_bar_item = -1;
12330 any_help_event_p = 0;
12331
12332 /* Try to use interrupt input; if we can't, then start polling. */
12333 Fset_input_mode (Qt, Qnil, Qt, Qnil);
12334
12335#ifdef USE_X_TOOLKIT
12336 XtToolkitInitialize ();
12337 Xt_app_con = XtCreateApplicationContext ();
12338 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
12339
12340 /* Install an asynchronous timer that processes Xt timeout events
12341 every 0.1s. This is necessary because some widget sets use
12342 timeouts internally, for example the LessTif menu bar, or the
12343 Xaw3d scroll bar. When Xt timouts aren't processed, these
12344 widgets don't behave normally. */
12345 {
12346 EMACS_TIME interval;
12347 EMACS_SET_SECS_USECS (interval, 0, 100000);
12348 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
12349 }
12350#endif
12351
12352#if USE_TOOLKIT_SCROLL_BARS
12353 xaw3d_arrow_scroll = False;
12354 xaw3d_pick_top = True;
12355#endif
12356
12357#if 0
12358 /* Note that there is no real way portable across R3/R4 to get the
12359 original error handler. */
12360 XSetErrorHandler (x_error_handler);
12361 XSetIOErrorHandler (x_io_error_quitter);
12362
12363 /* Disable Window Change signals; they are handled by X events. */
12364#ifdef SIGWINCH
12365 signal (SIGWINCH, SIG_DFL);
12366#endif /* ! defined (SIGWINCH) */
12367
12368 signal (SIGPIPE, x_connection_signal);
12369#endif
12370
12371 mac_initialize_display_info ();
12372}
12373
12374
12375void
12376syms_of_macterm ()
12377{
12378#if 0
12379 staticpro (&x_error_message_string);
12380 x_error_message_string = Qnil;
12381#endif
12382
12383 staticpro (&x_display_name_list);
12384 x_display_name_list = Qnil;
12385
12386 staticpro (&last_mouse_scroll_bar);
12387 last_mouse_scroll_bar = Qnil;
12388
12389 staticpro (&Qvendor_specific_keysyms);
12390 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
12391
12392 staticpro (&last_mouse_press_frame);
12393 last_mouse_press_frame = Qnil;
12394
12395 help_echo = Qnil;
12396 staticpro (&help_echo);
12397 help_echo_object = Qnil;
12398 staticpro (&help_echo_object);
12399 help_echo_window = Qnil;
12400 staticpro (&help_echo_window);
12401 previous_help_echo = Qnil;
12402 staticpro (&previous_help_echo);
12403 help_echo_pos = -1;
12404
12405 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
12406 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
12407For example, if a block cursor is over a tab, it will be drawn as\n\
12408wide as that tab on the display.");
12409 x_stretch_cursor_p = 0;
12410
12411 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
12412 "If not nil, Emacs uses toolkit scroll bars.");
12413#if USE_TOOLKIT_SCROLL_BARS
12414 x_toolkit_scroll_bars_p = 1;
12415#else
12416 x_toolkit_scroll_bars_p = 0;
12417#endif
12418
12419 staticpro (&last_mouse_motion_frame);
12420 last_mouse_motion_frame = Qnil;
12421
12422 DEFVAR_LISP ("mac-command-key-is-meta", &Vmac_command_key_is_meta,
12423 "Non-nil means that the command key is used as the Emacs meta key.\n\
12424Otherwise the option key is used.");
12425 Vmac_command_key_is_meta = Qt;
12426
12427 DEFVAR_LISP ("mac-ready-for-drag-n-drop", &Vmac_ready_for_drag_n_drop,
12428 "Non-nil indicates that the Mac event loop can now generate drag and\n\
12429drop events. Set in term/mac-win.el.");
12430 Vmac_ready_for_drag_n_drop = Qnil;
12431
12432 DEFVAR_INT ("mac-keyboard-text-encoding", &mac_keyboard_text_encoding,
12433 "One of the Text Encoding Base constant values defined in the\n\
12434Basic Text Constants section of Inside Macintosh - Text Encoding\n\
12435Conversion Manager. Its value determines the encoding characters\n\
12436typed at the Mac keyboard (presumed to be in the MacRoman encoding)\n\
12437will convert into. E.g., if it is set to kTextEncodingMacRoman (0),\n\
12438its default value, no conversion takes place. If it is set to\n\
12439kTextEncodingISOLatin1 (0x201) or kTextEncodingISOLatin2 (0x202),\n\
12440characters typed on Mac keyboard are first converted into the\n\
12441ISO Latin-1 or ISO Latin-2 encoding, respectively before being\n\
12442passed to Emacs. Together with Emacs's set-keyboard-coding-system\n\
12443command, this enables the Mac keyboard to be used to enter non-ASCII\n\
12444characters directly.");
12445 mac_keyboard_text_encoding = kTextEncodingMacRoman;
12446}