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