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