]> code.delx.au - gnu-emacs/blob - src/xfns.c
(Fx_open_connection): Fix docstring. Patch from Rune Kleveland <runekl@viewpoint...
[gnu-emacs] / src / xfns.c
1 /* Functions for the X window system.
2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <math.h>
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 /* This makes the fields of a Display accessible, in Xlib header files. */
32
33 #define XLIB_ILLEGAL_ACCESS
34
35 #include "lisp.h"
36 #include "xterm.h"
37 #include "frame.h"
38 #include "window.h"
39 #include "buffer.h"
40 #include "intervals.h"
41 #include "dispextern.h"
42 #include "keyboard.h"
43 #include "blockinput.h"
44 #include <epaths.h>
45 #include "charset.h"
46 #include "coding.h"
47 #include "fontset.h"
48 #include "systime.h"
49 #include "termhooks.h"
50 #include "atimer.h"
51
52 #ifdef HAVE_X_WINDOWS
53
54 #include <ctype.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57
58 #ifndef VMS
59 #if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work. */
60 #include "bitmaps/gray.xbm"
61 #else
62 #include <X11/bitmaps/gray>
63 #endif
64 #else
65 #include "[.bitmaps]gray.xbm"
66 #endif
67
68 #ifdef USE_X_TOOLKIT
69 #include <X11/Shell.h>
70
71 #ifndef USE_MOTIF
72 #include <X11/Xaw/Paned.h>
73 #include <X11/Xaw/Label.h>
74 #endif /* USE_MOTIF */
75
76 #ifdef USG
77 #undef USG /* ####KLUDGE for Solaris 2.2 and up */
78 #include <X11/Xos.h>
79 #define USG
80 #else
81 #include <X11/Xos.h>
82 #endif
83
84 #include "widget.h"
85
86 #include "../lwlib/lwlib.h"
87
88 #ifdef USE_MOTIF
89 #include <Xm/Xm.h>
90 #include <Xm/DialogS.h>
91 #include <Xm/FileSB.h>
92 #endif
93
94 /* Do the EDITRES protocol if running X11R5
95 Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */
96
97 #if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
98 #define HACK_EDITRES
99 extern void _XEditResCheckMessages ();
100 #endif /* R5 + Athena */
101
102 /* Unique id counter for widgets created by the Lucid Widget Library. */
103
104 extern LWLIB_ID widget_id_tick;
105
106 #ifdef USE_LUCID
107 /* This is part of a kludge--see lwlib/xlwmenu.c. */
108 extern XFontStruct *xlwmenu_default_font;
109 #endif
110
111 extern void free_frame_menubar ();
112 extern double atof ();
113
114 #ifdef USE_MOTIF
115
116 /* LessTif/Motif version info. */
117
118 static Lisp_Object Vmotif_version_string;
119
120 #endif /* USE_MOTIF */
121
122 #endif /* USE_X_TOOLKIT */
123
124 #ifdef HAVE_X11R4
125 #define MAXREQUEST(dpy) (XMaxRequestSize (dpy))
126 #else
127 #define MAXREQUEST(dpy) ((dpy)->max_request_size)
128 #endif
129
130 /* The gray bitmap `bitmaps/gray'. This is done because xterm.c uses
131 it, and including `bitmaps/gray' more than once is a problem when
132 config.h defines `static' as an empty replacement string. */
133
134 int gray_bitmap_width = gray_width;
135 int gray_bitmap_height = gray_height;
136 char *gray_bitmap_bits = gray_bits;
137
138 /* The name we're using in resource queries. Most often "emacs". */
139
140 Lisp_Object Vx_resource_name;
141
142 /* The application class we're using in resource queries.
143 Normally "Emacs". */
144
145 Lisp_Object Vx_resource_class;
146
147 /* Non-zero means we're allowed to display an hourglass cursor. */
148
149 int display_hourglass_p;
150
151 /* The background and shape of the mouse pointer, and shape when not
152 over text or in the modeline. */
153
154 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
155 Lisp_Object Vx_hourglass_pointer_shape;
156
157 /* The shape when over mouse-sensitive text. */
158
159 Lisp_Object Vx_sensitive_text_pointer_shape;
160
161 /* If non-nil, the pointer shape to indicate that windows can be
162 dragged horizontally. */
163
164 Lisp_Object Vx_window_horizontal_drag_shape;
165
166 /* Color of chars displayed in cursor box. */
167
168 Lisp_Object Vx_cursor_fore_pixel;
169
170 /* Nonzero if using X. */
171
172 static int x_in_use;
173
174 /* Non nil if no window manager is in use. */
175
176 Lisp_Object Vx_no_window_manager;
177
178 /* Search path for bitmap files. */
179
180 Lisp_Object Vx_bitmap_file_path;
181
182 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
183
184 Lisp_Object Vx_pixel_size_width_font_regexp;
185
186 Lisp_Object Qauto_raise;
187 Lisp_Object Qauto_lower;
188 Lisp_Object Qborder_color;
189 Lisp_Object Qborder_width;
190 Lisp_Object Qbox;
191 Lisp_Object Qcursor_color;
192 Lisp_Object Qcursor_type;
193 Lisp_Object Qgeometry;
194 Lisp_Object Qicon_left;
195 Lisp_Object Qicon_top;
196 Lisp_Object Qicon_type;
197 Lisp_Object Qicon_name;
198 Lisp_Object Qinternal_border_width;
199 Lisp_Object Qleft;
200 Lisp_Object Qright;
201 Lisp_Object Qmouse_color;
202 Lisp_Object Qnone;
203 Lisp_Object Qouter_window_id;
204 Lisp_Object Qparent_id;
205 Lisp_Object Qscroll_bar_width;
206 Lisp_Object Qsuppress_icon;
207 extern Lisp_Object Qtop;
208 Lisp_Object Qundefined_color;
209 Lisp_Object Qvertical_scroll_bars;
210 Lisp_Object Qvisibility;
211 Lisp_Object Qwindow_id;
212 Lisp_Object Qx_frame_parameter;
213 Lisp_Object Qx_resource_name;
214 Lisp_Object Quser_position;
215 Lisp_Object Quser_size;
216 extern Lisp_Object Qdisplay;
217 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
218 Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
219 Lisp_Object Qcompound_text, Qcancel_timer;
220 Lisp_Object Qwait_for_wm;
221 Lisp_Object Qfullscreen;
222 Lisp_Object Qfullwidth;
223 Lisp_Object Qfullheight;
224 Lisp_Object Qfullboth;
225
226 /* The below are defined in frame.c. */
227
228 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
229 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
230 extern Lisp_Object Qtool_bar_lines;
231
232 extern Lisp_Object Vwindow_system_version;
233
234 Lisp_Object Qface_set_after_frame_default;
235
236 #if GLYPH_DEBUG
237 int image_cache_refcount, dpyinfo_refcount;
238 #endif
239
240
241 \f
242 /* Error if we are not connected to X. */
243
244 void
245 check_x ()
246 {
247 if (! x_in_use)
248 error ("X windows are not in use or not initialized");
249 }
250
251 /* Nonzero if we can use mouse menus.
252 You should not call this unless HAVE_MENUS is defined. */
253
254 int
255 have_menus_p ()
256 {
257 return x_in_use;
258 }
259
260 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
261 and checking validity for X. */
262
263 FRAME_PTR
264 check_x_frame (frame)
265 Lisp_Object frame;
266 {
267 FRAME_PTR f;
268
269 if (NILP (frame))
270 frame = selected_frame;
271 CHECK_LIVE_FRAME (frame);
272 f = XFRAME (frame);
273 if (! FRAME_X_P (f))
274 error ("Non-X frame used");
275 return f;
276 }
277
278 /* Let the user specify an X display with a frame.
279 nil stands for the selected frame--or, if that is not an X frame,
280 the first X display on the list. */
281
282 static struct x_display_info *
283 check_x_display_info (frame)
284 Lisp_Object frame;
285 {
286 struct x_display_info *dpyinfo = NULL;
287
288 if (NILP (frame))
289 {
290 struct frame *sf = XFRAME (selected_frame);
291
292 if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
293 dpyinfo = FRAME_X_DISPLAY_INFO (sf);
294 else if (x_display_list != 0)
295 dpyinfo = x_display_list;
296 else
297 error ("X windows are not in use or not initialized");
298 }
299 else if (STRINGP (frame))
300 dpyinfo = x_display_info_for_name (frame);
301 else
302 {
303 FRAME_PTR f = check_x_frame (frame);
304 dpyinfo = FRAME_X_DISPLAY_INFO (f);
305 }
306
307 return dpyinfo;
308 }
309
310 \f
311 /* Return the Emacs frame-object corresponding to an X window.
312 It could be the frame's main window or an icon window. */
313
314 /* This function can be called during GC, so use GC_xxx type test macros. */
315
316 struct frame *
317 x_window_to_frame (dpyinfo, wdesc)
318 struct x_display_info *dpyinfo;
319 int wdesc;
320 {
321 Lisp_Object tail, frame;
322 struct frame *f;
323
324 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
325 {
326 frame = XCAR (tail);
327 if (!GC_FRAMEP (frame))
328 continue;
329 f = XFRAME (frame);
330 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
331 continue;
332 if (f->output_data.x->hourglass_window == wdesc)
333 return f;
334 #ifdef USE_X_TOOLKIT
335 if ((f->output_data.x->edit_widget
336 && XtWindow (f->output_data.x->edit_widget) == wdesc)
337 /* A tooltip frame? */
338 || (!f->output_data.x->edit_widget
339 && FRAME_X_WINDOW (f) == wdesc)
340 || f->output_data.x->icon_desc == wdesc)
341 return f;
342 #else /* not USE_X_TOOLKIT */
343 if (FRAME_X_WINDOW (f) == wdesc
344 || f->output_data.x->icon_desc == wdesc)
345 return f;
346 #endif /* not USE_X_TOOLKIT */
347 }
348 return 0;
349 }
350
351 #ifdef USE_X_TOOLKIT
352 /* Like x_window_to_frame but also compares the window with the widget's
353 windows. */
354
355 struct frame *
356 x_any_window_to_frame (dpyinfo, wdesc)
357 struct x_display_info *dpyinfo;
358 int wdesc;
359 {
360 Lisp_Object tail, frame;
361 struct frame *f, *found;
362 struct x_output *x;
363
364 found = NULL;
365 for (tail = Vframe_list; GC_CONSP (tail) && !found; tail = XCDR (tail))
366 {
367 frame = XCAR (tail);
368 if (!GC_FRAMEP (frame))
369 continue;
370
371 f = XFRAME (frame);
372 if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo)
373 {
374 /* This frame matches if the window is any of its widgets. */
375 x = f->output_data.x;
376 if (x->hourglass_window == wdesc)
377 found = f;
378 else if (x->widget)
379 {
380 if (wdesc == XtWindow (x->widget)
381 || wdesc == XtWindow (x->column_widget)
382 || wdesc == XtWindow (x->edit_widget))
383 found = f;
384 /* Match if the window is this frame's menubar. */
385 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
386 found = f;
387 }
388 else if (FRAME_X_WINDOW (f) == wdesc)
389 /* A tooltip frame. */
390 found = f;
391 }
392 }
393
394 return found;
395 }
396
397 /* Likewise, but exclude the menu bar widget. */
398
399 struct frame *
400 x_non_menubar_window_to_frame (dpyinfo, wdesc)
401 struct x_display_info *dpyinfo;
402 int wdesc;
403 {
404 Lisp_Object tail, frame;
405 struct frame *f;
406 struct x_output *x;
407
408 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
409 {
410 frame = XCAR (tail);
411 if (!GC_FRAMEP (frame))
412 continue;
413 f = XFRAME (frame);
414 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
415 continue;
416 x = f->output_data.x;
417 /* This frame matches if the window is any of its widgets. */
418 if (x->hourglass_window == wdesc)
419 return f;
420 else if (x->widget)
421 {
422 if (wdesc == XtWindow (x->widget)
423 || wdesc == XtWindow (x->column_widget)
424 || wdesc == XtWindow (x->edit_widget))
425 return f;
426 }
427 else if (FRAME_X_WINDOW (f) == wdesc)
428 /* A tooltip frame. */
429 return f;
430 }
431 return 0;
432 }
433
434 /* Likewise, but consider only the menu bar widget. */
435
436 struct frame *
437 x_menubar_window_to_frame (dpyinfo, wdesc)
438 struct x_display_info *dpyinfo;
439 int wdesc;
440 {
441 Lisp_Object tail, frame;
442 struct frame *f;
443 struct x_output *x;
444
445 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
446 {
447 frame = XCAR (tail);
448 if (!GC_FRAMEP (frame))
449 continue;
450 f = XFRAME (frame);
451 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
452 continue;
453 x = f->output_data.x;
454 /* Match if the window is this frame's menubar. */
455 if (x->menubar_widget
456 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
457 return f;
458 }
459 return 0;
460 }
461
462 /* Return the frame whose principal (outermost) window is WDESC.
463 If WDESC is some other (smaller) window, we return 0. */
464
465 struct frame *
466 x_top_window_to_frame (dpyinfo, wdesc)
467 struct x_display_info *dpyinfo;
468 int wdesc;
469 {
470 Lisp_Object tail, frame;
471 struct frame *f;
472 struct x_output *x;
473
474 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
475 {
476 frame = XCAR (tail);
477 if (!GC_FRAMEP (frame))
478 continue;
479 f = XFRAME (frame);
480 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
481 continue;
482 x = f->output_data.x;
483
484 if (x->widget)
485 {
486 /* This frame matches if the window is its topmost widget. */
487 if (wdesc == XtWindow (x->widget))
488 return f;
489 #if 0 /* I don't know why it did this,
490 but it seems logically wrong,
491 and it causes trouble for MapNotify events. */
492 /* Match if the window is this frame's menubar. */
493 if (x->menubar_widget
494 && wdesc == XtWindow (x->menubar_widget))
495 return f;
496 #endif
497 }
498 else if (FRAME_X_WINDOW (f) == wdesc)
499 /* Tooltip frame. */
500 return f;
501 }
502 return 0;
503 }
504 #endif /* USE_X_TOOLKIT */
505
506 \f
507
508 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
509 id, which is just an int that this section returns. Bitmaps are
510 reference counted so they can be shared among frames.
511
512 Bitmap indices are guaranteed to be > 0, so a negative number can
513 be used to indicate no bitmap.
514
515 If you use x_create_bitmap_from_data, then you must keep track of
516 the bitmaps yourself. That is, creating a bitmap from the same
517 data more than once will not be caught. */
518
519
520 /* Functions to access the contents of a bitmap, given an id. */
521
522 int
523 x_bitmap_height (f, id)
524 FRAME_PTR f;
525 int id;
526 {
527 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
528 }
529
530 int
531 x_bitmap_width (f, id)
532 FRAME_PTR f;
533 int id;
534 {
535 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
536 }
537
538 int
539 x_bitmap_pixmap (f, id)
540 FRAME_PTR f;
541 int id;
542 {
543 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
544 }
545
546
547 /* Allocate a new bitmap record. Returns index of new record. */
548
549 static int
550 x_allocate_bitmap_record (f)
551 FRAME_PTR f;
552 {
553 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
554 int i;
555
556 if (dpyinfo->bitmaps == NULL)
557 {
558 dpyinfo->bitmaps_size = 10;
559 dpyinfo->bitmaps
560 = (struct x_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
561 dpyinfo->bitmaps_last = 1;
562 return 1;
563 }
564
565 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
566 return ++dpyinfo->bitmaps_last;
567
568 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
569 if (dpyinfo->bitmaps[i].refcount == 0)
570 return i + 1;
571
572 dpyinfo->bitmaps_size *= 2;
573 dpyinfo->bitmaps
574 = (struct x_bitmap_record *) xrealloc (dpyinfo->bitmaps,
575 dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
576 return ++dpyinfo->bitmaps_last;
577 }
578
579 /* Add one reference to the reference count of the bitmap with id ID. */
580
581 void
582 x_reference_bitmap (f, id)
583 FRAME_PTR f;
584 int id;
585 {
586 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
587 }
588
589 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
590
591 int
592 x_create_bitmap_from_data (f, bits, width, height)
593 struct frame *f;
594 char *bits;
595 unsigned int width, height;
596 {
597 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
598 Pixmap bitmap;
599 int id;
600
601 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
602 bits, width, height);
603
604 if (! bitmap)
605 return -1;
606
607 id = x_allocate_bitmap_record (f);
608 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
609 dpyinfo->bitmaps[id - 1].file = NULL;
610 dpyinfo->bitmaps[id - 1].refcount = 1;
611 dpyinfo->bitmaps[id - 1].depth = 1;
612 dpyinfo->bitmaps[id - 1].height = height;
613 dpyinfo->bitmaps[id - 1].width = width;
614
615 return id;
616 }
617
618 /* Create bitmap from file FILE for frame F. */
619
620 int
621 x_create_bitmap_from_file (f, file)
622 struct frame *f;
623 Lisp_Object file;
624 {
625 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
626 unsigned int width, height;
627 Pixmap bitmap;
628 int xhot, yhot, result, id;
629 Lisp_Object found;
630 int fd;
631 char *filename;
632
633 /* Look for an existing bitmap with the same name. */
634 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
635 {
636 if (dpyinfo->bitmaps[id].refcount
637 && dpyinfo->bitmaps[id].file
638 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
639 {
640 ++dpyinfo->bitmaps[id].refcount;
641 return id + 1;
642 }
643 }
644
645 /* Search bitmap-file-path for the file, if appropriate. */
646 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
647 if (fd < 0)
648 return -1;
649 emacs_close (fd);
650
651 filename = (char *) SDATA (found);
652
653 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
654 filename, &width, &height, &bitmap, &xhot, &yhot);
655 if (result != BitmapSuccess)
656 return -1;
657
658 id = x_allocate_bitmap_record (f);
659 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
660 dpyinfo->bitmaps[id - 1].refcount = 1;
661 dpyinfo->bitmaps[id - 1].file
662 = (char *) xmalloc (SBYTES (file) + 1);
663 dpyinfo->bitmaps[id - 1].depth = 1;
664 dpyinfo->bitmaps[id - 1].height = height;
665 dpyinfo->bitmaps[id - 1].width = width;
666 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
667
668 return id;
669 }
670
671 /* Remove reference to bitmap with id number ID. */
672
673 void
674 x_destroy_bitmap (f, id)
675 FRAME_PTR f;
676 int id;
677 {
678 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
679
680 if (id > 0)
681 {
682 --dpyinfo->bitmaps[id - 1].refcount;
683 if (dpyinfo->bitmaps[id - 1].refcount == 0)
684 {
685 BLOCK_INPUT;
686 XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap);
687 if (dpyinfo->bitmaps[id - 1].file)
688 {
689 xfree (dpyinfo->bitmaps[id - 1].file);
690 dpyinfo->bitmaps[id - 1].file = NULL;
691 }
692 UNBLOCK_INPUT;
693 }
694 }
695 }
696
697 /* Free all the bitmaps for the display specified by DPYINFO. */
698
699 static void
700 x_destroy_all_bitmaps (dpyinfo)
701 struct x_display_info *dpyinfo;
702 {
703 int i;
704 for (i = 0; i < dpyinfo->bitmaps_last; i++)
705 if (dpyinfo->bitmaps[i].refcount > 0)
706 {
707 XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap);
708 if (dpyinfo->bitmaps[i].file)
709 xfree (dpyinfo->bitmaps[i].file);
710 }
711 dpyinfo->bitmaps_last = 0;
712 }
713 \f
714 /* Connect the frame-parameter names for X frames
715 to the ways of passing the parameter values to the window system.
716
717 The name of a parameter, as a Lisp symbol,
718 has an `x-frame-parameter' property which is an integer in Lisp
719 that is an index in this table. */
720
721 struct x_frame_parm_table
722 {
723 char *name;
724 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
725 };
726
727 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
728 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
729 static void x_change_window_heights P_ ((Lisp_Object, int));
730 static void x_disable_image P_ ((struct frame *, struct image *));
731 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
732 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
733 static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
734 static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
735 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
736 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
737 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
738 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
739 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
740 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
741 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
742 static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
743 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
744 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
745 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
746 Lisp_Object));
747 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
748 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
749 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
750 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
751 Lisp_Object));
752 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
753 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
754 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
755 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
756 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
757 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
758 void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
759 Lisp_Object));
760 void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
761 Lisp_Object));
762 static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
763 Lisp_Object,
764 Lisp_Object,
765 char *, char *,
766 int));
767 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
768 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
769 Lisp_Object));
770 static void init_color_table P_ ((void));
771 static void free_color_table P_ ((void));
772 static unsigned long *colors_in_color_table P_ ((int *n));
773 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
774 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
775
776
777
778 static struct x_frame_parm_table x_frame_parms[] =
779 {
780 {"auto-raise", x_set_autoraise},
781 {"auto-lower", x_set_autolower},
782 {"background-color", x_set_background_color},
783 {"border-color", x_set_border_color},
784 {"border-width", x_set_border_width},
785 {"cursor-color", x_set_cursor_color},
786 {"cursor-type", x_set_cursor_type},
787 {"font", x_set_font},
788 {"foreground-color", x_set_foreground_color},
789 {"icon-name", x_set_icon_name},
790 {"icon-type", x_set_icon_type},
791 {"internal-border-width", x_set_internal_border_width},
792 {"menu-bar-lines", x_set_menu_bar_lines},
793 {"mouse-color", x_set_mouse_color},
794 {"name", x_explicitly_set_name},
795 {"scroll-bar-width", x_set_scroll_bar_width},
796 {"title", x_set_title},
797 {"unsplittable", x_set_unsplittable},
798 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
799 {"visibility", x_set_visibility},
800 {"tool-bar-lines", x_set_tool_bar_lines},
801 {"scroll-bar-foreground", x_set_scroll_bar_foreground},
802 {"scroll-bar-background", x_set_scroll_bar_background},
803 {"screen-gamma", x_set_screen_gamma},
804 {"line-spacing", x_set_line_spacing},
805 {"left-fringe", x_set_fringe_width},
806 {"right-fringe", x_set_fringe_width},
807 {"wait-for-wm", x_set_wait_for_wm},
808 {"fullscreen", x_set_fullscreen},
809
810 };
811
812 /* Attach the `x-frame-parameter' properties to
813 the Lisp symbol names of parameters relevant to X. */
814
815 void
816 init_x_parm_symbols ()
817 {
818 int i;
819
820 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
821 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
822 make_number (i));
823 }
824 \f
825
826 /* Really try to move where we want to be in case of fullscreen. Some WMs
827 moves the window where we tell them. Some (mwm, twm) moves the outer
828 window manager window there instead.
829 Try to compensate for those WM here. */
830 static void
831 x_fullscreen_move (f, new_top, new_left)
832 struct frame *f;
833 int new_top;
834 int new_left;
835 {
836 if (new_top != f->output_data.x->top_pos
837 || new_left != f->output_data.x->left_pos)
838 {
839 int move_x = new_left + f->output_data.x->x_pixels_outer_diff;
840 int move_y = new_top + f->output_data.x->y_pixels_outer_diff;
841
842 f->output_data.x->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
843 x_set_offset (f, move_x, move_y, 1);
844 }
845 }
846
847 /* Change the parameters of frame F as specified by ALIST.
848 If a parameter is not specially recognized, do nothing special;
849 otherwise call the `x_set_...' function for that parameter.
850 Except for certain geometry properties, always call store_frame_param
851 to store the new value in the parameter alist. */
852
853 void
854 x_set_frame_parameters (f, alist)
855 FRAME_PTR f;
856 Lisp_Object alist;
857 {
858 Lisp_Object tail;
859
860 /* If both of these parameters are present, it's more efficient to
861 set them both at once. So we wait until we've looked at the
862 entire list before we set them. */
863 int width, height;
864
865 /* Same here. */
866 Lisp_Object left, top;
867
868 /* Same with these. */
869 Lisp_Object icon_left, icon_top;
870
871 /* Record in these vectors all the parms specified. */
872 Lisp_Object *parms;
873 Lisp_Object *values;
874 int i, p;
875 int left_no_change = 0, top_no_change = 0;
876 int icon_left_no_change = 0, icon_top_no_change = 0;
877 int fullscreen_is_being_set = 0;
878
879 struct gcpro gcpro1, gcpro2;
880
881 i = 0;
882 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
883 i++;
884
885 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
886 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
887
888 /* Extract parm names and values into those vectors. */
889
890 i = 0;
891 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
892 {
893 Lisp_Object elt;
894
895 elt = Fcar (tail);
896 parms[i] = Fcar (elt);
897 values[i] = Fcdr (elt);
898 i++;
899 }
900 /* TAIL and ALIST are not used again below here. */
901 alist = tail = Qnil;
902
903 GCPRO2 (*parms, *values);
904 gcpro1.nvars = i;
905 gcpro2.nvars = i;
906
907 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
908 because their values appear in VALUES and strings are not valid. */
909 top = left = Qunbound;
910 icon_left = icon_top = Qunbound;
911
912 /* Provide default values for HEIGHT and WIDTH. */
913 if (FRAME_NEW_WIDTH (f))
914 width = FRAME_NEW_WIDTH (f);
915 else
916 width = FRAME_WIDTH (f);
917
918 if (FRAME_NEW_HEIGHT (f))
919 height = FRAME_NEW_HEIGHT (f);
920 else
921 height = FRAME_HEIGHT (f);
922
923 /* Process foreground_color and background_color before anything else.
924 They are independent of other properties, but other properties (e.g.,
925 cursor_color) are dependent upon them. */
926 /* Process default font as well, since fringe widths depends on it. */
927 /* Also, process fullscreen, width and height depend upon that */
928 for (p = 0; p < i; p++)
929 {
930 Lisp_Object prop, val;
931
932 prop = parms[p];
933 val = values[p];
934 if (EQ (prop, Qforeground_color)
935 || EQ (prop, Qbackground_color)
936 || EQ (prop, Qfont)
937 || EQ (prop, Qfullscreen))
938 {
939 register Lisp_Object param_index, old_value;
940
941 old_value = get_frame_param (f, prop);
942 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
943
944 if (NILP (Fequal (val, old_value)))
945 {
946 store_frame_param (f, prop, val);
947
948 param_index = Fget (prop, Qx_frame_parameter);
949 if (NATNUMP (param_index)
950 && (XFASTINT (param_index)
951 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
952 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
953 }
954 }
955 }
956
957 /* Now process them in reverse of specified order. */
958 for (i--; i >= 0; i--)
959 {
960 Lisp_Object prop, val;
961
962 prop = parms[i];
963 val = values[i];
964
965 if (EQ (prop, Qwidth) && NUMBERP (val))
966 width = XFASTINT (val);
967 else if (EQ (prop, Qheight) && NUMBERP (val))
968 height = XFASTINT (val);
969 else if (EQ (prop, Qtop))
970 top = val;
971 else if (EQ (prop, Qleft))
972 left = val;
973 else if (EQ (prop, Qicon_top))
974 icon_top = val;
975 else if (EQ (prop, Qicon_left))
976 icon_left = val;
977 else if (EQ (prop, Qforeground_color)
978 || EQ (prop, Qbackground_color)
979 || EQ (prop, Qfont)
980 || EQ (prop, Qfullscreen))
981 /* Processed above. */
982 continue;
983 else
984 {
985 register Lisp_Object param_index, old_value;
986
987 old_value = get_frame_param (f, prop);
988
989 store_frame_param (f, prop, val);
990
991 param_index = Fget (prop, Qx_frame_parameter);
992 if (NATNUMP (param_index)
993 && (XFASTINT (param_index)
994 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
995 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
996 }
997 }
998
999 /* Don't die if just one of these was set. */
1000 if (EQ (left, Qunbound))
1001 {
1002 left_no_change = 1;
1003 if (f->output_data.x->left_pos < 0)
1004 left = Fcons (Qplus, Fcons (make_number (f->output_data.x->left_pos), Qnil));
1005 else
1006 XSETINT (left, f->output_data.x->left_pos);
1007 }
1008 if (EQ (top, Qunbound))
1009 {
1010 top_no_change = 1;
1011 if (f->output_data.x->top_pos < 0)
1012 top = Fcons (Qplus, Fcons (make_number (f->output_data.x->top_pos), Qnil));
1013 else
1014 XSETINT (top, f->output_data.x->top_pos);
1015 }
1016
1017 /* If one of the icon positions was not set, preserve or default it. */
1018 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
1019 {
1020 icon_left_no_change = 1;
1021 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
1022 if (NILP (icon_left))
1023 XSETINT (icon_left, 0);
1024 }
1025 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
1026 {
1027 icon_top_no_change = 1;
1028 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
1029 if (NILP (icon_top))
1030 XSETINT (icon_top, 0);
1031 }
1032
1033 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
1034 {
1035 /* If the frame is visible already and the fullscreen parameter is
1036 being set, it is too late to set WM manager hints to specify
1037 size and position.
1038 Here we first get the width, height and position that applies to
1039 fullscreen. We then move the frame to the appropriate
1040 position. Resize of the frame is taken care of in the code after
1041 this if-statement. */
1042 int new_left, new_top;
1043
1044 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
1045 x_fullscreen_move (f, new_top, new_left);
1046 }
1047
1048 /* Don't set these parameters unless they've been explicitly
1049 specified. The window might be mapped or resized while we're in
1050 this function, and we don't want to override that unless the lisp
1051 code has asked for it.
1052
1053 Don't set these parameters unless they actually differ from the
1054 window's current parameters; the window may not actually exist
1055 yet. */
1056 {
1057 Lisp_Object frame;
1058
1059 check_frame_size (f, &height, &width);
1060
1061 XSETFRAME (frame, f);
1062
1063 if (width != FRAME_WIDTH (f)
1064 || height != FRAME_HEIGHT (f)
1065 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
1066 Fset_frame_size (frame, make_number (width), make_number (height));
1067
1068 if ((!NILP (left) || !NILP (top))
1069 && ! (left_no_change && top_no_change)
1070 && ! (NUMBERP (left) && XINT (left) == f->output_data.x->left_pos
1071 && NUMBERP (top) && XINT (top) == f->output_data.x->top_pos))
1072 {
1073 int leftpos = 0;
1074 int toppos = 0;
1075
1076 /* Record the signs. */
1077 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
1078 if (EQ (left, Qminus))
1079 f->output_data.x->size_hint_flags |= XNegative;
1080 else if (INTEGERP (left))
1081 {
1082 leftpos = XINT (left);
1083 if (leftpos < 0)
1084 f->output_data.x->size_hint_flags |= XNegative;
1085 }
1086 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1087 && CONSP (XCDR (left))
1088 && INTEGERP (XCAR (XCDR (left))))
1089 {
1090 leftpos = - XINT (XCAR (XCDR (left)));
1091 f->output_data.x->size_hint_flags |= XNegative;
1092 }
1093 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1094 && CONSP (XCDR (left))
1095 && INTEGERP (XCAR (XCDR (left))))
1096 {
1097 leftpos = XINT (XCAR (XCDR (left)));
1098 }
1099
1100 if (EQ (top, Qminus))
1101 f->output_data.x->size_hint_flags |= YNegative;
1102 else if (INTEGERP (top))
1103 {
1104 toppos = XINT (top);
1105 if (toppos < 0)
1106 f->output_data.x->size_hint_flags |= YNegative;
1107 }
1108 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1109 && CONSP (XCDR (top))
1110 && INTEGERP (XCAR (XCDR (top))))
1111 {
1112 toppos = - XINT (XCAR (XCDR (top)));
1113 f->output_data.x->size_hint_flags |= YNegative;
1114 }
1115 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1116 && CONSP (XCDR (top))
1117 && INTEGERP (XCAR (XCDR (top))))
1118 {
1119 toppos = XINT (XCAR (XCDR (top)));
1120 }
1121
1122
1123 /* Store the numeric value of the position. */
1124 f->output_data.x->top_pos = toppos;
1125 f->output_data.x->left_pos = leftpos;
1126
1127 f->output_data.x->win_gravity = NorthWestGravity;
1128
1129 /* Actually set that position, and convert to absolute. */
1130 x_set_offset (f, leftpos, toppos, -1);
1131 }
1132
1133 if ((!NILP (icon_left) || !NILP (icon_top))
1134 && ! (icon_left_no_change && icon_top_no_change))
1135 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1136 }
1137
1138 UNGCPRO;
1139 }
1140
1141 /* Store the screen positions of frame F into XPTR and YPTR.
1142 These are the positions of the containing window manager window,
1143 not Emacs's own window. */
1144
1145 void
1146 x_real_positions (f, xptr, yptr)
1147 FRAME_PTR f;
1148 int *xptr, *yptr;
1149 {
1150 int win_x, win_y, outer_x, outer_y;
1151 int real_x = 0, real_y = 0;
1152 int had_errors = 0;
1153 Window win = f->output_data.x->parent_desc;
1154
1155 int count;
1156
1157 BLOCK_INPUT;
1158
1159 count = x_catch_errors (FRAME_X_DISPLAY (f));
1160
1161 if (win == FRAME_X_DISPLAY_INFO (f)->root_window)
1162 win = FRAME_OUTER_WINDOW (f);
1163
1164 /* This loop traverses up the containment tree until we hit the root
1165 window. Window managers may intersect many windows between our window
1166 and the root window. The window we find just before the root window
1167 should be the outer WM window. */
1168 for (;;)
1169 {
1170 Window wm_window, rootw;
1171 Window *tmp_children;
1172 unsigned int tmp_nchildren;
1173 int success;
1174
1175 success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
1176 &wm_window, &tmp_children, &tmp_nchildren);
1177
1178 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
1179
1180 /* Don't free tmp_children if XQueryTree failed. */
1181 if (! success)
1182 break;
1183
1184 XFree ((char *) tmp_children);
1185
1186 if (wm_window == rootw || had_errors)
1187 break;
1188
1189 win = wm_window;
1190 }
1191
1192 if (! had_errors)
1193 {
1194 int ign;
1195 Window child, rootw;
1196
1197 /* Get the real coordinates for the WM window upper left corner */
1198 XGetGeometry (FRAME_X_DISPLAY (f), win,
1199 &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);
1200
1201 /* Translate real coordinates to coordinates relative to our
1202 window. For our window, the upper left corner is 0, 0.
1203 Since the upper left corner of the WM window is outside
1204 our window, win_x and win_y will be negative:
1205
1206 ------------------ ---> x
1207 | title |
1208 | ----------------- v y
1209 | | our window
1210 */
1211 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1212
1213 /* From-window, to-window. */
1214 FRAME_X_DISPLAY_INFO (f)->root_window,
1215 FRAME_X_WINDOW (f),
1216
1217 /* From-position, to-position. */
1218 real_x, real_y, &win_x, &win_y,
1219
1220 /* Child of win. */
1221 &child);
1222
1223 if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
1224 {
1225 outer_x = win_x;
1226 outer_y = win_y;
1227 }
1228 else
1229 {
1230 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1231
1232 /* From-window, to-window. */
1233 FRAME_X_DISPLAY_INFO (f)->root_window,
1234 FRAME_OUTER_WINDOW (f),
1235
1236 /* From-position, to-position. */
1237 real_x, real_y, &outer_x, &outer_y,
1238
1239 /* Child of win. */
1240 &child);
1241 }
1242
1243 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
1244 }
1245
1246 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
1247
1248 UNBLOCK_INPUT;
1249
1250 if (had_errors) return;
1251
1252 f->output_data.x->x_pixels_diff = -win_x;
1253 f->output_data.x->y_pixels_diff = -win_y;
1254 f->output_data.x->x_pixels_outer_diff = -outer_x;
1255 f->output_data.x->y_pixels_outer_diff = -outer_y;
1256
1257 *xptr = real_x;
1258 *yptr = real_y;
1259 }
1260
1261 /* Insert a description of internally-recorded parameters of frame X
1262 into the parameter alist *ALISTPTR that is to be given to the user.
1263 Only parameters that are specific to the X window system
1264 and whose values are not correctly recorded in the frame's
1265 param_alist need to be considered here. */
1266
1267 void
1268 x_report_frame_params (f, alistptr)
1269 struct frame *f;
1270 Lisp_Object *alistptr;
1271 {
1272 char buf[16];
1273 Lisp_Object tem;
1274
1275 /* Represent negative positions (off the top or left screen edge)
1276 in a way that Fmodify_frame_parameters will understand correctly. */
1277 XSETINT (tem, f->output_data.x->left_pos);
1278 if (f->output_data.x->left_pos >= 0)
1279 store_in_alist (alistptr, Qleft, tem);
1280 else
1281 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1282
1283 XSETINT (tem, f->output_data.x->top_pos);
1284 if (f->output_data.x->top_pos >= 0)
1285 store_in_alist (alistptr, Qtop, tem);
1286 else
1287 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1288
1289 store_in_alist (alistptr, Qborder_width,
1290 make_number (f->output_data.x->border_width));
1291 store_in_alist (alistptr, Qinternal_border_width,
1292 make_number (f->output_data.x->internal_border_width));
1293 store_in_alist (alistptr, Qleft_fringe,
1294 make_number (f->output_data.x->left_fringe_width));
1295 store_in_alist (alistptr, Qright_fringe,
1296 make_number (f->output_data.x->right_fringe_width));
1297 store_in_alist (alistptr, Qscroll_bar_width,
1298 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1299 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1300 : 0));
1301 sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
1302 store_in_alist (alistptr, Qwindow_id,
1303 build_string (buf));
1304 #ifdef USE_X_TOOLKIT
1305 /* Tooltip frame may not have this widget. */
1306 if (f->output_data.x->widget)
1307 #endif
1308 sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f));
1309 store_in_alist (alistptr, Qouter_window_id,
1310 build_string (buf));
1311 store_in_alist (alistptr, Qicon_name, f->icon_name);
1312 FRAME_SAMPLE_VISIBILITY (f);
1313 store_in_alist (alistptr, Qvisibility,
1314 (FRAME_VISIBLE_P (f) ? Qt
1315 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1316 store_in_alist (alistptr, Qdisplay,
1317 XCAR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
1318
1319 if (f->output_data.x->parent_desc == FRAME_X_DISPLAY_INFO (f)->root_window)
1320 tem = Qnil;
1321 else
1322 XSETFASTINT (tem, f->output_data.x->parent_desc);
1323 store_in_alist (alistptr, Qparent_id, tem);
1324 }
1325 \f
1326
1327
1328 /* Gamma-correct COLOR on frame F. */
1329
1330 void
1331 gamma_correct (f, color)
1332 struct frame *f;
1333 XColor *color;
1334 {
1335 if (f->gamma)
1336 {
1337 color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5;
1338 color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5;
1339 color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5;
1340 }
1341 }
1342
1343
1344 /* Decide if color named COLOR_NAME is valid for use on frame F. If
1345 so, return the RGB values in COLOR. If ALLOC_P is non-zero,
1346 allocate the color. Value is zero if COLOR_NAME is invalid, or
1347 no color could be allocated. */
1348
1349 int
1350 x_defined_color (f, color_name, color, alloc_p)
1351 struct frame *f;
1352 char *color_name;
1353 XColor *color;
1354 int alloc_p;
1355 {
1356 int success_p;
1357 Display *dpy = FRAME_X_DISPLAY (f);
1358 Colormap cmap = FRAME_X_COLORMAP (f);
1359
1360 BLOCK_INPUT;
1361 success_p = XParseColor (dpy, cmap, color_name, color);
1362 if (success_p && alloc_p)
1363 success_p = x_alloc_nearest_color (f, cmap, color);
1364 UNBLOCK_INPUT;
1365
1366 return success_p;
1367 }
1368
1369
1370 /* Return the pixel color value for color COLOR_NAME on frame F. If F
1371 is a monochrome frame, return MONO_COLOR regardless of what ARG says.
1372 Signal an error if color can't be allocated. */
1373
1374 int
1375 x_decode_color (f, color_name, mono_color)
1376 FRAME_PTR f;
1377 Lisp_Object color_name;
1378 int mono_color;
1379 {
1380 XColor cdef;
1381
1382 CHECK_STRING (color_name);
1383
1384 #if 0 /* Don't do this. It's wrong when we're not using the default
1385 colormap, it makes freeing difficult, and it's probably not
1386 an important optimization. */
1387 if (strcmp (SDATA (color_name), "black") == 0)
1388 return BLACK_PIX_DEFAULT (f);
1389 else if (strcmp (SDATA (color_name), "white") == 0)
1390 return WHITE_PIX_DEFAULT (f);
1391 #endif
1392
1393 /* Return MONO_COLOR for monochrome frames. */
1394 if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
1395 return mono_color;
1396
1397 /* x_defined_color is responsible for coping with failures
1398 by looking for a near-miss. */
1399 if (x_defined_color (f, SDATA (color_name), &cdef, 1))
1400 return cdef.pixel;
1401
1402 Fsignal (Qerror, Fcons (build_string ("Undefined color"),
1403 Fcons (color_name, Qnil)));
1404 return 0;
1405 }
1406
1407
1408 \f
1409 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1410 the previous value of that parameter, NEW_VALUE is the new value. */
1411
1412 static void
1413 x_set_line_spacing (f, new_value, old_value)
1414 struct frame *f;
1415 Lisp_Object new_value, old_value;
1416 {
1417 if (NILP (new_value))
1418 f->extra_line_spacing = 0;
1419 else if (NATNUMP (new_value))
1420 f->extra_line_spacing = XFASTINT (new_value);
1421 else
1422 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
1423 Fcons (new_value, Qnil)));
1424 if (FRAME_VISIBLE_P (f))
1425 redraw_frame (f);
1426 }
1427
1428
1429 /* Change the `wait-for-wm' frame parameter of frame F. OLD_VALUE is
1430 the previous value of that parameter, NEW_VALUE is the new value.
1431 See also the comment of wait_for_wm in struct x_output. */
1432
1433 static void
1434 x_set_wait_for_wm (f, new_value, old_value)
1435 struct frame *f;
1436 Lisp_Object new_value, old_value;
1437 {
1438 f->output_data.x->wait_for_wm = !NILP (new_value);
1439 }
1440
1441
1442 /* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
1443 the previous value of that parameter, NEW_VALUE is the new value. */
1444
1445 static void
1446 x_set_fullscreen (f, new_value, old_value)
1447 struct frame *f;
1448 Lisp_Object new_value, old_value;
1449 {
1450 if (NILP (new_value))
1451 f->output_data.x->want_fullscreen = FULLSCREEN_NONE;
1452 else if (EQ (new_value, Qfullboth))
1453 f->output_data.x->want_fullscreen = FULLSCREEN_BOTH;
1454 else if (EQ (new_value, Qfullwidth))
1455 f->output_data.x->want_fullscreen = FULLSCREEN_WIDTH;
1456 else if (EQ (new_value, Qfullheight))
1457 f->output_data.x->want_fullscreen = FULLSCREEN_HEIGHT;
1458 }
1459
1460
1461 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1462 the previous value of that parameter, NEW_VALUE is the new
1463 value. */
1464
1465 static void
1466 x_set_screen_gamma (f, new_value, old_value)
1467 struct frame *f;
1468 Lisp_Object new_value, old_value;
1469 {
1470 if (NILP (new_value))
1471 f->gamma = 0;
1472 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1473 /* The value 0.4545 is the normal viewing gamma. */
1474 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1475 else
1476 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
1477 Fcons (new_value, Qnil)));
1478
1479 clear_face_cache (0);
1480 }
1481
1482
1483 /* Functions called only from `x_set_frame_param'
1484 to set individual parameters.
1485
1486 If FRAME_X_WINDOW (f) is 0,
1487 the frame is being created and its X-window does not exist yet.
1488 In that case, just record the parameter's new value
1489 in the standard place; do not attempt to change the window. */
1490
1491 void
1492 x_set_foreground_color (f, arg, oldval)
1493 struct frame *f;
1494 Lisp_Object arg, oldval;
1495 {
1496 struct x_output *x = f->output_data.x;
1497 unsigned long fg, old_fg;
1498
1499 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1500 old_fg = x->foreground_pixel;
1501 x->foreground_pixel = fg;
1502
1503 if (FRAME_X_WINDOW (f) != 0)
1504 {
1505 Display *dpy = FRAME_X_DISPLAY (f);
1506
1507 BLOCK_INPUT;
1508 XSetForeground (dpy, x->normal_gc, fg);
1509 XSetBackground (dpy, x->reverse_gc, fg);
1510
1511 if (x->cursor_pixel == old_fg)
1512 {
1513 unload_color (f, x->cursor_pixel);
1514 x->cursor_pixel = x_copy_color (f, fg);
1515 XSetBackground (dpy, x->cursor_gc, x->cursor_pixel);
1516 }
1517
1518 UNBLOCK_INPUT;
1519
1520 update_face_from_frame_parameter (f, Qforeground_color, arg);
1521
1522 if (FRAME_VISIBLE_P (f))
1523 redraw_frame (f);
1524 }
1525
1526 unload_color (f, old_fg);
1527 }
1528
1529 void
1530 x_set_background_color (f, arg, oldval)
1531 struct frame *f;
1532 Lisp_Object arg, oldval;
1533 {
1534 struct x_output *x = f->output_data.x;
1535 unsigned long bg;
1536
1537 bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1538 unload_color (f, x->background_pixel);
1539 x->background_pixel = bg;
1540
1541 if (FRAME_X_WINDOW (f) != 0)
1542 {
1543 Display *dpy = FRAME_X_DISPLAY (f);
1544
1545 BLOCK_INPUT;
1546 XSetBackground (dpy, x->normal_gc, bg);
1547 XSetForeground (dpy, x->reverse_gc, bg);
1548 XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg);
1549 XSetForeground (dpy, x->cursor_gc, bg);
1550
1551 #ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
1552 toolkit scroll bars. */
1553 {
1554 Lisp_Object bar;
1555 for (bar = FRAME_SCROLL_BARS (f);
1556 !NILP (bar);
1557 bar = XSCROLL_BAR (bar)->next)
1558 {
1559 Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar));
1560 XSetWindowBackground (dpy, window, bg);
1561 }
1562 }
1563 #endif /* USE_TOOLKIT_SCROLL_BARS */
1564
1565 UNBLOCK_INPUT;
1566 update_face_from_frame_parameter (f, Qbackground_color, arg);
1567
1568 if (FRAME_VISIBLE_P (f))
1569 redraw_frame (f);
1570 }
1571 }
1572
1573 void
1574 x_set_mouse_color (f, arg, oldval)
1575 struct frame *f;
1576 Lisp_Object arg, oldval;
1577 {
1578 struct x_output *x = f->output_data.x;
1579 Display *dpy = FRAME_X_DISPLAY (f);
1580 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
1581 Cursor hourglass_cursor, horizontal_drag_cursor;
1582 int count;
1583 unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1584 unsigned long mask_color = x->background_pixel;
1585
1586 /* Don't let pointers be invisible. */
1587 if (mask_color == pixel)
1588 {
1589 x_free_colors (f, &pixel, 1);
1590 pixel = x_copy_color (f, x->foreground_pixel);
1591 }
1592
1593 unload_color (f, x->mouse_pixel);
1594 x->mouse_pixel = pixel;
1595
1596 BLOCK_INPUT;
1597
1598 /* It's not okay to crash if the user selects a screwy cursor. */
1599 count = x_catch_errors (dpy);
1600
1601 if (!NILP (Vx_pointer_shape))
1602 {
1603 CHECK_NUMBER (Vx_pointer_shape);
1604 cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
1605 }
1606 else
1607 cursor = XCreateFontCursor (dpy, XC_xterm);
1608 x_check_errors (dpy, "bad text pointer cursor: %s");
1609
1610 if (!NILP (Vx_nontext_pointer_shape))
1611 {
1612 CHECK_NUMBER (Vx_nontext_pointer_shape);
1613 nontext_cursor
1614 = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
1615 }
1616 else
1617 nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
1618 x_check_errors (dpy, "bad nontext pointer cursor: %s");
1619
1620 if (!NILP (Vx_hourglass_pointer_shape))
1621 {
1622 CHECK_NUMBER (Vx_hourglass_pointer_shape);
1623 hourglass_cursor
1624 = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
1625 }
1626 else
1627 hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
1628 x_check_errors (dpy, "bad hourglass pointer cursor: %s");
1629
1630 x_check_errors (dpy, "bad nontext pointer cursor: %s");
1631 if (!NILP (Vx_mode_pointer_shape))
1632 {
1633 CHECK_NUMBER (Vx_mode_pointer_shape);
1634 mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
1635 }
1636 else
1637 mode_cursor = XCreateFontCursor (dpy, XC_xterm);
1638 x_check_errors (dpy, "bad modeline pointer cursor: %s");
1639
1640 if (!NILP (Vx_sensitive_text_pointer_shape))
1641 {
1642 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
1643 cross_cursor
1644 = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
1645 }
1646 else
1647 cross_cursor = XCreateFontCursor (dpy, XC_hand2);
1648
1649 if (!NILP (Vx_window_horizontal_drag_shape))
1650 {
1651 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
1652 horizontal_drag_cursor
1653 = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
1654 }
1655 else
1656 horizontal_drag_cursor
1657 = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
1658
1659 /* Check and report errors with the above calls. */
1660 x_check_errors (dpy, "can't set cursor shape: %s");
1661 x_uncatch_errors (dpy, count);
1662
1663 {
1664 XColor fore_color, back_color;
1665
1666 fore_color.pixel = x->mouse_pixel;
1667 x_query_color (f, &fore_color);
1668 back_color.pixel = mask_color;
1669 x_query_color (f, &back_color);
1670
1671 XRecolorCursor (dpy, cursor, &fore_color, &back_color);
1672 XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
1673 XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
1674 XRecolorCursor (dpy, cross_cursor, &fore_color, &back_color);
1675 XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
1676 XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
1677 }
1678
1679 if (FRAME_X_WINDOW (f) != 0)
1680 XDefineCursor (dpy, FRAME_X_WINDOW (f), cursor);
1681
1682 if (cursor != x->text_cursor
1683 && x->text_cursor != 0)
1684 XFreeCursor (dpy, x->text_cursor);
1685 x->text_cursor = cursor;
1686
1687 if (nontext_cursor != x->nontext_cursor
1688 && x->nontext_cursor != 0)
1689 XFreeCursor (dpy, x->nontext_cursor);
1690 x->nontext_cursor = nontext_cursor;
1691
1692 if (hourglass_cursor != x->hourglass_cursor
1693 && x->hourglass_cursor != 0)
1694 XFreeCursor (dpy, x->hourglass_cursor);
1695 x->hourglass_cursor = hourglass_cursor;
1696
1697 if (mode_cursor != x->modeline_cursor
1698 && x->modeline_cursor != 0)
1699 XFreeCursor (dpy, f->output_data.x->modeline_cursor);
1700 x->modeline_cursor = mode_cursor;
1701
1702 if (cross_cursor != x->cross_cursor
1703 && x->cross_cursor != 0)
1704 XFreeCursor (dpy, x->cross_cursor);
1705 x->cross_cursor = cross_cursor;
1706
1707 if (horizontal_drag_cursor != x->horizontal_drag_cursor
1708 && x->horizontal_drag_cursor != 0)
1709 XFreeCursor (dpy, x->horizontal_drag_cursor);
1710 x->horizontal_drag_cursor = horizontal_drag_cursor;
1711
1712 XFlush (dpy);
1713 UNBLOCK_INPUT;
1714
1715 update_face_from_frame_parameter (f, Qmouse_color, arg);
1716 }
1717
1718 void
1719 x_set_cursor_color (f, arg, oldval)
1720 struct frame *f;
1721 Lisp_Object arg, oldval;
1722 {
1723 unsigned long fore_pixel, pixel;
1724 int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
1725 struct x_output *x = f->output_data.x;
1726
1727 if (!NILP (Vx_cursor_fore_pixel))
1728 {
1729 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1730 WHITE_PIX_DEFAULT (f));
1731 fore_pixel_allocated_p = 1;
1732 }
1733 else
1734 fore_pixel = x->background_pixel;
1735
1736 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1737 pixel_allocated_p = 1;
1738
1739 /* Make sure that the cursor color differs from the background color. */
1740 if (pixel == x->background_pixel)
1741 {
1742 if (pixel_allocated_p)
1743 {
1744 x_free_colors (f, &pixel, 1);
1745 pixel_allocated_p = 0;
1746 }
1747
1748 pixel = x->mouse_pixel;
1749 if (pixel == fore_pixel)
1750 {
1751 if (fore_pixel_allocated_p)
1752 {
1753 x_free_colors (f, &fore_pixel, 1);
1754 fore_pixel_allocated_p = 0;
1755 }
1756 fore_pixel = x->background_pixel;
1757 }
1758 }
1759
1760 unload_color (f, x->cursor_foreground_pixel);
1761 if (!fore_pixel_allocated_p)
1762 fore_pixel = x_copy_color (f, fore_pixel);
1763 x->cursor_foreground_pixel = fore_pixel;
1764
1765 unload_color (f, x->cursor_pixel);
1766 if (!pixel_allocated_p)
1767 pixel = x_copy_color (f, pixel);
1768 x->cursor_pixel = pixel;
1769
1770 if (FRAME_X_WINDOW (f) != 0)
1771 {
1772 BLOCK_INPUT;
1773 XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
1774 XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
1775 UNBLOCK_INPUT;
1776
1777 if (FRAME_VISIBLE_P (f))
1778 {
1779 x_update_cursor (f, 0);
1780 x_update_cursor (f, 1);
1781 }
1782 }
1783
1784 update_face_from_frame_parameter (f, Qcursor_color, arg);
1785 }
1786 \f
1787 /* Set the border-color of frame F to value described by ARG.
1788 ARG can be a string naming a color.
1789 The border-color is used for the border that is drawn by the X server.
1790 Note that this does not fully take effect if done before
1791 F has an x-window; it must be redone when the window is created.
1792
1793 Note: this is done in two routines because of the way X10 works.
1794
1795 Note: under X11, this is normally the province of the window manager,
1796 and so emacs' border colors may be overridden. */
1797
1798 void
1799 x_set_border_color (f, arg, oldval)
1800 struct frame *f;
1801 Lisp_Object arg, oldval;
1802 {
1803 int pix;
1804
1805 CHECK_STRING (arg);
1806 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1807 x_set_border_pixel (f, pix);
1808 update_face_from_frame_parameter (f, Qborder_color, arg);
1809 }
1810
1811 /* Set the border-color of frame F to pixel value PIX.
1812 Note that this does not fully take effect if done before
1813 F has an x-window. */
1814
1815 void
1816 x_set_border_pixel (f, pix)
1817 struct frame *f;
1818 int pix;
1819 {
1820 unload_color (f, f->output_data.x->border_pixel);
1821 f->output_data.x->border_pixel = pix;
1822
1823 if (FRAME_X_WINDOW (f) != 0 && f->output_data.x->border_width > 0)
1824 {
1825 BLOCK_INPUT;
1826 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1827 (unsigned long)pix);
1828 UNBLOCK_INPUT;
1829
1830 if (FRAME_VISIBLE_P (f))
1831 redraw_frame (f);
1832 }
1833 }
1834
1835
1836
1837 void
1838 x_set_cursor_type (f, arg, oldval)
1839 FRAME_PTR f;
1840 Lisp_Object arg, oldval;
1841 {
1842 set_frame_cursor_types (f, arg);
1843
1844 /* Make sure the cursor gets redrawn. */
1845 cursor_type_changed = 1;
1846 }
1847 \f
1848 void
1849 x_set_icon_type (f, arg, oldval)
1850 struct frame *f;
1851 Lisp_Object arg, oldval;
1852 {
1853 int result;
1854
1855 if (STRINGP (arg))
1856 {
1857 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1858 return;
1859 }
1860 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1861 return;
1862
1863 BLOCK_INPUT;
1864 if (NILP (arg))
1865 result = x_text_icon (f,
1866 (char *) SDATA ((!NILP (f->icon_name)
1867 ? f->icon_name
1868 : f->name)));
1869 else
1870 result = x_bitmap_icon (f, arg);
1871
1872 if (result)
1873 {
1874 UNBLOCK_INPUT;
1875 error ("No icon window available");
1876 }
1877
1878 XFlush (FRAME_X_DISPLAY (f));
1879 UNBLOCK_INPUT;
1880 }
1881
1882 /* Return non-nil if frame F wants a bitmap icon. */
1883
1884 Lisp_Object
1885 x_icon_type (f)
1886 FRAME_PTR f;
1887 {
1888 Lisp_Object tem;
1889
1890 tem = assq_no_quit (Qicon_type, f->param_alist);
1891 if (CONSP (tem))
1892 return XCDR (tem);
1893 else
1894 return Qnil;
1895 }
1896
1897 void
1898 x_set_icon_name (f, arg, oldval)
1899 struct frame *f;
1900 Lisp_Object arg, oldval;
1901 {
1902 int result;
1903
1904 if (STRINGP (arg))
1905 {
1906 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1907 return;
1908 }
1909 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1910 return;
1911
1912 f->icon_name = arg;
1913
1914 if (f->output_data.x->icon_bitmap != 0)
1915 return;
1916
1917 BLOCK_INPUT;
1918
1919 result = x_text_icon (f,
1920 (char *) SDATA ((!NILP (f->icon_name)
1921 ? f->icon_name
1922 : !NILP (f->title)
1923 ? f->title
1924 : f->name)));
1925
1926 if (result)
1927 {
1928 UNBLOCK_INPUT;
1929 error ("No icon window available");
1930 }
1931
1932 XFlush (FRAME_X_DISPLAY (f));
1933 UNBLOCK_INPUT;
1934 }
1935 \f
1936 void
1937 x_set_font (f, arg, oldval)
1938 struct frame *f;
1939 Lisp_Object arg, oldval;
1940 {
1941 Lisp_Object result;
1942 Lisp_Object fontset_name;
1943 Lisp_Object frame;
1944 int old_fontset = f->output_data.x->fontset;
1945
1946 CHECK_STRING (arg);
1947
1948 fontset_name = Fquery_fontset (arg, Qnil);
1949
1950 BLOCK_INPUT;
1951 result = (STRINGP (fontset_name)
1952 ? x_new_fontset (f, SDATA (fontset_name))
1953 : x_new_font (f, SDATA (arg)));
1954 UNBLOCK_INPUT;
1955
1956 if (EQ (result, Qnil))
1957 error ("Font `%s' is not defined", SDATA (arg));
1958 else if (EQ (result, Qt))
1959 error ("The characters of the given font have varying widths");
1960 else if (STRINGP (result))
1961 {
1962 if (STRINGP (fontset_name))
1963 {
1964 /* Fontset names are built from ASCII font names, so the
1965 names may be equal despite there was a change. */
1966 if (old_fontset == f->output_data.x->fontset)
1967 return;
1968 }
1969 else if (!NILP (Fequal (result, oldval)))
1970 return;
1971
1972 store_frame_param (f, Qfont, result);
1973 recompute_basic_faces (f);
1974 }
1975 else
1976 abort ();
1977
1978 do_pending_window_change (0);
1979
1980 /* Don't call `face-set-after-frame-default' when faces haven't been
1981 initialized yet. This is the case when called from
1982 Fx_create_frame. In that case, the X widget or window doesn't
1983 exist either, and we can end up in x_report_frame_params with a
1984 null widget which gives a segfault. */
1985 if (FRAME_FACE_CACHE (f))
1986 {
1987 XSETFRAME (frame, f);
1988 call1 (Qface_set_after_frame_default, frame);
1989 }
1990 }
1991
1992 static void
1993 x_set_fringe_width (f, new_value, old_value)
1994 struct frame *f;
1995 Lisp_Object new_value, old_value;
1996 {
1997 x_compute_fringe_widths (f, 1);
1998 }
1999
2000 void
2001 x_set_border_width (f, arg, oldval)
2002 struct frame *f;
2003 Lisp_Object arg, oldval;
2004 {
2005 CHECK_NUMBER (arg);
2006
2007 if (XINT (arg) == f->output_data.x->border_width)
2008 return;
2009
2010 if (FRAME_X_WINDOW (f) != 0)
2011 error ("Cannot change the border width of a window");
2012
2013 f->output_data.x->border_width = XINT (arg);
2014 }
2015
2016 void
2017 x_set_internal_border_width (f, arg, oldval)
2018 struct frame *f;
2019 Lisp_Object arg, oldval;
2020 {
2021 int old = f->output_data.x->internal_border_width;
2022
2023 CHECK_NUMBER (arg);
2024 f->output_data.x->internal_border_width = XINT (arg);
2025 if (f->output_data.x->internal_border_width < 0)
2026 f->output_data.x->internal_border_width = 0;
2027
2028 #ifdef USE_X_TOOLKIT
2029 if (f->output_data.x->edit_widget)
2030 widget_store_internal_border (f->output_data.x->edit_widget);
2031 #endif
2032
2033 if (f->output_data.x->internal_border_width == old)
2034 return;
2035
2036 if (FRAME_X_WINDOW (f) != 0)
2037 {
2038 x_set_window_size (f, 0, f->width, f->height);
2039 SET_FRAME_GARBAGED (f);
2040 do_pending_window_change (0);
2041 }
2042 else
2043 SET_FRAME_GARBAGED (f);
2044 }
2045
2046 void
2047 x_set_visibility (f, value, oldval)
2048 struct frame *f;
2049 Lisp_Object value, oldval;
2050 {
2051 Lisp_Object frame;
2052 XSETFRAME (frame, f);
2053
2054 if (NILP (value))
2055 Fmake_frame_invisible (frame, Qt);
2056 else if (EQ (value, Qicon))
2057 Ficonify_frame (frame);
2058 else
2059 Fmake_frame_visible (frame);
2060 }
2061
2062 \f
2063 /* Change window heights in windows rooted in WINDOW by N lines. */
2064
2065 static void
2066 x_change_window_heights (window, n)
2067 Lisp_Object window;
2068 int n;
2069 {
2070 struct window *w = XWINDOW (window);
2071
2072 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2073 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2074
2075 if (INTEGERP (w->orig_top))
2076 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2077 if (INTEGERP (w->orig_height))
2078 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2079
2080 /* Handle just the top child in a vertical split. */
2081 if (!NILP (w->vchild))
2082 x_change_window_heights (w->vchild, n);
2083
2084 /* Adjust all children in a horizontal split. */
2085 for (window = w->hchild; !NILP (window); window = w->next)
2086 {
2087 w = XWINDOW (window);
2088 x_change_window_heights (window, n);
2089 }
2090 }
2091
2092 void
2093 x_set_menu_bar_lines (f, value, oldval)
2094 struct frame *f;
2095 Lisp_Object value, oldval;
2096 {
2097 int nlines;
2098 #ifndef USE_X_TOOLKIT
2099 int olines = FRAME_MENU_BAR_LINES (f);
2100 #endif
2101
2102 /* Right now, menu bars don't work properly in minibuf-only frames;
2103 most of the commands try to apply themselves to the minibuffer
2104 frame itself, and get an error because you can't switch buffers
2105 in or split the minibuffer window. */
2106 if (FRAME_MINIBUF_ONLY_P (f))
2107 return;
2108
2109 if (INTEGERP (value))
2110 nlines = XINT (value);
2111 else
2112 nlines = 0;
2113
2114 /* Make sure we redisplay all windows in this frame. */
2115 windows_or_buffers_changed++;
2116
2117 #ifdef USE_X_TOOLKIT
2118 FRAME_MENU_BAR_LINES (f) = 0;
2119 if (nlines)
2120 {
2121 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2122 if (FRAME_X_P (f) && f->output_data.x->menubar_widget == 0)
2123 /* Make sure next redisplay shows the menu bar. */
2124 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt;
2125 }
2126 else
2127 {
2128 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2129 free_frame_menubar (f);
2130 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2131 if (FRAME_X_P (f))
2132 f->output_data.x->menubar_widget = 0;
2133 }
2134 #else /* not USE_X_TOOLKIT */
2135 FRAME_MENU_BAR_LINES (f) = nlines;
2136 x_change_window_heights (f->root_window, nlines - olines);
2137 #endif /* not USE_X_TOOLKIT */
2138 adjust_glyphs (f);
2139 }
2140
2141
2142 /* Set the number of lines used for the tool bar of frame F to VALUE.
2143 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2144 is the old number of tool bar lines. This function changes the
2145 height of all windows on frame F to match the new tool bar height.
2146 The frame's height doesn't change. */
2147
2148 void
2149 x_set_tool_bar_lines (f, value, oldval)
2150 struct frame *f;
2151 Lisp_Object value, oldval;
2152 {
2153 int delta, nlines, root_height;
2154 Lisp_Object root_window;
2155
2156 /* Treat tool bars like menu bars. */
2157 if (FRAME_MINIBUF_ONLY_P (f))
2158 return;
2159
2160 /* Use VALUE only if an integer >= 0. */
2161 if (INTEGERP (value) && XINT (value) >= 0)
2162 nlines = XFASTINT (value);
2163 else
2164 nlines = 0;
2165
2166 /* Make sure we redisplay all windows in this frame. */
2167 ++windows_or_buffers_changed;
2168
2169 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2170
2171 /* Don't resize the tool-bar to more than we have room for. */
2172 root_window = FRAME_ROOT_WINDOW (f);
2173 root_height = XINT (XWINDOW (root_window)->height);
2174 if (root_height - delta < 1)
2175 {
2176 delta = root_height - 1;
2177 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2178 }
2179
2180 FRAME_TOOL_BAR_LINES (f) = nlines;
2181 x_change_window_heights (root_window, delta);
2182 adjust_glyphs (f);
2183
2184 /* We also have to make sure that the internal border at the top of
2185 the frame, below the menu bar or tool bar, is redrawn when the
2186 tool bar disappears. This is so because the internal border is
2187 below the tool bar if one is displayed, but is below the menu bar
2188 if there isn't a tool bar. The tool bar draws into the area
2189 below the menu bar. */
2190 if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2191 {
2192 updating_frame = f;
2193 clear_frame ();
2194 clear_current_matrices (f);
2195 updating_frame = NULL;
2196 }
2197
2198 /* If the tool bar gets smaller, the internal border below it
2199 has to be cleared. It was formerly part of the display
2200 of the larger tool bar, and updating windows won't clear it. */
2201 if (delta < 0)
2202 {
2203 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2204 int width = PIXEL_WIDTH (f);
2205 int y = nlines * CANON_Y_UNIT (f);
2206
2207 BLOCK_INPUT;
2208 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2209 0, y, width, height, False);
2210 UNBLOCK_INPUT;
2211
2212 if (WINDOWP (f->tool_bar_window))
2213 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2214 }
2215 }
2216
2217
2218 /* Set the foreground color for scroll bars on frame F to VALUE.
2219 VALUE should be a string, a color name. If it isn't a string or
2220 isn't a valid color name, do nothing. OLDVAL is the old value of
2221 the frame parameter. */
2222
2223 void
2224 x_set_scroll_bar_foreground (f, value, oldval)
2225 struct frame *f;
2226 Lisp_Object value, oldval;
2227 {
2228 unsigned long pixel;
2229
2230 if (STRINGP (value))
2231 pixel = x_decode_color (f, value, BLACK_PIX_DEFAULT (f));
2232 else
2233 pixel = -1;
2234
2235 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
2236 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
2237
2238 f->output_data.x->scroll_bar_foreground_pixel = pixel;
2239 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2240 {
2241 /* Remove all scroll bars because they have wrong colors. */
2242 if (condemn_scroll_bars_hook)
2243 (*condemn_scroll_bars_hook) (f);
2244 if (judge_scroll_bars_hook)
2245 (*judge_scroll_bars_hook) (f);
2246
2247 update_face_from_frame_parameter (f, Qscroll_bar_foreground, value);
2248 redraw_frame (f);
2249 }
2250 }
2251
2252
2253 /* Set the background color for scroll bars on frame F to VALUE VALUE
2254 should be a string, a color name. If it isn't a string or isn't a
2255 valid color name, do nothing. OLDVAL is the old value of the frame
2256 parameter. */
2257
2258 void
2259 x_set_scroll_bar_background (f, value, oldval)
2260 struct frame *f;
2261 Lisp_Object value, oldval;
2262 {
2263 unsigned long pixel;
2264
2265 if (STRINGP (value))
2266 pixel = x_decode_color (f, value, WHITE_PIX_DEFAULT (f));
2267 else
2268 pixel = -1;
2269
2270 if (f->output_data.x->scroll_bar_background_pixel != -1)
2271 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
2272
2273 #ifdef USE_TOOLKIT_SCROLL_BARS
2274 /* Scrollbar shadow colors. */
2275 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
2276 {
2277 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
2278 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
2279 }
2280 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
2281 {
2282 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
2283 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
2284 }
2285 #endif /* USE_TOOLKIT_SCROLL_BARS */
2286
2287 f->output_data.x->scroll_bar_background_pixel = pixel;
2288 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2289 {
2290 /* Remove all scroll bars because they have wrong colors. */
2291 if (condemn_scroll_bars_hook)
2292 (*condemn_scroll_bars_hook) (f);
2293 if (judge_scroll_bars_hook)
2294 (*judge_scroll_bars_hook) (f);
2295
2296 update_face_from_frame_parameter (f, Qscroll_bar_background, value);
2297 redraw_frame (f);
2298 }
2299 }
2300
2301 \f
2302 /* Encode Lisp string STRING as a text in a format appropriate for
2303 XICCC (X Inter Client Communication Conventions).
2304
2305 If STRING contains only ASCII characters, do no conversion and
2306 return the string data of STRING. Otherwise, encode the text by
2307 CODING_SYSTEM, and return a newly allocated memory area which
2308 should be freed by `xfree' by a caller.
2309
2310 SELECTIONP non-zero means the string is being encoded for an X
2311 selection, so it is safe to run pre-write conversions (which
2312 may run Lisp code).
2313
2314 Store the byte length of resulting text in *TEXT_BYTES.
2315
2316 If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
2317 which means that the `encoding' of the result can be `STRING'.
2318 Otherwise store 0 in *STRINGP, which means that the `encoding' of
2319 the result should be `COMPOUND_TEXT'. */
2320
2321 unsigned char *
2322 x_encode_text (string, coding_system, selectionp, text_bytes, stringp)
2323 Lisp_Object string, coding_system;
2324 int *text_bytes, *stringp;
2325 int selectionp;
2326 {
2327 unsigned char *str = SDATA (string);
2328 int chars = SCHARS (string);
2329 int bytes = SBYTES (string);
2330 int charset_info;
2331 int bufsize;
2332 unsigned char *buf;
2333 struct coding_system coding;
2334 extern Lisp_Object Qcompound_text_with_extensions;
2335
2336 charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
2337 if (charset_info == 0)
2338 {
2339 /* No multibyte character in OBJ. We need not encode it. */
2340 *text_bytes = bytes;
2341 *stringp = 1;
2342 return str;
2343 }
2344
2345 setup_coding_system (coding_system, &coding);
2346 if (selectionp
2347 && SYMBOLP (coding.pre_write_conversion)
2348 && !NILP (Ffboundp (coding.pre_write_conversion)))
2349 {
2350 string = run_pre_post_conversion_on_str (string, &coding, 1);
2351 str = SDATA (string);
2352 chars = SCHARS (string);
2353 bytes = SBYTES (string);
2354 }
2355 coding.src_multibyte = 1;
2356 coding.dst_multibyte = 0;
2357 coding.mode |= CODING_MODE_LAST_BLOCK;
2358 if (coding.type == coding_type_iso2022)
2359 coding.flags |= CODING_FLAG_ISO_SAFE;
2360 /* We suppress producing escape sequences for composition. */
2361 coding.composing = COMPOSITION_DISABLED;
2362 bufsize = encoding_buffer_size (&coding, bytes);
2363 buf = (unsigned char *) xmalloc (bufsize);
2364 encode_coding (&coding, str, buf, bytes, bufsize);
2365 *text_bytes = coding.produced;
2366 *stringp = (charset_info == 1
2367 || (!EQ (coding_system, Qcompound_text)
2368 && !EQ (coding_system, Qcompound_text_with_extensions)));
2369 return buf;
2370 }
2371
2372 \f
2373 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2374 x_id_name.
2375
2376 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2377 name; if NAME is a string, set F's name to NAME and set
2378 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2379
2380 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2381 suggesting a new name, which lisp code should override; if
2382 F->explicit_name is set, ignore the new name; otherwise, set it. */
2383
2384 void
2385 x_set_name (f, name, explicit)
2386 struct frame *f;
2387 Lisp_Object name;
2388 int explicit;
2389 {
2390 /* Make sure that requests from lisp code override requests from
2391 Emacs redisplay code. */
2392 if (explicit)
2393 {
2394 /* If we're switching from explicit to implicit, we had better
2395 update the mode lines and thereby update the title. */
2396 if (f->explicit_name && NILP (name))
2397 update_mode_lines = 1;
2398
2399 f->explicit_name = ! NILP (name);
2400 }
2401 else if (f->explicit_name)
2402 return;
2403
2404 /* If NAME is nil, set the name to the x_id_name. */
2405 if (NILP (name))
2406 {
2407 /* Check for no change needed in this very common case
2408 before we do any consing. */
2409 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->x_id_name,
2410 SDATA (f->name)))
2411 return;
2412 name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name);
2413 }
2414 else
2415 CHECK_STRING (name);
2416
2417 /* Don't change the name if it's already NAME. */
2418 if (! NILP (Fstring_equal (name, f->name)))
2419 return;
2420
2421 f->name = name;
2422
2423 /* For setting the frame title, the title parameter should override
2424 the name parameter. */
2425 if (! NILP (f->title))
2426 name = f->title;
2427
2428 if (FRAME_X_WINDOW (f))
2429 {
2430 BLOCK_INPUT;
2431 #ifdef HAVE_X11R4
2432 {
2433 XTextProperty text, icon;
2434 int bytes, stringp;
2435 Lisp_Object coding_system;
2436
2437 coding_system = Vlocale_coding_system;
2438 if (NILP (coding_system))
2439 coding_system = Qcompound_text;
2440 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
2441 text.encoding = (stringp ? XA_STRING
2442 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2443 text.format = 8;
2444 text.nitems = bytes;
2445
2446 if (NILP (f->icon_name))
2447 {
2448 icon = text;
2449 }
2450 else
2451 {
2452 icon.value = x_encode_text (f->icon_name, coding_system, 0,
2453 &bytes, &stringp);
2454 icon.encoding = (stringp ? XA_STRING
2455 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2456 icon.format = 8;
2457 icon.nitems = bytes;
2458 }
2459 #ifdef USE_X_TOOLKIT
2460 XSetWMName (FRAME_X_DISPLAY (f),
2461 XtWindow (f->output_data.x->widget), &text);
2462 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
2463 &icon);
2464 #else /* not USE_X_TOOLKIT */
2465 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
2466 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
2467 #endif /* not USE_X_TOOLKIT */
2468 if (!NILP (f->icon_name)
2469 && icon.value != SDATA (f->icon_name))
2470 xfree (icon.value);
2471 if (text.value != SDATA (name))
2472 xfree (text.value);
2473 }
2474 #else /* not HAVE_X11R4 */
2475 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2476 SDATA (name));
2477 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2478 SDATA (name));
2479 #endif /* not HAVE_X11R4 */
2480 UNBLOCK_INPUT;
2481 }
2482 }
2483
2484 /* This function should be called when the user's lisp code has
2485 specified a name for the frame; the name will override any set by the
2486 redisplay code. */
2487 void
2488 x_explicitly_set_name (f, arg, oldval)
2489 FRAME_PTR f;
2490 Lisp_Object arg, oldval;
2491 {
2492 x_set_name (f, arg, 1);
2493 }
2494
2495 /* This function should be called by Emacs redisplay code to set the
2496 name; names set this way will never override names set by the user's
2497 lisp code. */
2498 void
2499 x_implicitly_set_name (f, arg, oldval)
2500 FRAME_PTR f;
2501 Lisp_Object arg, oldval;
2502 {
2503 x_set_name (f, arg, 0);
2504 }
2505 \f
2506 /* Change the title of frame F to NAME.
2507 If NAME is nil, use the frame name as the title.
2508
2509 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2510 name; if NAME is a string, set F's name to NAME and set
2511 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2512
2513 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2514 suggesting a new name, which lisp code should override; if
2515 F->explicit_name is set, ignore the new name; otherwise, set it. */
2516
2517 void
2518 x_set_title (f, name, old_name)
2519 struct frame *f;
2520 Lisp_Object name, old_name;
2521 {
2522 /* Don't change the title if it's already NAME. */
2523 if (EQ (name, f->title))
2524 return;
2525
2526 update_mode_lines = 1;
2527
2528 f->title = name;
2529
2530 if (NILP (name))
2531 name = f->name;
2532 else
2533 CHECK_STRING (name);
2534
2535 if (FRAME_X_WINDOW (f))
2536 {
2537 BLOCK_INPUT;
2538 #ifdef HAVE_X11R4
2539 {
2540 XTextProperty text, icon;
2541 int bytes, stringp;
2542 Lisp_Object coding_system;
2543
2544 coding_system = Vlocale_coding_system;
2545 if (NILP (coding_system))
2546 coding_system = Qcompound_text;
2547 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
2548 text.encoding = (stringp ? XA_STRING
2549 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2550 text.format = 8;
2551 text.nitems = bytes;
2552
2553 if (NILP (f->icon_name))
2554 {
2555 icon = text;
2556 }
2557 else
2558 {
2559 icon.value = x_encode_text (f->icon_name, coding_system, 0,
2560 &bytes, &stringp);
2561 icon.encoding = (stringp ? XA_STRING
2562 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2563 icon.format = 8;
2564 icon.nitems = bytes;
2565 }
2566 #ifdef USE_X_TOOLKIT
2567 XSetWMName (FRAME_X_DISPLAY (f),
2568 XtWindow (f->output_data.x->widget), &text);
2569 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
2570 &icon);
2571 #else /* not USE_X_TOOLKIT */
2572 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
2573 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
2574 #endif /* not USE_X_TOOLKIT */
2575 if (!NILP (f->icon_name)
2576 && icon.value != SDATA (f->icon_name))
2577 xfree (icon.value);
2578 if (text.value != SDATA (name))
2579 xfree (text.value);
2580 }
2581 #else /* not HAVE_X11R4 */
2582 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2583 SDATA (name));
2584 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2585 SDATA (name));
2586 #endif /* not HAVE_X11R4 */
2587 UNBLOCK_INPUT;
2588 }
2589 }
2590 \f
2591 void
2592 x_set_autoraise (f, arg, oldval)
2593 struct frame *f;
2594 Lisp_Object arg, oldval;
2595 {
2596 f->auto_raise = !EQ (Qnil, arg);
2597 }
2598
2599 void
2600 x_set_autolower (f, arg, oldval)
2601 struct frame *f;
2602 Lisp_Object arg, oldval;
2603 {
2604 f->auto_lower = !EQ (Qnil, arg);
2605 }
2606
2607 void
2608 x_set_unsplittable (f, arg, oldval)
2609 struct frame *f;
2610 Lisp_Object arg, oldval;
2611 {
2612 f->no_split = !NILP (arg);
2613 }
2614
2615 void
2616 x_set_vertical_scroll_bars (f, arg, oldval)
2617 struct frame *f;
2618 Lisp_Object arg, oldval;
2619 {
2620 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2621 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2622 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2623 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2624 {
2625 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2626 = (NILP (arg)
2627 ? vertical_scroll_bar_none
2628 : EQ (Qright, arg)
2629 ? vertical_scroll_bar_right
2630 : vertical_scroll_bar_left);
2631
2632 /* We set this parameter before creating the X window for the
2633 frame, so we can get the geometry right from the start.
2634 However, if the window hasn't been created yet, we shouldn't
2635 call x_set_window_size. */
2636 if (FRAME_X_WINDOW (f))
2637 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2638 do_pending_window_change (0);
2639 }
2640 }
2641
2642 void
2643 x_set_scroll_bar_width (f, arg, oldval)
2644 struct frame *f;
2645 Lisp_Object arg, oldval;
2646 {
2647 int wid = FONT_WIDTH (f->output_data.x->font);
2648
2649 if (NILP (arg))
2650 {
2651 #ifdef USE_TOOLKIT_SCROLL_BARS
2652 /* A minimum width of 14 doesn't look good for toolkit scroll bars. */
2653 int width = 16 + 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM;
2654 FRAME_SCROLL_BAR_COLS (f) = (width + wid - 1) / wid;
2655 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = width;
2656 #else
2657 /* Make the actual width at least 14 pixels and a multiple of a
2658 character width. */
2659 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
2660
2661 /* Use all of that space (aside from required margins) for the
2662 scroll bar. */
2663 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
2664 #endif
2665
2666 if (FRAME_X_WINDOW (f))
2667 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2668 do_pending_window_change (0);
2669 }
2670 else if (INTEGERP (arg) && XINT (arg) > 0
2671 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2672 {
2673 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2674 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
2675
2676 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2677 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
2678 if (FRAME_X_WINDOW (f))
2679 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2680 }
2681
2682 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2683 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2684 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2685 }
2686
2687
2688 \f
2689 /* Subroutines of creating an X frame. */
2690
2691 /* Make sure that Vx_resource_name is set to a reasonable value.
2692 Fix it up, or set it to `emacs' if it is too hopeless. */
2693
2694 static void
2695 validate_x_resource_name ()
2696 {
2697 int len = 0;
2698 /* Number of valid characters in the resource name. */
2699 int good_count = 0;
2700 /* Number of invalid characters in the resource name. */
2701 int bad_count = 0;
2702 Lisp_Object new;
2703 int i;
2704
2705 if (!STRINGP (Vx_resource_class))
2706 Vx_resource_class = build_string (EMACS_CLASS);
2707
2708 if (STRINGP (Vx_resource_name))
2709 {
2710 unsigned char *p = SDATA (Vx_resource_name);
2711 int i;
2712
2713 len = SBYTES (Vx_resource_name);
2714
2715 /* Only letters, digits, - and _ are valid in resource names.
2716 Count the valid characters and count the invalid ones. */
2717 for (i = 0; i < len; i++)
2718 {
2719 int c = p[i];
2720 if (! ((c >= 'a' && c <= 'z')
2721 || (c >= 'A' && c <= 'Z')
2722 || (c >= '0' && c <= '9')
2723 || c == '-' || c == '_'))
2724 bad_count++;
2725 else
2726 good_count++;
2727 }
2728 }
2729 else
2730 /* Not a string => completely invalid. */
2731 bad_count = 5, good_count = 0;
2732
2733 /* If name is valid already, return. */
2734 if (bad_count == 0)
2735 return;
2736
2737 /* If name is entirely invalid, or nearly so, use `emacs'. */
2738 if (good_count == 0
2739 || (good_count == 1 && bad_count > 0))
2740 {
2741 Vx_resource_name = build_string ("emacs");
2742 return;
2743 }
2744
2745 /* Name is partly valid. Copy it and replace the invalid characters
2746 with underscores. */
2747
2748 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2749
2750 for (i = 0; i < len; i++)
2751 {
2752 int c = SREF (new, i);
2753 if (! ((c >= 'a' && c <= 'z')
2754 || (c >= 'A' && c <= 'Z')
2755 || (c >= '0' && c <= '9')
2756 || c == '-' || c == '_'))
2757 SSET (new, i, '_');
2758 }
2759 }
2760
2761
2762 extern char *x_get_string_resource ();
2763
2764 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2765 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2766 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2767 class, where INSTANCE is the name under which Emacs was invoked, or
2768 the name specified by the `-name' or `-rn' command-line arguments.
2769
2770 The optional arguments COMPONENT and SUBCLASS add to the key and the
2771 class, respectively. You must specify both of them or neither.
2772 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
2773 and the class is `Emacs.CLASS.SUBCLASS'. */)
2774 (attribute, class, component, subclass)
2775 Lisp_Object attribute, class, component, subclass;
2776 {
2777 register char *value;
2778 char *name_key;
2779 char *class_key;
2780
2781 check_x ();
2782
2783 CHECK_STRING (attribute);
2784 CHECK_STRING (class);
2785
2786 if (!NILP (component))
2787 CHECK_STRING (component);
2788 if (!NILP (subclass))
2789 CHECK_STRING (subclass);
2790 if (NILP (component) != NILP (subclass))
2791 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2792
2793 validate_x_resource_name ();
2794
2795 /* Allocate space for the components, the dots which separate them,
2796 and the final '\0'. Make them big enough for the worst case. */
2797 name_key = (char *) alloca (SBYTES (Vx_resource_name)
2798 + (STRINGP (component)
2799 ? SBYTES (component) : 0)
2800 + SBYTES (attribute)
2801 + 3);
2802
2803 class_key = (char *) alloca (SBYTES (Vx_resource_class)
2804 + SBYTES (class)
2805 + (STRINGP (subclass)
2806 ? SBYTES (subclass) : 0)
2807 + 3);
2808
2809 /* Start with emacs.FRAMENAME for the name (the specific one)
2810 and with `Emacs' for the class key (the general one). */
2811 strcpy (name_key, SDATA (Vx_resource_name));
2812 strcpy (class_key, SDATA (Vx_resource_class));
2813
2814 strcat (class_key, ".");
2815 strcat (class_key, SDATA (class));
2816
2817 if (!NILP (component))
2818 {
2819 strcat (class_key, ".");
2820 strcat (class_key, SDATA (subclass));
2821
2822 strcat (name_key, ".");
2823 strcat (name_key, SDATA (component));
2824 }
2825
2826 strcat (name_key, ".");
2827 strcat (name_key, SDATA (attribute));
2828
2829 value = x_get_string_resource (check_x_display_info (Qnil)->xrdb,
2830 name_key, class_key);
2831
2832 if (value != (char *) 0)
2833 return build_string (value);
2834 else
2835 return Qnil;
2836 }
2837
2838 /* Get an X resource, like Fx_get_resource, but for display DPYINFO. */
2839
2840 Lisp_Object
2841 display_x_get_resource (dpyinfo, attribute, class, component, subclass)
2842 struct x_display_info *dpyinfo;
2843 Lisp_Object attribute, class, component, subclass;
2844 {
2845 register char *value;
2846 char *name_key;
2847 char *class_key;
2848
2849 CHECK_STRING (attribute);
2850 CHECK_STRING (class);
2851
2852 if (!NILP (component))
2853 CHECK_STRING (component);
2854 if (!NILP (subclass))
2855 CHECK_STRING (subclass);
2856 if (NILP (component) != NILP (subclass))
2857 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2858
2859 validate_x_resource_name ();
2860
2861 /* Allocate space for the components, the dots which separate them,
2862 and the final '\0'. Make them big enough for the worst case. */
2863 name_key = (char *) alloca (SBYTES (Vx_resource_name)
2864 + (STRINGP (component)
2865 ? SBYTES (component) : 0)
2866 + SBYTES (attribute)
2867 + 3);
2868
2869 class_key = (char *) alloca (SBYTES (Vx_resource_class)
2870 + SBYTES (class)
2871 + (STRINGP (subclass)
2872 ? SBYTES (subclass) : 0)
2873 + 3);
2874
2875 /* Start with emacs.FRAMENAME for the name (the specific one)
2876 and with `Emacs' for the class key (the general one). */
2877 strcpy (name_key, SDATA (Vx_resource_name));
2878 strcpy (class_key, SDATA (Vx_resource_class));
2879
2880 strcat (class_key, ".");
2881 strcat (class_key, SDATA (class));
2882
2883 if (!NILP (component))
2884 {
2885 strcat (class_key, ".");
2886 strcat (class_key, SDATA (subclass));
2887
2888 strcat (name_key, ".");
2889 strcat (name_key, SDATA (component));
2890 }
2891
2892 strcat (name_key, ".");
2893 strcat (name_key, SDATA (attribute));
2894
2895 value = x_get_string_resource (dpyinfo->xrdb, name_key, class_key);
2896
2897 if (value != (char *) 0)
2898 return build_string (value);
2899 else
2900 return Qnil;
2901 }
2902
2903 /* Used when C code wants a resource value. */
2904
2905 char *
2906 x_get_resource_string (attribute, class)
2907 char *attribute, *class;
2908 {
2909 char *name_key;
2910 char *class_key;
2911 struct frame *sf = SELECTED_FRAME ();
2912
2913 /* Allocate space for the components, the dots which separate them,
2914 and the final '\0'. */
2915 name_key = (char *) alloca (SBYTES (Vinvocation_name)
2916 + strlen (attribute) + 2);
2917 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2918 + strlen (class) + 2);
2919
2920 sprintf (name_key, "%s.%s",
2921 SDATA (Vinvocation_name),
2922 attribute);
2923 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2924
2925 return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
2926 name_key, class_key);
2927 }
2928
2929 /* Types we might convert a resource string into. */
2930 enum resource_types
2931 {
2932 RES_TYPE_NUMBER,
2933 RES_TYPE_FLOAT,
2934 RES_TYPE_BOOLEAN,
2935 RES_TYPE_STRING,
2936 RES_TYPE_SYMBOL
2937 };
2938
2939 /* Return the value of parameter PARAM.
2940
2941 First search ALIST, then Vdefault_frame_alist, then the X defaults
2942 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2943
2944 Convert the resource to the type specified by desired_type.
2945
2946 If no default is specified, return Qunbound. If you call
2947 x_get_arg, make sure you deal with Qunbound in a reasonable way,
2948 and don't let it get stored in any Lisp-visible variables! */
2949
2950 static Lisp_Object
2951 x_get_arg (dpyinfo, alist, param, attribute, class, type)
2952 struct x_display_info *dpyinfo;
2953 Lisp_Object alist, param;
2954 char *attribute;
2955 char *class;
2956 enum resource_types type;
2957 {
2958 register Lisp_Object tem;
2959
2960 tem = Fassq (param, alist);
2961 if (EQ (tem, Qnil))
2962 tem = Fassq (param, Vdefault_frame_alist);
2963 if (EQ (tem, Qnil))
2964 {
2965
2966 if (attribute)
2967 {
2968 tem = display_x_get_resource (dpyinfo,
2969 build_string (attribute),
2970 build_string (class),
2971 Qnil, Qnil);
2972
2973 if (NILP (tem))
2974 return Qunbound;
2975
2976 switch (type)
2977 {
2978 case RES_TYPE_NUMBER:
2979 return make_number (atoi (SDATA (tem)));
2980
2981 case RES_TYPE_FLOAT:
2982 return make_float (atof (SDATA (tem)));
2983
2984 case RES_TYPE_BOOLEAN:
2985 tem = Fdowncase (tem);
2986 if (!strcmp (SDATA (tem), "on")
2987 || !strcmp (SDATA (tem), "true"))
2988 return Qt;
2989 else
2990 return Qnil;
2991
2992 case RES_TYPE_STRING:
2993 return tem;
2994
2995 case RES_TYPE_SYMBOL:
2996 /* As a special case, we map the values `true' and `on'
2997 to Qt, and `false' and `off' to Qnil. */
2998 {
2999 Lisp_Object lower;
3000 lower = Fdowncase (tem);
3001 if (!strcmp (SDATA (lower), "on")
3002 || !strcmp (SDATA (lower), "true"))
3003 return Qt;
3004 else if (!strcmp (SDATA (lower), "off")
3005 || !strcmp (SDATA (lower), "false"))
3006 return Qnil;
3007 else
3008 return Fintern (tem, Qnil);
3009 }
3010
3011 default:
3012 abort ();
3013 }
3014 }
3015 else
3016 return Qunbound;
3017 }
3018 return Fcdr (tem);
3019 }
3020
3021 /* Like x_get_arg, but also record the value in f->param_alist. */
3022
3023 static Lisp_Object
3024 x_get_and_record_arg (f, alist, param, attribute, class, type)
3025 struct frame *f;
3026 Lisp_Object alist, param;
3027 char *attribute;
3028 char *class;
3029 enum resource_types type;
3030 {
3031 Lisp_Object value;
3032
3033 value = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, param,
3034 attribute, class, type);
3035 if (! NILP (value))
3036 store_frame_param (f, param, value);
3037
3038 return value;
3039 }
3040
3041 /* Record in frame F the specified or default value according to ALIST
3042 of the parameter named PROP (a Lisp symbol).
3043 If no value is specified for PROP, look for an X default for XPROP
3044 on the frame named NAME.
3045 If that is not found either, use the value DEFLT. */
3046
3047 static Lisp_Object
3048 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3049 struct frame *f;
3050 Lisp_Object alist;
3051 Lisp_Object prop;
3052 Lisp_Object deflt;
3053 char *xprop;
3054 char *xclass;
3055 enum resource_types type;
3056 {
3057 Lisp_Object tem;
3058
3059 tem = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, prop, xprop, xclass, type);
3060 if (EQ (tem, Qunbound))
3061 tem = deflt;
3062 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3063 return tem;
3064 }
3065
3066
3067 /* Record in frame F the specified or default value according to ALIST
3068 of the parameter named PROP (a Lisp symbol). If no value is
3069 specified for PROP, look for an X default for XPROP on the frame
3070 named NAME. If that is not found either, use the value DEFLT. */
3071
3072 static Lisp_Object
3073 x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass,
3074 foreground_p)
3075 struct frame *f;
3076 Lisp_Object alist;
3077 Lisp_Object prop;
3078 char *xprop;
3079 char *xclass;
3080 int foreground_p;
3081 {
3082 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3083 Lisp_Object tem;
3084
3085 tem = x_get_arg (dpyinfo, alist, prop, xprop, xclass, RES_TYPE_STRING);
3086 if (EQ (tem, Qunbound))
3087 {
3088 #ifdef USE_TOOLKIT_SCROLL_BARS
3089
3090 /* See if an X resource for the scroll bar color has been
3091 specified. */
3092 tem = display_x_get_resource (dpyinfo,
3093 build_string (foreground_p
3094 ? "foreground"
3095 : "background"),
3096 empty_string,
3097 build_string ("verticalScrollBar"),
3098 empty_string);
3099 if (!STRINGP (tem))
3100 {
3101 /* If nothing has been specified, scroll bars will use a
3102 toolkit-dependent default. Because these defaults are
3103 difficult to get at without actually creating a scroll
3104 bar, use nil to indicate that no color has been
3105 specified. */
3106 tem = Qnil;
3107 }
3108
3109 #else /* not USE_TOOLKIT_SCROLL_BARS */
3110
3111 tem = Qnil;
3112
3113 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3114 }
3115
3116 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3117 return tem;
3118 }
3119
3120
3121 \f
3122 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3123 doc: /* Parse an X-style geometry string STRING.
3124 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3125 The properties returned may include `top', `left', `height', and `width'.
3126 The value of `left' or `top' may be an integer,
3127 or a list (+ N) meaning N pixels relative to top/left corner,
3128 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3129 (string)
3130 Lisp_Object string;
3131 {
3132 int geometry, x, y;
3133 unsigned int width, height;
3134 Lisp_Object result;
3135
3136 CHECK_STRING (string);
3137
3138 geometry = XParseGeometry ((char *) SDATA (string),
3139 &x, &y, &width, &height);
3140
3141 #if 0
3142 if (!!(geometry & XValue) != !!(geometry & YValue))
3143 error ("Must specify both x and y position, or neither");
3144 #endif
3145
3146 result = Qnil;
3147 if (geometry & XValue)
3148 {
3149 Lisp_Object element;
3150
3151 if (x >= 0 && (geometry & XNegative))
3152 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3153 else if (x < 0 && ! (geometry & XNegative))
3154 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3155 else
3156 element = Fcons (Qleft, make_number (x));
3157 result = Fcons (element, result);
3158 }
3159
3160 if (geometry & YValue)
3161 {
3162 Lisp_Object element;
3163
3164 if (y >= 0 && (geometry & YNegative))
3165 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3166 else if (y < 0 && ! (geometry & YNegative))
3167 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3168 else
3169 element = Fcons (Qtop, make_number (y));
3170 result = Fcons (element, result);
3171 }
3172
3173 if (geometry & WidthValue)
3174 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3175 if (geometry & HeightValue)
3176 result = Fcons (Fcons (Qheight, make_number (height)), result);
3177
3178 return result;
3179 }
3180
3181 /* Calculate the desired size and position of this window,
3182 and return the flags saying which aspects were specified.
3183
3184 This function does not make the coordinates positive. */
3185
3186 #define DEFAULT_ROWS 40
3187 #define DEFAULT_COLS 80
3188
3189 static int
3190 x_figure_window_size (f, parms)
3191 struct frame *f;
3192 Lisp_Object parms;
3193 {
3194 register Lisp_Object tem0, tem1, tem2;
3195 long window_prompting = 0;
3196 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3197
3198 /* Default values if we fall through.
3199 Actually, if that happens we should get
3200 window manager prompting. */
3201 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3202 f->height = DEFAULT_ROWS;
3203 /* Window managers expect that if program-specified
3204 positions are not (0,0), they're intentional, not defaults. */
3205 f->output_data.x->top_pos = 0;
3206 f->output_data.x->left_pos = 0;
3207
3208 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3209 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3210 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3211 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3212 {
3213 if (!EQ (tem0, Qunbound))
3214 {
3215 CHECK_NUMBER (tem0);
3216 f->height = XINT (tem0);
3217 }
3218 if (!EQ (tem1, Qunbound))
3219 {
3220 CHECK_NUMBER (tem1);
3221 SET_FRAME_WIDTH (f, XINT (tem1));
3222 }
3223 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3224 window_prompting |= USSize;
3225 else
3226 window_prompting |= PSize;
3227 }
3228
3229 f->output_data.x->vertical_scroll_bar_extra
3230 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3231 ? 0
3232 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
3233
3234 x_compute_fringe_widths (f, 0);
3235
3236 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3237 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3238
3239 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3240 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3241 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3242 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3243 {
3244 if (EQ (tem0, Qminus))
3245 {
3246 f->output_data.x->top_pos = 0;
3247 window_prompting |= YNegative;
3248 }
3249 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3250 && CONSP (XCDR (tem0))
3251 && INTEGERP (XCAR (XCDR (tem0))))
3252 {
3253 f->output_data.x->top_pos = - XINT (XCAR (XCDR (tem0)));
3254 window_prompting |= YNegative;
3255 }
3256 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3257 && CONSP (XCDR (tem0))
3258 && INTEGERP (XCAR (XCDR (tem0))))
3259 {
3260 f->output_data.x->top_pos = XINT (XCAR (XCDR (tem0)));
3261 }
3262 else if (EQ (tem0, Qunbound))
3263 f->output_data.x->top_pos = 0;
3264 else
3265 {
3266 CHECK_NUMBER (tem0);
3267 f->output_data.x->top_pos = XINT (tem0);
3268 if (f->output_data.x->top_pos < 0)
3269 window_prompting |= YNegative;
3270 }
3271
3272 if (EQ (tem1, Qminus))
3273 {
3274 f->output_data.x->left_pos = 0;
3275 window_prompting |= XNegative;
3276 }
3277 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3278 && CONSP (XCDR (tem1))
3279 && INTEGERP (XCAR (XCDR (tem1))))
3280 {
3281 f->output_data.x->left_pos = - XINT (XCAR (XCDR (tem1)));
3282 window_prompting |= XNegative;
3283 }
3284 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3285 && CONSP (XCDR (tem1))
3286 && INTEGERP (XCAR (XCDR (tem1))))
3287 {
3288 f->output_data.x->left_pos = XINT (XCAR (XCDR (tem1)));
3289 }
3290 else if (EQ (tem1, Qunbound))
3291 f->output_data.x->left_pos = 0;
3292 else
3293 {
3294 CHECK_NUMBER (tem1);
3295 f->output_data.x->left_pos = XINT (tem1);
3296 if (f->output_data.x->left_pos < 0)
3297 window_prompting |= XNegative;
3298 }
3299
3300 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3301 window_prompting |= USPosition;
3302 else
3303 window_prompting |= PPosition;
3304 }
3305
3306 if (f->output_data.x->want_fullscreen != FULLSCREEN_NONE)
3307 {
3308 int left, top;
3309 int width, height;
3310
3311 /* It takes both for some WM:s to place it where we want */
3312 window_prompting = USPosition | PPosition;
3313 x_fullscreen_adjust (f, &width, &height, &top, &left);
3314 f->width = width;
3315 f->height = height;
3316 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3317 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3318 f->output_data.x->left_pos = left;
3319 f->output_data.x->top_pos = top;
3320 }
3321
3322 return window_prompting;
3323 }
3324
3325 #if !defined (HAVE_X11R4) && !defined (HAVE_XSETWMPROTOCOLS)
3326
3327 Status
3328 XSetWMProtocols (dpy, w, protocols, count)
3329 Display *dpy;
3330 Window w;
3331 Atom *protocols;
3332 int count;
3333 {
3334 Atom prop;
3335 prop = XInternAtom (dpy, "WM_PROTOCOLS", False);
3336 if (prop == None) return False;
3337 XChangeProperty (dpy, w, prop, XA_ATOM, 32, PropModeReplace,
3338 (unsigned char *) protocols, count);
3339 return True;
3340 }
3341 #endif /* not HAVE_X11R4 && not HAVE_XSETWMPROTOCOLS */
3342 \f
3343 #ifdef USE_X_TOOLKIT
3344
3345 /* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS,
3346 WM_DELETE_WINDOW, and WM_SAVE_YOURSELF, then add them. (They may
3347 already be present because of the toolkit (Motif adds some of them,
3348 for example, but Xt doesn't). */
3349
3350 static void
3351 hack_wm_protocols (f, widget)
3352 FRAME_PTR f;
3353 Widget widget;
3354 {
3355 Display *dpy = XtDisplay (widget);
3356 Window w = XtWindow (widget);
3357 int need_delete = 1;
3358 int need_focus = 1;
3359 int need_save = 1;
3360
3361 BLOCK_INPUT;
3362 {
3363 Atom type, *atoms = 0;
3364 int format = 0;
3365 unsigned long nitems = 0;
3366 unsigned long bytes_after;
3367
3368 if ((XGetWindowProperty (dpy, w,
3369 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3370 (long)0, (long)100, False, XA_ATOM,
3371 &type, &format, &nitems, &bytes_after,
3372 (unsigned char **) &atoms)
3373 == Success)
3374 && format == 32 && type == XA_ATOM)
3375 while (nitems > 0)
3376 {
3377 nitems--;
3378 if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window)
3379 need_delete = 0;
3380 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus)
3381 need_focus = 0;
3382 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself)
3383 need_save = 0;
3384 }
3385 if (atoms) XFree ((char *) atoms);
3386 }
3387 {
3388 Atom props [10];
3389 int count = 0;
3390 if (need_delete)
3391 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
3392 if (need_focus)
3393 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus;
3394 if (need_save)
3395 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
3396 if (count)
3397 XChangeProperty (dpy, w, FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3398 XA_ATOM, 32, PropModeAppend,
3399 (unsigned char *) props, count);
3400 }
3401 UNBLOCK_INPUT;
3402 }
3403 #endif
3404
3405
3406 \f
3407 /* Support routines for XIC (X Input Context). */
3408
3409 #ifdef HAVE_X_I18N
3410
3411 static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
3412 static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
3413
3414
3415 /* Supported XIM styles, ordered by preferenc. */
3416
3417 static XIMStyle supported_xim_styles[] =
3418 {
3419 XIMPreeditPosition | XIMStatusArea,
3420 XIMPreeditPosition | XIMStatusNothing,
3421 XIMPreeditPosition | XIMStatusNone,
3422 XIMPreeditNothing | XIMStatusArea,
3423 XIMPreeditNothing | XIMStatusNothing,
3424 XIMPreeditNothing | XIMStatusNone,
3425 XIMPreeditNone | XIMStatusArea,
3426 XIMPreeditNone | XIMStatusNothing,
3427 XIMPreeditNone | XIMStatusNone,
3428 0,
3429 };
3430
3431
3432 /* Create an X fontset on frame F with base font name
3433 BASE_FONTNAME.. */
3434
3435 static XFontSet
3436 xic_create_xfontset (f, base_fontname)
3437 struct frame *f;
3438 char *base_fontname;
3439 {
3440 XFontSet xfs;
3441 char **missing_list;
3442 int missing_count;
3443 char *def_string;
3444
3445 xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
3446 base_fontname, &missing_list,
3447 &missing_count, &def_string);
3448 if (missing_list)
3449 XFreeStringList (missing_list);
3450
3451 /* No need to free def_string. */
3452 return xfs;
3453 }
3454
3455
3456 /* Value is the best input style, given user preferences USER (already
3457 checked to be supported by Emacs), and styles supported by the
3458 input method XIM. */
3459
3460 static XIMStyle
3461 best_xim_style (user, xim)
3462 XIMStyles *user;
3463 XIMStyles *xim;
3464 {
3465 int i, j;
3466
3467 for (i = 0; i < user->count_styles; ++i)
3468 for (j = 0; j < xim->count_styles; ++j)
3469 if (user->supported_styles[i] == xim->supported_styles[j])
3470 return user->supported_styles[i];
3471
3472 /* Return the default style. */
3473 return XIMPreeditNothing | XIMStatusNothing;
3474 }
3475
3476 /* Create XIC for frame F. */
3477
3478 static XIMStyle xic_style;
3479
3480 void
3481 create_frame_xic (f)
3482 struct frame *f;
3483 {
3484 XIM xim;
3485 XIC xic = NULL;
3486 XFontSet xfs = NULL;
3487
3488 if (FRAME_XIC (f))
3489 return;
3490
3491 xim = FRAME_X_XIM (f);
3492 if (xim)
3493 {
3494 XRectangle s_area;
3495 XPoint spot;
3496 XVaNestedList preedit_attr;
3497 XVaNestedList status_attr;
3498 char *base_fontname;
3499 int fontset;
3500
3501 s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
3502 spot.x = 0; spot.y = 1;
3503 /* Create X fontset. */
3504 fontset = FRAME_FONTSET (f);
3505 if (fontset < 0)
3506 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3507 else
3508 {
3509 /* Determine the base fontname from the ASCII font name of
3510 FONTSET. */
3511 char *ascii_font = (char *) SDATA (fontset_ascii (fontset));
3512 char *p = ascii_font;
3513 int i;
3514
3515 for (i = 0; *p; p++)
3516 if (*p == '-') i++;
3517 if (i != 14)
3518 /* As the font name doesn't conform to XLFD, we can't
3519 modify it to get a suitable base fontname for the
3520 frame. */
3521 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3522 else
3523 {
3524 int len = strlen (ascii_font) + 1;
3525 char *p1 = NULL;
3526
3527 for (i = 0, p = ascii_font; i < 8; p++)
3528 {
3529 if (*p == '-')
3530 {
3531 i++;
3532 if (i == 3)
3533 p1 = p + 1;
3534 }
3535 }
3536 base_fontname = (char *) alloca (len);
3537 bzero (base_fontname, len);
3538 strcpy (base_fontname, "-*-*-");
3539 bcopy (p1, base_fontname + 5, p - p1);
3540 strcat (base_fontname, "*-*-*-*-*-*-*");
3541 }
3542 }
3543 xfs = xic_create_xfontset (f, base_fontname);
3544
3545 /* Determine XIC style. */
3546 if (xic_style == 0)
3547 {
3548 XIMStyles supported_list;
3549 supported_list.count_styles = (sizeof supported_xim_styles
3550 / sizeof supported_xim_styles[0]);
3551 supported_list.supported_styles = supported_xim_styles;
3552 xic_style = best_xim_style (&supported_list,
3553 FRAME_X_XIM_STYLES (f));
3554 }
3555
3556 preedit_attr = XVaCreateNestedList (0,
3557 XNFontSet, xfs,
3558 XNForeground,
3559 FRAME_FOREGROUND_PIXEL (f),
3560 XNBackground,
3561 FRAME_BACKGROUND_PIXEL (f),
3562 (xic_style & XIMPreeditPosition
3563 ? XNSpotLocation
3564 : NULL),
3565 &spot,
3566 NULL);
3567 status_attr = XVaCreateNestedList (0,
3568 XNArea,
3569 &s_area,
3570 XNFontSet,
3571 xfs,
3572 XNForeground,
3573 FRAME_FOREGROUND_PIXEL (f),
3574 XNBackground,
3575 FRAME_BACKGROUND_PIXEL (f),
3576 NULL);
3577
3578 xic = XCreateIC (xim,
3579 XNInputStyle, xic_style,
3580 XNClientWindow, FRAME_X_WINDOW(f),
3581 XNFocusWindow, FRAME_X_WINDOW(f),
3582 XNStatusAttributes, status_attr,
3583 XNPreeditAttributes, preedit_attr,
3584 NULL);
3585 XFree (preedit_attr);
3586 XFree (status_attr);
3587 }
3588
3589 FRAME_XIC (f) = xic;
3590 FRAME_XIC_STYLE (f) = xic_style;
3591 FRAME_XIC_FONTSET (f) = xfs;
3592 }
3593
3594
3595 /* Destroy XIC and free XIC fontset of frame F, if any. */
3596
3597 void
3598 free_frame_xic (f)
3599 struct frame *f;
3600 {
3601 if (FRAME_XIC (f) == NULL)
3602 return;
3603
3604 XDestroyIC (FRAME_XIC (f));
3605 if (FRAME_XIC_FONTSET (f))
3606 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3607
3608 FRAME_XIC (f) = NULL;
3609 FRAME_XIC_FONTSET (f) = NULL;
3610 }
3611
3612
3613 /* Place preedit area for XIC of window W's frame to specified
3614 pixel position X/Y. X and Y are relative to window W. */
3615
3616 void
3617 xic_set_preeditarea (w, x, y)
3618 struct window *w;
3619 int x, y;
3620 {
3621 struct frame *f = XFRAME (w->frame);
3622 XVaNestedList attr;
3623 XPoint spot;
3624
3625 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
3626 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
3627 attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
3628 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3629 XFree (attr);
3630 }
3631
3632
3633 /* Place status area for XIC in bottom right corner of frame F.. */
3634
3635 void
3636 xic_set_statusarea (f)
3637 struct frame *f;
3638 {
3639 XIC xic = FRAME_XIC (f);
3640 XVaNestedList attr;
3641 XRectangle area;
3642 XRectangle *needed;
3643
3644 /* Negotiate geometry of status area. If input method has existing
3645 status area, use its current size. */
3646 area.x = area.y = area.width = area.height = 0;
3647 attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
3648 XSetICValues (xic, XNStatusAttributes, attr, NULL);
3649 XFree (attr);
3650
3651 attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
3652 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3653 XFree (attr);
3654
3655 if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
3656 {
3657 attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
3658 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3659 XFree (attr);
3660 }
3661
3662 area.width = needed->width;
3663 area.height = needed->height;
3664 area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
3665 area.y = (PIXEL_HEIGHT (f) - area.height
3666 - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
3667 XFree (needed);
3668
3669 attr = XVaCreateNestedList (0, XNArea, &area, NULL);
3670 XSetICValues(xic, XNStatusAttributes, attr, NULL);
3671 XFree (attr);
3672 }
3673
3674
3675 /* Set X fontset for XIC of frame F, using base font name
3676 BASE_FONTNAME. Called when a new Emacs fontset is chosen. */
3677
3678 void
3679 xic_set_xfontset (f, base_fontname)
3680 struct frame *f;
3681 char *base_fontname;
3682 {
3683 XVaNestedList attr;
3684 XFontSet xfs;
3685
3686 xfs = xic_create_xfontset (f, base_fontname);
3687
3688 attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
3689 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
3690 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3691 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
3692 XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
3693 XFree (attr);
3694
3695 if (FRAME_XIC_FONTSET (f))
3696 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3697 FRAME_XIC_FONTSET (f) = xfs;
3698 }
3699
3700 #endif /* HAVE_X_I18N */
3701
3702
3703 \f
3704 #ifdef USE_X_TOOLKIT
3705
3706 /* Create and set up the X widget for frame F. */
3707
3708 static void
3709 x_window (f, window_prompting, minibuffer_only)
3710 struct frame *f;
3711 long window_prompting;
3712 int minibuffer_only;
3713 {
3714 XClassHint class_hints;
3715 XSetWindowAttributes attributes;
3716 unsigned long attribute_mask;
3717 Widget shell_widget;
3718 Widget pane_widget;
3719 Widget frame_widget;
3720 Arg al [25];
3721 int ac;
3722
3723 BLOCK_INPUT;
3724
3725 /* Use the resource name as the top-level widget name
3726 for looking up resources. Make a non-Lisp copy
3727 for the window manager, so GC relocation won't bother it.
3728
3729 Elsewhere we specify the window name for the window manager. */
3730
3731 {
3732 char *str = (char *) SDATA (Vx_resource_name);
3733 f->namebuf = (char *) xmalloc (strlen (str) + 1);
3734 strcpy (f->namebuf, str);
3735 }
3736
3737 ac = 0;
3738 XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
3739 XtSetArg (al[ac], XtNinput, 1); ac++;
3740 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
3741 XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
3742 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3743 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3744 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3745 shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
3746 applicationShellWidgetClass,
3747 FRAME_X_DISPLAY (f), al, ac);
3748
3749 f->output_data.x->widget = shell_widget;
3750 /* maybe_set_screen_title_format (shell_widget); */
3751
3752 pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
3753 (widget_value *) NULL,
3754 shell_widget, False,
3755 (lw_callback) NULL,
3756 (lw_callback) NULL,
3757 (lw_callback) NULL,
3758 (lw_callback) NULL);
3759
3760 ac = 0;
3761 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3762 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3763 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3764 XtSetValues (pane_widget, al, ac);
3765 f->output_data.x->column_widget = pane_widget;
3766
3767 /* mappedWhenManaged to false tells to the paned window to not map/unmap
3768 the emacs screen when changing menubar. This reduces flickering. */
3769
3770 ac = 0;
3771 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
3772 XtSetArg (al[ac], XtNshowGrip, 0); ac++;
3773 XtSetArg (al[ac], XtNallowResize, 1); ac++;
3774 XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
3775 XtSetArg (al[ac], XtNemacsFrame, f); ac++;
3776 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3777 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3778 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3779 frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
3780 al, ac);
3781
3782 f->output_data.x->edit_widget = frame_widget;
3783
3784 XtManageChild (frame_widget);
3785
3786 /* Do some needed geometry management. */
3787 {
3788 int len;
3789 char *tem, shell_position[32];
3790 Arg al[2];
3791 int ac = 0;
3792 int extra_borders = 0;
3793 int menubar_size
3794 = (f->output_data.x->menubar_widget
3795 ? (f->output_data.x->menubar_widget->core.height
3796 + f->output_data.x->menubar_widget->core.border_width)
3797 : 0);
3798
3799 #if 0 /* Experimentally, we now get the right results
3800 for -geometry -0-0 without this. 24 Aug 96, rms. */
3801 if (FRAME_EXTERNAL_MENU_BAR (f))
3802 {
3803 Dimension ibw = 0;
3804 XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
3805 menubar_size += ibw;
3806 }
3807 #endif
3808
3809 f->output_data.x->menubar_height = menubar_size;
3810
3811 #ifndef USE_LUCID
3812 /* Motif seems to need this amount added to the sizes
3813 specified for the shell widget. The Athena/Lucid widgets don't.
3814 Both conclusions reached experimentally. -- rms. */
3815 XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
3816 &extra_borders, NULL);
3817 extra_borders *= 2;
3818 #endif
3819
3820 /* Convert our geometry parameters into a geometry string
3821 and specify it.
3822 Note that we do not specify here whether the position
3823 is a user-specified or program-specified one.
3824 We pass that information later, in x_wm_set_size_hints. */
3825 {
3826 int left = f->output_data.x->left_pos;
3827 int xneg = window_prompting & XNegative;
3828 int top = f->output_data.x->top_pos;
3829 int yneg = window_prompting & YNegative;
3830 if (xneg)
3831 left = -left;
3832 if (yneg)
3833 top = -top;
3834
3835 if (window_prompting & USPosition)
3836 sprintf (shell_position, "=%dx%d%c%d%c%d",
3837 PIXEL_WIDTH (f) + extra_borders,
3838 PIXEL_HEIGHT (f) + menubar_size + extra_borders,
3839 (xneg ? '-' : '+'), left,
3840 (yneg ? '-' : '+'), top);
3841 else
3842 sprintf (shell_position, "=%dx%d",
3843 PIXEL_WIDTH (f) + extra_borders,
3844 PIXEL_HEIGHT (f) + menubar_size + extra_borders);
3845 }
3846
3847 len = strlen (shell_position) + 1;
3848 /* We don't free this because we don't know whether
3849 it is safe to free it while the frame exists.
3850 It isn't worth the trouble of arranging to free it
3851 when the frame is deleted. */
3852 tem = (char *) xmalloc (len);
3853 strncpy (tem, shell_position, len);
3854 XtSetArg (al[ac], XtNgeometry, tem); ac++;
3855 XtSetValues (shell_widget, al, ac);
3856 }
3857
3858 XtManageChild (pane_widget);
3859 XtRealizeWidget (shell_widget);
3860
3861 FRAME_X_WINDOW (f) = XtWindow (frame_widget);
3862
3863 validate_x_resource_name ();
3864
3865 class_hints.res_name = (char *) SDATA (Vx_resource_name);
3866 class_hints.res_class = (char *) SDATA (Vx_resource_class);
3867 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
3868
3869 #ifdef HAVE_X_I18N
3870 FRAME_XIC (f) = NULL;
3871 #ifdef USE_XIM
3872 create_frame_xic (f);
3873 #endif
3874 #endif
3875
3876 f->output_data.x->wm_hints.input = True;
3877 f->output_data.x->wm_hints.flags |= InputHint;
3878 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3879 &f->output_data.x->wm_hints);
3880
3881 hack_wm_protocols (f, shell_widget);
3882
3883 #ifdef HACK_EDITRES
3884 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0);
3885 #endif
3886
3887 /* Do a stupid property change to force the server to generate a
3888 PropertyNotify event so that the event_stream server timestamp will
3889 be initialized to something relevant to the time we created the window.
3890 */
3891 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
3892 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3893 XA_ATOM, 32, PropModeAppend,
3894 (unsigned char*) NULL, 0);
3895
3896 /* Make all the standard events reach the Emacs frame. */
3897 attributes.event_mask = STANDARD_EVENT_SET;
3898
3899 #ifdef HAVE_X_I18N
3900 if (FRAME_XIC (f))
3901 {
3902 /* XIM server might require some X events. */
3903 unsigned long fevent = NoEventMask;
3904 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
3905 attributes.event_mask |= fevent;
3906 }
3907 #endif /* HAVE_X_I18N */
3908
3909 attribute_mask = CWEventMask;
3910 XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
3911 attribute_mask, &attributes);
3912
3913 XtMapWidget (frame_widget);
3914
3915 /* x_set_name normally ignores requests to set the name if the
3916 requested name is the same as the current name. This is the one
3917 place where that assumption isn't correct; f->name is set, but
3918 the X server hasn't been told. */
3919 {
3920 Lisp_Object name;
3921 int explicit = f->explicit_name;
3922
3923 f->explicit_name = 0;
3924 name = f->name;
3925 f->name = Qnil;
3926 x_set_name (f, name, explicit);
3927 }
3928
3929 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3930 f->output_data.x->text_cursor);
3931
3932 UNBLOCK_INPUT;
3933
3934 /* This is a no-op, except under Motif. Make sure main areas are
3935 set to something reasonable, in case we get an error later. */
3936 lw_set_main_areas (pane_widget, 0, frame_widget);
3937 }
3938
3939 #else /* not USE_X_TOOLKIT */
3940
3941 /* Create and set up the X window for frame F. */
3942
3943 void
3944 x_window (f)
3945 struct frame *f;
3946
3947 {
3948 XClassHint class_hints;
3949 XSetWindowAttributes attributes;
3950 unsigned long attribute_mask;
3951
3952 attributes.background_pixel = f->output_data.x->background_pixel;
3953 attributes.border_pixel = f->output_data.x->border_pixel;
3954 attributes.bit_gravity = StaticGravity;
3955 attributes.backing_store = NotUseful;
3956 attributes.save_under = True;
3957 attributes.event_mask = STANDARD_EVENT_SET;
3958 attributes.colormap = FRAME_X_COLORMAP (f);
3959 attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
3960 | CWColormap);
3961
3962 BLOCK_INPUT;
3963 FRAME_X_WINDOW (f)
3964 = XCreateWindow (FRAME_X_DISPLAY (f),
3965 f->output_data.x->parent_desc,
3966 f->output_data.x->left_pos,
3967 f->output_data.x->top_pos,
3968 PIXEL_WIDTH (f), PIXEL_HEIGHT (f),
3969 f->output_data.x->border_width,
3970 CopyFromParent, /* depth */
3971 InputOutput, /* class */
3972 FRAME_X_VISUAL (f),
3973 attribute_mask, &attributes);
3974
3975 #ifdef HAVE_X_I18N
3976 #ifdef USE_XIM
3977 create_frame_xic (f);
3978 if (FRAME_XIC (f))
3979 {
3980 /* XIM server might require some X events. */
3981 unsigned long fevent = NoEventMask;
3982 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
3983 attributes.event_mask |= fevent;
3984 attribute_mask = CWEventMask;
3985 XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3986 attribute_mask, &attributes);
3987 }
3988 #endif
3989 #endif /* HAVE_X_I18N */
3990
3991 validate_x_resource_name ();
3992
3993 class_hints.res_name = (char *) SDATA (Vx_resource_name);
3994 class_hints.res_class = (char *) SDATA (Vx_resource_class);
3995 XSetClassHint (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &class_hints);
3996
3997 /* The menubar is part of the ordinary display;
3998 it does not count in addition to the height of the window. */
3999 f->output_data.x->menubar_height = 0;
4000
4001 /* This indicates that we use the "Passive Input" input model.
4002 Unless we do this, we don't get the Focus{In,Out} events that we
4003 need to draw the cursor correctly. Accursed bureaucrats.
4004 XWhipsAndChains (FRAME_X_DISPLAY (f), IronMaiden, &TheRack); */
4005
4006 f->output_data.x->wm_hints.input = True;
4007 f->output_data.x->wm_hints.flags |= InputHint;
4008 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4009 &f->output_data.x->wm_hints);
4010 f->output_data.x->wm_hints.icon_pixmap = None;
4011
4012 /* Request "save yourself" and "delete window" commands from wm. */
4013 {
4014 Atom protocols[2];
4015 protocols[0] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
4016 protocols[1] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
4017 XSetWMProtocols (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), protocols, 2);
4018 }
4019
4020 /* x_set_name normally ignores requests to set the name if the
4021 requested name is the same as the current name. This is the one
4022 place where that assumption isn't correct; f->name is set, but
4023 the X server hasn't been told. */
4024 {
4025 Lisp_Object name;
4026 int explicit = f->explicit_name;
4027
4028 f->explicit_name = 0;
4029 name = f->name;
4030 f->name = Qnil;
4031 x_set_name (f, name, explicit);
4032 }
4033
4034 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4035 f->output_data.x->text_cursor);
4036
4037 UNBLOCK_INPUT;
4038
4039 if (FRAME_X_WINDOW (f) == 0)
4040 error ("Unable to create window");
4041 }
4042
4043 #endif /* not USE_X_TOOLKIT */
4044
4045 /* Handle the icon stuff for this window. Perhaps later we might
4046 want an x_set_icon_position which can be called interactively as
4047 well. */
4048
4049 static void
4050 x_icon (f, parms)
4051 struct frame *f;
4052 Lisp_Object parms;
4053 {
4054 Lisp_Object icon_x, icon_y;
4055 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4056
4057 /* Set the position of the icon. Note that twm groups all
4058 icons in an icon window. */
4059 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4060 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4061 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4062 {
4063 CHECK_NUMBER (icon_x);
4064 CHECK_NUMBER (icon_y);
4065 }
4066 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4067 error ("Both left and top icon corners of icon must be specified");
4068
4069 BLOCK_INPUT;
4070
4071 if (! EQ (icon_x, Qunbound))
4072 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4073
4074 /* Start up iconic or window? */
4075 x_wm_set_window_state
4076 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL),
4077 Qicon)
4078 ? IconicState
4079 : NormalState));
4080
4081 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
4082 ? f->icon_name
4083 : f->name)));
4084
4085 UNBLOCK_INPUT;
4086 }
4087
4088 /* Make the GCs needed for this window, setting the
4089 background, border and mouse colors; also create the
4090 mouse cursor and the gray border tile. */
4091
4092 static char cursor_bits[] =
4093 {
4094 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4095 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4098 };
4099
4100 static void
4101 x_make_gc (f)
4102 struct frame *f;
4103 {
4104 XGCValues gc_values;
4105
4106 BLOCK_INPUT;
4107
4108 /* Create the GCs of this frame.
4109 Note that many default values are used. */
4110
4111 /* Normal video */
4112 gc_values.font = f->output_data.x->font->fid;
4113 gc_values.foreground = f->output_data.x->foreground_pixel;
4114 gc_values.background = f->output_data.x->background_pixel;
4115 gc_values.line_width = 0; /* Means 1 using fast algorithm. */
4116 f->output_data.x->normal_gc
4117 = XCreateGC (FRAME_X_DISPLAY (f),
4118 FRAME_X_WINDOW (f),
4119 GCLineWidth | GCFont | GCForeground | GCBackground,
4120 &gc_values);
4121
4122 /* Reverse video style. */
4123 gc_values.foreground = f->output_data.x->background_pixel;
4124 gc_values.background = f->output_data.x->foreground_pixel;
4125 f->output_data.x->reverse_gc
4126 = XCreateGC (FRAME_X_DISPLAY (f),
4127 FRAME_X_WINDOW (f),
4128 GCFont | GCForeground | GCBackground | GCLineWidth,
4129 &gc_values);
4130
4131 /* Cursor has cursor-color background, background-color foreground. */
4132 gc_values.foreground = f->output_data.x->background_pixel;
4133 gc_values.background = f->output_data.x->cursor_pixel;
4134 gc_values.fill_style = FillOpaqueStippled;
4135 gc_values.stipple
4136 = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
4137 FRAME_X_DISPLAY_INFO (f)->root_window,
4138 cursor_bits, 16, 16);
4139 f->output_data.x->cursor_gc
4140 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4141 (GCFont | GCForeground | GCBackground
4142 | GCFillStyle /* | GCStipple */ | GCLineWidth),
4143 &gc_values);
4144
4145 /* Reliefs. */
4146 f->output_data.x->white_relief.gc = 0;
4147 f->output_data.x->black_relief.gc = 0;
4148
4149 /* Create the gray border tile used when the pointer is not in
4150 the frame. Since this depends on the frame's pixel values,
4151 this must be done on a per-frame basis. */
4152 f->output_data.x->border_tile
4153 = (XCreatePixmapFromBitmapData
4154 (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
4155 gray_bits, gray_width, gray_height,
4156 f->output_data.x->foreground_pixel,
4157 f->output_data.x->background_pixel,
4158 DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f))));
4159
4160 UNBLOCK_INPUT;
4161 }
4162
4163
4164 /* Free what was was allocated in x_make_gc. */
4165
4166 void
4167 x_free_gcs (f)
4168 struct frame *f;
4169 {
4170 Display *dpy = FRAME_X_DISPLAY (f);
4171
4172 BLOCK_INPUT;
4173
4174 if (f->output_data.x->normal_gc)
4175 {
4176 XFreeGC (dpy, f->output_data.x->normal_gc);
4177 f->output_data.x->normal_gc = 0;
4178 }
4179
4180 if (f->output_data.x->reverse_gc)
4181 {
4182 XFreeGC (dpy, f->output_data.x->reverse_gc);
4183 f->output_data.x->reverse_gc = 0;
4184 }
4185
4186 if (f->output_data.x->cursor_gc)
4187 {
4188 XFreeGC (dpy, f->output_data.x->cursor_gc);
4189 f->output_data.x->cursor_gc = 0;
4190 }
4191
4192 if (f->output_data.x->border_tile)
4193 {
4194 XFreePixmap (dpy, f->output_data.x->border_tile);
4195 f->output_data.x->border_tile = 0;
4196 }
4197
4198 UNBLOCK_INPUT;
4199 }
4200
4201
4202 /* Handler for signals raised during x_create_frame and
4203 x_create_top_frame. FRAME is the frame which is partially
4204 constructed. */
4205
4206 static Lisp_Object
4207 unwind_create_frame (frame)
4208 Lisp_Object frame;
4209 {
4210 struct frame *f = XFRAME (frame);
4211
4212 /* If frame is ``official'', nothing to do. */
4213 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4214 {
4215 #if GLYPH_DEBUG
4216 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4217 #endif
4218
4219 x_free_frame_resources (f);
4220
4221 /* Check that reference counts are indeed correct. */
4222 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4223 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
4224 return Qt;
4225 }
4226
4227 return Qnil;
4228 }
4229
4230
4231 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
4232 1, 1, 0,
4233 doc: /* Make a new X window, which is called a "frame" in Emacs terms.
4234 Returns an Emacs frame object.
4235 ALIST is an alist of frame parameters.
4236 If the parameters specify that the frame should not have a minibuffer,
4237 and do not specify a specific minibuffer window to use,
4238 then `default-minibuffer-frame' must be a frame whose minibuffer can
4239 be shared by the new frame.
4240
4241 This function is an internal primitive--use `make-frame' instead. */)
4242 (parms)
4243 Lisp_Object parms;
4244 {
4245 struct frame *f;
4246 Lisp_Object frame, tem;
4247 Lisp_Object name;
4248 int minibuffer_only = 0;
4249 long window_prompting = 0;
4250 int width, height;
4251 int count = SPECPDL_INDEX ();
4252 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
4253 Lisp_Object display;
4254 struct x_display_info *dpyinfo = NULL;
4255 Lisp_Object parent;
4256 struct kboard *kb;
4257
4258 check_x ();
4259
4260 /* Use this general default value to start with
4261 until we know if this frame has a specified name. */
4262 Vx_resource_name = Vinvocation_name;
4263
4264 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
4265 if (EQ (display, Qunbound))
4266 display = Qnil;
4267 dpyinfo = check_x_display_info (display);
4268 #ifdef MULTI_KBOARD
4269 kb = dpyinfo->kboard;
4270 #else
4271 kb = &the_only_kboard;
4272 #endif
4273
4274 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
4275 if (!STRINGP (name)
4276 && ! EQ (name, Qunbound)
4277 && ! NILP (name))
4278 error ("Invalid frame name--not a string or nil");
4279
4280 if (STRINGP (name))
4281 Vx_resource_name = name;
4282
4283 /* See if parent window is specified. */
4284 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
4285 if (EQ (parent, Qunbound))
4286 parent = Qnil;
4287 if (! NILP (parent))
4288 CHECK_NUMBER (parent);
4289
4290 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4291 /* No need to protect DISPLAY because that's not used after passing
4292 it to make_frame_without_minibuffer. */
4293 frame = Qnil;
4294 GCPRO4 (parms, parent, name, frame);
4295 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
4296 RES_TYPE_SYMBOL);
4297 if (EQ (tem, Qnone) || NILP (tem))
4298 f = make_frame_without_minibuffer (Qnil, kb, display);
4299 else if (EQ (tem, Qonly))
4300 {
4301 f = make_minibuffer_frame ();
4302 minibuffer_only = 1;
4303 }
4304 else if (WINDOWP (tem))
4305 f = make_frame_without_minibuffer (tem, kb, display);
4306 else
4307 f = make_frame (1);
4308
4309 XSETFRAME (frame, f);
4310
4311 /* Note that X Windows does support scroll bars. */
4312 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
4313
4314 f->output_method = output_x_window;
4315 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
4316 bzero (f->output_data.x, sizeof (struct x_output));
4317 f->output_data.x->icon_bitmap = -1;
4318 f->output_data.x->fontset = -1;
4319 f->output_data.x->scroll_bar_foreground_pixel = -1;
4320 f->output_data.x->scroll_bar_background_pixel = -1;
4321 #ifdef USE_TOOLKIT_SCROLL_BARS
4322 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
4323 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
4324 #endif /* USE_TOOLKIT_SCROLL_BARS */
4325 record_unwind_protect (unwind_create_frame, frame);
4326
4327 f->icon_name
4328 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
4329 RES_TYPE_STRING);
4330 if (! STRINGP (f->icon_name))
4331 f->icon_name = Qnil;
4332
4333 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
4334 #if GLYPH_DEBUG
4335 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
4336 dpyinfo_refcount = dpyinfo->reference_count;
4337 #endif /* GLYPH_DEBUG */
4338 #ifdef MULTI_KBOARD
4339 FRAME_KBOARD (f) = kb;
4340 #endif
4341
4342 /* These colors will be set anyway later, but it's important
4343 to get the color reference counts right, so initialize them! */
4344 {
4345 Lisp_Object black;
4346 struct gcpro gcpro1;
4347
4348 /* Function x_decode_color can signal an error. Make
4349 sure to initialize color slots so that we won't try
4350 to free colors we haven't allocated. */
4351 f->output_data.x->foreground_pixel = -1;
4352 f->output_data.x->background_pixel = -1;
4353 f->output_data.x->cursor_pixel = -1;
4354 f->output_data.x->cursor_foreground_pixel = -1;
4355 f->output_data.x->border_pixel = -1;
4356 f->output_data.x->mouse_pixel = -1;
4357
4358 black = build_string ("black");
4359 GCPRO1 (black);
4360 f->output_data.x->foreground_pixel
4361 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4362 f->output_data.x->background_pixel
4363 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4364 f->output_data.x->cursor_pixel
4365 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4366 f->output_data.x->cursor_foreground_pixel
4367 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4368 f->output_data.x->border_pixel
4369 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4370 f->output_data.x->mouse_pixel
4371 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4372 UNGCPRO;
4373 }
4374
4375 /* Specify the parent under which to make this X window. */
4376
4377 if (!NILP (parent))
4378 {
4379 f->output_data.x->parent_desc = (Window) XFASTINT (parent);
4380 f->output_data.x->explicit_parent = 1;
4381 }
4382 else
4383 {
4384 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
4385 f->output_data.x->explicit_parent = 0;
4386 }
4387
4388 /* Set the name; the functions to which we pass f expect the name to
4389 be set. */
4390 if (EQ (name, Qunbound) || NILP (name))
4391 {
4392 f->name = build_string (dpyinfo->x_id_name);
4393 f->explicit_name = 0;
4394 }
4395 else
4396 {
4397 f->name = name;
4398 f->explicit_name = 1;
4399 /* use the frame's title when getting resources for this frame. */
4400 specbind (Qx_resource_name, name);
4401 }
4402
4403 /* Extract the window parameters from the supplied values
4404 that are needed to determine window geometry. */
4405 {
4406 Lisp_Object font;
4407
4408 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
4409
4410 BLOCK_INPUT;
4411 /* First, try whatever font the caller has specified. */
4412 if (STRINGP (font))
4413 {
4414 tem = Fquery_fontset (font, Qnil);
4415 if (STRINGP (tem))
4416 font = x_new_fontset (f, SDATA (tem));
4417 else
4418 font = x_new_font (f, SDATA (font));
4419 }
4420
4421 /* Try out a font which we hope has bold and italic variations. */
4422 if (!STRINGP (font))
4423 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
4424 if (!STRINGP (font))
4425 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
4426 if (! STRINGP (font))
4427 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
4428 if (! STRINGP (font))
4429 /* This was formerly the first thing tried, but it finds too many fonts
4430 and takes too long. */
4431 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
4432 /* If those didn't work, look for something which will at least work. */
4433 if (! STRINGP (font))
4434 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
4435 UNBLOCK_INPUT;
4436 if (! STRINGP (font))
4437 font = build_string ("fixed");
4438
4439 x_default_parameter (f, parms, Qfont, font,
4440 "font", "Font", RES_TYPE_STRING);
4441 }
4442
4443 #ifdef USE_LUCID
4444 /* Prevent lwlib/xlwmenu.c from crashing because of a bug
4445 whereby it fails to get any font. */
4446 xlwmenu_default_font = f->output_data.x->font;
4447 #endif
4448
4449 x_default_parameter (f, parms, Qborder_width, make_number (2),
4450 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4451
4452 /* This defaults to 1 in order to match xterm. We recognize either
4453 internalBorderWidth or internalBorder (which is what xterm calls
4454 it). */
4455 if (NILP (Fassq (Qinternal_border_width, parms)))
4456 {
4457 Lisp_Object value;
4458
4459 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
4460 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
4461 if (! EQ (value, Qunbound))
4462 parms = Fcons (Fcons (Qinternal_border_width, value),
4463 parms);
4464 }
4465 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
4466 "internalBorderWidth", "internalBorderWidth",
4467 RES_TYPE_NUMBER);
4468 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft,
4469 "verticalScrollBars", "ScrollBars",
4470 RES_TYPE_SYMBOL);
4471
4472 /* Also do the stuff which must be set before the window exists. */
4473 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
4474 "foreground", "Foreground", RES_TYPE_STRING);
4475 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
4476 "background", "Background", RES_TYPE_STRING);
4477 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
4478 "pointerColor", "Foreground", RES_TYPE_STRING);
4479 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
4480 "cursorColor", "Foreground", RES_TYPE_STRING);
4481 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
4482 "borderColor", "BorderColor", RES_TYPE_STRING);
4483 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
4484 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
4485 x_default_parameter (f, parms, Qline_spacing, Qnil,
4486 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
4487 x_default_parameter (f, parms, Qleft_fringe, Qnil,
4488 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4489 x_default_parameter (f, parms, Qright_fringe, Qnil,
4490 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
4491
4492 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
4493 "scrollBarForeground",
4494 "ScrollBarForeground", 1);
4495 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
4496 "scrollBarBackground",
4497 "ScrollBarBackground", 0);
4498
4499 /* Init faces before x_default_parameter is called for scroll-bar
4500 parameters because that function calls x_set_scroll_bar_width,
4501 which calls change_frame_size, which calls Fset_window_buffer,
4502 which runs hooks, which call Fvertical_motion. At the end, we
4503 end up in init_iterator with a null face cache, which should not
4504 happen. */
4505 init_frame_faces (f);
4506
4507 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
4508 "menuBar", "MenuBar", RES_TYPE_NUMBER);
4509 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
4510 "toolBar", "ToolBar", RES_TYPE_NUMBER);
4511 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
4512 "bufferPredicate", "BufferPredicate",
4513 RES_TYPE_SYMBOL);
4514 x_default_parameter (f, parms, Qtitle, Qnil,
4515 "title", "Title", RES_TYPE_STRING);
4516 x_default_parameter (f, parms, Qwait_for_wm, Qt,
4517 "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
4518 x_default_parameter (f, parms, Qfullscreen, Qnil,
4519 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
4520
4521 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
4522
4523 /* Add the tool-bar height to the initial frame height so that the
4524 user gets a text display area of the size he specified with -g or
4525 via .Xdefaults. Later changes of the tool-bar height don't
4526 change the frame size. This is done so that users can create
4527 tall Emacs frames without having to guess how tall the tool-bar
4528 will get. */
4529 if (FRAME_TOOL_BAR_LINES (f))
4530 {
4531 int margin, relief, bar_height;
4532
4533 relief = (tool_bar_button_relief >= 0
4534 ? tool_bar_button_relief
4535 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
4536
4537 if (INTEGERP (Vtool_bar_button_margin)
4538 && XINT (Vtool_bar_button_margin) > 0)
4539 margin = XFASTINT (Vtool_bar_button_margin);
4540 else if (CONSP (Vtool_bar_button_margin)
4541 && INTEGERP (XCDR (Vtool_bar_button_margin))
4542 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4543 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
4544 else
4545 margin = 0;
4546
4547 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
4548 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
4549 }
4550
4551 /* Compute the size of the X window. */
4552 window_prompting = x_figure_window_size (f, parms);
4553
4554 if (window_prompting & XNegative)
4555 {
4556 if (window_prompting & YNegative)
4557 f->output_data.x->win_gravity = SouthEastGravity;
4558 else
4559 f->output_data.x->win_gravity = NorthEastGravity;
4560 }
4561 else
4562 {
4563 if (window_prompting & YNegative)
4564 f->output_data.x->win_gravity = SouthWestGravity;
4565 else
4566 f->output_data.x->win_gravity = NorthWestGravity;
4567 }
4568
4569 f->output_data.x->size_hint_flags = window_prompting;
4570
4571 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4572 f->no_split = minibuffer_only || EQ (tem, Qt);
4573
4574 /* Create the X widget or window. */
4575 #ifdef USE_X_TOOLKIT
4576 x_window (f, window_prompting, minibuffer_only);
4577 #else
4578 x_window (f);
4579 #endif
4580
4581 x_icon (f, parms);
4582 x_make_gc (f);
4583
4584 /* Now consider the frame official. */
4585 FRAME_X_DISPLAY_INFO (f)->reference_count++;
4586 Vframe_list = Fcons (frame, Vframe_list);
4587
4588 /* We need to do this after creating the X window, so that the
4589 icon-creation functions can say whose icon they're describing. */
4590 x_default_parameter (f, parms, Qicon_type, Qnil,
4591 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
4592
4593 x_default_parameter (f, parms, Qauto_raise, Qnil,
4594 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4595 x_default_parameter (f, parms, Qauto_lower, Qnil,
4596 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4597 x_default_parameter (f, parms, Qcursor_type, Qbox,
4598 "cursorType", "CursorType", RES_TYPE_SYMBOL);
4599 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4600 "scrollBarWidth", "ScrollBarWidth",
4601 RES_TYPE_NUMBER);
4602
4603 /* Dimensions, especially f->height, must be done via change_frame_size.
4604 Change will not be effected unless different from the current
4605 f->height. */
4606 width = f->width;
4607 height = f->height;
4608
4609 f->height = 0;
4610 SET_FRAME_WIDTH (f, 0);
4611 change_frame_size (f, height, width, 1, 0, 0);
4612
4613 /* Set up faces after all frame parameters are known. This call
4614 also merges in face attributes specified for new frames. If we
4615 don't do this, the `menu' face for instance won't have the right
4616 colors, and the menu bar won't appear in the specified colors for
4617 new frames. */
4618 call1 (Qface_set_after_frame_default, frame);
4619
4620 #ifdef USE_X_TOOLKIT
4621 /* Create the menu bar. */
4622 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4623 {
4624 /* If this signals an error, we haven't set size hints for the
4625 frame and we didn't make it visible. */
4626 initialize_frame_menubar (f);
4627
4628 /* This is a no-op, except under Motif where it arranges the
4629 main window for the widgets on it. */
4630 lw_set_main_areas (f->output_data.x->column_widget,
4631 f->output_data.x->menubar_widget,
4632 f->output_data.x->edit_widget);
4633 }
4634 #endif /* USE_X_TOOLKIT */
4635
4636 /* Tell the server what size and position, etc, we want, and how
4637 badly we want them. This should be done after we have the menu
4638 bar so that its size can be taken into account. */
4639 BLOCK_INPUT;
4640 x_wm_set_size_hint (f, window_prompting, 0);
4641 UNBLOCK_INPUT;
4642
4643 /* Make the window appear on the frame and enable display, unless
4644 the caller says not to. However, with explicit parent, Emacs
4645 cannot control visibility, so don't try. */
4646 if (! f->output_data.x->explicit_parent)
4647 {
4648 Lisp_Object visibility;
4649
4650 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
4651 RES_TYPE_SYMBOL);
4652 if (EQ (visibility, Qunbound))
4653 visibility = Qt;
4654
4655 if (EQ (visibility, Qicon))
4656 x_iconify_frame (f);
4657 else if (! NILP (visibility))
4658 x_make_frame_visible (f);
4659 else
4660 /* Must have been Qnil. */
4661 ;
4662 }
4663
4664 UNGCPRO;
4665
4666 /* Make sure windows on this frame appear in calls to next-window
4667 and similar functions. */
4668 Vwindow_list = Qnil;
4669
4670 return unbind_to (count, frame);
4671 }
4672
4673
4674 /* FRAME is used only to get a handle on the X display. We don't pass the
4675 display info directly because we're called from frame.c, which doesn't
4676 know about that structure. */
4677
4678 Lisp_Object
4679 x_get_focus_frame (frame)
4680 struct frame *frame;
4681 {
4682 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (frame);
4683 Lisp_Object xfocus;
4684 if (! dpyinfo->x_focus_frame)
4685 return Qnil;
4686
4687 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
4688 return xfocus;
4689 }
4690
4691
4692 /* In certain situations, when the window manager follows a
4693 click-to-focus policy, there seems to be no way around calling
4694 XSetInputFocus to give another frame the input focus .
4695
4696 In an ideal world, XSetInputFocus should generally be avoided so
4697 that applications don't interfere with the window manager's focus
4698 policy. But I think it's okay to use when it's clearly done
4699 following a user-command. */
4700
4701 DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
4702 doc: /* Set the input focus to FRAME.
4703 FRAME nil means use the selected frame. */)
4704 (frame)
4705 Lisp_Object frame;
4706 {
4707 struct frame *f = check_x_frame (frame);
4708 Display *dpy = FRAME_X_DISPLAY (f);
4709 int count;
4710
4711 BLOCK_INPUT;
4712 count = x_catch_errors (dpy);
4713 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4714 RevertToParent, CurrentTime);
4715 x_uncatch_errors (dpy, count);
4716 UNBLOCK_INPUT;
4717
4718 return Qnil;
4719 }
4720
4721 \f
4722 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
4723 doc: /* Internal function called by `color-defined-p', which see. */)
4724 (color, frame)
4725 Lisp_Object color, frame;
4726 {
4727 XColor foo;
4728 FRAME_PTR f = check_x_frame (frame);
4729
4730 CHECK_STRING (color);
4731
4732 if (x_defined_color (f, SDATA (color), &foo, 0))
4733 return Qt;
4734 else
4735 return Qnil;
4736 }
4737
4738 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
4739 doc: /* Internal function called by `color-values', which see. */)
4740 (color, frame)
4741 Lisp_Object color, frame;
4742 {
4743 XColor foo;
4744 FRAME_PTR f = check_x_frame (frame);
4745
4746 CHECK_STRING (color);
4747
4748 if (x_defined_color (f, SDATA (color), &foo, 0))
4749 {
4750 Lisp_Object rgb[3];
4751
4752 rgb[0] = make_number (foo.red);
4753 rgb[1] = make_number (foo.green);
4754 rgb[2] = make_number (foo.blue);
4755 return Flist (3, rgb);
4756 }
4757 else
4758 return Qnil;
4759 }
4760
4761 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
4762 doc: /* Internal function called by `display-color-p', which see. */)
4763 (display)
4764 Lisp_Object display;
4765 {
4766 struct x_display_info *dpyinfo = check_x_display_info (display);
4767
4768 if (dpyinfo->n_planes <= 2)
4769 return Qnil;
4770
4771 switch (dpyinfo->visual->class)
4772 {
4773 case StaticColor:
4774 case PseudoColor:
4775 case TrueColor:
4776 case DirectColor:
4777 return Qt;
4778
4779 default:
4780 return Qnil;
4781 }
4782 }
4783
4784 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
4785 0, 1, 0,
4786 doc: /* Return t if the X display supports shades of gray.
4787 Note that color displays do support shades of gray.
4788 The optional argument DISPLAY specifies which display to ask about.
4789 DISPLAY should be either a frame or a display name (a string).
4790 If omitted or nil, that stands for the selected frame's display. */)
4791 (display)
4792 Lisp_Object display;
4793 {
4794 struct x_display_info *dpyinfo = check_x_display_info (display);
4795
4796 if (dpyinfo->n_planes <= 1)
4797 return Qnil;
4798
4799 switch (dpyinfo->visual->class)
4800 {
4801 case StaticColor:
4802 case PseudoColor:
4803 case TrueColor:
4804 case DirectColor:
4805 case StaticGray:
4806 case GrayScale:
4807 return Qt;
4808
4809 default:
4810 return Qnil;
4811 }
4812 }
4813
4814 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
4815 0, 1, 0,
4816 doc: /* Returns the width in pixels of the X display DISPLAY.
4817 The optional argument DISPLAY specifies which display to ask about.
4818 DISPLAY should be either a frame or a display name (a string).
4819 If omitted or nil, that stands for the selected frame's display. */)
4820 (display)
4821 Lisp_Object display;
4822 {
4823 struct x_display_info *dpyinfo = check_x_display_info (display);
4824
4825 return make_number (dpyinfo->width);
4826 }
4827
4828 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
4829 Sx_display_pixel_height, 0, 1, 0,
4830 doc: /* Returns the height in pixels of the X display DISPLAY.
4831 The optional argument DISPLAY specifies which display to ask about.
4832 DISPLAY should be either a frame or a display name (a string).
4833 If omitted or nil, that stands for the selected frame's display. */)
4834 (display)
4835 Lisp_Object display;
4836 {
4837 struct x_display_info *dpyinfo = check_x_display_info (display);
4838
4839 return make_number (dpyinfo->height);
4840 }
4841
4842 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
4843 0, 1, 0,
4844 doc: /* Returns the number of bitplanes of the X display DISPLAY.
4845 The optional argument DISPLAY specifies which display to ask about.
4846 DISPLAY should be either a frame or a display name (a string).
4847 If omitted or nil, that stands for the selected frame's display. */)
4848 (display)
4849 Lisp_Object display;
4850 {
4851 struct x_display_info *dpyinfo = check_x_display_info (display);
4852
4853 return make_number (dpyinfo->n_planes);
4854 }
4855
4856 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
4857 0, 1, 0,
4858 doc: /* Returns the number of color cells of the X display DISPLAY.
4859 The optional argument DISPLAY specifies which display to ask about.
4860 DISPLAY should be either a frame or a display name (a string).
4861 If omitted or nil, that stands for the selected frame's display. */)
4862 (display)
4863 Lisp_Object display;
4864 {
4865 struct x_display_info *dpyinfo = check_x_display_info (display);
4866
4867 return make_number (DisplayCells (dpyinfo->display,
4868 XScreenNumberOfScreen (dpyinfo->screen)));
4869 }
4870
4871 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4872 Sx_server_max_request_size,
4873 0, 1, 0,
4874 doc: /* Returns the maximum request size of the X server of display DISPLAY.
4875 The optional argument DISPLAY specifies which display to ask about.
4876 DISPLAY should be either a frame or a display name (a string).
4877 If omitted or nil, that stands for the selected frame's display. */)
4878 (display)
4879 Lisp_Object display;
4880 {
4881 struct x_display_info *dpyinfo = check_x_display_info (display);
4882
4883 return make_number (MAXREQUEST (dpyinfo->display));
4884 }
4885
4886 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
4887 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
4888 The optional argument DISPLAY specifies which display to ask about.
4889 DISPLAY should be either a frame or a display name (a string).
4890 If omitted or nil, that stands for the selected frame's display. */)
4891 (display)
4892 Lisp_Object display;
4893 {
4894 struct x_display_info *dpyinfo = check_x_display_info (display);
4895 char *vendor = ServerVendor (dpyinfo->display);
4896
4897 if (! vendor) vendor = "";
4898 return build_string (vendor);
4899 }
4900
4901 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
4902 doc: /* Returns the version numbers of the X server of display DISPLAY.
4903 The value is a list of three integers: the major and minor
4904 version numbers of the X Protocol in use, and the vendor-specific release
4905 number. See also the function `x-server-vendor'.
4906
4907 The optional argument DISPLAY specifies which display to ask about.
4908 DISPLAY should be either a frame or a display name (a string).
4909 If omitted or nil, that stands for the selected frame's display. */)
4910 (display)
4911 Lisp_Object display;
4912 {
4913 struct x_display_info *dpyinfo = check_x_display_info (display);
4914 Display *dpy = dpyinfo->display;
4915
4916 return Fcons (make_number (ProtocolVersion (dpy)),
4917 Fcons (make_number (ProtocolRevision (dpy)),
4918 Fcons (make_number (VendorRelease (dpy)), Qnil)));
4919 }
4920
4921 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4922 doc: /* Return the number of screens on the X server of display DISPLAY.
4923 The optional argument DISPLAY specifies which display to ask about.
4924 DISPLAY should be either a frame or a display name (a string).
4925 If omitted or nil, that stands for the selected frame's display. */)
4926 (display)
4927 Lisp_Object display;
4928 {
4929 struct x_display_info *dpyinfo = check_x_display_info (display);
4930
4931 return make_number (ScreenCount (dpyinfo->display));
4932 }
4933
4934 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
4935 doc: /* Return the height in millimeters of the X display DISPLAY.
4936 The optional argument DISPLAY specifies which display to ask about.
4937 DISPLAY should be either a frame or a display name (a string).
4938 If omitted or nil, that stands for the selected frame's display. */)
4939 (display)
4940 Lisp_Object display;
4941 {
4942 struct x_display_info *dpyinfo = check_x_display_info (display);
4943
4944 return make_number (HeightMMOfScreen (dpyinfo->screen));
4945 }
4946
4947 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4948 doc: /* Return the width in millimeters of the X display DISPLAY.
4949 The optional argument DISPLAY specifies which display to ask about.
4950 DISPLAY should be either a frame or a display name (a string).
4951 If omitted or nil, that stands for the selected frame's display. */)
4952 (display)
4953 Lisp_Object display;
4954 {
4955 struct x_display_info *dpyinfo = check_x_display_info (display);
4956
4957 return make_number (WidthMMOfScreen (dpyinfo->screen));
4958 }
4959
4960 DEFUN ("x-display-backing-store", Fx_display_backing_store,
4961 Sx_display_backing_store, 0, 1, 0,
4962 doc: /* Returns an indication of whether X display DISPLAY does backing store.
4963 The value may be `always', `when-mapped', or `not-useful'.
4964 The optional argument DISPLAY specifies which display to ask about.
4965 DISPLAY should be either a frame or a display name (a string).
4966 If omitted or nil, that stands for the selected frame's display. */)
4967 (display)
4968 Lisp_Object display;
4969 {
4970 struct x_display_info *dpyinfo = check_x_display_info (display);
4971 Lisp_Object result;
4972
4973 switch (DoesBackingStore (dpyinfo->screen))
4974 {
4975 case Always:
4976 result = intern ("always");
4977 break;
4978
4979 case WhenMapped:
4980 result = intern ("when-mapped");
4981 break;
4982
4983 case NotUseful:
4984 result = intern ("not-useful");
4985 break;
4986
4987 default:
4988 error ("Strange value for BackingStore parameter of screen");
4989 result = Qnil;
4990 }
4991
4992 return result;
4993 }
4994
4995 DEFUN ("x-display-visual-class", Fx_display_visual_class,
4996 Sx_display_visual_class, 0, 1, 0,
4997 doc: /* Return the visual class of the X display DISPLAY.
4998 The value is one of the symbols `static-gray', `gray-scale',
4999 `static-color', `pseudo-color', `true-color', or `direct-color'.
5000
5001 The optional argument DISPLAY specifies which display to ask about.
5002 DISPLAY should be either a frame or a display name (a string).
5003 If omitted or nil, that stands for the selected frame's display. */)
5004 (display)
5005 Lisp_Object display;
5006 {
5007 struct x_display_info *dpyinfo = check_x_display_info (display);
5008 Lisp_Object result;
5009
5010 switch (dpyinfo->visual->class)
5011 {
5012 case StaticGray:
5013 result = intern ("static-gray");
5014 break;
5015 case GrayScale:
5016 result = intern ("gray-scale");
5017 break;
5018 case StaticColor:
5019 result = intern ("static-color");
5020 break;
5021 case PseudoColor:
5022 result = intern ("pseudo-color");
5023 break;
5024 case TrueColor:
5025 result = intern ("true-color");
5026 break;
5027 case DirectColor:
5028 result = intern ("direct-color");
5029 break;
5030 default:
5031 error ("Display has an unknown visual class");
5032 result = Qnil;
5033 }
5034
5035 return result;
5036 }
5037
5038 DEFUN ("x-display-save-under", Fx_display_save_under,
5039 Sx_display_save_under, 0, 1, 0,
5040 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
5041 The optional argument DISPLAY specifies which display to ask about.
5042 DISPLAY should be either a frame or a display name (a string).
5043 If omitted or nil, that stands for the selected frame's display. */)
5044 (display)
5045 Lisp_Object display;
5046 {
5047 struct x_display_info *dpyinfo = check_x_display_info (display);
5048
5049 if (DoesSaveUnders (dpyinfo->screen) == True)
5050 return Qt;
5051 else
5052 return Qnil;
5053 }
5054 \f
5055 int
5056 x_pixel_width (f)
5057 register struct frame *f;
5058 {
5059 return PIXEL_WIDTH (f);
5060 }
5061
5062 int
5063 x_pixel_height (f)
5064 register struct frame *f;
5065 {
5066 return PIXEL_HEIGHT (f);
5067 }
5068
5069 int
5070 x_char_width (f)
5071 register struct frame *f;
5072 {
5073 return FONT_WIDTH (f->output_data.x->font);
5074 }
5075
5076 int
5077 x_char_height (f)
5078 register struct frame *f;
5079 {
5080 return f->output_data.x->line_height;
5081 }
5082
5083 int
5084 x_screen_planes (f)
5085 register struct frame *f;
5086 {
5087 return FRAME_X_DISPLAY_INFO (f)->n_planes;
5088 }
5089
5090
5091 \f
5092 /************************************************************************
5093 X Displays
5094 ************************************************************************/
5095
5096 \f
5097 /* Mapping visual names to visuals. */
5098
5099 static struct visual_class
5100 {
5101 char *name;
5102 int class;
5103 }
5104 visual_classes[] =
5105 {
5106 {"StaticGray", StaticGray},
5107 {"GrayScale", GrayScale},
5108 {"StaticColor", StaticColor},
5109 {"PseudoColor", PseudoColor},
5110 {"TrueColor", TrueColor},
5111 {"DirectColor", DirectColor},
5112 {NULL, 0}
5113 };
5114
5115
5116 #ifndef HAVE_XSCREENNUMBEROFSCREEN
5117
5118 /* Value is the screen number of screen SCR. This is a substitute for
5119 the X function with the same name when that doesn't exist. */
5120
5121 int
5122 XScreenNumberOfScreen (scr)
5123 register Screen *scr;
5124 {
5125 Display *dpy = scr->display;
5126 int i;
5127
5128 for (i = 0; i < dpy->nscreens; ++i)
5129 if (scr == dpy->screens + i)
5130 break;
5131
5132 return i;
5133 }
5134
5135 #endif /* not HAVE_XSCREENNUMBEROFSCREEN */
5136
5137
5138 /* Select the visual that should be used on display DPYINFO. Set
5139 members of DPYINFO appropriately. Called from x_term_init. */
5140
5141 void
5142 select_visual (dpyinfo)
5143 struct x_display_info *dpyinfo;
5144 {
5145 Display *dpy = dpyinfo->display;
5146 Screen *screen = dpyinfo->screen;
5147 Lisp_Object value;
5148
5149 /* See if a visual is specified. */
5150 value = display_x_get_resource (dpyinfo,
5151 build_string ("visualClass"),
5152 build_string ("VisualClass"),
5153 Qnil, Qnil);
5154 if (STRINGP (value))
5155 {
5156 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
5157 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
5158 depth, a decimal number. NAME is compared with case ignored. */
5159 char *s = (char *) alloca (SBYTES (value) + 1);
5160 char *dash;
5161 int i, class = -1;
5162 XVisualInfo vinfo;
5163
5164 strcpy (s, SDATA (value));
5165 dash = index (s, '-');
5166 if (dash)
5167 {
5168 dpyinfo->n_planes = atoi (dash + 1);
5169 *dash = '\0';
5170 }
5171 else
5172 /* We won't find a matching visual with depth 0, so that
5173 an error will be printed below. */
5174 dpyinfo->n_planes = 0;
5175
5176 /* Determine the visual class. */
5177 for (i = 0; visual_classes[i].name; ++i)
5178 if (xstricmp (s, visual_classes[i].name) == 0)
5179 {
5180 class = visual_classes[i].class;
5181 break;
5182 }
5183
5184 /* Look up a matching visual for the specified class. */
5185 if (class == -1
5186 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
5187 dpyinfo->n_planes, class, &vinfo))
5188 fatal ("Invalid visual specification `%s'", SDATA (value));
5189
5190 dpyinfo->visual = vinfo.visual;
5191 }
5192 else
5193 {
5194 int n_visuals;
5195 XVisualInfo *vinfo, vinfo_template;
5196
5197 dpyinfo->visual = DefaultVisualOfScreen (screen);
5198
5199 #ifdef HAVE_X11R4
5200 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
5201 #else
5202 vinfo_template.visualid = dpyinfo->visual->visualid;
5203 #endif
5204 vinfo_template.screen = XScreenNumberOfScreen (screen);
5205 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
5206 &vinfo_template, &n_visuals);
5207 if (n_visuals != 1)
5208 fatal ("Can't get proper X visual info");
5209
5210 dpyinfo->n_planes = vinfo->depth;
5211 XFree ((char *) vinfo);
5212 }
5213 }
5214
5215
5216 /* Return the X display structure for the display named NAME.
5217 Open a new connection if necessary. */
5218
5219 struct x_display_info *
5220 x_display_info_for_name (name)
5221 Lisp_Object name;
5222 {
5223 Lisp_Object names;
5224 struct x_display_info *dpyinfo;
5225
5226 CHECK_STRING (name);
5227
5228 if (! EQ (Vwindow_system, intern ("x")))
5229 error ("Not using X Windows");
5230
5231 for (dpyinfo = x_display_list, names = x_display_name_list;
5232 dpyinfo;
5233 dpyinfo = dpyinfo->next, names = XCDR (names))
5234 {
5235 Lisp_Object tem;
5236 tem = Fstring_equal (XCAR (XCAR (names)), name);
5237 if (!NILP (tem))
5238 return dpyinfo;
5239 }
5240
5241 /* Use this general default value to start with. */
5242 Vx_resource_name = Vinvocation_name;
5243
5244 validate_x_resource_name ();
5245
5246 dpyinfo = x_term_init (name, (char *)0,
5247 (char *) SDATA (Vx_resource_name));
5248
5249 if (dpyinfo == 0)
5250 error ("Cannot connect to X server %s", SDATA (name));
5251
5252 x_in_use = 1;
5253 XSETFASTINT (Vwindow_system_version, 11);
5254
5255 return dpyinfo;
5256 }
5257
5258
5259 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
5260 1, 3, 0,
5261 doc: /* Open a connection to an X server.
5262 DISPLAY is the name of the display to connect to.
5263 Optional second arg XRM-STRING is a string of resources in xrdb format.
5264 If the optional third arg MUST-SUCCEED is non-nil,
5265 terminate Emacs if we can't open the connection. */)
5266 (display, xrm_string, must_succeed)
5267 Lisp_Object display, xrm_string, must_succeed;
5268 {
5269 unsigned char *xrm_option;
5270 struct x_display_info *dpyinfo;
5271
5272 CHECK_STRING (display);
5273 if (! NILP (xrm_string))
5274 CHECK_STRING (xrm_string);
5275
5276 if (! EQ (Vwindow_system, intern ("x")))
5277 error ("Not using X Windows");
5278
5279 if (! NILP (xrm_string))
5280 xrm_option = (unsigned char *) SDATA (xrm_string);
5281 else
5282 xrm_option = (unsigned char *) 0;
5283
5284 validate_x_resource_name ();
5285
5286 /* This is what opens the connection and sets x_current_display.
5287 This also initializes many symbols, such as those used for input. */
5288 dpyinfo = x_term_init (display, xrm_option,
5289 (char *) SDATA (Vx_resource_name));
5290
5291 if (dpyinfo == 0)
5292 {
5293 if (!NILP (must_succeed))
5294 fatal ("Cannot connect to X server %s.\n\
5295 Check the DISPLAY environment variable or use `-d'.\n\
5296 Also use the `xauth' program to verify that you have the proper\n\
5297 authorization information needed to connect the X server.\n\
5298 An insecure way to solve the problem may be to use `xhost'.\n",
5299 SDATA (display));
5300 else
5301 error ("Cannot connect to X server %s", SDATA (display));
5302 }
5303
5304 x_in_use = 1;
5305
5306 XSETFASTINT (Vwindow_system_version, 11);
5307 return Qnil;
5308 }
5309
5310 DEFUN ("x-close-connection", Fx_close_connection,
5311 Sx_close_connection, 1, 1, 0,
5312 doc: /* Close the connection to DISPLAY's X server.
5313 For DISPLAY, specify either a frame or a display name (a string).
5314 If DISPLAY is nil, that stands for the selected frame's display. */)
5315 (display)
5316 Lisp_Object display;
5317 {
5318 struct x_display_info *dpyinfo = check_x_display_info (display);
5319 int i;
5320
5321 if (dpyinfo->reference_count > 0)
5322 error ("Display still has frames on it");
5323
5324 BLOCK_INPUT;
5325 /* Free the fonts in the font table. */
5326 for (i = 0; i < dpyinfo->n_fonts; i++)
5327 if (dpyinfo->font_table[i].name)
5328 {
5329 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
5330 xfree (dpyinfo->font_table[i].full_name);
5331 xfree (dpyinfo->font_table[i].name);
5332 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
5333 }
5334
5335 x_destroy_all_bitmaps (dpyinfo);
5336 XSetCloseDownMode (dpyinfo->display, DestroyAll);
5337
5338 #ifdef USE_X_TOOLKIT
5339 XtCloseDisplay (dpyinfo->display);
5340 #else
5341 XCloseDisplay (dpyinfo->display);
5342 #endif
5343
5344 x_delete_display (dpyinfo);
5345 UNBLOCK_INPUT;
5346
5347 return Qnil;
5348 }
5349
5350 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
5351 doc: /* Return the list of display names that Emacs has connections to. */)
5352 ()
5353 {
5354 Lisp_Object tail, result;
5355
5356 result = Qnil;
5357 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
5358 result = Fcons (XCAR (XCAR (tail)), result);
5359
5360 return result;
5361 }
5362
5363 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
5364 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
5365 If ON is nil, allow buffering of requests.
5366 Turning on synchronization prohibits the Xlib routines from buffering
5367 requests and seriously degrades performance, but makes debugging much
5368 easier.
5369 The optional second argument DISPLAY specifies which display to act on.
5370 DISPLAY should be either a frame or a display name (a string).
5371 If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
5372 (on, display)
5373 Lisp_Object display, on;
5374 {
5375 struct x_display_info *dpyinfo = check_x_display_info (display);
5376
5377 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
5378
5379 return Qnil;
5380 }
5381
5382 /* Wait for responses to all X commands issued so far for frame F. */
5383
5384 void
5385 x_sync (f)
5386 FRAME_PTR f;
5387 {
5388 BLOCK_INPUT;
5389 XSync (FRAME_X_DISPLAY (f), False);
5390 UNBLOCK_INPUT;
5391 }
5392
5393 \f
5394 /***********************************************************************
5395 Image types
5396 ***********************************************************************/
5397
5398 /* Value is the number of elements of vector VECTOR. */
5399
5400 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
5401
5402 /* List of supported image types. Use define_image_type to add new
5403 types. Use lookup_image_type to find a type for a given symbol. */
5404
5405 static struct image_type *image_types;
5406
5407 /* The symbol `image' which is the car of the lists used to represent
5408 images in Lisp. */
5409
5410 extern Lisp_Object Qimage;
5411
5412 /* The symbol `xbm' which is used as the type symbol for XBM images. */
5413
5414 Lisp_Object Qxbm;
5415
5416 /* Keywords. */
5417
5418 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
5419 extern Lisp_Object QCdata, QCtype;
5420 Lisp_Object QCascent, QCmargin, QCrelief;
5421 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
5422 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
5423
5424 /* Other symbols. */
5425
5426 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
5427
5428 /* Time in seconds after which images should be removed from the cache
5429 if not displayed. */
5430
5431 Lisp_Object Vimage_cache_eviction_delay;
5432
5433 /* Function prototypes. */
5434
5435 static void define_image_type P_ ((struct image_type *type));
5436 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5437 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5438 static void x_laplace P_ ((struct frame *, struct image *));
5439 static void x_emboss P_ ((struct frame *, struct image *));
5440 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5441 Lisp_Object));
5442
5443
5444 /* Define a new image type from TYPE. This adds a copy of TYPE to
5445 image_types and adds the symbol *TYPE->type to Vimage_types. */
5446
5447 static void
5448 define_image_type (type)
5449 struct image_type *type;
5450 {
5451 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5452 The initialized data segment is read-only. */
5453 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5454 bcopy (type, p, sizeof *p);
5455 p->next = image_types;
5456 image_types = p;
5457 Vimage_types = Fcons (*p->type, Vimage_types);
5458 }
5459
5460
5461 /* Look up image type SYMBOL, and return a pointer to its image_type
5462 structure. Value is null if SYMBOL is not a known image type. */
5463
5464 static INLINE struct image_type *
5465 lookup_image_type (symbol)
5466 Lisp_Object symbol;
5467 {
5468 struct image_type *type;
5469
5470 for (type = image_types; type; type = type->next)
5471 if (EQ (symbol, *type->type))
5472 break;
5473
5474 return type;
5475 }
5476
5477
5478 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
5479 valid image specification is a list whose car is the symbol
5480 `image', and whose rest is a property list. The property list must
5481 contain a value for key `:type'. That value must be the name of a
5482 supported image type. The rest of the property list depends on the
5483 image type. */
5484
5485 int
5486 valid_image_p (object)
5487 Lisp_Object object;
5488 {
5489 int valid_p = 0;
5490
5491 if (CONSP (object) && EQ (XCAR (object), Qimage))
5492 {
5493 Lisp_Object tem;
5494
5495 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
5496 if (EQ (XCAR (tem), QCtype))
5497 {
5498 tem = XCDR (tem);
5499 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
5500 {
5501 struct image_type *type;
5502 type = lookup_image_type (XCAR (tem));
5503 if (type)
5504 valid_p = type->valid_p (object);
5505 }
5506
5507 break;
5508 }
5509 }
5510
5511 return valid_p;
5512 }
5513
5514
5515 /* Log error message with format string FORMAT and argument ARG.
5516 Signaling an error, e.g. when an image cannot be loaded, is not a
5517 good idea because this would interrupt redisplay, and the error
5518 message display would lead to another redisplay. This function
5519 therefore simply displays a message. */
5520
5521 static void
5522 image_error (format, arg1, arg2)
5523 char *format;
5524 Lisp_Object arg1, arg2;
5525 {
5526 add_to_log (format, arg1, arg2);
5527 }
5528
5529
5530 \f
5531 /***********************************************************************
5532 Image specifications
5533 ***********************************************************************/
5534
5535 enum image_value_type
5536 {
5537 IMAGE_DONT_CHECK_VALUE_TYPE,
5538 IMAGE_STRING_VALUE,
5539 IMAGE_STRING_OR_NIL_VALUE,
5540 IMAGE_SYMBOL_VALUE,
5541 IMAGE_POSITIVE_INTEGER_VALUE,
5542 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
5543 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
5544 IMAGE_ASCENT_VALUE,
5545 IMAGE_INTEGER_VALUE,
5546 IMAGE_FUNCTION_VALUE,
5547 IMAGE_NUMBER_VALUE,
5548 IMAGE_BOOL_VALUE
5549 };
5550
5551 /* Structure used when parsing image specifications. */
5552
5553 struct image_keyword
5554 {
5555 /* Name of keyword. */
5556 char *name;
5557
5558 /* The type of value allowed. */
5559 enum image_value_type type;
5560
5561 /* Non-zero means key must be present. */
5562 int mandatory_p;
5563
5564 /* Used to recognize duplicate keywords in a property list. */
5565 int count;
5566
5567 /* The value that was found. */
5568 Lisp_Object value;
5569 };
5570
5571
5572 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5573 int, Lisp_Object));
5574 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5575
5576
5577 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
5578 has the format (image KEYWORD VALUE ...). One of the keyword/
5579 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5580 image_keywords structures of size NKEYWORDS describing other
5581 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
5582
5583 static int
5584 parse_image_spec (spec, keywords, nkeywords, type)
5585 Lisp_Object spec;
5586 struct image_keyword *keywords;
5587 int nkeywords;
5588 Lisp_Object type;
5589 {
5590 int i;
5591 Lisp_Object plist;
5592
5593 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5594 return 0;
5595
5596 plist = XCDR (spec);
5597 while (CONSP (plist))
5598 {
5599 Lisp_Object key, value;
5600
5601 /* First element of a pair must be a symbol. */
5602 key = XCAR (plist);
5603 plist = XCDR (plist);
5604 if (!SYMBOLP (key))
5605 return 0;
5606
5607 /* There must follow a value. */
5608 if (!CONSP (plist))
5609 return 0;
5610 value = XCAR (plist);
5611 plist = XCDR (plist);
5612
5613 /* Find key in KEYWORDS. Error if not found. */
5614 for (i = 0; i < nkeywords; ++i)
5615 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
5616 break;
5617
5618 if (i == nkeywords)
5619 continue;
5620
5621 /* Record that we recognized the keyword. If a keywords
5622 was found more than once, it's an error. */
5623 keywords[i].value = value;
5624 ++keywords[i].count;
5625
5626 if (keywords[i].count > 1)
5627 return 0;
5628
5629 /* Check type of value against allowed type. */
5630 switch (keywords[i].type)
5631 {
5632 case IMAGE_STRING_VALUE:
5633 if (!STRINGP (value))
5634 return 0;
5635 break;
5636
5637 case IMAGE_STRING_OR_NIL_VALUE:
5638 if (!STRINGP (value) && !NILP (value))
5639 return 0;
5640 break;
5641
5642 case IMAGE_SYMBOL_VALUE:
5643 if (!SYMBOLP (value))
5644 return 0;
5645 break;
5646
5647 case IMAGE_POSITIVE_INTEGER_VALUE:
5648 if (!INTEGERP (value) || XINT (value) <= 0)
5649 return 0;
5650 break;
5651
5652 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
5653 if (INTEGERP (value) && XINT (value) >= 0)
5654 break;
5655 if (CONSP (value)
5656 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
5657 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
5658 break;
5659 return 0;
5660
5661 case IMAGE_ASCENT_VALUE:
5662 if (SYMBOLP (value) && EQ (value, Qcenter))
5663 break;
5664 else if (INTEGERP (value)
5665 && XINT (value) >= 0
5666 && XINT (value) <= 100)
5667 break;
5668 return 0;
5669
5670 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5671 if (!INTEGERP (value) || XINT (value) < 0)
5672 return 0;
5673 break;
5674
5675 case IMAGE_DONT_CHECK_VALUE_TYPE:
5676 break;
5677
5678 case IMAGE_FUNCTION_VALUE:
5679 value = indirect_function (value);
5680 if (SUBRP (value)
5681 || COMPILEDP (value)
5682 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5683 break;
5684 return 0;
5685
5686 case IMAGE_NUMBER_VALUE:
5687 if (!INTEGERP (value) && !FLOATP (value))
5688 return 0;
5689 break;
5690
5691 case IMAGE_INTEGER_VALUE:
5692 if (!INTEGERP (value))
5693 return 0;
5694 break;
5695
5696 case IMAGE_BOOL_VALUE:
5697 if (!NILP (value) && !EQ (value, Qt))
5698 return 0;
5699 break;
5700
5701 default:
5702 abort ();
5703 break;
5704 }
5705
5706 if (EQ (key, QCtype) && !EQ (type, value))
5707 return 0;
5708 }
5709
5710 /* Check that all mandatory fields are present. */
5711 for (i = 0; i < nkeywords; ++i)
5712 if (keywords[i].mandatory_p && keywords[i].count == 0)
5713 return 0;
5714
5715 return NILP (plist);
5716 }
5717
5718
5719 /* Return the value of KEY in image specification SPEC. Value is nil
5720 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5721 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5722
5723 static Lisp_Object
5724 image_spec_value (spec, key, found)
5725 Lisp_Object spec, key;
5726 int *found;
5727 {
5728 Lisp_Object tail;
5729
5730 xassert (valid_image_p (spec));
5731
5732 for (tail = XCDR (spec);
5733 CONSP (tail) && CONSP (XCDR (tail));
5734 tail = XCDR (XCDR (tail)))
5735 {
5736 if (EQ (XCAR (tail), key))
5737 {
5738 if (found)
5739 *found = 1;
5740 return XCAR (XCDR (tail));
5741 }
5742 }
5743
5744 if (found)
5745 *found = 0;
5746 return Qnil;
5747 }
5748
5749
5750 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
5751 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
5752 PIXELS non-nil means return the size in pixels, otherwise return the
5753 size in canonical character units.
5754 FRAME is the frame on which the image will be displayed. FRAME nil
5755 or omitted means use the selected frame. */)
5756 (spec, pixels, frame)
5757 Lisp_Object spec, pixels, frame;
5758 {
5759 Lisp_Object size;
5760
5761 size = Qnil;
5762 if (valid_image_p (spec))
5763 {
5764 struct frame *f = check_x_frame (frame);
5765 int id = lookup_image (f, spec);
5766 struct image *img = IMAGE_FROM_ID (f, id);
5767 int width = img->width + 2 * img->hmargin;
5768 int height = img->height + 2 * img->vmargin;
5769
5770 if (NILP (pixels))
5771 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
5772 make_float ((double) height / CANON_Y_UNIT (f)));
5773 else
5774 size = Fcons (make_number (width), make_number (height));
5775 }
5776 else
5777 error ("Invalid image specification");
5778
5779 return size;
5780 }
5781
5782
5783 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
5784 doc: /* Return t if image SPEC has a mask bitmap.
5785 FRAME is the frame on which the image will be displayed. FRAME nil
5786 or omitted means use the selected frame. */)
5787 (spec, frame)
5788 Lisp_Object spec, frame;
5789 {
5790 Lisp_Object mask;
5791
5792 mask = Qnil;
5793 if (valid_image_p (spec))
5794 {
5795 struct frame *f = check_x_frame (frame);
5796 int id = lookup_image (f, spec);
5797 struct image *img = IMAGE_FROM_ID (f, id);
5798 if (img->mask)
5799 mask = Qt;
5800 }
5801 else
5802 error ("Invalid image specification");
5803
5804 return mask;
5805 }
5806
5807
5808 \f
5809 /***********************************************************************
5810 Image type independent image structures
5811 ***********************************************************************/
5812
5813 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5814 static void free_image P_ ((struct frame *f, struct image *img));
5815
5816
5817 /* Allocate and return a new image structure for image specification
5818 SPEC. SPEC has a hash value of HASH. */
5819
5820 static struct image *
5821 make_image (spec, hash)
5822 Lisp_Object spec;
5823 unsigned hash;
5824 {
5825 struct image *img = (struct image *) xmalloc (sizeof *img);
5826
5827 xassert (valid_image_p (spec));
5828 bzero (img, sizeof *img);
5829 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5830 xassert (img->type != NULL);
5831 img->spec = spec;
5832 img->data.lisp_val = Qnil;
5833 img->ascent = DEFAULT_IMAGE_ASCENT;
5834 img->hash = hash;
5835 return img;
5836 }
5837
5838
5839 /* Free image IMG which was used on frame F, including its resources. */
5840
5841 static void
5842 free_image (f, img)
5843 struct frame *f;
5844 struct image *img;
5845 {
5846 if (img)
5847 {
5848 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5849
5850 /* Remove IMG from the hash table of its cache. */
5851 if (img->prev)
5852 img->prev->next = img->next;
5853 else
5854 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5855
5856 if (img->next)
5857 img->next->prev = img->prev;
5858
5859 c->images[img->id] = NULL;
5860
5861 /* Free resources, then free IMG. */
5862 img->type->free (f, img);
5863 xfree (img);
5864 }
5865 }
5866
5867
5868 /* Prepare image IMG for display on frame F. Must be called before
5869 drawing an image. */
5870
5871 void
5872 prepare_image_for_display (f, img)
5873 struct frame *f;
5874 struct image *img;
5875 {
5876 EMACS_TIME t;
5877
5878 /* We're about to display IMG, so set its timestamp to `now'. */
5879 EMACS_GET_TIME (t);
5880 img->timestamp = EMACS_SECS (t);
5881
5882 /* If IMG doesn't have a pixmap yet, load it now, using the image
5883 type dependent loader function. */
5884 if (img->pixmap == None && !img->load_failed_p)
5885 img->load_failed_p = img->type->load (f, img) == 0;
5886 }
5887
5888
5889 /* Value is the number of pixels for the ascent of image IMG when
5890 drawn in face FACE. */
5891
5892 int
5893 image_ascent (img, face)
5894 struct image *img;
5895 struct face *face;
5896 {
5897 int height = img->height + img->vmargin;
5898 int ascent;
5899
5900 if (img->ascent == CENTERED_IMAGE_ASCENT)
5901 {
5902 if (face->font)
5903 /* This expression is arranged so that if the image can't be
5904 exactly centered, it will be moved slightly up. This is
5905 because a typical font is `top-heavy' (due to the presence
5906 uppercase letters), so the image placement should err towards
5907 being top-heavy too. It also just generally looks better. */
5908 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
5909 else
5910 ascent = height / 2;
5911 }
5912 else
5913 ascent = height * img->ascent / 100.0;
5914
5915 return ascent;
5916 }
5917
5918 \f
5919 /* Image background colors. */
5920
5921 static unsigned long
5922 four_corners_best (ximg, width, height)
5923 XImage *ximg;
5924 unsigned long width, height;
5925 {
5926 unsigned long corners[4], best;
5927 int i, best_count;
5928
5929 /* Get the colors at the corners of ximg. */
5930 corners[0] = XGetPixel (ximg, 0, 0);
5931 corners[1] = XGetPixel (ximg, width - 1, 0);
5932 corners[2] = XGetPixel (ximg, width - 1, height - 1);
5933 corners[3] = XGetPixel (ximg, 0, height - 1);
5934
5935 /* Choose the most frequently found color as background. */
5936 for (i = best_count = 0; i < 4; ++i)
5937 {
5938 int j, n;
5939
5940 for (j = n = 0; j < 4; ++j)
5941 if (corners[i] == corners[j])
5942 ++n;
5943
5944 if (n > best_count)
5945 best = corners[i], best_count = n;
5946 }
5947
5948 return best;
5949 }
5950
5951 /* Return the `background' field of IMG. If IMG doesn't have one yet,
5952 it is guessed heuristically. If non-zero, XIMG is an existing XImage
5953 object to use for the heuristic. */
5954
5955 unsigned long
5956 image_background (img, f, ximg)
5957 struct image *img;
5958 struct frame *f;
5959 XImage *ximg;
5960 {
5961 if (! img->background_valid)
5962 /* IMG doesn't have a background yet, try to guess a reasonable value. */
5963 {
5964 int free_ximg = !ximg;
5965
5966 if (! ximg)
5967 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
5968 0, 0, img->width, img->height, ~0, ZPixmap);
5969
5970 img->background = four_corners_best (ximg, img->width, img->height);
5971
5972 if (free_ximg)
5973 XDestroyImage (ximg);
5974
5975 img->background_valid = 1;
5976 }
5977
5978 return img->background;
5979 }
5980
5981 /* Return the `background_transparent' field of IMG. If IMG doesn't
5982 have one yet, it is guessed heuristically. If non-zero, MASK is an
5983 existing XImage object to use for the heuristic. */
5984
5985 int
5986 image_background_transparent (img, f, mask)
5987 struct image *img;
5988 struct frame *f;
5989 XImage *mask;
5990 {
5991 if (! img->background_transparent_valid)
5992 /* IMG doesn't have a background yet, try to guess a reasonable value. */
5993 {
5994 if (img->mask)
5995 {
5996 int free_mask = !mask;
5997
5998 if (! mask)
5999 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
6000 0, 0, img->width, img->height, ~0, ZPixmap);
6001
6002 img->background_transparent
6003 = !four_corners_best (mask, img->width, img->height);
6004
6005 if (free_mask)
6006 XDestroyImage (mask);
6007 }
6008 else
6009 img->background_transparent = 0;
6010
6011 img->background_transparent_valid = 1;
6012 }
6013
6014 return img->background_transparent;
6015 }
6016
6017 \f
6018 /***********************************************************************
6019 Helper functions for X image types
6020 ***********************************************************************/
6021
6022 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
6023 int, int));
6024 static void x_clear_image P_ ((struct frame *f, struct image *img));
6025 static unsigned long x_alloc_image_color P_ ((struct frame *f,
6026 struct image *img,
6027 Lisp_Object color_name,
6028 unsigned long dflt));
6029
6030
6031 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
6032 free the pixmap if any. MASK_P non-zero means clear the mask
6033 pixmap if any. COLORS_P non-zero means free colors allocated for
6034 the image, if any. */
6035
6036 static void
6037 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
6038 struct frame *f;
6039 struct image *img;
6040 int pixmap_p, mask_p, colors_p;
6041 {
6042 if (pixmap_p && img->pixmap)
6043 {
6044 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
6045 img->pixmap = None;
6046 img->background_valid = 0;
6047 }
6048
6049 if (mask_p && img->mask)
6050 {
6051 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6052 img->mask = None;
6053 img->background_transparent_valid = 0;
6054 }
6055
6056 if (colors_p && img->ncolors)
6057 {
6058 x_free_colors (f, img->colors, img->ncolors);
6059 xfree (img->colors);
6060 img->colors = NULL;
6061 img->ncolors = 0;
6062 }
6063 }
6064
6065 /* Free X resources of image IMG which is used on frame F. */
6066
6067 static void
6068 x_clear_image (f, img)
6069 struct frame *f;
6070 struct image *img;
6071 {
6072 BLOCK_INPUT;
6073 x_clear_image_1 (f, img, 1, 1, 1);
6074 UNBLOCK_INPUT;
6075 }
6076
6077
6078 /* Allocate color COLOR_NAME for image IMG on frame F. If color
6079 cannot be allocated, use DFLT. Add a newly allocated color to
6080 IMG->colors, so that it can be freed again. Value is the pixel
6081 color. */
6082
6083 static unsigned long
6084 x_alloc_image_color (f, img, color_name, dflt)
6085 struct frame *f;
6086 struct image *img;
6087 Lisp_Object color_name;
6088 unsigned long dflt;
6089 {
6090 XColor color;
6091 unsigned long result;
6092
6093 xassert (STRINGP (color_name));
6094
6095 if (x_defined_color (f, SDATA (color_name), &color, 1))
6096 {
6097 /* This isn't called frequently so we get away with simply
6098 reallocating the color vector to the needed size, here. */
6099 ++img->ncolors;
6100 img->colors =
6101 (unsigned long *) xrealloc (img->colors,
6102 img->ncolors * sizeof *img->colors);
6103 img->colors[img->ncolors - 1] = color.pixel;
6104 result = color.pixel;
6105 }
6106 else
6107 result = dflt;
6108
6109 return result;
6110 }
6111
6112
6113 \f
6114 /***********************************************************************
6115 Image Cache
6116 ***********************************************************************/
6117
6118 static void cache_image P_ ((struct frame *f, struct image *img));
6119 static void postprocess_image P_ ((struct frame *, struct image *));
6120
6121
6122 /* Return a new, initialized image cache that is allocated from the
6123 heap. Call free_image_cache to free an image cache. */
6124
6125 struct image_cache *
6126 make_image_cache ()
6127 {
6128 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
6129 int size;
6130
6131 bzero (c, sizeof *c);
6132 c->size = 50;
6133 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
6134 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
6135 c->buckets = (struct image **) xmalloc (size);
6136 bzero (c->buckets, size);
6137 return c;
6138 }
6139
6140
6141 /* Free image cache of frame F. Be aware that X frames share images
6142 caches. */
6143
6144 void
6145 free_image_cache (f)
6146 struct frame *f;
6147 {
6148 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6149 if (c)
6150 {
6151 int i;
6152
6153 /* Cache should not be referenced by any frame when freed. */
6154 xassert (c->refcount == 0);
6155
6156 for (i = 0; i < c->used; ++i)
6157 free_image (f, c->images[i]);
6158 xfree (c->images);
6159 xfree (c->buckets);
6160 xfree (c);
6161 FRAME_X_IMAGE_CACHE (f) = NULL;
6162 }
6163 }
6164
6165
6166 /* Clear image cache of frame F. FORCE_P non-zero means free all
6167 images. FORCE_P zero means clear only images that haven't been
6168 displayed for some time. Should be called from time to time to
6169 reduce the number of loaded images. If image-eviction-seconds is
6170 non-nil, this frees images in the cache which weren't displayed for
6171 at least that many seconds. */
6172
6173 void
6174 clear_image_cache (f, force_p)
6175 struct frame *f;
6176 int force_p;
6177 {
6178 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6179
6180 if (c && INTEGERP (Vimage_cache_eviction_delay))
6181 {
6182 EMACS_TIME t;
6183 unsigned long old;
6184 int i, nfreed;
6185
6186 EMACS_GET_TIME (t);
6187 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
6188
6189 /* Block input so that we won't be interrupted by a SIGIO
6190 while being in an inconsistent state. */
6191 BLOCK_INPUT;
6192
6193 for (i = nfreed = 0; i < c->used; ++i)
6194 {
6195 struct image *img = c->images[i];
6196 if (img != NULL
6197 && (force_p || img->timestamp < old))
6198 {
6199 free_image (f, img);
6200 ++nfreed;
6201 }
6202 }
6203
6204 /* We may be clearing the image cache because, for example,
6205 Emacs was iconified for a longer period of time. In that
6206 case, current matrices may still contain references to
6207 images freed above. So, clear these matrices. */
6208 if (nfreed)
6209 {
6210 Lisp_Object tail, frame;
6211
6212 FOR_EACH_FRAME (tail, frame)
6213 {
6214 struct frame *f = XFRAME (frame);
6215 if (FRAME_X_P (f)
6216 && FRAME_X_IMAGE_CACHE (f) == c)
6217 clear_current_matrices (f);
6218 }
6219
6220 ++windows_or_buffers_changed;
6221 }
6222
6223 UNBLOCK_INPUT;
6224 }
6225 }
6226
6227
6228 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6229 0, 1, 0,
6230 doc: /* Clear the image cache of FRAME.
6231 FRAME nil or omitted means use the selected frame.
6232 FRAME t means clear the image caches of all frames. */)
6233 (frame)
6234 Lisp_Object frame;
6235 {
6236 if (EQ (frame, Qt))
6237 {
6238 Lisp_Object tail;
6239
6240 FOR_EACH_FRAME (tail, frame)
6241 if (FRAME_X_P (XFRAME (frame)))
6242 clear_image_cache (XFRAME (frame), 1);
6243 }
6244 else
6245 clear_image_cache (check_x_frame (frame), 1);
6246
6247 return Qnil;
6248 }
6249
6250
6251 /* Compute masks and transform image IMG on frame F, as specified
6252 by the image's specification, */
6253
6254 static void
6255 postprocess_image (f, img)
6256 struct frame *f;
6257 struct image *img;
6258 {
6259 /* Manipulation of the image's mask. */
6260 if (img->pixmap)
6261 {
6262 Lisp_Object conversion, spec;
6263 Lisp_Object mask;
6264
6265 spec = img->spec;
6266
6267 /* `:heuristic-mask t'
6268 `:mask heuristic'
6269 means build a mask heuristically.
6270 `:heuristic-mask (R G B)'
6271 `:mask (heuristic (R G B))'
6272 means build a mask from color (R G B) in the
6273 image.
6274 `:mask nil'
6275 means remove a mask, if any. */
6276
6277 mask = image_spec_value (spec, QCheuristic_mask, NULL);
6278 if (!NILP (mask))
6279 x_build_heuristic_mask (f, img, mask);
6280 else
6281 {
6282 int found_p;
6283
6284 mask = image_spec_value (spec, QCmask, &found_p);
6285
6286 if (EQ (mask, Qheuristic))
6287 x_build_heuristic_mask (f, img, Qt);
6288 else if (CONSP (mask)
6289 && EQ (XCAR (mask), Qheuristic))
6290 {
6291 if (CONSP (XCDR (mask)))
6292 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
6293 else
6294 x_build_heuristic_mask (f, img, XCDR (mask));
6295 }
6296 else if (NILP (mask) && found_p && img->mask)
6297 {
6298 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6299 img->mask = None;
6300 }
6301 }
6302
6303
6304 /* Should we apply an image transformation algorithm? */
6305 conversion = image_spec_value (spec, QCconversion, NULL);
6306 if (EQ (conversion, Qdisabled))
6307 x_disable_image (f, img);
6308 else if (EQ (conversion, Qlaplace))
6309 x_laplace (f, img);
6310 else if (EQ (conversion, Qemboss))
6311 x_emboss (f, img);
6312 else if (CONSP (conversion)
6313 && EQ (XCAR (conversion), Qedge_detection))
6314 {
6315 Lisp_Object tem;
6316 tem = XCDR (conversion);
6317 if (CONSP (tem))
6318 x_edge_detection (f, img,
6319 Fplist_get (tem, QCmatrix),
6320 Fplist_get (tem, QCcolor_adjustment));
6321 }
6322 }
6323 }
6324
6325
6326 /* Return the id of image with Lisp specification SPEC on frame F.
6327 SPEC must be a valid Lisp image specification (see valid_image_p). */
6328
6329 int
6330 lookup_image (f, spec)
6331 struct frame *f;
6332 Lisp_Object spec;
6333 {
6334 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6335 struct image *img;
6336 int i;
6337 unsigned hash;
6338 struct gcpro gcpro1;
6339 EMACS_TIME now;
6340
6341 /* F must be a window-system frame, and SPEC must be a valid image
6342 specification. */
6343 xassert (FRAME_WINDOW_P (f));
6344 xassert (valid_image_p (spec));
6345
6346 GCPRO1 (spec);
6347
6348 /* Look up SPEC in the hash table of the image cache. */
6349 hash = sxhash (spec, 0);
6350 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6351
6352 for (img = c->buckets[i]; img; img = img->next)
6353 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6354 break;
6355
6356 /* If not found, create a new image and cache it. */
6357 if (img == NULL)
6358 {
6359 extern Lisp_Object Qpostscript;
6360
6361 BLOCK_INPUT;
6362 img = make_image (spec, hash);
6363 cache_image (f, img);
6364 img->load_failed_p = img->type->load (f, img) == 0;
6365
6366 /* If we can't load the image, and we don't have a width and
6367 height, use some arbitrary width and height so that we can
6368 draw a rectangle for it. */
6369 if (img->load_failed_p)
6370 {
6371 Lisp_Object value;
6372
6373 value = image_spec_value (spec, QCwidth, NULL);
6374 img->width = (INTEGERP (value)
6375 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6376 value = image_spec_value (spec, QCheight, NULL);
6377 img->height = (INTEGERP (value)
6378 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6379 }
6380 else
6381 {
6382 /* Handle image type independent image attributes
6383 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
6384 `:background COLOR'. */
6385 Lisp_Object ascent, margin, relief, bg;
6386
6387 ascent = image_spec_value (spec, QCascent, NULL);
6388 if (INTEGERP (ascent))
6389 img->ascent = XFASTINT (ascent);
6390 else if (EQ (ascent, Qcenter))
6391 img->ascent = CENTERED_IMAGE_ASCENT;
6392
6393 margin = image_spec_value (spec, QCmargin, NULL);
6394 if (INTEGERP (margin) && XINT (margin) >= 0)
6395 img->vmargin = img->hmargin = XFASTINT (margin);
6396 else if (CONSP (margin) && INTEGERP (XCAR (margin))
6397 && INTEGERP (XCDR (margin)))
6398 {
6399 if (XINT (XCAR (margin)) > 0)
6400 img->hmargin = XFASTINT (XCAR (margin));
6401 if (XINT (XCDR (margin)) > 0)
6402 img->vmargin = XFASTINT (XCDR (margin));
6403 }
6404
6405 relief = image_spec_value (spec, QCrelief, NULL);
6406 if (INTEGERP (relief))
6407 {
6408 img->relief = XINT (relief);
6409 img->hmargin += abs (img->relief);
6410 img->vmargin += abs (img->relief);
6411 }
6412
6413 if (! img->background_valid)
6414 {
6415 bg = image_spec_value (img->spec, QCbackground, NULL);
6416 if (!NILP (bg))
6417 {
6418 img->background
6419 = x_alloc_image_color (f, img, bg,
6420 FRAME_BACKGROUND_PIXEL (f));
6421 img->background_valid = 1;
6422 }
6423 }
6424
6425 /* Do image transformations and compute masks, unless we
6426 don't have the image yet. */
6427 if (!EQ (*img->type->type, Qpostscript))
6428 postprocess_image (f, img);
6429 }
6430
6431 UNBLOCK_INPUT;
6432 xassert (!interrupt_input_blocked);
6433 }
6434
6435 /* We're using IMG, so set its timestamp to `now'. */
6436 EMACS_GET_TIME (now);
6437 img->timestamp = EMACS_SECS (now);
6438
6439 UNGCPRO;
6440
6441 /* Value is the image id. */
6442 return img->id;
6443 }
6444
6445
6446 /* Cache image IMG in the image cache of frame F. */
6447
6448 static void
6449 cache_image (f, img)
6450 struct frame *f;
6451 struct image *img;
6452 {
6453 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6454 int i;
6455
6456 /* Find a free slot in c->images. */
6457 for (i = 0; i < c->used; ++i)
6458 if (c->images[i] == NULL)
6459 break;
6460
6461 /* If no free slot found, maybe enlarge c->images. */
6462 if (i == c->used && c->used == c->size)
6463 {
6464 c->size *= 2;
6465 c->images = (struct image **) xrealloc (c->images,
6466 c->size * sizeof *c->images);
6467 }
6468
6469 /* Add IMG to c->images, and assign IMG an id. */
6470 c->images[i] = img;
6471 img->id = i;
6472 if (i == c->used)
6473 ++c->used;
6474
6475 /* Add IMG to the cache's hash table. */
6476 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6477 img->next = c->buckets[i];
6478 if (img->next)
6479 img->next->prev = img;
6480 img->prev = NULL;
6481 c->buckets[i] = img;
6482 }
6483
6484
6485 /* Call FN on every image in the image cache of frame F. Used to mark
6486 Lisp Objects in the image cache. */
6487
6488 void
6489 forall_images_in_image_cache (f, fn)
6490 struct frame *f;
6491 void (*fn) P_ ((struct image *img));
6492 {
6493 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6494 {
6495 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6496 if (c)
6497 {
6498 int i;
6499 for (i = 0; i < c->used; ++i)
6500 if (c->images[i])
6501 fn (c->images[i]);
6502 }
6503 }
6504 }
6505
6506
6507 \f
6508 /***********************************************************************
6509 X support code
6510 ***********************************************************************/
6511
6512 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6513 XImage **, Pixmap *));
6514 static void x_destroy_x_image P_ ((XImage *));
6515 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6516
6517
6518 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6519 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6520 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6521 via xmalloc. Print error messages via image_error if an error
6522 occurs. Value is non-zero if successful. */
6523
6524 static int
6525 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
6526 struct frame *f;
6527 int width, height, depth;
6528 XImage **ximg;
6529 Pixmap *pixmap;
6530 {
6531 Display *display = FRAME_X_DISPLAY (f);
6532 Screen *screen = FRAME_X_SCREEN (f);
6533 Window window = FRAME_X_WINDOW (f);
6534
6535 xassert (interrupt_input_blocked);
6536
6537 if (depth <= 0)
6538 depth = DefaultDepthOfScreen (screen);
6539 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6540 depth, ZPixmap, 0, NULL, width, height,
6541 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6542 if (*ximg == NULL)
6543 {
6544 image_error ("Unable to allocate X image", Qnil, Qnil);
6545 return 0;
6546 }
6547
6548 /* Allocate image raster. */
6549 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6550
6551 /* Allocate a pixmap of the same size. */
6552 *pixmap = XCreatePixmap (display, window, width, height, depth);
6553 if (*pixmap == None)
6554 {
6555 x_destroy_x_image (*ximg);
6556 *ximg = NULL;
6557 image_error ("Unable to create X pixmap", Qnil, Qnil);
6558 return 0;
6559 }
6560
6561 return 1;
6562 }
6563
6564
6565 /* Destroy XImage XIMG. Free XIMG->data. */
6566
6567 static void
6568 x_destroy_x_image (ximg)
6569 XImage *ximg;
6570 {
6571 xassert (interrupt_input_blocked);
6572 if (ximg)
6573 {
6574 xfree (ximg->data);
6575 ximg->data = NULL;
6576 XDestroyImage (ximg);
6577 }
6578 }
6579
6580
6581 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6582 are width and height of both the image and pixmap. */
6583
6584 static void
6585 x_put_x_image (f, ximg, pixmap, width, height)
6586 struct frame *f;
6587 XImage *ximg;
6588 Pixmap pixmap;
6589 {
6590 GC gc;
6591
6592 xassert (interrupt_input_blocked);
6593 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6594 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6595 XFreeGC (FRAME_X_DISPLAY (f), gc);
6596 }
6597
6598
6599 \f
6600 /***********************************************************************
6601 File Handling
6602 ***********************************************************************/
6603
6604 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
6605 static char *slurp_file P_ ((char *, int *));
6606
6607
6608 /* Find image file FILE. Look in data-directory, then
6609 x-bitmap-file-path. Value is the full name of the file found, or
6610 nil if not found. */
6611
6612 static Lisp_Object
6613 x_find_image_file (file)
6614 Lisp_Object file;
6615 {
6616 Lisp_Object file_found, search_path;
6617 struct gcpro gcpro1, gcpro2;
6618 int fd;
6619
6620 file_found = Qnil;
6621 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6622 GCPRO2 (file_found, search_path);
6623
6624 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
6625 fd = openp (search_path, file, Qnil, &file_found, Qnil);
6626
6627 if (fd == -1)
6628 file_found = Qnil;
6629 else
6630 close (fd);
6631
6632 UNGCPRO;
6633 return file_found;
6634 }
6635
6636
6637 /* Read FILE into memory. Value is a pointer to a buffer allocated
6638 with xmalloc holding FILE's contents. Value is null if an error
6639 occurred. *SIZE is set to the size of the file. */
6640
6641 static char *
6642 slurp_file (file, size)
6643 char *file;
6644 int *size;
6645 {
6646 FILE *fp = NULL;
6647 char *buf = NULL;
6648 struct stat st;
6649
6650 if (stat (file, &st) == 0
6651 && (fp = fopen (file, "r")) != NULL
6652 && (buf = (char *) xmalloc (st.st_size),
6653 fread (buf, 1, st.st_size, fp) == st.st_size))
6654 {
6655 *size = st.st_size;
6656 fclose (fp);
6657 }
6658 else
6659 {
6660 if (fp)
6661 fclose (fp);
6662 if (buf)
6663 {
6664 xfree (buf);
6665 buf = NULL;
6666 }
6667 }
6668
6669 return buf;
6670 }
6671
6672
6673 \f
6674 /***********************************************************************
6675 XBM images
6676 ***********************************************************************/
6677
6678 static int xbm_scan P_ ((char **, char *, char *, int *));
6679 static int xbm_load P_ ((struct frame *f, struct image *img));
6680 static int xbm_load_image P_ ((struct frame *f, struct image *img,
6681 char *, char *));
6682 static int xbm_image_p P_ ((Lisp_Object object));
6683 static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
6684 unsigned char **));
6685 static int xbm_file_p P_ ((Lisp_Object));
6686
6687
6688 /* Indices of image specification fields in xbm_format, below. */
6689
6690 enum xbm_keyword_index
6691 {
6692 XBM_TYPE,
6693 XBM_FILE,
6694 XBM_WIDTH,
6695 XBM_HEIGHT,
6696 XBM_DATA,
6697 XBM_FOREGROUND,
6698 XBM_BACKGROUND,
6699 XBM_ASCENT,
6700 XBM_MARGIN,
6701 XBM_RELIEF,
6702 XBM_ALGORITHM,
6703 XBM_HEURISTIC_MASK,
6704 XBM_MASK,
6705 XBM_LAST
6706 };
6707
6708 /* Vector of image_keyword structures describing the format
6709 of valid XBM image specifications. */
6710
6711 static struct image_keyword xbm_format[XBM_LAST] =
6712 {
6713 {":type", IMAGE_SYMBOL_VALUE, 1},
6714 {":file", IMAGE_STRING_VALUE, 0},
6715 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6716 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6717 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6718 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6719 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6720 {":ascent", IMAGE_ASCENT_VALUE, 0},
6721 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6722 {":relief", IMAGE_INTEGER_VALUE, 0},
6723 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6724 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6725 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6726 };
6727
6728 /* Structure describing the image type XBM. */
6729
6730 static struct image_type xbm_type =
6731 {
6732 &Qxbm,
6733 xbm_image_p,
6734 xbm_load,
6735 x_clear_image,
6736 NULL
6737 };
6738
6739 /* Tokens returned from xbm_scan. */
6740
6741 enum xbm_token
6742 {
6743 XBM_TK_IDENT = 256,
6744 XBM_TK_NUMBER
6745 };
6746
6747
6748 /* Return non-zero if OBJECT is a valid XBM-type image specification.
6749 A valid specification is a list starting with the symbol `image'
6750 The rest of the list is a property list which must contain an
6751 entry `:type xbm..
6752
6753 If the specification specifies a file to load, it must contain
6754 an entry `:file FILENAME' where FILENAME is a string.
6755
6756 If the specification is for a bitmap loaded from memory it must
6757 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6758 WIDTH and HEIGHT are integers > 0. DATA may be:
6759
6760 1. a string large enough to hold the bitmap data, i.e. it must
6761 have a size >= (WIDTH + 7) / 8 * HEIGHT
6762
6763 2. a bool-vector of size >= WIDTH * HEIGHT
6764
6765 3. a vector of strings or bool-vectors, one for each line of the
6766 bitmap.
6767
6768 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
6769 may not be specified in this case because they are defined in the
6770 XBM file.
6771
6772 Both the file and data forms may contain the additional entries
6773 `:background COLOR' and `:foreground COLOR'. If not present,
6774 foreground and background of the frame on which the image is
6775 displayed is used. */
6776
6777 static int
6778 xbm_image_p (object)
6779 Lisp_Object object;
6780 {
6781 struct image_keyword kw[XBM_LAST];
6782
6783 bcopy (xbm_format, kw, sizeof kw);
6784 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
6785 return 0;
6786
6787 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6788
6789 if (kw[XBM_FILE].count)
6790 {
6791 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6792 return 0;
6793 }
6794 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
6795 {
6796 /* In-memory XBM file. */
6797 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
6798 return 0;
6799 }
6800 else
6801 {
6802 Lisp_Object data;
6803 int width, height;
6804
6805 /* Entries for `:width', `:height' and `:data' must be present. */
6806 if (!kw[XBM_WIDTH].count
6807 || !kw[XBM_HEIGHT].count
6808 || !kw[XBM_DATA].count)
6809 return 0;
6810
6811 data = kw[XBM_DATA].value;
6812 width = XFASTINT (kw[XBM_WIDTH].value);
6813 height = XFASTINT (kw[XBM_HEIGHT].value);
6814
6815 /* Check type of data, and width and height against contents of
6816 data. */
6817 if (VECTORP (data))
6818 {
6819 int i;
6820
6821 /* Number of elements of the vector must be >= height. */
6822 if (XVECTOR (data)->size < height)
6823 return 0;
6824
6825 /* Each string or bool-vector in data must be large enough
6826 for one line of the image. */
6827 for (i = 0; i < height; ++i)
6828 {
6829 Lisp_Object elt = XVECTOR (data)->contents[i];
6830
6831 if (STRINGP (elt))
6832 {
6833 if (SCHARS (elt)
6834 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6835 return 0;
6836 }
6837 else if (BOOL_VECTOR_P (elt))
6838 {
6839 if (XBOOL_VECTOR (elt)->size < width)
6840 return 0;
6841 }
6842 else
6843 return 0;
6844 }
6845 }
6846 else if (STRINGP (data))
6847 {
6848 if (SCHARS (data)
6849 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6850 return 0;
6851 }
6852 else if (BOOL_VECTOR_P (data))
6853 {
6854 if (XBOOL_VECTOR (data)->size < width * height)
6855 return 0;
6856 }
6857 else
6858 return 0;
6859 }
6860
6861 return 1;
6862 }
6863
6864
6865 /* Scan a bitmap file. FP is the stream to read from. Value is
6866 either an enumerator from enum xbm_token, or a character for a
6867 single-character token, or 0 at end of file. If scanning an
6868 identifier, store the lexeme of the identifier in SVAL. If
6869 scanning a number, store its value in *IVAL. */
6870
6871 static int
6872 xbm_scan (s, end, sval, ival)
6873 char **s, *end;
6874 char *sval;
6875 int *ival;
6876 {
6877 int c;
6878
6879 loop:
6880
6881 /* Skip white space. */
6882 while (*s < end && (c = *(*s)++, isspace (c)))
6883 ;
6884
6885 if (*s >= end)
6886 c = 0;
6887 else if (isdigit (c))
6888 {
6889 int value = 0, digit;
6890
6891 if (c == '0' && *s < end)
6892 {
6893 c = *(*s)++;
6894 if (c == 'x' || c == 'X')
6895 {
6896 while (*s < end)
6897 {
6898 c = *(*s)++;
6899 if (isdigit (c))
6900 digit = c - '0';
6901 else if (c >= 'a' && c <= 'f')
6902 digit = c - 'a' + 10;
6903 else if (c >= 'A' && c <= 'F')
6904 digit = c - 'A' + 10;
6905 else
6906 break;
6907 value = 16 * value + digit;
6908 }
6909 }
6910 else if (isdigit (c))
6911 {
6912 value = c - '0';
6913 while (*s < end
6914 && (c = *(*s)++, isdigit (c)))
6915 value = 8 * value + c - '0';
6916 }
6917 }
6918 else
6919 {
6920 value = c - '0';
6921 while (*s < end
6922 && (c = *(*s)++, isdigit (c)))
6923 value = 10 * value + c - '0';
6924 }
6925
6926 if (*s < end)
6927 *s = *s - 1;
6928 *ival = value;
6929 c = XBM_TK_NUMBER;
6930 }
6931 else if (isalpha (c) || c == '_')
6932 {
6933 *sval++ = c;
6934 while (*s < end
6935 && (c = *(*s)++, (isalnum (c) || c == '_')))
6936 *sval++ = c;
6937 *sval = 0;
6938 if (*s < end)
6939 *s = *s - 1;
6940 c = XBM_TK_IDENT;
6941 }
6942 else if (c == '/' && **s == '*')
6943 {
6944 /* C-style comment. */
6945 ++*s;
6946 while (**s && (**s != '*' || *(*s + 1) != '/'))
6947 ++*s;
6948 if (**s)
6949 {
6950 *s += 2;
6951 goto loop;
6952 }
6953 }
6954
6955 return c;
6956 }
6957
6958
6959 /* Replacement for XReadBitmapFileData which isn't available under old
6960 X versions. CONTENTS is a pointer to a buffer to parse; END is the
6961 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
6962 the image. Return in *DATA the bitmap data allocated with xmalloc.
6963 Value is non-zero if successful. DATA null means just test if
6964 CONTENTS looks like an in-memory XBM file. */
6965
6966 static int
6967 xbm_read_bitmap_data (contents, end, width, height, data)
6968 char *contents, *end;
6969 int *width, *height;
6970 unsigned char **data;
6971 {
6972 char *s = contents;
6973 char buffer[BUFSIZ];
6974 int padding_p = 0;
6975 int v10 = 0;
6976 int bytes_per_line, i, nbytes;
6977 unsigned char *p;
6978 int value;
6979 int LA1;
6980
6981 #define match() \
6982 LA1 = xbm_scan (&s, end, buffer, &value)
6983
6984 #define expect(TOKEN) \
6985 if (LA1 != (TOKEN)) \
6986 goto failure; \
6987 else \
6988 match ()
6989
6990 #define expect_ident(IDENT) \
6991 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
6992 match (); \
6993 else \
6994 goto failure
6995
6996 *width = *height = -1;
6997 if (data)
6998 *data = NULL;
6999 LA1 = xbm_scan (&s, end, buffer, &value);
7000
7001 /* Parse defines for width, height and hot-spots. */
7002 while (LA1 == '#')
7003 {
7004 match ();
7005 expect_ident ("define");
7006 expect (XBM_TK_IDENT);
7007
7008 if (LA1 == XBM_TK_NUMBER);
7009 {
7010 char *p = strrchr (buffer, '_');
7011 p = p ? p + 1 : buffer;
7012 if (strcmp (p, "width") == 0)
7013 *width = value;
7014 else if (strcmp (p, "height") == 0)
7015 *height = value;
7016 }
7017 expect (XBM_TK_NUMBER);
7018 }
7019
7020 if (*width < 0 || *height < 0)
7021 goto failure;
7022 else if (data == NULL)
7023 goto success;
7024
7025 /* Parse bits. Must start with `static'. */
7026 expect_ident ("static");
7027 if (LA1 == XBM_TK_IDENT)
7028 {
7029 if (strcmp (buffer, "unsigned") == 0)
7030 {
7031 match ();
7032 expect_ident ("char");
7033 }
7034 else if (strcmp (buffer, "short") == 0)
7035 {
7036 match ();
7037 v10 = 1;
7038 if (*width % 16 && *width % 16 < 9)
7039 padding_p = 1;
7040 }
7041 else if (strcmp (buffer, "char") == 0)
7042 match ();
7043 else
7044 goto failure;
7045 }
7046 else
7047 goto failure;
7048
7049 expect (XBM_TK_IDENT);
7050 expect ('[');
7051 expect (']');
7052 expect ('=');
7053 expect ('{');
7054
7055 bytes_per_line = (*width + 7) / 8 + padding_p;
7056 nbytes = bytes_per_line * *height;
7057 p = *data = (char *) xmalloc (nbytes);
7058
7059 if (v10)
7060 {
7061 for (i = 0; i < nbytes; i += 2)
7062 {
7063 int val = value;
7064 expect (XBM_TK_NUMBER);
7065
7066 *p++ = val;
7067 if (!padding_p || ((i + 2) % bytes_per_line))
7068 *p++ = value >> 8;
7069
7070 if (LA1 == ',' || LA1 == '}')
7071 match ();
7072 else
7073 goto failure;
7074 }
7075 }
7076 else
7077 {
7078 for (i = 0; i < nbytes; ++i)
7079 {
7080 int val = value;
7081 expect (XBM_TK_NUMBER);
7082
7083 *p++ = val;
7084
7085 if (LA1 == ',' || LA1 == '}')
7086 match ();
7087 else
7088 goto failure;
7089 }
7090 }
7091
7092 success:
7093 return 1;
7094
7095 failure:
7096
7097 if (data && *data)
7098 {
7099 xfree (*data);
7100 *data = NULL;
7101 }
7102 return 0;
7103
7104 #undef match
7105 #undef expect
7106 #undef expect_ident
7107 }
7108
7109
7110 /* Load XBM image IMG which will be displayed on frame F from buffer
7111 CONTENTS. END is the end of the buffer. Value is non-zero if
7112 successful. */
7113
7114 static int
7115 xbm_load_image (f, img, contents, end)
7116 struct frame *f;
7117 struct image *img;
7118 char *contents, *end;
7119 {
7120 int rc;
7121 unsigned char *data;
7122 int success_p = 0;
7123
7124 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
7125 if (rc)
7126 {
7127 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7128 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7129 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7130 Lisp_Object value;
7131
7132 xassert (img->width > 0 && img->height > 0);
7133
7134 /* Get foreground and background colors, maybe allocate colors. */
7135 value = image_spec_value (img->spec, QCforeground, NULL);
7136 if (!NILP (value))
7137 foreground = x_alloc_image_color (f, img, value, foreground);
7138 value = image_spec_value (img->spec, QCbackground, NULL);
7139 if (!NILP (value))
7140 {
7141 background = x_alloc_image_color (f, img, value, background);
7142 img->background = background;
7143 img->background_valid = 1;
7144 }
7145
7146 img->pixmap
7147 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7148 FRAME_X_WINDOW (f),
7149 data,
7150 img->width, img->height,
7151 foreground, background,
7152 depth);
7153 xfree (data);
7154
7155 if (img->pixmap == None)
7156 {
7157 x_clear_image (f, img);
7158 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
7159 }
7160 else
7161 success_p = 1;
7162 }
7163 else
7164 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7165
7166 return success_p;
7167 }
7168
7169
7170 /* Value is non-zero if DATA looks like an in-memory XBM file. */
7171
7172 static int
7173 xbm_file_p (data)
7174 Lisp_Object data;
7175 {
7176 int w, h;
7177 return (STRINGP (data)
7178 && xbm_read_bitmap_data (SDATA (data),
7179 (SDATA (data)
7180 + SBYTES (data)),
7181 &w, &h, NULL));
7182 }
7183
7184
7185 /* Fill image IMG which is used on frame F with pixmap data. Value is
7186 non-zero if successful. */
7187
7188 static int
7189 xbm_load (f, img)
7190 struct frame *f;
7191 struct image *img;
7192 {
7193 int success_p = 0;
7194 Lisp_Object file_name;
7195
7196 xassert (xbm_image_p (img->spec));
7197
7198 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7199 file_name = image_spec_value (img->spec, QCfile, NULL);
7200 if (STRINGP (file_name))
7201 {
7202 Lisp_Object file;
7203 char *contents;
7204 int size;
7205 struct gcpro gcpro1;
7206
7207 file = x_find_image_file (file_name);
7208 GCPRO1 (file);
7209 if (!STRINGP (file))
7210 {
7211 image_error ("Cannot find image file `%s'", file_name, Qnil);
7212 UNGCPRO;
7213 return 0;
7214 }
7215
7216 contents = slurp_file (SDATA (file), &size);
7217 if (contents == NULL)
7218 {
7219 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7220 UNGCPRO;
7221 return 0;
7222 }
7223
7224 success_p = xbm_load_image (f, img, contents, contents + size);
7225 UNGCPRO;
7226 }
7227 else
7228 {
7229 struct image_keyword fmt[XBM_LAST];
7230 Lisp_Object data;
7231 int depth;
7232 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7233 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7234 char *bits;
7235 int parsed_p;
7236 int in_memory_file_p = 0;
7237
7238 /* See if data looks like an in-memory XBM file. */
7239 data = image_spec_value (img->spec, QCdata, NULL);
7240 in_memory_file_p = xbm_file_p (data);
7241
7242 /* Parse the image specification. */
7243 bcopy (xbm_format, fmt, sizeof fmt);
7244 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
7245 xassert (parsed_p);
7246
7247 /* Get specified width, and height. */
7248 if (!in_memory_file_p)
7249 {
7250 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7251 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7252 xassert (img->width > 0 && img->height > 0);
7253 }
7254
7255 /* Get foreground and background colors, maybe allocate colors. */
7256 if (fmt[XBM_FOREGROUND].count
7257 && STRINGP (fmt[XBM_FOREGROUND].value))
7258 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7259 foreground);
7260 if (fmt[XBM_BACKGROUND].count
7261 && STRINGP (fmt[XBM_BACKGROUND].value))
7262 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7263 background);
7264
7265 if (in_memory_file_p)
7266 success_p = xbm_load_image (f, img, SDATA (data),
7267 (SDATA (data)
7268 + SBYTES (data)));
7269 else
7270 {
7271 if (VECTORP (data))
7272 {
7273 int i;
7274 char *p;
7275 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
7276
7277 p = bits = (char *) alloca (nbytes * img->height);
7278 for (i = 0; i < img->height; ++i, p += nbytes)
7279 {
7280 Lisp_Object line = XVECTOR (data)->contents[i];
7281 if (STRINGP (line))
7282 bcopy (SDATA (line), p, nbytes);
7283 else
7284 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7285 }
7286 }
7287 else if (STRINGP (data))
7288 bits = SDATA (data);
7289 else
7290 bits = XBOOL_VECTOR (data)->data;
7291
7292 /* Create the pixmap. */
7293 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7294 img->pixmap
7295 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7296 FRAME_X_WINDOW (f),
7297 bits,
7298 img->width, img->height,
7299 foreground, background,
7300 depth);
7301 if (img->pixmap)
7302 success_p = 1;
7303 else
7304 {
7305 image_error ("Unable to create pixmap for XBM image `%s'",
7306 img->spec, Qnil);
7307 x_clear_image (f, img);
7308 }
7309 }
7310 }
7311
7312 return success_p;
7313 }
7314
7315
7316 \f
7317 /***********************************************************************
7318 XPM images
7319 ***********************************************************************/
7320
7321 #if HAVE_XPM
7322
7323 static int xpm_image_p P_ ((Lisp_Object object));
7324 static int xpm_load P_ ((struct frame *f, struct image *img));
7325 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7326
7327 #include "X11/xpm.h"
7328
7329 /* The symbol `xpm' identifying XPM-format images. */
7330
7331 Lisp_Object Qxpm;
7332
7333 /* Indices of image specification fields in xpm_format, below. */
7334
7335 enum xpm_keyword_index
7336 {
7337 XPM_TYPE,
7338 XPM_FILE,
7339 XPM_DATA,
7340 XPM_ASCENT,
7341 XPM_MARGIN,
7342 XPM_RELIEF,
7343 XPM_ALGORITHM,
7344 XPM_HEURISTIC_MASK,
7345 XPM_MASK,
7346 XPM_COLOR_SYMBOLS,
7347 XPM_BACKGROUND,
7348 XPM_LAST
7349 };
7350
7351 /* Vector of image_keyword structures describing the format
7352 of valid XPM image specifications. */
7353
7354 static struct image_keyword xpm_format[XPM_LAST] =
7355 {
7356 {":type", IMAGE_SYMBOL_VALUE, 1},
7357 {":file", IMAGE_STRING_VALUE, 0},
7358 {":data", IMAGE_STRING_VALUE, 0},
7359 {":ascent", IMAGE_ASCENT_VALUE, 0},
7360 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7361 {":relief", IMAGE_INTEGER_VALUE, 0},
7362 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7363 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7364 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7365 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7366 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7367 };
7368
7369 /* Structure describing the image type XBM. */
7370
7371 static struct image_type xpm_type =
7372 {
7373 &Qxpm,
7374 xpm_image_p,
7375 xpm_load,
7376 x_clear_image,
7377 NULL
7378 };
7379
7380
7381 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
7382 functions for allocating image colors. Our own functions handle
7383 color allocation failures more gracefully than the ones on the XPM
7384 lib. */
7385
7386 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
7387 #define ALLOC_XPM_COLORS
7388 #endif
7389
7390 #ifdef ALLOC_XPM_COLORS
7391
7392 static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
7393 static void xpm_free_color_cache P_ ((void));
7394 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
7395 static int xpm_color_bucket P_ ((char *));
7396 static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
7397 XColor *, int));
7398
7399 /* An entry in a hash table used to cache color definitions of named
7400 colors. This cache is necessary to speed up XPM image loading in
7401 case we do color allocations ourselves. Without it, we would need
7402 a call to XParseColor per pixel in the image. */
7403
7404 struct xpm_cached_color
7405 {
7406 /* Next in collision chain. */
7407 struct xpm_cached_color *next;
7408
7409 /* Color definition (RGB and pixel color). */
7410 XColor color;
7411
7412 /* Color name. */
7413 char name[1];
7414 };
7415
7416 /* The hash table used for the color cache, and its bucket vector
7417 size. */
7418
7419 #define XPM_COLOR_CACHE_BUCKETS 1001
7420 struct xpm_cached_color **xpm_color_cache;
7421
7422 /* Initialize the color cache. */
7423
7424 static void
7425 xpm_init_color_cache (f, attrs)
7426 struct frame *f;
7427 XpmAttributes *attrs;
7428 {
7429 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
7430 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
7431 memset (xpm_color_cache, 0, nbytes);
7432 init_color_table ();
7433
7434 if (attrs->valuemask & XpmColorSymbols)
7435 {
7436 int i;
7437 XColor color;
7438
7439 for (i = 0; i < attrs->numsymbols; ++i)
7440 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7441 attrs->colorsymbols[i].value, &color))
7442 {
7443 color.pixel = lookup_rgb_color (f, color.red, color.green,
7444 color.blue);
7445 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
7446 }
7447 }
7448 }
7449
7450
7451 /* Free the color cache. */
7452
7453 static void
7454 xpm_free_color_cache ()
7455 {
7456 struct xpm_cached_color *p, *next;
7457 int i;
7458
7459 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
7460 for (p = xpm_color_cache[i]; p; p = next)
7461 {
7462 next = p->next;
7463 xfree (p);
7464 }
7465
7466 xfree (xpm_color_cache);
7467 xpm_color_cache = NULL;
7468 free_color_table ();
7469 }
7470
7471
7472 /* Return the bucket index for color named COLOR_NAME in the color
7473 cache. */
7474
7475 static int
7476 xpm_color_bucket (color_name)
7477 char *color_name;
7478 {
7479 unsigned h = 0;
7480 char *s;
7481
7482 for (s = color_name; *s; ++s)
7483 h = (h << 2) ^ *s;
7484 return h %= XPM_COLOR_CACHE_BUCKETS;
7485 }
7486
7487
7488 /* On frame F, cache values COLOR for color with name COLOR_NAME.
7489 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
7490 entry added. */
7491
7492 static struct xpm_cached_color *
7493 xpm_cache_color (f, color_name, color, bucket)
7494 struct frame *f;
7495 char *color_name;
7496 XColor *color;
7497 int bucket;
7498 {
7499 size_t nbytes;
7500 struct xpm_cached_color *p;
7501
7502 if (bucket < 0)
7503 bucket = xpm_color_bucket (color_name);
7504
7505 nbytes = sizeof *p + strlen (color_name);
7506 p = (struct xpm_cached_color *) xmalloc (nbytes);
7507 strcpy (p->name, color_name);
7508 p->color = *color;
7509 p->next = xpm_color_cache[bucket];
7510 xpm_color_cache[bucket] = p;
7511 return p;
7512 }
7513
7514
7515 /* Look up color COLOR_NAME for frame F in the color cache. If found,
7516 return the cached definition in *COLOR. Otherwise, make a new
7517 entry in the cache and allocate the color. Value is zero if color
7518 allocation failed. */
7519
7520 static int
7521 xpm_lookup_color (f, color_name, color)
7522 struct frame *f;
7523 char *color_name;
7524 XColor *color;
7525 {
7526 struct xpm_cached_color *p;
7527 int h = xpm_color_bucket (color_name);
7528
7529 for (p = xpm_color_cache[h]; p; p = p->next)
7530 if (strcmp (p->name, color_name) == 0)
7531 break;
7532
7533 if (p != NULL)
7534 *color = p->color;
7535 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7536 color_name, color))
7537 {
7538 color->pixel = lookup_rgb_color (f, color->red, color->green,
7539 color->blue);
7540 p = xpm_cache_color (f, color_name, color, h);
7541 }
7542
7543 return p != NULL;
7544 }
7545
7546
7547 /* Callback for allocating color COLOR_NAME. Called from the XPM lib.
7548 CLOSURE is a pointer to the frame on which we allocate the
7549 color. Return in *COLOR the allocated color. Value is non-zero
7550 if successful. */
7551
7552 static int
7553 xpm_alloc_color (dpy, cmap, color_name, color, closure)
7554 Display *dpy;
7555 Colormap cmap;
7556 char *color_name;
7557 XColor *color;
7558 void *closure;
7559 {
7560 return xpm_lookup_color ((struct frame *) closure, color_name, color);
7561 }
7562
7563
7564 /* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
7565 is a pointer to the frame on which we allocate the color. Value is
7566 non-zero if successful. */
7567
7568 static int
7569 xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7570 Display *dpy;
7571 Colormap cmap;
7572 Pixel *pixels;
7573 int npixels;
7574 void *closure;
7575 {
7576 return 1;
7577 }
7578
7579 #endif /* ALLOC_XPM_COLORS */
7580
7581
7582 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7583 for XPM images. Such a list must consist of conses whose car and
7584 cdr are strings. */
7585
7586 static int
7587 xpm_valid_color_symbols_p (color_symbols)
7588 Lisp_Object color_symbols;
7589 {
7590 while (CONSP (color_symbols))
7591 {
7592 Lisp_Object sym = XCAR (color_symbols);
7593 if (!CONSP (sym)
7594 || !STRINGP (XCAR (sym))
7595 || !STRINGP (XCDR (sym)))
7596 break;
7597 color_symbols = XCDR (color_symbols);
7598 }
7599
7600 return NILP (color_symbols);
7601 }
7602
7603
7604 /* Value is non-zero if OBJECT is a valid XPM image specification. */
7605
7606 static int
7607 xpm_image_p (object)
7608 Lisp_Object object;
7609 {
7610 struct image_keyword fmt[XPM_LAST];
7611 bcopy (xpm_format, fmt, sizeof fmt);
7612 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
7613 /* Either `:file' or `:data' must be present. */
7614 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7615 /* Either no `:color-symbols' or it's a list of conses
7616 whose car and cdr are strings. */
7617 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7618 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
7619 }
7620
7621
7622 /* Load image IMG which will be displayed on frame F. Value is
7623 non-zero if successful. */
7624
7625 static int
7626 xpm_load (f, img)
7627 struct frame *f;
7628 struct image *img;
7629 {
7630 int rc;
7631 XpmAttributes attrs;
7632 Lisp_Object specified_file, color_symbols;
7633
7634 /* Configure the XPM lib. Use the visual of frame F. Allocate
7635 close colors. Return colors allocated. */
7636 bzero (&attrs, sizeof attrs);
7637 attrs.visual = FRAME_X_VISUAL (f);
7638 attrs.colormap = FRAME_X_COLORMAP (f);
7639 attrs.valuemask |= XpmVisual;
7640 attrs.valuemask |= XpmColormap;
7641
7642 #ifdef ALLOC_XPM_COLORS
7643 /* Allocate colors with our own functions which handle
7644 failing color allocation more gracefully. */
7645 attrs.color_closure = f;
7646 attrs.alloc_color = xpm_alloc_color;
7647 attrs.free_colors = xpm_free_colors;
7648 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7649 #else /* not ALLOC_XPM_COLORS */
7650 /* Let the XPM lib allocate colors. */
7651 attrs.valuemask |= XpmReturnAllocPixels;
7652 #ifdef XpmAllocCloseColors
7653 attrs.alloc_close_colors = 1;
7654 attrs.valuemask |= XpmAllocCloseColors;
7655 #else /* not XpmAllocCloseColors */
7656 attrs.closeness = 600;
7657 attrs.valuemask |= XpmCloseness;
7658 #endif /* not XpmAllocCloseColors */
7659 #endif /* ALLOC_XPM_COLORS */
7660
7661 /* If image specification contains symbolic color definitions, add
7662 these to `attrs'. */
7663 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7664 if (CONSP (color_symbols))
7665 {
7666 Lisp_Object tail;
7667 XpmColorSymbol *xpm_syms;
7668 int i, size;
7669
7670 attrs.valuemask |= XpmColorSymbols;
7671
7672 /* Count number of symbols. */
7673 attrs.numsymbols = 0;
7674 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7675 ++attrs.numsymbols;
7676
7677 /* Allocate an XpmColorSymbol array. */
7678 size = attrs.numsymbols * sizeof *xpm_syms;
7679 xpm_syms = (XpmColorSymbol *) alloca (size);
7680 bzero (xpm_syms, size);
7681 attrs.colorsymbols = xpm_syms;
7682
7683 /* Fill the color symbol array. */
7684 for (tail = color_symbols, i = 0;
7685 CONSP (tail);
7686 ++i, tail = XCDR (tail))
7687 {
7688 Lisp_Object name = XCAR (XCAR (tail));
7689 Lisp_Object color = XCDR (XCAR (tail));
7690 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
7691 strcpy (xpm_syms[i].name, SDATA (name));
7692 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
7693 strcpy (xpm_syms[i].value, SDATA (color));
7694 }
7695 }
7696
7697 /* Create a pixmap for the image, either from a file, or from a
7698 string buffer containing data in the same format as an XPM file. */
7699 #ifdef ALLOC_XPM_COLORS
7700 xpm_init_color_cache (f, &attrs);
7701 #endif
7702
7703 specified_file = image_spec_value (img->spec, QCfile, NULL);
7704 if (STRINGP (specified_file))
7705 {
7706 Lisp_Object file = x_find_image_file (specified_file);
7707 if (!STRINGP (file))
7708 {
7709 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7710 return 0;
7711 }
7712
7713 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7714 SDATA (file), &img->pixmap, &img->mask,
7715 &attrs);
7716 }
7717 else
7718 {
7719 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7720 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7721 SDATA (buffer),
7722 &img->pixmap, &img->mask,
7723 &attrs);
7724 }
7725
7726 if (rc == XpmSuccess)
7727 {
7728 #ifdef ALLOC_XPM_COLORS
7729 img->colors = colors_in_color_table (&img->ncolors);
7730 #else /* not ALLOC_XPM_COLORS */
7731 int i;
7732
7733 img->ncolors = attrs.nalloc_pixels;
7734 img->colors = (unsigned long *) xmalloc (img->ncolors
7735 * sizeof *img->colors);
7736 for (i = 0; i < attrs.nalloc_pixels; ++i)
7737 {
7738 img->colors[i] = attrs.alloc_pixels[i];
7739 #ifdef DEBUG_X_COLORS
7740 register_color (img->colors[i]);
7741 #endif
7742 }
7743 #endif /* not ALLOC_XPM_COLORS */
7744
7745 img->width = attrs.width;
7746 img->height = attrs.height;
7747 xassert (img->width > 0 && img->height > 0);
7748
7749 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
7750 XpmFreeAttributes (&attrs);
7751 }
7752 else
7753 {
7754 switch (rc)
7755 {
7756 case XpmOpenFailed:
7757 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7758 break;
7759
7760 case XpmFileInvalid:
7761 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7762 break;
7763
7764 case XpmNoMemory:
7765 image_error ("Out of memory (%s)", img->spec, Qnil);
7766 break;
7767
7768 case XpmColorFailed:
7769 image_error ("Color allocation error (%s)", img->spec, Qnil);
7770 break;
7771
7772 default:
7773 image_error ("Unknown error (%s)", img->spec, Qnil);
7774 break;
7775 }
7776 }
7777
7778 #ifdef ALLOC_XPM_COLORS
7779 xpm_free_color_cache ();
7780 #endif
7781 return rc == XpmSuccess;
7782 }
7783
7784 #endif /* HAVE_XPM != 0 */
7785
7786 \f
7787 /***********************************************************************
7788 Color table
7789 ***********************************************************************/
7790
7791 /* An entry in the color table mapping an RGB color to a pixel color. */
7792
7793 struct ct_color
7794 {
7795 int r, g, b;
7796 unsigned long pixel;
7797
7798 /* Next in color table collision list. */
7799 struct ct_color *next;
7800 };
7801
7802 /* The bucket vector size to use. Must be prime. */
7803
7804 #define CT_SIZE 101
7805
7806 /* Value is a hash of the RGB color given by R, G, and B. */
7807
7808 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7809
7810 /* The color hash table. */
7811
7812 struct ct_color **ct_table;
7813
7814 /* Number of entries in the color table. */
7815
7816 int ct_colors_allocated;
7817
7818 /* Initialize the color table. */
7819
7820 static void
7821 init_color_table ()
7822 {
7823 int size = CT_SIZE * sizeof (*ct_table);
7824 ct_table = (struct ct_color **) xmalloc (size);
7825 bzero (ct_table, size);
7826 ct_colors_allocated = 0;
7827 }
7828
7829
7830 /* Free memory associated with the color table. */
7831
7832 static void
7833 free_color_table ()
7834 {
7835 int i;
7836 struct ct_color *p, *next;
7837
7838 for (i = 0; i < CT_SIZE; ++i)
7839 for (p = ct_table[i]; p; p = next)
7840 {
7841 next = p->next;
7842 xfree (p);
7843 }
7844
7845 xfree (ct_table);
7846 ct_table = NULL;
7847 }
7848
7849
7850 /* Value is a pixel color for RGB color R, G, B on frame F. If an
7851 entry for that color already is in the color table, return the
7852 pixel color of that entry. Otherwise, allocate a new color for R,
7853 G, B, and make an entry in the color table. */
7854
7855 static unsigned long
7856 lookup_rgb_color (f, r, g, b)
7857 struct frame *f;
7858 int r, g, b;
7859 {
7860 unsigned hash = CT_HASH_RGB (r, g, b);
7861 int i = hash % CT_SIZE;
7862 struct ct_color *p;
7863
7864 for (p = ct_table[i]; p; p = p->next)
7865 if (p->r == r && p->g == g && p->b == b)
7866 break;
7867
7868 if (p == NULL)
7869 {
7870 XColor color;
7871 Colormap cmap;
7872 int rc;
7873
7874 color.red = r;
7875 color.green = g;
7876 color.blue = b;
7877
7878 cmap = FRAME_X_COLORMAP (f);
7879 rc = x_alloc_nearest_color (f, cmap, &color);
7880
7881 if (rc)
7882 {
7883 ++ct_colors_allocated;
7884
7885 p = (struct ct_color *) xmalloc (sizeof *p);
7886 p->r = r;
7887 p->g = g;
7888 p->b = b;
7889 p->pixel = color.pixel;
7890 p->next = ct_table[i];
7891 ct_table[i] = p;
7892 }
7893 else
7894 return FRAME_FOREGROUND_PIXEL (f);
7895 }
7896
7897 return p->pixel;
7898 }
7899
7900
7901 /* Look up pixel color PIXEL which is used on frame F in the color
7902 table. If not already present, allocate it. Value is PIXEL. */
7903
7904 static unsigned long
7905 lookup_pixel_color (f, pixel)
7906 struct frame *f;
7907 unsigned long pixel;
7908 {
7909 int i = pixel % CT_SIZE;
7910 struct ct_color *p;
7911
7912 for (p = ct_table[i]; p; p = p->next)
7913 if (p->pixel == pixel)
7914 break;
7915
7916 if (p == NULL)
7917 {
7918 XColor color;
7919 Colormap cmap;
7920 int rc;
7921
7922 cmap = FRAME_X_COLORMAP (f);
7923 color.pixel = pixel;
7924 x_query_color (f, &color);
7925 rc = x_alloc_nearest_color (f, cmap, &color);
7926
7927 if (rc)
7928 {
7929 ++ct_colors_allocated;
7930
7931 p = (struct ct_color *) xmalloc (sizeof *p);
7932 p->r = color.red;
7933 p->g = color.green;
7934 p->b = color.blue;
7935 p->pixel = pixel;
7936 p->next = ct_table[i];
7937 ct_table[i] = p;
7938 }
7939 else
7940 return FRAME_FOREGROUND_PIXEL (f);
7941 }
7942
7943 return p->pixel;
7944 }
7945
7946
7947 /* Value is a vector of all pixel colors contained in the color table,
7948 allocated via xmalloc. Set *N to the number of colors. */
7949
7950 static unsigned long *
7951 colors_in_color_table (n)
7952 int *n;
7953 {
7954 int i, j;
7955 struct ct_color *p;
7956 unsigned long *colors;
7957
7958 if (ct_colors_allocated == 0)
7959 {
7960 *n = 0;
7961 colors = NULL;
7962 }
7963 else
7964 {
7965 colors = (unsigned long *) xmalloc (ct_colors_allocated
7966 * sizeof *colors);
7967 *n = ct_colors_allocated;
7968
7969 for (i = j = 0; i < CT_SIZE; ++i)
7970 for (p = ct_table[i]; p; p = p->next)
7971 colors[j++] = p->pixel;
7972 }
7973
7974 return colors;
7975 }
7976
7977
7978 \f
7979 /***********************************************************************
7980 Algorithms
7981 ***********************************************************************/
7982
7983 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
7984 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
7985 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
7986
7987 /* Non-zero means draw a cross on images having `:conversion
7988 disabled'. */
7989
7990 int cross_disabled_images;
7991
7992 /* Edge detection matrices for different edge-detection
7993 strategies. */
7994
7995 static int emboss_matrix[9] = {
7996 /* x - 1 x x + 1 */
7997 2, -1, 0, /* y - 1 */
7998 -1, 0, 1, /* y */
7999 0, 1, -2 /* y + 1 */
8000 };
8001
8002 static int laplace_matrix[9] = {
8003 /* x - 1 x x + 1 */
8004 1, 0, 0, /* y - 1 */
8005 0, 0, 0, /* y */
8006 0, 0, -1 /* y + 1 */
8007 };
8008
8009 /* Value is the intensity of the color whose red/green/blue values
8010 are R, G, and B. */
8011
8012 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
8013
8014
8015 /* On frame F, return an array of XColor structures describing image
8016 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
8017 non-zero means also fill the red/green/blue members of the XColor
8018 structures. Value is a pointer to the array of XColors structures,
8019 allocated with xmalloc; it must be freed by the caller. */
8020
8021 static XColor *
8022 x_to_xcolors (f, img, rgb_p)
8023 struct frame *f;
8024 struct image *img;
8025 int rgb_p;
8026 {
8027 int x, y;
8028 XColor *colors, *p;
8029 XImage *ximg;
8030
8031 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
8032
8033 /* Get the X image IMG->pixmap. */
8034 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8035 0, 0, img->width, img->height, ~0, ZPixmap);
8036
8037 /* Fill the `pixel' members of the XColor array. I wished there
8038 were an easy and portable way to circumvent XGetPixel. */
8039 p = colors;
8040 for (y = 0; y < img->height; ++y)
8041 {
8042 XColor *row = p;
8043
8044 for (x = 0; x < img->width; ++x, ++p)
8045 p->pixel = XGetPixel (ximg, x, y);
8046
8047 if (rgb_p)
8048 x_query_colors (f, row, img->width);
8049 }
8050
8051 XDestroyImage (ximg);
8052 return colors;
8053 }
8054
8055
8056 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
8057 RGB members are set. F is the frame on which this all happens.
8058 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
8059
8060 static void
8061 x_from_xcolors (f, img, colors)
8062 struct frame *f;
8063 struct image *img;
8064 XColor *colors;
8065 {
8066 int x, y;
8067 XImage *oimg;
8068 Pixmap pixmap;
8069 XColor *p;
8070
8071 init_color_table ();
8072
8073 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
8074 &oimg, &pixmap);
8075 p = colors;
8076 for (y = 0; y < img->height; ++y)
8077 for (x = 0; x < img->width; ++x, ++p)
8078 {
8079 unsigned long pixel;
8080 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
8081 XPutPixel (oimg, x, y, pixel);
8082 }
8083
8084 xfree (colors);
8085 x_clear_image_1 (f, img, 1, 0, 1);
8086
8087 x_put_x_image (f, oimg, pixmap, img->width, img->height);
8088 x_destroy_x_image (oimg);
8089 img->pixmap = pixmap;
8090 img->colors = colors_in_color_table (&img->ncolors);
8091 free_color_table ();
8092 }
8093
8094
8095 /* On frame F, perform edge-detection on image IMG.
8096
8097 MATRIX is a nine-element array specifying the transformation
8098 matrix. See emboss_matrix for an example.
8099
8100 COLOR_ADJUST is a color adjustment added to each pixel of the
8101 outgoing image. */
8102
8103 static void
8104 x_detect_edges (f, img, matrix, color_adjust)
8105 struct frame *f;
8106 struct image *img;
8107 int matrix[9], color_adjust;
8108 {
8109 XColor *colors = x_to_xcolors (f, img, 1);
8110 XColor *new, *p;
8111 int x, y, i, sum;
8112
8113 for (i = sum = 0; i < 9; ++i)
8114 sum += abs (matrix[i]);
8115
8116 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
8117
8118 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
8119
8120 for (y = 0; y < img->height; ++y)
8121 {
8122 p = COLOR (new, 0, y);
8123 p->red = p->green = p->blue = 0xffff/2;
8124 p = COLOR (new, img->width - 1, y);
8125 p->red = p->green = p->blue = 0xffff/2;
8126 }
8127
8128 for (x = 1; x < img->width - 1; ++x)
8129 {
8130 p = COLOR (new, x, 0);
8131 p->red = p->green = p->blue = 0xffff/2;
8132 p = COLOR (new, x, img->height - 1);
8133 p->red = p->green = p->blue = 0xffff/2;
8134 }
8135
8136 for (y = 1; y < img->height - 1; ++y)
8137 {
8138 p = COLOR (new, 1, y);
8139
8140 for (x = 1; x < img->width - 1; ++x, ++p)
8141 {
8142 int r, g, b, y1, x1;
8143
8144 r = g = b = i = 0;
8145 for (y1 = y - 1; y1 < y + 2; ++y1)
8146 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
8147 if (matrix[i])
8148 {
8149 XColor *t = COLOR (colors, x1, y1);
8150 r += matrix[i] * t->red;
8151 g += matrix[i] * t->green;
8152 b += matrix[i] * t->blue;
8153 }
8154
8155 r = (r / sum + color_adjust) & 0xffff;
8156 g = (g / sum + color_adjust) & 0xffff;
8157 b = (b / sum + color_adjust) & 0xffff;
8158 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
8159 }
8160 }
8161
8162 xfree (colors);
8163 x_from_xcolors (f, img, new);
8164
8165 #undef COLOR
8166 }
8167
8168
8169 /* Perform the pre-defined `emboss' edge-detection on image IMG
8170 on frame F. */
8171
8172 static void
8173 x_emboss (f, img)
8174 struct frame *f;
8175 struct image *img;
8176 {
8177 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
8178 }
8179
8180
8181 /* Perform the pre-defined `laplace' edge-detection on image IMG
8182 on frame F. */
8183
8184 static void
8185 x_laplace (f, img)
8186 struct frame *f;
8187 struct image *img;
8188 {
8189 x_detect_edges (f, img, laplace_matrix, 45000);
8190 }
8191
8192
8193 /* Perform edge-detection on image IMG on frame F, with specified
8194 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
8195
8196 MATRIX must be either
8197
8198 - a list of at least 9 numbers in row-major form
8199 - a vector of at least 9 numbers
8200
8201 COLOR_ADJUST nil means use a default; otherwise it must be a
8202 number. */
8203
8204 static void
8205 x_edge_detection (f, img, matrix, color_adjust)
8206 struct frame *f;
8207 struct image *img;
8208 Lisp_Object matrix, color_adjust;
8209 {
8210 int i = 0;
8211 int trans[9];
8212
8213 if (CONSP (matrix))
8214 {
8215 for (i = 0;
8216 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
8217 ++i, matrix = XCDR (matrix))
8218 trans[i] = XFLOATINT (XCAR (matrix));
8219 }
8220 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
8221 {
8222 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
8223 trans[i] = XFLOATINT (AREF (matrix, i));
8224 }
8225
8226 if (NILP (color_adjust))
8227 color_adjust = make_number (0xffff / 2);
8228
8229 if (i == 9 && NUMBERP (color_adjust))
8230 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
8231 }
8232
8233
8234 /* Transform image IMG on frame F so that it looks disabled. */
8235
8236 static void
8237 x_disable_image (f, img)
8238 struct frame *f;
8239 struct image *img;
8240 {
8241 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8242
8243 if (dpyinfo->n_planes >= 2)
8244 {
8245 /* Color (or grayscale). Convert to gray, and equalize. Just
8246 drawing such images with a stipple can look very odd, so
8247 we're using this method instead. */
8248 XColor *colors = x_to_xcolors (f, img, 1);
8249 XColor *p, *end;
8250 const int h = 15000;
8251 const int l = 30000;
8252
8253 for (p = colors, end = colors + img->width * img->height;
8254 p < end;
8255 ++p)
8256 {
8257 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
8258 int i2 = (0xffff - h - l) * i / 0xffff + l;
8259 p->red = p->green = p->blue = i2;
8260 }
8261
8262 x_from_xcolors (f, img, colors);
8263 }
8264
8265 /* Draw a cross over the disabled image, if we must or if we
8266 should. */
8267 if (dpyinfo->n_planes < 2 || cross_disabled_images)
8268 {
8269 Display *dpy = FRAME_X_DISPLAY (f);
8270 GC gc;
8271
8272 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
8273 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
8274 XDrawLine (dpy, img->pixmap, gc, 0, 0,
8275 img->width - 1, img->height - 1);
8276 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
8277 img->width - 1, 0);
8278 XFreeGC (dpy, gc);
8279
8280 if (img->mask)
8281 {
8282 gc = XCreateGC (dpy, img->mask, 0, NULL);
8283 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
8284 XDrawLine (dpy, img->mask, gc, 0, 0,
8285 img->width - 1, img->height - 1);
8286 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
8287 img->width - 1, 0);
8288 XFreeGC (dpy, gc);
8289 }
8290 }
8291 }
8292
8293
8294 /* Build a mask for image IMG which is used on frame F. FILE is the
8295 name of an image file, for error messages. HOW determines how to
8296 determine the background color of IMG. If it is a list '(R G B)',
8297 with R, G, and B being integers >= 0, take that as the color of the
8298 background. Otherwise, determine the background color of IMG
8299 heuristically. Value is non-zero if successful. */
8300
8301 static int
8302 x_build_heuristic_mask (f, img, how)
8303 struct frame *f;
8304 struct image *img;
8305 Lisp_Object how;
8306 {
8307 Display *dpy = FRAME_X_DISPLAY (f);
8308 XImage *ximg, *mask_img;
8309 int x, y, rc, use_img_background;
8310 unsigned long bg = 0;
8311
8312 if (img->mask)
8313 {
8314 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8315 img->mask = None;
8316 img->background_transparent_valid = 0;
8317 }
8318
8319 /* Create an image and pixmap serving as mask. */
8320 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
8321 &mask_img, &img->mask);
8322 if (!rc)
8323 return 0;
8324
8325 /* Get the X image of IMG->pixmap. */
8326 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
8327 ~0, ZPixmap);
8328
8329 /* Determine the background color of ximg. If HOW is `(R G B)'
8330 take that as color. Otherwise, use the image's background color. */
8331 use_img_background = 1;
8332
8333 if (CONSP (how))
8334 {
8335 int rgb[3], i;
8336
8337 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
8338 {
8339 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
8340 how = XCDR (how);
8341 }
8342
8343 if (i == 3 && NILP (how))
8344 {
8345 char color_name[30];
8346 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
8347 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
8348 use_img_background = 0;
8349 }
8350 }
8351
8352 if (use_img_background)
8353 bg = four_corners_best (ximg, img->width, img->height);
8354
8355 /* Set all bits in mask_img to 1 whose color in ximg is different
8356 from the background color bg. */
8357 for (y = 0; y < img->height; ++y)
8358 for (x = 0; x < img->width; ++x)
8359 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
8360
8361 /* Fill in the background_transparent field while we have the mask handy. */
8362 image_background_transparent (img, f, mask_img);
8363
8364 /* Put mask_img into img->mask. */
8365 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8366 x_destroy_x_image (mask_img);
8367 XDestroyImage (ximg);
8368
8369 return 1;
8370 }
8371
8372
8373 \f
8374 /***********************************************************************
8375 PBM (mono, gray, color)
8376 ***********************************************************************/
8377
8378 static int pbm_image_p P_ ((Lisp_Object object));
8379 static int pbm_load P_ ((struct frame *f, struct image *img));
8380 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
8381
8382 /* The symbol `pbm' identifying images of this type. */
8383
8384 Lisp_Object Qpbm;
8385
8386 /* Indices of image specification fields in gs_format, below. */
8387
8388 enum pbm_keyword_index
8389 {
8390 PBM_TYPE,
8391 PBM_FILE,
8392 PBM_DATA,
8393 PBM_ASCENT,
8394 PBM_MARGIN,
8395 PBM_RELIEF,
8396 PBM_ALGORITHM,
8397 PBM_HEURISTIC_MASK,
8398 PBM_MASK,
8399 PBM_FOREGROUND,
8400 PBM_BACKGROUND,
8401 PBM_LAST
8402 };
8403
8404 /* Vector of image_keyword structures describing the format
8405 of valid user-defined image specifications. */
8406
8407 static struct image_keyword pbm_format[PBM_LAST] =
8408 {
8409 {":type", IMAGE_SYMBOL_VALUE, 1},
8410 {":file", IMAGE_STRING_VALUE, 0},
8411 {":data", IMAGE_STRING_VALUE, 0},
8412 {":ascent", IMAGE_ASCENT_VALUE, 0},
8413 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8414 {":relief", IMAGE_INTEGER_VALUE, 0},
8415 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8416 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8417 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8418 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8419 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8420 };
8421
8422 /* Structure describing the image type `pbm'. */
8423
8424 static struct image_type pbm_type =
8425 {
8426 &Qpbm,
8427 pbm_image_p,
8428 pbm_load,
8429 x_clear_image,
8430 NULL
8431 };
8432
8433
8434 /* Return non-zero if OBJECT is a valid PBM image specification. */
8435
8436 static int
8437 pbm_image_p (object)
8438 Lisp_Object object;
8439 {
8440 struct image_keyword fmt[PBM_LAST];
8441
8442 bcopy (pbm_format, fmt, sizeof fmt);
8443
8444 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
8445 return 0;
8446
8447 /* Must specify either :data or :file. */
8448 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
8449 }
8450
8451
8452 /* Scan a decimal number from *S and return it. Advance *S while
8453 reading the number. END is the end of the string. Value is -1 at
8454 end of input. */
8455
8456 static int
8457 pbm_scan_number (s, end)
8458 unsigned char **s, *end;
8459 {
8460 int c = 0, val = -1;
8461
8462 while (*s < end)
8463 {
8464 /* Skip white-space. */
8465 while (*s < end && (c = *(*s)++, isspace (c)))
8466 ;
8467
8468 if (c == '#')
8469 {
8470 /* Skip comment to end of line. */
8471 while (*s < end && (c = *(*s)++, c != '\n'))
8472 ;
8473 }
8474 else if (isdigit (c))
8475 {
8476 /* Read decimal number. */
8477 val = c - '0';
8478 while (*s < end && (c = *(*s)++, isdigit (c)))
8479 val = 10 * val + c - '0';
8480 break;
8481 }
8482 else
8483 break;
8484 }
8485
8486 return val;
8487 }
8488
8489
8490 /* Load PBM image IMG for use on frame F. */
8491
8492 static int
8493 pbm_load (f, img)
8494 struct frame *f;
8495 struct image *img;
8496 {
8497 int raw_p, x, y;
8498 int width, height, max_color_idx = 0;
8499 XImage *ximg;
8500 Lisp_Object file, specified_file;
8501 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8502 struct gcpro gcpro1;
8503 unsigned char *contents = NULL;
8504 unsigned char *end, *p;
8505 int size;
8506
8507 specified_file = image_spec_value (img->spec, QCfile, NULL);
8508 file = Qnil;
8509 GCPRO1 (file);
8510
8511 if (STRINGP (specified_file))
8512 {
8513 file = x_find_image_file (specified_file);
8514 if (!STRINGP (file))
8515 {
8516 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8517 UNGCPRO;
8518 return 0;
8519 }
8520
8521 contents = slurp_file (SDATA (file), &size);
8522 if (contents == NULL)
8523 {
8524 image_error ("Error reading `%s'", file, Qnil);
8525 UNGCPRO;
8526 return 0;
8527 }
8528
8529 p = contents;
8530 end = contents + size;
8531 }
8532 else
8533 {
8534 Lisp_Object data;
8535 data = image_spec_value (img->spec, QCdata, NULL);
8536 p = SDATA (data);
8537 end = p + SBYTES (data);
8538 }
8539
8540 /* Check magic number. */
8541 if (end - p < 2 || *p++ != 'P')
8542 {
8543 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
8544 error:
8545 xfree (contents);
8546 UNGCPRO;
8547 return 0;
8548 }
8549
8550 switch (*p++)
8551 {
8552 case '1':
8553 raw_p = 0, type = PBM_MONO;
8554 break;
8555
8556 case '2':
8557 raw_p = 0, type = PBM_GRAY;
8558 break;
8559
8560 case '3':
8561 raw_p = 0, type = PBM_COLOR;
8562 break;
8563
8564 case '4':
8565 raw_p = 1, type = PBM_MONO;
8566 break;
8567
8568 case '5':
8569 raw_p = 1, type = PBM_GRAY;
8570 break;
8571
8572 case '6':
8573 raw_p = 1, type = PBM_COLOR;
8574 break;
8575
8576 default:
8577 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
8578 goto error;
8579 }
8580
8581 /* Read width, height, maximum color-component. Characters
8582 starting with `#' up to the end of a line are ignored. */
8583 width = pbm_scan_number (&p, end);
8584 height = pbm_scan_number (&p, end);
8585
8586 if (type != PBM_MONO)
8587 {
8588 max_color_idx = pbm_scan_number (&p, end);
8589 if (raw_p && max_color_idx > 255)
8590 max_color_idx = 255;
8591 }
8592
8593 if (width < 0
8594 || height < 0
8595 || (type != PBM_MONO && max_color_idx < 0))
8596 goto error;
8597
8598 if (!x_create_x_image_and_pixmap (f, width, height, 0,
8599 &ximg, &img->pixmap))
8600 goto error;
8601
8602 /* Initialize the color hash table. */
8603 init_color_table ();
8604
8605 if (type == PBM_MONO)
8606 {
8607 int c = 0, g;
8608 struct image_keyword fmt[PBM_LAST];
8609 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
8610 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
8611
8612 /* Parse the image specification. */
8613 bcopy (pbm_format, fmt, sizeof fmt);
8614 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
8615
8616 /* Get foreground and background colors, maybe allocate colors. */
8617 if (fmt[PBM_FOREGROUND].count
8618 && STRINGP (fmt[PBM_FOREGROUND].value))
8619 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
8620 if (fmt[PBM_BACKGROUND].count
8621 && STRINGP (fmt[PBM_BACKGROUND].value))
8622 {
8623 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
8624 img->background = bg;
8625 img->background_valid = 1;
8626 }
8627
8628 for (y = 0; y < height; ++y)
8629 for (x = 0; x < width; ++x)
8630 {
8631 if (raw_p)
8632 {
8633 if ((x & 7) == 0)
8634 c = *p++;
8635 g = c & 0x80;
8636 c <<= 1;
8637 }
8638 else
8639 g = pbm_scan_number (&p, end);
8640
8641 XPutPixel (ximg, x, y, g ? fg : bg);
8642 }
8643 }
8644 else
8645 {
8646 for (y = 0; y < height; ++y)
8647 for (x = 0; x < width; ++x)
8648 {
8649 int r, g, b;
8650
8651 if (type == PBM_GRAY)
8652 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
8653 else if (raw_p)
8654 {
8655 r = *p++;
8656 g = *p++;
8657 b = *p++;
8658 }
8659 else
8660 {
8661 r = pbm_scan_number (&p, end);
8662 g = pbm_scan_number (&p, end);
8663 b = pbm_scan_number (&p, end);
8664 }
8665
8666 if (r < 0 || g < 0 || b < 0)
8667 {
8668 xfree (ximg->data);
8669 ximg->data = NULL;
8670 XDestroyImage (ximg);
8671 image_error ("Invalid pixel value in image `%s'",
8672 img->spec, Qnil);
8673 goto error;
8674 }
8675
8676 /* RGB values are now in the range 0..max_color_idx.
8677 Scale this to the range 0..0xffff supported by X. */
8678 r = (double) r * 65535 / max_color_idx;
8679 g = (double) g * 65535 / max_color_idx;
8680 b = (double) b * 65535 / max_color_idx;
8681 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8682 }
8683 }
8684
8685 /* Store in IMG->colors the colors allocated for the image, and
8686 free the color table. */
8687 img->colors = colors_in_color_table (&img->ncolors);
8688 free_color_table ();
8689
8690 /* Maybe fill in the background field while we have ximg handy. */
8691 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8692 IMAGE_BACKGROUND (img, f, ximg);
8693
8694 /* Put the image into a pixmap. */
8695 x_put_x_image (f, ximg, img->pixmap, width, height);
8696 x_destroy_x_image (ximg);
8697
8698 img->width = width;
8699 img->height = height;
8700
8701 UNGCPRO;
8702 xfree (contents);
8703 return 1;
8704 }
8705
8706
8707 \f
8708 /***********************************************************************
8709 PNG
8710 ***********************************************************************/
8711
8712 #if HAVE_PNG
8713
8714 #include <png.h>
8715
8716 /* Function prototypes. */
8717
8718 static int png_image_p P_ ((Lisp_Object object));
8719 static int png_load P_ ((struct frame *f, struct image *img));
8720
8721 /* The symbol `png' identifying images of this type. */
8722
8723 Lisp_Object Qpng;
8724
8725 /* Indices of image specification fields in png_format, below. */
8726
8727 enum png_keyword_index
8728 {
8729 PNG_TYPE,
8730 PNG_DATA,
8731 PNG_FILE,
8732 PNG_ASCENT,
8733 PNG_MARGIN,
8734 PNG_RELIEF,
8735 PNG_ALGORITHM,
8736 PNG_HEURISTIC_MASK,
8737 PNG_MASK,
8738 PNG_BACKGROUND,
8739 PNG_LAST
8740 };
8741
8742 /* Vector of image_keyword structures describing the format
8743 of valid user-defined image specifications. */
8744
8745 static struct image_keyword png_format[PNG_LAST] =
8746 {
8747 {":type", IMAGE_SYMBOL_VALUE, 1},
8748 {":data", IMAGE_STRING_VALUE, 0},
8749 {":file", IMAGE_STRING_VALUE, 0},
8750 {":ascent", IMAGE_ASCENT_VALUE, 0},
8751 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8752 {":relief", IMAGE_INTEGER_VALUE, 0},
8753 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8754 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8755 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8756 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8757 };
8758
8759 /* Structure describing the image type `png'. */
8760
8761 static struct image_type png_type =
8762 {
8763 &Qpng,
8764 png_image_p,
8765 png_load,
8766 x_clear_image,
8767 NULL
8768 };
8769
8770
8771 /* Return non-zero if OBJECT is a valid PNG image specification. */
8772
8773 static int
8774 png_image_p (object)
8775 Lisp_Object object;
8776 {
8777 struct image_keyword fmt[PNG_LAST];
8778 bcopy (png_format, fmt, sizeof fmt);
8779
8780 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
8781 return 0;
8782
8783 /* Must specify either the :data or :file keyword. */
8784 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
8785 }
8786
8787
8788 /* Error and warning handlers installed when the PNG library
8789 is initialized. */
8790
8791 static void
8792 my_png_error (png_ptr, msg)
8793 png_struct *png_ptr;
8794 char *msg;
8795 {
8796 xassert (png_ptr != NULL);
8797 image_error ("PNG error: %s", build_string (msg), Qnil);
8798 longjmp (png_ptr->jmpbuf, 1);
8799 }
8800
8801
8802 static void
8803 my_png_warning (png_ptr, msg)
8804 png_struct *png_ptr;
8805 char *msg;
8806 {
8807 xassert (png_ptr != NULL);
8808 image_error ("PNG warning: %s", build_string (msg), Qnil);
8809 }
8810
8811 /* Memory source for PNG decoding. */
8812
8813 struct png_memory_storage
8814 {
8815 unsigned char *bytes; /* The data */
8816 size_t len; /* How big is it? */
8817 int index; /* Where are we? */
8818 };
8819
8820
8821 /* Function set as reader function when reading PNG image from memory.
8822 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8823 bytes from the input to DATA. */
8824
8825 static void
8826 png_read_from_memory (png_ptr, data, length)
8827 png_structp png_ptr;
8828 png_bytep data;
8829 png_size_t length;
8830 {
8831 struct png_memory_storage *tbr
8832 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
8833
8834 if (length > tbr->len - tbr->index)
8835 png_error (png_ptr, "Read error");
8836
8837 bcopy (tbr->bytes + tbr->index, data, length);
8838 tbr->index = tbr->index + length;
8839 }
8840
8841 /* Load PNG image IMG for use on frame F. Value is non-zero if
8842 successful. */
8843
8844 static int
8845 png_load (f, img)
8846 struct frame *f;
8847 struct image *img;
8848 {
8849 Lisp_Object file, specified_file;
8850 Lisp_Object specified_data;
8851 int x, y, i;
8852 XImage *ximg, *mask_img = NULL;
8853 struct gcpro gcpro1;
8854 png_struct *png_ptr = NULL;
8855 png_info *info_ptr = NULL, *end_info = NULL;
8856 FILE *volatile fp = NULL;
8857 png_byte sig[8];
8858 png_byte * volatile pixels = NULL;
8859 png_byte ** volatile rows = NULL;
8860 png_uint_32 width, height;
8861 int bit_depth, color_type, interlace_type;
8862 png_byte channels;
8863 png_uint_32 row_bytes;
8864 int transparent_p;
8865 double screen_gamma, image_gamma;
8866 int intent;
8867 struct png_memory_storage tbr; /* Data to be read */
8868
8869 /* Find out what file to load. */
8870 specified_file = image_spec_value (img->spec, QCfile, NULL);
8871 specified_data = image_spec_value (img->spec, QCdata, NULL);
8872 file = Qnil;
8873 GCPRO1 (file);
8874
8875 if (NILP (specified_data))
8876 {
8877 file = x_find_image_file (specified_file);
8878 if (!STRINGP (file))
8879 {
8880 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8881 UNGCPRO;
8882 return 0;
8883 }
8884
8885 /* Open the image file. */
8886 fp = fopen (SDATA (file), "rb");
8887 if (!fp)
8888 {
8889 image_error ("Cannot open image file `%s'", file, Qnil);
8890 UNGCPRO;
8891 fclose (fp);
8892 return 0;
8893 }
8894
8895 /* Check PNG signature. */
8896 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8897 || !png_check_sig (sig, sizeof sig))
8898 {
8899 image_error ("Not a PNG file: `%s'", file, Qnil);
8900 UNGCPRO;
8901 fclose (fp);
8902 return 0;
8903 }
8904 }
8905 else
8906 {
8907 /* Read from memory. */
8908 tbr.bytes = SDATA (specified_data);
8909 tbr.len = SBYTES (specified_data);
8910 tbr.index = 0;
8911
8912 /* Check PNG signature. */
8913 if (tbr.len < sizeof sig
8914 || !png_check_sig (tbr.bytes, sizeof sig))
8915 {
8916 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
8917 UNGCPRO;
8918 return 0;
8919 }
8920
8921 /* Need to skip past the signature. */
8922 tbr.bytes += sizeof (sig);
8923 }
8924
8925 /* Initialize read and info structs for PNG lib. */
8926 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8927 my_png_error, my_png_warning);
8928 if (!png_ptr)
8929 {
8930 if (fp) fclose (fp);
8931 UNGCPRO;
8932 return 0;
8933 }
8934
8935 info_ptr = png_create_info_struct (png_ptr);
8936 if (!info_ptr)
8937 {
8938 png_destroy_read_struct (&png_ptr, NULL, NULL);
8939 if (fp) fclose (fp);
8940 UNGCPRO;
8941 return 0;
8942 }
8943
8944 end_info = png_create_info_struct (png_ptr);
8945 if (!end_info)
8946 {
8947 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
8948 if (fp) fclose (fp);
8949 UNGCPRO;
8950 return 0;
8951 }
8952
8953 /* Set error jump-back. We come back here when the PNG library
8954 detects an error. */
8955 if (setjmp (png_ptr->jmpbuf))
8956 {
8957 error:
8958 if (png_ptr)
8959 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8960 xfree (pixels);
8961 xfree (rows);
8962 if (fp) fclose (fp);
8963 UNGCPRO;
8964 return 0;
8965 }
8966
8967 /* Read image info. */
8968 if (!NILP (specified_data))
8969 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
8970 else
8971 png_init_io (png_ptr, fp);
8972
8973 png_set_sig_bytes (png_ptr, sizeof sig);
8974 png_read_info (png_ptr, info_ptr);
8975 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
8976 &interlace_type, NULL, NULL);
8977
8978 /* If image contains simply transparency data, we prefer to
8979 construct a clipping mask. */
8980 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
8981 transparent_p = 1;
8982 else
8983 transparent_p = 0;
8984
8985 /* This function is easier to write if we only have to handle
8986 one data format: RGB or RGBA with 8 bits per channel. Let's
8987 transform other formats into that format. */
8988
8989 /* Strip more than 8 bits per channel. */
8990 if (bit_depth == 16)
8991 png_set_strip_16 (png_ptr);
8992
8993 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
8994 if available. */
8995 png_set_expand (png_ptr);
8996
8997 /* Convert grayscale images to RGB. */
8998 if (color_type == PNG_COLOR_TYPE_GRAY
8999 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9000 png_set_gray_to_rgb (png_ptr);
9001
9002 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
9003
9004 /* Tell the PNG lib to handle gamma correction for us. */
9005
9006 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
9007 if (png_get_sRGB (png_ptr, info_ptr, &intent))
9008 /* The libpng documentation says this is right in this case. */
9009 png_set_gamma (png_ptr, screen_gamma, 0.45455);
9010 else
9011 #endif
9012 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
9013 /* Image contains gamma information. */
9014 png_set_gamma (png_ptr, screen_gamma, image_gamma);
9015 else
9016 /* Use the standard default for the image gamma. */
9017 png_set_gamma (png_ptr, screen_gamma, 0.45455);
9018
9019 /* Handle alpha channel by combining the image with a background
9020 color. Do this only if a real alpha channel is supplied. For
9021 simple transparency, we prefer a clipping mask. */
9022 if (!transparent_p)
9023 {
9024 png_color_16 *image_bg;
9025 Lisp_Object specified_bg
9026 = image_spec_value (img->spec, QCbackground, NULL);
9027
9028 if (STRINGP (specified_bg))
9029 /* The user specified `:background', use that. */
9030 {
9031 XColor color;
9032 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
9033 {
9034 png_color_16 user_bg;
9035
9036 bzero (&user_bg, sizeof user_bg);
9037 user_bg.red = color.red;
9038 user_bg.green = color.green;
9039 user_bg.blue = color.blue;
9040
9041 png_set_background (png_ptr, &user_bg,
9042 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9043 }
9044 }
9045 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
9046 /* Image contains a background color with which to
9047 combine the image. */
9048 png_set_background (png_ptr, image_bg,
9049 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
9050 else
9051 {
9052 /* Image does not contain a background color with which
9053 to combine the image data via an alpha channel. Use
9054 the frame's background instead. */
9055 XColor color;
9056 Colormap cmap;
9057 png_color_16 frame_background;
9058
9059 cmap = FRAME_X_COLORMAP (f);
9060 color.pixel = FRAME_BACKGROUND_PIXEL (f);
9061 x_query_color (f, &color);
9062
9063 bzero (&frame_background, sizeof frame_background);
9064 frame_background.red = color.red;
9065 frame_background.green = color.green;
9066 frame_background.blue = color.blue;
9067
9068 png_set_background (png_ptr, &frame_background,
9069 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9070 }
9071 }
9072
9073 /* Update info structure. */
9074 png_read_update_info (png_ptr, info_ptr);
9075
9076 /* Get number of channels. Valid values are 1 for grayscale images
9077 and images with a palette, 2 for grayscale images with transparency
9078 information (alpha channel), 3 for RGB images, and 4 for RGB
9079 images with alpha channel, i.e. RGBA. If conversions above were
9080 sufficient we should only have 3 or 4 channels here. */
9081 channels = png_get_channels (png_ptr, info_ptr);
9082 xassert (channels == 3 || channels == 4);
9083
9084 /* Number of bytes needed for one row of the image. */
9085 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
9086
9087 /* Allocate memory for the image. */
9088 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
9089 rows = (png_byte **) xmalloc (height * sizeof *rows);
9090 for (i = 0; i < height; ++i)
9091 rows[i] = pixels + i * row_bytes;
9092
9093 /* Read the entire image. */
9094 png_read_image (png_ptr, rows);
9095 png_read_end (png_ptr, info_ptr);
9096 if (fp)
9097 {
9098 fclose (fp);
9099 fp = NULL;
9100 }
9101
9102 /* Create the X image and pixmap. */
9103 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
9104 &img->pixmap))
9105 goto error;
9106
9107 /* Create an image and pixmap serving as mask if the PNG image
9108 contains an alpha channel. */
9109 if (channels == 4
9110 && !transparent_p
9111 && !x_create_x_image_and_pixmap (f, width, height, 1,
9112 &mask_img, &img->mask))
9113 {
9114 x_destroy_x_image (ximg);
9115 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
9116 img->pixmap = None;
9117 goto error;
9118 }
9119
9120 /* Fill the X image and mask from PNG data. */
9121 init_color_table ();
9122
9123 for (y = 0; y < height; ++y)
9124 {
9125 png_byte *p = rows[y];
9126
9127 for (x = 0; x < width; ++x)
9128 {
9129 unsigned r, g, b;
9130
9131 r = *p++ << 8;
9132 g = *p++ << 8;
9133 b = *p++ << 8;
9134 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9135
9136 /* An alpha channel, aka mask channel, associates variable
9137 transparency with an image. Where other image formats
9138 support binary transparency---fully transparent or fully
9139 opaque---PNG allows up to 254 levels of partial transparency.
9140 The PNG library implements partial transparency by combining
9141 the image with a specified background color.
9142
9143 I'm not sure how to handle this here nicely: because the
9144 background on which the image is displayed may change, for
9145 real alpha channel support, it would be necessary to create
9146 a new image for each possible background.
9147
9148 What I'm doing now is that a mask is created if we have
9149 boolean transparency information. Otherwise I'm using
9150 the frame's background color to combine the image with. */
9151
9152 if (channels == 4)
9153 {
9154 if (mask_img)
9155 XPutPixel (mask_img, x, y, *p > 0);
9156 ++p;
9157 }
9158 }
9159 }
9160
9161 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9162 /* Set IMG's background color from the PNG image, unless the user
9163 overrode it. */
9164 {
9165 png_color_16 *bg;
9166 if (png_get_bKGD (png_ptr, info_ptr, &bg))
9167 {
9168 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
9169 img->background_valid = 1;
9170 }
9171 }
9172
9173 /* Remember colors allocated for this image. */
9174 img->colors = colors_in_color_table (&img->ncolors);
9175 free_color_table ();
9176
9177 /* Clean up. */
9178 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9179 xfree (rows);
9180 xfree (pixels);
9181
9182 img->width = width;
9183 img->height = height;
9184
9185 /* Maybe fill in the background field while we have ximg handy. */
9186 IMAGE_BACKGROUND (img, f, ximg);
9187
9188 /* Put the image into the pixmap, then free the X image and its buffer. */
9189 x_put_x_image (f, ximg, img->pixmap, width, height);
9190 x_destroy_x_image (ximg);
9191
9192 /* Same for the mask. */
9193 if (mask_img)
9194 {
9195 /* Fill in the background_transparent field while we have the mask
9196 handy. */
9197 image_background_transparent (img, f, mask_img);
9198
9199 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9200 x_destroy_x_image (mask_img);
9201 }
9202
9203 UNGCPRO;
9204 return 1;
9205 }
9206
9207 #endif /* HAVE_PNG != 0 */
9208
9209
9210 \f
9211 /***********************************************************************
9212 JPEG
9213 ***********************************************************************/
9214
9215 #if HAVE_JPEG
9216
9217 /* Work around a warning about HAVE_STDLIB_H being redefined in
9218 jconfig.h. */
9219 #ifdef HAVE_STDLIB_H
9220 #define HAVE_STDLIB_H_1
9221 #undef HAVE_STDLIB_H
9222 #endif /* HAVE_STLIB_H */
9223
9224 #include <jpeglib.h>
9225 #include <jerror.h>
9226 #include <setjmp.h>
9227
9228 #ifdef HAVE_STLIB_H_1
9229 #define HAVE_STDLIB_H 1
9230 #endif
9231
9232 static int jpeg_image_p P_ ((Lisp_Object object));
9233 static int jpeg_load P_ ((struct frame *f, struct image *img));
9234
9235 /* The symbol `jpeg' identifying images of this type. */
9236
9237 Lisp_Object Qjpeg;
9238
9239 /* Indices of image specification fields in gs_format, below. */
9240
9241 enum jpeg_keyword_index
9242 {
9243 JPEG_TYPE,
9244 JPEG_DATA,
9245 JPEG_FILE,
9246 JPEG_ASCENT,
9247 JPEG_MARGIN,
9248 JPEG_RELIEF,
9249 JPEG_ALGORITHM,
9250 JPEG_HEURISTIC_MASK,
9251 JPEG_MASK,
9252 JPEG_BACKGROUND,
9253 JPEG_LAST
9254 };
9255
9256 /* Vector of image_keyword structures describing the format
9257 of valid user-defined image specifications. */
9258
9259 static struct image_keyword jpeg_format[JPEG_LAST] =
9260 {
9261 {":type", IMAGE_SYMBOL_VALUE, 1},
9262 {":data", IMAGE_STRING_VALUE, 0},
9263 {":file", IMAGE_STRING_VALUE, 0},
9264 {":ascent", IMAGE_ASCENT_VALUE, 0},
9265 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9266 {":relief", IMAGE_INTEGER_VALUE, 0},
9267 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9268 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9269 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9270 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9271 };
9272
9273 /* Structure describing the image type `jpeg'. */
9274
9275 static struct image_type jpeg_type =
9276 {
9277 &Qjpeg,
9278 jpeg_image_p,
9279 jpeg_load,
9280 x_clear_image,
9281 NULL
9282 };
9283
9284
9285 /* Return non-zero if OBJECT is a valid JPEG image specification. */
9286
9287 static int
9288 jpeg_image_p (object)
9289 Lisp_Object object;
9290 {
9291 struct image_keyword fmt[JPEG_LAST];
9292
9293 bcopy (jpeg_format, fmt, sizeof fmt);
9294
9295 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
9296 return 0;
9297
9298 /* Must specify either the :data or :file keyword. */
9299 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
9300 }
9301
9302
9303 struct my_jpeg_error_mgr
9304 {
9305 struct jpeg_error_mgr pub;
9306 jmp_buf setjmp_buffer;
9307 };
9308
9309
9310 static void
9311 my_error_exit (cinfo)
9312 j_common_ptr cinfo;
9313 {
9314 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
9315 longjmp (mgr->setjmp_buffer, 1);
9316 }
9317
9318
9319 /* Init source method for JPEG data source manager. Called by
9320 jpeg_read_header() before any data is actually read. See
9321 libjpeg.doc from the JPEG lib distribution. */
9322
9323 static void
9324 our_init_source (cinfo)
9325 j_decompress_ptr cinfo;
9326 {
9327 }
9328
9329
9330 /* Fill input buffer method for JPEG data source manager. Called
9331 whenever more data is needed. We read the whole image in one step,
9332 so this only adds a fake end of input marker at the end. */
9333
9334 static boolean
9335 our_fill_input_buffer (cinfo)
9336 j_decompress_ptr cinfo;
9337 {
9338 /* Insert a fake EOI marker. */
9339 struct jpeg_source_mgr *src = cinfo->src;
9340 static JOCTET buffer[2];
9341
9342 buffer[0] = (JOCTET) 0xFF;
9343 buffer[1] = (JOCTET) JPEG_EOI;
9344
9345 src->next_input_byte = buffer;
9346 src->bytes_in_buffer = 2;
9347 return TRUE;
9348 }
9349
9350
9351 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
9352 is the JPEG data source manager. */
9353
9354 static void
9355 our_skip_input_data (cinfo, num_bytes)
9356 j_decompress_ptr cinfo;
9357 long num_bytes;
9358 {
9359 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
9360
9361 if (src)
9362 {
9363 if (num_bytes > src->bytes_in_buffer)
9364 ERREXIT (cinfo, JERR_INPUT_EOF);
9365
9366 src->bytes_in_buffer -= num_bytes;
9367 src->next_input_byte += num_bytes;
9368 }
9369 }
9370
9371
9372 /* Method to terminate data source. Called by
9373 jpeg_finish_decompress() after all data has been processed. */
9374
9375 static void
9376 our_term_source (cinfo)
9377 j_decompress_ptr cinfo;
9378 {
9379 }
9380
9381
9382 /* Set up the JPEG lib for reading an image from DATA which contains
9383 LEN bytes. CINFO is the decompression info structure created for
9384 reading the image. */
9385
9386 static void
9387 jpeg_memory_src (cinfo, data, len)
9388 j_decompress_ptr cinfo;
9389 JOCTET *data;
9390 unsigned int len;
9391 {
9392 struct jpeg_source_mgr *src;
9393
9394 if (cinfo->src == NULL)
9395 {
9396 /* First time for this JPEG object? */
9397 cinfo->src = (struct jpeg_source_mgr *)
9398 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
9399 sizeof (struct jpeg_source_mgr));
9400 src = (struct jpeg_source_mgr *) cinfo->src;
9401 src->next_input_byte = data;
9402 }
9403
9404 src = (struct jpeg_source_mgr *) cinfo->src;
9405 src->init_source = our_init_source;
9406 src->fill_input_buffer = our_fill_input_buffer;
9407 src->skip_input_data = our_skip_input_data;
9408 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
9409 src->term_source = our_term_source;
9410 src->bytes_in_buffer = len;
9411 src->next_input_byte = data;
9412 }
9413
9414
9415 /* Load image IMG for use on frame F. Patterned after example.c
9416 from the JPEG lib. */
9417
9418 static int
9419 jpeg_load (f, img)
9420 struct frame *f;
9421 struct image *img;
9422 {
9423 struct jpeg_decompress_struct cinfo;
9424 struct my_jpeg_error_mgr mgr;
9425 Lisp_Object file, specified_file;
9426 Lisp_Object specified_data;
9427 FILE * volatile fp = NULL;
9428 JSAMPARRAY buffer;
9429 int row_stride, x, y;
9430 XImage *ximg = NULL;
9431 int rc;
9432 unsigned long *colors;
9433 int width, height;
9434 struct gcpro gcpro1;
9435
9436 /* Open the JPEG file. */
9437 specified_file = image_spec_value (img->spec, QCfile, NULL);
9438 specified_data = image_spec_value (img->spec, QCdata, NULL);
9439 file = Qnil;
9440 GCPRO1 (file);
9441
9442 if (NILP (specified_data))
9443 {
9444 file = x_find_image_file (specified_file);
9445 if (!STRINGP (file))
9446 {
9447 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9448 UNGCPRO;
9449 return 0;
9450 }
9451
9452 fp = fopen (SDATA (file), "r");
9453 if (fp == NULL)
9454 {
9455 image_error ("Cannot open `%s'", file, Qnil);
9456 UNGCPRO;
9457 return 0;
9458 }
9459 }
9460
9461 /* Customize libjpeg's error handling to call my_error_exit when an
9462 error is detected. This function will perform a longjmp. */
9463 cinfo.err = jpeg_std_error (&mgr.pub);
9464 mgr.pub.error_exit = my_error_exit;
9465
9466 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9467 {
9468 if (rc == 1)
9469 {
9470 /* Called from my_error_exit. Display a JPEG error. */
9471 char buffer[JMSG_LENGTH_MAX];
9472 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
9473 image_error ("Error reading JPEG image `%s': %s", img->spec,
9474 build_string (buffer));
9475 }
9476
9477 /* Close the input file and destroy the JPEG object. */
9478 if (fp)
9479 fclose ((FILE *) fp);
9480 jpeg_destroy_decompress (&cinfo);
9481
9482 /* If we already have an XImage, free that. */
9483 x_destroy_x_image (ximg);
9484
9485 /* Free pixmap and colors. */
9486 x_clear_image (f, img);
9487
9488 UNGCPRO;
9489 return 0;
9490 }
9491
9492 /* Create the JPEG decompression object. Let it read from fp.
9493 Read the JPEG image header. */
9494 jpeg_create_decompress (&cinfo);
9495
9496 if (NILP (specified_data))
9497 jpeg_stdio_src (&cinfo, (FILE *) fp);
9498 else
9499 jpeg_memory_src (&cinfo, SDATA (specified_data),
9500 SBYTES (specified_data));
9501
9502 jpeg_read_header (&cinfo, TRUE);
9503
9504 /* Customize decompression so that color quantization will be used.
9505 Start decompression. */
9506 cinfo.quantize_colors = TRUE;
9507 jpeg_start_decompress (&cinfo);
9508 width = img->width = cinfo.output_width;
9509 height = img->height = cinfo.output_height;
9510
9511 /* Create X image and pixmap. */
9512 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
9513 longjmp (mgr.setjmp_buffer, 2);
9514
9515 /* Allocate colors. When color quantization is used,
9516 cinfo.actual_number_of_colors has been set with the number of
9517 colors generated, and cinfo.colormap is a two-dimensional array
9518 of color indices in the range 0..cinfo.actual_number_of_colors.
9519 No more than 255 colors will be generated. */
9520 {
9521 int i, ir, ig, ib;
9522
9523 if (cinfo.out_color_components > 2)
9524 ir = 0, ig = 1, ib = 2;
9525 else if (cinfo.out_color_components > 1)
9526 ir = 0, ig = 1, ib = 0;
9527 else
9528 ir = 0, ig = 0, ib = 0;
9529
9530 /* Use the color table mechanism because it handles colors that
9531 cannot be allocated nicely. Such colors will be replaced with
9532 a default color, and we don't have to care about which colors
9533 can be freed safely, and which can't. */
9534 init_color_table ();
9535 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9536 * sizeof *colors);
9537
9538 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9539 {
9540 /* Multiply RGB values with 255 because X expects RGB values
9541 in the range 0..0xffff. */
9542 int r = cinfo.colormap[ir][i] << 8;
9543 int g = cinfo.colormap[ig][i] << 8;
9544 int b = cinfo.colormap[ib][i] << 8;
9545 colors[i] = lookup_rgb_color (f, r, g, b);
9546 }
9547
9548 /* Remember those colors actually allocated. */
9549 img->colors = colors_in_color_table (&img->ncolors);
9550 free_color_table ();
9551 }
9552
9553 /* Read pixels. */
9554 row_stride = width * cinfo.output_components;
9555 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
9556 row_stride, 1);
9557 for (y = 0; y < height; ++y)
9558 {
9559 jpeg_read_scanlines (&cinfo, buffer, 1);
9560 for (x = 0; x < cinfo.output_width; ++x)
9561 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
9562 }
9563
9564 /* Clean up. */
9565 jpeg_finish_decompress (&cinfo);
9566 jpeg_destroy_decompress (&cinfo);
9567 if (fp)
9568 fclose ((FILE *) fp);
9569
9570 /* Maybe fill in the background field while we have ximg handy. */
9571 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9572 IMAGE_BACKGROUND (img, f, ximg);
9573
9574 /* Put the image into the pixmap. */
9575 x_put_x_image (f, ximg, img->pixmap, width, height);
9576 x_destroy_x_image (ximg);
9577 UNGCPRO;
9578 return 1;
9579 }
9580
9581 #endif /* HAVE_JPEG */
9582
9583
9584 \f
9585 /***********************************************************************
9586 TIFF
9587 ***********************************************************************/
9588
9589 #if HAVE_TIFF
9590
9591 #include <tiffio.h>
9592
9593 static int tiff_image_p P_ ((Lisp_Object object));
9594 static int tiff_load P_ ((struct frame *f, struct image *img));
9595
9596 /* The symbol `tiff' identifying images of this type. */
9597
9598 Lisp_Object Qtiff;
9599
9600 /* Indices of image specification fields in tiff_format, below. */
9601
9602 enum tiff_keyword_index
9603 {
9604 TIFF_TYPE,
9605 TIFF_DATA,
9606 TIFF_FILE,
9607 TIFF_ASCENT,
9608 TIFF_MARGIN,
9609 TIFF_RELIEF,
9610 TIFF_ALGORITHM,
9611 TIFF_HEURISTIC_MASK,
9612 TIFF_MASK,
9613 TIFF_BACKGROUND,
9614 TIFF_LAST
9615 };
9616
9617 /* Vector of image_keyword structures describing the format
9618 of valid user-defined image specifications. */
9619
9620 static struct image_keyword tiff_format[TIFF_LAST] =
9621 {
9622 {":type", IMAGE_SYMBOL_VALUE, 1},
9623 {":data", IMAGE_STRING_VALUE, 0},
9624 {":file", IMAGE_STRING_VALUE, 0},
9625 {":ascent", IMAGE_ASCENT_VALUE, 0},
9626 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9627 {":relief", IMAGE_INTEGER_VALUE, 0},
9628 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9629 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9630 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9631 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9632 };
9633
9634 /* Structure describing the image type `tiff'. */
9635
9636 static struct image_type tiff_type =
9637 {
9638 &Qtiff,
9639 tiff_image_p,
9640 tiff_load,
9641 x_clear_image,
9642 NULL
9643 };
9644
9645
9646 /* Return non-zero if OBJECT is a valid TIFF image specification. */
9647
9648 static int
9649 tiff_image_p (object)
9650 Lisp_Object object;
9651 {
9652 struct image_keyword fmt[TIFF_LAST];
9653 bcopy (tiff_format, fmt, sizeof fmt);
9654
9655 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
9656 return 0;
9657
9658 /* Must specify either the :data or :file keyword. */
9659 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
9660 }
9661
9662
9663 /* Reading from a memory buffer for TIFF images Based on the PNG
9664 memory source, but we have to provide a lot of extra functions.
9665 Blah.
9666
9667 We really only need to implement read and seek, but I am not
9668 convinced that the TIFF library is smart enough not to destroy
9669 itself if we only hand it the function pointers we need to
9670 override. */
9671
9672 typedef struct
9673 {
9674 unsigned char *bytes;
9675 size_t len;
9676 int index;
9677 }
9678 tiff_memory_source;
9679
9680
9681 static size_t
9682 tiff_read_from_memory (data, buf, size)
9683 thandle_t data;
9684 tdata_t buf;
9685 tsize_t size;
9686 {
9687 tiff_memory_source *src = (tiff_memory_source *) data;
9688
9689 if (size > src->len - src->index)
9690 return (size_t) -1;
9691 bcopy (src->bytes + src->index, buf, size);
9692 src->index += size;
9693 return size;
9694 }
9695
9696
9697 static size_t
9698 tiff_write_from_memory (data, buf, size)
9699 thandle_t data;
9700 tdata_t buf;
9701 tsize_t size;
9702 {
9703 return (size_t) -1;
9704 }
9705
9706
9707 static toff_t
9708 tiff_seek_in_memory (data, off, whence)
9709 thandle_t data;
9710 toff_t off;
9711 int whence;
9712 {
9713 tiff_memory_source *src = (tiff_memory_source *) data;
9714 int idx;
9715
9716 switch (whence)
9717 {
9718 case SEEK_SET: /* Go from beginning of source. */
9719 idx = off;
9720 break;
9721
9722 case SEEK_END: /* Go from end of source. */
9723 idx = src->len + off;
9724 break;
9725
9726 case SEEK_CUR: /* Go from current position. */
9727 idx = src->index + off;
9728 break;
9729
9730 default: /* Invalid `whence'. */
9731 return -1;
9732 }
9733
9734 if (idx > src->len || idx < 0)
9735 return -1;
9736
9737 src->index = idx;
9738 return src->index;
9739 }
9740
9741
9742 static int
9743 tiff_close_memory (data)
9744 thandle_t data;
9745 {
9746 /* NOOP */
9747 return 0;
9748 }
9749
9750
9751 static int
9752 tiff_mmap_memory (data, pbase, psize)
9753 thandle_t data;
9754 tdata_t *pbase;
9755 toff_t *psize;
9756 {
9757 /* It is already _IN_ memory. */
9758 return 0;
9759 }
9760
9761
9762 static void
9763 tiff_unmap_memory (data, base, size)
9764 thandle_t data;
9765 tdata_t base;
9766 toff_t size;
9767 {
9768 /* We don't need to do this. */
9769 }
9770
9771
9772 static toff_t
9773 tiff_size_of_memory (data)
9774 thandle_t data;
9775 {
9776 return ((tiff_memory_source *) data)->len;
9777 }
9778
9779
9780 static void
9781 tiff_error_handler (title, format, ap)
9782 const char *title, *format;
9783 va_list ap;
9784 {
9785 char buf[512];
9786 int len;
9787
9788 len = sprintf (buf, "TIFF error: %s ", title);
9789 vsprintf (buf + len, format, ap);
9790 add_to_log (buf, Qnil, Qnil);
9791 }
9792
9793
9794 static void
9795 tiff_warning_handler (title, format, ap)
9796 const char *title, *format;
9797 va_list ap;
9798 {
9799 char buf[512];
9800 int len;
9801
9802 len = sprintf (buf, "TIFF warning: %s ", title);
9803 vsprintf (buf + len, format, ap);
9804 add_to_log (buf, Qnil, Qnil);
9805 }
9806
9807
9808 /* Load TIFF image IMG for use on frame F. Value is non-zero if
9809 successful. */
9810
9811 static int
9812 tiff_load (f, img)
9813 struct frame *f;
9814 struct image *img;
9815 {
9816 Lisp_Object file, specified_file;
9817 Lisp_Object specified_data;
9818 TIFF *tiff;
9819 int width, height, x, y;
9820 uint32 *buf;
9821 int rc;
9822 XImage *ximg;
9823 struct gcpro gcpro1;
9824 tiff_memory_source memsrc;
9825
9826 specified_file = image_spec_value (img->spec, QCfile, NULL);
9827 specified_data = image_spec_value (img->spec, QCdata, NULL);
9828 file = Qnil;
9829 GCPRO1 (file);
9830
9831 TIFFSetErrorHandler (tiff_error_handler);
9832 TIFFSetWarningHandler (tiff_warning_handler);
9833
9834 if (NILP (specified_data))
9835 {
9836 /* Read from a file */
9837 file = x_find_image_file (specified_file);
9838 if (!STRINGP (file))
9839 {
9840 image_error ("Cannot find image file `%s'", file, Qnil);
9841 UNGCPRO;
9842 return 0;
9843 }
9844
9845 /* Try to open the image file. */
9846 tiff = TIFFOpen (SDATA (file), "r");
9847 if (tiff == NULL)
9848 {
9849 image_error ("Cannot open `%s'", file, Qnil);
9850 UNGCPRO;
9851 return 0;
9852 }
9853 }
9854 else
9855 {
9856 /* Memory source! */
9857 memsrc.bytes = SDATA (specified_data);
9858 memsrc.len = SBYTES (specified_data);
9859 memsrc.index = 0;
9860
9861 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9862 (TIFFReadWriteProc) tiff_read_from_memory,
9863 (TIFFReadWriteProc) tiff_write_from_memory,
9864 tiff_seek_in_memory,
9865 tiff_close_memory,
9866 tiff_size_of_memory,
9867 tiff_mmap_memory,
9868 tiff_unmap_memory);
9869
9870 if (!tiff)
9871 {
9872 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
9873 UNGCPRO;
9874 return 0;
9875 }
9876 }
9877
9878 /* Get width and height of the image, and allocate a raster buffer
9879 of width x height 32-bit values. */
9880 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9881 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9882 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9883
9884 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9885 TIFFClose (tiff);
9886 if (!rc)
9887 {
9888 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
9889 xfree (buf);
9890 UNGCPRO;
9891 return 0;
9892 }
9893
9894 /* Create the X image and pixmap. */
9895 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
9896 {
9897 xfree (buf);
9898 UNGCPRO;
9899 return 0;
9900 }
9901
9902 /* Initialize the color table. */
9903 init_color_table ();
9904
9905 /* Process the pixel raster. Origin is in the lower-left corner. */
9906 for (y = 0; y < height; ++y)
9907 {
9908 uint32 *row = buf + y * width;
9909
9910 for (x = 0; x < width; ++x)
9911 {
9912 uint32 abgr = row[x];
9913 int r = TIFFGetR (abgr) << 8;
9914 int g = TIFFGetG (abgr) << 8;
9915 int b = TIFFGetB (abgr) << 8;
9916 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9917 }
9918 }
9919
9920 /* Remember the colors allocated for the image. Free the color table. */
9921 img->colors = colors_in_color_table (&img->ncolors);
9922 free_color_table ();
9923
9924 img->width = width;
9925 img->height = height;
9926
9927 /* Maybe fill in the background field while we have ximg handy. */
9928 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9929 IMAGE_BACKGROUND (img, f, ximg);
9930
9931 /* Put the image into the pixmap, then free the X image and its buffer. */
9932 x_put_x_image (f, ximg, img->pixmap, width, height);
9933 x_destroy_x_image (ximg);
9934 xfree (buf);
9935
9936 UNGCPRO;
9937 return 1;
9938 }
9939
9940 #endif /* HAVE_TIFF != 0 */
9941
9942
9943 \f
9944 /***********************************************************************
9945 GIF
9946 ***********************************************************************/
9947
9948 #if HAVE_GIF
9949
9950 #include <gif_lib.h>
9951
9952 static int gif_image_p P_ ((Lisp_Object object));
9953 static int gif_load P_ ((struct frame *f, struct image *img));
9954
9955 /* The symbol `gif' identifying images of this type. */
9956
9957 Lisp_Object Qgif;
9958
9959 /* Indices of image specification fields in gif_format, below. */
9960
9961 enum gif_keyword_index
9962 {
9963 GIF_TYPE,
9964 GIF_DATA,
9965 GIF_FILE,
9966 GIF_ASCENT,
9967 GIF_MARGIN,
9968 GIF_RELIEF,
9969 GIF_ALGORITHM,
9970 GIF_HEURISTIC_MASK,
9971 GIF_MASK,
9972 GIF_IMAGE,
9973 GIF_BACKGROUND,
9974 GIF_LAST
9975 };
9976
9977 /* Vector of image_keyword structures describing the format
9978 of valid user-defined image specifications. */
9979
9980 static struct image_keyword gif_format[GIF_LAST] =
9981 {
9982 {":type", IMAGE_SYMBOL_VALUE, 1},
9983 {":data", IMAGE_STRING_VALUE, 0},
9984 {":file", IMAGE_STRING_VALUE, 0},
9985 {":ascent", IMAGE_ASCENT_VALUE, 0},
9986 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9987 {":relief", IMAGE_INTEGER_VALUE, 0},
9988 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9989 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9990 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9991 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9992 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9993 };
9994
9995 /* Structure describing the image type `gif'. */
9996
9997 static struct image_type gif_type =
9998 {
9999 &Qgif,
10000 gif_image_p,
10001 gif_load,
10002 x_clear_image,
10003 NULL
10004 };
10005
10006
10007 /* Return non-zero if OBJECT is a valid GIF image specification. */
10008
10009 static int
10010 gif_image_p (object)
10011 Lisp_Object object;
10012 {
10013 struct image_keyword fmt[GIF_LAST];
10014 bcopy (gif_format, fmt, sizeof fmt);
10015
10016 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
10017 return 0;
10018
10019 /* Must specify either the :data or :file keyword. */
10020 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
10021 }
10022
10023
10024 /* Reading a GIF image from memory
10025 Based on the PNG memory stuff to a certain extent. */
10026
10027 typedef struct
10028 {
10029 unsigned char *bytes;
10030 size_t len;
10031 int index;
10032 }
10033 gif_memory_source;
10034
10035
10036 /* Make the current memory source available to gif_read_from_memory.
10037 It's done this way because not all versions of libungif support
10038 a UserData field in the GifFileType structure. */
10039 static gif_memory_source *current_gif_memory_src;
10040
10041 static int
10042 gif_read_from_memory (file, buf, len)
10043 GifFileType *file;
10044 GifByteType *buf;
10045 int len;
10046 {
10047 gif_memory_source *src = current_gif_memory_src;
10048
10049 if (len > src->len - src->index)
10050 return -1;
10051
10052 bcopy (src->bytes + src->index, buf, len);
10053 src->index += len;
10054 return len;
10055 }
10056
10057
10058 /* Load GIF image IMG for use on frame F. Value is non-zero if
10059 successful. */
10060
10061 static int
10062 gif_load (f, img)
10063 struct frame *f;
10064 struct image *img;
10065 {
10066 Lisp_Object file, specified_file;
10067 Lisp_Object specified_data;
10068 int rc, width, height, x, y, i;
10069 XImage *ximg;
10070 ColorMapObject *gif_color_map;
10071 unsigned long pixel_colors[256];
10072 GifFileType *gif;
10073 struct gcpro gcpro1;
10074 Lisp_Object image;
10075 int ino, image_left, image_top, image_width, image_height;
10076 gif_memory_source memsrc;
10077 unsigned char *raster;
10078
10079 specified_file = image_spec_value (img->spec, QCfile, NULL);
10080 specified_data = image_spec_value (img->spec, QCdata, NULL);
10081 file = Qnil;
10082 GCPRO1 (file);
10083
10084 if (NILP (specified_data))
10085 {
10086 file = x_find_image_file (specified_file);
10087 if (!STRINGP (file))
10088 {
10089 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10090 UNGCPRO;
10091 return 0;
10092 }
10093
10094 /* Open the GIF file. */
10095 gif = DGifOpenFileName (SDATA (file));
10096 if (gif == NULL)
10097 {
10098 image_error ("Cannot open `%s'", file, Qnil);
10099 UNGCPRO;
10100 return 0;
10101 }
10102 }
10103 else
10104 {
10105 /* Read from memory! */
10106 current_gif_memory_src = &memsrc;
10107 memsrc.bytes = SDATA (specified_data);
10108 memsrc.len = SBYTES (specified_data);
10109 memsrc.index = 0;
10110
10111 gif = DGifOpen(&memsrc, gif_read_from_memory);
10112 if (!gif)
10113 {
10114 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
10115 UNGCPRO;
10116 return 0;
10117 }
10118 }
10119
10120 /* Read entire contents. */
10121 rc = DGifSlurp (gif);
10122 if (rc == GIF_ERROR)
10123 {
10124 image_error ("Error reading `%s'", img->spec, Qnil);
10125 DGifCloseFile (gif);
10126 UNGCPRO;
10127 return 0;
10128 }
10129
10130 image = image_spec_value (img->spec, QCindex, NULL);
10131 ino = INTEGERP (image) ? XFASTINT (image) : 0;
10132 if (ino >= gif->ImageCount)
10133 {
10134 image_error ("Invalid image number `%s' in image `%s'",
10135 image, img->spec);
10136 DGifCloseFile (gif);
10137 UNGCPRO;
10138 return 0;
10139 }
10140
10141 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
10142 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
10143
10144 /* Create the X image and pixmap. */
10145 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
10146 {
10147 DGifCloseFile (gif);
10148 UNGCPRO;
10149 return 0;
10150 }
10151
10152 /* Allocate colors. */
10153 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10154 if (!gif_color_map)
10155 gif_color_map = gif->SColorMap;
10156 init_color_table ();
10157 bzero (pixel_colors, sizeof pixel_colors);
10158
10159 for (i = 0; i < gif_color_map->ColorCount; ++i)
10160 {
10161 int r = gif_color_map->Colors[i].Red << 8;
10162 int g = gif_color_map->Colors[i].Green << 8;
10163 int b = gif_color_map->Colors[i].Blue << 8;
10164 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10165 }
10166
10167 img->colors = colors_in_color_table (&img->ncolors);
10168 free_color_table ();
10169
10170 /* Clear the part of the screen image that are not covered by
10171 the image from the GIF file. Full animated GIF support
10172 requires more than can be done here (see the gif89 spec,
10173 disposal methods). Let's simply assume that the part
10174 not covered by a sub-image is in the frame's background color. */
10175 image_top = gif->SavedImages[ino].ImageDesc.Top;
10176 image_left = gif->SavedImages[ino].ImageDesc.Left;
10177 image_width = gif->SavedImages[ino].ImageDesc.Width;
10178 image_height = gif->SavedImages[ino].ImageDesc.Height;
10179
10180 for (y = 0; y < image_top; ++y)
10181 for (x = 0; x < width; ++x)
10182 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10183
10184 for (y = image_top + image_height; y < height; ++y)
10185 for (x = 0; x < width; ++x)
10186 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10187
10188 for (y = image_top; y < image_top + image_height; ++y)
10189 {
10190 for (x = 0; x < image_left; ++x)
10191 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10192 for (x = image_left + image_width; x < width; ++x)
10193 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10194 }
10195
10196 /* Read the GIF image into the X image. We use a local variable
10197 `raster' here because RasterBits below is a char *, and invites
10198 problems with bytes >= 0x80. */
10199 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
10200
10201 if (gif->SavedImages[ino].ImageDesc.Interlace)
10202 {
10203 static int interlace_start[] = {0, 4, 2, 1};
10204 static int interlace_increment[] = {8, 8, 4, 2};
10205 int pass;
10206 int row = interlace_start[0];
10207
10208 pass = 0;
10209
10210 for (y = 0; y < image_height; y++)
10211 {
10212 if (row >= image_height)
10213 {
10214 row = interlace_start[++pass];
10215 while (row >= image_height)
10216 row = interlace_start[++pass];
10217 }
10218
10219 for (x = 0; x < image_width; x++)
10220 {
10221 int i = raster[(y * image_width) + x];
10222 XPutPixel (ximg, x + image_left, row + image_top,
10223 pixel_colors[i]);
10224 }
10225
10226 row += interlace_increment[pass];
10227 }
10228 }
10229 else
10230 {
10231 for (y = 0; y < image_height; ++y)
10232 for (x = 0; x < image_width; ++x)
10233 {
10234 int i = raster[y * image_width + x];
10235 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
10236 }
10237 }
10238
10239 DGifCloseFile (gif);
10240
10241 /* Maybe fill in the background field while we have ximg handy. */
10242 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10243 IMAGE_BACKGROUND (img, f, ximg);
10244
10245 /* Put the image into the pixmap, then free the X image and its buffer. */
10246 x_put_x_image (f, ximg, img->pixmap, width, height);
10247 x_destroy_x_image (ximg);
10248
10249 UNGCPRO;
10250 return 1;
10251 }
10252
10253 #endif /* HAVE_GIF != 0 */
10254
10255
10256 \f
10257 /***********************************************************************
10258 Ghostscript
10259 ***********************************************************************/
10260
10261 static int gs_image_p P_ ((Lisp_Object object));
10262 static int gs_load P_ ((struct frame *f, struct image *img));
10263 static void gs_clear_image P_ ((struct frame *f, struct image *img));
10264
10265 /* The symbol `postscript' identifying images of this type. */
10266
10267 Lisp_Object Qpostscript;
10268
10269 /* Keyword symbols. */
10270
10271 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
10272
10273 /* Indices of image specification fields in gs_format, below. */
10274
10275 enum gs_keyword_index
10276 {
10277 GS_TYPE,
10278 GS_PT_WIDTH,
10279 GS_PT_HEIGHT,
10280 GS_FILE,
10281 GS_LOADER,
10282 GS_BOUNDING_BOX,
10283 GS_ASCENT,
10284 GS_MARGIN,
10285 GS_RELIEF,
10286 GS_ALGORITHM,
10287 GS_HEURISTIC_MASK,
10288 GS_MASK,
10289 GS_BACKGROUND,
10290 GS_LAST
10291 };
10292
10293 /* Vector of image_keyword structures describing the format
10294 of valid user-defined image specifications. */
10295
10296 static struct image_keyword gs_format[GS_LAST] =
10297 {
10298 {":type", IMAGE_SYMBOL_VALUE, 1},
10299 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10300 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10301 {":file", IMAGE_STRING_VALUE, 1},
10302 {":loader", IMAGE_FUNCTION_VALUE, 0},
10303 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
10304 {":ascent", IMAGE_ASCENT_VALUE, 0},
10305 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10306 {":relief", IMAGE_INTEGER_VALUE, 0},
10307 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10308 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10309 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10310 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10311 };
10312
10313 /* Structure describing the image type `ghostscript'. */
10314
10315 static struct image_type gs_type =
10316 {
10317 &Qpostscript,
10318 gs_image_p,
10319 gs_load,
10320 gs_clear_image,
10321 NULL
10322 };
10323
10324
10325 /* Free X resources of Ghostscript image IMG which is used on frame F. */
10326
10327 static void
10328 gs_clear_image (f, img)
10329 struct frame *f;
10330 struct image *img;
10331 {
10332 /* IMG->data.ptr_val may contain a recorded colormap. */
10333 xfree (img->data.ptr_val);
10334 x_clear_image (f, img);
10335 }
10336
10337
10338 /* Return non-zero if OBJECT is a valid Ghostscript image
10339 specification. */
10340
10341 static int
10342 gs_image_p (object)
10343 Lisp_Object object;
10344 {
10345 struct image_keyword fmt[GS_LAST];
10346 Lisp_Object tem;
10347 int i;
10348
10349 bcopy (gs_format, fmt, sizeof fmt);
10350
10351 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
10352 return 0;
10353
10354 /* Bounding box must be a list or vector containing 4 integers. */
10355 tem = fmt[GS_BOUNDING_BOX].value;
10356 if (CONSP (tem))
10357 {
10358 for (i = 0; i < 4; ++i, tem = XCDR (tem))
10359 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
10360 return 0;
10361 if (!NILP (tem))
10362 return 0;
10363 }
10364 else if (VECTORP (tem))
10365 {
10366 if (XVECTOR (tem)->size != 4)
10367 return 0;
10368 for (i = 0; i < 4; ++i)
10369 if (!INTEGERP (XVECTOR (tem)->contents[i]))
10370 return 0;
10371 }
10372 else
10373 return 0;
10374
10375 return 1;
10376 }
10377
10378
10379 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
10380 if successful. */
10381
10382 static int
10383 gs_load (f, img)
10384 struct frame *f;
10385 struct image *img;
10386 {
10387 char buffer[100];
10388 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
10389 struct gcpro gcpro1, gcpro2;
10390 Lisp_Object frame;
10391 double in_width, in_height;
10392 Lisp_Object pixel_colors = Qnil;
10393
10394 /* Compute pixel size of pixmap needed from the given size in the
10395 image specification. Sizes in the specification are in pt. 1 pt
10396 = 1/72 in, xdpi and ydpi are stored in the frame's X display
10397 info. */
10398 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
10399 in_width = XFASTINT (pt_width) / 72.0;
10400 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
10401 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
10402 in_height = XFASTINT (pt_height) / 72.0;
10403 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
10404
10405 /* Create the pixmap. */
10406 xassert (img->pixmap == None);
10407 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10408 img->width, img->height,
10409 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
10410
10411 if (!img->pixmap)
10412 {
10413 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
10414 return 0;
10415 }
10416
10417 /* Call the loader to fill the pixmap. It returns a process object
10418 if successful. We do not record_unwind_protect here because
10419 other places in redisplay like calling window scroll functions
10420 don't either. Let the Lisp loader use `unwind-protect' instead. */
10421 GCPRO2 (window_and_pixmap_id, pixel_colors);
10422
10423 sprintf (buffer, "%lu %lu",
10424 (unsigned long) FRAME_X_WINDOW (f),
10425 (unsigned long) img->pixmap);
10426 window_and_pixmap_id = build_string (buffer);
10427
10428 sprintf (buffer, "%lu %lu",
10429 FRAME_FOREGROUND_PIXEL (f),
10430 FRAME_BACKGROUND_PIXEL (f));
10431 pixel_colors = build_string (buffer);
10432
10433 XSETFRAME (frame, f);
10434 loader = image_spec_value (img->spec, QCloader, NULL);
10435 if (NILP (loader))
10436 loader = intern ("gs-load-image");
10437
10438 img->data.lisp_val = call6 (loader, frame, img->spec,
10439 make_number (img->width),
10440 make_number (img->height),
10441 window_and_pixmap_id,
10442 pixel_colors);
10443 UNGCPRO;
10444 return PROCESSP (img->data.lisp_val);
10445 }
10446
10447
10448 /* Kill the Ghostscript process that was started to fill PIXMAP on
10449 frame F. Called from XTread_socket when receiving an event
10450 telling Emacs that Ghostscript has finished drawing. */
10451
10452 void
10453 x_kill_gs_process (pixmap, f)
10454 Pixmap pixmap;
10455 struct frame *f;
10456 {
10457 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
10458 int class, i;
10459 struct image *img;
10460
10461 /* Find the image containing PIXMAP. */
10462 for (i = 0; i < c->used; ++i)
10463 if (c->images[i]->pixmap == pixmap)
10464 break;
10465
10466 /* Should someone in between have cleared the image cache, for
10467 instance, give up. */
10468 if (i == c->used)
10469 return;
10470
10471 /* Kill the GS process. We should have found PIXMAP in the image
10472 cache and its image should contain a process object. */
10473 img = c->images[i];
10474 xassert (PROCESSP (img->data.lisp_val));
10475 Fkill_process (img->data.lisp_val, Qnil);
10476 img->data.lisp_val = Qnil;
10477
10478 /* On displays with a mutable colormap, figure out the colors
10479 allocated for the image by looking at the pixels of an XImage for
10480 img->pixmap. */
10481 class = FRAME_X_VISUAL (f)->class;
10482 if (class != StaticColor && class != StaticGray && class != TrueColor)
10483 {
10484 XImage *ximg;
10485
10486 BLOCK_INPUT;
10487
10488 /* Try to get an XImage for img->pixmep. */
10489 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10490 0, 0, img->width, img->height, ~0, ZPixmap);
10491 if (ximg)
10492 {
10493 int x, y;
10494
10495 /* Initialize the color table. */
10496 init_color_table ();
10497
10498 /* For each pixel of the image, look its color up in the
10499 color table. After having done so, the color table will
10500 contain an entry for each color used by the image. */
10501 for (y = 0; y < img->height; ++y)
10502 for (x = 0; x < img->width; ++x)
10503 {
10504 unsigned long pixel = XGetPixel (ximg, x, y);
10505 lookup_pixel_color (f, pixel);
10506 }
10507
10508 /* Record colors in the image. Free color table and XImage. */
10509 img->colors = colors_in_color_table (&img->ncolors);
10510 free_color_table ();
10511 XDestroyImage (ximg);
10512
10513 #if 0 /* This doesn't seem to be the case. If we free the colors
10514 here, we get a BadAccess later in x_clear_image when
10515 freeing the colors. */
10516 /* We have allocated colors once, but Ghostscript has also
10517 allocated colors on behalf of us. So, to get the
10518 reference counts right, free them once. */
10519 if (img->ncolors)
10520 x_free_colors (f, img->colors, img->ncolors);
10521 #endif
10522 }
10523 else
10524 image_error ("Cannot get X image of `%s'; colors will not be freed",
10525 img->spec, Qnil);
10526
10527 UNBLOCK_INPUT;
10528 }
10529
10530 /* Now that we have the pixmap, compute mask and transform the
10531 image if requested. */
10532 BLOCK_INPUT;
10533 postprocess_image (f, img);
10534 UNBLOCK_INPUT;
10535 }
10536
10537
10538 \f
10539 /***********************************************************************
10540 Window properties
10541 ***********************************************************************/
10542
10543 DEFUN ("x-change-window-property", Fx_change_window_property,
10544 Sx_change_window_property, 2, 3, 0,
10545 doc: /* Change window property PROP to VALUE on the X window of FRAME.
10546 PROP and VALUE must be strings. FRAME nil or omitted means use the
10547 selected frame. Value is VALUE. */)
10548 (prop, value, frame)
10549 Lisp_Object frame, prop, value;
10550 {
10551 struct frame *f = check_x_frame (frame);
10552 Atom prop_atom;
10553
10554 CHECK_STRING (prop);
10555 CHECK_STRING (value);
10556
10557 BLOCK_INPUT;
10558 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
10559 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10560 prop_atom, XA_STRING, 8, PropModeReplace,
10561 SDATA (value), SCHARS (value));
10562
10563 /* Make sure the property is set when we return. */
10564 XFlush (FRAME_X_DISPLAY (f));
10565 UNBLOCK_INPUT;
10566
10567 return value;
10568 }
10569
10570
10571 DEFUN ("x-delete-window-property", Fx_delete_window_property,
10572 Sx_delete_window_property, 1, 2, 0,
10573 doc: /* Remove window property PROP from X window of FRAME.
10574 FRAME nil or omitted means use the selected frame. Value is PROP. */)
10575 (prop, frame)
10576 Lisp_Object prop, frame;
10577 {
10578 struct frame *f = check_x_frame (frame);
10579 Atom prop_atom;
10580
10581 CHECK_STRING (prop);
10582 BLOCK_INPUT;
10583 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
10584 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10585
10586 /* Make sure the property is removed when we return. */
10587 XFlush (FRAME_X_DISPLAY (f));
10588 UNBLOCK_INPUT;
10589
10590 return prop;
10591 }
10592
10593
10594 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10595 1, 2, 0,
10596 doc: /* Value is the value of window property PROP on FRAME.
10597 If FRAME is nil or omitted, use the selected frame. Value is nil
10598 if FRAME hasn't a property with name PROP or if PROP has no string
10599 value. */)
10600 (prop, frame)
10601 Lisp_Object prop, frame;
10602 {
10603 struct frame *f = check_x_frame (frame);
10604 Atom prop_atom;
10605 int rc;
10606 Lisp_Object prop_value = Qnil;
10607 char *tmp_data = NULL;
10608 Atom actual_type;
10609 int actual_format;
10610 unsigned long actual_size, bytes_remaining;
10611
10612 CHECK_STRING (prop);
10613 BLOCK_INPUT;
10614 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
10615 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10616 prop_atom, 0, 0, False, XA_STRING,
10617 &actual_type, &actual_format, &actual_size,
10618 &bytes_remaining, (unsigned char **) &tmp_data);
10619 if (rc == Success)
10620 {
10621 int size = bytes_remaining;
10622
10623 XFree (tmp_data);
10624 tmp_data = NULL;
10625
10626 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10627 prop_atom, 0, bytes_remaining,
10628 False, XA_STRING,
10629 &actual_type, &actual_format,
10630 &actual_size, &bytes_remaining,
10631 (unsigned char **) &tmp_data);
10632 if (rc == Success && tmp_data)
10633 prop_value = make_string (tmp_data, size);
10634
10635 XFree (tmp_data);
10636 }
10637
10638 UNBLOCK_INPUT;
10639 return prop_value;
10640 }
10641
10642
10643 \f
10644 /***********************************************************************
10645 Busy cursor
10646 ***********************************************************************/
10647
10648 /* If non-null, an asynchronous timer that, when it expires, displays
10649 an hourglass cursor on all frames. */
10650
10651 static struct atimer *hourglass_atimer;
10652
10653 /* Non-zero means an hourglass cursor is currently shown. */
10654
10655 static int hourglass_shown_p;
10656
10657 /* Number of seconds to wait before displaying an hourglass cursor. */
10658
10659 static Lisp_Object Vhourglass_delay;
10660
10661 /* Default number of seconds to wait before displaying an hourglass
10662 cursor. */
10663
10664 #define DEFAULT_HOURGLASS_DELAY 1
10665
10666 /* Function prototypes. */
10667
10668 static void show_hourglass P_ ((struct atimer *));
10669 static void hide_hourglass P_ ((void));
10670
10671
10672 /* Cancel a currently active hourglass timer, and start a new one. */
10673
10674 void
10675 start_hourglass ()
10676 {
10677 EMACS_TIME delay;
10678 int secs, usecs = 0;
10679
10680 cancel_hourglass ();
10681
10682 if (INTEGERP (Vhourglass_delay)
10683 && XINT (Vhourglass_delay) > 0)
10684 secs = XFASTINT (Vhourglass_delay);
10685 else if (FLOATP (Vhourglass_delay)
10686 && XFLOAT_DATA (Vhourglass_delay) > 0)
10687 {
10688 Lisp_Object tem;
10689 tem = Ftruncate (Vhourglass_delay, Qnil);
10690 secs = XFASTINT (tem);
10691 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
10692 }
10693 else
10694 secs = DEFAULT_HOURGLASS_DELAY;
10695
10696 EMACS_SET_SECS_USECS (delay, secs, usecs);
10697 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
10698 show_hourglass, NULL);
10699 }
10700
10701
10702 /* Cancel the hourglass cursor timer if active, hide a busy cursor if
10703 shown. */
10704
10705 void
10706 cancel_hourglass ()
10707 {
10708 if (hourglass_atimer)
10709 {
10710 cancel_atimer (hourglass_atimer);
10711 hourglass_atimer = NULL;
10712 }
10713
10714 if (hourglass_shown_p)
10715 hide_hourglass ();
10716 }
10717
10718
10719 /* Timer function of hourglass_atimer. TIMER is equal to
10720 hourglass_atimer.
10721
10722 Display an hourglass pointer on all frames by mapping the frames'
10723 hourglass_window. Set the hourglass_p flag in the frames'
10724 output_data.x structure to indicate that an hourglass cursor is
10725 shown on the frames. */
10726
10727 static void
10728 show_hourglass (timer)
10729 struct atimer *timer;
10730 {
10731 /* The timer implementation will cancel this timer automatically
10732 after this function has run. Set hourglass_atimer to null
10733 so that we know the timer doesn't have to be canceled. */
10734 hourglass_atimer = NULL;
10735
10736 if (!hourglass_shown_p)
10737 {
10738 Lisp_Object rest, frame;
10739
10740 BLOCK_INPUT;
10741
10742 FOR_EACH_FRAME (rest, frame)
10743 {
10744 struct frame *f = XFRAME (frame);
10745
10746 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
10747 {
10748 Display *dpy = FRAME_X_DISPLAY (f);
10749
10750 #ifdef USE_X_TOOLKIT
10751 if (f->output_data.x->widget)
10752 #else
10753 if (FRAME_OUTER_WINDOW (f))
10754 #endif
10755 {
10756 f->output_data.x->hourglass_p = 1;
10757
10758 if (!f->output_data.x->hourglass_window)
10759 {
10760 unsigned long mask = CWCursor;
10761 XSetWindowAttributes attrs;
10762
10763 attrs.cursor = f->output_data.x->hourglass_cursor;
10764
10765 f->output_data.x->hourglass_window
10766 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
10767 0, 0, 32000, 32000, 0, 0,
10768 InputOnly,
10769 CopyFromParent,
10770 mask, &attrs);
10771 }
10772
10773 XMapRaised (dpy, f->output_data.x->hourglass_window);
10774 XFlush (dpy);
10775 }
10776 }
10777 }
10778
10779 hourglass_shown_p = 1;
10780 UNBLOCK_INPUT;
10781 }
10782 }
10783
10784
10785 /* Hide the hourglass pointer on all frames, if it is currently
10786 shown. */
10787
10788 static void
10789 hide_hourglass ()
10790 {
10791 if (hourglass_shown_p)
10792 {
10793 Lisp_Object rest, frame;
10794
10795 BLOCK_INPUT;
10796 FOR_EACH_FRAME (rest, frame)
10797 {
10798 struct frame *f = XFRAME (frame);
10799
10800 if (FRAME_X_P (f)
10801 /* Watch out for newly created frames. */
10802 && f->output_data.x->hourglass_window)
10803 {
10804 XUnmapWindow (FRAME_X_DISPLAY (f),
10805 f->output_data.x->hourglass_window);
10806 /* Sync here because XTread_socket looks at the
10807 hourglass_p flag that is reset to zero below. */
10808 XSync (FRAME_X_DISPLAY (f), False);
10809 f->output_data.x->hourglass_p = 0;
10810 }
10811 }
10812
10813 hourglass_shown_p = 0;
10814 UNBLOCK_INPUT;
10815 }
10816 }
10817
10818
10819 \f
10820 /***********************************************************************
10821 Tool tips
10822 ***********************************************************************/
10823
10824 static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
10825 Lisp_Object, Lisp_Object));
10826 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
10827 Lisp_Object, int, int, int *, int *));
10828
10829 /* The frame of a currently visible tooltip. */
10830
10831 Lisp_Object tip_frame;
10832
10833 /* If non-nil, a timer started that hides the last tooltip when it
10834 fires. */
10835
10836 Lisp_Object tip_timer;
10837 Window tip_window;
10838
10839 /* If non-nil, a vector of 3 elements containing the last args
10840 with which x-show-tip was called. See there. */
10841
10842 Lisp_Object last_show_tip_args;
10843
10844 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
10845
10846 Lisp_Object Vx_max_tooltip_size;
10847
10848
10849 static Lisp_Object
10850 unwind_create_tip_frame (frame)
10851 Lisp_Object frame;
10852 {
10853 Lisp_Object deleted;
10854
10855 deleted = unwind_create_frame (frame);
10856 if (EQ (deleted, Qt))
10857 {
10858 tip_window = None;
10859 tip_frame = Qnil;
10860 }
10861
10862 return deleted;
10863 }
10864
10865
10866 /* Create a frame for a tooltip on the display described by DPYINFO.
10867 PARMS is a list of frame parameters. TEXT is the string to
10868 display in the tip frame. Value is the frame.
10869
10870 Note that functions called here, esp. x_default_parameter can
10871 signal errors, for instance when a specified color name is
10872 undefined. We have to make sure that we're in a consistent state
10873 when this happens. */
10874
10875 static Lisp_Object
10876 x_create_tip_frame (dpyinfo, parms, text)
10877 struct x_display_info *dpyinfo;
10878 Lisp_Object parms, text;
10879 {
10880 struct frame *f;
10881 Lisp_Object frame, tem;
10882 Lisp_Object name;
10883 long window_prompting = 0;
10884 int width, height;
10885 int count = SPECPDL_INDEX ();
10886 struct gcpro gcpro1, gcpro2, gcpro3;
10887 struct kboard *kb;
10888 int face_change_count_before = face_change_count;
10889 Lisp_Object buffer;
10890 struct buffer *old_buffer;
10891
10892 check_x ();
10893
10894 /* Use this general default value to start with until we know if
10895 this frame has a specified name. */
10896 Vx_resource_name = Vinvocation_name;
10897
10898 #ifdef MULTI_KBOARD
10899 kb = dpyinfo->kboard;
10900 #else
10901 kb = &the_only_kboard;
10902 #endif
10903
10904 /* Get the name of the frame to use for resource lookup. */
10905 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10906 if (!STRINGP (name)
10907 && !EQ (name, Qunbound)
10908 && !NILP (name))
10909 error ("Invalid frame name--not a string or nil");
10910 Vx_resource_name = name;
10911
10912 frame = Qnil;
10913 GCPRO3 (parms, name, frame);
10914 f = make_frame (1);
10915 XSETFRAME (frame, f);
10916
10917 buffer = Fget_buffer_create (build_string (" *tip*"));
10918 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10919 old_buffer = current_buffer;
10920 set_buffer_internal_1 (XBUFFER (buffer));
10921 current_buffer->truncate_lines = Qnil;
10922 Ferase_buffer ();
10923 Finsert (1, &text);
10924 set_buffer_internal_1 (old_buffer);
10925
10926 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
10927 record_unwind_protect (unwind_create_tip_frame, frame);
10928
10929 /* By setting the output method, we're essentially saying that
10930 the frame is live, as per FRAME_LIVE_P. If we get a signal
10931 from this point on, x_destroy_window might screw up reference
10932 counts etc. */
10933 f->output_method = output_x_window;
10934 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10935 bzero (f->output_data.x, sizeof (struct x_output));
10936 f->output_data.x->icon_bitmap = -1;
10937 f->output_data.x->fontset = -1;
10938 f->output_data.x->scroll_bar_foreground_pixel = -1;
10939 f->output_data.x->scroll_bar_background_pixel = -1;
10940 #ifdef USE_TOOLKIT_SCROLL_BARS
10941 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
10942 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
10943 #endif /* USE_TOOLKIT_SCROLL_BARS */
10944 f->icon_name = Qnil;
10945 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
10946 #if GLYPH_DEBUG
10947 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
10948 dpyinfo_refcount = dpyinfo->reference_count;
10949 #endif /* GLYPH_DEBUG */
10950 #ifdef MULTI_KBOARD
10951 FRAME_KBOARD (f) = kb;
10952 #endif
10953 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10954 f->output_data.x->explicit_parent = 0;
10955
10956 /* These colors will be set anyway later, but it's important
10957 to get the color reference counts right, so initialize them! */
10958 {
10959 Lisp_Object black;
10960 struct gcpro gcpro1;
10961
10962 black = build_string ("black");
10963 GCPRO1 (black);
10964 f->output_data.x->foreground_pixel
10965 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10966 f->output_data.x->background_pixel
10967 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10968 f->output_data.x->cursor_pixel
10969 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10970 f->output_data.x->cursor_foreground_pixel
10971 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10972 f->output_data.x->border_pixel
10973 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10974 f->output_data.x->mouse_pixel
10975 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10976 UNGCPRO;
10977 }
10978
10979 /* Set the name; the functions to which we pass f expect the name to
10980 be set. */
10981 if (EQ (name, Qunbound) || NILP (name))
10982 {
10983 f->name = build_string (dpyinfo->x_id_name);
10984 f->explicit_name = 0;
10985 }
10986 else
10987 {
10988 f->name = name;
10989 f->explicit_name = 1;
10990 /* use the frame's title when getting resources for this frame. */
10991 specbind (Qx_resource_name, name);
10992 }
10993
10994 /* Extract the window parameters from the supplied values that are
10995 needed to determine window geometry. */
10996 {
10997 Lisp_Object font;
10998
10999 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
11000
11001 BLOCK_INPUT;
11002 /* First, try whatever font the caller has specified. */
11003 if (STRINGP (font))
11004 {
11005 tem = Fquery_fontset (font, Qnil);
11006 if (STRINGP (tem))
11007 font = x_new_fontset (f, SDATA (tem));
11008 else
11009 font = x_new_font (f, SDATA (font));
11010 }
11011
11012 /* Try out a font which we hope has bold and italic variations. */
11013 if (!STRINGP (font))
11014 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
11015 if (!STRINGP (font))
11016 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11017 if (! STRINGP (font))
11018 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11019 if (! STRINGP (font))
11020 /* This was formerly the first thing tried, but it finds too many fonts
11021 and takes too long. */
11022 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
11023 /* If those didn't work, look for something which will at least work. */
11024 if (! STRINGP (font))
11025 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
11026 UNBLOCK_INPUT;
11027 if (! STRINGP (font))
11028 font = build_string ("fixed");
11029
11030 x_default_parameter (f, parms, Qfont, font,
11031 "font", "Font", RES_TYPE_STRING);
11032 }
11033
11034 x_default_parameter (f, parms, Qborder_width, make_number (2),
11035 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
11036
11037 /* This defaults to 2 in order to match xterm. We recognize either
11038 internalBorderWidth or internalBorder (which is what xterm calls
11039 it). */
11040 if (NILP (Fassq (Qinternal_border_width, parms)))
11041 {
11042 Lisp_Object value;
11043
11044 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
11045 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
11046 if (! EQ (value, Qunbound))
11047 parms = Fcons (Fcons (Qinternal_border_width, value),
11048 parms);
11049 }
11050
11051 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
11052 "internalBorderWidth", "internalBorderWidth",
11053 RES_TYPE_NUMBER);
11054
11055 /* Also do the stuff which must be set before the window exists. */
11056 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
11057 "foreground", "Foreground", RES_TYPE_STRING);
11058 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
11059 "background", "Background", RES_TYPE_STRING);
11060 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
11061 "pointerColor", "Foreground", RES_TYPE_STRING);
11062 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
11063 "cursorColor", "Foreground", RES_TYPE_STRING);
11064 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
11065 "borderColor", "BorderColor", RES_TYPE_STRING);
11066
11067 /* Init faces before x_default_parameter is called for scroll-bar
11068 parameters because that function calls x_set_scroll_bar_width,
11069 which calls change_frame_size, which calls Fset_window_buffer,
11070 which runs hooks, which call Fvertical_motion. At the end, we
11071 end up in init_iterator with a null face cache, which should not
11072 happen. */
11073 init_frame_faces (f);
11074
11075 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
11076 window_prompting = x_figure_window_size (f, parms);
11077
11078 if (window_prompting & XNegative)
11079 {
11080 if (window_prompting & YNegative)
11081 f->output_data.x->win_gravity = SouthEastGravity;
11082 else
11083 f->output_data.x->win_gravity = NorthEastGravity;
11084 }
11085 else
11086 {
11087 if (window_prompting & YNegative)
11088 f->output_data.x->win_gravity = SouthWestGravity;
11089 else
11090 f->output_data.x->win_gravity = NorthWestGravity;
11091 }
11092
11093 f->output_data.x->size_hint_flags = window_prompting;
11094 {
11095 XSetWindowAttributes attrs;
11096 unsigned long mask;
11097
11098 BLOCK_INPUT;
11099 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
11100 if (DoesSaveUnders (dpyinfo->screen))
11101 mask |= CWSaveUnder;
11102
11103 /* Window managers look at the override-redirect flag to determine
11104 whether or net to give windows a decoration (Xlib spec, chapter
11105 3.2.8). */
11106 attrs.override_redirect = True;
11107 attrs.save_under = True;
11108 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
11109 /* Arrange for getting MapNotify and UnmapNotify events. */
11110 attrs.event_mask = StructureNotifyMask;
11111 tip_window
11112 = FRAME_X_WINDOW (f)
11113 = XCreateWindow (FRAME_X_DISPLAY (f),
11114 FRAME_X_DISPLAY_INFO (f)->root_window,
11115 /* x, y, width, height */
11116 0, 0, 1, 1,
11117 /* Border. */
11118 1,
11119 CopyFromParent, InputOutput, CopyFromParent,
11120 mask, &attrs);
11121 UNBLOCK_INPUT;
11122 }
11123
11124 x_make_gc (f);
11125
11126 x_default_parameter (f, parms, Qauto_raise, Qnil,
11127 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11128 x_default_parameter (f, parms, Qauto_lower, Qnil,
11129 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11130 x_default_parameter (f, parms, Qcursor_type, Qbox,
11131 "cursorType", "CursorType", RES_TYPE_SYMBOL);
11132
11133 /* Dimensions, especially f->height, must be done via change_frame_size.
11134 Change will not be effected unless different from the current
11135 f->height. */
11136 width = f->width;
11137 height = f->height;
11138 f->height = 0;
11139 SET_FRAME_WIDTH (f, 0);
11140 change_frame_size (f, height, width, 1, 0, 0);
11141
11142 /* Set up faces after all frame parameters are known. This call
11143 also merges in face attributes specified for new frames.
11144
11145 Frame parameters may be changed if .Xdefaults contains
11146 specifications for the default font. For example, if there is an
11147 `Emacs.default.attributeBackground: pink', the `background-color'
11148 attribute of the frame get's set, which let's the internal border
11149 of the tooltip frame appear in pink. Prevent this. */
11150 {
11151 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
11152
11153 /* Set tip_frame here, so that */
11154 tip_frame = frame;
11155 call1 (Qface_set_after_frame_default, frame);
11156
11157 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
11158 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
11159 Qnil));
11160 }
11161
11162 f->no_split = 1;
11163
11164 UNGCPRO;
11165
11166 /* It is now ok to make the frame official even if we get an error
11167 below. And the frame needs to be on Vframe_list or making it
11168 visible won't work. */
11169 Vframe_list = Fcons (frame, Vframe_list);
11170
11171 /* Now that the frame is official, it counts as a reference to
11172 its display. */
11173 FRAME_X_DISPLAY_INFO (f)->reference_count++;
11174
11175 /* Setting attributes of faces of the tooltip frame from resources
11176 and similar will increment face_change_count, which leads to the
11177 clearing of all current matrices. Since this isn't necessary
11178 here, avoid it by resetting face_change_count to the value it
11179 had before we created the tip frame. */
11180 face_change_count = face_change_count_before;
11181
11182 /* Discard the unwind_protect. */
11183 return unbind_to (count, frame);
11184 }
11185
11186
11187 /* Compute where to display tip frame F. PARMS is the list of frame
11188 parameters for F. DX and DY are specified offsets from the current
11189 location of the mouse. WIDTH and HEIGHT are the width and height
11190 of the tooltip. Return coordinates relative to the root window of
11191 the display in *ROOT_X, and *ROOT_Y. */
11192
11193 static void
11194 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
11195 struct frame *f;
11196 Lisp_Object parms, dx, dy;
11197 int width, height;
11198 int *root_x, *root_y;
11199 {
11200 Lisp_Object left, top;
11201 int win_x, win_y;
11202 Window root, child;
11203 unsigned pmask;
11204
11205 /* User-specified position? */
11206 left = Fcdr (Fassq (Qleft, parms));
11207 top = Fcdr (Fassq (Qtop, parms));
11208
11209 /* Move the tooltip window where the mouse pointer is. Resize and
11210 show it. */
11211 if (!INTEGERP (left) || !INTEGERP (top))
11212 {
11213 BLOCK_INPUT;
11214 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
11215 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
11216 UNBLOCK_INPUT;
11217 }
11218
11219 if (INTEGERP (top))
11220 *root_y = XINT (top);
11221 else if (*root_y + XINT (dy) - height < 0)
11222 *root_y -= XINT (dy);
11223 else
11224 {
11225 *root_y -= height;
11226 *root_y += XINT (dy);
11227 }
11228
11229 if (INTEGERP (left))
11230 *root_x = XINT (left);
11231 else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
11232 /* It fits to the right of the pointer. */
11233 *root_x += XINT (dx);
11234 else if (width + XINT (dx) <= *root_x)
11235 /* It fits to the left of the pointer. */
11236 *root_x -= width + XINT (dx);
11237 else
11238 /* Put it left-justified on the screen--it ought to fit that way. */
11239 *root_x = 0;
11240 }
11241
11242
11243 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
11244 doc: /* Show STRING in a "tooltip" window on frame FRAME.
11245 A tooltip window is a small X window displaying a string.
11246
11247 FRAME nil or omitted means use the selected frame.
11248
11249 PARMS is an optional list of frame parameters which can be used to
11250 change the tooltip's appearance.
11251
11252 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
11253 means use the default timeout of 5 seconds.
11254
11255 If the list of frame parameters PARAMS contains a `left' parameters,
11256 the tooltip is displayed at that x-position. Otherwise it is
11257 displayed at the mouse position, with offset DX added (default is 5 if
11258 DX isn't specified). Likewise for the y-position; if a `top' frame
11259 parameter is specified, it determines the y-position of the tooltip
11260 window, otherwise it is displayed at the mouse position, with offset
11261 DY added (default is -10).
11262
11263 A tooltip's maximum size is specified by `x-max-tooltip-size'.
11264 Text larger than the specified size is clipped. */)
11265 (string, frame, parms, timeout, dx, dy)
11266 Lisp_Object string, frame, parms, timeout, dx, dy;
11267 {
11268 struct frame *f;
11269 struct window *w;
11270 int root_x, root_y;
11271 struct buffer *old_buffer;
11272 struct text_pos pos;
11273 int i, width, height;
11274 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
11275 int old_windows_or_buffers_changed = windows_or_buffers_changed;
11276 int count = SPECPDL_INDEX ();
11277
11278 specbind (Qinhibit_redisplay, Qt);
11279
11280 GCPRO4 (string, parms, frame, timeout);
11281
11282 CHECK_STRING (string);
11283 f = check_x_frame (frame);
11284 if (NILP (timeout))
11285 timeout = make_number (5);
11286 else
11287 CHECK_NATNUM (timeout);
11288
11289 if (NILP (dx))
11290 dx = make_number (5);
11291 else
11292 CHECK_NUMBER (dx);
11293
11294 if (NILP (dy))
11295 dy = make_number (-10);
11296 else
11297 CHECK_NUMBER (dy);
11298
11299 if (NILP (last_show_tip_args))
11300 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
11301
11302 if (!NILP (tip_frame))
11303 {
11304 Lisp_Object last_string = AREF (last_show_tip_args, 0);
11305 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
11306 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
11307
11308 if (EQ (frame, last_frame)
11309 && !NILP (Fequal (last_string, string))
11310 && !NILP (Fequal (last_parms, parms)))
11311 {
11312 struct frame *f = XFRAME (tip_frame);
11313
11314 /* Only DX and DY have changed. */
11315 if (!NILP (tip_timer))
11316 {
11317 Lisp_Object timer = tip_timer;
11318 tip_timer = Qnil;
11319 call1 (Qcancel_timer, timer);
11320 }
11321
11322 BLOCK_INPUT;
11323 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
11324 PIXEL_HEIGHT (f), &root_x, &root_y);
11325 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11326 root_x, root_y);
11327 UNBLOCK_INPUT;
11328 goto start_timer;
11329 }
11330 }
11331
11332 /* Hide a previous tip, if any. */
11333 Fx_hide_tip ();
11334
11335 ASET (last_show_tip_args, 0, string);
11336 ASET (last_show_tip_args, 1, frame);
11337 ASET (last_show_tip_args, 2, parms);
11338
11339 /* Add default values to frame parameters. */
11340 if (NILP (Fassq (Qname, parms)))
11341 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11342 if (NILP (Fassq (Qinternal_border_width, parms)))
11343 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11344 if (NILP (Fassq (Qborder_width, parms)))
11345 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11346 if (NILP (Fassq (Qborder_color, parms)))
11347 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11348 if (NILP (Fassq (Qbackground_color, parms)))
11349 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11350 parms);
11351
11352 /* Create a frame for the tooltip, and record it in the global
11353 variable tip_frame. */
11354 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
11355 f = XFRAME (frame);
11356
11357 /* Set up the frame's root window. */
11358 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11359 w->left = w->top = make_number (0);
11360
11361 if (CONSP (Vx_max_tooltip_size)
11362 && INTEGERP (XCAR (Vx_max_tooltip_size))
11363 && XINT (XCAR (Vx_max_tooltip_size)) > 0
11364 && INTEGERP (XCDR (Vx_max_tooltip_size))
11365 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
11366 {
11367 w->width = XCAR (Vx_max_tooltip_size);
11368 w->height = XCDR (Vx_max_tooltip_size);
11369 }
11370 else
11371 {
11372 w->width = make_number (80);
11373 w->height = make_number (40);
11374 }
11375
11376 f->window_width = XINT (w->width);
11377 adjust_glyphs (f);
11378 w->pseudo_window_p = 1;
11379
11380 /* Display the tooltip text in a temporary buffer. */
11381 old_buffer = current_buffer;
11382 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
11383 current_buffer->truncate_lines = Qnil;
11384 clear_glyph_matrix (w->desired_matrix);
11385 clear_glyph_matrix (w->current_matrix);
11386 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11387 try_window (FRAME_ROOT_WINDOW (f), pos);
11388
11389 /* Compute width and height of the tooltip. */
11390 width = height = 0;
11391 for (i = 0; i < w->desired_matrix->nrows; ++i)
11392 {
11393 struct glyph_row *row = &w->desired_matrix->rows[i];
11394 struct glyph *last;
11395 int row_width;
11396
11397 /* Stop at the first empty row at the end. */
11398 if (!row->enabled_p || !row->displays_text_p)
11399 break;
11400
11401 /* Let the row go over the full width of the frame. */
11402 row->full_width_p = 1;
11403
11404 /* There's a glyph at the end of rows that is used to place
11405 the cursor there. Don't include the width of this glyph. */
11406 if (row->used[TEXT_AREA])
11407 {
11408 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11409 row_width = row->pixel_width - last->pixel_width;
11410 }
11411 else
11412 row_width = row->pixel_width;
11413
11414 height += row->height;
11415 width = max (width, row_width);
11416 }
11417
11418 /* Add the frame's internal border to the width and height the X
11419 window should have. */
11420 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11421 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11422
11423 /* Move the tooltip window where the mouse pointer is. Resize and
11424 show it. */
11425 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
11426
11427 BLOCK_INPUT;
11428 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11429 root_x, root_y, width, height);
11430 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11431 UNBLOCK_INPUT;
11432
11433 /* Draw into the window. */
11434 w->must_be_updated_p = 1;
11435 update_single_window (w, 1);
11436
11437 /* Restore original current buffer. */
11438 set_buffer_internal_1 (old_buffer);
11439 windows_or_buffers_changed = old_windows_or_buffers_changed;
11440
11441 start_timer:
11442 /* Let the tip disappear after timeout seconds. */
11443 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11444 intern ("x-hide-tip"));
11445
11446 UNGCPRO;
11447 return unbind_to (count, Qnil);
11448 }
11449
11450
11451 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
11452 doc: /* Hide the current tooltip window, if there is any.
11453 Value is t if tooltip was open, nil otherwise. */)
11454 ()
11455 {
11456 int count;
11457 Lisp_Object deleted, frame, timer;
11458 struct gcpro gcpro1, gcpro2;
11459
11460 /* Return quickly if nothing to do. */
11461 if (NILP (tip_timer) && NILP (tip_frame))
11462 return Qnil;
11463
11464 frame = tip_frame;
11465 timer = tip_timer;
11466 GCPRO2 (frame, timer);
11467 tip_frame = tip_timer = deleted = Qnil;
11468
11469 count = SPECPDL_INDEX ();
11470 specbind (Qinhibit_redisplay, Qt);
11471 specbind (Qinhibit_quit, Qt);
11472
11473 if (!NILP (timer))
11474 call1 (Qcancel_timer, timer);
11475
11476 if (FRAMEP (frame))
11477 {
11478 Fdelete_frame (frame, Qnil);
11479 deleted = Qt;
11480
11481 #ifdef USE_LUCID
11482 /* Bloodcurdling hack alert: The Lucid menu bar widget's
11483 redisplay procedure is not called when a tip frame over menu
11484 items is unmapped. Redisplay the menu manually... */
11485 {
11486 struct frame *f = SELECTED_FRAME ();
11487 Widget w = f->output_data.x->menubar_widget;
11488 extern void xlwmenu_redisplay P_ ((Widget));
11489
11490 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
11491 && w != NULL)
11492 {
11493 BLOCK_INPUT;
11494 xlwmenu_redisplay (w);
11495 UNBLOCK_INPUT;
11496 }
11497 }
11498 #endif /* USE_LUCID */
11499 }
11500
11501 UNGCPRO;
11502 return unbind_to (count, deleted);
11503 }
11504
11505
11506 \f
11507 /***********************************************************************
11508 File selection dialog
11509 ***********************************************************************/
11510
11511 #ifdef USE_MOTIF
11512
11513 /* Callback for "OK" and "Cancel" on file selection dialog. */
11514
11515 static void
11516 file_dialog_cb (widget, client_data, call_data)
11517 Widget widget;
11518 XtPointer call_data, client_data;
11519 {
11520 int *result = (int *) client_data;
11521 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
11522 *result = cb->reason;
11523 }
11524
11525
11526 /* Callback for unmapping a file selection dialog. This is used to
11527 capture the case where a dialog is closed via a window manager's
11528 closer button, for example. Using a XmNdestroyCallback didn't work
11529 in this case. */
11530
11531 static void
11532 file_dialog_unmap_cb (widget, client_data, call_data)
11533 Widget widget;
11534 XtPointer call_data, client_data;
11535 {
11536 int *result = (int *) client_data;
11537 *result = XmCR_CANCEL;
11538 }
11539
11540
11541 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
11542 doc: /* Read file name, prompting with PROMPT in directory DIR.
11543 Use a file selection dialog.
11544 Select DEFAULT-FILENAME in the dialog's file selection box, if
11545 specified. Don't let the user enter a file name in the file
11546 selection dialog's entry field, if MUSTMATCH is non-nil. */)
11547 (prompt, dir, default_filename, mustmatch)
11548 Lisp_Object prompt, dir, default_filename, mustmatch;
11549 {
11550 int result;
11551 struct frame *f = SELECTED_FRAME ();
11552 Lisp_Object file = Qnil;
11553 Widget dialog, text, list, help;
11554 Arg al[10];
11555 int ac = 0;
11556 extern XtAppContext Xt_app_con;
11557 XmString dir_xmstring, pattern_xmstring;
11558 int count = SPECPDL_INDEX ();
11559 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
11560
11561 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
11562 CHECK_STRING (prompt);
11563 CHECK_STRING (dir);
11564
11565 /* Prevent redisplay. */
11566 specbind (Qinhibit_redisplay, Qt);
11567
11568 BLOCK_INPUT;
11569
11570 /* Create the dialog with PROMPT as title, using DIR as initial
11571 directory and using "*" as pattern. */
11572 dir = Fexpand_file_name (dir, Qnil);
11573 dir_xmstring = XmStringCreateLocalized (SDATA (dir));
11574 pattern_xmstring = XmStringCreateLocalized ("*");
11575
11576 XtSetArg (al[ac], XmNtitle, SDATA (prompt)); ++ac;
11577 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
11578 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
11579 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
11580 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
11581 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
11582 "fsb", al, ac);
11583 XmStringFree (dir_xmstring);
11584 XmStringFree (pattern_xmstring);
11585
11586 /* Add callbacks for OK and Cancel. */
11587 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
11588 (XtPointer) &result);
11589 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
11590 (XtPointer) &result);
11591 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
11592 (XtPointer) &result);
11593
11594 /* Disable the help button since we can't display help. */
11595 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
11596 XtSetSensitive (help, False);
11597
11598 /* Mark OK button as default. */
11599 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
11600 XmNshowAsDefault, True, NULL);
11601
11602 /* If MUSTMATCH is non-nil, disable the file entry field of the
11603 dialog, so that the user must select a file from the files list
11604 box. We can't remove it because we wouldn't have a way to get at
11605 the result file name, then. */
11606 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
11607 if (!NILP (mustmatch))
11608 {
11609 Widget label;
11610 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
11611 XtSetSensitive (text, False);
11612 XtSetSensitive (label, False);
11613 }
11614
11615 /* Manage the dialog, so that list boxes get filled. */
11616 XtManageChild (dialog);
11617
11618 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
11619 must include the path for this to work. */
11620 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
11621 if (STRINGP (default_filename))
11622 {
11623 XmString default_xmstring;
11624 int item_pos;
11625
11626 default_xmstring
11627 = XmStringCreateLocalized (SDATA (default_filename));
11628
11629 if (!XmListItemExists (list, default_xmstring))
11630 {
11631 /* Add a new item if DEFAULT_FILENAME is not in the list. */
11632 XmListAddItem (list, default_xmstring, 0);
11633 item_pos = 0;
11634 }
11635 else
11636 item_pos = XmListItemPos (list, default_xmstring);
11637 XmStringFree (default_xmstring);
11638
11639 /* Select the item and scroll it into view. */
11640 XmListSelectPos (list, item_pos, True);
11641 XmListSetPos (list, item_pos);
11642 }
11643
11644 /* Process events until the user presses Cancel or OK. Block
11645 and unblock input here so that we get a chance of processing
11646 expose events. */
11647 UNBLOCK_INPUT;
11648 result = 0;
11649 while (result == 0)
11650 {
11651 BLOCK_INPUT;
11652 XtAppProcessEvent (Xt_app_con, XtIMAll);
11653 UNBLOCK_INPUT;
11654 }
11655 BLOCK_INPUT;
11656
11657 /* Get the result. */
11658 if (result == XmCR_OK)
11659 {
11660 XmString text;
11661 String data;
11662
11663 XtVaGetValues (dialog, XmNtextString, &text, NULL);
11664 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
11665 XmStringFree (text);
11666 file = build_string (data);
11667 XtFree (data);
11668 }
11669 else
11670 file = Qnil;
11671
11672 /* Clean up. */
11673 XtUnmanageChild (dialog);
11674 XtDestroyWidget (dialog);
11675 UNBLOCK_INPUT;
11676 UNGCPRO;
11677
11678 /* Make "Cancel" equivalent to C-g. */
11679 if (NILP (file))
11680 Fsignal (Qquit, Qnil);
11681
11682 return unbind_to (count, file);
11683 }
11684
11685 #endif /* USE_MOTIF */
11686
11687
11688 \f
11689 /***********************************************************************
11690 Keyboard
11691 ***********************************************************************/
11692
11693 #ifdef HAVE_XKBGETKEYBOARD
11694 #include <X11/XKBlib.h>
11695 #include <X11/keysym.h>
11696 #endif
11697
11698 DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
11699 Sx_backspace_delete_keys_p, 0, 1, 0,
11700 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
11701 FRAME nil means use the selected frame.
11702 Value is t if we know that both keys are present, and are mapped to the
11703 usual X keysyms. */)
11704 (frame)
11705 Lisp_Object frame;
11706 {
11707 #ifdef HAVE_XKBGETKEYBOARD
11708 XkbDescPtr kb;
11709 struct frame *f = check_x_frame (frame);
11710 Display *dpy = FRAME_X_DISPLAY (f);
11711 Lisp_Object have_keys;
11712 int major, minor, op, event, error;
11713
11714 BLOCK_INPUT;
11715
11716 /* Check library version in case we're dynamically linked. */
11717 major = XkbMajorVersion;
11718 minor = XkbMinorVersion;
11719 if (!XkbLibraryVersion (&major, &minor))
11720 {
11721 UNBLOCK_INPUT;
11722 return Qnil;
11723 }
11724
11725 /* Check that the server supports XKB. */
11726 major = XkbMajorVersion;
11727 minor = XkbMinorVersion;
11728 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
11729 {
11730 UNBLOCK_INPUT;
11731 return Qnil;
11732 }
11733
11734 have_keys = Qnil;
11735 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
11736 if (kb)
11737 {
11738 int delete_keycode = 0, backspace_keycode = 0, i;
11739
11740 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
11741 {
11742 for (i = kb->min_key_code;
11743 (i < kb->max_key_code
11744 && (delete_keycode == 0 || backspace_keycode == 0));
11745 ++i)
11746 {
11747 /* The XKB symbolic key names can be seen most easily in
11748 the PS file generated by `xkbprint -label name
11749 $DISPLAY'. */
11750 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
11751 delete_keycode = i;
11752 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
11753 backspace_keycode = i;
11754 }
11755
11756 XkbFreeNames (kb, 0, True);
11757 }
11758
11759 XkbFreeClientMap (kb, 0, True);
11760
11761 if (delete_keycode
11762 && backspace_keycode
11763 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
11764 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
11765 have_keys = Qt;
11766 }
11767 UNBLOCK_INPUT;
11768 return have_keys;
11769 #else /* not HAVE_XKBGETKEYBOARD */
11770 return Qnil;
11771 #endif /* not HAVE_XKBGETKEYBOARD */
11772 }
11773
11774
11775 \f
11776 /***********************************************************************
11777 Initialization
11778 ***********************************************************************/
11779
11780 void
11781 syms_of_xfns ()
11782 {
11783 /* This is zero if not using X windows. */
11784 x_in_use = 0;
11785
11786 /* The section below is built by the lisp expression at the top of the file,
11787 just above where these variables are declared. */
11788 /*&&& init symbols here &&&*/
11789 Qauto_raise = intern ("auto-raise");
11790 staticpro (&Qauto_raise);
11791 Qauto_lower = intern ("auto-lower");
11792 staticpro (&Qauto_lower);
11793 Qborder_color = intern ("border-color");
11794 staticpro (&Qborder_color);
11795 Qborder_width = intern ("border-width");
11796 staticpro (&Qborder_width);
11797 Qcursor_color = intern ("cursor-color");
11798 staticpro (&Qcursor_color);
11799 Qcursor_type = intern ("cursor-type");
11800 staticpro (&Qcursor_type);
11801 Qgeometry = intern ("geometry");
11802 staticpro (&Qgeometry);
11803 Qicon_left = intern ("icon-left");
11804 staticpro (&Qicon_left);
11805 Qicon_top = intern ("icon-top");
11806 staticpro (&Qicon_top);
11807 Qicon_type = intern ("icon-type");
11808 staticpro (&Qicon_type);
11809 Qicon_name = intern ("icon-name");
11810 staticpro (&Qicon_name);
11811 Qinternal_border_width = intern ("internal-border-width");
11812 staticpro (&Qinternal_border_width);
11813 Qleft = intern ("left");
11814 staticpro (&Qleft);
11815 Qright = intern ("right");
11816 staticpro (&Qright);
11817 Qmouse_color = intern ("mouse-color");
11818 staticpro (&Qmouse_color);
11819 Qnone = intern ("none");
11820 staticpro (&Qnone);
11821 Qparent_id = intern ("parent-id");
11822 staticpro (&Qparent_id);
11823 Qscroll_bar_width = intern ("scroll-bar-width");
11824 staticpro (&Qscroll_bar_width);
11825 Qsuppress_icon = intern ("suppress-icon");
11826 staticpro (&Qsuppress_icon);
11827 Qundefined_color = intern ("undefined-color");
11828 staticpro (&Qundefined_color);
11829 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11830 staticpro (&Qvertical_scroll_bars);
11831 Qvisibility = intern ("visibility");
11832 staticpro (&Qvisibility);
11833 Qwindow_id = intern ("window-id");
11834 staticpro (&Qwindow_id);
11835 Qouter_window_id = intern ("outer-window-id");
11836 staticpro (&Qouter_window_id);
11837 Qx_frame_parameter = intern ("x-frame-parameter");
11838 staticpro (&Qx_frame_parameter);
11839 Qx_resource_name = intern ("x-resource-name");
11840 staticpro (&Qx_resource_name);
11841 Quser_position = intern ("user-position");
11842 staticpro (&Quser_position);
11843 Quser_size = intern ("user-size");
11844 staticpro (&Quser_size);
11845 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11846 staticpro (&Qscroll_bar_foreground);
11847 Qscroll_bar_background = intern ("scroll-bar-background");
11848 staticpro (&Qscroll_bar_background);
11849 Qscreen_gamma = intern ("screen-gamma");
11850 staticpro (&Qscreen_gamma);
11851 Qline_spacing = intern ("line-spacing");
11852 staticpro (&Qline_spacing);
11853 Qcenter = intern ("center");
11854 staticpro (&Qcenter);
11855 Qcompound_text = intern ("compound-text");
11856 staticpro (&Qcompound_text);
11857 Qcancel_timer = intern ("cancel-timer");
11858 staticpro (&Qcancel_timer);
11859 Qwait_for_wm = intern ("wait-for-wm");
11860 staticpro (&Qwait_for_wm);
11861 Qfullscreen = intern ("fullscreen");
11862 staticpro (&Qfullscreen);
11863 Qfullwidth = intern ("fullwidth");
11864 staticpro (&Qfullwidth);
11865 Qfullheight = intern ("fullheight");
11866 staticpro (&Qfullheight);
11867 Qfullboth = intern ("fullboth");
11868 staticpro (&Qfullboth);
11869 /* This is the end of symbol initialization. */
11870
11871 /* Text property `display' should be nonsticky by default. */
11872 Vtext_property_default_nonsticky
11873 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11874
11875
11876 Qlaplace = intern ("laplace");
11877 staticpro (&Qlaplace);
11878 Qemboss = intern ("emboss");
11879 staticpro (&Qemboss);
11880 Qedge_detection = intern ("edge-detection");
11881 staticpro (&Qedge_detection);
11882 Qheuristic = intern ("heuristic");
11883 staticpro (&Qheuristic);
11884 QCmatrix = intern (":matrix");
11885 staticpro (&QCmatrix);
11886 QCcolor_adjustment = intern (":color-adjustment");
11887 staticpro (&QCcolor_adjustment);
11888 QCmask = intern (":mask");
11889 staticpro (&QCmask);
11890
11891 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11892 staticpro (&Qface_set_after_frame_default);
11893
11894 Fput (Qundefined_color, Qerror_conditions,
11895 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11896 Fput (Qundefined_color, Qerror_message,
11897 build_string ("Undefined color"));
11898
11899 init_x_parm_symbols ();
11900
11901 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
11902 doc: /* Non-nil means always draw a cross over disabled images.
11903 Disabled images are those having an `:conversion disabled' property.
11904 A cross is always drawn on black & white displays. */);
11905 cross_disabled_images = 0;
11906
11907 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11908 doc: /* List of directories to search for bitmap files for X. */);
11909 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
11910
11911 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
11912 doc: /* The shape of the pointer when over text.
11913 Changing the value does not affect existing frames
11914 unless you set the mouse color. */);
11915 Vx_pointer_shape = Qnil;
11916
11917 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
11918 doc: /* The name Emacs uses to look up X resources.
11919 `x-get-resource' uses this as the first component of the instance name
11920 when requesting resource values.
11921 Emacs initially sets `x-resource-name' to the name under which Emacs
11922 was invoked, or to the value specified with the `-name' or `-rn'
11923 switches, if present.
11924
11925 It may be useful to bind this variable locally around a call
11926 to `x-get-resource'. See also the variable `x-resource-class'. */);
11927 Vx_resource_name = Qnil;
11928
11929 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11930 doc: /* The class Emacs uses to look up X resources.
11931 `x-get-resource' uses this as the first component of the instance class
11932 when requesting resource values.
11933
11934 Emacs initially sets `x-resource-class' to "Emacs".
11935
11936 Setting this variable permanently is not a reasonable thing to do,
11937 but binding this variable locally around a call to `x-get-resource'
11938 is a reasonable practice. See also the variable `x-resource-name'. */);
11939 Vx_resource_class = build_string (EMACS_CLASS);
11940
11941 #if 0 /* This doesn't really do anything. */
11942 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
11943 doc: /* The shape of the pointer when not over text.
11944 This variable takes effect when you create a new frame
11945 or when you set the mouse color. */);
11946 #endif
11947 Vx_nontext_pointer_shape = Qnil;
11948
11949 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
11950 doc: /* The shape of the pointer when Emacs is busy.
11951 This variable takes effect when you create a new frame
11952 or when you set the mouse color. */);
11953 Vx_hourglass_pointer_shape = Qnil;
11954
11955 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
11956 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
11957 display_hourglass_p = 1;
11958
11959 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
11960 doc: /* *Seconds to wait before displaying an hourglass pointer.
11961 Value must be an integer or float. */);
11962 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
11963
11964 #if 0 /* This doesn't really do anything. */
11965 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
11966 doc: /* The shape of the pointer when over the mode line.
11967 This variable takes effect when you create a new frame
11968 or when you set the mouse color. */);
11969 #endif
11970 Vx_mode_pointer_shape = Qnil;
11971
11972 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
11973 &Vx_sensitive_text_pointer_shape,
11974 doc: /* The shape of the pointer when over mouse-sensitive text.
11975 This variable takes effect when you create a new frame
11976 or when you set the mouse color. */);
11977 Vx_sensitive_text_pointer_shape = Qnil;
11978
11979 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
11980 &Vx_window_horizontal_drag_shape,
11981 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
11982 This variable takes effect when you create a new frame
11983 or when you set the mouse color. */);
11984 Vx_window_horizontal_drag_shape = Qnil;
11985
11986 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
11987 doc: /* A string indicating the foreground color of the cursor box. */);
11988 Vx_cursor_fore_pixel = Qnil;
11989
11990 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
11991 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
11992 Text larger than this is clipped. */);
11993 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
11994
11995 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
11996 doc: /* Non-nil if no X window manager is in use.
11997 Emacs doesn't try to figure this out; this is always nil
11998 unless you set it to something else. */);
11999 /* We don't have any way to find this out, so set it to nil
12000 and maybe the user would like to set it to t. */
12001 Vx_no_window_manager = Qnil;
12002
12003 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
12004 &Vx_pixel_size_width_font_regexp,
12005 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
12006
12007 Since Emacs gets width of a font matching with this regexp from
12008 PIXEL_SIZE field of the name, font finding mechanism gets faster for
12009 such a font. This is especially effective for such large fonts as
12010 Chinese, Japanese, and Korean. */);
12011 Vx_pixel_size_width_font_regexp = Qnil;
12012
12013 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
12014 doc: /* Time after which cached images are removed from the cache.
12015 When an image has not been displayed this many seconds, remove it
12016 from the image cache. Value must be an integer or nil with nil
12017 meaning don't clear the cache. */);
12018 Vimage_cache_eviction_delay = make_number (30 * 60);
12019
12020 #ifdef USE_X_TOOLKIT
12021 Fprovide (intern ("x-toolkit"), Qnil);
12022 #ifdef USE_MOTIF
12023 Fprovide (intern ("motif"), Qnil);
12024
12025 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
12026 doc: /* Version info for LessTif/Motif. */);
12027 Vmotif_version_string = build_string (XmVERSION_STRING);
12028 #endif /* USE_MOTIF */
12029 #endif /* USE_X_TOOLKIT */
12030
12031 defsubr (&Sx_get_resource);
12032
12033 /* X window properties. */
12034 defsubr (&Sx_change_window_property);
12035 defsubr (&Sx_delete_window_property);
12036 defsubr (&Sx_window_property);
12037
12038 defsubr (&Sxw_display_color_p);
12039 defsubr (&Sx_display_grayscale_p);
12040 defsubr (&Sxw_color_defined_p);
12041 defsubr (&Sxw_color_values);
12042 defsubr (&Sx_server_max_request_size);
12043 defsubr (&Sx_server_vendor);
12044 defsubr (&Sx_server_version);
12045 defsubr (&Sx_display_pixel_width);
12046 defsubr (&Sx_display_pixel_height);
12047 defsubr (&Sx_display_mm_width);
12048 defsubr (&Sx_display_mm_height);
12049 defsubr (&Sx_display_screens);
12050 defsubr (&Sx_display_planes);
12051 defsubr (&Sx_display_color_cells);
12052 defsubr (&Sx_display_visual_class);
12053 defsubr (&Sx_display_backing_store);
12054 defsubr (&Sx_display_save_under);
12055 defsubr (&Sx_parse_geometry);
12056 defsubr (&Sx_create_frame);
12057 defsubr (&Sx_open_connection);
12058 defsubr (&Sx_close_connection);
12059 defsubr (&Sx_display_list);
12060 defsubr (&Sx_synchronize);
12061 defsubr (&Sx_focus_frame);
12062 defsubr (&Sx_backspace_delete_keys_p);
12063
12064 /* Setting callback functions for fontset handler. */
12065 get_font_info_func = x_get_font_info;
12066
12067 #if 0 /* This function pointer doesn't seem to be used anywhere.
12068 And the pointer assigned has the wrong type, anyway. */
12069 list_fonts_func = x_list_fonts;
12070 #endif
12071
12072 load_font_func = x_load_font;
12073 find_ccl_program_func = x_find_ccl_program;
12074 query_font_func = x_query_font;
12075 set_frame_fontset_func = x_set_font;
12076 check_window_system_func = check_x;
12077
12078 /* Images. */
12079 Qxbm = intern ("xbm");
12080 staticpro (&Qxbm);
12081 QCconversion = intern (":conversion");
12082 staticpro (&QCconversion);
12083 QCheuristic_mask = intern (":heuristic-mask");
12084 staticpro (&QCheuristic_mask);
12085 QCcolor_symbols = intern (":color-symbols");
12086 staticpro (&QCcolor_symbols);
12087 QCascent = intern (":ascent");
12088 staticpro (&QCascent);
12089 QCmargin = intern (":margin");
12090 staticpro (&QCmargin);
12091 QCrelief = intern (":relief");
12092 staticpro (&QCrelief);
12093 Qpostscript = intern ("postscript");
12094 staticpro (&Qpostscript);
12095 QCloader = intern (":loader");
12096 staticpro (&QCloader);
12097 QCbounding_box = intern (":bounding-box");
12098 staticpro (&QCbounding_box);
12099 QCpt_width = intern (":pt-width");
12100 staticpro (&QCpt_width);
12101 QCpt_height = intern (":pt-height");
12102 staticpro (&QCpt_height);
12103 QCindex = intern (":index");
12104 staticpro (&QCindex);
12105 Qpbm = intern ("pbm");
12106 staticpro (&Qpbm);
12107
12108 #if HAVE_XPM
12109 Qxpm = intern ("xpm");
12110 staticpro (&Qxpm);
12111 #endif
12112
12113 #if HAVE_JPEG
12114 Qjpeg = intern ("jpeg");
12115 staticpro (&Qjpeg);
12116 #endif
12117
12118 #if HAVE_TIFF
12119 Qtiff = intern ("tiff");
12120 staticpro (&Qtiff);
12121 #endif
12122
12123 #if HAVE_GIF
12124 Qgif = intern ("gif");
12125 staticpro (&Qgif);
12126 #endif
12127
12128 #if HAVE_PNG
12129 Qpng = intern ("png");
12130 staticpro (&Qpng);
12131 #endif
12132
12133 defsubr (&Sclear_image_cache);
12134 defsubr (&Simage_size);
12135 defsubr (&Simage_mask_p);
12136
12137 hourglass_atimer = NULL;
12138 hourglass_shown_p = 0;
12139
12140 defsubr (&Sx_show_tip);
12141 defsubr (&Sx_hide_tip);
12142 tip_timer = Qnil;
12143 staticpro (&tip_timer);
12144 tip_frame = Qnil;
12145 staticpro (&tip_frame);
12146
12147 last_show_tip_args = Qnil;
12148 staticpro (&last_show_tip_args);
12149
12150 #ifdef USE_MOTIF
12151 defsubr (&Sx_file_dialog);
12152 #endif
12153 }
12154
12155
12156 void
12157 init_xfns ()
12158 {
12159 image_types = NULL;
12160 Vimage_types = Qnil;
12161
12162 define_image_type (&xbm_type);
12163 define_image_type (&gs_type);
12164 define_image_type (&pbm_type);
12165
12166 #if HAVE_XPM
12167 define_image_type (&xpm_type);
12168 #endif
12169
12170 #if HAVE_JPEG
12171 define_image_type (&jpeg_type);
12172 #endif
12173
12174 #if HAVE_TIFF
12175 define_image_type (&tiff_type);
12176 #endif
12177
12178 #if HAVE_GIF
12179 define_image_type (&gif_type);
12180 #endif
12181
12182 #if HAVE_PNG
12183 define_image_type (&png_type);
12184 #endif
12185 }
12186
12187 #endif /* HAVE_X_WINDOWS */