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