Mercurial > emacs
comparison src/xfns.c @ 24994:d549b7ac676d
(x_real_positions): Don't subtract window borders
from positions returned.
(top-level): Added image support, busy cursor, tooltips, file
selection box.
(x_report_frame_params): Don't report `outer-window-id'
if widget not present.
(x_set_font): Don't call face-set-after-frame-default
if faces haven't been initialized.
(Fx_create_frame): Call face-set-after-frame-default after
faces have been initialized, and widget has been created.
(x_set_scroll_bar_foreground): New.
(x_set_scroll_bar_background): New.
(x_default_scroll_bar_color_parameter): New.
(Fx_create_frame): Call it.
(Fx_create_frame): Initialize scroll bar pixel color
values in x_output structure.
(Qscroll_bar_foreground, Qscroll_bar_background): New.
(syms_of_xfns): Initialize these symbols.
(x_frame_parms): Add entries for scroll bar colors.
(Fx_create_frame): Try 12pt Courier font first.
(Fx_create_frame): Add toolbar height to frame height.
(x_frame_parms): Add `toolbar-lines'.
(x_set_toolbar_lines): New.
(x_set_internal_border_width): Correct call to
widget_store_internal_border_width.
(x_destroy_bitmap): Use xfree instead of free. Return
void.
(init_x_parm_symbols): Return void.
(x_report_frame_params): Ditto.
(x_set_border_pixel): Ditto.
(syms_of_xfns): Ditto.
(x_destroy_all_bitmaps): Use xfree instead of free.
(Fx_close_connection): Use xfree instead of free.
Only free fonts from filled font table entries.
(display_x_get_resource): Make it externally visible.
(x_set_font): First store real font name in frame
parameters, then call recompute_basic_faces.
(Fx_face_fixed_p): Removed.
(Fx_list_fonts): Moved to xfaces.c.
author | Gerd Moellmann <gerd@gnu.org> |
---|---|
date | Wed, 21 Jul 1999 21:43:52 +0000 |
parents | 2c79eecad64d |
children | 9f5d679349e9 |
comparison
equal
deleted
inserted
replaced
24993:825f11b1c34d | 24994:d549b7ac676d |
---|---|
1 /* Functions for the X window system. | 1 /* Functions for the X window system. |
2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997 Free Software Foundation. | 2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999 |
3 Free Software Foundation. | |
3 | 4 |
4 This file is part of GNU Emacs. | 5 This file is part of GNU Emacs. |
5 | 6 |
6 GNU Emacs is free software; you can redistribute it and/or modify | 7 GNU Emacs is free software; you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 8 it under the terms of the GNU General Public License as published by |
16 You should have received a copy of the GNU General Public License | 17 You should have received a copy of the GNU General Public License |
17 along with GNU Emacs; see the file COPYING. If not, write to | 18 along with GNU Emacs; see the file COPYING. If not, write to |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 Boston, MA 02111-1307, USA. */ | 20 Boston, MA 02111-1307, USA. */ |
20 | 21 |
22 /* Image support (XBM, XPM, PBM, JPEG, TIFF, GIF, PNG, GS). tooltips, | |
23 toolbars, busy-cursor, file selection dialog added by Gerd | |
24 Moellmann <gerd@gnu.org>. */ | |
25 | |
21 /* Completely rewritten by Richard Stallman. */ | 26 /* Completely rewritten by Richard Stallman. */ |
22 | 27 |
23 /* Rewritten for X11 by Joseph Arceneaux */ | 28 /* Rewritten for X11 by Joseph Arceneaux */ |
24 | 29 |
25 #include <signal.h> | 30 #include <signal.h> |
26 #include <config.h> | 31 #include <config.h> |
32 #include <stdio.h> | |
27 | 33 |
28 /* This makes the fields of a Display accessible, in Xlib header files. */ | 34 /* This makes the fields of a Display accessible, in Xlib header files. */ |
35 | |
29 #define XLIB_ILLEGAL_ACCESS | 36 #define XLIB_ILLEGAL_ACCESS |
30 | 37 |
31 #include "lisp.h" | 38 #include "lisp.h" |
32 #include "xterm.h" | 39 #include "xterm.h" |
33 #include "frame.h" | 40 #include "frame.h" |
37 #include "keyboard.h" | 44 #include "keyboard.h" |
38 #include "blockinput.h" | 45 #include "blockinput.h" |
39 #include <epaths.h> | 46 #include <epaths.h> |
40 #include "charset.h" | 47 #include "charset.h" |
41 #include "fontset.h" | 48 #include "fontset.h" |
49 #include "systime.h" | |
50 #include "termhooks.h" | |
42 | 51 |
43 #ifdef HAVE_X_WINDOWS | 52 #ifdef HAVE_X_WINDOWS |
44 extern void abort (); | 53 extern void abort (); |
45 | 54 |
46 /* On some systems, the character-composition stuff is broken in X11R5. */ | 55 /* On some systems, the character-composition stuff is broken in X11R5. */ |
56 | |
47 #if defined (HAVE_X11R5) && ! defined (HAVE_X11R6) | 57 #if defined (HAVE_X11R5) && ! defined (HAVE_X11R6) |
48 #ifdef X11R5_INHIBIT_I18N | 58 #ifdef X11R5_INHIBIT_I18N |
49 #define X_I18N_INHIBITED | 59 #define X_I18N_INHIBITED |
50 #endif | 60 #endif |
51 #endif | 61 #endif |
78 | 88 |
79 #include "widget.h" | 89 #include "widget.h" |
80 | 90 |
81 #include "../lwlib/lwlib.h" | 91 #include "../lwlib/lwlib.h" |
82 | 92 |
93 #ifdef USE_MOTIF | |
94 #include <Xm/Xm.h> | |
95 #include <Xm/DialogS.h> | |
96 #include <Xm/FileSB.h> | |
97 #endif | |
98 | |
83 /* Do the EDITRES protocol if running X11R5 | 99 /* Do the EDITRES protocol if running X11R5 |
84 Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */ | 100 Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */ |
101 | |
85 #if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES) | 102 #if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES) |
86 #define HACK_EDITRES | 103 #define HACK_EDITRES |
87 extern void _XEditResCheckMessages (); | 104 extern void _XEditResCheckMessages (); |
88 #endif /* R5 + Athena */ | 105 #endif /* R5 + Athena */ |
89 | 106 |
90 /* Unique id counter for widgets created by the Lucid Widget | 107 /* Unique id counter for widgets created by the Lucid Widget Library. */ |
91 Library. */ | 108 |
92 extern LWLIB_ID widget_id_tick; | 109 extern LWLIB_ID widget_id_tick; |
93 | 110 |
94 #ifdef USE_LUCID | 111 #ifdef USE_LUCID |
95 /* This is part of a kludge--see lwlib/xlwmenu.c. */ | 112 /* This is part of a kludge--see lwlib/xlwmenu.c. */ |
96 extern XFontStruct *xlwmenu_default_font; | 113 extern XFontStruct *xlwmenu_default_font; |
97 #endif | 114 #endif |
98 | 115 |
99 extern void free_frame_menubar (); | 116 extern void free_frame_menubar (); |
117 | |
100 #endif /* USE_X_TOOLKIT */ | 118 #endif /* USE_X_TOOLKIT */ |
101 | 119 |
102 #define min(a,b) ((a) < (b) ? (a) : (b)) | 120 #define min(a,b) ((a) < (b) ? (a) : (b)) |
103 #define max(a,b) ((a) > (b) ? (a) : (b)) | 121 #define max(a,b) ((a) > (b) ? (a) : (b)) |
104 | 122 |
106 #define MAXREQUEST(dpy) (XMaxRequestSize (dpy)) | 124 #define MAXREQUEST(dpy) (XMaxRequestSize (dpy)) |
107 #else | 125 #else |
108 #define MAXREQUEST(dpy) ((dpy)->max_request_size) | 126 #define MAXREQUEST(dpy) ((dpy)->max_request_size) |
109 #endif | 127 #endif |
110 | 128 |
129 /* The gray bitmap `bitmaps/gray'. This is done because xterm.c uses | |
130 it, and including `bitmaps/gray' more than once is a problem when | |
131 config.h defines `static' as an empty replacement string. */ | |
132 | |
133 int gray_bitmap_width = gray_width; | |
134 int gray_bitmap_height = gray_height; | |
135 unsigned char *gray_bitmap_bits = gray_bits; | |
136 | |
111 /* The name we're using in resource queries. Most often "emacs". */ | 137 /* The name we're using in resource queries. Most often "emacs". */ |
138 | |
112 Lisp_Object Vx_resource_name; | 139 Lisp_Object Vx_resource_name; |
113 | 140 |
114 /* The application class we're using in resource queries. | 141 /* The application class we're using in resource queries. |
115 Normally "Emacs". */ | 142 Normally "Emacs". */ |
143 | |
116 Lisp_Object Vx_resource_class; | 144 Lisp_Object Vx_resource_class; |
145 | |
146 /* Non-zero means we're allowed to display a busy cursor. */ | |
147 | |
148 int display_busy_cursor_p; | |
117 | 149 |
118 /* The background and shape of the mouse pointer, and shape when not | 150 /* The background and shape of the mouse pointer, and shape when not |
119 over text or in the modeline. */ | 151 over text or in the modeline. */ |
152 | |
120 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape; | 153 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape; |
154 Lisp_Object Vx_busy_pointer_shape; | |
155 | |
121 /* The shape when over mouse-sensitive text. */ | 156 /* The shape when over mouse-sensitive text. */ |
157 | |
122 Lisp_Object Vx_sensitive_text_pointer_shape; | 158 Lisp_Object Vx_sensitive_text_pointer_shape; |
123 | 159 |
124 /* Color of chars displayed in cursor box. */ | 160 /* Color of chars displayed in cursor box. */ |
161 | |
125 Lisp_Object Vx_cursor_fore_pixel; | 162 Lisp_Object Vx_cursor_fore_pixel; |
126 | 163 |
127 /* Nonzero if using X. */ | 164 /* Nonzero if using X. */ |
165 | |
128 static int x_in_use; | 166 static int x_in_use; |
129 | 167 |
130 /* Non nil if no window manager is in use. */ | 168 /* Non nil if no window manager is in use. */ |
169 | |
131 Lisp_Object Vx_no_window_manager; | 170 Lisp_Object Vx_no_window_manager; |
132 | 171 |
133 /* Search path for bitmap files. */ | 172 /* Search path for bitmap files. */ |
173 | |
134 Lisp_Object Vx_bitmap_file_path; | 174 Lisp_Object Vx_bitmap_file_path; |
135 | 175 |
136 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ | 176 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ |
177 | |
137 Lisp_Object Vx_pixel_size_width_font_regexp; | 178 Lisp_Object Vx_pixel_size_width_font_regexp; |
138 | 179 |
139 /* Evaluate this expression to rebuild the section of syms_of_xfns | 180 /* Evaluate this expression to rebuild the section of syms_of_xfns |
140 that initializes and staticpros the symbols declared below. Note | 181 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 | 182 that Emacs 18 has a bug that keeps C-x C-e from being able to |
171 */ | 212 */ |
172 | 213 |
173 /*&&& symbols declared here &&&*/ | 214 /*&&& symbols declared here &&&*/ |
174 Lisp_Object Qauto_raise; | 215 Lisp_Object Qauto_raise; |
175 Lisp_Object Qauto_lower; | 216 Lisp_Object Qauto_lower; |
176 Lisp_Object Qbackground_color; | |
177 Lisp_Object Qbar; | 217 Lisp_Object Qbar; |
178 Lisp_Object Qborder_color; | 218 Lisp_Object Qborder_color; |
179 Lisp_Object Qborder_width; | 219 Lisp_Object Qborder_width; |
180 Lisp_Object Qbox; | 220 Lisp_Object Qbox; |
181 Lisp_Object Qcursor_color; | 221 Lisp_Object Qcursor_color; |
182 Lisp_Object Qcursor_type; | 222 Lisp_Object Qcursor_type; |
183 Lisp_Object Qforeground_color; | |
184 Lisp_Object Qgeometry; | 223 Lisp_Object Qgeometry; |
185 Lisp_Object Qicon_left; | 224 Lisp_Object Qicon_left; |
186 Lisp_Object Qicon_top; | 225 Lisp_Object Qicon_top; |
187 Lisp_Object Qicon_type; | 226 Lisp_Object Qicon_type; |
188 Lisp_Object Qicon_name; | 227 Lisp_Object Qicon_name; |
193 Lisp_Object Qnone; | 232 Lisp_Object Qnone; |
194 Lisp_Object Qouter_window_id; | 233 Lisp_Object Qouter_window_id; |
195 Lisp_Object Qparent_id; | 234 Lisp_Object Qparent_id; |
196 Lisp_Object Qscroll_bar_width; | 235 Lisp_Object Qscroll_bar_width; |
197 Lisp_Object Qsuppress_icon; | 236 Lisp_Object Qsuppress_icon; |
198 Lisp_Object Qtop; | 237 extern Lisp_Object Qtop; |
199 Lisp_Object Qundefined_color; | 238 Lisp_Object Qundefined_color; |
200 Lisp_Object Qvertical_scroll_bars; | 239 Lisp_Object Qvertical_scroll_bars; |
201 Lisp_Object Qvisibility; | 240 Lisp_Object Qvisibility; |
202 Lisp_Object Qwindow_id; | 241 Lisp_Object Qwindow_id; |
203 Lisp_Object Qx_frame_parameter; | 242 Lisp_Object Qx_frame_parameter; |
204 Lisp_Object Qx_resource_name; | 243 Lisp_Object Qx_resource_name; |
205 Lisp_Object Quser_position; | 244 Lisp_Object Quser_position; |
206 Lisp_Object Quser_size; | 245 Lisp_Object Quser_size; |
207 Lisp_Object Qdisplay; | 246 Lisp_Object Qdisplay; |
247 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background; | |
208 | 248 |
209 /* The below are defined in frame.c. */ | 249 /* The below are defined in frame.c. */ |
250 | |
210 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth; | 251 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth; |
211 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle; | 252 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle; |
253 extern Lisp_Object Qtoolbar_lines; | |
212 | 254 |
213 extern Lisp_Object Vwindow_system_version; | 255 extern Lisp_Object Vwindow_system_version; |
214 | 256 |
215 Lisp_Object Qface_set_after_frame_default; | 257 Lisp_Object Qface_set_after_frame_default; |
258 | |
216 | 259 |
217 /* Error if we are not connected to X. */ | 260 /* Error if we are not connected to X. */ |
261 | |
218 void | 262 void |
219 check_x () | 263 check_x () |
220 { | 264 { |
221 if (! x_in_use) | 265 if (! x_in_use) |
222 error ("X windows are not in use or not initialized"); | 266 error ("X windows are not in use or not initialized"); |
281 if (! FRAME_X_P (f)) | 325 if (! FRAME_X_P (f)) |
282 error ("Non-X frame used"); | 326 error ("Non-X frame used"); |
283 return FRAME_X_DISPLAY_INFO (f); | 327 return FRAME_X_DISPLAY_INFO (f); |
284 } | 328 } |
285 } | 329 } |
330 | |
286 | 331 |
287 /* Return the Emacs frame-object corresponding to an X window. | 332 /* Return the Emacs frame-object corresponding to an X window. |
288 It could be the frame's main window or an icon window. */ | 333 It could be the frame's main window or an icon window. */ |
289 | 334 |
290 /* This function can be called during GC, so use GC_xxx type test macros. */ | 335 /* This function can be called during GC, so use GC_xxx type test macros. */ |
306 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) | 351 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) |
307 continue; | 352 continue; |
308 #ifdef USE_X_TOOLKIT | 353 #ifdef USE_X_TOOLKIT |
309 if ((f->output_data.x->edit_widget | 354 if ((f->output_data.x->edit_widget |
310 && XtWindow (f->output_data.x->edit_widget) == wdesc) | 355 && XtWindow (f->output_data.x->edit_widget) == wdesc) |
356 /* A tooltip frame? */ | |
357 || (!f->output_data.x->edit_widget | |
358 && FRAME_X_WINDOW (f) == wdesc) | |
311 || f->output_data.x->icon_desc == wdesc) | 359 || f->output_data.x->icon_desc == wdesc) |
312 return f; | 360 return f; |
313 #else /* not USE_X_TOOLKIT */ | 361 #else /* not USE_X_TOOLKIT */ |
314 if (FRAME_X_WINDOW (f) == wdesc | 362 if (FRAME_X_WINDOW (f) == wdesc |
315 || f->output_data.x->icon_desc == wdesc) | 363 || f->output_data.x->icon_desc == wdesc) |
340 f = XFRAME (frame); | 388 f = XFRAME (frame); |
341 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) | 389 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) |
342 continue; | 390 continue; |
343 x = f->output_data.x; | 391 x = f->output_data.x; |
344 /* This frame matches if the window is any of its widgets. */ | 392 /* This frame matches if the window is any of its widgets. */ |
345 if (wdesc == XtWindow (x->widget) | 393 if (x->widget) |
346 || wdesc == XtWindow (x->column_widget) | 394 { |
347 || wdesc == XtWindow (x->edit_widget)) | 395 if (wdesc == XtWindow (x->widget) |
348 return f; | 396 || wdesc == XtWindow (x->column_widget) |
349 /* Match if the window is this frame's menubar. */ | 397 || wdesc == XtWindow (x->edit_widget)) |
350 if (lw_window_is_in_menubar (wdesc, x->menubar_widget)) | 398 return f; |
399 /* Match if the window is this frame's menubar. */ | |
400 if (lw_window_is_in_menubar (wdesc, x->menubar_widget)) | |
401 return f; | |
402 } | |
403 else if (FRAME_X_WINDOW (f) == wdesc) | |
404 /* A tooltip frame. */ | |
351 return f; | 405 return f; |
352 } | 406 } |
353 return 0; | 407 return 0; |
354 } | 408 } |
355 | 409 |
372 f = XFRAME (frame); | 426 f = XFRAME (frame); |
373 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) | 427 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) |
374 continue; | 428 continue; |
375 x = f->output_data.x; | 429 x = f->output_data.x; |
376 /* This frame matches if the window is any of its widgets. */ | 430 /* This frame matches if the window is any of its widgets. */ |
377 if (wdesc == XtWindow (x->widget) | 431 if (x->widget) |
378 || wdesc == XtWindow (x->column_widget) | 432 { |
379 || wdesc == XtWindow (x->edit_widget)) | 433 if (wdesc == XtWindow (x->widget) |
434 || wdesc == XtWindow (x->column_widget) | |
435 || wdesc == XtWindow (x->edit_widget)) | |
436 return f; | |
437 } | |
438 else if (FRAME_X_WINDOW (f) == wdesc) | |
439 /* A tooltip frame. */ | |
380 return f; | 440 return f; |
381 } | 441 } |
382 return 0; | 442 return 0; |
383 } | 443 } |
384 | 444 |
401 f = XFRAME (frame); | 461 f = XFRAME (frame); |
402 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) | 462 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) |
403 continue; | 463 continue; |
404 x = f->output_data.x; | 464 x = f->output_data.x; |
405 /* Match if the window is this frame's menubar. */ | 465 /* Match if the window is this frame's menubar. */ |
406 if (lw_window_is_in_menubar (wdesc, x->menubar_widget)) | 466 if (x->menubar_widget |
467 && lw_window_is_in_menubar (wdesc, x->menubar_widget)) | |
407 return f; | 468 return f; |
408 } | 469 } |
409 return 0; | 470 return 0; |
410 } | 471 } |
411 | 472 |
428 continue; | 489 continue; |
429 f = XFRAME (frame); | 490 f = XFRAME (frame); |
430 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) | 491 if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo) |
431 continue; | 492 continue; |
432 x = f->output_data.x; | 493 x = f->output_data.x; |
433 /* This frame matches if the window is its topmost widget. */ | 494 |
434 if (wdesc == XtWindow (x->widget)) | 495 if (x->widget) |
435 return f; | 496 { |
497 /* This frame matches if the window is its topmost widget. */ | |
498 if (wdesc == XtWindow (x->widget)) | |
499 return f; | |
436 #if 0 /* I don't know why it did this, | 500 #if 0 /* I don't know why it did this, |
437 but it seems logically wrong, | 501 but it seems logically wrong, |
438 and it causes trouble for MapNotify events. */ | 502 and it causes trouble for MapNotify events. */ |
439 /* Match if the window is this frame's menubar. */ | 503 /* Match if the window is this frame's menubar. */ |
440 if (x->menubar_widget | 504 if (x->menubar_widget |
441 && wdesc == XtWindow (x->menubar_widget)) | 505 && wdesc == XtWindow (x->menubar_widget)) |
506 return f; | |
507 #endif | |
508 } | |
509 else if (FRAME_X_WINDOW (f) == wdesc) | |
510 /* Tooltip frame. */ | |
442 return f; | 511 return f; |
443 #endif | |
444 } | 512 } |
445 return 0; | 513 return 0; |
446 } | 514 } |
447 #endif /* USE_X_TOOLKIT */ | 515 #endif /* USE_X_TOOLKIT */ |
448 | 516 |
630 { | 698 { |
631 BLOCK_INPUT; | 699 BLOCK_INPUT; |
632 XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap); | 700 XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap); |
633 if (dpyinfo->bitmaps[id - 1].file) | 701 if (dpyinfo->bitmaps[id - 1].file) |
634 { | 702 { |
635 free (dpyinfo->bitmaps[id - 1].file); | 703 xfree (dpyinfo->bitmaps[id - 1].file); |
636 dpyinfo->bitmaps[id - 1].file = NULL; | 704 dpyinfo->bitmaps[id - 1].file = NULL; |
637 } | 705 } |
638 UNBLOCK_INPUT; | 706 UNBLOCK_INPUT; |
639 } | 707 } |
640 } | 708 } |
650 for (i = 0; i < dpyinfo->bitmaps_last; i++) | 718 for (i = 0; i < dpyinfo->bitmaps_last; i++) |
651 if (dpyinfo->bitmaps[i].refcount > 0) | 719 if (dpyinfo->bitmaps[i].refcount > 0) |
652 { | 720 { |
653 XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap); | 721 XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap); |
654 if (dpyinfo->bitmaps[i].file) | 722 if (dpyinfo->bitmaps[i].file) |
655 free (dpyinfo->bitmaps[i].file); | 723 xfree (dpyinfo->bitmaps[i].file); |
656 } | 724 } |
657 dpyinfo->bitmaps_last = 0; | 725 dpyinfo->bitmaps_last = 0; |
658 } | 726 } |
659 | 727 |
660 /* Connect the frame-parameter names for X frames | 728 /* Connect the frame-parameter names for X frames |
688 void x_set_visibility (); | 756 void x_set_visibility (); |
689 void x_set_menu_bar_lines (); | 757 void x_set_menu_bar_lines (); |
690 void x_set_scroll_bar_width (); | 758 void x_set_scroll_bar_width (); |
691 void x_set_title (); | 759 void x_set_title (); |
692 void x_set_unsplittable (); | 760 void x_set_unsplittable (); |
761 void x_set_toolbar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object)); | |
762 void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object, | |
763 Lisp_Object)); | |
764 void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object, | |
765 Lisp_Object)); | |
766 static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *, | |
767 Lisp_Object, | |
768 Lisp_Object, | |
769 char *, char *, | |
770 int)); | |
693 | 771 |
694 static struct x_frame_parm_table x_frame_parms[] = | 772 static struct x_frame_parm_table x_frame_parms[] = |
695 { | 773 { |
696 "auto-raise", x_set_autoraise, | 774 "auto-raise", x_set_autoraise, |
697 "auto-lower", x_set_autolower, | 775 "auto-lower", x_set_autolower, |
711 "scroll-bar-width", x_set_scroll_bar_width, | 789 "scroll-bar-width", x_set_scroll_bar_width, |
712 "title", x_set_title, | 790 "title", x_set_title, |
713 "unsplittable", x_set_unsplittable, | 791 "unsplittable", x_set_unsplittable, |
714 "vertical-scroll-bars", x_set_vertical_scroll_bars, | 792 "vertical-scroll-bars", x_set_vertical_scroll_bars, |
715 "visibility", x_set_visibility, | 793 "visibility", x_set_visibility, |
794 "toolbar-lines", x_set_toolbar_lines, | |
795 "scroll-bar-foreground", x_set_scroll_bar_foreground, | |
796 "scroll-bar-background", x_set_scroll_bar_background, | |
716 }; | 797 }; |
717 | 798 |
718 /* Attach the `x-frame-parameter' properties to | 799 /* Attach the `x-frame-parameter' properties to |
719 the Lisp symbol names of parameters relevant to X. */ | 800 the Lisp symbol names of parameters relevant to X. */ |
720 | 801 |
769 /* Extract parm names and values into those vectors. */ | 850 /* Extract parm names and values into those vectors. */ |
770 | 851 |
771 i = 0; | 852 i = 0; |
772 for (tail = alist; CONSP (tail); tail = Fcdr (tail)) | 853 for (tail = alist; CONSP (tail); tail = Fcdr (tail)) |
773 { | 854 { |
774 Lisp_Object elt, prop, val; | 855 Lisp_Object elt; |
775 | 856 |
776 elt = Fcar (tail); | 857 elt = Fcar (tail); |
777 parms[i] = Fcar (elt); | 858 parms[i] = Fcar (elt); |
778 values[i] = Fcdr (elt); | 859 values[i] = Fcdr (elt); |
779 i++; | 860 i++; |
976 | 1057 |
977 /* This is pretty gross, but seems to be the easiest way out of | 1058 /* This is pretty gross, but seems to be the easiest way out of |
978 the problem that arises when restarting window-managers. */ | 1059 the problem that arises when restarting window-managers. */ |
979 | 1060 |
980 #ifdef USE_X_TOOLKIT | 1061 #ifdef USE_X_TOOLKIT |
981 Window outer = XtWindow (f->output_data.x->widget); | 1062 Window outer = (f->output_data.x->widget |
1063 ? XtWindow (f->output_data.x->widget) | |
1064 : FRAME_X_WINDOW (f)); | |
982 #else | 1065 #else |
983 Window outer = f->output_data.x->window_desc; | 1066 Window outer = f->output_data.x->window_desc; |
984 #endif | 1067 #endif |
985 Window tmp_root_window; | 1068 Window tmp_root_window; |
986 Window *tmp_children; | 1069 Window *tmp_children; |
1029 } | 1112 } |
1030 | 1113 |
1031 x_uncatch_errors (FRAME_X_DISPLAY (f), count); | 1114 x_uncatch_errors (FRAME_X_DISPLAY (f), count); |
1032 } | 1115 } |
1033 | 1116 |
1034 *xptr = win_x - f->output_data.x->border_width; | 1117 *xptr = win_x; |
1035 *yptr = win_y - f->output_data.x->border_width; | 1118 *yptr = win_y; |
1036 } | 1119 } |
1037 | 1120 |
1038 /* Insert a description of internally-recorded parameters of frame X | 1121 /* Insert a description of internally-recorded parameters of frame X |
1039 into the parameter alist *ALISTPTR that is to be given to the user. | 1122 into the parameter alist *ALISTPTR that is to be given to the user. |
1040 Only parameters that are specific to the X window system | 1123 Only parameters that are specific to the X window system |
1068 store_in_alist (alistptr, Qinternal_border_width, | 1151 store_in_alist (alistptr, Qinternal_border_width, |
1069 make_number (f->output_data.x->internal_border_width)); | 1152 make_number (f->output_data.x->internal_border_width)); |
1070 sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f)); | 1153 sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f)); |
1071 store_in_alist (alistptr, Qwindow_id, | 1154 store_in_alist (alistptr, Qwindow_id, |
1072 build_string (buf)); | 1155 build_string (buf)); |
1073 sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f)); | 1156 #ifdef USE_X_TOOLKIT |
1157 /* Tooltip frame may not have this widget. */ | |
1158 if (f->output_data.x->widget) | |
1159 #endif | |
1160 sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f)); | |
1074 store_in_alist (alistptr, Qouter_window_id, | 1161 store_in_alist (alistptr, Qouter_window_id, |
1075 build_string (buf)); | 1162 build_string (buf)); |
1076 store_in_alist (alistptr, Qicon_name, f->icon_name); | 1163 store_in_alist (alistptr, Qicon_name, f->icon_name); |
1077 FRAME_SAMPLE_VISIBILITY (f); | 1164 FRAME_SAMPLE_VISIBILITY (f); |
1078 store_in_alist (alistptr, Qvisibility, | 1165 store_in_alist (alistptr, Qvisibility, |
1297 x_set_mouse_color (f, arg, oldval) | 1384 x_set_mouse_color (f, arg, oldval) |
1298 struct frame *f; | 1385 struct frame *f; |
1299 Lisp_Object arg, oldval; | 1386 Lisp_Object arg, oldval; |
1300 { | 1387 { |
1301 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor; | 1388 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor; |
1389 Cursor busy_cursor; | |
1302 int count; | 1390 int count; |
1303 int mask_color; | 1391 int mask_color; |
1304 unsigned long pixel = f->output_data.x->mouse_pixel; | 1392 unsigned long pixel = f->output_data.x->mouse_pixel; |
1305 | 1393 |
1306 if (!EQ (Qnil, arg)) | 1394 if (!EQ (Qnil, arg)) |
1341 } | 1429 } |
1342 else | 1430 else |
1343 nontext_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_left_ptr); | 1431 nontext_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_left_ptr); |
1344 x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s"); | 1432 x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s"); |
1345 | 1433 |
1434 if (!EQ (Qnil, Vx_busy_pointer_shape)) | |
1435 { | |
1436 CHECK_NUMBER (Vx_busy_pointer_shape, 0); | |
1437 busy_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), | |
1438 XINT (Vx_busy_pointer_shape)); | |
1439 } | |
1440 else | |
1441 busy_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_watch); | |
1442 x_check_errors (FRAME_X_DISPLAY (f), "bad busy pointer cursor: %s"); | |
1443 | |
1444 x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s"); | |
1346 if (!EQ (Qnil, Vx_mode_pointer_shape)) | 1445 if (!EQ (Qnil, Vx_mode_pointer_shape)) |
1347 { | 1446 { |
1348 CHECK_NUMBER (Vx_mode_pointer_shape, 0); | 1447 CHECK_NUMBER (Vx_mode_pointer_shape, 0); |
1349 mode_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), | 1448 mode_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), |
1350 XINT (Vx_mode_pointer_shape)); | 1449 XINT (Vx_mode_pointer_shape)); |
1386 &fore_color, &back_color); | 1485 &fore_color, &back_color); |
1387 XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor, | 1486 XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor, |
1388 &fore_color, &back_color); | 1487 &fore_color, &back_color); |
1389 XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor, | 1488 XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor, |
1390 &fore_color, &back_color); | 1489 &fore_color, &back_color); |
1490 XRecolorCursor (FRAME_X_DISPLAY (f), busy_cursor, | |
1491 &fore_color, &back_color); | |
1391 } | 1492 } |
1392 | 1493 |
1393 if (FRAME_X_WINDOW (f) != 0) | 1494 if (FRAME_X_WINDOW (f) != 0) |
1394 { | 1495 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); |
1395 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); | |
1396 } | |
1397 | 1496 |
1398 if (cursor != f->output_data.x->text_cursor && f->output_data.x->text_cursor != 0) | 1497 if (cursor != f->output_data.x->text_cursor && f->output_data.x->text_cursor != 0) |
1399 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor); | 1498 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor); |
1400 f->output_data.x->text_cursor = cursor; | 1499 f->output_data.x->text_cursor = cursor; |
1401 | 1500 |
1402 if (nontext_cursor != f->output_data.x->nontext_cursor | 1501 if (nontext_cursor != f->output_data.x->nontext_cursor |
1403 && f->output_data.x->nontext_cursor != 0) | 1502 && f->output_data.x->nontext_cursor != 0) |
1404 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor); | 1503 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor); |
1405 f->output_data.x->nontext_cursor = nontext_cursor; | 1504 f->output_data.x->nontext_cursor = nontext_cursor; |
1406 | 1505 |
1506 if (busy_cursor != f->output_data.x->busy_cursor | |
1507 && f->output_data.x->busy_cursor != 0) | |
1508 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->busy_cursor); | |
1509 f->output_data.x->busy_cursor = busy_cursor; | |
1510 | |
1407 if (mode_cursor != f->output_data.x->modeline_cursor | 1511 if (mode_cursor != f->output_data.x->modeline_cursor |
1408 && f->output_data.x->modeline_cursor != 0) | 1512 && f->output_data.x->modeline_cursor != 0) |
1409 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor); | 1513 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor); |
1410 f->output_data.x->modeline_cursor = mode_cursor; | 1514 f->output_data.x->modeline_cursor = mode_cursor; |
1515 | |
1411 if (cross_cursor != f->output_data.x->cross_cursor | 1516 if (cross_cursor != f->output_data.x->cross_cursor |
1412 && f->output_data.x->cross_cursor != 0) | 1517 && f->output_data.x->cross_cursor != 0) |
1413 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor); | 1518 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor); |
1414 f->output_data.x->cross_cursor = cross_cursor; | 1519 f->output_data.x->cross_cursor = cross_cursor; |
1415 | 1520 |
1529 FRAME_PTR f; | 1634 FRAME_PTR f; |
1530 Lisp_Object arg, oldval; | 1635 Lisp_Object arg, oldval; |
1531 { | 1636 { |
1532 if (EQ (arg, Qbar)) | 1637 if (EQ (arg, Qbar)) |
1533 { | 1638 { |
1534 FRAME_DESIRED_CURSOR (f) = bar_cursor; | 1639 FRAME_DESIRED_CURSOR (f) = BAR_CURSOR; |
1535 f->output_data.x->cursor_width = 2; | 1640 f->output_data.x->cursor_width = 2; |
1536 } | 1641 } |
1537 else if (CONSP (arg) && EQ (XCONS (arg)->car, Qbar) | 1642 else if (CONSP (arg) && EQ (XCONS (arg)->car, Qbar) |
1538 && INTEGERP (XCONS (arg)->cdr)) | 1643 && INTEGERP (XCONS (arg)->cdr)) |
1539 { | 1644 { |
1540 FRAME_DESIRED_CURSOR (f) = bar_cursor; | 1645 FRAME_DESIRED_CURSOR (f) = BAR_CURSOR; |
1541 f->output_data.x->cursor_width = XINT (XCONS (arg)->cdr); | 1646 f->output_data.x->cursor_width = XINT (XCONS (arg)->cdr); |
1542 } | 1647 } |
1543 else | 1648 else |
1544 /* Treat anything unknown as "box cursor". | 1649 /* Treat anything unknown as "box cursor". |
1545 It was bad to signal an error; people have trouble fixing | 1650 It was bad to signal an error; people have trouble fixing |
1546 .Xdefaults with Emacs, when it has something bad in it. */ | 1651 .Xdefaults with Emacs, when it has something bad in it. */ |
1547 FRAME_DESIRED_CURSOR (f) = filled_box_cursor; | 1652 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR; |
1548 | 1653 |
1549 /* Make sure the cursor gets redrawn. This is overkill, but how | 1654 /* Make sure the cursor gets redrawn. This is overkill, but how |
1550 often do people change cursor types? */ | 1655 often do people change cursor types? */ |
1551 update_mode_lines++; | 1656 update_mode_lines++; |
1552 } | 1657 } |
1554 void | 1659 void |
1555 x_set_icon_type (f, arg, oldval) | 1660 x_set_icon_type (f, arg, oldval) |
1556 struct frame *f; | 1661 struct frame *f; |
1557 Lisp_Object arg, oldval; | 1662 Lisp_Object arg, oldval; |
1558 { | 1663 { |
1559 Lisp_Object tem; | |
1560 int result; | 1664 int result; |
1561 | 1665 |
1562 if (STRINGP (arg)) | 1666 if (STRINGP (arg)) |
1563 { | 1667 { |
1564 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) | 1668 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) |
1604 void | 1708 void |
1605 x_set_icon_name (f, arg, oldval) | 1709 x_set_icon_name (f, arg, oldval) |
1606 struct frame *f; | 1710 struct frame *f; |
1607 Lisp_Object arg, oldval; | 1711 Lisp_Object arg, oldval; |
1608 { | 1712 { |
1609 Lisp_Object tem; | |
1610 int result; | 1713 int result; |
1611 | 1714 |
1612 if (STRINGP (arg)) | 1715 if (STRINGP (arg)) |
1613 { | 1716 { |
1614 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) | 1717 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) |
1664 error ("Font `%s' is not defined", XSTRING (arg)->data); | 1767 error ("Font `%s' is not defined", XSTRING (arg)->data); |
1665 else if (EQ (result, Qt)) | 1768 else if (EQ (result, Qt)) |
1666 error ("The characters of the given font have varying widths"); | 1769 error ("The characters of the given font have varying widths"); |
1667 else if (STRINGP (result)) | 1770 else if (STRINGP (result)) |
1668 { | 1771 { |
1772 store_frame_param (f, Qfont, result); | |
1669 recompute_basic_faces (f); | 1773 recompute_basic_faces (f); |
1670 store_frame_param (f, Qfont, result); | |
1671 } | 1774 } |
1672 else | 1775 else |
1673 abort (); | 1776 abort (); |
1674 | 1777 |
1675 XSETFRAME (frame, f); | 1778 /* Don't call `face-set-after-frame-default' when faces haven't been |
1676 call1 (Qface_set_after_frame_default, frame); | 1779 initialized yet. This is the case when called from |
1780 Fx_create_frame. In that case, the X widget or window doesn't | |
1781 exist either, and we can end up in x_report_frame_params with a | |
1782 null widget which gives a segfault. */ | |
1783 if (FRAME_FACE_CACHE (f)) | |
1784 { | |
1785 XSETFRAME (frame, f); | |
1786 call1 (Qface_set_after_frame_default, frame); | |
1787 } | |
1677 } | 1788 } |
1678 | 1789 |
1679 void | 1790 void |
1680 x_set_border_width (f, arg, oldval) | 1791 x_set_border_width (f, arg, oldval) |
1681 struct frame *f; | 1792 struct frame *f; |
1695 void | 1806 void |
1696 x_set_internal_border_width (f, arg, oldval) | 1807 x_set_internal_border_width (f, arg, oldval) |
1697 struct frame *f; | 1808 struct frame *f; |
1698 Lisp_Object arg, oldval; | 1809 Lisp_Object arg, oldval; |
1699 { | 1810 { |
1700 int mask; | |
1701 int old = f->output_data.x->internal_border_width; | 1811 int old = f->output_data.x->internal_border_width; |
1702 | 1812 |
1703 CHECK_NUMBER (arg, 0); | 1813 CHECK_NUMBER (arg, 0); |
1704 f->output_data.x->internal_border_width = XINT (arg); | 1814 f->output_data.x->internal_border_width = XINT (arg); |
1705 if (f->output_data.x->internal_border_width < 0) | 1815 if (f->output_data.x->internal_border_width < 0) |
1772 int nlines; | 1882 int nlines; |
1773 int olines = FRAME_MENU_BAR_LINES (f); | 1883 int olines = FRAME_MENU_BAR_LINES (f); |
1774 | 1884 |
1775 /* Right now, menu bars don't work properly in minibuf-only frames; | 1885 /* Right now, menu bars don't work properly in minibuf-only frames; |
1776 most of the commands try to apply themselves to the minibuffer | 1886 most of the commands try to apply themselves to the minibuffer |
1777 frame itslef, and get an error because you can't switch buffers | 1887 frame itself, and get an error because you can't switch buffers |
1778 in or split the minibuffer window. */ | 1888 in or split the minibuffer window. */ |
1779 if (FRAME_MINIBUF_ONLY_P (f)) | 1889 if (FRAME_MINIBUF_ONLY_P (f)) |
1780 return; | 1890 return; |
1781 | 1891 |
1782 if (INTEGERP (value)) | 1892 if (INTEGERP (value)) |
1806 } | 1916 } |
1807 #else /* not USE_X_TOOLKIT */ | 1917 #else /* not USE_X_TOOLKIT */ |
1808 FRAME_MENU_BAR_LINES (f) = nlines; | 1918 FRAME_MENU_BAR_LINES (f) = nlines; |
1809 x_set_menu_bar_lines_1 (f->root_window, nlines - olines); | 1919 x_set_menu_bar_lines_1 (f->root_window, nlines - olines); |
1810 #endif /* not USE_X_TOOLKIT */ | 1920 #endif /* not USE_X_TOOLKIT */ |
1811 } | 1921 adjust_glyphs (f); |
1922 } | |
1923 | |
1924 | |
1925 /* Set the number of lines used for the tool bar of frame F to VALUE. | |
1926 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | |
1927 is the old number of tool bar lines. This function changes the | |
1928 height of all windows on frame F to match the new tool bar height. | |
1929 The frame's height doesn't change. */ | |
1930 | |
1931 void | |
1932 x_set_toolbar_lines (f, value, oldval) | |
1933 struct frame *f; | |
1934 Lisp_Object value, oldval; | |
1935 { | |
1936 int delta, nlines; | |
1937 | |
1938 /* Use VALUE only if an integer >= 0. */ | |
1939 if (INTEGERP (value) && XINT (value) >= 0) | |
1940 nlines = XFASTINT (value); | |
1941 else | |
1942 nlines = 0; | |
1943 | |
1944 /* Make sure we redisplay all windows in this frame. */ | |
1945 ++windows_or_buffers_changed; | |
1946 | |
1947 delta = nlines - FRAME_TOOLBAR_LINES (f); | |
1948 FRAME_TOOLBAR_LINES (f) = nlines; | |
1949 x_set_menu_bar_lines_1 (FRAME_ROOT_WINDOW (f), delta); | |
1950 adjust_glyphs (f); | |
1951 } | |
1952 | |
1953 | |
1954 /* Set the foreground color for scroll bars on frame F to VALUE. | |
1955 VALUE should be a string, a color name. If it isn't a string or | |
1956 isn't a valid color name, do nothing. OLDVAL is the old value of | |
1957 the frame parameter. */ | |
1958 | |
1959 void | |
1960 x_set_scroll_bar_foreground (f, value, oldval) | |
1961 struct frame *f; | |
1962 Lisp_Object value, oldval; | |
1963 { | |
1964 unsigned long pixel; | |
1965 | |
1966 if (STRINGP (value)) | |
1967 pixel = x_decode_color (f, value, BLACK_PIX_DEFAULT (f)); | |
1968 else | |
1969 pixel = -1; | |
1970 | |
1971 if (f->output_data.x->scroll_bar_foreground_pixel != -1) | |
1972 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel); | |
1973 | |
1974 f->output_data.x->scroll_bar_foreground_pixel = pixel; | |
1975 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f)) | |
1976 { | |
1977 /* Remove all scroll bars because they have wrong colors. */ | |
1978 if (condemn_scroll_bars_hook) | |
1979 (*condemn_scroll_bars_hook) (f); | |
1980 if (judge_scroll_bars_hook) | |
1981 (*judge_scroll_bars_hook) (f); | |
1982 | |
1983 redraw_frame (f); | |
1984 } | |
1985 } | |
1986 | |
1987 | |
1988 /* Set the background color for scroll bars on frame F to VALUE VALUE | |
1989 should be a string, a color name. If it isn't a string or isn't a | |
1990 valid color name, do nothing. OLDVAL is the old value of the frame | |
1991 parameter. */ | |
1992 | |
1993 void | |
1994 x_set_scroll_bar_background (f, value, oldval) | |
1995 struct frame *f; | |
1996 Lisp_Object value, oldval; | |
1997 { | |
1998 unsigned long pixel; | |
1999 | |
2000 if (STRINGP (value)) | |
2001 pixel = x_decode_color (f, value, WHITE_PIX_DEFAULT (f)); | |
2002 else | |
2003 pixel = -1; | |
2004 | |
2005 if (f->output_data.x->scroll_bar_background_pixel != -1) | |
2006 unload_color (f, f->output_data.x->scroll_bar_background_pixel); | |
2007 | |
2008 f->output_data.x->scroll_bar_background_pixel = pixel; | |
2009 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f)) | |
2010 { | |
2011 /* Remove all scroll bars because they have wrong colors. */ | |
2012 if (condemn_scroll_bars_hook) | |
2013 (*condemn_scroll_bars_hook) (f); | |
2014 if (judge_scroll_bars_hook) | |
2015 (*judge_scroll_bars_hook) (f); | |
2016 | |
2017 redraw_frame (f); | |
2018 } | |
2019 } | |
2020 | |
1812 | 2021 |
1813 /* Change the name of frame F to NAME. If NAME is nil, set F's name to | 2022 /* Change the name of frame F to NAME. If NAME is nil, set F's name to |
1814 x_id_name. | 2023 x_id_name. |
1815 | 2024 |
1816 If EXPLICIT is non-zero, that indicates that lisp code is setting the | 2025 If EXPLICIT is non-zero, that indicates that lisp code is setting the |
2051 { | 2260 { |
2052 int wid = FONT_WIDTH (f->output_data.x->font); | 2261 int wid = FONT_WIDTH (f->output_data.x->font); |
2053 | 2262 |
2054 if (NILP (arg)) | 2263 if (NILP (arg)) |
2055 { | 2264 { |
2056 /* Make the actual width at least 14 pixels | 2265 #ifdef USE_X_TOOLKIT |
2057 and a multiple of a character width. */ | 2266 /* A too wide or narrow toolkit scroll bar doesn't look good. */ |
2267 int width = 16 + 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM; | |
2268 FRAME_SCROLL_BAR_COLS (f) = (width + wid - 1) / wid; | |
2269 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = width; | |
2270 #else | |
2271 /* Make the actual width at least 14 pixels and a multiple of a | |
2272 character width. */ | |
2058 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid; | 2273 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid; |
2059 /* Use all of that space (aside from required margins) | 2274 |
2060 for the scroll bar. */ | 2275 /* Use all of that space (aside from required margins) for the |
2276 scroll bar. */ | |
2061 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0; | 2277 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0; |
2278 #endif | |
2062 | 2279 |
2063 if (FRAME_X_WINDOW (f)) | 2280 if (FRAME_X_WINDOW (f)) |
2064 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); | 2281 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); |
2065 } | 2282 } |
2066 else if (INTEGERP (arg) && XINT (arg) > 0 | 2283 else if (INTEGERP (arg) && XINT (arg) > 0 |
2074 if (FRAME_X_WINDOW (f)) | 2291 if (FRAME_X_WINDOW (f)) |
2075 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); | 2292 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); |
2076 } | 2293 } |
2077 | 2294 |
2078 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0); | 2295 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0); |
2079 FRAME_CURSOR_X (f) = FRAME_LEFT_SCROLL_BAR_WIDTH (f); | 2296 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0; |
2080 } | 2297 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0; |
2298 } | |
2299 | |
2300 | |
2081 | 2301 |
2082 /* Subroutines of creating an X frame. */ | 2302 /* Subroutines of creating an X frame. */ |
2083 | 2303 |
2084 /* Make sure that Vx_resource_name is set to a reasonable value. | 2304 /* Make sure that Vx_resource_name is set to a reasonable value. |
2085 Fix it up, or set it to `emacs' if it is too hopeless. */ | 2305 Fix it up, or set it to `emacs' if it is too hopeless. */ |
2086 | 2306 |
2087 static void | 2307 static void |
2088 validate_x_resource_name () | 2308 validate_x_resource_name () |
2089 { | 2309 { |
2090 int len; | 2310 int len = 0; |
2091 /* Number of valid characters in the resource name. */ | 2311 /* Number of valid characters in the resource name. */ |
2092 int good_count = 0; | 2312 int good_count = 0; |
2093 /* Number of invalid characters in the resource name. */ | 2313 /* Number of invalid characters in the resource name. */ |
2094 int bad_count = 0; | 2314 int bad_count = 0; |
2095 Lisp_Object new; | 2315 Lisp_Object new; |
2228 return Qnil; | 2448 return Qnil; |
2229 } | 2449 } |
2230 | 2450 |
2231 /* Get an X resource, like Fx_get_resource, but for display DPYINFO. */ | 2451 /* Get an X resource, like Fx_get_resource, but for display DPYINFO. */ |
2232 | 2452 |
2233 static Lisp_Object | 2453 Lisp_Object |
2234 display_x_get_resource (dpyinfo, attribute, class, component, subclass) | 2454 display_x_get_resource (dpyinfo, attribute, class, component, subclass) |
2235 struct x_display_info *dpyinfo; | 2455 struct x_display_info *dpyinfo; |
2236 Lisp_Object attribute, class, component, subclass; | 2456 Lisp_Object attribute, class, component, subclass; |
2237 { | 2457 { |
2238 register char *value; | 2458 register char *value; |
2299 | 2519 |
2300 char * | 2520 char * |
2301 x_get_resource_string (attribute, class) | 2521 x_get_resource_string (attribute, class) |
2302 char *attribute, *class; | 2522 char *attribute, *class; |
2303 { | 2523 { |
2304 register char *value; | |
2305 char *name_key; | 2524 char *name_key; |
2306 char *class_key; | 2525 char *class_key; |
2307 | 2526 |
2308 /* Allocate space for the components, the dots which separate them, | 2527 /* Allocate space for the components, the dots which separate them, |
2309 and the final '\0'. */ | 2528 and the final '\0'. */ |
2321 name_key, class_key); | 2540 name_key, class_key); |
2322 } | 2541 } |
2323 | 2542 |
2324 /* Types we might convert a resource string into. */ | 2543 /* Types we might convert a resource string into. */ |
2325 enum resource_types | 2544 enum resource_types |
2326 { | 2545 { |
2327 number, boolean, string, symbol | 2546 RES_TYPE_NUMBER, |
2328 }; | 2547 RES_TYPE_BOOLEAN, |
2548 RES_TYPE_STRING, | |
2549 RES_TYPE_SYMBOL | |
2550 }; | |
2329 | 2551 |
2330 /* Return the value of parameter PARAM. | 2552 /* Return the value of parameter PARAM. |
2331 | 2553 |
2332 First search ALIST, then Vdefault_frame_alist, then the X defaults | 2554 First search ALIST, then Vdefault_frame_alist, then the X defaults |
2333 database, using ATTRIBUTE as the attribute name and CLASS as its class. | 2555 database, using ATTRIBUTE as the attribute name and CLASS as its class. |
2364 if (NILP (tem)) | 2586 if (NILP (tem)) |
2365 return Qunbound; | 2587 return Qunbound; |
2366 | 2588 |
2367 switch (type) | 2589 switch (type) |
2368 { | 2590 { |
2369 case number: | 2591 case RES_TYPE_NUMBER: |
2370 return make_number (atoi (XSTRING (tem)->data)); | 2592 return make_number (atoi (XSTRING (tem)->data)); |
2371 | 2593 |
2372 case boolean: | 2594 case RES_TYPE_BOOLEAN: |
2373 tem = Fdowncase (tem); | 2595 tem = Fdowncase (tem); |
2374 if (!strcmp (XSTRING (tem)->data, "on") | 2596 if (!strcmp (XSTRING (tem)->data, "on") |
2375 || !strcmp (XSTRING (tem)->data, "true")) | 2597 || !strcmp (XSTRING (tem)->data, "true")) |
2376 return Qt; | 2598 return Qt; |
2377 else | 2599 else |
2378 return Qnil; | 2600 return Qnil; |
2379 | 2601 |
2380 case string: | 2602 case RES_TYPE_STRING: |
2381 return tem; | 2603 return tem; |
2382 | 2604 |
2383 case symbol: | 2605 case RES_TYPE_SYMBOL: |
2384 /* As a special case, we map the values `true' and `on' | 2606 /* As a special case, we map the values `true' and `on' |
2385 to Qt, and `false' and `off' to Qnil. */ | 2607 to Qt, and `false' and `off' to Qnil. */ |
2386 { | 2608 { |
2387 Lisp_Object lower; | 2609 Lisp_Object lower; |
2388 lower = Fdowncase (tem); | 2610 lower = Fdowncase (tem); |
2448 if (EQ (tem, Qunbound)) | 2670 if (EQ (tem, Qunbound)) |
2449 tem = deflt; | 2671 tem = deflt; |
2450 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil)); | 2672 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil)); |
2451 return tem; | 2673 return tem; |
2452 } | 2674 } |
2675 | |
2676 | |
2677 /* Record in frame F the specified or default value according to ALIST | |
2678 of the parameter named PROP (a Lisp symbol). If no value is | |
2679 specified for PROP, look for an X default for XPROP on the frame | |
2680 named NAME. If that is not found either, use the value DEFLT. */ | |
2681 | |
2682 static Lisp_Object | |
2683 x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass, | |
2684 foreground_p) | |
2685 struct frame *f; | |
2686 Lisp_Object alist; | |
2687 Lisp_Object prop; | |
2688 char *xprop; | |
2689 char *xclass; | |
2690 int foreground_p; | |
2691 { | |
2692 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | |
2693 Lisp_Object tem; | |
2694 | |
2695 tem = x_get_arg (dpyinfo, alist, prop, xprop, xclass, RES_TYPE_STRING); | |
2696 if (EQ (tem, Qunbound)) | |
2697 { | |
2698 #ifdef USE_TOOLKIT_SCROLL_BARS | |
2699 | |
2700 /* See if an X resource for the scroll bar color has been | |
2701 specified. */ | |
2702 tem = display_x_get_resource (dpyinfo, | |
2703 build_string (foreground_p | |
2704 ? "foreground" | |
2705 : "background"), | |
2706 build_string (""), | |
2707 build_string ("verticalScrollBar"), | |
2708 build_string ("")); | |
2709 if (!STRINGP (tem)) | |
2710 { | |
2711 /* If nothing has been specified, scroll bars will use a | |
2712 toolkit-dependent default. Because these defaults are | |
2713 difficult to get at without actually creating a scroll | |
2714 bar, use nil to indicate that no color has been | |
2715 specified. */ | |
2716 tem = Qnil; | |
2717 } | |
2718 | |
2719 #else /* not USE_TOOLKIT_SCROLL_BARS */ | |
2720 | |
2721 tem = Qnil; | |
2722 | |
2723 #endif /* not USE_TOOLKIT_SCROLL_BARS */ | |
2724 } | |
2725 | |
2726 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil)); | |
2727 return tem; | |
2728 } | |
2729 | |
2730 | |
2453 | 2731 |
2454 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0, | 2732 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0, |
2455 "Parse an X-style geometry string STRING.\n\ | 2733 "Parse an X-style geometry string STRING.\n\ |
2456 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\ | 2734 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\ |
2457 The properties returned may include `top', `left', `height', and `width'.\n\ | 2735 The properties returned may include `top', `left', `height', and `width'.\n\ |
2537 /* Window managers expect that if program-specified | 2815 /* Window managers expect that if program-specified |
2538 positions are not (0,0), they're intentional, not defaults. */ | 2816 positions are not (0,0), they're intentional, not defaults. */ |
2539 f->output_data.x->top_pos = 0; | 2817 f->output_data.x->top_pos = 0; |
2540 f->output_data.x->left_pos = 0; | 2818 f->output_data.x->left_pos = 0; |
2541 | 2819 |
2542 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, number); | 2820 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER); |
2543 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, number); | 2821 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER); |
2544 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, number); | 2822 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER); |
2545 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) | 2823 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) |
2546 { | 2824 { |
2547 if (!EQ (tem0, Qunbound)) | 2825 if (!EQ (tem0, Qunbound)) |
2548 { | 2826 { |
2549 CHECK_NUMBER (tem0, 0); | 2827 CHECK_NUMBER (tem0, 0); |
2561 } | 2839 } |
2562 | 2840 |
2563 f->output_data.x->vertical_scroll_bar_extra | 2841 f->output_data.x->vertical_scroll_bar_extra |
2564 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) | 2842 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) |
2565 ? 0 | 2843 ? 0 |
2566 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0 | |
2567 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f) | |
2568 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font))); | 2844 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font))); |
2845 f->output_data.x->flags_areas_extra | |
2846 = 2 * FRAME_FLAGS_AREA_WIDTH (f); | |
2569 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width); | 2847 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width); |
2570 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height); | 2848 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height); |
2571 | 2849 |
2572 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, number); | 2850 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER); |
2573 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, number); | 2851 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER); |
2574 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, number); | 2852 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER); |
2575 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) | 2853 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) |
2576 { | 2854 { |
2577 if (EQ (tem0, Qminus)) | 2855 if (EQ (tem0, Qminus)) |
2578 { | 2856 { |
2579 f->output_data.x->top_pos = 0; | 2857 f->output_data.x->top_pos = 0; |
2916 #ifdef HACK_EDITRES | 3194 #ifdef HACK_EDITRES |
2917 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0); | 3195 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0); |
2918 #endif | 3196 #endif |
2919 | 3197 |
2920 /* Do a stupid property change to force the server to generate a | 3198 /* Do a stupid property change to force the server to generate a |
2921 propertyNotify event so that the event_stream server timestamp will | 3199 PropertyNotify event so that the event_stream server timestamp will |
2922 be initialized to something relevant to the time we created the window. | 3200 be initialized to something relevant to the time we created the window. |
2923 */ | 3201 */ |
2924 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget), | 3202 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget), |
2925 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols, | 3203 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols, |
2926 XA_ATOM, 32, PropModeAppend, | 3204 XA_ATOM, 32, PropModeAppend, |
3096 Lisp_Object icon_x, icon_y; | 3374 Lisp_Object icon_x, icon_y; |
3097 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | 3375 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); |
3098 | 3376 |
3099 /* Set the position of the icon. Note that twm groups all | 3377 /* Set the position of the icon. Note that twm groups all |
3100 icons in an icon window. */ | 3378 icons in an icon window. */ |
3101 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, number); | 3379 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER); |
3102 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, number); | 3380 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER); |
3103 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) | 3381 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) |
3104 { | 3382 { |
3105 CHECK_NUMBER (icon_x, 0); | 3383 CHECK_NUMBER (icon_x, 0); |
3106 CHECK_NUMBER (icon_y, 0); | 3384 CHECK_NUMBER (icon_y, 0); |
3107 } | 3385 } |
3113 if (! EQ (icon_x, Qunbound)) | 3391 if (! EQ (icon_x, Qunbound)) |
3114 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y)); | 3392 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y)); |
3115 | 3393 |
3116 /* Start up iconic or window? */ | 3394 /* Start up iconic or window? */ |
3117 x_wm_set_window_state | 3395 x_wm_set_window_state |
3118 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, symbol), Qicon) | 3396 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), |
3397 Qicon) | |
3119 ? IconicState | 3398 ? IconicState |
3120 : NormalState)); | 3399 : NormalState)); |
3121 | 3400 |
3122 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name) | 3401 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name) |
3123 ? f->icon_name | 3402 ? f->icon_name |
3141 static void | 3420 static void |
3142 x_make_gc (f) | 3421 x_make_gc (f) |
3143 struct frame *f; | 3422 struct frame *f; |
3144 { | 3423 { |
3145 XGCValues gc_values; | 3424 XGCValues gc_values; |
3146 GC temp_gc; | |
3147 XImage tileimage; | |
3148 | 3425 |
3149 BLOCK_INPUT; | 3426 BLOCK_INPUT; |
3150 | 3427 |
3151 /* Create the GC's of this frame. | 3428 /* Create the GC's of this frame. |
3152 Note that many default values are used. */ | 3429 Note that many default values are used. */ |
3183 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | 3460 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), |
3184 (GCFont | GCForeground | GCBackground | 3461 (GCFont | GCForeground | GCBackground |
3185 | GCFillStyle /* | GCStipple */ | GCLineWidth), | 3462 | GCFillStyle /* | GCStipple */ | GCLineWidth), |
3186 &gc_values); | 3463 &gc_values); |
3187 | 3464 |
3465 /* Reliefs. */ | |
3466 f->output_data.x->white_relief.gc = 0; | |
3467 f->output_data.x->black_relief.gc = 0; | |
3468 | |
3188 /* Create the gray border tile used when the pointer is not in | 3469 /* Create the gray border tile used when the pointer is not in |
3189 the frame. Since this depends on the frame's pixel values, | 3470 the frame. Since this depends on the frame's pixel values, |
3190 this must be done on a per-frame basis. */ | 3471 this must be done on a per-frame basis. */ |
3191 f->output_data.x->border_tile | 3472 f->output_data.x->border_tile |
3192 = (XCreatePixmapFromBitmapData | 3473 = (XCreatePixmapFromBitmapData |
3221 long window_prompting = 0; | 3502 long window_prompting = 0; |
3222 int width, height; | 3503 int width, height; |
3223 int count = specpdl_ptr - specpdl; | 3504 int count = specpdl_ptr - specpdl; |
3224 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | 3505 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; |
3225 Lisp_Object display; | 3506 Lisp_Object display; |
3226 struct x_display_info *dpyinfo; | 3507 struct x_display_info *dpyinfo = NULL; |
3227 Lisp_Object parent; | 3508 Lisp_Object parent; |
3228 struct kboard *kb; | 3509 struct kboard *kb; |
3229 | 3510 |
3230 check_x (); | 3511 check_x (); |
3231 | 3512 |
3232 /* Use this general default value to start with | 3513 /* Use this general default value to start with |
3233 until we know if this frame has a specified name. */ | 3514 until we know if this frame has a specified name. */ |
3234 Vx_resource_name = Vinvocation_name; | 3515 Vx_resource_name = Vinvocation_name; |
3235 | 3516 |
3236 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, string); | 3517 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING); |
3237 if (EQ (display, Qunbound)) | 3518 if (EQ (display, Qunbound)) |
3238 display = Qnil; | 3519 display = Qnil; |
3239 dpyinfo = check_x_display_info (display); | 3520 dpyinfo = check_x_display_info (display); |
3240 #ifdef MULTI_KBOARD | 3521 #ifdef MULTI_KBOARD |
3241 kb = dpyinfo->kboard; | 3522 kb = dpyinfo->kboard; |
3242 #else | 3523 #else |
3243 kb = &the_only_kboard; | 3524 kb = &the_only_kboard; |
3244 #endif | 3525 #endif |
3245 | 3526 |
3246 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", string); | 3527 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING); |
3247 if (!STRINGP (name) | 3528 if (!STRINGP (name) |
3248 && ! EQ (name, Qunbound) | 3529 && ! EQ (name, Qunbound) |
3249 && ! NILP (name)) | 3530 && ! NILP (name)) |
3250 error ("Invalid frame name--not a string or nil"); | 3531 error ("Invalid frame name--not a string or nil"); |
3251 | 3532 |
3252 if (STRINGP (name)) | 3533 if (STRINGP (name)) |
3253 Vx_resource_name = name; | 3534 Vx_resource_name = name; |
3254 | 3535 |
3255 /* See if parent window is specified. */ | 3536 /* See if parent window is specified. */ |
3256 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, number); | 3537 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER); |
3257 if (EQ (parent, Qunbound)) | 3538 if (EQ (parent, Qunbound)) |
3258 parent = Qnil; | 3539 parent = Qnil; |
3259 if (! NILP (parent)) | 3540 if (! NILP (parent)) |
3260 CHECK_NUMBER (parent, 0); | 3541 CHECK_NUMBER (parent, 0); |
3261 | 3542 |
3262 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ | 3543 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ |
3263 /* No need to protect DISPLAY because that's not used after passing | 3544 /* No need to protect DISPLAY because that's not used after passing |
3264 it to make_frame_without_minibuffer. */ | 3545 it to make_frame_without_minibuffer. */ |
3265 frame = Qnil; | 3546 frame = Qnil; |
3266 GCPRO4 (parms, parent, name, frame); | 3547 GCPRO4 (parms, parent, name, frame); |
3267 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer", symbol); | 3548 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer", |
3549 RES_TYPE_SYMBOL); | |
3268 if (EQ (tem, Qnone) || NILP (tem)) | 3550 if (EQ (tem, Qnone) || NILP (tem)) |
3269 f = make_frame_without_minibuffer (Qnil, kb, display); | 3551 f = make_frame_without_minibuffer (Qnil, kb, display); |
3270 else if (EQ (tem, Qonly)) | 3552 else if (EQ (tem, Qonly)) |
3271 { | 3553 { |
3272 f = make_minibuffer_frame (); | 3554 f = make_minibuffer_frame (); |
3285 f->output_method = output_x_window; | 3567 f->output_method = output_x_window; |
3286 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output)); | 3568 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output)); |
3287 bzero (f->output_data.x, sizeof (struct x_output)); | 3569 bzero (f->output_data.x, sizeof (struct x_output)); |
3288 f->output_data.x->icon_bitmap = -1; | 3570 f->output_data.x->icon_bitmap = -1; |
3289 f->output_data.x->fontset = -1; | 3571 f->output_data.x->fontset = -1; |
3572 f->output_data.x->scroll_bar_foreground_pixel = -1; | |
3573 f->output_data.x->scroll_bar_background_pixel = -1; | |
3290 | 3574 |
3291 f->icon_name | 3575 f->icon_name |
3292 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title", string); | 3576 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title", |
3577 RES_TYPE_STRING); | |
3293 if (! STRINGP (f->icon_name)) | 3578 if (! STRINGP (f->icon_name)) |
3294 f->icon_name = Qnil; | 3579 f->icon_name = Qnil; |
3295 | 3580 |
3296 FRAME_X_DISPLAY_INFO (f) = dpyinfo; | 3581 FRAME_X_DISPLAY_INFO (f) = dpyinfo; |
3297 #ifdef MULTI_KBOARD | 3582 #ifdef MULTI_KBOARD |
3309 { | 3594 { |
3310 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; | 3595 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; |
3311 f->output_data.x->explicit_parent = 0; | 3596 f->output_data.x->explicit_parent = 0; |
3312 } | 3597 } |
3313 | 3598 |
3314 /* Note that the frame has no physical cursor right now. */ | |
3315 f->phys_cursor_x = -1; | |
3316 | |
3317 /* Set the name; the functions to which we pass f expect the name to | 3599 /* Set the name; the functions to which we pass f expect the name to |
3318 be set. */ | 3600 be set. */ |
3319 if (EQ (name, Qunbound) || NILP (name)) | 3601 if (EQ (name, Qunbound) || NILP (name)) |
3320 { | 3602 { |
3321 f->name = build_string (dpyinfo->x_id_name); | 3603 f->name = build_string (dpyinfo->x_id_name); |
3336 /* Extract the window parameters from the supplied values | 3618 /* Extract the window parameters from the supplied values |
3337 that are needed to determine window geometry. */ | 3619 that are needed to determine window geometry. */ |
3338 { | 3620 { |
3339 Lisp_Object font; | 3621 Lisp_Object font; |
3340 | 3622 |
3341 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", string); | 3623 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING); |
3342 | 3624 |
3343 BLOCK_INPUT; | 3625 BLOCK_INPUT; |
3344 /* First, try whatever font the caller has specified. */ | 3626 /* First, try whatever font the caller has specified. */ |
3345 if (STRINGP (font)) | 3627 if (STRINGP (font)) |
3346 { | 3628 { |
3348 if (STRINGP (tem)) | 3630 if (STRINGP (tem)) |
3349 font = x_new_fontset (f, XSTRING (tem)->data); | 3631 font = x_new_fontset (f, XSTRING (tem)->data); |
3350 else | 3632 else |
3351 font = x_new_font (f, XSTRING (font)->data); | 3633 font = x_new_font (f, XSTRING (font)->data); |
3352 } | 3634 } |
3635 | |
3353 /* Try out a font which we hope has bold and italic variations. */ | 3636 /* Try out a font which we hope has bold and italic variations. */ |
3637 if (!STRINGP (font)) | |
3638 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1"); | |
3354 if (!STRINGP (font)) | 3639 if (!STRINGP (font)) |
3355 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); | 3640 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); |
3356 if (! STRINGP (font)) | 3641 if (! STRINGP (font)) |
3357 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); | 3642 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); |
3358 if (! STRINGP (font)) | 3643 if (! STRINGP (font)) |
3365 UNBLOCK_INPUT; | 3650 UNBLOCK_INPUT; |
3366 if (! STRINGP (font)) | 3651 if (! STRINGP (font)) |
3367 font = build_string ("fixed"); | 3652 font = build_string ("fixed"); |
3368 | 3653 |
3369 x_default_parameter (f, parms, Qfont, font, | 3654 x_default_parameter (f, parms, Qfont, font, |
3370 "font", "Font", string); | 3655 "font", "Font", RES_TYPE_STRING); |
3371 } | 3656 } |
3372 | 3657 |
3373 #ifdef USE_LUCID | 3658 #ifdef USE_LUCID |
3374 /* Prevent lwlib/xlwmenu.c from crashing because of a bug | 3659 /* Prevent lwlib/xlwmenu.c from crashing because of a bug |
3375 whereby it fails to get any font. */ | 3660 whereby it fails to get any font. */ |
3376 xlwmenu_default_font = f->output_data.x->font; | 3661 xlwmenu_default_font = f->output_data.x->font; |
3377 #endif | 3662 #endif |
3378 | 3663 |
3379 x_default_parameter (f, parms, Qborder_width, make_number (2), | 3664 x_default_parameter (f, parms, Qborder_width, make_number (2), |
3380 "borderWidth", "BorderWidth", number); | 3665 "borderWidth", "BorderWidth", RES_TYPE_NUMBER); |
3666 | |
3381 /* This defaults to 2 in order to match xterm. We recognize either | 3667 /* This defaults to 2 in order to match xterm. We recognize either |
3382 internalBorderWidth or internalBorder (which is what xterm calls | 3668 internalBorderWidth or internalBorder (which is what xterm calls |
3383 it). */ | 3669 it). */ |
3384 if (NILP (Fassq (Qinternal_border_width, parms))) | 3670 if (NILP (Fassq (Qinternal_border_width, parms))) |
3385 { | 3671 { |
3386 Lisp_Object value; | 3672 Lisp_Object value; |
3387 | 3673 |
3388 value = x_get_arg (dpyinfo, parms, Qinternal_border_width, | 3674 value = x_get_arg (dpyinfo, parms, Qinternal_border_width, |
3389 "internalBorder", "internalBorder", number); | 3675 "internalBorder", "internalBorder", RES_TYPE_NUMBER); |
3390 if (! EQ (value, Qunbound)) | 3676 if (! EQ (value, Qunbound)) |
3391 parms = Fcons (Fcons (Qinternal_border_width, value), | 3677 parms = Fcons (Fcons (Qinternal_border_width, value), |
3392 parms); | 3678 parms); |
3393 } | 3679 } |
3394 x_default_parameter (f, parms, Qinternal_border_width, make_number (1), | 3680 x_default_parameter (f, parms, Qinternal_border_width, make_number (1), |
3395 "internalBorderWidth", "internalBorderWidth", number); | 3681 "internalBorderWidth", "internalBorderWidth", |
3682 RES_TYPE_NUMBER); | |
3396 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft, | 3683 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft, |
3397 "verticalScrollBars", "ScrollBars", symbol); | 3684 "verticalScrollBars", "ScrollBars", |
3685 RES_TYPE_SYMBOL); | |
3398 | 3686 |
3399 /* Also do the stuff which must be set before the window exists. */ | 3687 /* Also do the stuff which must be set before the window exists. */ |
3400 x_default_parameter (f, parms, Qforeground_color, build_string ("black"), | 3688 x_default_parameter (f, parms, Qforeground_color, build_string ("black"), |
3401 "foreground", "Foreground", string); | 3689 "foreground", "Foreground", RES_TYPE_STRING); |
3402 x_default_parameter (f, parms, Qbackground_color, build_string ("white"), | 3690 x_default_parameter (f, parms, Qbackground_color, build_string ("white"), |
3403 "background", "Background", string); | 3691 "background", "Background", RES_TYPE_STRING); |
3404 x_default_parameter (f, parms, Qmouse_color, build_string ("black"), | 3692 x_default_parameter (f, parms, Qmouse_color, build_string ("black"), |
3405 "pointerColor", "Foreground", string); | 3693 "pointerColor", "Foreground", RES_TYPE_STRING); |
3406 x_default_parameter (f, parms, Qcursor_color, build_string ("black"), | 3694 x_default_parameter (f, parms, Qcursor_color, build_string ("black"), |
3407 "cursorColor", "Foreground", string); | 3695 "cursorColor", "Foreground", RES_TYPE_STRING); |
3408 x_default_parameter (f, parms, Qborder_color, build_string ("black"), | 3696 x_default_parameter (f, parms, Qborder_color, build_string ("black"), |
3409 "borderColor", "BorderColor", string); | 3697 "borderColor", "BorderColor", RES_TYPE_STRING); |
3410 | 3698 |
3699 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground, | |
3700 "scrollBarForeground", | |
3701 "ScrollBarForeground", 1); | |
3702 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background, | |
3703 "scrollBarBackground", | |
3704 "ScrollBarBackground", 0); | |
3705 | |
3706 /* Init faces before x_default_parameter is called for scroll-bar | |
3707 parameters because that function calls x_set_scroll_bar_width, | |
3708 which calls change_frame_size, which calls Fset_window_buffer, | |
3709 which runs hooks, which call Fvertical_motion. At the end, we | |
3710 end up in init_iterator with a null face cache, which should not | |
3711 happen. */ | |
3712 init_frame_faces (f); | |
3713 | |
3411 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1), | 3714 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1), |
3412 "menuBar", "MenuBar", number); | 3715 "menuBar", "MenuBar", RES_TYPE_NUMBER); |
3716 x_default_parameter (f, parms, Qtoolbar_lines, make_number (0), | |
3717 "toolBar", "ToolBar", RES_TYPE_NUMBER); | |
3413 x_default_parameter (f, parms, Qscroll_bar_width, Qnil, | 3718 x_default_parameter (f, parms, Qscroll_bar_width, Qnil, |
3414 "scrollBarWidth", "ScrollBarWidth", number); | 3719 "scrollBarWidth", "ScrollBarWidth", |
3720 RES_TYPE_NUMBER); | |
3415 x_default_parameter (f, parms, Qbuffer_predicate, Qnil, | 3721 x_default_parameter (f, parms, Qbuffer_predicate, Qnil, |
3416 "bufferPredicate", "BufferPredicate", symbol); | 3722 "bufferPredicate", "BufferPredicate", |
3723 RES_TYPE_SYMBOL); | |
3417 x_default_parameter (f, parms, Qtitle, Qnil, | 3724 x_default_parameter (f, parms, Qtitle, Qnil, |
3418 "title", "Title", string); | 3725 "title", "Title", RES_TYPE_STRING); |
3419 | 3726 |
3420 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; | 3727 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; |
3421 window_prompting = x_figure_window_size (f, parms); | 3728 window_prompting = x_figure_window_size (f, parms); |
3422 | 3729 |
3423 if (window_prompting & XNegative) | 3730 if (window_prompting & XNegative) |
3435 f->output_data.x->win_gravity = NorthWestGravity; | 3742 f->output_data.x->win_gravity = NorthWestGravity; |
3436 } | 3743 } |
3437 | 3744 |
3438 f->output_data.x->size_hint_flags = window_prompting; | 3745 f->output_data.x->size_hint_flags = window_prompting; |
3439 | 3746 |
3747 /* Create the X widget or window. Add the toolbar height to the | |
3748 initial frame height so that the user gets a text display area of | |
3749 the size he specified with -g or via .Xdefaults. Later changes | |
3750 of the toolbar height don't change the frame size. This is done | |
3751 so that users can create tall Emacs frames without having to | |
3752 guess how tall the toolbar will get. */ | |
3753 f->height += FRAME_TOOLBAR_LINES (f); | |
3440 #ifdef USE_X_TOOLKIT | 3754 #ifdef USE_X_TOOLKIT |
3441 x_window (f, window_prompting, minibuffer_only); | 3755 x_window (f, window_prompting, minibuffer_only); |
3442 #else | 3756 #else |
3443 x_window (f); | 3757 x_window (f); |
3444 #endif | 3758 #endif |
3445 x_icon (f, parms); | 3759 x_icon (f, parms); |
3446 x_make_gc (f); | 3760 x_make_gc (f); |
3447 init_frame_faces (f); | 3761 |
3448 | 3762 call1 (Qface_set_after_frame_default, frame); |
3763 | |
3449 /* We need to do this after creating the X window, so that the | 3764 /* We need to do this after creating the X window, so that the |
3450 icon-creation functions can say whose icon they're describing. */ | 3765 icon-creation functions can say whose icon they're describing. */ |
3451 x_default_parameter (f, parms, Qicon_type, Qnil, | 3766 x_default_parameter (f, parms, Qicon_type, Qnil, |
3452 "bitmapIcon", "BitmapIcon", symbol); | 3767 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL); |
3453 | 3768 |
3454 x_default_parameter (f, parms, Qauto_raise, Qnil, | 3769 x_default_parameter (f, parms, Qauto_raise, Qnil, |
3455 "autoRaise", "AutoRaiseLower", boolean); | 3770 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); |
3456 x_default_parameter (f, parms, Qauto_lower, Qnil, | 3771 x_default_parameter (f, parms, Qauto_lower, Qnil, |
3457 "autoLower", "AutoRaiseLower", boolean); | 3772 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); |
3458 x_default_parameter (f, parms, Qcursor_type, Qbox, | 3773 x_default_parameter (f, parms, Qcursor_type, Qbox, |
3459 "cursorType", "CursorType", symbol); | 3774 "cursorType", "CursorType", RES_TYPE_SYMBOL); |
3460 | 3775 |
3461 /* Dimensions, especially f->height, must be done via change_frame_size. | 3776 /* Dimensions, especially f->height, must be done via change_frame_size. |
3462 Change will not be effected unless different from the current | 3777 Change will not be effected unless different from the current |
3463 f->height. */ | 3778 f->height. */ |
3464 width = f->width; | 3779 width = f->width; |
3471 and how badly we want them. */ | 3786 and how badly we want them. */ |
3472 BLOCK_INPUT; | 3787 BLOCK_INPUT; |
3473 x_wm_set_size_hint (f, window_prompting, 0); | 3788 x_wm_set_size_hint (f, window_prompting, 0); |
3474 UNBLOCK_INPUT; | 3789 UNBLOCK_INPUT; |
3475 | 3790 |
3476 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, boolean); | 3791 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN); |
3477 f->no_split = minibuffer_only || EQ (tem, Qt); | 3792 f->no_split = minibuffer_only || EQ (tem, Qt); |
3478 | 3793 |
3479 UNGCPRO; | 3794 UNGCPRO; |
3480 | 3795 |
3481 /* It is now ok to make the frame official | 3796 /* It is now ok to make the frame official |
3493 Emacs cannot control visibility, so don't try. */ | 3808 Emacs cannot control visibility, so don't try. */ |
3494 if (! f->output_data.x->explicit_parent) | 3809 if (! f->output_data.x->explicit_parent) |
3495 { | 3810 { |
3496 Lisp_Object visibility; | 3811 Lisp_Object visibility; |
3497 | 3812 |
3498 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, symbol); | 3813 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, |
3814 RES_TYPE_SYMBOL); | |
3499 if (EQ (visibility, Qunbound)) | 3815 if (EQ (visibility, Qunbound)) |
3500 visibility = Qt; | 3816 visibility = Qt; |
3501 | 3817 |
3502 if (EQ (visibility, Qicon)) | 3818 if (EQ (visibility, Qicon)) |
3503 x_iconify_frame (f); | 3819 x_iconify_frame (f); |
3525 return Qnil; | 3841 return Qnil; |
3526 | 3842 |
3527 XSETFRAME (xfocus, dpyinfo->x_focus_frame); | 3843 XSETFRAME (xfocus, dpyinfo->x_focus_frame); |
3528 return xfocus; | 3844 return xfocus; |
3529 } | 3845 } |
3530 | |
3531 #if 1 | |
3532 #include "x-list-font.c" | |
3533 #else | |
3534 DEFUN ("x-list-fonts", Fx_list_fonts, Sx_list_fonts, 1, 4, 0, | |
3535 "Return a list of the names of available fonts matching PATTERN.\n\ | |
3536 If optional arguments FACE and FRAME are specified, return only fonts\n\ | |
3537 the same size as FACE on FRAME.\n\ | |
3538 \n\ | |
3539 PATTERN is a string, perhaps with wildcard characters;\n\ | |
3540 the * character matches any substring, and\n\ | |
3541 the ? character matches any single character.\n\ | |
3542 PATTERN is case-insensitive.\n\ | |
3543 FACE is a face name--a symbol.\n\ | |
3544 \n\ | |
3545 The return value is a list of strings, suitable as arguments to\n\ | |
3546 set-face-font.\n\ | |
3547 \n\ | |
3548 Fonts Emacs can't use (i.e. proportional fonts) may or may not be excluded\n\ | |
3549 even if they match PATTERN and FACE.\n\ | |
3550 \n\ | |
3551 The optional fourth argument MAXIMUM sets a limit on how many\n\ | |
3552 fonts to match. The first MAXIMUM fonts are reported.") | |
3553 (pattern, face, frame, maximum) | |
3554 Lisp_Object pattern, face, frame, maximum; | |
3555 { | |
3556 int num_fonts; | |
3557 char **names; | |
3558 #ifndef BROKEN_XLISTFONTSWITHINFO | |
3559 XFontStruct *info; | |
3560 #endif | |
3561 XFontStruct *size_ref; | |
3562 Lisp_Object list; | |
3563 FRAME_PTR f; | |
3564 Lisp_Object key; | |
3565 int maxnames; | |
3566 int count; | |
3567 | |
3568 check_x (); | |
3569 CHECK_STRING (pattern, 0); | |
3570 if (!NILP (face)) | |
3571 CHECK_SYMBOL (face, 1); | |
3572 | |
3573 if (NILP (maximum)) | |
3574 maxnames = 2000; | |
3575 else | |
3576 { | |
3577 CHECK_NATNUM (maximum, 0); | |
3578 maxnames = XINT (maximum); | |
3579 } | |
3580 | |
3581 f = check_x_frame (frame); | |
3582 | |
3583 /* Determine the width standard for comparison with the fonts we find. */ | |
3584 | |
3585 if (NILP (face)) | |
3586 size_ref = 0; | |
3587 else | |
3588 { | |
3589 int face_id; | |
3590 | |
3591 /* Don't die if we get called with a terminal frame. */ | |
3592 if (! FRAME_X_P (f)) | |
3593 error ("Non-X frame used in `x-list-fonts'"); | |
3594 | |
3595 face_id = face_name_id_number (f, face); | |
3596 | |
3597 if (face_id < 0 || face_id >= FRAME_N_PARAM_FACES (f) | |
3598 || FRAME_PARAM_FACES (f) [face_id] == 0) | |
3599 size_ref = f->output_data.x->font; | |
3600 else | |
3601 { | |
3602 size_ref = FRAME_PARAM_FACES (f) [face_id]->font; | |
3603 if (size_ref == (XFontStruct *) (~0)) | |
3604 size_ref = f->output_data.x->font; | |
3605 } | |
3606 } | |
3607 | |
3608 /* See if we cached the result for this particular query. */ | |
3609 key = Fcons (pattern, maximum); | |
3610 list = Fassoc (key, | |
3611 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr); | |
3612 | |
3613 /* We have info in the cache for this PATTERN. */ | |
3614 if (!NILP (list)) | |
3615 { | |
3616 Lisp_Object tem, newlist; | |
3617 | |
3618 /* We have info about this pattern. */ | |
3619 list = XCONS (list)->cdr; | |
3620 | |
3621 if (size_ref == 0) | |
3622 return list; | |
3623 | |
3624 BLOCK_INPUT; | |
3625 | |
3626 /* Filter the cached info and return just the fonts that match FACE. */ | |
3627 newlist = Qnil; | |
3628 for (tem = list; CONSP (tem); tem = XCONS (tem)->cdr) | |
3629 { | |
3630 XFontStruct *thisinfo; | |
3631 | |
3632 count = x_catch_errors (FRAME_X_DISPLAY (f)); | |
3633 | |
3634 thisinfo = XLoadQueryFont (FRAME_X_DISPLAY (f), | |
3635 XSTRING (XCONS (tem)->car)->data); | |
3636 | |
3637 x_check_errors (FRAME_X_DISPLAY (f), "XLoadQueryFont failure: %s"); | |
3638 x_uncatch_errors (FRAME_X_DISPLAY (f), count); | |
3639 | |
3640 if (thisinfo && same_size_fonts (thisinfo, size_ref)) | |
3641 newlist = Fcons (XCONS (tem)->car, newlist); | |
3642 | |
3643 if (thisinfo != 0) | |
3644 XFreeFont (FRAME_X_DISPLAY (f), thisinfo); | |
3645 } | |
3646 | |
3647 UNBLOCK_INPUT; | |
3648 | |
3649 return newlist; | |
3650 } | |
3651 | |
3652 BLOCK_INPUT; | |
3653 | |
3654 count = x_catch_errors (FRAME_X_DISPLAY (f)); | |
3655 | |
3656 /* Solaris 2.3 has a bug in XListFontsWithInfo. */ | |
3657 #ifndef BROKEN_XLISTFONTSWITHINFO | |
3658 if (size_ref) | |
3659 names = XListFontsWithInfo (FRAME_X_DISPLAY (f), | |
3660 XSTRING (pattern)->data, | |
3661 maxnames, | |
3662 &num_fonts, /* count_return */ | |
3663 &info); /* info_return */ | |
3664 else | |
3665 #endif | |
3666 names = XListFonts (FRAME_X_DISPLAY (f), | |
3667 XSTRING (pattern)->data, | |
3668 maxnames, | |
3669 &num_fonts); /* count_return */ | |
3670 | |
3671 x_check_errors (FRAME_X_DISPLAY (f), "XListFonts failure: %s"); | |
3672 x_uncatch_errors (FRAME_X_DISPLAY (f), count); | |
3673 | |
3674 UNBLOCK_INPUT; | |
3675 | |
3676 list = Qnil; | |
3677 | |
3678 if (names) | |
3679 { | |
3680 int i; | |
3681 Lisp_Object full_list; | |
3682 | |
3683 /* Make a list of all the fonts we got back. | |
3684 Store that in the font cache for the display. */ | |
3685 full_list = Qnil; | |
3686 for (i = 0; i < num_fonts; i++) | |
3687 full_list = Fcons (build_string (names[i]), full_list); | |
3688 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr | |
3689 = Fcons (Fcons (key, full_list), | |
3690 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr); | |
3691 | |
3692 /* Make a list of the fonts that have the right width. */ | |
3693 list = Qnil; | |
3694 for (i = 0; i < num_fonts; i++) | |
3695 { | |
3696 int keeper; | |
3697 | |
3698 if (!size_ref) | |
3699 keeper = 1; | |
3700 else | |
3701 { | |
3702 #ifdef BROKEN_XLISTFONTSWITHINFO | |
3703 XFontStruct *thisinfo; | |
3704 | |
3705 BLOCK_INPUT; | |
3706 | |
3707 count = x_catch_errors (FRAME_X_DISPLAY (f)); | |
3708 thisinfo = XLoadQueryFont (FRAME_X_DISPLAY (f), names[i]); | |
3709 x_check_errors (FRAME_X_DISPLAY (f), | |
3710 "XLoadQueryFont failure: %s"); | |
3711 x_uncatch_errors (FRAME_X_DISPLAY (f), count); | |
3712 | |
3713 UNBLOCK_INPUT; | |
3714 | |
3715 keeper = thisinfo && same_size_fonts (thisinfo, size_ref); | |
3716 BLOCK_INPUT; | |
3717 if (thisinfo && ! keeper) | |
3718 XFreeFont (FRAME_X_DISPLAY (f), thisinfo); | |
3719 else if (thisinfo) | |
3720 XFreeFontInfo (NULL, thisinfo, 1); | |
3721 UNBLOCK_INPUT; | |
3722 #else | |
3723 keeper = same_size_fonts (&info[i], size_ref); | |
3724 #endif | |
3725 } | |
3726 if (keeper) | |
3727 list = Fcons (build_string (names[i]), list); | |
3728 } | |
3729 list = Fnreverse (list); | |
3730 | |
3731 BLOCK_INPUT; | |
3732 #ifndef BROKEN_XLISTFONTSWITHINFO | |
3733 if (size_ref) | |
3734 XFreeFontInfo (names, info, num_fonts); | |
3735 else | |
3736 #endif | |
3737 XFreeFontNames (names); | |
3738 UNBLOCK_INPUT; | |
3739 } | |
3740 | |
3741 return list; | |
3742 } | |
3743 #endif | |
3744 | 3846 |
3745 | 3847 |
3746 DEFUN ("x-color-defined-p", Fx_color_defined_p, Sx_color_defined_p, 1, 2, 0, | 3848 DEFUN ("x-color-defined-p", Fx_color_defined_p, Sx_color_defined_p, 1, 2, 0, |
3747 "Return non-nil if color COLOR is supported on frame FRAME.\n\ | 3849 "Return non-nil if color COLOR is supported on frame FRAME.\n\ |
3748 If FRAME is omitted or nil, use the selected frame.") | 3850 If FRAME is omitted or nil, use the selected frame.") |
4314 (event) | 4416 (event) |
4315 register Lisp_Object event; | 4417 register Lisp_Object event; |
4316 { | 4418 { |
4317 register int x0, y0, x1, y1; | 4419 register int x0, y0, x1, y1; |
4318 register struct frame *f = selected_frame; | 4420 register struct frame *f = selected_frame; |
4421 struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); | |
4319 register int p1, p2; | 4422 register int p1, p2; |
4320 | 4423 |
4321 CHECK_CONS (event, 0); | 4424 CHECK_CONS (event, 0); |
4322 | 4425 |
4323 BLOCK_INPUT; | 4426 BLOCK_INPUT; |
4325 y0 = XINT (Fcar (Fcdr (Fcar (event)))); | 4428 y0 = XINT (Fcar (Fcdr (Fcar (event)))); |
4326 | 4429 |
4327 /* If the mouse is past the end of the line, don't that area. */ | 4430 /* If the mouse is past the end of the line, don't that area. */ |
4328 /* ReWrite this... */ | 4431 /* ReWrite this... */ |
4329 | 4432 |
4330 x1 = f->cursor_x; | 4433 /* Where the cursor is. */ |
4331 y1 = f->cursor_y; | 4434 x1 = WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x); |
4435 y1 = WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y); | |
4332 | 4436 |
4333 if (y1 > y0) /* point below mouse */ | 4437 if (y1 > y0) /* point below mouse */ |
4334 outline_region (f, f->output_data.x->cursor_gc, | 4438 outline_region (f, f->output_data.x->cursor_gc, |
4335 x0, y0, x1, y1); | 4439 x0, y0, x1, y1); |
4336 else if (y1 < y0) /* point above mouse */ | 4440 else if (y1 < y0) /* point above mouse */ |
4358 (event) | 4462 (event) |
4359 register Lisp_Object event; | 4463 register Lisp_Object event; |
4360 { | 4464 { |
4361 register int x0, y0, x1, y1; | 4465 register int x0, y0, x1, y1; |
4362 register struct frame *f = selected_frame; | 4466 register struct frame *f = selected_frame; |
4467 struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); | |
4363 | 4468 |
4364 BLOCK_INPUT; | 4469 BLOCK_INPUT; |
4365 x0 = XINT (Fcar (Fcar (event))); | 4470 x0 = XINT (Fcar (Fcar (event))); |
4366 y0 = XINT (Fcar (Fcdr (Fcar (event)))); | 4471 y0 = XINT (Fcar (Fcdr (Fcar (event)))); |
4367 x1 = f->cursor_x; | 4472 x1 = WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x); |
4368 y1 = f->cursor_y; | 4473 y1 = WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y); |
4369 | 4474 |
4370 if (y1 > y0) /* point below mouse */ | 4475 if (y1 > y0) /* point below mouse */ |
4371 outline_region (f, f->output_data.x->reverse_gc, | 4476 outline_region (f, f->output_data.x->reverse_gc, |
4372 x0, y0, x1, y1); | 4477 x0, y0, x1, y1); |
4373 else if (y1 < y0) /* point above mouse */ | 4478 else if (y1 < y0) /* point above mouse */ |
4466 "") | 4571 "") |
4467 (event) | 4572 (event) |
4468 Lisp_Object event; | 4573 Lisp_Object event; |
4469 { | 4574 { |
4470 register struct frame *f = selected_frame; | 4575 register struct frame *f = selected_frame; |
4471 register int point_x = f->cursor_x; | 4576 struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); |
4472 register int point_y = f->cursor_y; | 4577 register int point_x = WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x); |
4578 register int point_y = WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y); | |
4473 register int mouse_below_point; | 4579 register int mouse_below_point; |
4474 register Lisp_Object obj; | 4580 register Lisp_Object obj; |
4475 register int x_contour_x, x_contour_y; | 4581 register int x_contour_x, x_contour_y; |
4476 | 4582 |
4477 x_contour_x = x_mouse_x; | 4583 x_contour_x = x_mouse_x; |
5112 If the optional third arg MUST-SUCCEED is non-nil,\n\ | 5218 If the optional third arg MUST-SUCCEED is non-nil,\n\ |
5113 terminate Emacs if we can't open the connection.") | 5219 terminate Emacs if we can't open the connection.") |
5114 (display, xrm_string, must_succeed) | 5220 (display, xrm_string, must_succeed) |
5115 Lisp_Object display, xrm_string, must_succeed; | 5221 Lisp_Object display, xrm_string, must_succeed; |
5116 { | 5222 { |
5117 unsigned int n_planes; | |
5118 unsigned char *xrm_option; | 5223 unsigned char *xrm_option; |
5119 struct x_display_info *dpyinfo; | 5224 struct x_display_info *dpyinfo; |
5120 | 5225 |
5121 CHECK_STRING (display, 0); | 5226 CHECK_STRING (display, 0); |
5122 if (! NILP (xrm_string)) | 5227 if (! NILP (xrm_string)) |
5162 If DISPLAY is nil, that stands for the selected frame's display.") | 5267 If DISPLAY is nil, that stands for the selected frame's display.") |
5163 (display) | 5268 (display) |
5164 Lisp_Object display; | 5269 Lisp_Object display; |
5165 { | 5270 { |
5166 struct x_display_info *dpyinfo = check_x_display_info (display); | 5271 struct x_display_info *dpyinfo = check_x_display_info (display); |
5167 struct x_display_info *tail; | |
5168 int i; | 5272 int i; |
5169 | 5273 |
5170 if (dpyinfo->reference_count > 0) | 5274 if (dpyinfo->reference_count > 0) |
5171 error ("Display still has frames on it"); | 5275 error ("Display still has frames on it"); |
5172 | 5276 |
5173 BLOCK_INPUT; | 5277 BLOCK_INPUT; |
5174 /* Free the fonts in the font table. */ | 5278 /* Free the fonts in the font table. */ |
5175 for (i = 0; i < dpyinfo->n_fonts; i++) | 5279 for (i = 0; i < dpyinfo->n_fonts; i++) |
5176 { | 5280 if (dpyinfo->font_table[i].name) |
5177 if (dpyinfo->font_table[i].name) | 5281 { |
5178 free (dpyinfo->font_table[i].name); | 5282 xfree (dpyinfo->font_table[i].name); |
5179 /* Don't free the full_name string; | 5283 /* Don't free the full_name string; |
5180 it is always shared with something else. */ | 5284 it is always shared with something else. */ |
5181 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font); | 5285 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font); |
5182 } | 5286 } |
5287 | |
5183 x_destroy_all_bitmaps (dpyinfo); | 5288 x_destroy_all_bitmaps (dpyinfo); |
5184 XSetCloseDownMode (dpyinfo->display, DestroyAll); | 5289 XSetCloseDownMode (dpyinfo->display, DestroyAll); |
5185 | 5290 |
5186 #ifdef USE_X_TOOLKIT | 5291 #ifdef USE_X_TOOLKIT |
5187 XtCloseDisplay (dpyinfo->display); | 5292 XtCloseDisplay (dpyinfo->display); |
5235 { | 5340 { |
5236 BLOCK_INPUT; | 5341 BLOCK_INPUT; |
5237 XSync (FRAME_X_DISPLAY (f), False); | 5342 XSync (FRAME_X_DISPLAY (f), False); |
5238 UNBLOCK_INPUT; | 5343 UNBLOCK_INPUT; |
5239 } | 5344 } |
5345 | |
5240 | 5346 |
5347 /*********************************************************************** | |
5348 Image types | |
5349 ***********************************************************************/ | |
5350 | |
5351 /* Value is the number of elements of vector VECTOR. */ | |
5352 | |
5353 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR)) | |
5354 | |
5355 /* List of supported image types. Use define_image_type to add new | |
5356 types. Use lookup_image_type to find a type for a given symbol. */ | |
5357 | |
5358 static struct image_type *image_types; | |
5359 | |
5360 /* A list of symbols, one for each supported image type. */ | |
5361 | |
5362 Lisp_Object Vimage_types; | |
5363 | |
5364 /* The symbol `image' which is the car of the lists used to represent | |
5365 images in Lisp. */ | |
5366 | |
5367 extern Lisp_Object Qimage; | |
5368 | |
5369 /* The symbol `xbm' which is used as the type symbol for XBM images. */ | |
5370 | |
5371 Lisp_Object Qxbm; | |
5372 | |
5373 /* Keywords. */ | |
5374 | |
5375 Lisp_Object QCtype, QCdata, QCfile, QCascent, QCmargin, QCrelief; | |
5376 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground; | |
5377 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask; | |
5378 extern Lisp_Object QCimage; | |
5379 | |
5380 /* Other symbols. */ | |
5381 | |
5382 Lisp_Object Qlaplace; | |
5383 | |
5384 /* Time in seconds after which images should be removed from the cache | |
5385 if not displayed. */ | |
5386 | |
5387 Lisp_Object Vimage_eviction_seconds; | |
5388 | |
5389 /* Function prototypes. */ | |
5390 | |
5391 static void define_image_type P_ ((struct image_type *type)); | |
5392 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol)); | |
5393 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object)); | |
5394 static void x_laplace P_ ((struct frame *, struct image *)); | |
5395 static int x_build_heuristic_mask P_ ((struct frame *, Lisp_Object, | |
5396 struct image *, Lisp_Object)); | |
5397 | |
5398 | |
5399 /* Define a new image type from TYPE. This adds a copy of TYPE to | |
5400 image_types and adds the symbol *TYPE->type to Vimage_types. */ | |
5401 | |
5402 static void | |
5403 define_image_type (type) | |
5404 struct image_type *type; | |
5405 { | |
5406 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs. | |
5407 The initialized data segment is read-only. */ | |
5408 struct image_type *p = (struct image_type *) xmalloc (sizeof *p); | |
5409 bcopy (type, p, sizeof *p); | |
5410 p->next = image_types; | |
5411 image_types = p; | |
5412 Vimage_types = Fcons (*p->type, Vimage_types); | |
5413 } | |
5414 | |
5415 | |
5416 /* Look up image type SYMBOL, and return a pointer to its image_type | |
5417 structure. Value is null if SYMBOL is not a known image type. */ | |
5418 | |
5419 static INLINE struct image_type * | |
5420 lookup_image_type (symbol) | |
5421 Lisp_Object symbol; | |
5422 { | |
5423 struct image_type *type; | |
5424 | |
5425 for (type = image_types; type; type = type->next) | |
5426 if (EQ (symbol, *type->type)) | |
5427 break; | |
5428 | |
5429 return type; | |
5430 } | |
5431 | |
5432 | |
5433 /* Value is non-zero if OBJECT is a valid Lisp image specification. A | |
5434 valid image specification is a list whose car is the symbol | |
5435 `image', and whose rest is a property list. The property list must | |
5436 contain a value for key `:type'. That value must be the name of a | |
5437 supported image type. The rest of the property list depends on the | |
5438 image type. */ | |
5439 | |
5440 int | |
5441 valid_image_p (object) | |
5442 Lisp_Object object; | |
5443 { | |
5444 int valid_p = 0; | |
5445 | |
5446 if (CONSP (object) && EQ (XCAR (object), Qimage)) | |
5447 { | |
5448 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype); | |
5449 struct image_type *type = lookup_image_type (symbol); | |
5450 | |
5451 if (type) | |
5452 valid_p = type->valid_p (object); | |
5453 } | |
5454 | |
5455 return valid_p; | |
5456 } | |
5457 | |
5458 | |
5459 /* Display an error message with format string FORMAT and argument | |
5460 ARG. Signaling an error, e.g. when an image cannot be loaded, | |
5461 is not a good idea because this would interrupt redisplay, and | |
5462 the error message display would lead to another redisplay. This | |
5463 function therefore simply displays a message. */ | |
5464 | |
5465 static void | |
5466 image_error (format, arg1, arg2) | |
5467 char *format; | |
5468 Lisp_Object arg1, arg2; | |
5469 { | |
5470 Lisp_Object args[3]; | |
5471 | |
5472 args[0] = build_string (format); | |
5473 args[1] = arg1; | |
5474 args[2] = arg2; | |
5475 Fmessage (make_number (DIM (args)), args); | |
5476 } | |
5477 | |
5478 | |
5479 | |
5480 /*********************************************************************** | |
5481 Image specifications | |
5482 ***********************************************************************/ | |
5483 | |
5484 enum image_value_type | |
5485 { | |
5486 IMAGE_DONT_CHECK_VALUE_TYPE, | |
5487 IMAGE_STRING_VALUE, | |
5488 IMAGE_SYMBOL_VALUE, | |
5489 IMAGE_POSITIVE_INTEGER_VALUE, | |
5490 IMAGE_NON_NEGATIVE_INTEGER_VALUE, | |
5491 IMAGE_INTEGER_VALUE, | |
5492 IMAGE_FUNCTION_VALUE, | |
5493 IMAGE_NUMBER_VALUE, | |
5494 IMAGE_BOOL_VALUE | |
5495 }; | |
5496 | |
5497 /* Structure used when parsing image specifications. */ | |
5498 | |
5499 struct image_keyword | |
5500 { | |
5501 /* Name of keyword. */ | |
5502 char *name; | |
5503 | |
5504 /* The type of value allowed. */ | |
5505 enum image_value_type type; | |
5506 | |
5507 /* Non-zero means key must be present. */ | |
5508 int mandatory_p; | |
5509 | |
5510 /* Used to recognize duplicate keywords in a property list. */ | |
5511 int count; | |
5512 | |
5513 /* The value that was found. */ | |
5514 Lisp_Object value; | |
5515 }; | |
5516 | |
5517 | |
5518 static int parse_image_spec P_ ((Lisp_Object spec, | |
5519 struct image_keyword *keywords, | |
5520 int nkeywords, Lisp_Object type, | |
5521 int allow_other_keys_p)); | |
5522 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *)); | |
5523 | |
5524 | |
5525 /* Parse image spec SPEC according to KEYWORDS. A valid image spec | |
5526 has the format (image KEYWORD VALUE ...). One of the keyword/ | |
5527 value pairs must be `:type TYPE'. KEYWORDS is a vector of | |
5528 image_keywords structures of size NKEYWORDS describing other | |
5529 allowed keyword/value pairs. ALLOW_OTHER_KEYS_P non-zero means | |
5530 allow KEYWORD/VALUE pairs other than those described by KEYWORDS | |
5531 without checking them. Value is non-zero if SPEC is valid. */ | |
5532 | |
5533 static int | |
5534 parse_image_spec (spec, keywords, nkeywords, type, allow_other_keys_p) | |
5535 Lisp_Object spec; | |
5536 struct image_keyword *keywords; | |
5537 int nkeywords; | |
5538 Lisp_Object type; | |
5539 int allow_other_keys_p; | |
5540 { | |
5541 int i; | |
5542 Lisp_Object plist; | |
5543 | |
5544 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) | |
5545 return 0; | |
5546 | |
5547 plist = XCDR (spec); | |
5548 while (CONSP (plist)) | |
5549 { | |
5550 Lisp_Object key, value; | |
5551 | |
5552 /* First element of a pair must be a symbol. */ | |
5553 key = XCAR (plist); | |
5554 plist = XCDR (plist); | |
5555 if (!SYMBOLP (key)) | |
5556 return 0; | |
5557 | |
5558 /* There must follow a value. */ | |
5559 if (!CONSP (plist)) | |
5560 return 0; | |
5561 value = XCAR (plist); | |
5562 plist = XCDR (plist); | |
5563 | |
5564 /* Find key in KEYWORDS. Error if not found. */ | |
5565 for (i = 0; i < nkeywords; ++i) | |
5566 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0) | |
5567 break; | |
5568 | |
5569 if (i == nkeywords) | |
5570 { | |
5571 if (!allow_other_keys_p) | |
5572 return 0; | |
5573 continue; | |
5574 } | |
5575 | |
5576 /* Record that we recognized the keyword. If a keywords | |
5577 was found more than once, it's an error. */ | |
5578 keywords[i].value = value; | |
5579 ++keywords[i].count; | |
5580 | |
5581 if (keywords[i].count > 1) | |
5582 return 0; | |
5583 | |
5584 /* Check type of value against allowed type. */ | |
5585 switch (keywords[i].type) | |
5586 { | |
5587 case IMAGE_STRING_VALUE: | |
5588 if (!STRINGP (value)) | |
5589 return 0; | |
5590 break; | |
5591 | |
5592 case IMAGE_SYMBOL_VALUE: | |
5593 if (!SYMBOLP (value)) | |
5594 return 0; | |
5595 break; | |
5596 | |
5597 case IMAGE_POSITIVE_INTEGER_VALUE: | |
5598 if (!INTEGERP (value) || XINT (value) <= 0) | |
5599 return 0; | |
5600 break; | |
5601 | |
5602 case IMAGE_NON_NEGATIVE_INTEGER_VALUE: | |
5603 if (!INTEGERP (value) || XINT (value) < 0) | |
5604 return 0; | |
5605 break; | |
5606 | |
5607 case IMAGE_DONT_CHECK_VALUE_TYPE: | |
5608 break; | |
5609 | |
5610 case IMAGE_FUNCTION_VALUE: | |
5611 value = indirect_function (value); | |
5612 if (SUBRP (value) | |
5613 || COMPILEDP (value) | |
5614 || (CONSP (value) && EQ (XCAR (value), Qlambda))) | |
5615 break; | |
5616 return 0; | |
5617 | |
5618 case IMAGE_NUMBER_VALUE: | |
5619 if (!INTEGERP (value) && !FLOATP (value)) | |
5620 return 0; | |
5621 break; | |
5622 | |
5623 case IMAGE_INTEGER_VALUE: | |
5624 if (!INTEGERP (value)) | |
5625 return 0; | |
5626 break; | |
5627 | |
5628 case IMAGE_BOOL_VALUE: | |
5629 if (!NILP (value) && !EQ (value, Qt)) | |
5630 return 0; | |
5631 break; | |
5632 | |
5633 default: | |
5634 abort (); | |
5635 break; | |
5636 } | |
5637 | |
5638 if (EQ (key, QCtype) && !EQ (type, value)) | |
5639 return 0; | |
5640 } | |
5641 | |
5642 /* Check that all mandatory fields are present. */ | |
5643 for (i = 0; i < nkeywords; ++i) | |
5644 if (keywords[i].mandatory_p && keywords[i].count == 0) | |
5645 return 0; | |
5646 | |
5647 return NILP (plist); | |
5648 } | |
5649 | |
5650 | |
5651 /* Return the value of KEY in image specification SPEC. Value is nil | |
5652 if KEY is not present in SPEC. if FOUND is not null, set *FOUND | |
5653 to 1 if KEY was found in SPEC, set it to 0 otherwise. */ | |
5654 | |
5655 static Lisp_Object | |
5656 image_spec_value (spec, key, found) | |
5657 Lisp_Object spec, key; | |
5658 int *found; | |
5659 { | |
5660 Lisp_Object tail; | |
5661 | |
5662 xassert (valid_image_p (spec)); | |
5663 | |
5664 for (tail = XCDR (spec); | |
5665 CONSP (tail) && CONSP (XCDR (tail)); | |
5666 tail = XCDR (XCDR (tail))) | |
5667 { | |
5668 if (EQ (XCAR (tail), key)) | |
5669 { | |
5670 if (found) | |
5671 *found = 1; | |
5672 return XCAR (XCDR (tail)); | |
5673 } | |
5674 } | |
5675 | |
5676 if (found) | |
5677 *found = 0; | |
5678 return Qnil; | |
5679 } | |
5680 | |
5681 | |
5682 | |
5683 | |
5684 /*********************************************************************** | |
5685 Image type independent image structures | |
5686 ***********************************************************************/ | |
5687 | |
5688 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash)); | |
5689 static void free_image P_ ((struct frame *f, struct image *img)); | |
5690 | |
5691 | |
5692 /* Allocate and return a new image structure for image specification | |
5693 SPEC. SPEC has a hash value of HASH. */ | |
5694 | |
5695 static struct image * | |
5696 make_image (spec, hash) | |
5697 Lisp_Object spec; | |
5698 unsigned hash; | |
5699 { | |
5700 struct image *img = (struct image *) xmalloc (sizeof *img); | |
5701 | |
5702 xassert (valid_image_p (spec)); | |
5703 bzero (img, sizeof *img); | |
5704 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); | |
5705 xassert (img->type != NULL); | |
5706 img->spec = spec; | |
5707 img->data.lisp_val = Qnil; | |
5708 img->ascent = DEFAULT_IMAGE_ASCENT; | |
5709 img->hash = hash; | |
5710 return img; | |
5711 } | |
5712 | |
5713 | |
5714 /* Free image IMG which was used on frame F, including its resources. */ | |
5715 | |
5716 static void | |
5717 free_image (f, img) | |
5718 struct frame *f; | |
5719 struct image *img; | |
5720 { | |
5721 if (img) | |
5722 { | |
5723 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
5724 | |
5725 /* Remove IMG from the hash table of its cache. */ | |
5726 if (img->prev) | |
5727 img->prev->next = img->next; | |
5728 else | |
5729 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next; | |
5730 | |
5731 if (img->next) | |
5732 img->next->prev = img->prev; | |
5733 | |
5734 c->images[img->id] = NULL; | |
5735 | |
5736 /* Free resources, then free IMG. */ | |
5737 img->type->free (f, img); | |
5738 xfree (img); | |
5739 } | |
5740 } | |
5741 | |
5742 | |
5743 /* Prepare image IMG for display on frame F. Must be called before | |
5744 drawing an image. */ | |
5745 | |
5746 void | |
5747 prepare_image_for_display (f, img) | |
5748 struct frame *f; | |
5749 struct image *img; | |
5750 { | |
5751 EMACS_TIME t; | |
5752 | |
5753 /* We're about to display IMG, so set its timestamp to `now'. */ | |
5754 EMACS_GET_TIME (t); | |
5755 img->timestamp = EMACS_SECS (t); | |
5756 | |
5757 /* If IMG doesn't have a pixmap yet, load it now, using the image | |
5758 type dependent loader function. */ | |
5759 if (img->pixmap == 0) | |
5760 img->type->load (f, img); | |
5761 } | |
5762 | |
5763 | |
5764 | |
5765 /*********************************************************************** | |
5766 Helper functions for X image types | |
5767 ***********************************************************************/ | |
5768 | |
5769 static void x_clear_image P_ ((struct frame *f, struct image *img)); | |
5770 static unsigned long x_alloc_image_color P_ ((struct frame *f, | |
5771 struct image *img, | |
5772 Lisp_Object color_name, | |
5773 unsigned long dflt)); | |
5774 | |
5775 /* Free X resources of image IMG which is used on frame F. */ | |
5776 | |
5777 static void | |
5778 x_clear_image (f, img) | |
5779 struct frame *f; | |
5780 struct image *img; | |
5781 { | |
5782 if (img->pixmap) | |
5783 { | |
5784 BLOCK_INPUT; | |
5785 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); | |
5786 img->pixmap = 0; | |
5787 UNBLOCK_INPUT; | |
5788 } | |
5789 | |
5790 if (img->ncolors) | |
5791 { | |
5792 int class = FRAME_X_DISPLAY_INFO (f)->visual->class; | |
5793 | |
5794 /* If display has an immutable color map, freeing colors is not | |
5795 necessary and some servers don't allow it. So don't do it. */ | |
5796 if (class != StaticColor | |
5797 && class != StaticGray | |
5798 && class != TrueColor) | |
5799 { | |
5800 Colormap cmap; | |
5801 BLOCK_INPUT; | |
5802 cmap = DefaultColormapOfScreen (FRAME_X_DISPLAY_INFO (f)->screen); | |
5803 XFreeColors (FRAME_X_DISPLAY (f), cmap, img->colors, | |
5804 img->ncolors, 0); | |
5805 UNBLOCK_INPUT; | |
5806 } | |
5807 | |
5808 xfree (img->colors); | |
5809 img->colors = NULL; | |
5810 img->ncolors = 0; | |
5811 } | |
5812 } | |
5813 | |
5814 | |
5815 /* Allocate color COLOR_NAME for image IMG on frame F. If color | |
5816 cannot be allocated, use DFLT. Add a newly allocated color to | |
5817 IMG->colors, so that it can be freed again. Value is the pixel | |
5818 color. */ | |
5819 | |
5820 static unsigned long | |
5821 x_alloc_image_color (f, img, color_name, dflt) | |
5822 struct frame *f; | |
5823 struct image *img; | |
5824 Lisp_Object color_name; | |
5825 unsigned long dflt; | |
5826 { | |
5827 XColor color; | |
5828 unsigned long result; | |
5829 | |
5830 xassert (STRINGP (color_name)); | |
5831 | |
5832 if (defined_color (f, XSTRING (color_name)->data, &color, 1)) | |
5833 { | |
5834 /* This isn't called frequently so we get away with simply | |
5835 reallocating the color vector to the needed size, here. */ | |
5836 ++img->ncolors; | |
5837 img->colors = | |
5838 (unsigned long *) xrealloc (img->colors, | |
5839 img->ncolors * sizeof *img->colors); | |
5840 img->colors[img->ncolors - 1] = color.pixel; | |
5841 result = color.pixel; | |
5842 } | |
5843 else | |
5844 result = dflt; | |
5845 | |
5846 return result; | |
5847 } | |
5848 | |
5849 | |
5850 | |
5851 /*********************************************************************** | |
5852 Image Cache | |
5853 ***********************************************************************/ | |
5854 | |
5855 static void cache_image P_ ((struct frame *f, struct image *img)); | |
5856 | |
5857 | |
5858 /* Return a new, initialized image cache that is allocated from the | |
5859 heap. Call free_image_cache to free an image cache. */ | |
5860 | |
5861 struct image_cache * | |
5862 make_image_cache () | |
5863 { | |
5864 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c); | |
5865 int size; | |
5866 | |
5867 bzero (c, sizeof *c); | |
5868 c->size = 50; | |
5869 c->images = (struct image **) xmalloc (c->size * sizeof *c->images); | |
5870 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; | |
5871 c->buckets = (struct image **) xmalloc (size); | |
5872 bzero (c->buckets, size); | |
5873 return c; | |
5874 } | |
5875 | |
5876 | |
5877 /* Free image cache of frame F. Be aware that X frames share images | |
5878 caches. */ | |
5879 | |
5880 void | |
5881 free_image_cache (f) | |
5882 struct frame *f; | |
5883 { | |
5884 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
5885 if (c) | |
5886 { | |
5887 int i; | |
5888 | |
5889 /* Cache should not be referenced by any frame when freed. */ | |
5890 xassert (c->refcount == 0); | |
5891 | |
5892 for (i = 0; i < c->used; ++i) | |
5893 free_image (f, c->images[i]); | |
5894 xfree (c->images); | |
5895 xfree (c); | |
5896 xfree (c->buckets); | |
5897 FRAME_X_IMAGE_CACHE (f) = NULL; | |
5898 } | |
5899 } | |
5900 | |
5901 | |
5902 /* Clear image cache of frame F. FORCE_P non-zero means free all | |
5903 images. FORCE_P zero means clear only images that haven't been | |
5904 displayed for some time. Should be called from time to time to | |
5905 reduce the number of loaded images. If image-eviction-seconds is | |
5906 non-nil, this frees images in the cache which weren't displayed for | |
5907 at least that many seconds. */ | |
5908 | |
5909 void | |
5910 clear_image_cache (f, force_p) | |
5911 struct frame *f; | |
5912 int force_p; | |
5913 { | |
5914 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
5915 | |
5916 if (c && INTEGERP (Vimage_eviction_seconds)) | |
5917 { | |
5918 EMACS_TIME t; | |
5919 unsigned long old; | |
5920 int i, any_freed_p = 0; | |
5921 | |
5922 EMACS_GET_TIME (t); | |
5923 old = EMACS_SECS (t) - XFASTINT (Vimage_eviction_seconds); | |
5924 | |
5925 for (i = 0; i < c->used; ++i) | |
5926 { | |
5927 struct image *img = c->images[i]; | |
5928 if (img != NULL | |
5929 && (force_p | |
5930 || (img->timestamp > old))) | |
5931 { | |
5932 free_image (f, img); | |
5933 any_freed_p = 1; | |
5934 } | |
5935 } | |
5936 | |
5937 /* We may be clearing the image cache because, for example, | |
5938 Emacs was iconified for a longer period of time. In that | |
5939 case, current matrices may still contain references to | |
5940 images freed above. So, clear these matrices. */ | |
5941 if (any_freed_p) | |
5942 { | |
5943 clear_current_matrices (f); | |
5944 ++windows_or_buffers_changed; | |
5945 } | |
5946 } | |
5947 } | |
5948 | |
5949 | |
5950 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, | |
5951 0, 1, 0, | |
5952 "Clear the image cache of FRAME.\n\ | |
5953 FRAME nil or omitted means use the selected frame.\n\ | |
5954 FRAME t means clear the image caches of all frames.") | |
5955 (frame) | |
5956 Lisp_Object frame; | |
5957 { | |
5958 if (EQ (frame, Qt)) | |
5959 { | |
5960 Lisp_Object tail; | |
5961 | |
5962 FOR_EACH_FRAME (tail, frame) | |
5963 if (FRAME_X_P (XFRAME (frame))) | |
5964 clear_image_cache (XFRAME (frame), 1); | |
5965 } | |
5966 else | |
5967 clear_image_cache (check_x_frame (frame), 1); | |
5968 | |
5969 return Qnil; | |
5970 } | |
5971 | |
5972 | |
5973 /* Return the id of image with Lisp specification SPEC on frame F. | |
5974 SPEC must be a valid Lisp image specification (see valid_image_p). */ | |
5975 | |
5976 int | |
5977 lookup_image (f, spec) | |
5978 struct frame *f; | |
5979 Lisp_Object spec; | |
5980 { | |
5981 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
5982 struct image *img; | |
5983 int i; | |
5984 unsigned hash; | |
5985 struct gcpro gcpro1; | |
5986 | |
5987 /* F must be a window-system frame, and SPEC must be a valid image | |
5988 specification. */ | |
5989 xassert (FRAME_WINDOW_P (f)); | |
5990 xassert (valid_image_p (spec)); | |
5991 | |
5992 GCPRO1 (spec); | |
5993 | |
5994 /* Look up SPEC in the hash table of the image cache. */ | |
5995 hash = sxhash (spec, 0); | |
5996 i = hash % IMAGE_CACHE_BUCKETS_SIZE; | |
5997 | |
5998 for (img = c->buckets[i]; img; img = img->next) | |
5999 if (img->hash == hash && !NILP (Fequal (img->spec, spec))) | |
6000 break; | |
6001 | |
6002 /* If not found, create a new image and cache it. */ | |
6003 if (img == NULL) | |
6004 { | |
6005 extern Lisp_Object QCenable, QCselect; | |
6006 Lisp_Object tem; | |
6007 int loading_failed_p; | |
6008 | |
6009 img = make_image (spec, hash); | |
6010 cache_image (f, img); | |
6011 loading_failed_p = img->type->load (f, img) == 0; | |
6012 | |
6013 /* If we can't load the image, and we don't have a width and | |
6014 height, use some arbitrary width and height so that we can | |
6015 draw a rectangle for it. */ | |
6016 if (loading_failed_p) | |
6017 { | |
6018 Lisp_Object value; | |
6019 | |
6020 value = image_spec_value (spec, QCwidth, NULL); | |
6021 img->width = (INTEGERP (value) | |
6022 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH); | |
6023 value = image_spec_value (spec, QCheight, NULL); | |
6024 img->height = (INTEGERP (value) | |
6025 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT); | |
6026 } | |
6027 else | |
6028 { | |
6029 /* Handle image type independent image attributes | |
6030 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */ | |
6031 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask; | |
6032 Lisp_Object file; | |
6033 | |
6034 ascent = image_spec_value (spec, QCascent, NULL); | |
6035 if (INTEGERP (ascent)) | |
6036 img->ascent = XFASTINT (ascent); | |
6037 | |
6038 margin = image_spec_value (spec, QCmargin, NULL); | |
6039 if (INTEGERP (margin) && XINT (margin) >= 0) | |
6040 img->margin = XFASTINT (margin); | |
6041 | |
6042 relief = image_spec_value (spec, QCrelief, NULL); | |
6043 if (INTEGERP (relief)) | |
6044 { | |
6045 img->relief = XINT (relief); | |
6046 img->margin += abs (img->relief); | |
6047 } | |
6048 | |
6049 /* Should we apply a Laplace edge-detection algorithm? */ | |
6050 algorithm = image_spec_value (spec, QCalgorithm, NULL); | |
6051 if (img->pixmap && EQ (algorithm, Qlaplace)) | |
6052 x_laplace (f, img); | |
6053 | |
6054 /* Should we built a mask heuristically? */ | |
6055 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL); | |
6056 if (img->pixmap && !img->mask && !NILP (heuristic_mask)) | |
6057 { | |
6058 file = image_spec_value (spec, QCfile, NULL); | |
6059 x_build_heuristic_mask (f, file, img, heuristic_mask); | |
6060 } | |
6061 } | |
6062 } | |
6063 | |
6064 UNGCPRO; | |
6065 | |
6066 /* Value is the image id. */ | |
6067 return img->id; | |
6068 } | |
6069 | |
6070 | |
6071 /* Cache image IMG in the image cache of frame F. */ | |
6072 | |
6073 static void | |
6074 cache_image (f, img) | |
6075 struct frame *f; | |
6076 struct image *img; | |
6077 { | |
6078 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
6079 int i; | |
6080 | |
6081 /* Find a free slot in c->images. */ | |
6082 for (i = 0; i < c->used; ++i) | |
6083 if (c->images[i] == NULL) | |
6084 break; | |
6085 | |
6086 /* If no free slot found, maybe enlarge c->images. */ | |
6087 if (i == c->used && c->used == c->size) | |
6088 { | |
6089 c->size *= 2; | |
6090 c->images = (struct image **) xrealloc (c->images, | |
6091 c->size * sizeof *c->images); | |
6092 } | |
6093 | |
6094 /* Add IMG to c->images, and assign IMG an id. */ | |
6095 c->images[i] = img; | |
6096 img->id = i; | |
6097 if (i == c->used) | |
6098 ++c->used; | |
6099 | |
6100 /* Add IMG to the cache's hash table. */ | |
6101 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; | |
6102 img->next = c->buckets[i]; | |
6103 if (img->next) | |
6104 img->next->prev = img; | |
6105 img->prev = NULL; | |
6106 c->buckets[i] = img; | |
6107 } | |
6108 | |
6109 | |
6110 /* Call FN on every image in the image cache of frame F. Used to mark | |
6111 Lisp Objects in the image cache. */ | |
6112 | |
6113 void | |
6114 forall_images_in_image_cache (f, fn) | |
6115 struct frame *f; | |
6116 void (*fn) P_ ((struct image *img)); | |
6117 { | |
6118 if (FRAME_LIVE_P (f) && FRAME_X_P (f)) | |
6119 { | |
6120 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
6121 if (c) | |
6122 { | |
6123 int i; | |
6124 for (i = 0; i < c->used; ++i) | |
6125 if (c->images[i]) | |
6126 fn (c->images[i]); | |
6127 } | |
6128 } | |
6129 } | |
6130 | |
6131 | |
6132 | |
6133 /*********************************************************************** | |
6134 X support code | |
6135 ***********************************************************************/ | |
6136 | |
6137 static int x_create_x_image_and_pixmap P_ ((struct frame *, Lisp_Object, | |
6138 int, int, int, XImage **, | |
6139 Pixmap *)); | |
6140 static void x_destroy_x_image P_ ((XImage *)); | |
6141 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int)); | |
6142 | |
6143 | |
6144 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on | |
6145 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. | |
6146 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated | |
6147 via xmalloc. Print error messages via image_error if an error | |
6148 occurs. FILE is the name of an image file being processed, for | |
6149 error messages. Value is non-zero if successful. */ | |
6150 | |
6151 static int | |
6152 x_create_x_image_and_pixmap (f, file, width, height, depth, ximg, pixmap) | |
6153 struct frame *f; | |
6154 Lisp_Object file; | |
6155 int width, height, depth; | |
6156 XImage **ximg; | |
6157 Pixmap *pixmap; | |
6158 { | |
6159 Display *display = FRAME_X_DISPLAY (f); | |
6160 Screen *screen = FRAME_X_SCREEN (f); | |
6161 Window window = FRAME_X_WINDOW (f); | |
6162 | |
6163 xassert (interrupt_input_blocked); | |
6164 | |
6165 if (depth <= 0) | |
6166 depth = DefaultDepthOfScreen (screen); | |
6167 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen), | |
6168 depth, ZPixmap, 0, NULL, width, height, | |
6169 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0); | |
6170 if (*ximg == NULL) | |
6171 { | |
6172 image_error ("Unable to allocate X image for %s", file, Qnil); | |
6173 return 0; | |
6174 } | |
6175 | |
6176 /* Allocate image raster. */ | |
6177 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); | |
6178 | |
6179 /* Allocate a pixmap of the same size. */ | |
6180 *pixmap = XCreatePixmap (display, window, width, height, depth); | |
6181 if (*pixmap == 0) | |
6182 { | |
6183 x_destroy_x_image (*ximg); | |
6184 *ximg = NULL; | |
6185 image_error ("Unable to create pixmap for `%s'", file, Qnil); | |
6186 return 0; | |
6187 } | |
6188 | |
6189 return 1; | |
6190 } | |
6191 | |
6192 | |
6193 /* Destroy XImage XIMG. Free XIMG->data. */ | |
6194 | |
6195 static void | |
6196 x_destroy_x_image (ximg) | |
6197 XImage *ximg; | |
6198 { | |
6199 xassert (interrupt_input_blocked); | |
6200 if (ximg) | |
6201 { | |
6202 xfree (ximg->data); | |
6203 ximg->data = NULL; | |
6204 XDestroyImage (ximg); | |
6205 } | |
6206 } | |
6207 | |
6208 | |
6209 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT | |
6210 are width and height of both the image and pixmap. */ | |
6211 | |
6212 void | |
6213 x_put_x_image (f, ximg, pixmap, width, height) | |
6214 struct frame *f; | |
6215 XImage *ximg; | |
6216 Pixmap pixmap; | |
6217 { | |
6218 GC gc; | |
6219 | |
6220 xassert (interrupt_input_blocked); | |
6221 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL); | |
6222 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height); | |
6223 XFreeGC (FRAME_X_DISPLAY (f), gc); | |
6224 } | |
6225 | |
6226 | |
6227 | |
6228 /*********************************************************************** | |
6229 Searching files | |
6230 ***********************************************************************/ | |
6231 | |
6232 static Lisp_Object x_find_image_file P_ ((Lisp_Object)); | |
6233 | |
6234 /* Find image file FILE. Look in data-directory, then | |
6235 x-bitmap-file-path. Value is the full name of the file found, or | |
6236 nil if not found. */ | |
6237 | |
6238 static Lisp_Object | |
6239 x_find_image_file (file) | |
6240 Lisp_Object file; | |
6241 { | |
6242 Lisp_Object file_found, search_path; | |
6243 struct gcpro gcpro1, gcpro2; | |
6244 int fd; | |
6245 | |
6246 file_found = Qnil; | |
6247 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path); | |
6248 GCPRO2 (file_found, search_path); | |
6249 | |
6250 /* Try to find FILE in data-directory, then x-bitmap-file-path. */ | |
6251 fd = openp (search_path, file, "", &file_found, 0); | |
6252 | |
6253 if (fd < 0) | |
6254 file_found = Qnil; | |
6255 else | |
6256 close (fd); | |
6257 | |
6258 UNGCPRO; | |
6259 return file_found; | |
6260 } | |
6261 | |
6262 | |
6263 | |
6264 /*********************************************************************** | |
6265 XBM images | |
6266 ***********************************************************************/ | |
6267 | |
6268 static int xbm_load P_ ((struct frame *f, struct image *img)); | |
6269 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img, | |
6270 Lisp_Object file)); | |
6271 static int xbm_image_p P_ ((Lisp_Object object)); | |
6272 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *, | |
6273 unsigned char **)); | |
6274 static int xbm_read_hexint P_ ((FILE *)); | |
6275 | |
6276 | |
6277 /* Indices of image specification fields in xbm_format, below. */ | |
6278 | |
6279 enum xbm_keyword_index | |
6280 { | |
6281 XBM_TYPE, | |
6282 XBM_FILE, | |
6283 XBM_WIDTH, | |
6284 XBM_HEIGHT, | |
6285 XBM_DATA, | |
6286 XBM_FOREGROUND, | |
6287 XBM_BACKGROUND, | |
6288 XBM_ASCENT, | |
6289 XBM_MARGIN, | |
6290 XBM_RELIEF, | |
6291 XBM_ALGORITHM, | |
6292 XBM_HEURISTIC_MASK, | |
6293 XBM_LAST | |
6294 }; | |
6295 | |
6296 /* Vector of image_keyword structures describing the format | |
6297 of valid XBM image specifications. */ | |
6298 | |
6299 static struct image_keyword xbm_format[XBM_LAST] = | |
6300 { | |
6301 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
6302 {":file", IMAGE_STRING_VALUE, 0}, | |
6303 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
6304 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
6305 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
6306 {":foreground", IMAGE_STRING_VALUE, 0}, | |
6307 {":background", IMAGE_STRING_VALUE, 0}, | |
6308 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
6309 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
6310 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
6311 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
6312 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
6313 }; | |
6314 | |
6315 /* Structure describing the image type XBM. */ | |
6316 | |
6317 static struct image_type xbm_type = | |
6318 { | |
6319 &Qxbm, | |
6320 xbm_image_p, | |
6321 xbm_load, | |
6322 x_clear_image, | |
6323 NULL | |
6324 }; | |
6325 | |
6326 /* Tokens returned from xbm_scan. */ | |
6327 | |
6328 enum xbm_token | |
6329 { | |
6330 XBM_TK_IDENT = 256, | |
6331 XBM_TK_NUMBER | |
6332 }; | |
6333 | |
6334 | |
6335 /* Return non-zero if OBJECT is a valid XBM-type image specification. | |
6336 A valid specification is a list starting with the symbol `image' | |
6337 The rest of the list is a property list which must contain an | |
6338 entry `:type xbm.. | |
6339 | |
6340 If the specification specifies a file to load, it must contain | |
6341 an entry `:file FILENAME' where FILENAME is a string. | |
6342 | |
6343 If the specification is for a bitmap loaded from memory it must | |
6344 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where | |
6345 WIDTH and HEIGHT are integers > 0. DATA may be: | |
6346 | |
6347 1. a string large enough to hold the bitmap data, i.e. it must | |
6348 have a size >= (WIDTH + 7) / 8 * HEIGHT | |
6349 | |
6350 2. a bool-vector of size >= WIDTH * HEIGHT | |
6351 | |
6352 3. a vector of strings or bool-vectors, one for each line of the | |
6353 bitmap. | |
6354 | |
6355 Both the file and data forms may contain the additional entries | |
6356 `:background COLOR' and `:foreground COLOR'. If not present, | |
6357 foreground and background of the frame on which the image is | |
6358 displayed, is used. */ | |
6359 | |
6360 static int | |
6361 xbm_image_p (object) | |
6362 Lisp_Object object; | |
6363 { | |
6364 struct image_keyword kw[XBM_LAST]; | |
6365 | |
6366 bcopy (xbm_format, kw, sizeof kw); | |
6367 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm, 0)) | |
6368 return 0; | |
6369 | |
6370 xassert (EQ (kw[XBM_TYPE].value, Qxbm)); | |
6371 | |
6372 if (kw[XBM_FILE].count) | |
6373 { | |
6374 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) | |
6375 return 0; | |
6376 } | |
6377 else | |
6378 { | |
6379 Lisp_Object data; | |
6380 int width, height; | |
6381 | |
6382 /* Entries for `:width', `:height' and `:data' must be present. */ | |
6383 if (!kw[XBM_WIDTH].count | |
6384 || !kw[XBM_HEIGHT].count | |
6385 || !kw[XBM_DATA].count) | |
6386 return 0; | |
6387 | |
6388 data = kw[XBM_DATA].value; | |
6389 width = XFASTINT (kw[XBM_WIDTH].value); | |
6390 height = XFASTINT (kw[XBM_HEIGHT].value); | |
6391 | |
6392 /* Check type of data, and width and height against contents of | |
6393 data. */ | |
6394 if (VECTORP (data)) | |
6395 { | |
6396 int i; | |
6397 | |
6398 /* Number of elements of the vector must be >= height. */ | |
6399 if (XVECTOR (data)->size < height) | |
6400 return 0; | |
6401 | |
6402 /* Each string or bool-vector in data must be large enough | |
6403 for one line of the image. */ | |
6404 for (i = 0; i < height; ++i) | |
6405 { | |
6406 Lisp_Object elt = XVECTOR (data)->contents[i]; | |
6407 | |
6408 if (STRINGP (elt)) | |
6409 { | |
6410 if (XSTRING (elt)->size | |
6411 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR) | |
6412 return 0; | |
6413 } | |
6414 else if (BOOL_VECTOR_P (elt)) | |
6415 { | |
6416 if (XBOOL_VECTOR (elt)->size < width) | |
6417 return 0; | |
6418 } | |
6419 else | |
6420 return 0; | |
6421 } | |
6422 } | |
6423 else if (STRINGP (data)) | |
6424 { | |
6425 if (XSTRING (data)->size | |
6426 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height) | |
6427 return 0; | |
6428 } | |
6429 else if (BOOL_VECTOR_P (data)) | |
6430 { | |
6431 if (XBOOL_VECTOR (data)->size < width * height) | |
6432 return 0; | |
6433 } | |
6434 else | |
6435 return 0; | |
6436 } | |
6437 | |
6438 /* Baseline must be a value between 0 and 100 (a percentage). */ | |
6439 if (kw[XBM_ASCENT].count | |
6440 && XFASTINT (kw[XBM_ASCENT].value) > 100) | |
6441 return 0; | |
6442 | |
6443 return 1; | |
6444 } | |
6445 | |
6446 | |
6447 /* Scan a bitmap file. FP is the stream to read from. Value is | |
6448 either an enumerator from enum xbm_token, or a character for a | |
6449 single-character token, or 0 at end of file. If scanning an | |
6450 identifier, store the lexeme of the identifier in SVAL. If | |
6451 scanning a number, store its value in *IVAL. */ | |
6452 | |
6453 static int | |
6454 xbm_scan (fp, sval, ival) | |
6455 FILE *fp; | |
6456 char *sval; | |
6457 int *ival; | |
6458 { | |
6459 int c; | |
6460 | |
6461 /* Skip white space. */ | |
6462 while ((c = fgetc (fp)) != EOF && isspace (c)) | |
6463 ; | |
6464 | |
6465 if (c == EOF) | |
6466 c = 0; | |
6467 else if (isdigit (c)) | |
6468 { | |
6469 int value = 0, digit; | |
6470 | |
6471 if (c == '0') | |
6472 { | |
6473 c = fgetc (fp); | |
6474 if (c == 'x' || c == 'X') | |
6475 { | |
6476 while ((c = fgetc (fp)) != EOF) | |
6477 { | |
6478 if (isdigit (c)) | |
6479 digit = c - '0'; | |
6480 else if (c >= 'a' && c <= 'f') | |
6481 digit = c - 'a' + 10; | |
6482 else if (c >= 'A' && c <= 'F') | |
6483 digit = c - 'A' + 10; | |
6484 else | |
6485 break; | |
6486 value = 16 * value + digit; | |
6487 } | |
6488 } | |
6489 else if (isdigit (c)) | |
6490 { | |
6491 value = c - '0'; | |
6492 while ((c = fgetc (fp)) != EOF | |
6493 && isdigit (c)) | |
6494 value = 8 * value + c - '0'; | |
6495 } | |
6496 } | |
6497 else | |
6498 { | |
6499 value = c - '0'; | |
6500 while ((c = fgetc (fp)) != EOF | |
6501 && isdigit (c)) | |
6502 value = 10 * value + c - '0'; | |
6503 } | |
6504 | |
6505 if (c != EOF) | |
6506 ungetc (c, fp); | |
6507 *ival = value; | |
6508 c = XBM_TK_NUMBER; | |
6509 } | |
6510 else if (isalpha (c) || c == '_') | |
6511 { | |
6512 *sval++ = c; | |
6513 while ((c = fgetc (fp)) != EOF | |
6514 && (isalnum (c) || c == '_')) | |
6515 *sval++ = c; | |
6516 *sval = 0; | |
6517 if (c != EOF) | |
6518 ungetc (c, fp); | |
6519 c = XBM_TK_IDENT; | |
6520 } | |
6521 | |
6522 return c; | |
6523 } | |
6524 | |
6525 | |
6526 /* Replacement for XReadBitmapFileData which isn't available under old | |
6527 X versions. FILE is the name of the bitmap file to read. Set | |
6528 *WIDTH and *HEIGHT to the width and height of the image. Return in | |
6529 *DATA the bitmap data allocated with xmalloc. Value is non-zero if | |
6530 successful. */ | |
6531 | |
6532 static int | |
6533 xbm_read_bitmap_file_data (file, width, height, data) | |
6534 char *file; | |
6535 int *width, *height; | |
6536 unsigned char **data; | |
6537 { | |
6538 FILE *fp; | |
6539 char buffer[BUFSIZ]; | |
6540 int padding_p = 0; | |
6541 int v10 = 0; | |
6542 int bytes_per_line, i, nbytes; | |
6543 unsigned char *p; | |
6544 int value; | |
6545 int LA1; | |
6546 | |
6547 #define match() \ | |
6548 LA1 = xbm_scan (fp, buffer, &value) | |
6549 | |
6550 #define expect(TOKEN) \ | |
6551 if (LA1 != (TOKEN)) \ | |
6552 goto failure; \ | |
6553 else \ | |
6554 match () | |
6555 | |
6556 #define expect_ident(IDENT) \ | |
6557 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ | |
6558 match (); \ | |
6559 else \ | |
6560 goto failure | |
6561 | |
6562 fp = fopen (file, "r"); | |
6563 if (fp == NULL) | |
6564 return 0; | |
6565 | |
6566 *width = *height = -1; | |
6567 *data = NULL; | |
6568 LA1 = xbm_scan (fp, buffer, &value); | |
6569 | |
6570 /* Parse defines for width, height and hot-spots. */ | |
6571 while (LA1 == '#') | |
6572 { | |
6573 char *p; | |
6574 | |
6575 match (); | |
6576 expect_ident ("define"); | |
6577 expect (XBM_TK_IDENT); | |
6578 | |
6579 if (LA1 == XBM_TK_NUMBER); | |
6580 { | |
6581 char *p = strrchr (buffer, '_'); | |
6582 p = p ? p + 1 : buffer; | |
6583 if (strcmp (p, "width") == 0) | |
6584 *width = value; | |
6585 else if (strcmp (p, "height") == 0) | |
6586 *height = value; | |
6587 } | |
6588 expect (XBM_TK_NUMBER); | |
6589 } | |
6590 | |
6591 if (*width < 0 || *height < 0) | |
6592 goto failure; | |
6593 | |
6594 /* Parse bits. Must start with `static'. */ | |
6595 expect_ident ("static"); | |
6596 if (LA1 == XBM_TK_IDENT) | |
6597 { | |
6598 if (strcmp (buffer, "unsigned") == 0) | |
6599 { | |
6600 match (); | |
6601 expect_ident ("char"); | |
6602 } | |
6603 else if (strcmp (buffer, "short") == 0) | |
6604 { | |
6605 match (); | |
6606 v10 = 1; | |
6607 if (*width % 16 && *width % 16 < 9) | |
6608 padding_p = 1; | |
6609 } | |
6610 else if (strcmp (buffer, "char") == 0) | |
6611 match (); | |
6612 else | |
6613 goto failure; | |
6614 } | |
6615 else | |
6616 goto failure; | |
6617 | |
6618 expect (XBM_TK_IDENT); | |
6619 expect ('['); | |
6620 expect (']'); | |
6621 expect ('='); | |
6622 expect ('{'); | |
6623 | |
6624 bytes_per_line = (*width + 7) / 8 + padding_p; | |
6625 nbytes = bytes_per_line * *height; | |
6626 p = *data = (char *) xmalloc (nbytes); | |
6627 | |
6628 if (v10) | |
6629 { | |
6630 | |
6631 for (i = 0; i < nbytes; i += 2) | |
6632 { | |
6633 int val = value; | |
6634 expect (XBM_TK_NUMBER); | |
6635 | |
6636 *p++ = val; | |
6637 if (!padding_p || ((i + 2) % bytes_per_line)) | |
6638 *p++ = value >> 8; | |
6639 | |
6640 if (LA1 == ',' || LA1 == '}') | |
6641 match (); | |
6642 else | |
6643 goto failure; | |
6644 } | |
6645 } | |
6646 else | |
6647 { | |
6648 for (i = 0; i < nbytes; ++i) | |
6649 { | |
6650 int val = value; | |
6651 expect (XBM_TK_NUMBER); | |
6652 | |
6653 *p++ = val; | |
6654 | |
6655 if (LA1 == ',' || LA1 == '}') | |
6656 match (); | |
6657 else | |
6658 goto failure; | |
6659 } | |
6660 } | |
6661 | |
6662 fclose (fp); | |
6663 return 1; | |
6664 | |
6665 failure: | |
6666 | |
6667 fclose (fp); | |
6668 if (*data) | |
6669 { | |
6670 xfree (*data); | |
6671 *data = NULL; | |
6672 } | |
6673 return 0; | |
6674 | |
6675 #undef match | |
6676 #undef expect | |
6677 #undef expect_ident | |
6678 } | |
6679 | |
6680 | |
6681 /* Load XBM image IMG which will be displayed on frame F from file | |
6682 SPECIFIED_FILE. Value is non-zero if successful. */ | |
6683 | |
6684 static int | |
6685 xbm_load_image_from_file (f, img, specified_file) | |
6686 struct frame *f; | |
6687 struct image *img; | |
6688 Lisp_Object specified_file; | |
6689 { | |
6690 int rc; | |
6691 unsigned char *data; | |
6692 int success_p = 0; | |
6693 Lisp_Object file; | |
6694 struct gcpro gcpro1; | |
6695 | |
6696 xassert (STRINGP (specified_file)); | |
6697 file = Qnil; | |
6698 GCPRO1 (file); | |
6699 | |
6700 file = x_find_image_file (specified_file); | |
6701 if (!STRINGP (file)) | |
6702 { | |
6703 image_error ("Cannot find image file %s", specified_file, Qnil); | |
6704 UNGCPRO; | |
6705 return 0; | |
6706 } | |
6707 | |
6708 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width, | |
6709 &img->height, &data); | |
6710 if (rc) | |
6711 { | |
6712 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); | |
6713 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); | |
6714 unsigned long background = FRAME_BACKGROUND_PIXEL (f); | |
6715 Lisp_Object value; | |
6716 | |
6717 xassert (img->width > 0 && img->height > 0); | |
6718 | |
6719 /* Get foreground and background colors, maybe allocate colors. */ | |
6720 value = image_spec_value (img->spec, QCforeground, NULL); | |
6721 if (!NILP (value)) | |
6722 foreground = x_alloc_image_color (f, img, value, foreground); | |
6723 | |
6724 value = image_spec_value (img->spec, QCbackground, NULL); | |
6725 if (!NILP (value)) | |
6726 background = x_alloc_image_color (f, img, value, background); | |
6727 | |
6728 BLOCK_INPUT; | |
6729 img->pixmap | |
6730 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), | |
6731 FRAME_X_WINDOW (f), | |
6732 data, | |
6733 img->width, img->height, | |
6734 foreground, background, | |
6735 depth); | |
6736 xfree (data); | |
6737 | |
6738 if (img->pixmap == 0) | |
6739 { | |
6740 x_clear_image (f, img); | |
6741 image_error ("Unable to create X pixmap for `%s'", file, Qnil); | |
6742 } | |
6743 else | |
6744 success_p = 1; | |
6745 | |
6746 UNBLOCK_INPUT; | |
6747 } | |
6748 else | |
6749 image_error ("Error loading XBM image %s", img->spec, Qnil); | |
6750 | |
6751 UNGCPRO; | |
6752 return success_p; | |
6753 } | |
6754 | |
6755 | |
6756 /* Fill image IMG which is used on frame F with pixmap data. Value is | |
6757 non-zero if successful. */ | |
6758 | |
6759 static int | |
6760 xbm_load (f, img) | |
6761 struct frame *f; | |
6762 struct image *img; | |
6763 { | |
6764 int success_p = 0; | |
6765 Lisp_Object file_name; | |
6766 | |
6767 xassert (xbm_image_p (img->spec)); | |
6768 | |
6769 /* If IMG->spec specifies a file name, create a non-file spec from it. */ | |
6770 file_name = image_spec_value (img->spec, QCfile, NULL); | |
6771 if (STRINGP (file_name)) | |
6772 success_p = xbm_load_image_from_file (f, img, file_name); | |
6773 else | |
6774 { | |
6775 struct image_keyword fmt[XBM_LAST]; | |
6776 Lisp_Object data; | |
6777 int depth; | |
6778 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); | |
6779 unsigned long background = FRAME_BACKGROUND_PIXEL (f); | |
6780 char *bits; | |
6781 int parsed_p; | |
6782 | |
6783 /* Parse the list specification. */ | |
6784 bcopy (xbm_format, fmt, sizeof fmt); | |
6785 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm, 0); | |
6786 xassert (parsed_p); | |
6787 | |
6788 /* Get specified width, and height. */ | |
6789 img->width = XFASTINT (fmt[XBM_WIDTH].value); | |
6790 img->height = XFASTINT (fmt[XBM_HEIGHT].value); | |
6791 xassert (img->width > 0 && img->height > 0); | |
6792 | |
6793 BLOCK_INPUT; | |
6794 | |
6795 if (fmt[XBM_ASCENT].count) | |
6796 img->ascent = XFASTINT (fmt[XBM_ASCENT].value); | |
6797 | |
6798 /* Get foreground and background colors, maybe allocate colors. */ | |
6799 if (fmt[XBM_FOREGROUND].count) | |
6800 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, | |
6801 foreground); | |
6802 if (fmt[XBM_BACKGROUND].count) | |
6803 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, | |
6804 background); | |
6805 | |
6806 /* Set bits to the bitmap image data. */ | |
6807 data = fmt[XBM_DATA].value; | |
6808 if (VECTORP (data)) | |
6809 { | |
6810 int i; | |
6811 char *p; | |
6812 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; | |
6813 | |
6814 p = bits = (char *) alloca (nbytes * img->height); | |
6815 for (i = 0; i < img->height; ++i, p += nbytes) | |
6816 { | |
6817 Lisp_Object line = XVECTOR (data)->contents[i]; | |
6818 if (STRINGP (line)) | |
6819 bcopy (XSTRING (line)->data, p, nbytes); | |
6820 else | |
6821 bcopy (XBOOL_VECTOR (line)->data, p, nbytes); | |
6822 } | |
6823 } | |
6824 else if (STRINGP (data)) | |
6825 bits = XSTRING (data)->data; | |
6826 else | |
6827 bits = XBOOL_VECTOR (data)->data; | |
6828 | |
6829 /* Create the pixmap. */ | |
6830 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); | |
6831 img->pixmap | |
6832 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), | |
6833 FRAME_X_WINDOW (f), | |
6834 bits, | |
6835 img->width, img->height, | |
6836 foreground, background, | |
6837 depth); | |
6838 if (img->pixmap) | |
6839 success_p = 1; | |
6840 else | |
6841 { | |
6842 image_error ("Unable to create pixmap for XBM image", Qnil, Qnil); | |
6843 x_clear_image (f, img); | |
6844 } | |
6845 | |
6846 UNBLOCK_INPUT; | |
6847 } | |
6848 | |
6849 return success_p; | |
6850 } | |
6851 | |
6852 | |
6853 | |
6854 /*********************************************************************** | |
6855 XPM images | |
6856 ***********************************************************************/ | |
6857 | |
6858 #if HAVE_XPM | |
6859 | |
6860 static int xpm_image_p P_ ((Lisp_Object object)); | |
6861 static int xpm_load P_ ((struct frame *f, struct image *img)); | |
6862 static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); | |
6863 | |
6864 #include "X11/xpm.h" | |
6865 | |
6866 /* The symbol `xpm' identifying XPM-format images. */ | |
6867 | |
6868 Lisp_Object Qxpm; | |
6869 | |
6870 /* Indices of image specification fields in xpm_format, below. */ | |
6871 | |
6872 enum xpm_keyword_index | |
6873 { | |
6874 XPM_TYPE, | |
6875 XPM_FILE, | |
6876 XPM_DATA, | |
6877 XPM_ASCENT, | |
6878 XPM_MARGIN, | |
6879 XPM_RELIEF, | |
6880 XPM_ALGORITHM, | |
6881 XPM_HEURISTIC_MASK, | |
6882 XPM_COLOR_SYMBOLS, | |
6883 XPM_LAST | |
6884 }; | |
6885 | |
6886 /* Vector of image_keyword structures describing the format | |
6887 of valid XPM image specifications. */ | |
6888 | |
6889 static struct image_keyword xpm_format[XPM_LAST] = | |
6890 { | |
6891 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
6892 {":file", IMAGE_STRING_VALUE, 0}, | |
6893 {":data", IMAGE_STRING_VALUE, 0}, | |
6894 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
6895 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
6896 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
6897 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
6898 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
6899 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
6900 }; | |
6901 | |
6902 /* Structure describing the image type XBM. */ | |
6903 | |
6904 static struct image_type xpm_type = | |
6905 { | |
6906 &Qxpm, | |
6907 xpm_image_p, | |
6908 xpm_load, | |
6909 x_clear_image, | |
6910 NULL | |
6911 }; | |
6912 | |
6913 | |
6914 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list | |
6915 for XPM images. Such a list must consist of conses whose car and | |
6916 cdr are strings. */ | |
6917 | |
6918 static int | |
6919 xpm_valid_color_symbols_p (color_symbols) | |
6920 Lisp_Object color_symbols; | |
6921 { | |
6922 while (CONSP (color_symbols)) | |
6923 { | |
6924 Lisp_Object sym = XCAR (color_symbols); | |
6925 if (!CONSP (sym) | |
6926 || !STRINGP (XCAR (sym)) | |
6927 || !STRINGP (XCDR (sym))) | |
6928 break; | |
6929 color_symbols = XCDR (color_symbols); | |
6930 } | |
6931 | |
6932 return NILP (color_symbols); | |
6933 } | |
6934 | |
6935 | |
6936 /* Value is non-zero if OBJECT is a valid XPM image specification. */ | |
6937 | |
6938 static int | |
6939 xpm_image_p (object) | |
6940 Lisp_Object object; | |
6941 { | |
6942 struct image_keyword fmt[XPM_LAST]; | |
6943 bcopy (xpm_format, fmt, sizeof fmt); | |
6944 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm, 0) | |
6945 /* Either `:file' or `:data' must be present. */ | |
6946 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 | |
6947 /* Either no `:color-symbols' or it's a list of conses | |
6948 whose car and cdr are strings. */ | |
6949 && (fmt[XPM_COLOR_SYMBOLS].count == 0 | |
6950 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)) | |
6951 && (fmt[XPM_ASCENT].count == 0 | |
6952 || XFASTINT (fmt[XPM_ASCENT].value) < 100)); | |
6953 } | |
6954 | |
6955 | |
6956 /* Load image IMG which will be displayed on frame F. Value is | |
6957 non-zero if successful. */ | |
6958 | |
6959 static int | |
6960 xpm_load (f, img) | |
6961 struct frame *f; | |
6962 struct image *img; | |
6963 { | |
6964 int rc, i; | |
6965 XpmAttributes attrs; | |
6966 Lisp_Object specified_file, color_symbols; | |
6967 | |
6968 /* Configure the XPM lib. Use the visual of frame F. Allocate | |
6969 close colors. Return colors allocated. */ | |
6970 bzero (&attrs, sizeof attrs); | |
6971 attrs.visual = FRAME_X_DISPLAY_INFO (f)->visual; | |
6972 attrs.valuemask |= XpmVisual; | |
6973 attrs.valuemask |= XpmReturnAllocPixels; | |
6974 attrs.alloc_close_colors = 1; | |
6975 attrs.valuemask |= XpmAllocCloseColors; | |
6976 | |
6977 /* If image specification contains symbolic color definitions, add | |
6978 these to `attrs'. */ | |
6979 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); | |
6980 if (CONSP (color_symbols)) | |
6981 { | |
6982 Lisp_Object tail; | |
6983 XpmColorSymbol *xpm_syms; | |
6984 int i, size; | |
6985 | |
6986 attrs.valuemask |= XpmColorSymbols; | |
6987 | |
6988 /* Count number of symbols. */ | |
6989 attrs.numsymbols = 0; | |
6990 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail)) | |
6991 ++attrs.numsymbols; | |
6992 | |
6993 /* Allocate an XpmColorSymbol array. */ | |
6994 size = attrs.numsymbols * sizeof *xpm_syms; | |
6995 xpm_syms = (XpmColorSymbol *) alloca (size); | |
6996 bzero (xpm_syms, size); | |
6997 attrs.colorsymbols = xpm_syms; | |
6998 | |
6999 /* Fill the color symbol array. */ | |
7000 for (tail = color_symbols, i = 0; | |
7001 CONSP (tail); | |
7002 ++i, tail = XCDR (tail)) | |
7003 { | |
7004 Lisp_Object name = XCAR (XCAR (tail)); | |
7005 Lisp_Object color = XCDR (XCAR (tail)); | |
7006 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1); | |
7007 strcpy (xpm_syms[i].name, XSTRING (name)->data); | |
7008 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1); | |
7009 strcpy (xpm_syms[i].value, XSTRING (color)->data); | |
7010 } | |
7011 } | |
7012 | |
7013 /* Create a pixmap for the image, either from a file, or from a | |
7014 string buffer containing data in the same format as an XPM file. */ | |
7015 BLOCK_INPUT; | |
7016 specified_file = image_spec_value (img->spec, QCfile, NULL); | |
7017 if (STRINGP (specified_file)) | |
7018 { | |
7019 Lisp_Object file = x_find_image_file (specified_file); | |
7020 if (!STRINGP (file)) | |
7021 { | |
7022 image_error ("Cannot find image file %s", specified_file, Qnil); | |
7023 return 0; | |
7024 } | |
7025 | |
7026 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
7027 XSTRING (file)->data, &img->pixmap, &img->mask, | |
7028 &attrs); | |
7029 } | |
7030 else | |
7031 { | |
7032 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); | |
7033 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
7034 XSTRING (buffer)->data, | |
7035 &img->pixmap, &img->mask, | |
7036 &attrs); | |
7037 } | |
7038 UNBLOCK_INPUT; | |
7039 | |
7040 if (rc == XpmSuccess) | |
7041 { | |
7042 /* Remember allocated colors. */ | |
7043 img->ncolors = attrs.nalloc_pixels; | |
7044 img->colors = (unsigned long *) xmalloc (img->ncolors | |
7045 * sizeof *img->colors); | |
7046 for (i = 0; i < attrs.nalloc_pixels; ++i) | |
7047 img->colors[i] = attrs.alloc_pixels[i]; | |
7048 | |
7049 img->width = attrs.width; | |
7050 img->height = attrs.height; | |
7051 xassert (img->width > 0 && img->height > 0); | |
7052 | |
7053 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ | |
7054 BLOCK_INPUT; | |
7055 XpmFreeAttributes (&attrs); | |
7056 UNBLOCK_INPUT; | |
7057 } | |
7058 else | |
7059 { | |
7060 switch (rc) | |
7061 { | |
7062 case XpmOpenFailed: | |
7063 image_error ("Error opening XPM file (%s)", img->spec, Qnil); | |
7064 break; | |
7065 | |
7066 case XpmFileInvalid: | |
7067 image_error ("Invalid XPM file (%s)", img->spec, Qnil); | |
7068 break; | |
7069 | |
7070 case XpmNoMemory: | |
7071 image_error ("Out of memory (%s)", img->spec, Qnil); | |
7072 break; | |
7073 | |
7074 case XpmColorFailed: | |
7075 image_error ("Color allocation error (%s)", img->spec, Qnil); | |
7076 break; | |
7077 | |
7078 default: | |
7079 image_error ("Unknown error (%s)", img->spec, Qnil); | |
7080 break; | |
7081 } | |
7082 } | |
7083 | |
7084 return rc == XpmSuccess; | |
7085 } | |
7086 | |
7087 #endif /* HAVE_XPM != 0 */ | |
7088 | |
7089 | |
7090 /*********************************************************************** | |
7091 Color table | |
7092 ***********************************************************************/ | |
7093 | |
7094 /* An entry in the color table mapping an RGB color to a pixel color. */ | |
7095 | |
7096 struct ct_color | |
7097 { | |
7098 int r, g, b; | |
7099 unsigned long pixel; | |
7100 | |
7101 /* Next in color table collision list. */ | |
7102 struct ct_color *next; | |
7103 }; | |
7104 | |
7105 /* The bucket vector size to use. Must be prime. */ | |
7106 | |
7107 #define CT_SIZE 101 | |
7108 | |
7109 /* Value is a hash of the RGB color given by R, G, and B. */ | |
7110 | |
7111 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B)) | |
7112 | |
7113 /* The color hash table. */ | |
7114 | |
7115 struct ct_color **ct_table; | |
7116 | |
7117 /* Number of entries in the color table. */ | |
7118 | |
7119 int ct_colors_allocated; | |
7120 | |
7121 /* Function prototypes. */ | |
7122 | |
7123 static void init_color_table P_ ((void)); | |
7124 static void free_color_table P_ ((void)); | |
7125 static unsigned long *colors_in_color_table P_ ((int *n)); | |
7126 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); | |
7127 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); | |
7128 | |
7129 | |
7130 /* Initialize the color table. */ | |
7131 | |
7132 static void | |
7133 init_color_table () | |
7134 { | |
7135 int size = CT_SIZE * sizeof (*ct_table); | |
7136 ct_table = (struct ct_color **) xmalloc (size); | |
7137 bzero (ct_table, size); | |
7138 ct_colors_allocated = 0; | |
7139 } | |
7140 | |
7141 | |
7142 /* Free memory associated with the color table. */ | |
7143 | |
7144 static void | |
7145 free_color_table () | |
7146 { | |
7147 int i; | |
7148 struct ct_color *p, *next; | |
7149 | |
7150 for (i = 0; i < CT_SIZE; ++i) | |
7151 for (p = ct_table[i]; p; p = next) | |
7152 { | |
7153 next = p->next; | |
7154 xfree (p); | |
7155 } | |
7156 | |
7157 xfree (ct_table); | |
7158 ct_table = NULL; | |
7159 } | |
7160 | |
7161 | |
7162 /* Value is a pixel color for RGB color R, G, B on frame F. If an | |
7163 entry for that color already is in the color table, return the | |
7164 pixel color of that entry. Otherwise, allocate a new color for R, | |
7165 G, B, and make an entry in the color table. */ | |
7166 | |
7167 static unsigned long | |
7168 lookup_rgb_color (f, r, g, b) | |
7169 struct frame *f; | |
7170 int r, g, b; | |
7171 { | |
7172 unsigned hash = CT_HASH_RGB (r, g, b); | |
7173 int i = hash % CT_SIZE; | |
7174 struct ct_color *p; | |
7175 | |
7176 for (p = ct_table[i]; p; p = p->next) | |
7177 if (p->r == r && p->g == g && p->b == b) | |
7178 break; | |
7179 | |
7180 if (p == NULL) | |
7181 { | |
7182 XColor color; | |
7183 Colormap cmap; | |
7184 int rc; | |
7185 | |
7186 color.red = r; | |
7187 color.green = g; | |
7188 color.blue = b; | |
7189 | |
7190 BLOCK_INPUT; | |
7191 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); | |
7192 rc = x_alloc_nearest_color (FRAME_X_DISPLAY (f), FRAME_X_SCREEN (f), | |
7193 cmap, &color); | |
7194 UNBLOCK_INPUT; | |
7195 | |
7196 if (rc) | |
7197 { | |
7198 ++ct_colors_allocated; | |
7199 | |
7200 p = (struct ct_color *) xmalloc (sizeof *p); | |
7201 p->r = r; | |
7202 p->g = g; | |
7203 p->b = b; | |
7204 p->pixel = color.pixel; | |
7205 p->next = ct_table[i]; | |
7206 ct_table[i] = p; | |
7207 } | |
7208 else | |
7209 return FRAME_FOREGROUND_PIXEL (f); | |
7210 } | |
7211 | |
7212 return p->pixel; | |
7213 } | |
7214 | |
7215 | |
7216 /* Look up pixel color PIXEL which is used on frame F in the color | |
7217 table. If not already present, allocate it. Value is PIXEL. */ | |
7218 | |
7219 static unsigned long | |
7220 lookup_pixel_color (f, pixel) | |
7221 struct frame *f; | |
7222 unsigned long pixel; | |
7223 { | |
7224 int i = pixel % CT_SIZE; | |
7225 struct ct_color *p; | |
7226 | |
7227 for (p = ct_table[i]; p; p = p->next) | |
7228 if (p->pixel == pixel) | |
7229 break; | |
7230 | |
7231 if (p == NULL) | |
7232 { | |
7233 XColor color; | |
7234 Colormap cmap; | |
7235 int rc; | |
7236 | |
7237 BLOCK_INPUT; | |
7238 | |
7239 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); | |
7240 color.pixel = pixel; | |
7241 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color); | |
7242 rc = x_alloc_nearest_color (FRAME_X_DISPLAY (f), FRAME_X_SCREEN (f), | |
7243 cmap, &color); | |
7244 UNBLOCK_INPUT; | |
7245 | |
7246 if (rc) | |
7247 { | |
7248 ++ct_colors_allocated; | |
7249 | |
7250 p = (struct ct_color *) xmalloc (sizeof *p); | |
7251 p->r = color.red; | |
7252 p->g = color.green; | |
7253 p->b = color.blue; | |
7254 p->pixel = pixel; | |
7255 p->next = ct_table[i]; | |
7256 ct_table[i] = p; | |
7257 } | |
7258 else | |
7259 return FRAME_FOREGROUND_PIXEL (f); | |
7260 } | |
7261 | |
7262 return p->pixel; | |
7263 } | |
7264 | |
7265 | |
7266 /* Value is a vector of all pixel colors contained in the color table, | |
7267 allocated via xmalloc. Set *N to the number of colors. */ | |
7268 | |
7269 static unsigned long * | |
7270 colors_in_color_table (n) | |
7271 int *n; | |
7272 { | |
7273 int i, j; | |
7274 struct ct_color *p; | |
7275 unsigned long *colors; | |
7276 | |
7277 if (ct_colors_allocated == 0) | |
7278 { | |
7279 *n = 0; | |
7280 colors = NULL; | |
7281 } | |
7282 else | |
7283 { | |
7284 colors = (unsigned long *) xmalloc (ct_colors_allocated | |
7285 * sizeof *colors); | |
7286 *n = ct_colors_allocated; | |
7287 | |
7288 for (i = j = 0; i < CT_SIZE; ++i) | |
7289 for (p = ct_table[i]; p; p = p->next) | |
7290 colors[j++] = p->pixel; | |
7291 } | |
7292 | |
7293 return colors; | |
7294 } | |
7295 | |
7296 | |
7297 | |
7298 /*********************************************************************** | |
7299 Algorithms | |
7300 ***********************************************************************/ | |
7301 | |
7302 static void x_laplace_write_row P_ ((struct frame *, long *, | |
7303 int, XImage *, int)); | |
7304 static void x_laplace_read_row P_ ((struct frame *, Colormap, | |
7305 XColor *, int, XImage *, int)); | |
7306 | |
7307 | |
7308 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the | |
7309 frame we operate on, CMAP is the color-map in effect, and WIDTH is | |
7310 the width of one row in the image. */ | |
7311 | |
7312 static void | |
7313 x_laplace_read_row (f, cmap, colors, width, ximg, y) | |
7314 struct frame *f; | |
7315 Colormap cmap; | |
7316 XColor *colors; | |
7317 int width; | |
7318 XImage *ximg; | |
7319 int y; | |
7320 { | |
7321 int x; | |
7322 | |
7323 for (x = 0; x < width; ++x) | |
7324 colors[x].pixel = XGetPixel (ximg, x, y); | |
7325 | |
7326 XQueryColors (FRAME_X_DISPLAY (f), cmap, colors, width); | |
7327 } | |
7328 | |
7329 | |
7330 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs | |
7331 containing the pixel colors to write. F is the frame we are | |
7332 working on. */ | |
7333 | |
7334 static void | |
7335 x_laplace_write_row (f, pixels, width, ximg, y) | |
7336 struct frame *f; | |
7337 long *pixels; | |
7338 int width; | |
7339 XImage *ximg; | |
7340 int y; | |
7341 { | |
7342 int x; | |
7343 | |
7344 for (x = 0; x < width; ++x) | |
7345 XPutPixel (ximg, x, y, pixels[x]); | |
7346 } | |
7347 | |
7348 | |
7349 /* Transform image IMG which is used on frame F with a Laplace | |
7350 edge-detection algorithm. The result is an image that can be used | |
7351 to draw disabled buttons, for example. */ | |
7352 | |
7353 static void | |
7354 x_laplace (f, img) | |
7355 struct frame *f; | |
7356 struct image *img; | |
7357 { | |
7358 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); | |
7359 XImage *ximg, *oimg; | |
7360 XColor *in[3]; | |
7361 long *out; | |
7362 Pixmap pixmap; | |
7363 int x, y, i; | |
7364 long pixel; | |
7365 int in_y, out_y, rc; | |
7366 int mv2 = 45000; | |
7367 | |
7368 BLOCK_INPUT; | |
7369 | |
7370 /* Get the X image IMG->pixmap. */ | |
7371 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, | |
7372 0, 0, img->width, img->height, ~0, ZPixmap); | |
7373 | |
7374 /* Allocate 3 input rows, and one output row of colors. */ | |
7375 for (i = 0; i < 3; ++i) | |
7376 in[i] = (XColor *) alloca (img->width * sizeof (XColor)); | |
7377 out = (long *) alloca (img->width * sizeof (long)); | |
7378 | |
7379 /* Create an X image for output. */ | |
7380 rc = x_create_x_image_and_pixmap (f, Qnil, img->width, img->height, 0, | |
7381 &oimg, &pixmap); | |
7382 | |
7383 /* Fill first two rows. */ | |
7384 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0); | |
7385 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1); | |
7386 in_y = 2; | |
7387 | |
7388 /* Write first row, all zeros. */ | |
7389 init_color_table (); | |
7390 pixel = lookup_rgb_color (f, 0, 0, 0); | |
7391 for (x = 0; x < img->width; ++x) | |
7392 out[x] = pixel; | |
7393 x_laplace_write_row (f, out, img->width, oimg, 0); | |
7394 out_y = 1; | |
7395 | |
7396 for (y = 2; y < img->height; ++y) | |
7397 { | |
7398 int rowa = y % 3; | |
7399 int rowb = (y + 2) % 3; | |
7400 | |
7401 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++); | |
7402 | |
7403 for (x = 0; x < img->width - 2; ++x) | |
7404 { | |
7405 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red; | |
7406 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green; | |
7407 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue; | |
7408 | |
7409 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff, | |
7410 b & 0xffff); | |
7411 } | |
7412 | |
7413 x_laplace_write_row (f, out, img->width, oimg, out_y++); | |
7414 } | |
7415 | |
7416 /* Write last line, all zeros. */ | |
7417 for (x = 0; x < img->width; ++x) | |
7418 out[x] = pixel; | |
7419 x_laplace_write_row (f, out, img->width, oimg, out_y); | |
7420 | |
7421 /* Free the input image, and free resources of IMG. */ | |
7422 XDestroyImage (ximg); | |
7423 x_clear_image (f, img); | |
7424 | |
7425 /* Put the output image into pixmap, and destroy it. */ | |
7426 x_put_x_image (f, oimg, pixmap, img->width, img->height); | |
7427 x_destroy_x_image (oimg); | |
7428 | |
7429 /* Remember new pixmap and colors in IMG. */ | |
7430 img->pixmap = pixmap; | |
7431 img->colors = colors_in_color_table (&img->ncolors); | |
7432 free_color_table (); | |
7433 | |
7434 UNBLOCK_INPUT; | |
7435 } | |
7436 | |
7437 | |
7438 /* Build a mask for image IMG which is used on frame F. FILE is the | |
7439 name of an image file, for error messages. HOW determines how to | |
7440 determine the background color of IMG. If it is an integer, take | |
7441 that as the pixel value of the background. Otherwise, determine | |
7442 the background color of IMG heuristically. Value is non-zero | |
7443 if successful. */ | |
7444 | |
7445 static int | |
7446 x_build_heuristic_mask (f, file, img, how) | |
7447 struct frame *f; | |
7448 Lisp_Object file; | |
7449 struct image *img; | |
7450 Lisp_Object how; | |
7451 { | |
7452 Display *dpy = FRAME_X_DISPLAY (f); | |
7453 Window win = FRAME_X_WINDOW (f); | |
7454 XImage *ximg, *mask_img; | |
7455 int x, y, rc; | |
7456 unsigned long bg; | |
7457 | |
7458 BLOCK_INPUT; | |
7459 | |
7460 /* Create an image and pixmap serving as mask. */ | |
7461 rc = x_create_x_image_and_pixmap (f, file, img->width, img->height, 1, | |
7462 &mask_img, &img->mask); | |
7463 if (!rc) | |
7464 { | |
7465 UNBLOCK_INPUT; | |
7466 return 0; | |
7467 } | |
7468 | |
7469 /* Get the X image of IMG->pixmap. */ | |
7470 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height, | |
7471 ~0, ZPixmap); | |
7472 | |
7473 /* Determine the background color of ximg. If HOW is an integer, | |
7474 take that as a pixel color. Otherwise, try to determine the | |
7475 color heuristically. */ | |
7476 if (NATNUMP (how)) | |
7477 bg = XFASTINT (how); | |
7478 else | |
7479 { | |
7480 unsigned long corners[4]; | |
7481 int i, best_count; | |
7482 | |
7483 /* Get the colors at the corners of ximg. */ | |
7484 corners[0] = XGetPixel (ximg, 0, 0); | |
7485 corners[1] = XGetPixel (ximg, img->width - 1, 0); | |
7486 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1); | |
7487 corners[3] = XGetPixel (ximg, 0, img->height - 1); | |
7488 | |
7489 /* Choose the most frequently found color as background. */ | |
7490 for (i = best_count = 0; i < 4; ++i) | |
7491 { | |
7492 int j, n; | |
7493 | |
7494 for (j = n = 0; j < 4; ++j) | |
7495 if (corners[i] == corners[j]) | |
7496 ++n; | |
7497 | |
7498 if (n > best_count) | |
7499 bg = corners[i], best_count = n; | |
7500 } | |
7501 } | |
7502 | |
7503 /* Set all bits in mask_img to 1 whose color in ximg is different | |
7504 from the background color bg. */ | |
7505 for (y = 0; y < img->height; ++y) | |
7506 for (x = 0; x < img->width; ++x) | |
7507 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); | |
7508 | |
7509 /* Put mask_img into img->mask. */ | |
7510 x_put_x_image (f, mask_img, img->mask, img->width, img->height); | |
7511 x_destroy_x_image (mask_img); | |
7512 XDestroyImage (ximg); | |
7513 | |
7514 UNBLOCK_INPUT; | |
7515 return 1; | |
7516 } | |
7517 | |
7518 | |
7519 | |
7520 /*********************************************************************** | |
7521 PBM (mono, gray, color) | |
7522 ***********************************************************************/ | |
7523 | |
7524 static int pbm_image_p P_ ((Lisp_Object object)); | |
7525 static int pbm_load P_ ((struct frame *f, struct image *img)); | |
7526 static int pbm_scan_number P_ ((FILE *fp)); | |
7527 | |
7528 /* The symbol `pbm' identifying images of this type. */ | |
7529 | |
7530 Lisp_Object Qpbm; | |
7531 | |
7532 /* Indices of image specification fields in gs_format, below. */ | |
7533 | |
7534 enum pbm_keyword_index | |
7535 { | |
7536 PBM_TYPE, | |
7537 PBM_FILE, | |
7538 PBM_ASCENT, | |
7539 PBM_MARGIN, | |
7540 PBM_RELIEF, | |
7541 PBM_ALGORITHM, | |
7542 PBM_HEURISTIC_MASK, | |
7543 PBM_LAST | |
7544 }; | |
7545 | |
7546 /* Vector of image_keyword structures describing the format | |
7547 of valid user-defined image specifications. */ | |
7548 | |
7549 static struct image_keyword pbm_format[PBM_LAST] = | |
7550 { | |
7551 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
7552 {":file", IMAGE_STRING_VALUE, 1}, | |
7553 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
7554 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
7555 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
7556 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
7557 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
7558 }; | |
7559 | |
7560 /* Structure describing the image type `pbm'. */ | |
7561 | |
7562 static struct image_type pbm_type = | |
7563 { | |
7564 &Qpbm, | |
7565 pbm_image_p, | |
7566 pbm_load, | |
7567 x_clear_image, | |
7568 NULL | |
7569 }; | |
7570 | |
7571 | |
7572 /* Return non-zero if OBJECT is a valid PBM image specification. */ | |
7573 | |
7574 static int | |
7575 pbm_image_p (object) | |
7576 Lisp_Object object; | |
7577 { | |
7578 struct image_keyword fmt[PBM_LAST]; | |
7579 | |
7580 bcopy (pbm_format, fmt, sizeof fmt); | |
7581 | |
7582 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm, 0) | |
7583 || (fmt[PBM_ASCENT].count | |
7584 && XFASTINT (fmt[PBM_ASCENT].value) > 100)) | |
7585 return 0; | |
7586 return 1; | |
7587 } | |
7588 | |
7589 | |
7590 /* Scan a decimal number from PBM input file FP and return it. Value | |
7591 is -1 at end of file or if an error occurs. */ | |
7592 | |
7593 static int | |
7594 pbm_scan_number (fp) | |
7595 FILE *fp; | |
7596 { | |
7597 int c, val = -1; | |
7598 | |
7599 while (!feof (fp)) | |
7600 { | |
7601 /* Skip white-space. */ | |
7602 while ((c = fgetc (fp)) != EOF && isspace (c)) | |
7603 ; | |
7604 | |
7605 if (c == '#') | |
7606 { | |
7607 /* Skip comment to end of line. */ | |
7608 while ((c = fgetc (fp)) != EOF && c != '\n') | |
7609 ; | |
7610 } | |
7611 else if (isdigit (c)) | |
7612 { | |
7613 /* Read decimal number. */ | |
7614 val = c - '0'; | |
7615 while ((c = fgetc (fp)) != EOF && isdigit (c)) | |
7616 val = 10 * val + c - '0'; | |
7617 break; | |
7618 } | |
7619 else | |
7620 break; | |
7621 } | |
7622 | |
7623 return val; | |
7624 } | |
7625 | |
7626 | |
7627 /* Load PBM image IMG for use on frame F. */ | |
7628 | |
7629 static int | |
7630 pbm_load (f, img) | |
7631 struct frame *f; | |
7632 struct image *img; | |
7633 { | |
7634 FILE *fp; | |
7635 char magic[2]; | |
7636 int raw_p, x, y; | |
7637 int width, height, max_color_idx = 0, value; | |
7638 XImage *ximg; | |
7639 Lisp_Object file, specified_file; | |
7640 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; | |
7641 struct gcpro gcpro1; | |
7642 | |
7643 specified_file = image_spec_value (img->spec, QCfile, NULL); | |
7644 file = x_find_image_file (specified_file); | |
7645 GCPRO1 (file); | |
7646 if (!STRINGP (file)) | |
7647 { | |
7648 image_error ("Cannot find image file %s", specified_file, Qnil); | |
7649 UNGCPRO; | |
7650 return 0; | |
7651 } | |
7652 | |
7653 fp = fopen (XSTRING (file)->data, "r"); | |
7654 if (fp == NULL) | |
7655 { | |
7656 UNGCPRO; | |
7657 return 0; | |
7658 } | |
7659 | |
7660 /* Read first two characters. */ | |
7661 if (fread (magic, sizeof *magic, 2, fp) != 2) | |
7662 { | |
7663 fclose (fp); | |
7664 image_error ("Not a PBM image file: %s", file, Qnil); | |
7665 UNGCPRO; | |
7666 return 0; | |
7667 } | |
7668 | |
7669 if (*magic != 'P') | |
7670 { | |
7671 fclose (fp); | |
7672 image_error ("Not a PBM image file: %s", file, Qnil); | |
7673 UNGCPRO; | |
7674 return 0; | |
7675 } | |
7676 | |
7677 switch (magic[1]) | |
7678 { | |
7679 case '1': | |
7680 raw_p = 0, type = PBM_MONO; | |
7681 break; | |
7682 | |
7683 case '2': | |
7684 raw_p = 0, type = PBM_GRAY; | |
7685 break; | |
7686 | |
7687 case '3': | |
7688 raw_p = 0, type = PBM_COLOR; | |
7689 break; | |
7690 | |
7691 case '4': | |
7692 raw_p = 1, type = PBM_MONO; | |
7693 break; | |
7694 | |
7695 case '5': | |
7696 raw_p = 1, type = PBM_GRAY; | |
7697 break; | |
7698 | |
7699 case '6': | |
7700 raw_p = 1, type = PBM_COLOR; | |
7701 break; | |
7702 | |
7703 default: | |
7704 fclose (fp); | |
7705 image_error ("Not a PBM image file: %s", file, Qnil); | |
7706 UNGCPRO; | |
7707 return 0; | |
7708 } | |
7709 | |
7710 /* Read width, height, maximum color-component. Characters | |
7711 starting with `#' up to the end of a line are ignored. */ | |
7712 width = pbm_scan_number (fp); | |
7713 height = pbm_scan_number (fp); | |
7714 | |
7715 if (type != PBM_MONO) | |
7716 { | |
7717 max_color_idx = pbm_scan_number (fp); | |
7718 if (raw_p && max_color_idx > 255) | |
7719 max_color_idx = 255; | |
7720 } | |
7721 | |
7722 if (width < 0 || height < 0 | |
7723 || (type != PBM_MONO && max_color_idx < 0)) | |
7724 { | |
7725 fclose (fp); | |
7726 UNGCPRO; | |
7727 return 0; | |
7728 } | |
7729 | |
7730 BLOCK_INPUT; | |
7731 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, | |
7732 &ximg, &img->pixmap)) | |
7733 { | |
7734 fclose (fp); | |
7735 UNBLOCK_INPUT; | |
7736 UNGCPRO; | |
7737 return 0; | |
7738 } | |
7739 | |
7740 /* Initialize the color hash table. */ | |
7741 init_color_table (); | |
7742 | |
7743 if (type == PBM_MONO) | |
7744 { | |
7745 int c = 0, g; | |
7746 | |
7747 for (y = 0; y < height; ++y) | |
7748 for (x = 0; x < width; ++x) | |
7749 { | |
7750 if (raw_p) | |
7751 { | |
7752 if ((x & 7) == 0) | |
7753 c = fgetc (fp); | |
7754 g = c & 0x80; | |
7755 c <<= 1; | |
7756 } | |
7757 else | |
7758 g = pbm_scan_number (fp); | |
7759 | |
7760 XPutPixel (ximg, x, y, (g | |
7761 ? FRAME_FOREGROUND_PIXEL (f) | |
7762 : FRAME_BACKGROUND_PIXEL (f))); | |
7763 } | |
7764 } | |
7765 else | |
7766 { | |
7767 for (y = 0; y < height; ++y) | |
7768 for (x = 0; x < width; ++x) | |
7769 { | |
7770 int r, g, b; | |
7771 | |
7772 if (type == PBM_GRAY) | |
7773 r = g = b = raw_p ? fgetc (fp) : pbm_scan_number (fp); | |
7774 else if (raw_p) | |
7775 { | |
7776 r = fgetc (fp); | |
7777 g = fgetc (fp); | |
7778 b = fgetc (fp); | |
7779 } | |
7780 else | |
7781 { | |
7782 r = pbm_scan_number (fp); | |
7783 g = pbm_scan_number (fp); | |
7784 b = pbm_scan_number (fp); | |
7785 } | |
7786 | |
7787 if (r < 0 || g < 0 || b < 0) | |
7788 { | |
7789 fclose (fp); | |
7790 xfree (ximg->data); | |
7791 ximg->data = NULL; | |
7792 XDestroyImage (ximg); | |
7793 UNBLOCK_INPUT; | |
7794 image_error ("Invalid pixel value in file `%s'", | |
7795 file, Qnil); | |
7796 UNGCPRO; | |
7797 return 0; | |
7798 } | |
7799 | |
7800 /* RGB values are now in the range 0..max_color_idx. | |
7801 Scale this to the range 0..0xffff supported by X. */ | |
7802 r = (double) r * 65535 / max_color_idx; | |
7803 g = (double) g * 65535 / max_color_idx; | |
7804 b = (double) b * 65535 / max_color_idx; | |
7805 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); | |
7806 } | |
7807 } | |
7808 | |
7809 fclose (fp); | |
7810 | |
7811 /* Store in IMG->colors the colors allocated for the image, and | |
7812 free the color table. */ | |
7813 img->colors = colors_in_color_table (&img->ncolors); | |
7814 free_color_table (); | |
7815 | |
7816 /* Put the image into a pixmap. */ | |
7817 x_put_x_image (f, ximg, img->pixmap, width, height); | |
7818 x_destroy_x_image (ximg); | |
7819 UNBLOCK_INPUT; | |
7820 | |
7821 img->width = width; | |
7822 img->height = height; | |
7823 | |
7824 UNGCPRO; | |
7825 return 1; | |
7826 } | |
7827 | |
7828 | |
7829 | |
7830 /*********************************************************************** | |
7831 PNG | |
7832 ***********************************************************************/ | |
7833 | |
7834 #if HAVE_PNG | |
7835 | |
7836 #include <png.h> | |
7837 | |
7838 /* Function prototypes. */ | |
7839 | |
7840 static int png_image_p P_ ((Lisp_Object object)); | |
7841 static int png_load P_ ((struct frame *f, struct image *img)); | |
7842 | |
7843 /* The symbol `png' identifying images of this type. */ | |
7844 | |
7845 Lisp_Object Qpng; | |
7846 | |
7847 /* Indices of image specification fields in png_format, below. */ | |
7848 | |
7849 enum png_keyword_index | |
7850 { | |
7851 PNG_TYPE, | |
7852 PNG_FILE, | |
7853 PNG_ASCENT, | |
7854 PNG_MARGIN, | |
7855 PNG_RELIEF, | |
7856 PNG_ALGORITHM, | |
7857 PNG_HEURISTIC_MASK, | |
7858 PNG_LAST | |
7859 }; | |
7860 | |
7861 /* Vector of image_keyword structures describing the format | |
7862 of valid user-defined image specifications. */ | |
7863 | |
7864 static struct image_keyword png_format[PNG_LAST] = | |
7865 { | |
7866 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
7867 {":file", IMAGE_STRING_VALUE, 1}, | |
7868 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
7869 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
7870 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
7871 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
7872 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
7873 }; | |
7874 | |
7875 /* Structure describing the image type `gif'. */ | |
7876 | |
7877 static struct image_type png_type = | |
7878 { | |
7879 &Qpng, | |
7880 png_image_p, | |
7881 png_load, | |
7882 x_clear_image, | |
7883 NULL | |
7884 }; | |
7885 | |
7886 | |
7887 /* Return non-zero if OBJECT is a valid PNG image specification. */ | |
7888 | |
7889 static int | |
7890 png_image_p (object) | |
7891 Lisp_Object object; | |
7892 { | |
7893 struct image_keyword fmt[PNG_LAST]; | |
7894 bcopy (png_format, fmt, sizeof fmt); | |
7895 | |
7896 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng, 1) | |
7897 || (fmt[PNG_ASCENT].count | |
7898 && XFASTINT (fmt[PNG_ASCENT].value) > 100)) | |
7899 return 0; | |
7900 return 1; | |
7901 } | |
7902 | |
7903 | |
7904 /* Error and warning handlers installed when the PNG library | |
7905 is initialized. */ | |
7906 | |
7907 static void | |
7908 my_png_error (png_ptr, msg) | |
7909 png_struct *png_ptr; | |
7910 char *msg; | |
7911 { | |
7912 xassert (png_ptr != NULL); | |
7913 image_error ("PNG error: %s", build_string (msg), Qnil); | |
7914 longjmp (png_ptr->jmpbuf, 1); | |
7915 } | |
7916 | |
7917 | |
7918 static void | |
7919 my_png_warning (png_ptr, msg) | |
7920 png_struct *png_ptr; | |
7921 char *msg; | |
7922 { | |
7923 xassert (png_ptr != NULL); | |
7924 image_error ("PNG warning: %s", build_string (msg), Qnil); | |
7925 } | |
7926 | |
7927 | |
7928 /* Load PNG image IMG for use on frame F. Value is non-zero if | |
7929 successful. */ | |
7930 | |
7931 static int | |
7932 png_load (f, img) | |
7933 struct frame *f; | |
7934 struct image *img; | |
7935 { | |
7936 Lisp_Object file, specified_file; | |
7937 int rc, x, y, i; | |
7938 XImage *ximg, *mask_img = NULL; | |
7939 struct gcpro gcpro1; | |
7940 png_struct *png_ptr = NULL; | |
7941 png_info *info_ptr = NULL, *end_info = NULL; | |
7942 FILE *fp; | |
7943 png_byte sig[8]; | |
7944 png_byte *pixels = NULL; | |
7945 png_byte **rows = NULL; | |
7946 png_uint_32 width, height; | |
7947 int bit_depth, color_type, interlace_type; | |
7948 png_byte channels; | |
7949 png_uint_32 row_bytes; | |
7950 int transparent_p; | |
7951 char *gamma_str; | |
7952 double screen_gamma, image_gamma; | |
7953 int intent; | |
7954 | |
7955 /* Find out what file to load. */ | |
7956 specified_file = image_spec_value (img->spec, QCfile, NULL); | |
7957 file = x_find_image_file (specified_file); | |
7958 GCPRO1 (file); | |
7959 if (!STRINGP (file)) | |
7960 { | |
7961 image_error ("Cannot find image file %s", specified_file, Qnil); | |
7962 UNGCPRO; | |
7963 return 0; | |
7964 } | |
7965 | |
7966 /* Open the image file. */ | |
7967 fp = fopen (XSTRING (file)->data, "rb"); | |
7968 if (!fp) | |
7969 { | |
7970 image_error ("Cannot open image file %s", file, Qnil); | |
7971 UNGCPRO; | |
7972 fclose (fp); | |
7973 return 0; | |
7974 } | |
7975 | |
7976 /* Check PNG signature. */ | |
7977 if (fread (sig, 1, sizeof sig, fp) != sizeof sig | |
7978 || !png_check_sig (sig, sizeof sig)) | |
7979 { | |
7980 image_error ("Not a PNG file: %s", file, Qnil); | |
7981 UNGCPRO; | |
7982 fclose (fp); | |
7983 return 0; | |
7984 } | |
7985 | |
7986 /* Initialize read and info structs for PNG lib. */ | |
7987 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, | |
7988 my_png_error, my_png_warning); | |
7989 if (!png_ptr) | |
7990 { | |
7991 fclose (fp); | |
7992 UNGCPRO; | |
7993 return 0; | |
7994 } | |
7995 | |
7996 info_ptr = png_create_info_struct (png_ptr); | |
7997 if (!info_ptr) | |
7998 { | |
7999 png_destroy_read_struct (&png_ptr, NULL, NULL); | |
8000 fclose (fp); | |
8001 UNGCPRO; | |
8002 return 0; | |
8003 } | |
8004 | |
8005 end_info = png_create_info_struct (png_ptr); | |
8006 if (!end_info) | |
8007 { | |
8008 png_destroy_read_struct (&png_ptr, &info_ptr, NULL); | |
8009 fclose (fp); | |
8010 UNGCPRO; | |
8011 return 0; | |
8012 } | |
8013 | |
8014 /* Set error jump-back. We come back here when the PNG library | |
8015 detects an error. */ | |
8016 if (setjmp (png_ptr->jmpbuf)) | |
8017 { | |
8018 error: | |
8019 if (png_ptr) | |
8020 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); | |
8021 xfree (pixels); | |
8022 xfree (rows); | |
8023 if (fp) | |
8024 fclose (fp); | |
8025 UNGCPRO; | |
8026 return 0; | |
8027 } | |
8028 | |
8029 /* Read image info. */ | |
8030 png_init_io (png_ptr, fp); | |
8031 png_set_sig_bytes (png_ptr, sizeof sig); | |
8032 png_read_info (png_ptr, info_ptr); | |
8033 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, | |
8034 &interlace_type, NULL, NULL); | |
8035 | |
8036 /* If image contains simply transparency data, we prefer to | |
8037 construct a clipping mask. */ | |
8038 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) | |
8039 transparent_p = 1; | |
8040 else | |
8041 transparent_p = 0; | |
8042 | |
8043 /* This function is easier to write if we only have to handle | |
8044 one data format: RGB or RGBA with 8 bits per channel. Let's | |
8045 transform other formats into that format. */ | |
8046 | |
8047 /* Strip more than 8 bits per channel. */ | |
8048 if (bit_depth == 16) | |
8049 png_set_strip_16 (png_ptr); | |
8050 | |
8051 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel | |
8052 if available. */ | |
8053 png_set_expand (png_ptr); | |
8054 | |
8055 /* Convert grayscale images to RGB. */ | |
8056 if (color_type == PNG_COLOR_TYPE_GRAY | |
8057 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
8058 png_set_gray_to_rgb (png_ptr); | |
8059 | |
8060 /* The value 2.2 is a guess for PC monitors from PNG example.c. */ | |
8061 gamma_str = getenv ("SCREEN_GAMMA"); | |
8062 screen_gamma = gamma_str ? atof (gamma_str) : 2.2; | |
8063 | |
8064 /* Tell the PNG lib to handle gamma correction for us. */ | |
8065 | |
8066 if (png_get_sRGB (png_ptr, info_ptr, &intent)) | |
8067 /* There is a special chunk in the image specifying the gamma. */ | |
8068 png_set_sRGB (png_ptr, info_ptr, intent); | |
8069 else if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) | |
8070 /* Image contains gamma information. */ | |
8071 png_set_gamma (png_ptr, screen_gamma, image_gamma); | |
8072 else | |
8073 /* Use a default of 0.5 for the image gamma. */ | |
8074 png_set_gamma (png_ptr, screen_gamma, 0.5); | |
8075 | |
8076 /* Handle alpha channel by combining the image with a background | |
8077 color. Do this only if a real alpha channel is supplied. For | |
8078 simple transparency, we prefer a clipping mask. */ | |
8079 if (!transparent_p) | |
8080 { | |
8081 png_color_16 *image_background; | |
8082 | |
8083 if (png_get_bKGD (png_ptr, info_ptr, &image_background)) | |
8084 /* Image contains a background color with which to | |
8085 combine the image. */ | |
8086 png_set_background (png_ptr, image_background, | |
8087 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); | |
8088 else | |
8089 { | |
8090 /* Image does not contain a background color with which | |
8091 to combine the image data via an alpha channel. Use | |
8092 the frame's background instead. */ | |
8093 XColor color; | |
8094 Colormap cmap; | |
8095 png_color_16 frame_background; | |
8096 | |
8097 BLOCK_INPUT; | |
8098 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); | |
8099 color.pixel = FRAME_BACKGROUND_PIXEL (f); | |
8100 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color); | |
8101 UNBLOCK_INPUT; | |
8102 | |
8103 bzero (&frame_background, sizeof frame_background); | |
8104 frame_background.red = color.red; | |
8105 frame_background.green = color.green; | |
8106 frame_background.blue = color.blue; | |
8107 | |
8108 png_set_background (png_ptr, &frame_background, | |
8109 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); | |
8110 } | |
8111 } | |
8112 | |
8113 /* Update info structure. */ | |
8114 png_read_update_info (png_ptr, info_ptr); | |
8115 | |
8116 /* Get number of channels. Valid values are 1 for grayscale images | |
8117 and images with a palette, 2 for grayscale images with transparency | |
8118 information (alpha channel), 3 for RGB images, and 4 for RGB | |
8119 images with alpha channel, i.e. RGBA. If conversions above were | |
8120 sufficient we should only have 3 or 4 channels here. */ | |
8121 channels = png_get_channels (png_ptr, info_ptr); | |
8122 xassert (channels == 3 || channels == 4); | |
8123 | |
8124 /* Number of bytes needed for one row of the image. */ | |
8125 row_bytes = png_get_rowbytes (png_ptr, info_ptr); | |
8126 | |
8127 /* Allocate memory for the image. */ | |
8128 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels); | |
8129 rows = (png_byte **) xmalloc (height * sizeof *rows); | |
8130 for (i = 0; i < height; ++i) | |
8131 rows[i] = pixels + i * row_bytes; | |
8132 | |
8133 /* Read the entire image. */ | |
8134 png_read_image (png_ptr, rows); | |
8135 png_read_end (png_ptr, info_ptr); | |
8136 fclose (fp); | |
8137 fp = NULL; | |
8138 | |
8139 BLOCK_INPUT; | |
8140 | |
8141 /* Create the X image and pixmap. */ | |
8142 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, | |
8143 &img->pixmap)) | |
8144 { | |
8145 UNBLOCK_INPUT; | |
8146 goto error; | |
8147 } | |
8148 | |
8149 /* Create an image and pixmap serving as mask if the PNG image | |
8150 contains an alpha channel. */ | |
8151 if (channels == 4 | |
8152 && !transparent_p | |
8153 && !x_create_x_image_and_pixmap (f, file, width, height, 1, | |
8154 &mask_img, &img->mask)) | |
8155 { | |
8156 x_destroy_x_image (ximg); | |
8157 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); | |
8158 img->pixmap = 0; | |
8159 UNBLOCK_INPUT; | |
8160 goto error; | |
8161 } | |
8162 | |
8163 /* Fill the X image and mask from PNG data. */ | |
8164 init_color_table (); | |
8165 | |
8166 for (y = 0; y < height; ++y) | |
8167 { | |
8168 png_byte *p = rows[y]; | |
8169 | |
8170 for (x = 0; x < width; ++x) | |
8171 { | |
8172 unsigned r, g, b; | |
8173 | |
8174 r = *p++ << 8; | |
8175 g = *p++ << 8; | |
8176 b = *p++ << 8; | |
8177 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); | |
8178 | |
8179 /* An alpha channel, aka mask channel, associates variable | |
8180 transparency with an image. Where other image formats | |
8181 support binary transparency---fully transparent or fully | |
8182 opaque---PNG allows up to 254 levels of partial transparency. | |
8183 The PNG library implements partial transparency by combining | |
8184 the image with a specified background color. | |
8185 | |
8186 I'm not sure how to handle this here nicely: because the | |
8187 background on which the image is displayed may change, for | |
8188 real alpha channel support, it would be necessary to create | |
8189 a new image for each possible background. | |
8190 | |
8191 What I'm doing now is that a mask is created if we have | |
8192 boolean transparency information. Otherwise I'm using | |
8193 the frame's background color to combine the image with. */ | |
8194 | |
8195 if (channels == 4) | |
8196 { | |
8197 if (mask_img) | |
8198 XPutPixel (mask_img, x, y, *p > 0); | |
8199 ++p; | |
8200 } | |
8201 } | |
8202 } | |
8203 | |
8204 /* Remember colors allocated for this image. */ | |
8205 img->colors = colors_in_color_table (&img->ncolors); | |
8206 free_color_table (); | |
8207 | |
8208 /* Clean up. */ | |
8209 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); | |
8210 xfree (rows); | |
8211 xfree (pixels); | |
8212 | |
8213 img->width = width; | |
8214 img->height = height; | |
8215 | |
8216 /* Put the image into the pixmap, then free the X image and its buffer. */ | |
8217 x_put_x_image (f, ximg, img->pixmap, width, height); | |
8218 x_destroy_x_image (ximg); | |
8219 | |
8220 /* Same for the mask. */ | |
8221 if (mask_img) | |
8222 { | |
8223 x_put_x_image (f, mask_img, img->mask, img->width, img->height); | |
8224 x_destroy_x_image (mask_img); | |
8225 } | |
8226 | |
8227 UNBLOCK_INPUT; | |
8228 UNGCPRO; | |
8229 return 1; | |
8230 } | |
8231 | |
8232 #endif /* HAVE_PNG != 0 */ | |
8233 | |
8234 | |
8235 | |
8236 /*********************************************************************** | |
8237 JPEG | |
8238 ***********************************************************************/ | |
8239 | |
8240 #if HAVE_JPEG | |
8241 | |
8242 #include <jpeglib.h> | |
8243 #include <jerror.h> | |
8244 #include <setjmp.h> | |
8245 | |
8246 static int jpeg_image_p P_ ((Lisp_Object object)); | |
8247 static int jpeg_load P_ ((struct frame *f, struct image *img)); | |
8248 | |
8249 /* The symbol `jpeg' identifying images of this type. */ | |
8250 | |
8251 Lisp_Object Qjpeg; | |
8252 | |
8253 /* Indices of image specification fields in gs_format, below. */ | |
8254 | |
8255 enum jpeg_keyword_index | |
8256 { | |
8257 JPEG_TYPE, | |
8258 JPEG_FILE, | |
8259 JPEG_ASCENT, | |
8260 JPEG_MARGIN, | |
8261 JPEG_RELIEF, | |
8262 JPEG_ALGORITHM, | |
8263 JPEG_HEURISTIC_MASK, | |
8264 JPEG_LAST | |
8265 }; | |
8266 | |
8267 /* Vector of image_keyword structures describing the format | |
8268 of valid user-defined image specifications. */ | |
8269 | |
8270 static struct image_keyword jpeg_format[JPEG_LAST] = | |
8271 { | |
8272 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
8273 {":file", IMAGE_STRING_VALUE, 1}, | |
8274 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
8275 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
8276 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
8277 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8278 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
8279 }; | |
8280 | |
8281 /* Structure describing the image type `jpeg'. */ | |
8282 | |
8283 static struct image_type jpeg_type = | |
8284 { | |
8285 &Qjpeg, | |
8286 jpeg_image_p, | |
8287 jpeg_load, | |
8288 x_clear_image, | |
8289 NULL | |
8290 }; | |
8291 | |
8292 | |
8293 /* Return non-zero if OBJECT is a valid JPEG image specification. */ | |
8294 | |
8295 static int | |
8296 jpeg_image_p (object) | |
8297 Lisp_Object object; | |
8298 { | |
8299 struct image_keyword fmt[JPEG_LAST]; | |
8300 | |
8301 bcopy (jpeg_format, fmt, sizeof fmt); | |
8302 | |
8303 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg, 0) | |
8304 || (fmt[JPEG_ASCENT].count | |
8305 && XFASTINT (fmt[JPEG_ASCENT].value) > 100)) | |
8306 return 0; | |
8307 return 1; | |
8308 } | |
8309 | |
8310 struct my_jpeg_error_mgr | |
8311 { | |
8312 struct jpeg_error_mgr pub; | |
8313 jmp_buf setjmp_buffer; | |
8314 }; | |
8315 | |
8316 static void | |
8317 my_error_exit (cinfo) | |
8318 j_common_ptr cinfo; | |
8319 { | |
8320 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err; | |
8321 longjmp (mgr->setjmp_buffer, 1); | |
8322 } | |
8323 | |
8324 /* Load image IMG for use on frame F. Patterned after example.c | |
8325 from the JPEG lib. */ | |
8326 | |
8327 static int | |
8328 jpeg_load (f, img) | |
8329 struct frame *f; | |
8330 struct image *img; | |
8331 { | |
8332 struct jpeg_decompress_struct cinfo; | |
8333 struct my_jpeg_error_mgr mgr; | |
8334 Lisp_Object file, specified_file; | |
8335 FILE *fp; | |
8336 JSAMPARRAY buffer; | |
8337 int row_stride, x, y; | |
8338 XImage *ximg = NULL; | |
8339 int rc, value; | |
8340 unsigned long *colors; | |
8341 int width, height; | |
8342 struct gcpro gcpro1; | |
8343 | |
8344 /* Open the JPEG file. */ | |
8345 specified_file = image_spec_value (img->spec, QCfile, NULL); | |
8346 file = x_find_image_file (specified_file); | |
8347 GCPRO1 (file); | |
8348 if (!STRINGP (file)) | |
8349 { | |
8350 image_error ("Cannot find image file %s", specified_file, Qnil); | |
8351 UNGCPRO; | |
8352 return 0; | |
8353 } | |
8354 | |
8355 fp = fopen (XSTRING (file)->data, "r"); | |
8356 if (fp == NULL) | |
8357 { | |
8358 image_error ("Cannot open `%s'", file, Qnil); | |
8359 UNGCPRO; | |
8360 return 0; | |
8361 } | |
8362 | |
8363 /* Customize libjpeg's error handling to call my_error_exit | |
8364 when an error is detected. This function will perform | |
8365 a longjmp. */ | |
8366 mgr.pub.error_exit = my_error_exit; | |
8367 cinfo.err = jpeg_std_error (&mgr.pub); | |
8368 | |
8369 if ((rc = setjmp (mgr.setjmp_buffer)) != 0) | |
8370 { | |
8371 if (rc == 1) | |
8372 { | |
8373 /* Called from my_error_exit. Display a JPEG error. */ | |
8374 char buffer[JMSG_LENGTH_MAX]; | |
8375 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); | |
8376 image_error ("Error reading JPEG file `%s': %s", file, | |
8377 build_string (buffer)); | |
8378 } | |
8379 | |
8380 /* Close the input file and destroy the JPEG object. */ | |
8381 fclose (fp); | |
8382 jpeg_destroy_decompress (&cinfo); | |
8383 | |
8384 BLOCK_INPUT; | |
8385 | |
8386 /* If we already have an XImage, free that. */ | |
8387 x_destroy_x_image (ximg); | |
8388 | |
8389 /* Free pixmap and colors. */ | |
8390 x_clear_image (f, img); | |
8391 | |
8392 UNBLOCK_INPUT; | |
8393 UNGCPRO; | |
8394 return 0; | |
8395 } | |
8396 | |
8397 /* Create the JPEG decompression object. Let it read from fp. | |
8398 Read the JPEG image header. */ | |
8399 jpeg_create_decompress (&cinfo); | |
8400 jpeg_stdio_src (&cinfo, fp); | |
8401 jpeg_read_header (&cinfo, TRUE); | |
8402 | |
8403 /* Customize decompression so that color quantization will be used. | |
8404 Start decompression. */ | |
8405 cinfo.quantize_colors = TRUE; | |
8406 jpeg_start_decompress (&cinfo); | |
8407 width = img->width = cinfo.output_width; | |
8408 height = img->height = cinfo.output_height; | |
8409 | |
8410 BLOCK_INPUT; | |
8411 | |
8412 /* Create X image and pixmap. */ | |
8413 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, | |
8414 &img->pixmap)) | |
8415 { | |
8416 UNBLOCK_INPUT; | |
8417 longjmp (mgr.setjmp_buffer, 2); | |
8418 } | |
8419 | |
8420 /* Allocate colors. When color quantization is used, | |
8421 cinfo.actual_number_of_colors has been set with the number of | |
8422 colors generated, and cinfo.colormap is a two-dimensional array | |
8423 of color indices in the range 0..cinfo.actual_number_of_colors. | |
8424 No more than 255 colors will be generated. */ | |
8425 { | |
8426 int i, ir, ig, ib; | |
8427 | |
8428 if (cinfo.out_color_components > 2) | |
8429 ir = 0, ig = 1, ib = 2; | |
8430 else if (cinfo.out_color_components > 1) | |
8431 ir = 0, ig = 1, ib = 0; | |
8432 else | |
8433 ir = 0, ig = 0, ib = 0; | |
8434 | |
8435 /* Use the color table mechanism because it handles colors that | |
8436 cannot be allocated nicely. Such colors will be replaced with | |
8437 a default color, and we don't have to care about which colors | |
8438 can be freed safely, and which can't. */ | |
8439 init_color_table (); | |
8440 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors | |
8441 * sizeof *colors); | |
8442 | |
8443 for (i = 0; i < cinfo.actual_number_of_colors; ++i) | |
8444 { | |
8445 /* Multiply RGB values with 255 because X expects RGB values | |
8446 in the range 0..0xffff. */ | |
8447 int r = cinfo.colormap[ir][i] << 8; | |
8448 int g = cinfo.colormap[ig][i] << 8; | |
8449 int b = cinfo.colormap[ib][i] << 8; | |
8450 colors[i] = lookup_rgb_color (f, r, g, b); | |
8451 } | |
8452 | |
8453 /* Remember those colors actually allocated. */ | |
8454 img->colors = colors_in_color_table (&img->ncolors); | |
8455 free_color_table (); | |
8456 } | |
8457 | |
8458 /* Read pixels. */ | |
8459 row_stride = width * cinfo.output_components; | |
8460 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, | |
8461 row_stride, 1); | |
8462 for (y = 0; y < height; ++y) | |
8463 { | |
8464 jpeg_read_scanlines (&cinfo, buffer, 1); | |
8465 for (x = 0; x < cinfo.output_width; ++x) | |
8466 XPutPixel (ximg, x, y, colors[buffer[0][x]]); | |
8467 } | |
8468 | |
8469 /* Clean up. */ | |
8470 jpeg_finish_decompress (&cinfo); | |
8471 jpeg_destroy_decompress (&cinfo); | |
8472 fclose (fp); | |
8473 | |
8474 /* Put the image into the pixmap. */ | |
8475 x_put_x_image (f, ximg, img->pixmap, width, height); | |
8476 x_destroy_x_image (ximg); | |
8477 UNBLOCK_INPUT; | |
8478 UNGCPRO; | |
8479 return 1; | |
8480 } | |
8481 | |
8482 #endif /* HAVE_JPEG */ | |
8483 | |
8484 | |
8485 | |
8486 /*********************************************************************** | |
8487 TIFF | |
8488 ***********************************************************************/ | |
8489 | |
8490 #if HAVE_TIFF | |
8491 | |
8492 #include <tiff34/tiffio.h> | |
8493 | |
8494 static int tiff_image_p P_ ((Lisp_Object object)); | |
8495 static int tiff_load P_ ((struct frame *f, struct image *img)); | |
8496 | |
8497 /* The symbol `tiff' identifying images of this type. */ | |
8498 | |
8499 Lisp_Object Qtiff; | |
8500 | |
8501 /* Indices of image specification fields in tiff_format, below. */ | |
8502 | |
8503 enum tiff_keyword_index | |
8504 { | |
8505 TIFF_TYPE, | |
8506 TIFF_FILE, | |
8507 TIFF_ASCENT, | |
8508 TIFF_MARGIN, | |
8509 TIFF_RELIEF, | |
8510 TIFF_ALGORITHM, | |
8511 TIFF_HEURISTIC_MASK, | |
8512 TIFF_LAST | |
8513 }; | |
8514 | |
8515 /* Vector of image_keyword structures describing the format | |
8516 of valid user-defined image specifications. */ | |
8517 | |
8518 static struct image_keyword tiff_format[TIFF_LAST] = | |
8519 { | |
8520 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
8521 {":file", IMAGE_STRING_VALUE, 1}, | |
8522 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
8523 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
8524 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
8525 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8526 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
8527 }; | |
8528 | |
8529 /* Structure describing the image type `tiff'. */ | |
8530 | |
8531 static struct image_type tiff_type = | |
8532 { | |
8533 &Qtiff, | |
8534 tiff_image_p, | |
8535 tiff_load, | |
8536 x_clear_image, | |
8537 NULL | |
8538 }; | |
8539 | |
8540 | |
8541 /* Return non-zero if OBJECT is a valid TIFF image specification. */ | |
8542 | |
8543 static int | |
8544 tiff_image_p (object) | |
8545 Lisp_Object object; | |
8546 { | |
8547 struct image_keyword fmt[TIFF_LAST]; | |
8548 bcopy (tiff_format, fmt, sizeof fmt); | |
8549 | |
8550 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff, 1) | |
8551 || (fmt[TIFF_ASCENT].count | |
8552 && XFASTINT (fmt[TIFF_ASCENT].value) > 100)) | |
8553 return 0; | |
8554 return 1; | |
8555 } | |
8556 | |
8557 | |
8558 /* Load TIFF image IMG for use on frame F. Value is non-zero if | |
8559 successful. */ | |
8560 | |
8561 static int | |
8562 tiff_load (f, img) | |
8563 struct frame *f; | |
8564 struct image *img; | |
8565 { | |
8566 Lisp_Object file, specified_file; | |
8567 TIFF *tiff; | |
8568 int width, height, x, y; | |
8569 uint32 *buf; | |
8570 int rc; | |
8571 XImage *ximg; | |
8572 struct gcpro gcpro1; | |
8573 | |
8574 specified_file = image_spec_value (img->spec, QCfile, NULL); | |
8575 file = x_find_image_file (specified_file); | |
8576 GCPRO1 (file); | |
8577 if (!STRINGP (file)) | |
8578 { | |
8579 image_error ("Cannot find image file %s", file, Qnil); | |
8580 UNGCPRO; | |
8581 return 0; | |
8582 } | |
8583 | |
8584 /* Try to open the image file. */ | |
8585 tiff = TIFFOpen (XSTRING (file)->data, "r"); | |
8586 if (tiff == NULL) | |
8587 { | |
8588 image_error ("Cannot open `%s'", file, Qnil); | |
8589 UNGCPRO; | |
8590 return 0; | |
8591 } | |
8592 | |
8593 /* Get width and height of the image, and allocate a raster buffer | |
8594 of width x height 32-bit values. */ | |
8595 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); | |
8596 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); | |
8597 buf = (uint32 *) xmalloc (width * height * sizeof *buf); | |
8598 | |
8599 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0); | |
8600 TIFFClose (tiff); | |
8601 if (!rc) | |
8602 { | |
8603 image_error ("Error reading `%s'", file, Qnil); | |
8604 xfree (buf); | |
8605 UNGCPRO; | |
8606 return 0; | |
8607 } | |
8608 | |
8609 BLOCK_INPUT; | |
8610 | |
8611 /* Create the X image and pixmap. */ | |
8612 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, | |
8613 &img->pixmap)) | |
8614 { | |
8615 UNBLOCK_INPUT; | |
8616 xfree (buf); | |
8617 UNGCPRO; | |
8618 return 0; | |
8619 } | |
8620 | |
8621 /* Initialize the color table. */ | |
8622 init_color_table (); | |
8623 | |
8624 /* Process the pixel raster. Origin is in the lower-left corner. */ | |
8625 for (y = 0; y < height; ++y) | |
8626 { | |
8627 uint32 *row = buf + y * width; | |
8628 | |
8629 for (x = 0; x < width; ++x) | |
8630 { | |
8631 uint32 abgr = row[x]; | |
8632 int r = TIFFGetR (abgr) << 8; | |
8633 int g = TIFFGetG (abgr) << 8; | |
8634 int b = TIFFGetB (abgr) << 8; | |
8635 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b)); | |
8636 } | |
8637 } | |
8638 | |
8639 /* Remember the colors allocated for the image. Free the color table. */ | |
8640 img->colors = colors_in_color_table (&img->ncolors); | |
8641 free_color_table (); | |
8642 | |
8643 /* Put the image into the pixmap, then free the X image and its buffer. */ | |
8644 x_put_x_image (f, ximg, img->pixmap, width, height); | |
8645 x_destroy_x_image (ximg); | |
8646 xfree (buf); | |
8647 UNBLOCK_INPUT; | |
8648 | |
8649 img->width = width; | |
8650 img->height = height; | |
8651 | |
8652 UNGCPRO; | |
8653 return 1; | |
8654 } | |
8655 | |
8656 #endif /* HAVE_TIFF != 0 */ | |
8657 | |
8658 | |
8659 | |
8660 /*********************************************************************** | |
8661 GIF | |
8662 ***********************************************************************/ | |
8663 | |
8664 #if HAVE_GIF | |
8665 | |
8666 #include <gif_lib.h> | |
8667 | |
8668 static int gif_image_p P_ ((Lisp_Object object)); | |
8669 static int gif_load P_ ((struct frame *f, struct image *img)); | |
8670 | |
8671 /* The symbol `gif' identifying images of this type. */ | |
8672 | |
8673 Lisp_Object Qgif; | |
8674 | |
8675 /* Indices of image specification fields in gif_format, below. */ | |
8676 | |
8677 enum gif_keyword_index | |
8678 { | |
8679 GIF_TYPE, | |
8680 GIF_FILE, | |
8681 GIF_ASCENT, | |
8682 GIF_MARGIN, | |
8683 GIF_RELIEF, | |
8684 GIF_ALGORITHM, | |
8685 GIF_HEURISTIC_MASK, | |
8686 GIF_IMAGE, | |
8687 GIF_LAST | |
8688 }; | |
8689 | |
8690 /* Vector of image_keyword structures describing the format | |
8691 of valid user-defined image specifications. */ | |
8692 | |
8693 static struct image_keyword gif_format[GIF_LAST] = | |
8694 { | |
8695 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
8696 {":file", IMAGE_STRING_VALUE, 1}, | |
8697 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
8698 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
8699 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
8700 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8701 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8702 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0} | |
8703 }; | |
8704 | |
8705 /* Structure describing the image type `gif'. */ | |
8706 | |
8707 static struct image_type gif_type = | |
8708 { | |
8709 &Qgif, | |
8710 gif_image_p, | |
8711 gif_load, | |
8712 x_clear_image, | |
8713 NULL | |
8714 }; | |
8715 | |
8716 | |
8717 /* Return non-zero if OBJECT is a valid GIF image specification. */ | |
8718 | |
8719 static int | |
8720 gif_image_p (object) | |
8721 Lisp_Object object; | |
8722 { | |
8723 struct image_keyword fmt[GIF_LAST]; | |
8724 bcopy (gif_format, fmt, sizeof fmt); | |
8725 | |
8726 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif, 1) | |
8727 || (fmt[GIF_ASCENT].count | |
8728 && XFASTINT (fmt[GIF_ASCENT].value) > 100)) | |
8729 return 0; | |
8730 return 1; | |
8731 } | |
8732 | |
8733 | |
8734 /* Load GIF image IMG for use on frame F. Value is non-zero if | |
8735 successful. */ | |
8736 | |
8737 static int | |
8738 gif_load (f, img) | |
8739 struct frame *f; | |
8740 struct image *img; | |
8741 { | |
8742 Lisp_Object file, specified_file; | |
8743 int rc, width, height, x, y, i; | |
8744 XImage *ximg; | |
8745 ColorMapObject *gif_color_map; | |
8746 unsigned long pixel_colors[256]; | |
8747 GifFileType *gif; | |
8748 struct gcpro gcpro1; | |
8749 Lisp_Object image; | |
8750 int ino, image_left, image_top, image_width, image_height; | |
8751 int bg; | |
8752 | |
8753 specified_file = image_spec_value (img->spec, QCfile, NULL); | |
8754 file = x_find_image_file (specified_file); | |
8755 GCPRO1 (file); | |
8756 if (!STRINGP (file)) | |
8757 { | |
8758 image_error ("Cannot find image file %s", specified_file, Qnil); | |
8759 UNGCPRO; | |
8760 return 0; | |
8761 } | |
8762 | |
8763 /* Open the GIF file. */ | |
8764 gif = DGifOpenFileName (XSTRING (file)->data); | |
8765 if (gif == NULL) | |
8766 { | |
8767 image_error ("Cannot open `%s'", file, Qnil); | |
8768 UNGCPRO; | |
8769 return 0; | |
8770 } | |
8771 | |
8772 /* Read entire contents. */ | |
8773 rc = DGifSlurp (gif); | |
8774 if (rc == GIF_ERROR) | |
8775 { | |
8776 image_error ("Error reading `%s'", file, Qnil); | |
8777 DGifCloseFile (gif); | |
8778 UNGCPRO; | |
8779 return 0; | |
8780 } | |
8781 | |
8782 image = image_spec_value (img->spec, QCimage, NULL); | |
8783 ino = INTEGERP (image) ? XFASTINT (image) : 0; | |
8784 if (ino >= gif->ImageCount) | |
8785 { | |
8786 image_error ("Invalid image number `%s'", image, Qnil); | |
8787 DGifCloseFile (gif); | |
8788 UNGCPRO; | |
8789 return 0; | |
8790 } | |
8791 | |
8792 width = img->width = gif->SWidth; | |
8793 height = img->height = gif->SHeight; | |
8794 | |
8795 BLOCK_INPUT; | |
8796 | |
8797 /* Create the X image and pixmap. */ | |
8798 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, | |
8799 &img->pixmap)) | |
8800 { | |
8801 UNBLOCK_INPUT; | |
8802 DGifCloseFile (gif); | |
8803 UNGCPRO; | |
8804 return 0; | |
8805 } | |
8806 | |
8807 /* Allocate colors. */ | |
8808 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; | |
8809 if (!gif_color_map) | |
8810 gif_color_map = gif->SColorMap; | |
8811 init_color_table (); | |
8812 bzero (pixel_colors, sizeof pixel_colors); | |
8813 | |
8814 for (i = 0; i < gif_color_map->ColorCount; ++i) | |
8815 { | |
8816 int r = gif_color_map->Colors[i].Red << 8; | |
8817 int g = gif_color_map->Colors[i].Green << 8; | |
8818 int b = gif_color_map->Colors[i].Blue << 8; | |
8819 pixel_colors[i] = lookup_rgb_color (f, r, g, b); | |
8820 } | |
8821 | |
8822 img->colors = colors_in_color_table (&img->ncolors); | |
8823 free_color_table (); | |
8824 | |
8825 /* Clear the part of the screen image that are not covered by | |
8826 the image from the GIF file. Full animated GIF support | |
8827 requires more than can be done here (see the gif89 spec, | |
8828 disposal methods). Let's simply assume that the part | |
8829 not covered by a sub-image is in the frame's background color. */ | |
8830 image_top = gif->SavedImages[ino].ImageDesc.Top; | |
8831 image_left = gif->SavedImages[ino].ImageDesc.Left; | |
8832 image_width = gif->SavedImages[ino].ImageDesc.Width; | |
8833 image_height = gif->SavedImages[ino].ImageDesc.Height; | |
8834 | |
8835 for (y = 0; y < image_top; ++y) | |
8836 for (x = 0; x < width; ++x) | |
8837 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); | |
8838 | |
8839 for (y = image_top + image_height; y < height; ++y) | |
8840 for (x = 0; x < width; ++x) | |
8841 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); | |
8842 | |
8843 for (y = image_top; y < image_top + image_height; ++y) | |
8844 { | |
8845 for (x = 0; x < image_left; ++x) | |
8846 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); | |
8847 for (x = image_left + image_width; x < width; ++x) | |
8848 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); | |
8849 } | |
8850 | |
8851 /* Read the GIF image into the X image. */ | |
8852 if (gif->SavedImages[ino].ImageDesc.Interlace) | |
8853 { | |
8854 static int interlace_start[] = {0, 4, 2, 1}; | |
8855 static int interlace_increment[] = {8, 8, 4, 2}; | |
8856 int pass, inc; | |
8857 | |
8858 for (pass = 0; pass < 4; ++pass) | |
8859 { | |
8860 inc = interlace_increment[pass]; | |
8861 for (y = interlace_start[pass]; y < image_height; y += inc) | |
8862 for (x = 0; x < image_width; ++x) | |
8863 { | |
8864 unsigned i = gif->SavedImages[ino].RasterBits[y * image_width + x]; | |
8865 XPutPixel (ximg, x + image_left, y + image_top, | |
8866 pixel_colors[i]); | |
8867 } | |
8868 } | |
8869 } | |
8870 else | |
8871 { | |
8872 for (y = 0; y < image_height; ++y) | |
8873 for (x = 0; x < image_width; ++x) | |
8874 { | |
8875 unsigned i = gif->SavedImages[ino].RasterBits[y * image_width + x]; | |
8876 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); | |
8877 } | |
8878 } | |
8879 | |
8880 DGifCloseFile (gif); | |
8881 | |
8882 /* Put the image into the pixmap, then free the X image and its buffer. */ | |
8883 x_put_x_image (f, ximg, img->pixmap, width, height); | |
8884 x_destroy_x_image (ximg); | |
8885 UNBLOCK_INPUT; | |
8886 | |
8887 UNGCPRO; | |
8888 return 1; | |
8889 } | |
8890 | |
8891 #endif /* HAVE_GIF != 0 */ | |
8892 | |
8893 | |
8894 | |
8895 /*********************************************************************** | |
8896 Ghostscript | |
8897 ***********************************************************************/ | |
8898 | |
8899 static int gs_image_p P_ ((Lisp_Object object)); | |
8900 static int gs_load P_ ((struct frame *f, struct image *img)); | |
8901 static void gs_clear_image P_ ((struct frame *f, struct image *img)); | |
8902 | |
8903 /* The symbol `ghostscript' identifying images of this type. */ | |
8904 | |
8905 Lisp_Object Qghostscript; | |
8906 | |
8907 /* Keyword symbols. */ | |
8908 | |
8909 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; | |
8910 | |
8911 /* Indices of image specification fields in gs_format, below. */ | |
8912 | |
8913 enum gs_keyword_index | |
8914 { | |
8915 GS_TYPE, | |
8916 GS_PT_WIDTH, | |
8917 GS_PT_HEIGHT, | |
8918 GS_FILE, | |
8919 GS_LOADER, | |
8920 GS_BOUNDING_BOX, | |
8921 GS_ASCENT, | |
8922 GS_MARGIN, | |
8923 GS_RELIEF, | |
8924 GS_ALGORITHM, | |
8925 GS_HEURISTIC_MASK, | |
8926 GS_LAST | |
8927 }; | |
8928 | |
8929 /* Vector of image_keyword structures describing the format | |
8930 of valid user-defined image specifications. */ | |
8931 | |
8932 static struct image_keyword gs_format[GS_LAST] = | |
8933 { | |
8934 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
8935 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1}, | |
8936 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1}, | |
8937 {":file", IMAGE_STRING_VALUE, 1}, | |
8938 {":loader", IMAGE_FUNCTION_VALUE, 0}, | |
8939 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, | |
8940 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, | |
8941 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, | |
8942 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
8943 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8944 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} | |
8945 }; | |
8946 | |
8947 /* Structure describing the image type `ghostscript'. */ | |
8948 | |
8949 static struct image_type gs_type = | |
8950 { | |
8951 &Qghostscript, | |
8952 gs_image_p, | |
8953 gs_load, | |
8954 gs_clear_image, | |
8955 NULL | |
8956 }; | |
8957 | |
8958 | |
8959 /* Free X resources of Ghostscript image IMG which is used on frame F. */ | |
8960 | |
8961 static void | |
8962 gs_clear_image (f, img) | |
8963 struct frame *f; | |
8964 struct image *img; | |
8965 { | |
8966 /* IMG->data.ptr_val may contain a recorded colormap. */ | |
8967 xfree (img->data.ptr_val); | |
8968 x_clear_image (f, img); | |
8969 } | |
8970 | |
8971 | |
8972 /* Return non-zero if OBJECT is a valid Ghostscript image | |
8973 specification. */ | |
8974 | |
8975 static int | |
8976 gs_image_p (object) | |
8977 Lisp_Object object; | |
8978 { | |
8979 struct image_keyword fmt[GS_LAST]; | |
8980 Lisp_Object tem; | |
8981 int i; | |
8982 | |
8983 bcopy (gs_format, fmt, sizeof fmt); | |
8984 | |
8985 if (!parse_image_spec (object, fmt, GS_LAST, Qghostscript, 1) | |
8986 || (fmt[GS_ASCENT].count | |
8987 && XFASTINT (fmt[GS_ASCENT].value) > 100)) | |
8988 return 0; | |
8989 | |
8990 /* Bounding box must be a list or vector containing 4 integers. */ | |
8991 tem = fmt[GS_BOUNDING_BOX].value; | |
8992 if (CONSP (tem)) | |
8993 { | |
8994 for (i = 0; i < 4; ++i, tem = XCDR (tem)) | |
8995 if (!CONSP (tem) || !INTEGERP (XCAR (tem))) | |
8996 return 0; | |
8997 if (!NILP (tem)) | |
8998 return 0; | |
8999 } | |
9000 else if (VECTORP (tem)) | |
9001 { | |
9002 if (XVECTOR (tem)->size != 4) | |
9003 return 0; | |
9004 for (i = 0; i < 4; ++i) | |
9005 if (!INTEGERP (XVECTOR (tem)->contents[i])) | |
9006 return 0; | |
9007 } | |
9008 else | |
9009 return 0; | |
9010 | |
9011 return 1; | |
9012 } | |
9013 | |
9014 | |
9015 /* Load Ghostscript image IMG for use on frame F. Value is non-zero | |
9016 if successful. */ | |
9017 | |
9018 static int | |
9019 gs_load (f, img) | |
9020 struct frame *f; | |
9021 struct image *img; | |
9022 { | |
9023 char buffer[100]; | |
9024 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; | |
9025 struct gcpro gcpro1, gcpro2; | |
9026 Lisp_Object frame; | |
9027 double in_width, in_height; | |
9028 Lisp_Object pixel_colors = Qnil; | |
9029 | |
9030 /* Compute pixel size of pixmap needed from the given size in the | |
9031 image specification. Sizes in the specification are in pt. 1 pt | |
9032 = 1/72 in, xdpi and ydpi are stored in the frame's X display | |
9033 info. */ | |
9034 pt_width = image_spec_value (img->spec, QCpt_width, NULL); | |
9035 in_width = XFASTINT (pt_width) / 72.0; | |
9036 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx; | |
9037 pt_height = image_spec_value (img->spec, QCpt_height, NULL); | |
9038 in_height = XFASTINT (pt_height) / 72.0; | |
9039 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy; | |
9040 | |
9041 /* Create the pixmap. */ | |
9042 BLOCK_INPUT; | |
9043 xassert (img->pixmap == 0); | |
9044 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
9045 img->width, img->height, | |
9046 DefaultDepthOfScreen (FRAME_X_SCREEN (f))); | |
9047 UNBLOCK_INPUT; | |
9048 | |
9049 if (!img->pixmap) | |
9050 { | |
9051 image_error ("Unable to create pixmap for `%s'", | |
9052 image_spec_value (img->spec, QCfile, NULL), Qnil); | |
9053 return 0; | |
9054 } | |
9055 | |
9056 /* Call the loader to fill the pixmap. It returns a process object | |
9057 if successful. We do not record_unwind_protect here because | |
9058 other places in redisplay like calling window scroll functions | |
9059 don't either. Let the Lisp loader use `unwind-protect' instead. */ | |
9060 GCPRO2 (window_and_pixmap_id, pixel_colors); | |
9061 | |
9062 sprintf (buffer, "%lu %lu", | |
9063 (unsigned long) FRAME_X_WINDOW (f), | |
9064 (unsigned long) img->pixmap); | |
9065 window_and_pixmap_id = build_string (buffer); | |
9066 | |
9067 sprintf (buffer, "%lu %lu", | |
9068 FRAME_FOREGROUND_PIXEL (f), | |
9069 FRAME_BACKGROUND_PIXEL (f)); | |
9070 pixel_colors = build_string (buffer); | |
9071 | |
9072 XSETFRAME (frame, f); | |
9073 loader = image_spec_value (img->spec, QCloader, NULL); | |
9074 if (NILP (loader)) | |
9075 loader = intern ("gs-load-image"); | |
9076 | |
9077 img->data.lisp_val = call6 (loader, frame, img->spec, | |
9078 make_number (img->width), | |
9079 make_number (img->height), | |
9080 window_and_pixmap_id, | |
9081 pixel_colors); | |
9082 UNGCPRO; | |
9083 return PROCESSP (img->data.lisp_val); | |
9084 } | |
9085 | |
9086 | |
9087 /* Kill the Ghostscript process that was started to fill PIXMAP on | |
9088 frame F. Called from XTread_socket when receiving an event | |
9089 telling Emacs that Ghostscript has finished drawing. */ | |
9090 | |
9091 void | |
9092 x_kill_gs_process (pixmap, f) | |
9093 Pixmap pixmap; | |
9094 struct frame *f; | |
9095 { | |
9096 struct image_cache *c = FRAME_X_IMAGE_CACHE (f); | |
9097 int class, i; | |
9098 struct image *img; | |
9099 | |
9100 /* Find the image containing PIXMAP. */ | |
9101 for (i = 0; i < c->used; ++i) | |
9102 if (c->images[i]->pixmap == pixmap) | |
9103 break; | |
9104 | |
9105 /* Kill the GS process. We should have found PIXMAP in the image | |
9106 cache and its image should contain a process object. */ | |
9107 xassert (i < c->used); | |
9108 img = c->images[i]; | |
9109 xassert (PROCESSP (img->data.lisp_val)); | |
9110 Fkill_process (img->data.lisp_val, Qnil); | |
9111 img->data.lisp_val = Qnil; | |
9112 | |
9113 /* On displays with a mutable colormap, figure out the colors | |
9114 allocated for the image by looking at the pixels of an XImage for | |
9115 img->pixmap. */ | |
9116 class = FRAME_X_DISPLAY_INFO (f)->visual->class; | |
9117 if (class != StaticColor && class != StaticGray && class != TrueColor) | |
9118 { | |
9119 XImage *ximg; | |
9120 | |
9121 BLOCK_INPUT; | |
9122 | |
9123 /* Try to get an XImage for img->pixmep. */ | |
9124 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, | |
9125 0, 0, img->width, img->height, ~0, ZPixmap); | |
9126 if (ximg) | |
9127 { | |
9128 int x, y; | |
9129 | |
9130 /* Initialize the color table. */ | |
9131 init_color_table (); | |
9132 | |
9133 /* For each pixel of the image, look its color up in the | |
9134 color table. After having done so, the color table will | |
9135 contain an entry for each color used by the image. */ | |
9136 for (y = 0; y < img->height; ++y) | |
9137 for (x = 0; x < img->width; ++x) | |
9138 { | |
9139 unsigned long pixel = XGetPixel (ximg, x, y); | |
9140 lookup_pixel_color (f, pixel); | |
9141 } | |
9142 | |
9143 /* Record colors in the image. Free color table and XImage. */ | |
9144 img->colors = colors_in_color_table (&img->ncolors); | |
9145 free_color_table (); | |
9146 XDestroyImage (ximg); | |
9147 | |
9148 #if 0 /* This doesn't seem to be the case. If we free the colors | |
9149 here, we get a BadAccess later in x_clear_image when | |
9150 freeing the colors. */ | |
9151 /* We have allocated colors once, but Ghostscript has also | |
9152 allocated colors on behalf of us. So, to get the | |
9153 reference counts right, free them once. */ | |
9154 if (img->ncolors) | |
9155 { | |
9156 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); | |
9157 XFreeColors (FRAME_X_DISPLAY (f), cmap, | |
9158 img->colors, img->ncolors, 0); | |
9159 } | |
9160 #endif | |
9161 } | |
9162 else | |
9163 image_error ("Cannot get X image of `%s'; colors will not be freed", | |
9164 image_spec_value (img->spec, QCfile, NULL), Qnil); | |
9165 | |
9166 UNBLOCK_INPUT; | |
9167 } | |
9168 } | |
9169 | |
9170 | |
9171 | |
9172 /*********************************************************************** | |
9173 Window properties | |
9174 ***********************************************************************/ | |
9175 | |
9176 DEFUN ("x-change-window-property", Fx_change_window_property, | |
9177 Sx_change_window_property, 2, 3, 0, | |
9178 "Change window property PROP to VALUE on the X window of FRAME.\n\ | |
9179 PROP and VALUE must be strings. FRAME nil or omitted means use the\n\ | |
9180 selected frame. Value is VALUE.") | |
9181 (prop, value, frame) | |
9182 Lisp_Object frame, prop, value; | |
9183 { | |
9184 struct frame *f = check_x_frame (frame); | |
9185 Atom prop_atom; | |
9186 | |
9187 CHECK_STRING (prop, 1); | |
9188 CHECK_STRING (value, 2); | |
9189 | |
9190 BLOCK_INPUT; | |
9191 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False); | |
9192 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
9193 prop_atom, XA_STRING, 8, PropModeReplace, | |
9194 XSTRING (value)->data, XSTRING (value)->size); | |
9195 | |
9196 /* Make sure the property is set when we return. */ | |
9197 XFlush (FRAME_X_DISPLAY (f)); | |
9198 UNBLOCK_INPUT; | |
9199 | |
9200 return value; | |
9201 } | |
9202 | |
9203 | |
9204 DEFUN ("x-delete-window-property", Fx_delete_window_property, | |
9205 Sx_delete_window_property, 1, 2, 0, | |
9206 "Remove window property PROP from X window of FRAME.\n\ | |
9207 FRAME nil or omitted means use the selected frame. Value is PROP.") | |
9208 (prop, frame) | |
9209 Lisp_Object prop, frame; | |
9210 { | |
9211 struct frame *f = check_x_frame (frame); | |
9212 Atom prop_atom; | |
9213 | |
9214 CHECK_STRING (prop, 1); | |
9215 BLOCK_INPUT; | |
9216 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False); | |
9217 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom); | |
9218 | |
9219 /* Make sure the property is removed when we return. */ | |
9220 XFlush (FRAME_X_DISPLAY (f)); | |
9221 UNBLOCK_INPUT; | |
9222 | |
9223 return prop; | |
9224 } | |
9225 | |
9226 | |
9227 DEFUN ("x-window-property", Fx_window_property, Sx_window_property, | |
9228 1, 2, 0, | |
9229 "Value is the value of window property PROP on FRAME.\n\ | |
9230 If FRAME is nil or omitted, use the selected frame. Value is nil\n\ | |
9231 if FRAME hasn't a property with name PROP or if PROP has no string\n\ | |
9232 value.") | |
9233 (prop, frame) | |
9234 Lisp_Object prop, frame; | |
9235 { | |
9236 struct frame *f = check_x_frame (frame); | |
9237 Atom prop_atom; | |
9238 int rc; | |
9239 Lisp_Object prop_value = Qnil; | |
9240 char *tmp_data = NULL; | |
9241 Atom actual_type; | |
9242 int actual_format; | |
9243 unsigned long actual_size, bytes_remaining; | |
9244 | |
9245 CHECK_STRING (prop, 1); | |
9246 BLOCK_INPUT; | |
9247 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False); | |
9248 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
9249 prop_atom, 0, 0, False, XA_STRING, | |
9250 &actual_type, &actual_format, &actual_size, | |
9251 &bytes_remaining, (unsigned char **) &tmp_data); | |
9252 if (rc == Success) | |
9253 { | |
9254 int size = bytes_remaining; | |
9255 | |
9256 XFree (tmp_data); | |
9257 tmp_data = NULL; | |
9258 | |
9259 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
9260 prop_atom, 0, bytes_remaining, | |
9261 False, XA_STRING, | |
9262 &actual_type, &actual_format, | |
9263 &actual_size, &bytes_remaining, | |
9264 (unsigned char **) &tmp_data); | |
9265 if (rc == Success) | |
9266 prop_value = make_string (tmp_data, size); | |
9267 | |
9268 XFree (tmp_data); | |
9269 } | |
9270 | |
9271 UNBLOCK_INPUT; | |
9272 return prop_value; | |
9273 } | |
9274 | |
9275 | |
9276 | |
9277 /*********************************************************************** | |
9278 Busy cursor | |
9279 ***********************************************************************/ | |
9280 | |
9281 /* The implementation partly follows a patch from | |
9282 F.Pierresteguy@frcl.bull.fr dated 1994. */ | |
9283 | |
9284 /* Setting inhibit_busy_cursor to 2 inhibits busy-cursor display until | |
9285 the next X event is read and we enter XTread_socket again. Setting | |
9286 it to 1 inhibits busy-cursor display for direct commands. */ | |
9287 | |
9288 int inhibit_busy_cursor; | |
9289 | |
9290 /* Incremented with each call to x-display-busy-cursor. | |
9291 Decremented in x-undisplay-busy-cursor. */ | |
9292 | |
9293 static int busy_count; | |
9294 | |
9295 | |
9296 DEFUN ("x-show-busy-cursor", Fx_show_busy_cursor, | |
9297 Sx_show_busy_cursor, 0, 0, 0, | |
9298 "Show a busy cursor, if not already shown.\n\ | |
9299 Each call to this function must be matched by a call to\n\ | |
9300 x-undisplay-busy-cursor to make the busy pointer disappear again.") | |
9301 () | |
9302 { | |
9303 ++busy_count; | |
9304 if (busy_count == 1) | |
9305 { | |
9306 Lisp_Object rest, frame; | |
9307 | |
9308 FOR_EACH_FRAME (rest, frame) | |
9309 if (FRAME_X_P (XFRAME (frame))) | |
9310 { | |
9311 struct frame *f = XFRAME (frame); | |
9312 | |
9313 BLOCK_INPUT; | |
9314 f->output_data.x->busy_p = 1; | |
9315 | |
9316 if (!f->output_data.x->busy_window) | |
9317 { | |
9318 unsigned long mask = CWCursor; | |
9319 XSetWindowAttributes attrs; | |
9320 | |
9321 attrs.cursor = f->output_data.x->busy_cursor; | |
9322 f->output_data.x->busy_window | |
9323 = XCreateWindow (FRAME_X_DISPLAY (f), | |
9324 FRAME_OUTER_WINDOW (f), | |
9325 0, 0, 32000, 32000, 0, 0, | |
9326 InputOnly, CopyFromParent, | |
9327 mask, &attrs); | |
9328 } | |
9329 | |
9330 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window); | |
9331 UNBLOCK_INPUT; | |
9332 } | |
9333 } | |
9334 | |
9335 return Qnil; | |
9336 } | |
9337 | |
9338 | |
9339 DEFUN ("x-hide-busy-cursor", Fx_hide_busy_cursor, | |
9340 Sx_hide_busy_cursor, 0, 1, 0, | |
9341 "Hide a busy-cursor.\n\ | |
9342 A busy-cursor will actually be undisplayed when a matching\n\ | |
9343 `x-undisplay-busy-cursor' is called for each `x-display-busy-cursor'\n\ | |
9344 issued. FORCE non-nil means undisplay the busy-cursor forcibly,\n\ | |
9345 not counting calls.") | |
9346 (force) | |
9347 Lisp_Object force; | |
9348 { | |
9349 Lisp_Object rest, frame; | |
9350 | |
9351 if (busy_count == 0) | |
9352 return Qnil; | |
9353 | |
9354 if (!NILP (force) && busy_count != 0) | |
9355 busy_count = 1; | |
9356 | |
9357 --busy_count; | |
9358 if (busy_count != 0) | |
9359 return Qnil; | |
9360 | |
9361 FOR_EACH_FRAME (rest, frame) | |
9362 { | |
9363 struct frame *f = XFRAME (frame); | |
9364 | |
9365 if (FRAME_X_P (f) | |
9366 /* Watch out for newly created frames. */ | |
9367 && f->output_data.x->busy_window) | |
9368 { | |
9369 | |
9370 BLOCK_INPUT; | |
9371 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window); | |
9372 /* Sync here because XTread_socket looks at the busy_p flag | |
9373 that is reset to zero below. */ | |
9374 XSync (FRAME_X_DISPLAY (f), False); | |
9375 UNBLOCK_INPUT; | |
9376 f->output_data.x->busy_p = 0; | |
9377 } | |
9378 } | |
9379 | |
9380 return Qnil; | |
9381 } | |
9382 | |
9383 | |
9384 | |
9385 /*********************************************************************** | |
9386 Tool tips | |
9387 ***********************************************************************/ | |
9388 | |
9389 static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *, | |
9390 Lisp_Object)); | |
9391 | |
9392 /* The frame of a currently visible tooltip, or null. */ | |
9393 | |
9394 struct frame *tip_frame; | |
9395 | |
9396 /* If non-nil, a timer started that hides the last tooltip when it | |
9397 fires. */ | |
9398 | |
9399 Lisp_Object tip_timer; | |
9400 Window tip_window; | |
9401 | |
9402 /* Create a frame for a tooltip on the display described by DPYINFO. | |
9403 PARMS is a list of frame parameters. Value is the frame. */ | |
9404 | |
9405 static Lisp_Object | |
9406 x_create_tip_frame (dpyinfo, parms) | |
9407 struct x_display_info *dpyinfo; | |
9408 Lisp_Object parms; | |
9409 { | |
9410 struct frame *f; | |
9411 Lisp_Object frame, tem; | |
9412 Lisp_Object name; | |
9413 int minibuffer_only = 0; | |
9414 long window_prompting = 0; | |
9415 int width, height; | |
9416 int count = specpdl_ptr - specpdl; | |
9417 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
9418 struct kboard *kb; | |
9419 | |
9420 check_x (); | |
9421 | |
9422 /* Use this general default value to start with until we know if | |
9423 this frame has a specified name. */ | |
9424 Vx_resource_name = Vinvocation_name; | |
9425 | |
9426 #ifdef MULTI_KBOARD | |
9427 kb = dpyinfo->kboard; | |
9428 #else | |
9429 kb = &the_only_kboard; | |
9430 #endif | |
9431 | |
9432 /* Get the name of the frame to use for resource lookup. */ | |
9433 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING); | |
9434 if (!STRINGP (name) | |
9435 && !EQ (name, Qunbound) | |
9436 && !NILP (name)) | |
9437 error ("Invalid frame name--not a string or nil"); | |
9438 Vx_resource_name = name; | |
9439 | |
9440 frame = Qnil; | |
9441 GCPRO3 (parms, name, frame); | |
9442 tip_frame = f = make_frame (1); | |
9443 XSETFRAME (frame, f); | |
9444 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0; | |
9445 | |
9446 f->output_method = output_x_window; | |
9447 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output)); | |
9448 bzero (f->output_data.x, sizeof (struct x_output)); | |
9449 f->output_data.x->icon_bitmap = -1; | |
9450 f->output_data.x->fontset = -1; | |
9451 f->icon_name = Qnil; | |
9452 FRAME_X_DISPLAY_INFO (f) = dpyinfo; | |
9453 #ifdef MULTI_KBOARD | |
9454 FRAME_KBOARD (f) = kb; | |
9455 #endif | |
9456 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; | |
9457 f->output_data.x->explicit_parent = 0; | |
9458 | |
9459 /* Set the name; the functions to which we pass f expect the name to | |
9460 be set. */ | |
9461 if (EQ (name, Qunbound) || NILP (name)) | |
9462 { | |
9463 f->name = build_string (dpyinfo->x_id_name); | |
9464 f->explicit_name = 0; | |
9465 } | |
9466 else | |
9467 { | |
9468 f->name = name; | |
9469 f->explicit_name = 1; | |
9470 /* use the frame's title when getting resources for this frame. */ | |
9471 specbind (Qx_resource_name, name); | |
9472 } | |
9473 | |
9474 /* Create fontsets from `global_fontset_alist' before handling fonts. */ | |
9475 for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCONS (tem)->cdr) | |
9476 fs_register_fontset (f, XCONS (tem)->car); | |
9477 | |
9478 /* Extract the window parameters from the supplied values | |
9479 that are needed to determine window geometry. */ | |
9480 { | |
9481 Lisp_Object font; | |
9482 | |
9483 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING); | |
9484 | |
9485 BLOCK_INPUT; | |
9486 /* First, try whatever font the caller has specified. */ | |
9487 if (STRINGP (font)) | |
9488 { | |
9489 tem = Fquery_fontset (font, Qnil); | |
9490 if (STRINGP (tem)) | |
9491 font = x_new_fontset (f, XSTRING (tem)->data); | |
9492 else | |
9493 font = x_new_font (f, XSTRING (font)->data); | |
9494 } | |
9495 | |
9496 /* Try out a font which we hope has bold and italic variations. */ | |
9497 if (!STRINGP (font)) | |
9498 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1"); | |
9499 if (!STRINGP (font)) | |
9500 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); | |
9501 if (! STRINGP (font)) | |
9502 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); | |
9503 if (! STRINGP (font)) | |
9504 /* This was formerly the first thing tried, but it finds too many fonts | |
9505 and takes too long. */ | |
9506 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1"); | |
9507 /* If those didn't work, look for something which will at least work. */ | |
9508 if (! STRINGP (font)) | |
9509 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1"); | |
9510 UNBLOCK_INPUT; | |
9511 if (! STRINGP (font)) | |
9512 font = build_string ("fixed"); | |
9513 | |
9514 x_default_parameter (f, parms, Qfont, font, | |
9515 "font", "Font", RES_TYPE_STRING); | |
9516 } | |
9517 | |
9518 x_default_parameter (f, parms, Qborder_width, make_number (2), | |
9519 "borderWidth", "BorderWidth", RES_TYPE_NUMBER); | |
9520 | |
9521 /* This defaults to 2 in order to match xterm. We recognize either | |
9522 internalBorderWidth or internalBorder (which is what xterm calls | |
9523 it). */ | |
9524 if (NILP (Fassq (Qinternal_border_width, parms))) | |
9525 { | |
9526 Lisp_Object value; | |
9527 | |
9528 value = x_get_arg (dpyinfo, parms, Qinternal_border_width, | |
9529 "internalBorder", "internalBorder", RES_TYPE_NUMBER); | |
9530 if (! EQ (value, Qunbound)) | |
9531 parms = Fcons (Fcons (Qinternal_border_width, value), | |
9532 parms); | |
9533 } | |
9534 | |
9535 x_default_parameter (f, parms, Qinternal_border_width, make_number (1), | |
9536 "internalBorderWidth", "internalBorderWidth", | |
9537 RES_TYPE_NUMBER); | |
9538 | |
9539 /* Also do the stuff which must be set before the window exists. */ | |
9540 x_default_parameter (f, parms, Qforeground_color, build_string ("black"), | |
9541 "foreground", "Foreground", RES_TYPE_STRING); | |
9542 x_default_parameter (f, parms, Qbackground_color, build_string ("white"), | |
9543 "background", "Background", RES_TYPE_STRING); | |
9544 x_default_parameter (f, parms, Qmouse_color, build_string ("black"), | |
9545 "pointerColor", "Foreground", RES_TYPE_STRING); | |
9546 x_default_parameter (f, parms, Qcursor_color, build_string ("black"), | |
9547 "cursorColor", "Foreground", RES_TYPE_STRING); | |
9548 x_default_parameter (f, parms, Qborder_color, build_string ("black"), | |
9549 "borderColor", "BorderColor", RES_TYPE_STRING); | |
9550 | |
9551 /* Init faces before x_default_parameter is called for scroll-bar | |
9552 parameters because that function calls x_set_scroll_bar_width, | |
9553 which calls change_frame_size, which calls Fset_window_buffer, | |
9554 which runs hooks, which call Fvertical_motion. At the end, we | |
9555 end up in init_iterator with a null face cache, which should not | |
9556 happen. */ | |
9557 init_frame_faces (f); | |
9558 | |
9559 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; | |
9560 window_prompting = x_figure_window_size (f, parms); | |
9561 | |
9562 if (window_prompting & XNegative) | |
9563 { | |
9564 if (window_prompting & YNegative) | |
9565 f->output_data.x->win_gravity = SouthEastGravity; | |
9566 else | |
9567 f->output_data.x->win_gravity = NorthEastGravity; | |
9568 } | |
9569 else | |
9570 { | |
9571 if (window_prompting & YNegative) | |
9572 f->output_data.x->win_gravity = SouthWestGravity; | |
9573 else | |
9574 f->output_data.x->win_gravity = NorthWestGravity; | |
9575 } | |
9576 | |
9577 f->output_data.x->size_hint_flags = window_prompting; | |
9578 { | |
9579 XSetWindowAttributes attrs; | |
9580 unsigned long mask; | |
9581 | |
9582 BLOCK_INPUT; | |
9583 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask; | |
9584 /* Window managers looks at the override-redirect flag to | |
9585 determine whether or net to give windows a decoration (Xlib | |
9586 3.2.8). */ | |
9587 attrs.override_redirect = True; | |
9588 attrs.save_under = True; | |
9589 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f); | |
9590 /* Arrange for getting MapNotify and UnmapNotify events. */ | |
9591 attrs.event_mask = StructureNotifyMask; | |
9592 tip_window | |
9593 = FRAME_X_WINDOW (f) | |
9594 = XCreateWindow (FRAME_X_DISPLAY (f), | |
9595 FRAME_X_DISPLAY_INFO (f)->root_window, | |
9596 /* x, y, width, height */ | |
9597 0, 0, 1, 1, | |
9598 /* Border. */ | |
9599 1, | |
9600 CopyFromParent, InputOutput, CopyFromParent, | |
9601 mask, &attrs); | |
9602 UNBLOCK_INPUT; | |
9603 } | |
9604 | |
9605 x_make_gc (f); | |
9606 | |
9607 /* We need to do this after creating the X window, so that the | |
9608 icon-creation functions can say whose icon they're describing. */ | |
9609 x_default_parameter (f, parms, Qicon_type, Qnil, | |
9610 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL); | |
9611 | |
9612 x_default_parameter (f, parms, Qauto_raise, Qnil, | |
9613 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); | |
9614 x_default_parameter (f, parms, Qauto_lower, Qnil, | |
9615 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); | |
9616 x_default_parameter (f, parms, Qcursor_type, Qbox, | |
9617 "cursorType", "CursorType", RES_TYPE_SYMBOL); | |
9618 | |
9619 /* Dimensions, especially f->height, must be done via change_frame_size. | |
9620 Change will not be effected unless different from the current | |
9621 f->height. */ | |
9622 width = f->width; | |
9623 height = f->height; | |
9624 f->height = 0; | |
9625 SET_FRAME_WIDTH (f, 0); | |
9626 change_frame_size (f, height, width, 1, 0); | |
9627 | |
9628 f->no_split = 1; | |
9629 | |
9630 UNGCPRO; | |
9631 | |
9632 /* It is now ok to make the frame official even if we get an error | |
9633 below. And the frame needs to be on Vframe_list or making it | |
9634 visible won't work. */ | |
9635 Vframe_list = Fcons (frame, Vframe_list); | |
9636 | |
9637 /* Now that the frame is official, it counts as a reference to | |
9638 its display. */ | |
9639 FRAME_X_DISPLAY_INFO (f)->reference_count++; | |
9640 | |
9641 return unbind_to (count, frame); | |
9642 } | |
9643 | |
9644 | |
9645 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0, | |
9646 "Show tooltip STRING on frame FRAME.\n\ | |
9647 FRAME nil or omitted means use the selected frame.\n\ | |
9648 PARMS is an optional list of frame parameters which can be\n\ | |
9649 used to change the tooltip's appearance.\n\ | |
9650 Automatically hide the tooltip after TIMEOUT seconds.\n\ | |
9651 TIMEOUT nil means use the default timeout of 5 seconds.") | |
9652 (string, frame, parms, timeout) | |
9653 Lisp_Object string, frame, parms; | |
9654 { | |
9655 struct frame *f; | |
9656 struct window *w; | |
9657 Window root, child; | |
9658 struct it it; | |
9659 Lisp_Object buffer; | |
9660 struct buffer *old_buffer; | |
9661 struct text_pos pos; | |
9662 int i, width, height; | |
9663 int root_x, root_y, win_x, win_y; | |
9664 unsigned pmask; | |
9665 struct gcpro gcpro1, gcpro2, gcpro3; | |
9666 int old_windows_or_buffers_changed = windows_or_buffers_changed; | |
9667 int count = specpdl_ptr - specpdl; | |
9668 | |
9669 specbind (Qinhibit_redisplay, Qt); | |
9670 | |
9671 GCPRO3 (string, parms, frame); | |
9672 | |
9673 CHECK_STRING (string, 0); | |
9674 f = check_x_frame (frame); | |
9675 if (NILP (timeout)) | |
9676 timeout = make_number (5); | |
9677 else | |
9678 CHECK_NATNUM (timeout, 2); | |
9679 | |
9680 /* Hide a previous tip, if any. */ | |
9681 Fx_hide_tip (); | |
9682 | |
9683 /* Add default values to frame parameters. */ | |
9684 if (NILP (Fassq (Qname, parms))) | |
9685 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); | |
9686 if (NILP (Fassq (Qinternal_border_width, parms))) | |
9687 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); | |
9688 if (NILP (Fassq (Qborder_width, parms))) | |
9689 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); | |
9690 if (NILP (Fassq (Qborder_color, parms))) | |
9691 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); | |
9692 if (NILP (Fassq (Qbackground_color, parms))) | |
9693 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), | |
9694 parms); | |
9695 | |
9696 /* Create a frame for the tooltip, and record it in the global | |
9697 variable tip_frame. */ | |
9698 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms); | |
9699 tip_frame = f = XFRAME (frame); | |
9700 | |
9701 /* Set up the frame's root window. Currently we use a size of 80 | |
9702 columns x 40 lines. If someone wants to show a larger tip, he | |
9703 will loose. I don't think this is a realistic case. */ | |
9704 w = XWINDOW (FRAME_ROOT_WINDOW (f)); | |
9705 w->left = w->top = make_number (0); | |
9706 w->width = 80; | |
9707 w->height = 40; | |
9708 adjust_glyphs (f); | |
9709 w->pseudo_window_p = 1; | |
9710 | |
9711 /* Display the tooltip text in a temporary buffer. */ | |
9712 buffer = Fget_buffer_create (build_string (" *tip*")); | |
9713 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer); | |
9714 old_buffer = current_buffer; | |
9715 set_buffer_internal_1 (XBUFFER (buffer)); | |
9716 Ferase_buffer (); | |
9717 Finsert (make_number (1), &string); | |
9718 clear_glyph_matrix (w->desired_matrix); | |
9719 clear_glyph_matrix (w->current_matrix); | |
9720 SET_TEXT_POS (pos, BEGV, BEGV_BYTE); | |
9721 try_window (FRAME_ROOT_WINDOW (f), pos); | |
9722 | |
9723 /* Compute width and height of the tooltip. */ | |
9724 width = height = 0; | |
9725 for (i = 0; i < w->desired_matrix->nrows; ++i) | |
9726 { | |
9727 struct glyph_row *row = &w->desired_matrix->rows[i]; | |
9728 struct glyph *last; | |
9729 int row_width; | |
9730 | |
9731 /* Stop at the first empty row at the end. */ | |
9732 if (!row->enabled_p || !row->displays_text_p) | |
9733 break; | |
9734 | |
9735 /* Let the row go over the full width of the frame, not | |
9736 including internal borders. */ | |
9737 row->full_width_p = row->internal_border_p = 1; | |
9738 | |
9739 /* There's a glyph at the end of rows that is use to place | |
9740 the cursor there. Don't include the width of this glyph. */ | |
9741 if (row->used[TEXT_AREA]) | |
9742 { | |
9743 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; | |
9744 row_width = row->pixel_width - last->pixel_width; | |
9745 } | |
9746 else | |
9747 row_width = row->pixel_width; | |
9748 | |
9749 height += row->height; | |
9750 width = max (width, row_width); | |
9751 } | |
9752 | |
9753 /* Add the frame's internal border to the width and height the X | |
9754 window should have. */ | |
9755 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); | |
9756 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); | |
9757 | |
9758 /* Move the tooltip window where the mouse pointer is. Resize and | |
9759 show it. */ | |
9760 BLOCK_INPUT; | |
9761 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window, | |
9762 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask); | |
9763 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
9764 root_x + 5, root_y - height - 5, width, height); | |
9765 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); | |
9766 UNBLOCK_INPUT; | |
9767 | |
9768 /* Draw into the window. */ | |
9769 w->must_be_updated_p = 1; | |
9770 update_single_window (w, 1); | |
9771 | |
9772 /* Restore original current buffer. */ | |
9773 set_buffer_internal_1 (old_buffer); | |
9774 windows_or_buffers_changed = old_windows_or_buffers_changed; | |
9775 | |
9776 /* Let the tip disappear after timeout seconds. */ | |
9777 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, | |
9778 intern ("x-hide-tip")); | |
9779 | |
9780 return unbind_to (count, Qnil); | |
9781 } | |
9782 | |
9783 | |
9784 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, | |
9785 "Hide the current tooltip, if there is any.\n\ | |
9786 Value is t is tooltip was open, nil otherwise.") | |
9787 () | |
9788 { | |
9789 int count = specpdl_ptr - specpdl; | |
9790 int deleted_p = 0; | |
9791 | |
9792 specbind (Qinhibit_redisplay, Qt); | |
9793 | |
9794 if (!NILP (tip_timer)) | |
9795 { | |
9796 call1 (intern ("cancel-timer"), tip_timer); | |
9797 tip_timer = Qnil; | |
9798 } | |
9799 | |
9800 if (tip_frame) | |
9801 { | |
9802 Lisp_Object frame; | |
9803 | |
9804 XSETFRAME (frame, tip_frame); | |
9805 Fdelete_frame (frame, Qt); | |
9806 tip_frame = NULL; | |
9807 deleted_p = 1; | |
9808 } | |
9809 | |
9810 return unbind_to (count, deleted_p ? Qt : Qnil); | |
9811 } | |
9812 | |
9813 | |
9814 | |
9815 /*********************************************************************** | |
9816 File selection dialog | |
9817 ***********************************************************************/ | |
9818 | |
9819 #ifdef USE_MOTIF | |
9820 | |
9821 /* Callback for "OK" and "Cancel" on file selection dialog. */ | |
9822 | |
9823 static void | |
9824 file_dialog_cb (widget, client_data, call_data) | |
9825 Widget widget; | |
9826 XtPointer call_data, client_data; | |
9827 { | |
9828 int *result = (int *) client_data; | |
9829 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data; | |
9830 *result = cb->reason; | |
9831 } | |
9832 | |
9833 | |
9834 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0, | |
9835 "Read file name, prompting with PROMPT in directory DIR.\n\ | |
9836 Use a file selection dialog.\n\ | |
9837 Select DEFAULT-FILENAME in the dialog's file selection box, if\n\ | |
9838 specified. Don't let the user enter a file name in the file\n\ | |
9839 selection dialog's entry field, if MUSTMATCH is non-nil.") | |
9840 (prompt, dir, default_filename, mustmatch) | |
9841 Lisp_Object prompt, dir, default_filename, mustmatch; | |
9842 { | |
9843 int result; | |
9844 struct frame *f = selected_frame; | |
9845 Lisp_Object file = Qnil; | |
9846 Widget dialog, text, list, help; | |
9847 Arg al[10]; | |
9848 int ac = 0; | |
9849 extern XtAppContext Xt_app_con; | |
9850 char *title; | |
9851 XmString dir_xmstring, pattern_xmstring; | |
9852 int popup_activated_flag; | |
9853 int count = specpdl_ptr - specpdl; | |
9854 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | |
9855 | |
9856 GCPRO5 (prompt, dir, default_filename, mustmatch, file); | |
9857 CHECK_STRING (prompt, 0); | |
9858 CHECK_STRING (dir, 1); | |
9859 | |
9860 /* Prevent redisplay. */ | |
9861 specbind (Qinhibit_redisplay, Qt); | |
9862 | |
9863 BLOCK_INPUT; | |
9864 | |
9865 /* Create the dialog with PROMPT as title, using DIR as initial | |
9866 directory and using "*" as pattern. */ | |
9867 dir = Fexpand_file_name (dir, Qnil); | |
9868 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data); | |
9869 pattern_xmstring = XmStringCreateLocalized ("*"); | |
9870 | |
9871 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac; | |
9872 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac; | |
9873 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac; | |
9874 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac; | |
9875 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac; | |
9876 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget, | |
9877 "fsb", al, ac); | |
9878 XmStringFree (dir_xmstring); | |
9879 XmStringFree (pattern_xmstring); | |
9880 | |
9881 /* Add callbacks for OK and Cancel. */ | |
9882 XtAddCallback (dialog, XmNokCallback, file_dialog_cb, | |
9883 (XtPointer) &result); | |
9884 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb, | |
9885 (XtPointer) &result); | |
9886 | |
9887 /* Disable the help button since we can't display help. */ | |
9888 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON); | |
9889 XtSetSensitive (help, False); | |
9890 | |
9891 /* Mark OK button as default. */ | |
9892 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON), | |
9893 XmNshowAsDefault, True, NULL); | |
9894 | |
9895 /* If MUSTMATCH is non-nil, disable the file entry field of the | |
9896 dialog, so that the user must select a file from the files list | |
9897 box. We can't remove it because we wouldn't have a way to get at | |
9898 the result file name, then. */ | |
9899 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT); | |
9900 if (!NILP (mustmatch)) | |
9901 { | |
9902 Widget label; | |
9903 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL); | |
9904 XtSetSensitive (text, False); | |
9905 XtSetSensitive (label, False); | |
9906 } | |
9907 | |
9908 /* Manage the dialog, so that list boxes get filled. */ | |
9909 XtManageChild (dialog); | |
9910 | |
9911 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME | |
9912 must include the path for this to work. */ | |
9913 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST); | |
9914 if (STRINGP (default_filename)) | |
9915 { | |
9916 XmString default_xmstring; | |
9917 int item_pos; | |
9918 | |
9919 default_xmstring | |
9920 = XmStringCreateLocalized (XSTRING (default_filename)->data); | |
9921 | |
9922 if (!XmListItemExists (list, default_xmstring)) | |
9923 { | |
9924 /* Add a new item if DEFAULT_FILENAME is not in the list. */ | |
9925 XmListAddItem (list, default_xmstring, 0); | |
9926 item_pos = 0; | |
9927 } | |
9928 else | |
9929 item_pos = XmListItemPos (list, default_xmstring); | |
9930 XmStringFree (default_xmstring); | |
9931 | |
9932 /* Select the item and scroll it into view. */ | |
9933 XmListSelectPos (list, item_pos, True); | |
9934 XmListSetPos (list, item_pos); | |
9935 } | |
9936 | |
9937 /* Process all events until the user presses Cancel or OK. */ | |
9938 for (result = 0; result == 0;) | |
9939 { | |
9940 XEvent event; | |
9941 Widget widget, parent; | |
9942 | |
9943 XtAppNextEvent (Xt_app_con, &event); | |
9944 | |
9945 /* See if the receiver of the event is one of the widgets of | |
9946 the file selection dialog. If so, dispatch it. If not, | |
9947 discard it. */ | |
9948 widget = XtWindowToWidget (event.xany.display, event.xany.window); | |
9949 parent = widget; | |
9950 while (parent && parent != dialog) | |
9951 parent = XtParent (parent); | |
9952 | |
9953 if (parent == dialog | |
9954 || (event.type == Expose | |
9955 && !process_expose_from_menu (event))) | |
9956 XtDispatchEvent (&event); | |
9957 } | |
9958 | |
9959 /* Get the result. */ | |
9960 if (result == XmCR_OK) | |
9961 { | |
9962 XmString text; | |
9963 String data; | |
9964 | |
9965 XtVaGetValues (dialog, XmNtextString, &text, 0); | |
9966 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data); | |
9967 XmStringFree (text); | |
9968 file = build_string (data); | |
9969 XtFree (data); | |
9970 } | |
9971 else | |
9972 file = Qnil; | |
9973 | |
9974 /* Clean up. */ | |
9975 XtUnmanageChild (dialog); | |
9976 XtDestroyWidget (dialog); | |
9977 UNBLOCK_INPUT; | |
9978 UNGCPRO; | |
9979 | |
9980 /* Make "Cancel" equivalent to C-g. */ | |
9981 if (NILP (file)) | |
9982 Fsignal (Qquit, Qnil); | |
9983 | |
9984 return unbind_to (count, file); | |
9985 } | |
9986 | |
9987 #endif /* USE_MOTIF */ | |
9988 | |
9989 | |
9990 /*********************************************************************** | |
9991 Tests | |
9992 ***********************************************************************/ | |
9993 | |
9994 #if GLYPH_DEBUG | |
9995 | |
9996 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0, | |
9997 "Value is non-nil if SPEC is a valid image specification.") | |
9998 (spec) | |
9999 Lisp_Object spec; | |
10000 { | |
10001 return valid_image_p (spec) ? Qt : Qnil; | |
10002 } | |
10003 | |
10004 | |
10005 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "") | |
10006 (spec) | |
10007 Lisp_Object spec; | |
10008 { | |
10009 int id = -1; | |
10010 | |
10011 if (valid_image_p (spec)) | |
10012 id = lookup_image (selected_frame, spec); | |
10013 | |
10014 debug_print (spec); | |
10015 return make_number (id); | |
10016 } | |
10017 | |
10018 #endif /* GLYPH_DEBUG != 0 */ | |
10019 | |
10020 | |
10021 | |
10022 /*********************************************************************** | |
10023 Initialization | |
10024 ***********************************************************************/ | |
10025 | |
5241 void | 10026 void |
5242 syms_of_xfns () | 10027 syms_of_xfns () |
5243 { | 10028 { |
5244 /* This is zero if not using X windows. */ | 10029 /* This is zero if not using X windows. */ |
5245 x_in_use = 0; | 10030 x_in_use = 0; |
5249 /*&&& init symbols here &&&*/ | 10034 /*&&& init symbols here &&&*/ |
5250 Qauto_raise = intern ("auto-raise"); | 10035 Qauto_raise = intern ("auto-raise"); |
5251 staticpro (&Qauto_raise); | 10036 staticpro (&Qauto_raise); |
5252 Qauto_lower = intern ("auto-lower"); | 10037 Qauto_lower = intern ("auto-lower"); |
5253 staticpro (&Qauto_lower); | 10038 staticpro (&Qauto_lower); |
5254 Qbackground_color = intern ("background-color"); | |
5255 staticpro (&Qbackground_color); | |
5256 Qbar = intern ("bar"); | 10039 Qbar = intern ("bar"); |
5257 staticpro (&Qbar); | 10040 staticpro (&Qbar); |
5258 Qborder_color = intern ("border-color"); | 10041 Qborder_color = intern ("border-color"); |
5259 staticpro (&Qborder_color); | 10042 staticpro (&Qborder_color); |
5260 Qborder_width = intern ("border-width"); | 10043 Qborder_width = intern ("border-width"); |
5263 staticpro (&Qbox); | 10046 staticpro (&Qbox); |
5264 Qcursor_color = intern ("cursor-color"); | 10047 Qcursor_color = intern ("cursor-color"); |
5265 staticpro (&Qcursor_color); | 10048 staticpro (&Qcursor_color); |
5266 Qcursor_type = intern ("cursor-type"); | 10049 Qcursor_type = intern ("cursor-type"); |
5267 staticpro (&Qcursor_type); | 10050 staticpro (&Qcursor_type); |
5268 Qforeground_color = intern ("foreground-color"); | |
5269 staticpro (&Qforeground_color); | |
5270 Qgeometry = intern ("geometry"); | 10051 Qgeometry = intern ("geometry"); |
5271 staticpro (&Qgeometry); | 10052 staticpro (&Qgeometry); |
5272 Qicon_left = intern ("icon-left"); | 10053 Qicon_left = intern ("icon-left"); |
5273 staticpro (&Qicon_left); | 10054 staticpro (&Qicon_left); |
5274 Qicon_top = intern ("icon-top"); | 10055 Qicon_top = intern ("icon-top"); |
5291 staticpro (&Qparent_id); | 10072 staticpro (&Qparent_id); |
5292 Qscroll_bar_width = intern ("scroll-bar-width"); | 10073 Qscroll_bar_width = intern ("scroll-bar-width"); |
5293 staticpro (&Qscroll_bar_width); | 10074 staticpro (&Qscroll_bar_width); |
5294 Qsuppress_icon = intern ("suppress-icon"); | 10075 Qsuppress_icon = intern ("suppress-icon"); |
5295 staticpro (&Qsuppress_icon); | 10076 staticpro (&Qsuppress_icon); |
5296 Qtop = intern ("top"); | |
5297 staticpro (&Qtop); | |
5298 Qundefined_color = intern ("undefined-color"); | 10077 Qundefined_color = intern ("undefined-color"); |
5299 staticpro (&Qundefined_color); | 10078 staticpro (&Qundefined_color); |
5300 Qvertical_scroll_bars = intern ("vertical-scroll-bars"); | 10079 Qvertical_scroll_bars = intern ("vertical-scroll-bars"); |
5301 staticpro (&Qvertical_scroll_bars); | 10080 staticpro (&Qvertical_scroll_bars); |
5302 Qvisibility = intern ("visibility"); | 10081 Qvisibility = intern ("visibility"); |
5313 staticpro (&Quser_position); | 10092 staticpro (&Quser_position); |
5314 Quser_size = intern ("user-size"); | 10093 Quser_size = intern ("user-size"); |
5315 staticpro (&Quser_size); | 10094 staticpro (&Quser_size); |
5316 Qdisplay = intern ("display"); | 10095 Qdisplay = intern ("display"); |
5317 staticpro (&Qdisplay); | 10096 staticpro (&Qdisplay); |
10097 Qscroll_bar_foreground = intern ("scroll-bar-foreground"); | |
10098 staticpro (&Qscroll_bar_foreground); | |
10099 Qscroll_bar_background = intern ("scroll-bar-background"); | |
10100 staticpro (&Qscroll_bar_background); | |
5318 /* This is the end of symbol initialization. */ | 10101 /* This is the end of symbol initialization. */ |
5319 | 10102 |
10103 Qlaplace = intern ("laplace"); | |
10104 staticpro (&Qlaplace); | |
10105 | |
5320 Qface_set_after_frame_default = intern ("face-set-after-frame-default"); | 10106 Qface_set_after_frame_default = intern ("face-set-after-frame-default"); |
5321 staticpro (&Qface_set_after_frame_default); | 10107 staticpro (&Qface_set_after_frame_default); |
5322 | 10108 |
5323 Fput (Qundefined_color, Qerror_conditions, | 10109 Fput (Qundefined_color, Qerror_conditions, |
5324 Fcons (Qundefined_color, Fcons (Qerror, Qnil))); | 10110 Fcons (Qundefined_color, Fcons (Qerror, Qnil))); |
5355 when requesting resource values.\n\ | 10141 when requesting resource values.\n\ |
5356 Emacs initially sets `x-resource-class' to \"Emacs\".\n\ | 10142 Emacs initially sets `x-resource-class' to \"Emacs\".\n\ |
5357 \n\ | 10143 \n\ |
5358 Setting this variable permanently is not a reasonable thing to do,\n\ | 10144 Setting this variable permanently is not a reasonable thing to do,\n\ |
5359 but binding this variable locally around a call to `x-get-resource'\n\ | 10145 but binding this variable locally around a call to `x-get-resource'\n\ |
5360 is a reasonabvle practice. See also the variable `x-resource-name'."); | 10146 is a reasonable practice. See also the variable `x-resource-name'."); |
5361 Vx_resource_class = build_string (EMACS_CLASS); | 10147 Vx_resource_class = build_string (EMACS_CLASS); |
5362 | 10148 |
5363 #if 0 /* This doesn't really do anything. */ | 10149 #if 0 /* This doesn't really do anything. */ |
5364 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape, | 10150 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape, |
5365 "The shape of the pointer when not over text.\n\ | 10151 "The shape of the pointer when not over text.\n\ |
5366 This variable takes effect when you create a new frame\n\ | 10152 This variable takes effect when you create a new frame\n\ |
5367 or when you set the mouse color."); | 10153 or when you set the mouse color."); |
5368 #endif | 10154 #endif |
5369 Vx_nontext_pointer_shape = Qnil; | 10155 Vx_nontext_pointer_shape = Qnil; |
5370 | 10156 |
10157 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape, | |
10158 "The shape of the pointer when Emacs is busy.\n\ | |
10159 This variable takes effect when you create a new frame\n\ | |
10160 or when you set the mouse color."); | |
10161 Vx_busy_pointer_shape = Qnil; | |
10162 | |
10163 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p, | |
10164 "Non-zero means Emacs displays a busy cursor on window systems."); | |
10165 display_busy_cursor_p = 1; | |
10166 | |
5371 #if 0 /* This doesn't really do anything. */ | 10167 #if 0 /* This doesn't really do anything. */ |
5372 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape, | 10168 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape, |
5373 "The shape of the pointer when over the mode line.\n\ | 10169 "The shape of the pointer when over the mode line.\n\ |
5374 This variable takes effect when you create a new frame\n\ | 10170 This variable takes effect when you create a new frame\n\ |
5375 or when you set the mouse color."); | 10171 or when you set the mouse color."); |
5403 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\ | 10199 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\ |
5404 such a font. This is especially effective for such large fonts as\n\ | 10200 such a font. This is especially effective for such large fonts as\n\ |
5405 Chinese, Japanese, and Korean."); | 10201 Chinese, Japanese, and Korean."); |
5406 Vx_pixel_size_width_font_regexp = Qnil; | 10202 Vx_pixel_size_width_font_regexp = Qnil; |
5407 | 10203 |
10204 DEFVAR_LISP ("image-eviction-seconds", &Vimage_eviction_seconds, | |
10205 "Time after which cached images are removed from the cache.\n\ | |
10206 When an image has not been displayed this many seconds, remove it\n\ | |
10207 from the image cache. Value must be an integer or nil with nil\n\ | |
10208 meaning don't clear the cache."); | |
10209 Vimage_eviction_seconds = make_number (30 * 60); | |
10210 | |
10211 DEFVAR_LISP ("image-types", &Vimage_types, | |
10212 "List of supported image types.\n\ | |
10213 Each element of the list is a symbol for a supported image type."); | |
10214 Vimage_types = Qnil; | |
10215 | |
5408 #ifdef USE_X_TOOLKIT | 10216 #ifdef USE_X_TOOLKIT |
5409 Fprovide (intern ("x-toolkit")); | 10217 Fprovide (intern ("x-toolkit")); |
5410 #endif | 10218 #endif |
5411 #ifdef USE_MOTIF | 10219 #ifdef USE_MOTIF |
5412 Fprovide (intern ("motif")); | 10220 Fprovide (intern ("motif")); |
5413 #endif | 10221 #endif |
5414 | 10222 |
5415 defsubr (&Sx_get_resource); | 10223 defsubr (&Sx_get_resource); |
10224 | |
10225 /* X window properties. */ | |
10226 defsubr (&Sx_change_window_property); | |
10227 defsubr (&Sx_delete_window_property); | |
10228 defsubr (&Sx_window_property); | |
10229 | |
5416 #if 0 | 10230 #if 0 |
5417 defsubr (&Sx_draw_rectangle); | 10231 defsubr (&Sx_draw_rectangle); |
5418 defsubr (&Sx_erase_rectangle); | 10232 defsubr (&Sx_erase_rectangle); |
5419 defsubr (&Sx_contour_region); | 10233 defsubr (&Sx_contour_region); |
5420 defsubr (&Sx_uncontour_region); | 10234 defsubr (&Sx_uncontour_region); |
5421 #endif | 10235 #endif |
5422 defsubr (&Sx_list_fonts); | |
5423 defsubr (&Sx_display_color_p); | 10236 defsubr (&Sx_display_color_p); |
5424 defsubr (&Sx_display_grayscale_p); | 10237 defsubr (&Sx_display_grayscale_p); |
5425 defsubr (&Sx_color_defined_p); | 10238 defsubr (&Sx_color_defined_p); |
5426 defsubr (&Sx_color_values); | 10239 defsubr (&Sx_color_values); |
5427 defsubr (&Sx_server_max_request_size); | 10240 defsubr (&Sx_server_max_request_size); |
5454 defsubr (&Sx_display_list); | 10267 defsubr (&Sx_display_list); |
5455 defsubr (&Sx_synchronize); | 10268 defsubr (&Sx_synchronize); |
5456 | 10269 |
5457 /* Setting callback functions for fontset handler. */ | 10270 /* Setting callback functions for fontset handler. */ |
5458 get_font_info_func = x_get_font_info; | 10271 get_font_info_func = x_get_font_info; |
10272 | |
10273 #if 0 /* This function pointer doesn't seem to be used anywhere. | |
10274 And the pointer assigned has the wrong type, anyway. */ | |
5459 list_fonts_func = x_list_fonts; | 10275 list_fonts_func = x_list_fonts; |
10276 #endif | |
10277 | |
5460 load_font_func = x_load_font; | 10278 load_font_func = x_load_font; |
5461 find_ccl_program_func = x_find_ccl_program; | 10279 find_ccl_program_func = x_find_ccl_program; |
5462 query_font_func = x_query_font; | 10280 query_font_func = x_query_font; |
5463 set_frame_fontset_func = x_set_font; | 10281 set_frame_fontset_func = x_set_font; |
5464 check_window_system_func = check_x; | 10282 check_window_system_func = check_x; |
10283 | |
10284 /* Images. */ | |
10285 Qxbm = intern ("xbm"); | |
10286 staticpro (&Qxbm); | |
10287 QCtype = intern (":type"); | |
10288 staticpro (&QCtype); | |
10289 QCfile = intern (":file"); | |
10290 staticpro (&QCfile); | |
10291 QCalgorithm = intern (":algorithm"); | |
10292 staticpro (&QCalgorithm); | |
10293 QCheuristic_mask = intern (":heuristic-mask"); | |
10294 staticpro (&QCheuristic_mask); | |
10295 QCcolor_symbols = intern (":color-symbols"); | |
10296 staticpro (&QCcolor_symbols); | |
10297 QCdata = intern (":data"); | |
10298 staticpro (&QCdata); | |
10299 QCascent = intern (":ascent"); | |
10300 staticpro (&QCascent); | |
10301 QCmargin = intern (":margin"); | |
10302 staticpro (&QCmargin); | |
10303 QCrelief = intern (":relief"); | |
10304 staticpro (&QCrelief); | |
10305 Qghostscript = intern ("ghostscript"); | |
10306 staticpro (&Qghostscript); | |
10307 QCloader = intern (":loader"); | |
10308 staticpro (&QCloader); | |
10309 QCbounding_box = intern (":bounding-box"); | |
10310 staticpro (&QCbounding_box); | |
10311 QCpt_width = intern (":pt-width"); | |
10312 staticpro (&QCpt_width); | |
10313 QCpt_height = intern (":pt-height"); | |
10314 staticpro (&QCpt_height); | |
10315 Qpbm = intern ("pbm"); | |
10316 staticpro (&Qpbm); | |
10317 | |
10318 #if HAVE_XPM | |
10319 Qxpm = intern ("xpm"); | |
10320 staticpro (&Qxpm); | |
10321 #endif | |
10322 | |
10323 #if HAVE_JPEG | |
10324 Qjpeg = intern ("jpeg"); | |
10325 staticpro (&Qjpeg); | |
10326 #endif | |
10327 | |
10328 #if HAVE_TIFF | |
10329 Qtiff = intern ("tiff"); | |
10330 staticpro (&Qtiff); | |
10331 #endif | |
10332 | |
10333 #if HAVE_GIF | |
10334 Qgif = intern ("gif"); | |
10335 staticpro (&Qgif); | |
10336 #endif | |
10337 | |
10338 #if HAVE_PNG | |
10339 Qpng = intern ("png"); | |
10340 staticpro (&Qpng); | |
10341 #endif | |
10342 | |
10343 defsubr (&Sclear_image_cache); | |
10344 | |
10345 #if GLYPH_DEBUG | |
10346 defsubr (&Simagep); | |
10347 defsubr (&Slookup_image); | |
10348 #endif | |
10349 | |
10350 /* Busy-cursor. */ | |
10351 defsubr (&Sx_show_busy_cursor); | |
10352 defsubr (&Sx_hide_busy_cursor); | |
10353 busy_count = 0; | |
10354 inhibit_busy_cursor = 0; | |
10355 | |
10356 defsubr (&Sx_show_tip); | |
10357 defsubr (&Sx_hide_tip); | |
10358 staticpro (&tip_timer); | |
10359 tip_timer = Qnil; | |
10360 | |
10361 #ifdef USE_MOTIF | |
10362 defsubr (&Sx_file_dialog); | |
10363 #endif | |
10364 } | |
10365 | |
10366 | |
10367 void | |
10368 init_xfns () | |
10369 { | |
10370 image_types = NULL; | |
10371 Vimage_types = Qnil; | |
10372 | |
10373 define_image_type (&xbm_type); | |
10374 define_image_type (&gs_type); | |
10375 define_image_type (&pbm_type); | |
10376 | |
10377 #if HAVE_XPM | |
10378 define_image_type (&xpm_type); | |
10379 #endif | |
10380 | |
10381 #if HAVE_JPEG | |
10382 define_image_type (&jpeg_type); | |
10383 #endif | |
10384 | |
10385 #if HAVE_TIFF | |
10386 define_image_type (&tiff_type); | |
10387 #endif | |
10388 | |
10389 #if HAVE_GIF | |
10390 define_image_type (&gif_type); | |
10391 #endif | |
10392 | |
10393 #if HAVE_PNG | |
10394 define_image_type (&png_type); | |
10395 #endif | |
5465 } | 10396 } |
5466 | 10397 |
5467 #endif /* HAVE_X_WINDOWS */ | 10398 #endif /* HAVE_X_WINDOWS */ |