]> code.delx.au - gnu-emacs/blob - src/xfns.c
(x_build_heuristic_mask): Use x_alloc_image_color.
[gnu-emacs] / src / xfns.c
1 /* Functions for the X window system.
2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <math.h>
26
27 /* 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 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2643 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2644 class, where INSTANCE is the name under which Emacs was invoked, or
2645 the name specified by the `-name' or `-rn' command-line arguments.
2646
2647 The optional arguments COMPONENT and SUBCLASS add to the key and the
2648 class, respectively. You must specify both of them or neither.
2649 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
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 doc: /* Parse an X-style geometry string STRING.
3001 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3002 The properties returned may include `top', `left', `height', and `width'.
3003 The value of `left' or `top' may be an integer,
3004 or a list (+ N) meaning N pixels relative to top/left corner,
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 doc: /* Make a new X window, which is called a "frame" in Emacs terms.
4094 Returns an Emacs frame object.
4095 ALIST is an alist of frame parameters.
4096 If the parameters specify that the frame should not have a minibuffer,
4097 and do not specify a specific minibuffer window to use,
4098 then `default-minibuffer-frame' must be a frame whose minibuffer can
4099 be shared by the new frame.
4100
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 doc: /* Set the input focus to FRAME.
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 doc: /* 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 doc: /* 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 doc: /* 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 doc: /* Return t if the X display supports shades of gray.
4641 Note that color displays do support shades of gray.
4642 The optional argument DISPLAY specifies which display to ask about.
4643 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the width in pixels of the X display DISPLAY.
4671 The optional argument DISPLAY specifies which display to ask about.
4672 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the height in pixels of the X display DISPLAY.
4685 The optional argument DISPLAY specifies which display to ask about.
4686 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the number of bitplanes of the X display DISPLAY.
4699 The optional argument DISPLAY specifies which display to ask about.
4700 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the number of color cells of the X display DISPLAY.
4713 The optional argument DISPLAY specifies which display to ask about.
4714 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the maximum request size of the X server of display DISPLAY.
4729 The optional argument DISPLAY specifies which display to ask about.
4730 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
4742 The optional argument DISPLAY specifies which display to ask about.
4743 DISPLAY should be either a frame or a display name (a string).
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 doc: /* Returns the version numbers of the X server of display DISPLAY.
4757 The value is a list of three integers: the major and minor
4758 version numbers of the X Protocol in use, and the vendor-specific release
4759 number. See also the function `x-server-vendor'.
4760
4761 The optional argument DISPLAY specifies which display to ask about.
4762 DISPLAY should be either a frame or a display name (a string).
4763 If omitted or nil, that stands for the selected frame's display. */)
4764 (display)
4765 Lisp_Object display;
4766 {
4767 struct x_display_info *dpyinfo = check_x_display_info (display);
4768 Display *dpy = dpyinfo->display;
4769
4770 return Fcons (make_number (ProtocolVersion (dpy)),
4771 Fcons (make_number (ProtocolRevision (dpy)),
4772 Fcons (make_number (VendorRelease (dpy)), Qnil)));
4773 }
4774
4775 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4776 doc: /* Return the number of screens on the X server of display DISPLAY.
4777 The optional argument DISPLAY specifies which display to ask about.
4778 DISPLAY should be either a frame or a display name (a string).
4779 If omitted or nil, that stands for the selected frame's display. */)
4780 (display)
4781 Lisp_Object display;
4782 {
4783 struct x_display_info *dpyinfo = check_x_display_info (display);
4784
4785 return make_number (ScreenCount (dpyinfo->display));
4786 }
4787
4788 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
4789 doc: /* Return the height in millimeters of the X display DISPLAY.
4790 The optional argument DISPLAY specifies which display to ask about.
4791 DISPLAY should be either a frame or a display name (a string).
4792 If omitted or nil, that stands for the selected frame's display. */)
4793 (display)
4794 Lisp_Object display;
4795 {
4796 struct x_display_info *dpyinfo = check_x_display_info (display);
4797
4798 return make_number (HeightMMOfScreen (dpyinfo->screen));
4799 }
4800
4801 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4802 doc: /* Return the width in millimeters of the X display DISPLAY.
4803 The optional argument DISPLAY specifies which display to ask about.
4804 DISPLAY should be either a frame or a display name (a string).
4805 If omitted or nil, that stands for the selected frame's display. */)
4806 (display)
4807 Lisp_Object display;
4808 {
4809 struct x_display_info *dpyinfo = check_x_display_info (display);
4810
4811 return make_number (WidthMMOfScreen (dpyinfo->screen));
4812 }
4813
4814 DEFUN ("x-display-backing-store", Fx_display_backing_store,
4815 Sx_display_backing_store, 0, 1, 0,
4816 doc: /* Returns an indication of whether X display DISPLAY does backing store.
4817 The value may be `always', `when-mapped', or `not-useful'.
4818 The optional argument DISPLAY specifies which display to ask about.
4819 DISPLAY should be either a frame or a display name (a string).
4820 If omitted or nil, that stands for the selected frame's display. */)
4821 (display)
4822 Lisp_Object display;
4823 {
4824 struct x_display_info *dpyinfo = check_x_display_info (display);
4825 Lisp_Object result;
4826
4827 switch (DoesBackingStore (dpyinfo->screen))
4828 {
4829 case Always:
4830 result = intern ("always");
4831 break;
4832
4833 case WhenMapped:
4834 result = intern ("when-mapped");
4835 break;
4836
4837 case NotUseful:
4838 result = intern ("not-useful");
4839 break;
4840
4841 default:
4842 error ("Strange value for BackingStore parameter of screen");
4843 result = Qnil;
4844 }
4845
4846 return result;
4847 }
4848
4849 DEFUN ("x-display-visual-class", Fx_display_visual_class,
4850 Sx_display_visual_class, 0, 1, 0,
4851 doc: /* Return the visual class of the X display DISPLAY.
4852 The value is one of the symbols `static-gray', `gray-scale',
4853 `static-color', `pseudo-color', `true-color', or `direct-color'.
4854
4855 The optional argument DISPLAY specifies which display to ask about.
4856 DISPLAY should be either a frame or a display name (a string).
4857 If omitted or nil, that stands for the selected frame's display. */)
4858 (display)
4859 Lisp_Object display;
4860 {
4861 struct x_display_info *dpyinfo = check_x_display_info (display);
4862 Lisp_Object result;
4863
4864 switch (dpyinfo->visual->class)
4865 {
4866 case StaticGray:
4867 result = intern ("static-gray");
4868 break;
4869 case GrayScale:
4870 result = intern ("gray-scale");
4871 break;
4872 case StaticColor:
4873 result = intern ("static-color");
4874 break;
4875 case PseudoColor:
4876 result = intern ("pseudo-color");
4877 break;
4878 case TrueColor:
4879 result = intern ("true-color");
4880 break;
4881 case DirectColor:
4882 result = intern ("direct-color");
4883 break;
4884 default:
4885 error ("Display has an unknown visual class");
4886 result = Qnil;
4887 }
4888
4889 return result;
4890 }
4891
4892 DEFUN ("x-display-save-under", Fx_display_save_under,
4893 Sx_display_save_under, 0, 1, 0,
4894 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
4895 The optional argument DISPLAY specifies which display to ask about.
4896 DISPLAY should be either a frame or a display name (a string).
4897 If omitted or nil, that stands for the selected frame's display. */)
4898 (display)
4899 Lisp_Object display;
4900 {
4901 struct x_display_info *dpyinfo = check_x_display_info (display);
4902
4903 if (DoesSaveUnders (dpyinfo->screen) == True)
4904 return Qt;
4905 else
4906 return Qnil;
4907 }
4908 \f
4909 int
4910 x_pixel_width (f)
4911 register struct frame *f;
4912 {
4913 return PIXEL_WIDTH (f);
4914 }
4915
4916 int
4917 x_pixel_height (f)
4918 register struct frame *f;
4919 {
4920 return PIXEL_HEIGHT (f);
4921 }
4922
4923 int
4924 x_char_width (f)
4925 register struct frame *f;
4926 {
4927 return FONT_WIDTH (f->output_data.x->font);
4928 }
4929
4930 int
4931 x_char_height (f)
4932 register struct frame *f;
4933 {
4934 return f->output_data.x->line_height;
4935 }
4936
4937 int
4938 x_screen_planes (f)
4939 register struct frame *f;
4940 {
4941 return FRAME_X_DISPLAY_INFO (f)->n_planes;
4942 }
4943
4944
4945 \f
4946 /************************************************************************
4947 X Displays
4948 ************************************************************************/
4949
4950 \f
4951 /* Mapping visual names to visuals. */
4952
4953 static struct visual_class
4954 {
4955 char *name;
4956 int class;
4957 }
4958 visual_classes[] =
4959 {
4960 {"StaticGray", StaticGray},
4961 {"GrayScale", GrayScale},
4962 {"StaticColor", StaticColor},
4963 {"PseudoColor", PseudoColor},
4964 {"TrueColor", TrueColor},
4965 {"DirectColor", DirectColor},
4966 NULL
4967 };
4968
4969
4970 #ifndef HAVE_XSCREENNUMBEROFSCREEN
4971
4972 /* Value is the screen number of screen SCR. This is a substitute for
4973 the X function with the same name when that doesn't exist. */
4974
4975 int
4976 XScreenNumberOfScreen (scr)
4977 register Screen *scr;
4978 {
4979 Display *dpy = scr->display;
4980 int i;
4981
4982 for (i = 0; i < dpy->nscreens; ++i)
4983 if (scr == dpy->screens + i)
4984 break;
4985
4986 return i;
4987 }
4988
4989 #endif /* not HAVE_XSCREENNUMBEROFSCREEN */
4990
4991
4992 /* Select the visual that should be used on display DPYINFO. Set
4993 members of DPYINFO appropriately. Called from x_term_init. */
4994
4995 void
4996 select_visual (dpyinfo)
4997 struct x_display_info *dpyinfo;
4998 {
4999 Display *dpy = dpyinfo->display;
5000 Screen *screen = dpyinfo->screen;
5001 Lisp_Object value;
5002
5003 /* See if a visual is specified. */
5004 value = display_x_get_resource (dpyinfo,
5005 build_string ("visualClass"),
5006 build_string ("VisualClass"),
5007 Qnil, Qnil);
5008 if (STRINGP (value))
5009 {
5010 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
5011 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
5012 depth, a decimal number. NAME is compared with case ignored. */
5013 char *s = (char *) alloca (STRING_BYTES (XSTRING (value)) + 1);
5014 char *dash;
5015 int i, class = -1;
5016 XVisualInfo vinfo;
5017
5018 strcpy (s, XSTRING (value)->data);
5019 dash = index (s, '-');
5020 if (dash)
5021 {
5022 dpyinfo->n_planes = atoi (dash + 1);
5023 *dash = '\0';
5024 }
5025 else
5026 /* We won't find a matching visual with depth 0, so that
5027 an error will be printed below. */
5028 dpyinfo->n_planes = 0;
5029
5030 /* Determine the visual class. */
5031 for (i = 0; visual_classes[i].name; ++i)
5032 if (xstricmp (s, visual_classes[i].name) == 0)
5033 {
5034 class = visual_classes[i].class;
5035 break;
5036 }
5037
5038 /* Look up a matching visual for the specified class. */
5039 if (class == -1
5040 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
5041 dpyinfo->n_planes, class, &vinfo))
5042 fatal ("Invalid visual specification `%s'", XSTRING (value)->data);
5043
5044 dpyinfo->visual = vinfo.visual;
5045 }
5046 else
5047 {
5048 int n_visuals;
5049 XVisualInfo *vinfo, vinfo_template;
5050
5051 dpyinfo->visual = DefaultVisualOfScreen (screen);
5052
5053 #ifdef HAVE_X11R4
5054 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
5055 #else
5056 vinfo_template.visualid = dpyinfo->visual->visualid;
5057 #endif
5058 vinfo_template.screen = XScreenNumberOfScreen (screen);
5059 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
5060 &vinfo_template, &n_visuals);
5061 if (n_visuals != 1)
5062 fatal ("Can't get proper X visual info");
5063
5064 dpyinfo->n_planes = vinfo->depth;
5065 XFree ((char *) vinfo);
5066 }
5067 }
5068
5069
5070 /* Return the X display structure for the display named NAME.
5071 Open a new connection if necessary. */
5072
5073 struct x_display_info *
5074 x_display_info_for_name (name)
5075 Lisp_Object name;
5076 {
5077 Lisp_Object names;
5078 struct x_display_info *dpyinfo;
5079
5080 CHECK_STRING (name, 0);
5081
5082 if (! EQ (Vwindow_system, intern ("x")))
5083 error ("Not using X Windows");
5084
5085 for (dpyinfo = x_display_list, names = x_display_name_list;
5086 dpyinfo;
5087 dpyinfo = dpyinfo->next, names = XCDR (names))
5088 {
5089 Lisp_Object tem;
5090 tem = Fstring_equal (XCAR (XCAR (names)), name);
5091 if (!NILP (tem))
5092 return dpyinfo;
5093 }
5094
5095 /* Use this general default value to start with. */
5096 Vx_resource_name = Vinvocation_name;
5097
5098 validate_x_resource_name ();
5099
5100 dpyinfo = x_term_init (name, (char *)0,
5101 (char *) XSTRING (Vx_resource_name)->data);
5102
5103 if (dpyinfo == 0)
5104 error ("Cannot connect to X server %s", XSTRING (name)->data);
5105
5106 x_in_use = 1;
5107 XSETFASTINT (Vwindow_system_version, 11);
5108
5109 return dpyinfo;
5110 }
5111
5112
5113 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
5114 1, 3, 0,
5115 doc: /* Open a connection to an X server.
5116 DISPLAY is the name of the display to connect to.
5117 Optional second arg XRM-STRING is a string of resources in xrdb format.
5118 If the optional third arg MUST-SUCCEED is non-nil,
5119 terminate Emacs if we can't open the connection. */)
5120 (display, xrm_string, must_succeed)
5121 Lisp_Object display, xrm_string, must_succeed;
5122 {
5123 unsigned char *xrm_option;
5124 struct x_display_info *dpyinfo;
5125
5126 CHECK_STRING (display, 0);
5127 if (! NILP (xrm_string))
5128 CHECK_STRING (xrm_string, 1);
5129
5130 if (! EQ (Vwindow_system, intern ("x")))
5131 error ("Not using X Windows");
5132
5133 if (! NILP (xrm_string))
5134 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
5135 else
5136 xrm_option = (unsigned char *) 0;
5137
5138 validate_x_resource_name ();
5139
5140 /* This is what opens the connection and sets x_current_display.
5141 This also initializes many symbols, such as those used for input. */
5142 dpyinfo = x_term_init (display, xrm_option,
5143 (char *) XSTRING (Vx_resource_name)->data);
5144
5145 if (dpyinfo == 0)
5146 {
5147 if (!NILP (must_succeed))
5148 fatal ("Cannot connect to X server %s.\n\
5149 Check the DISPLAY environment variable or use `-d'.\n\
5150 Also use the `xhost' program to verify that it is set to permit\n\
5151 connections from your machine.\n",
5152 XSTRING (display)->data);
5153 else
5154 error ("Cannot connect to X server %s", XSTRING (display)->data);
5155 }
5156
5157 x_in_use = 1;
5158
5159 XSETFASTINT (Vwindow_system_version, 11);
5160 return Qnil;
5161 }
5162
5163 DEFUN ("x-close-connection", Fx_close_connection,
5164 Sx_close_connection, 1, 1, 0,
5165 doc: /* Close the connection to DISPLAY's X server.
5166 For DISPLAY, specify either a frame or a display name (a string).
5167 If DISPLAY is nil, that stands for the selected frame's display. */)
5168 (display)
5169 Lisp_Object display;
5170 {
5171 struct x_display_info *dpyinfo = check_x_display_info (display);
5172 int i;
5173
5174 if (dpyinfo->reference_count > 0)
5175 error ("Display still has frames on it");
5176
5177 BLOCK_INPUT;
5178 /* Free the fonts in the font table. */
5179 for (i = 0; i < dpyinfo->n_fonts; i++)
5180 if (dpyinfo->font_table[i].name)
5181 {
5182 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
5183 xfree (dpyinfo->font_table[i].full_name);
5184 xfree (dpyinfo->font_table[i].name);
5185 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
5186 }
5187
5188 x_destroy_all_bitmaps (dpyinfo);
5189 XSetCloseDownMode (dpyinfo->display, DestroyAll);
5190
5191 #ifdef USE_X_TOOLKIT
5192 XtCloseDisplay (dpyinfo->display);
5193 #else
5194 XCloseDisplay (dpyinfo->display);
5195 #endif
5196
5197 x_delete_display (dpyinfo);
5198 UNBLOCK_INPUT;
5199
5200 return Qnil;
5201 }
5202
5203 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
5204 doc: /* Return the list of display names that Emacs has connections to. */)
5205 ()
5206 {
5207 Lisp_Object tail, result;
5208
5209 result = Qnil;
5210 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
5211 result = Fcons (XCAR (XCAR (tail)), result);
5212
5213 return result;
5214 }
5215
5216 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
5217 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
5218 If ON is nil, allow buffering of requests.
5219 Turning on synchronization prohibits the Xlib routines from buffering
5220 requests and seriously degrades performance, but makes debugging much
5221 easier.
5222 The optional second argument DISPLAY specifies which display to act on.
5223 DISPLAY should be either a frame or a display name (a string).
5224 If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
5225 (on, display)
5226 Lisp_Object display, on;
5227 {
5228 struct x_display_info *dpyinfo = check_x_display_info (display);
5229
5230 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
5231
5232 return Qnil;
5233 }
5234
5235 /* Wait for responses to all X commands issued so far for frame F. */
5236
5237 void
5238 x_sync (f)
5239 FRAME_PTR f;
5240 {
5241 BLOCK_INPUT;
5242 XSync (FRAME_X_DISPLAY (f), False);
5243 UNBLOCK_INPUT;
5244 }
5245
5246 \f
5247 /***********************************************************************
5248 Image types
5249 ***********************************************************************/
5250
5251 /* Value is the number of elements of vector VECTOR. */
5252
5253 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
5254
5255 /* List of supported image types. Use define_image_type to add new
5256 types. Use lookup_image_type to find a type for a given symbol. */
5257
5258 static struct image_type *image_types;
5259
5260 /* The symbol `image' which is the car of the lists used to represent
5261 images in Lisp. */
5262
5263 extern Lisp_Object Qimage;
5264
5265 /* The symbol `xbm' which is used as the type symbol for XBM images. */
5266
5267 Lisp_Object Qxbm;
5268
5269 /* Keywords. */
5270
5271 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
5272 extern Lisp_Object QCdata;
5273 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
5274 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
5275 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
5276
5277 /* Other symbols. */
5278
5279 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
5280
5281 /* Time in seconds after which images should be removed from the cache
5282 if not displayed. */
5283
5284 Lisp_Object Vimage_cache_eviction_delay;
5285
5286 /* Function prototypes. */
5287
5288 static void define_image_type P_ ((struct image_type *type));
5289 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5290 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5291 static void x_laplace P_ ((struct frame *, struct image *));
5292 static void x_emboss P_ ((struct frame *, struct image *));
5293 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5294 Lisp_Object));
5295
5296
5297 /* Define a new image type from TYPE. This adds a copy of TYPE to
5298 image_types and adds the symbol *TYPE->type to Vimage_types. */
5299
5300 static void
5301 define_image_type (type)
5302 struct image_type *type;
5303 {
5304 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5305 The initialized data segment is read-only. */
5306 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5307 bcopy (type, p, sizeof *p);
5308 p->next = image_types;
5309 image_types = p;
5310 Vimage_types = Fcons (*p->type, Vimage_types);
5311 }
5312
5313
5314 /* Look up image type SYMBOL, and return a pointer to its image_type
5315 structure. Value is null if SYMBOL is not a known image type. */
5316
5317 static INLINE struct image_type *
5318 lookup_image_type (symbol)
5319 Lisp_Object symbol;
5320 {
5321 struct image_type *type;
5322
5323 for (type = image_types; type; type = type->next)
5324 if (EQ (symbol, *type->type))
5325 break;
5326
5327 return type;
5328 }
5329
5330
5331 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
5332 valid image specification is a list whose car is the symbol
5333 `image', and whose rest is a property list. The property list must
5334 contain a value for key `:type'. That value must be the name of a
5335 supported image type. The rest of the property list depends on the
5336 image type. */
5337
5338 int
5339 valid_image_p (object)
5340 Lisp_Object object;
5341 {
5342 int valid_p = 0;
5343
5344 if (CONSP (object) && EQ (XCAR (object), Qimage))
5345 {
5346 Lisp_Object tem;
5347
5348 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
5349 if (EQ (XCAR (tem), QCtype))
5350 {
5351 tem = XCDR (tem);
5352 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
5353 {
5354 struct image_type *type;
5355 type = lookup_image_type (XCAR (tem));
5356 if (type)
5357 valid_p = type->valid_p (object);
5358 }
5359
5360 break;
5361 }
5362 }
5363
5364 return valid_p;
5365 }
5366
5367
5368 /* Log error message with format string FORMAT and argument ARG.
5369 Signaling an error, e.g. when an image cannot be loaded, is not a
5370 good idea because this would interrupt redisplay, and the error
5371 message display would lead to another redisplay. This function
5372 therefore simply displays a message. */
5373
5374 static void
5375 image_error (format, arg1, arg2)
5376 char *format;
5377 Lisp_Object arg1, arg2;
5378 {
5379 add_to_log (format, arg1, arg2);
5380 }
5381
5382
5383 \f
5384 /***********************************************************************
5385 Image specifications
5386 ***********************************************************************/
5387
5388 enum image_value_type
5389 {
5390 IMAGE_DONT_CHECK_VALUE_TYPE,
5391 IMAGE_STRING_VALUE,
5392 IMAGE_STRING_OR_NIL_VALUE,
5393 IMAGE_SYMBOL_VALUE,
5394 IMAGE_POSITIVE_INTEGER_VALUE,
5395 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
5396 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
5397 IMAGE_ASCENT_VALUE,
5398 IMAGE_INTEGER_VALUE,
5399 IMAGE_FUNCTION_VALUE,
5400 IMAGE_NUMBER_VALUE,
5401 IMAGE_BOOL_VALUE
5402 };
5403
5404 /* Structure used when parsing image specifications. */
5405
5406 struct image_keyword
5407 {
5408 /* Name of keyword. */
5409 char *name;
5410
5411 /* The type of value allowed. */
5412 enum image_value_type type;
5413
5414 /* Non-zero means key must be present. */
5415 int mandatory_p;
5416
5417 /* Used to recognize duplicate keywords in a property list. */
5418 int count;
5419
5420 /* The value that was found. */
5421 Lisp_Object value;
5422 };
5423
5424
5425 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5426 int, Lisp_Object));
5427 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5428
5429
5430 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
5431 has the format (image KEYWORD VALUE ...). One of the keyword/
5432 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5433 image_keywords structures of size NKEYWORDS describing other
5434 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
5435
5436 static int
5437 parse_image_spec (spec, keywords, nkeywords, type)
5438 Lisp_Object spec;
5439 struct image_keyword *keywords;
5440 int nkeywords;
5441 Lisp_Object type;
5442 {
5443 int i;
5444 Lisp_Object plist;
5445
5446 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5447 return 0;
5448
5449 plist = XCDR (spec);
5450 while (CONSP (plist))
5451 {
5452 Lisp_Object key, value;
5453
5454 /* First element of a pair must be a symbol. */
5455 key = XCAR (plist);
5456 plist = XCDR (plist);
5457 if (!SYMBOLP (key))
5458 return 0;
5459
5460 /* There must follow a value. */
5461 if (!CONSP (plist))
5462 return 0;
5463 value = XCAR (plist);
5464 plist = XCDR (plist);
5465
5466 /* Find key in KEYWORDS. Error if not found. */
5467 for (i = 0; i < nkeywords; ++i)
5468 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
5469 break;
5470
5471 if (i == nkeywords)
5472 continue;
5473
5474 /* Record that we recognized the keyword. If a keywords
5475 was found more than once, it's an error. */
5476 keywords[i].value = value;
5477 ++keywords[i].count;
5478
5479 if (keywords[i].count > 1)
5480 return 0;
5481
5482 /* Check type of value against allowed type. */
5483 switch (keywords[i].type)
5484 {
5485 case IMAGE_STRING_VALUE:
5486 if (!STRINGP (value))
5487 return 0;
5488 break;
5489
5490 case IMAGE_STRING_OR_NIL_VALUE:
5491 if (!STRINGP (value) && !NILP (value))
5492 return 0;
5493 break;
5494
5495 case IMAGE_SYMBOL_VALUE:
5496 if (!SYMBOLP (value))
5497 return 0;
5498 break;
5499
5500 case IMAGE_POSITIVE_INTEGER_VALUE:
5501 if (!INTEGERP (value) || XINT (value) <= 0)
5502 return 0;
5503 break;
5504
5505 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
5506 if (INTEGERP (value) && XINT (value) >= 0)
5507 break;
5508 if (CONSP (value)
5509 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
5510 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
5511 break;
5512 return 0;
5513
5514 case IMAGE_ASCENT_VALUE:
5515 if (SYMBOLP (value) && EQ (value, Qcenter))
5516 break;
5517 else if (INTEGERP (value)
5518 && XINT (value) >= 0
5519 && XINT (value) <= 100)
5520 break;
5521 return 0;
5522
5523 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5524 if (!INTEGERP (value) || XINT (value) < 0)
5525 return 0;
5526 break;
5527
5528 case IMAGE_DONT_CHECK_VALUE_TYPE:
5529 break;
5530
5531 case IMAGE_FUNCTION_VALUE:
5532 value = indirect_function (value);
5533 if (SUBRP (value)
5534 || COMPILEDP (value)
5535 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5536 break;
5537 return 0;
5538
5539 case IMAGE_NUMBER_VALUE:
5540 if (!INTEGERP (value) && !FLOATP (value))
5541 return 0;
5542 break;
5543
5544 case IMAGE_INTEGER_VALUE:
5545 if (!INTEGERP (value))
5546 return 0;
5547 break;
5548
5549 case IMAGE_BOOL_VALUE:
5550 if (!NILP (value) && !EQ (value, Qt))
5551 return 0;
5552 break;
5553
5554 default:
5555 abort ();
5556 break;
5557 }
5558
5559 if (EQ (key, QCtype) && !EQ (type, value))
5560 return 0;
5561 }
5562
5563 /* Check that all mandatory fields are present. */
5564 for (i = 0; i < nkeywords; ++i)
5565 if (keywords[i].mandatory_p && keywords[i].count == 0)
5566 return 0;
5567
5568 return NILP (plist);
5569 }
5570
5571
5572 /* Return the value of KEY in image specification SPEC. Value is nil
5573 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5574 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5575
5576 static Lisp_Object
5577 image_spec_value (spec, key, found)
5578 Lisp_Object spec, key;
5579 int *found;
5580 {
5581 Lisp_Object tail;
5582
5583 xassert (valid_image_p (spec));
5584
5585 for (tail = XCDR (spec);
5586 CONSP (tail) && CONSP (XCDR (tail));
5587 tail = XCDR (XCDR (tail)))
5588 {
5589 if (EQ (XCAR (tail), key))
5590 {
5591 if (found)
5592 *found = 1;
5593 return XCAR (XCDR (tail));
5594 }
5595 }
5596
5597 if (found)
5598 *found = 0;
5599 return Qnil;
5600 }
5601
5602
5603 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
5604 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
5605 PIXELS non-nil means return the size in pixels, otherwise return the
5606 size in canonical character units.
5607 FRAME is the frame on which the image will be displayed. FRAME nil
5608 or omitted means use the selected frame. */)
5609 (spec, pixels, frame)
5610 Lisp_Object spec, pixels, frame;
5611 {
5612 Lisp_Object size;
5613
5614 size = Qnil;
5615 if (valid_image_p (spec))
5616 {
5617 struct frame *f = check_x_frame (frame);
5618 int id = lookup_image (f, spec);
5619 struct image *img = IMAGE_FROM_ID (f, id);
5620 int width = img->width + 2 * img->hmargin;
5621 int height = img->height + 2 * img->vmargin;
5622
5623 if (NILP (pixels))
5624 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
5625 make_float ((double) height / CANON_Y_UNIT (f)));
5626 else
5627 size = Fcons (make_number (width), make_number (height));
5628 }
5629 else
5630 error ("Invalid image specification");
5631
5632 return size;
5633 }
5634
5635
5636 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
5637 doc: /* Return t if image SPEC has a mask bitmap.
5638 FRAME is the frame on which the image will be displayed. FRAME nil
5639 or omitted means use the selected frame. */)
5640 (spec, frame)
5641 Lisp_Object spec, frame;
5642 {
5643 Lisp_Object mask;
5644
5645 mask = Qnil;
5646 if (valid_image_p (spec))
5647 {
5648 struct frame *f = check_x_frame (frame);
5649 int id = lookup_image (f, spec);
5650 struct image *img = IMAGE_FROM_ID (f, id);
5651 if (img->mask)
5652 mask = Qt;
5653 }
5654 else
5655 error ("Invalid image specification");
5656
5657 return mask;
5658 }
5659
5660
5661 \f
5662 /***********************************************************************
5663 Image type independent image structures
5664 ***********************************************************************/
5665
5666 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5667 static void free_image P_ ((struct frame *f, struct image *img));
5668
5669
5670 /* Allocate and return a new image structure for image specification
5671 SPEC. SPEC has a hash value of HASH. */
5672
5673 static struct image *
5674 make_image (spec, hash)
5675 Lisp_Object spec;
5676 unsigned hash;
5677 {
5678 struct image *img = (struct image *) xmalloc (sizeof *img);
5679
5680 xassert (valid_image_p (spec));
5681 bzero (img, sizeof *img);
5682 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5683 xassert (img->type != NULL);
5684 img->spec = spec;
5685 img->data.lisp_val = Qnil;
5686 img->ascent = DEFAULT_IMAGE_ASCENT;
5687 img->hash = hash;
5688 return img;
5689 }
5690
5691
5692 /* Free image IMG which was used on frame F, including its resources. */
5693
5694 static void
5695 free_image (f, img)
5696 struct frame *f;
5697 struct image *img;
5698 {
5699 if (img)
5700 {
5701 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5702
5703 /* Remove IMG from the hash table of its cache. */
5704 if (img->prev)
5705 img->prev->next = img->next;
5706 else
5707 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5708
5709 if (img->next)
5710 img->next->prev = img->prev;
5711
5712 c->images[img->id] = NULL;
5713
5714 /* Free resources, then free IMG. */
5715 img->type->free (f, img);
5716 xfree (img);
5717 }
5718 }
5719
5720
5721 /* Prepare image IMG for display on frame F. Must be called before
5722 drawing an image. */
5723
5724 void
5725 prepare_image_for_display (f, img)
5726 struct frame *f;
5727 struct image *img;
5728 {
5729 EMACS_TIME t;
5730
5731 /* We're about to display IMG, so set its timestamp to `now'. */
5732 EMACS_GET_TIME (t);
5733 img->timestamp = EMACS_SECS (t);
5734
5735 /* If IMG doesn't have a pixmap yet, load it now, using the image
5736 type dependent loader function. */
5737 if (img->pixmap == None && !img->load_failed_p)
5738 img->load_failed_p = img->type->load (f, img) == 0;
5739 }
5740
5741
5742 /* Value is the number of pixels for the ascent of image IMG when
5743 drawn in face FACE. */
5744
5745 int
5746 image_ascent (img, face)
5747 struct image *img;
5748 struct face *face;
5749 {
5750 int height = img->height + img->vmargin;
5751 int ascent;
5752
5753 if (img->ascent == CENTERED_IMAGE_ASCENT)
5754 {
5755 if (face->font)
5756 /* This expression is arranged so that if the image can't be
5757 exactly centered, it will be moved slightly up. This is
5758 because a typical font is `top-heavy' (due to the presence
5759 uppercase letters), so the image placement should err towards
5760 being top-heavy too. It also just generally looks better. */
5761 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
5762 else
5763 ascent = height / 2;
5764 }
5765 else
5766 ascent = height * img->ascent / 100.0;
5767
5768 return ascent;
5769 }
5770
5771 \f
5772 /* Image background colors. */
5773
5774 static unsigned long
5775 four_corners_best (ximg, width, height)
5776 XImage *ximg;
5777 unsigned long width, height;
5778 {
5779 unsigned long corners[4], best;
5780 int i, best_count;
5781
5782 /* Get the colors at the corners of ximg. */
5783 corners[0] = XGetPixel (ximg, 0, 0);
5784 corners[1] = XGetPixel (ximg, width - 1, 0);
5785 corners[2] = XGetPixel (ximg, width - 1, height - 1);
5786 corners[3] = XGetPixel (ximg, 0, height - 1);
5787
5788 /* Choose the most frequently found color as background. */
5789 for (i = best_count = 0; i < 4; ++i)
5790 {
5791 int j, n;
5792
5793 for (j = n = 0; j < 4; ++j)
5794 if (corners[i] == corners[j])
5795 ++n;
5796
5797 if (n > best_count)
5798 best = corners[i], best_count = n;
5799 }
5800
5801 return best;
5802 }
5803
5804 /* Return the `background' field of IMG. If IMG doesn't have one yet,
5805 it is guessed heuristically. If non-zero, XIMG is an existing XImage
5806 object to use for the heuristic. */
5807
5808 unsigned long
5809 image_background (img, f, ximg)
5810 struct image *img;
5811 struct frame *f;
5812 XImage *ximg;
5813 {
5814 if (! img->background_valid)
5815 /* IMG doesn't have a background yet, try to guess a reasonable value. */
5816 {
5817 int free_ximg = !ximg;
5818
5819 if (! ximg)
5820 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
5821 0, 0, img->width, img->height, ~0, ZPixmap);
5822
5823 img->background = four_corners_best (ximg, img->width, img->height);
5824
5825 if (free_ximg)
5826 XDestroyImage (ximg);
5827
5828 img->background_valid = 1;
5829 }
5830
5831 return img->background;
5832 }
5833
5834 /* Return the `background_transparent' field of IMG. If IMG doesn't
5835 have one yet, it is guessed heuristically. If non-zero, MASK is an
5836 existing XImage object to use for the heuristic. */
5837
5838 int
5839 image_background_transparent (img, f, mask)
5840 struct image *img;
5841 struct frame *f;
5842 XImage *mask;
5843 {
5844 if (! img->background_transparent_valid)
5845 /* IMG doesn't have a background yet, try to guess a reasonable value. */
5846 {
5847 if (img->mask)
5848 {
5849 int free_mask = !mask;
5850
5851 if (! mask)
5852 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
5853 0, 0, img->width, img->height, ~0, ZPixmap);
5854
5855 img->background_transparent
5856 = !four_corners_best (mask, img->width, img->height);
5857
5858 if (free_mask)
5859 XDestroyImage (mask);
5860 }
5861 else
5862 img->background_transparent = 0;
5863
5864 img->background_transparent_valid = 1;
5865 }
5866
5867 return img->background_transparent;
5868 }
5869
5870 \f
5871 /***********************************************************************
5872 Helper functions for X image types
5873 ***********************************************************************/
5874
5875 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
5876 int, int));
5877 static void x_clear_image P_ ((struct frame *f, struct image *img));
5878 static unsigned long x_alloc_image_color P_ ((struct frame *f,
5879 struct image *img,
5880 Lisp_Object color_name,
5881 unsigned long dflt));
5882
5883
5884 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
5885 free the pixmap if any. MASK_P non-zero means clear the mask
5886 pixmap if any. COLORS_P non-zero means free colors allocated for
5887 the image, if any. */
5888
5889 static void
5890 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
5891 struct frame *f;
5892 struct image *img;
5893 int pixmap_p, mask_p, colors_p;
5894 {
5895 if (pixmap_p && img->pixmap)
5896 {
5897 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
5898 img->pixmap = None;
5899 img->background_valid = 0;
5900 }
5901
5902 if (mask_p && img->mask)
5903 {
5904 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
5905 img->mask = None;
5906 img->background_transparent_valid = 0;
5907 }
5908
5909 if (colors_p && img->ncolors)
5910 {
5911 x_free_colors (f, img->colors, img->ncolors);
5912 xfree (img->colors);
5913 img->colors = NULL;
5914 img->ncolors = 0;
5915 }
5916 }
5917
5918 /* Free X resources of image IMG which is used on frame F. */
5919
5920 static void
5921 x_clear_image (f, img)
5922 struct frame *f;
5923 struct image *img;
5924 {
5925 BLOCK_INPUT;
5926 x_clear_image_1 (f, img, 1, 1, 1);
5927 UNBLOCK_INPUT;
5928 }
5929
5930
5931 /* Allocate color COLOR_NAME for image IMG on frame F. If color
5932 cannot be allocated, use DFLT. Add a newly allocated color to
5933 IMG->colors, so that it can be freed again. Value is the pixel
5934 color. */
5935
5936 static unsigned long
5937 x_alloc_image_color (f, img, color_name, dflt)
5938 struct frame *f;
5939 struct image *img;
5940 Lisp_Object color_name;
5941 unsigned long dflt;
5942 {
5943 XColor color;
5944 unsigned long result;
5945
5946 xassert (STRINGP (color_name));
5947
5948 if (x_defined_color (f, XSTRING (color_name)->data, &color, 1))
5949 {
5950 /* This isn't called frequently so we get away with simply
5951 reallocating the color vector to the needed size, here. */
5952 ++img->ncolors;
5953 img->colors =
5954 (unsigned long *) xrealloc (img->colors,
5955 img->ncolors * sizeof *img->colors);
5956 img->colors[img->ncolors - 1] = color.pixel;
5957 result = color.pixel;
5958 }
5959 else
5960 result = dflt;
5961
5962 return result;
5963 }
5964
5965
5966 \f
5967 /***********************************************************************
5968 Image Cache
5969 ***********************************************************************/
5970
5971 static void cache_image P_ ((struct frame *f, struct image *img));
5972 static void postprocess_image P_ ((struct frame *, struct image *));
5973
5974
5975 /* Return a new, initialized image cache that is allocated from the
5976 heap. Call free_image_cache to free an image cache. */
5977
5978 struct image_cache *
5979 make_image_cache ()
5980 {
5981 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
5982 int size;
5983
5984 bzero (c, sizeof *c);
5985 c->size = 50;
5986 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
5987 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
5988 c->buckets = (struct image **) xmalloc (size);
5989 bzero (c->buckets, size);
5990 return c;
5991 }
5992
5993
5994 /* Free image cache of frame F. Be aware that X frames share images
5995 caches. */
5996
5997 void
5998 free_image_cache (f)
5999 struct frame *f;
6000 {
6001 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6002 if (c)
6003 {
6004 int i;
6005
6006 /* Cache should not be referenced by any frame when freed. */
6007 xassert (c->refcount == 0);
6008
6009 for (i = 0; i < c->used; ++i)
6010 free_image (f, c->images[i]);
6011 xfree (c->images);
6012 xfree (c->buckets);
6013 xfree (c);
6014 FRAME_X_IMAGE_CACHE (f) = NULL;
6015 }
6016 }
6017
6018
6019 /* Clear image cache of frame F. FORCE_P non-zero means free all
6020 images. FORCE_P zero means clear only images that haven't been
6021 displayed for some time. Should be called from time to time to
6022 reduce the number of loaded images. If image-eviction-seconds is
6023 non-nil, this frees images in the cache which weren't displayed for
6024 at least that many seconds. */
6025
6026 void
6027 clear_image_cache (f, force_p)
6028 struct frame *f;
6029 int force_p;
6030 {
6031 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6032
6033 if (c && INTEGERP (Vimage_cache_eviction_delay))
6034 {
6035 EMACS_TIME t;
6036 unsigned long old;
6037 int i, nfreed;
6038
6039 EMACS_GET_TIME (t);
6040 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
6041
6042 /* Block input so that we won't be interrupted by a SIGIO
6043 while being in an inconsistent state. */
6044 BLOCK_INPUT;
6045
6046 for (i = nfreed = 0; i < c->used; ++i)
6047 {
6048 struct image *img = c->images[i];
6049 if (img != NULL
6050 && (force_p || img->timestamp < old))
6051 {
6052 free_image (f, img);
6053 ++nfreed;
6054 }
6055 }
6056
6057 /* We may be clearing the image cache because, for example,
6058 Emacs was iconified for a longer period of time. In that
6059 case, current matrices may still contain references to
6060 images freed above. So, clear these matrices. */
6061 if (nfreed)
6062 {
6063 Lisp_Object tail, frame;
6064
6065 FOR_EACH_FRAME (tail, frame)
6066 {
6067 struct frame *f = XFRAME (frame);
6068 if (FRAME_X_P (f)
6069 && FRAME_X_IMAGE_CACHE (f) == c)
6070 clear_current_matrices (f);
6071 }
6072
6073 ++windows_or_buffers_changed;
6074 }
6075
6076 UNBLOCK_INPUT;
6077 }
6078 }
6079
6080
6081 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6082 0, 1, 0,
6083 doc: /* Clear the image cache of FRAME.
6084 FRAME nil or omitted means use the selected frame.
6085 FRAME t means clear the image caches of all frames. */)
6086 (frame)
6087 Lisp_Object frame;
6088 {
6089 if (EQ (frame, Qt))
6090 {
6091 Lisp_Object tail;
6092
6093 FOR_EACH_FRAME (tail, frame)
6094 if (FRAME_X_P (XFRAME (frame)))
6095 clear_image_cache (XFRAME (frame), 1);
6096 }
6097 else
6098 clear_image_cache (check_x_frame (frame), 1);
6099
6100 return Qnil;
6101 }
6102
6103
6104 /* Compute masks and transform image IMG on frame F, as specified
6105 by the image's specification, */
6106
6107 static void
6108 postprocess_image (f, img)
6109 struct frame *f;
6110 struct image *img;
6111 {
6112 /* Manipulation of the image's mask. */
6113 if (img->pixmap)
6114 {
6115 Lisp_Object conversion, spec;
6116 Lisp_Object mask;
6117
6118 spec = img->spec;
6119
6120 /* `:heuristic-mask t'
6121 `:mask heuristic'
6122 means build a mask heuristically.
6123 `:heuristic-mask (R G B)'
6124 `:mask (heuristic (R G B))'
6125 means build a mask from color (R G B) in the
6126 image.
6127 `:mask nil'
6128 means remove a mask, if any. */
6129
6130 mask = image_spec_value (spec, QCheuristic_mask, NULL);
6131 if (!NILP (mask))
6132 x_build_heuristic_mask (f, img, mask);
6133 else
6134 {
6135 int found_p;
6136
6137 mask = image_spec_value (spec, QCmask, &found_p);
6138
6139 if (EQ (mask, Qheuristic))
6140 x_build_heuristic_mask (f, img, Qt);
6141 else if (CONSP (mask)
6142 && EQ (XCAR (mask), Qheuristic))
6143 {
6144 if (CONSP (XCDR (mask)))
6145 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
6146 else
6147 x_build_heuristic_mask (f, img, XCDR (mask));
6148 }
6149 else if (NILP (mask) && found_p && img->mask)
6150 {
6151 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6152 img->mask = None;
6153 }
6154 }
6155
6156
6157 /* Should we apply an image transformation algorithm? */
6158 conversion = image_spec_value (spec, QCconversion, NULL);
6159 if (EQ (conversion, Qdisabled))
6160 x_disable_image (f, img);
6161 else if (EQ (conversion, Qlaplace))
6162 x_laplace (f, img);
6163 else if (EQ (conversion, Qemboss))
6164 x_emboss (f, img);
6165 else if (CONSP (conversion)
6166 && EQ (XCAR (conversion), Qedge_detection))
6167 {
6168 Lisp_Object tem;
6169 tem = XCDR (conversion);
6170 if (CONSP (tem))
6171 x_edge_detection (f, img,
6172 Fplist_get (tem, QCmatrix),
6173 Fplist_get (tem, QCcolor_adjustment));
6174 }
6175 }
6176 }
6177
6178
6179 /* Return the id of image with Lisp specification SPEC on frame F.
6180 SPEC must be a valid Lisp image specification (see valid_image_p). */
6181
6182 int
6183 lookup_image (f, spec)
6184 struct frame *f;
6185 Lisp_Object spec;
6186 {
6187 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6188 struct image *img;
6189 int i;
6190 unsigned hash;
6191 struct gcpro gcpro1;
6192 EMACS_TIME now;
6193
6194 /* F must be a window-system frame, and SPEC must be a valid image
6195 specification. */
6196 xassert (FRAME_WINDOW_P (f));
6197 xassert (valid_image_p (spec));
6198
6199 GCPRO1 (spec);
6200
6201 /* Look up SPEC in the hash table of the image cache. */
6202 hash = sxhash (spec, 0);
6203 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6204
6205 for (img = c->buckets[i]; img; img = img->next)
6206 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6207 break;
6208
6209 /* If not found, create a new image and cache it. */
6210 if (img == NULL)
6211 {
6212 extern Lisp_Object Qpostscript;
6213
6214 BLOCK_INPUT;
6215 img = make_image (spec, hash);
6216 cache_image (f, img);
6217 img->load_failed_p = img->type->load (f, img) == 0;
6218
6219 /* If we can't load the image, and we don't have a width and
6220 height, use some arbitrary width and height so that we can
6221 draw a rectangle for it. */
6222 if (img->load_failed_p)
6223 {
6224 Lisp_Object value;
6225
6226 value = image_spec_value (spec, QCwidth, NULL);
6227 img->width = (INTEGERP (value)
6228 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6229 value = image_spec_value (spec, QCheight, NULL);
6230 img->height = (INTEGERP (value)
6231 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6232 }
6233 else
6234 {
6235 /* Handle image type independent image attributes
6236 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
6237 `:background COLOR'. */
6238 Lisp_Object ascent, margin, relief, bg;
6239
6240 ascent = image_spec_value (spec, QCascent, NULL);
6241 if (INTEGERP (ascent))
6242 img->ascent = XFASTINT (ascent);
6243 else if (EQ (ascent, Qcenter))
6244 img->ascent = CENTERED_IMAGE_ASCENT;
6245
6246 margin = image_spec_value (spec, QCmargin, NULL);
6247 if (INTEGERP (margin) && XINT (margin) >= 0)
6248 img->vmargin = img->hmargin = XFASTINT (margin);
6249 else if (CONSP (margin) && INTEGERP (XCAR (margin))
6250 && INTEGERP (XCDR (margin)))
6251 {
6252 if (XINT (XCAR (margin)) > 0)
6253 img->hmargin = XFASTINT (XCAR (margin));
6254 if (XINT (XCDR (margin)) > 0)
6255 img->vmargin = XFASTINT (XCDR (margin));
6256 }
6257
6258 relief = image_spec_value (spec, QCrelief, NULL);
6259 if (INTEGERP (relief))
6260 {
6261 img->relief = XINT (relief);
6262 img->hmargin += abs (img->relief);
6263 img->vmargin += abs (img->relief);
6264 }
6265
6266 if (! img->background_valid)
6267 {
6268 bg = image_spec_value (img->spec, QCbackground, NULL);
6269 if (!NILP (bg))
6270 {
6271 img->background
6272 = x_alloc_image_color (f, img, bg,
6273 FRAME_BACKGROUND_PIXEL (f));
6274 img->background_valid = 1;
6275 }
6276 }
6277
6278 /* Do image transformations and compute masks, unless we
6279 don't have the image yet. */
6280 if (!EQ (*img->type->type, Qpostscript))
6281 postprocess_image (f, img);
6282 }
6283
6284 UNBLOCK_INPUT;
6285 xassert (!interrupt_input_blocked);
6286 }
6287
6288 /* We're using IMG, so set its timestamp to `now'. */
6289 EMACS_GET_TIME (now);
6290 img->timestamp = EMACS_SECS (now);
6291
6292 UNGCPRO;
6293
6294 /* Value is the image id. */
6295 return img->id;
6296 }
6297
6298
6299 /* Cache image IMG in the image cache of frame F. */
6300
6301 static void
6302 cache_image (f, img)
6303 struct frame *f;
6304 struct image *img;
6305 {
6306 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6307 int i;
6308
6309 /* Find a free slot in c->images. */
6310 for (i = 0; i < c->used; ++i)
6311 if (c->images[i] == NULL)
6312 break;
6313
6314 /* If no free slot found, maybe enlarge c->images. */
6315 if (i == c->used && c->used == c->size)
6316 {
6317 c->size *= 2;
6318 c->images = (struct image **) xrealloc (c->images,
6319 c->size * sizeof *c->images);
6320 }
6321
6322 /* Add IMG to c->images, and assign IMG an id. */
6323 c->images[i] = img;
6324 img->id = i;
6325 if (i == c->used)
6326 ++c->used;
6327
6328 /* Add IMG to the cache's hash table. */
6329 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6330 img->next = c->buckets[i];
6331 if (img->next)
6332 img->next->prev = img;
6333 img->prev = NULL;
6334 c->buckets[i] = img;
6335 }
6336
6337
6338 /* Call FN on every image in the image cache of frame F. Used to mark
6339 Lisp Objects in the image cache. */
6340
6341 void
6342 forall_images_in_image_cache (f, fn)
6343 struct frame *f;
6344 void (*fn) P_ ((struct image *img));
6345 {
6346 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6347 {
6348 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6349 if (c)
6350 {
6351 int i;
6352 for (i = 0; i < c->used; ++i)
6353 if (c->images[i])
6354 fn (c->images[i]);
6355 }
6356 }
6357 }
6358
6359
6360 \f
6361 /***********************************************************************
6362 X support code
6363 ***********************************************************************/
6364
6365 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6366 XImage **, Pixmap *));
6367 static void x_destroy_x_image P_ ((XImage *));
6368 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6369
6370
6371 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6372 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6373 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6374 via xmalloc. Print error messages via image_error if an error
6375 occurs. Value is non-zero if successful. */
6376
6377 static int
6378 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
6379 struct frame *f;
6380 int width, height, depth;
6381 XImage **ximg;
6382 Pixmap *pixmap;
6383 {
6384 Display *display = FRAME_X_DISPLAY (f);
6385 Screen *screen = FRAME_X_SCREEN (f);
6386 Window window = FRAME_X_WINDOW (f);
6387
6388 xassert (interrupt_input_blocked);
6389
6390 if (depth <= 0)
6391 depth = DefaultDepthOfScreen (screen);
6392 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6393 depth, ZPixmap, 0, NULL, width, height,
6394 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6395 if (*ximg == NULL)
6396 {
6397 image_error ("Unable to allocate X image", Qnil, Qnil);
6398 return 0;
6399 }
6400
6401 /* Allocate image raster. */
6402 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6403
6404 /* Allocate a pixmap of the same size. */
6405 *pixmap = XCreatePixmap (display, window, width, height, depth);
6406 if (*pixmap == None)
6407 {
6408 x_destroy_x_image (*ximg);
6409 *ximg = NULL;
6410 image_error ("Unable to create X pixmap", Qnil, Qnil);
6411 return 0;
6412 }
6413
6414 return 1;
6415 }
6416
6417
6418 /* Destroy XImage XIMG. Free XIMG->data. */
6419
6420 static void
6421 x_destroy_x_image (ximg)
6422 XImage *ximg;
6423 {
6424 xassert (interrupt_input_blocked);
6425 if (ximg)
6426 {
6427 xfree (ximg->data);
6428 ximg->data = NULL;
6429 XDestroyImage (ximg);
6430 }
6431 }
6432
6433
6434 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6435 are width and height of both the image and pixmap. */
6436
6437 static void
6438 x_put_x_image (f, ximg, pixmap, width, height)
6439 struct frame *f;
6440 XImage *ximg;
6441 Pixmap pixmap;
6442 {
6443 GC gc;
6444
6445 xassert (interrupt_input_blocked);
6446 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6447 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6448 XFreeGC (FRAME_X_DISPLAY (f), gc);
6449 }
6450
6451
6452 \f
6453 /***********************************************************************
6454 File Handling
6455 ***********************************************************************/
6456
6457 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
6458 static char *slurp_file P_ ((char *, int *));
6459
6460
6461 /* Find image file FILE. Look in data-directory, then
6462 x-bitmap-file-path. Value is the full name of the file found, or
6463 nil if not found. */
6464
6465 static Lisp_Object
6466 x_find_image_file (file)
6467 Lisp_Object file;
6468 {
6469 Lisp_Object file_found, search_path;
6470 struct gcpro gcpro1, gcpro2;
6471 int fd;
6472
6473 file_found = Qnil;
6474 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6475 GCPRO2 (file_found, search_path);
6476
6477 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
6478 fd = openp (search_path, file, Qnil, &file_found, 0);
6479
6480 if (fd == -1)
6481 file_found = Qnil;
6482 else
6483 close (fd);
6484
6485 UNGCPRO;
6486 return file_found;
6487 }
6488
6489
6490 /* Read FILE into memory. Value is a pointer to a buffer allocated
6491 with xmalloc holding FILE's contents. Value is null if an error
6492 occurred. *SIZE is set to the size of the file. */
6493
6494 static char *
6495 slurp_file (file, size)
6496 char *file;
6497 int *size;
6498 {
6499 FILE *fp = NULL;
6500 char *buf = NULL;
6501 struct stat st;
6502
6503 if (stat (file, &st) == 0
6504 && (fp = fopen (file, "r")) != NULL
6505 && (buf = (char *) xmalloc (st.st_size),
6506 fread (buf, 1, st.st_size, fp) == st.st_size))
6507 {
6508 *size = st.st_size;
6509 fclose (fp);
6510 }
6511 else
6512 {
6513 if (fp)
6514 fclose (fp);
6515 if (buf)
6516 {
6517 xfree (buf);
6518 buf = NULL;
6519 }
6520 }
6521
6522 return buf;
6523 }
6524
6525
6526 \f
6527 /***********************************************************************
6528 XBM images
6529 ***********************************************************************/
6530
6531 static int xbm_scan P_ ((char **, char *, char *, int *));
6532 static int xbm_load P_ ((struct frame *f, struct image *img));
6533 static int xbm_load_image P_ ((struct frame *f, struct image *img,
6534 char *, char *));
6535 static int xbm_image_p P_ ((Lisp_Object object));
6536 static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
6537 unsigned char **));
6538 static int xbm_file_p P_ ((Lisp_Object));
6539
6540
6541 /* Indices of image specification fields in xbm_format, below. */
6542
6543 enum xbm_keyword_index
6544 {
6545 XBM_TYPE,
6546 XBM_FILE,
6547 XBM_WIDTH,
6548 XBM_HEIGHT,
6549 XBM_DATA,
6550 XBM_FOREGROUND,
6551 XBM_BACKGROUND,
6552 XBM_ASCENT,
6553 XBM_MARGIN,
6554 XBM_RELIEF,
6555 XBM_ALGORITHM,
6556 XBM_HEURISTIC_MASK,
6557 XBM_MASK,
6558 XBM_LAST
6559 };
6560
6561 /* Vector of image_keyword structures describing the format
6562 of valid XBM image specifications. */
6563
6564 static struct image_keyword xbm_format[XBM_LAST] =
6565 {
6566 {":type", IMAGE_SYMBOL_VALUE, 1},
6567 {":file", IMAGE_STRING_VALUE, 0},
6568 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6569 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6570 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6571 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6572 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6573 {":ascent", IMAGE_ASCENT_VALUE, 0},
6574 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6575 {":relief", IMAGE_INTEGER_VALUE, 0},
6576 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6577 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6578 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6579 };
6580
6581 /* Structure describing the image type XBM. */
6582
6583 static struct image_type xbm_type =
6584 {
6585 &Qxbm,
6586 xbm_image_p,
6587 xbm_load,
6588 x_clear_image,
6589 NULL
6590 };
6591
6592 /* Tokens returned from xbm_scan. */
6593
6594 enum xbm_token
6595 {
6596 XBM_TK_IDENT = 256,
6597 XBM_TK_NUMBER
6598 };
6599
6600
6601 /* Return non-zero if OBJECT is a valid XBM-type image specification.
6602 A valid specification is a list starting with the symbol `image'
6603 The rest of the list is a property list which must contain an
6604 entry `:type xbm..
6605
6606 If the specification specifies a file to load, it must contain
6607 an entry `:file FILENAME' where FILENAME is a string.
6608
6609 If the specification is for a bitmap loaded from memory it must
6610 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6611 WIDTH and HEIGHT are integers > 0. DATA may be:
6612
6613 1. a string large enough to hold the bitmap data, i.e. it must
6614 have a size >= (WIDTH + 7) / 8 * HEIGHT
6615
6616 2. a bool-vector of size >= WIDTH * HEIGHT
6617
6618 3. a vector of strings or bool-vectors, one for each line of the
6619 bitmap.
6620
6621 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
6622 may not be specified in this case because they are defined in the
6623 XBM file.
6624
6625 Both the file and data forms may contain the additional entries
6626 `:background COLOR' and `:foreground COLOR'. If not present,
6627 foreground and background of the frame on which the image is
6628 displayed is used. */
6629
6630 static int
6631 xbm_image_p (object)
6632 Lisp_Object object;
6633 {
6634 struct image_keyword kw[XBM_LAST];
6635
6636 bcopy (xbm_format, kw, sizeof kw);
6637 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
6638 return 0;
6639
6640 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6641
6642 if (kw[XBM_FILE].count)
6643 {
6644 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6645 return 0;
6646 }
6647 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
6648 {
6649 /* In-memory XBM file. */
6650 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
6651 return 0;
6652 }
6653 else
6654 {
6655 Lisp_Object data;
6656 int width, height;
6657
6658 /* Entries for `:width', `:height' and `:data' must be present. */
6659 if (!kw[XBM_WIDTH].count
6660 || !kw[XBM_HEIGHT].count
6661 || !kw[XBM_DATA].count)
6662 return 0;
6663
6664 data = kw[XBM_DATA].value;
6665 width = XFASTINT (kw[XBM_WIDTH].value);
6666 height = XFASTINT (kw[XBM_HEIGHT].value);
6667
6668 /* Check type of data, and width and height against contents of
6669 data. */
6670 if (VECTORP (data))
6671 {
6672 int i;
6673
6674 /* Number of elements of the vector must be >= height. */
6675 if (XVECTOR (data)->size < height)
6676 return 0;
6677
6678 /* Each string or bool-vector in data must be large enough
6679 for one line of the image. */
6680 for (i = 0; i < height; ++i)
6681 {
6682 Lisp_Object elt = XVECTOR (data)->contents[i];
6683
6684 if (STRINGP (elt))
6685 {
6686 if (XSTRING (elt)->size
6687 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6688 return 0;
6689 }
6690 else if (BOOL_VECTOR_P (elt))
6691 {
6692 if (XBOOL_VECTOR (elt)->size < width)
6693 return 0;
6694 }
6695 else
6696 return 0;
6697 }
6698 }
6699 else if (STRINGP (data))
6700 {
6701 if (XSTRING (data)->size
6702 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6703 return 0;
6704 }
6705 else if (BOOL_VECTOR_P (data))
6706 {
6707 if (XBOOL_VECTOR (data)->size < width * height)
6708 return 0;
6709 }
6710 else
6711 return 0;
6712 }
6713
6714 return 1;
6715 }
6716
6717
6718 /* Scan a bitmap file. FP is the stream to read from. Value is
6719 either an enumerator from enum xbm_token, or a character for a
6720 single-character token, or 0 at end of file. If scanning an
6721 identifier, store the lexeme of the identifier in SVAL. If
6722 scanning a number, store its value in *IVAL. */
6723
6724 static int
6725 xbm_scan (s, end, sval, ival)
6726 char **s, *end;
6727 char *sval;
6728 int *ival;
6729 {
6730 int c;
6731
6732 loop:
6733
6734 /* Skip white space. */
6735 while (*s < end && (c = *(*s)++, isspace (c)))
6736 ;
6737
6738 if (*s >= end)
6739 c = 0;
6740 else if (isdigit (c))
6741 {
6742 int value = 0, digit;
6743
6744 if (c == '0' && *s < end)
6745 {
6746 c = *(*s)++;
6747 if (c == 'x' || c == 'X')
6748 {
6749 while (*s < end)
6750 {
6751 c = *(*s)++;
6752 if (isdigit (c))
6753 digit = c - '0';
6754 else if (c >= 'a' && c <= 'f')
6755 digit = c - 'a' + 10;
6756 else if (c >= 'A' && c <= 'F')
6757 digit = c - 'A' + 10;
6758 else
6759 break;
6760 value = 16 * value + digit;
6761 }
6762 }
6763 else if (isdigit (c))
6764 {
6765 value = c - '0';
6766 while (*s < end
6767 && (c = *(*s)++, isdigit (c)))
6768 value = 8 * value + c - '0';
6769 }
6770 }
6771 else
6772 {
6773 value = c - '0';
6774 while (*s < end
6775 && (c = *(*s)++, isdigit (c)))
6776 value = 10 * value + c - '0';
6777 }
6778
6779 if (*s < end)
6780 *s = *s - 1;
6781 *ival = value;
6782 c = XBM_TK_NUMBER;
6783 }
6784 else if (isalpha (c) || c == '_')
6785 {
6786 *sval++ = c;
6787 while (*s < end
6788 && (c = *(*s)++, (isalnum (c) || c == '_')))
6789 *sval++ = c;
6790 *sval = 0;
6791 if (*s < end)
6792 *s = *s - 1;
6793 c = XBM_TK_IDENT;
6794 }
6795 else if (c == '/' && **s == '*')
6796 {
6797 /* C-style comment. */
6798 ++*s;
6799 while (**s && (**s != '*' || *(*s + 1) != '/'))
6800 ++*s;
6801 if (**s)
6802 {
6803 *s += 2;
6804 goto loop;
6805 }
6806 }
6807
6808 return c;
6809 }
6810
6811
6812 /* Replacement for XReadBitmapFileData which isn't available under old
6813 X versions. CONTENTS is a pointer to a buffer to parse; END is the
6814 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
6815 the image. Return in *DATA the bitmap data allocated with xmalloc.
6816 Value is non-zero if successful. DATA null means just test if
6817 CONTENTS looks like an in-memory XBM file. */
6818
6819 static int
6820 xbm_read_bitmap_data (contents, end, width, height, data)
6821 char *contents, *end;
6822 int *width, *height;
6823 unsigned char **data;
6824 {
6825 char *s = contents;
6826 char buffer[BUFSIZ];
6827 int padding_p = 0;
6828 int v10 = 0;
6829 int bytes_per_line, i, nbytes;
6830 unsigned char *p;
6831 int value;
6832 int LA1;
6833
6834 #define match() \
6835 LA1 = xbm_scan (&s, end, buffer, &value)
6836
6837 #define expect(TOKEN) \
6838 if (LA1 != (TOKEN)) \
6839 goto failure; \
6840 else \
6841 match ()
6842
6843 #define expect_ident(IDENT) \
6844 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
6845 match (); \
6846 else \
6847 goto failure
6848
6849 *width = *height = -1;
6850 if (data)
6851 *data = NULL;
6852 LA1 = xbm_scan (&s, end, buffer, &value);
6853
6854 /* Parse defines for width, height and hot-spots. */
6855 while (LA1 == '#')
6856 {
6857 match ();
6858 expect_ident ("define");
6859 expect (XBM_TK_IDENT);
6860
6861 if (LA1 == XBM_TK_NUMBER);
6862 {
6863 char *p = strrchr (buffer, '_');
6864 p = p ? p + 1 : buffer;
6865 if (strcmp (p, "width") == 0)
6866 *width = value;
6867 else if (strcmp (p, "height") == 0)
6868 *height = value;
6869 }
6870 expect (XBM_TK_NUMBER);
6871 }
6872
6873 if (*width < 0 || *height < 0)
6874 goto failure;
6875 else if (data == NULL)
6876 goto success;
6877
6878 /* Parse bits. Must start with `static'. */
6879 expect_ident ("static");
6880 if (LA1 == XBM_TK_IDENT)
6881 {
6882 if (strcmp (buffer, "unsigned") == 0)
6883 {
6884 match ();
6885 expect_ident ("char");
6886 }
6887 else if (strcmp (buffer, "short") == 0)
6888 {
6889 match ();
6890 v10 = 1;
6891 if (*width % 16 && *width % 16 < 9)
6892 padding_p = 1;
6893 }
6894 else if (strcmp (buffer, "char") == 0)
6895 match ();
6896 else
6897 goto failure;
6898 }
6899 else
6900 goto failure;
6901
6902 expect (XBM_TK_IDENT);
6903 expect ('[');
6904 expect (']');
6905 expect ('=');
6906 expect ('{');
6907
6908 bytes_per_line = (*width + 7) / 8 + padding_p;
6909 nbytes = bytes_per_line * *height;
6910 p = *data = (char *) xmalloc (nbytes);
6911
6912 if (v10)
6913 {
6914 for (i = 0; i < nbytes; i += 2)
6915 {
6916 int val = value;
6917 expect (XBM_TK_NUMBER);
6918
6919 *p++ = val;
6920 if (!padding_p || ((i + 2) % bytes_per_line))
6921 *p++ = value >> 8;
6922
6923 if (LA1 == ',' || LA1 == '}')
6924 match ();
6925 else
6926 goto failure;
6927 }
6928 }
6929 else
6930 {
6931 for (i = 0; i < nbytes; ++i)
6932 {
6933 int val = value;
6934 expect (XBM_TK_NUMBER);
6935
6936 *p++ = val;
6937
6938 if (LA1 == ',' || LA1 == '}')
6939 match ();
6940 else
6941 goto failure;
6942 }
6943 }
6944
6945 success:
6946 return 1;
6947
6948 failure:
6949
6950 if (data && *data)
6951 {
6952 xfree (*data);
6953 *data = NULL;
6954 }
6955 return 0;
6956
6957 #undef match
6958 #undef expect
6959 #undef expect_ident
6960 }
6961
6962
6963 /* Load XBM image IMG which will be displayed on frame F from buffer
6964 CONTENTS. END is the end of the buffer. Value is non-zero if
6965 successful. */
6966
6967 static int
6968 xbm_load_image (f, img, contents, end)
6969 struct frame *f;
6970 struct image *img;
6971 char *contents, *end;
6972 {
6973 int rc;
6974 unsigned char *data;
6975 int success_p = 0;
6976
6977 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6978 if (rc)
6979 {
6980 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6981 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
6982 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
6983 Lisp_Object value;
6984
6985 xassert (img->width > 0 && img->height > 0);
6986
6987 /* Get foreground and background colors, maybe allocate colors. */
6988 value = image_spec_value (img->spec, QCforeground, NULL);
6989 if (!NILP (value))
6990 foreground = x_alloc_image_color (f, img, value, foreground);
6991 value = image_spec_value (img->spec, QCbackground, NULL);
6992 if (!NILP (value))
6993 {
6994 background = x_alloc_image_color (f, img, value, background);
6995 img->background = background;
6996 img->background_valid = 1;
6997 }
6998
6999 img->pixmap
7000 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7001 FRAME_X_WINDOW (f),
7002 data,
7003 img->width, img->height,
7004 foreground, background,
7005 depth);
7006 xfree (data);
7007
7008 if (img->pixmap == None)
7009 {
7010 x_clear_image (f, img);
7011 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
7012 }
7013 else
7014 success_p = 1;
7015 }
7016 else
7017 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7018
7019 return success_p;
7020 }
7021
7022
7023 /* Value is non-zero if DATA looks like an in-memory XBM file. */
7024
7025 static int
7026 xbm_file_p (data)
7027 Lisp_Object data;
7028 {
7029 int w, h;
7030 return (STRINGP (data)
7031 && xbm_read_bitmap_data (XSTRING (data)->data,
7032 (XSTRING (data)->data
7033 + STRING_BYTES (XSTRING (data))),
7034 &w, &h, NULL));
7035 }
7036
7037
7038 /* Fill image IMG which is used on frame F with pixmap data. Value is
7039 non-zero if successful. */
7040
7041 static int
7042 xbm_load (f, img)
7043 struct frame *f;
7044 struct image *img;
7045 {
7046 int success_p = 0;
7047 Lisp_Object file_name;
7048
7049 xassert (xbm_image_p (img->spec));
7050
7051 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7052 file_name = image_spec_value (img->spec, QCfile, NULL);
7053 if (STRINGP (file_name))
7054 {
7055 Lisp_Object file;
7056 char *contents;
7057 int size;
7058 struct gcpro gcpro1;
7059
7060 file = x_find_image_file (file_name);
7061 GCPRO1 (file);
7062 if (!STRINGP (file))
7063 {
7064 image_error ("Cannot find image file `%s'", file_name, Qnil);
7065 UNGCPRO;
7066 return 0;
7067 }
7068
7069 contents = slurp_file (XSTRING (file)->data, &size);
7070 if (contents == NULL)
7071 {
7072 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7073 UNGCPRO;
7074 return 0;
7075 }
7076
7077 success_p = xbm_load_image (f, img, contents, contents + size);
7078 UNGCPRO;
7079 }
7080 else
7081 {
7082 struct image_keyword fmt[XBM_LAST];
7083 Lisp_Object data;
7084 int depth;
7085 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7086 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7087 char *bits;
7088 int parsed_p;
7089 int in_memory_file_p = 0;
7090
7091 /* See if data looks like an in-memory XBM file. */
7092 data = image_spec_value (img->spec, QCdata, NULL);
7093 in_memory_file_p = xbm_file_p (data);
7094
7095 /* Parse the image specification. */
7096 bcopy (xbm_format, fmt, sizeof fmt);
7097 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
7098 xassert (parsed_p);
7099
7100 /* Get specified width, and height. */
7101 if (!in_memory_file_p)
7102 {
7103 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7104 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7105 xassert (img->width > 0 && img->height > 0);
7106 }
7107
7108 /* Get foreground and background colors, maybe allocate colors. */
7109 if (fmt[XBM_FOREGROUND].count
7110 && STRINGP (fmt[XBM_FOREGROUND].value))
7111 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7112 foreground);
7113 if (fmt[XBM_BACKGROUND].count
7114 && STRINGP (fmt[XBM_BACKGROUND].value))
7115 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7116 background);
7117
7118 if (in_memory_file_p)
7119 success_p = xbm_load_image (f, img, XSTRING (data)->data,
7120 (XSTRING (data)->data
7121 + STRING_BYTES (XSTRING (data))));
7122 else
7123 {
7124 if (VECTORP (data))
7125 {
7126 int i;
7127 char *p;
7128 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
7129
7130 p = bits = (char *) alloca (nbytes * img->height);
7131 for (i = 0; i < img->height; ++i, p += nbytes)
7132 {
7133 Lisp_Object line = XVECTOR (data)->contents[i];
7134 if (STRINGP (line))
7135 bcopy (XSTRING (line)->data, p, nbytes);
7136 else
7137 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7138 }
7139 }
7140 else if (STRINGP (data))
7141 bits = XSTRING (data)->data;
7142 else
7143 bits = XBOOL_VECTOR (data)->data;
7144
7145 /* Create the pixmap. */
7146 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7147 img->pixmap
7148 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7149 FRAME_X_WINDOW (f),
7150 bits,
7151 img->width, img->height,
7152 foreground, background,
7153 depth);
7154 if (img->pixmap)
7155 success_p = 1;
7156 else
7157 {
7158 image_error ("Unable to create pixmap for XBM image `%s'",
7159 img->spec, Qnil);
7160 x_clear_image (f, img);
7161 }
7162 }
7163 }
7164
7165 return success_p;
7166 }
7167
7168
7169 \f
7170 /***********************************************************************
7171 XPM images
7172 ***********************************************************************/
7173
7174 #if HAVE_XPM
7175
7176 static int xpm_image_p P_ ((Lisp_Object object));
7177 static int xpm_load P_ ((struct frame *f, struct image *img));
7178 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7179
7180 #include "X11/xpm.h"
7181
7182 /* The symbol `xpm' identifying XPM-format images. */
7183
7184 Lisp_Object Qxpm;
7185
7186 /* Indices of image specification fields in xpm_format, below. */
7187
7188 enum xpm_keyword_index
7189 {
7190 XPM_TYPE,
7191 XPM_FILE,
7192 XPM_DATA,
7193 XPM_ASCENT,
7194 XPM_MARGIN,
7195 XPM_RELIEF,
7196 XPM_ALGORITHM,
7197 XPM_HEURISTIC_MASK,
7198 XPM_MASK,
7199 XPM_COLOR_SYMBOLS,
7200 XPM_BACKGROUND,
7201 XPM_LAST
7202 };
7203
7204 /* Vector of image_keyword structures describing the format
7205 of valid XPM image specifications. */
7206
7207 static struct image_keyword xpm_format[XPM_LAST] =
7208 {
7209 {":type", IMAGE_SYMBOL_VALUE, 1},
7210 {":file", IMAGE_STRING_VALUE, 0},
7211 {":data", IMAGE_STRING_VALUE, 0},
7212 {":ascent", IMAGE_ASCENT_VALUE, 0},
7213 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7214 {":relief", IMAGE_INTEGER_VALUE, 0},
7215 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7216 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7217 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7218 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7219 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7220 };
7221
7222 /* Structure describing the image type XBM. */
7223
7224 static struct image_type xpm_type =
7225 {
7226 &Qxpm,
7227 xpm_image_p,
7228 xpm_load,
7229 x_clear_image,
7230 NULL
7231 };
7232
7233
7234 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
7235 functions for allocating image colors. Our own functions handle
7236 color allocation failures more gracefully than the ones on the XPM
7237 lib. */
7238
7239 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
7240 #define ALLOC_XPM_COLORS
7241 #endif
7242
7243 #ifdef ALLOC_XPM_COLORS
7244
7245 static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
7246 static void xpm_free_color_cache P_ ((void));
7247 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
7248 static int xpm_color_bucket P_ ((char *));
7249 static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
7250 XColor *, int));
7251
7252 /* An entry in a hash table used to cache color definitions of named
7253 colors. This cache is necessary to speed up XPM image loading in
7254 case we do color allocations ourselves. Without it, we would need
7255 a call to XParseColor per pixel in the image. */
7256
7257 struct xpm_cached_color
7258 {
7259 /* Next in collision chain. */
7260 struct xpm_cached_color *next;
7261
7262 /* Color definition (RGB and pixel color). */
7263 XColor color;
7264
7265 /* Color name. */
7266 char name[1];
7267 };
7268
7269 /* The hash table used for the color cache, and its bucket vector
7270 size. */
7271
7272 #define XPM_COLOR_CACHE_BUCKETS 1001
7273 struct xpm_cached_color **xpm_color_cache;
7274
7275 /* Initialize the color cache. */
7276
7277 static void
7278 xpm_init_color_cache (f, attrs)
7279 struct frame *f;
7280 XpmAttributes *attrs;
7281 {
7282 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
7283 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
7284 memset (xpm_color_cache, 0, nbytes);
7285 init_color_table ();
7286
7287 if (attrs->valuemask & XpmColorSymbols)
7288 {
7289 int i;
7290 XColor color;
7291
7292 for (i = 0; i < attrs->numsymbols; ++i)
7293 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7294 attrs->colorsymbols[i].value, &color))
7295 {
7296 color.pixel = lookup_rgb_color (f, color.red, color.green,
7297 color.blue);
7298 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
7299 }
7300 }
7301 }
7302
7303
7304 /* Free the color cache. */
7305
7306 static void
7307 xpm_free_color_cache ()
7308 {
7309 struct xpm_cached_color *p, *next;
7310 int i;
7311
7312 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
7313 for (p = xpm_color_cache[i]; p; p = next)
7314 {
7315 next = p->next;
7316 xfree (p);
7317 }
7318
7319 xfree (xpm_color_cache);
7320 xpm_color_cache = NULL;
7321 free_color_table ();
7322 }
7323
7324
7325 /* Return the bucket index for color named COLOR_NAME in the color
7326 cache. */
7327
7328 static int
7329 xpm_color_bucket (color_name)
7330 char *color_name;
7331 {
7332 unsigned h = 0;
7333 char *s;
7334
7335 for (s = color_name; *s; ++s)
7336 h = (h << 2) ^ *s;
7337 return h %= XPM_COLOR_CACHE_BUCKETS;
7338 }
7339
7340
7341 /* On frame F, cache values COLOR for color with name COLOR_NAME.
7342 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
7343 entry added. */
7344
7345 static struct xpm_cached_color *
7346 xpm_cache_color (f, color_name, color, bucket)
7347 struct frame *f;
7348 char *color_name;
7349 XColor *color;
7350 int bucket;
7351 {
7352 size_t nbytes;
7353 struct xpm_cached_color *p;
7354
7355 if (bucket < 0)
7356 bucket = xpm_color_bucket (color_name);
7357
7358 nbytes = sizeof *p + strlen (color_name);
7359 p = (struct xpm_cached_color *) xmalloc (nbytes);
7360 strcpy (p->name, color_name);
7361 p->color = *color;
7362 p->next = xpm_color_cache[bucket];
7363 xpm_color_cache[bucket] = p;
7364 return p;
7365 }
7366
7367
7368 /* Look up color COLOR_NAME for frame F in the color cache. If found,
7369 return the cached definition in *COLOR. Otherwise, make a new
7370 entry in the cache and allocate the color. Value is zero if color
7371 allocation failed. */
7372
7373 static int
7374 xpm_lookup_color (f, color_name, color)
7375 struct frame *f;
7376 char *color_name;
7377 XColor *color;
7378 {
7379 struct xpm_cached_color *p;
7380 int h = xpm_color_bucket (color_name);
7381
7382 for (p = xpm_color_cache[h]; p; p = p->next)
7383 if (strcmp (p->name, color_name) == 0)
7384 break;
7385
7386 if (p != NULL)
7387 *color = p->color;
7388 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7389 color_name, color))
7390 {
7391 color->pixel = lookup_rgb_color (f, color->red, color->green,
7392 color->blue);
7393 p = xpm_cache_color (f, color_name, color, h);
7394 }
7395
7396 return p != NULL;
7397 }
7398
7399
7400 /* Callback for allocating color COLOR_NAME. Called from the XPM lib.
7401 CLOSURE is a pointer to the frame on which we allocate the
7402 color. Return in *COLOR the allocated color. Value is non-zero
7403 if successful. */
7404
7405 static int
7406 xpm_alloc_color (dpy, cmap, color_name, color, closure)
7407 Display *dpy;
7408 Colormap cmap;
7409 char *color_name;
7410 XColor *color;
7411 void *closure;
7412 {
7413 return xpm_lookup_color ((struct frame *) closure, color_name, color);
7414 }
7415
7416
7417 /* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
7418 is a pointer to the frame on which we allocate the color. Value is
7419 non-zero if successful. */
7420
7421 static int
7422 xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7423 Display *dpy;
7424 Colormap cmap;
7425 Pixel *pixels;
7426 int npixels;
7427 void *closure;
7428 {
7429 return 1;
7430 }
7431
7432 #endif /* ALLOC_XPM_COLORS */
7433
7434
7435 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7436 for XPM images. Such a list must consist of conses whose car and
7437 cdr are strings. */
7438
7439 static int
7440 xpm_valid_color_symbols_p (color_symbols)
7441 Lisp_Object color_symbols;
7442 {
7443 while (CONSP (color_symbols))
7444 {
7445 Lisp_Object sym = XCAR (color_symbols);
7446 if (!CONSP (sym)
7447 || !STRINGP (XCAR (sym))
7448 || !STRINGP (XCDR (sym)))
7449 break;
7450 color_symbols = XCDR (color_symbols);
7451 }
7452
7453 return NILP (color_symbols);
7454 }
7455
7456
7457 /* Value is non-zero if OBJECT is a valid XPM image specification. */
7458
7459 static int
7460 xpm_image_p (object)
7461 Lisp_Object object;
7462 {
7463 struct image_keyword fmt[XPM_LAST];
7464 bcopy (xpm_format, fmt, sizeof fmt);
7465 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
7466 /* Either `:file' or `:data' must be present. */
7467 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7468 /* Either no `:color-symbols' or it's a list of conses
7469 whose car and cdr are strings. */
7470 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7471 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
7472 }
7473
7474
7475 /* Load image IMG which will be displayed on frame F. Value is
7476 non-zero if successful. */
7477
7478 static int
7479 xpm_load (f, img)
7480 struct frame *f;
7481 struct image *img;
7482 {
7483 int rc;
7484 XpmAttributes attrs;
7485 Lisp_Object specified_file, color_symbols;
7486
7487 /* Configure the XPM lib. Use the visual of frame F. Allocate
7488 close colors. Return colors allocated. */
7489 bzero (&attrs, sizeof attrs);
7490 attrs.visual = FRAME_X_VISUAL (f);
7491 attrs.colormap = FRAME_X_COLORMAP (f);
7492 attrs.valuemask |= XpmVisual;
7493 attrs.valuemask |= XpmColormap;
7494
7495 #ifdef ALLOC_XPM_COLORS
7496 /* Allocate colors with our own functions which handle
7497 failing color allocation more gracefully. */
7498 attrs.color_closure = f;
7499 attrs.alloc_color = xpm_alloc_color;
7500 attrs.free_colors = xpm_free_colors;
7501 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7502 #else /* not ALLOC_XPM_COLORS */
7503 /* Let the XPM lib allocate colors. */
7504 attrs.valuemask |= XpmReturnAllocPixels;
7505 #ifdef XpmAllocCloseColors
7506 attrs.alloc_close_colors = 1;
7507 attrs.valuemask |= XpmAllocCloseColors;
7508 #else /* not XpmAllocCloseColors */
7509 attrs.closeness = 600;
7510 attrs.valuemask |= XpmCloseness;
7511 #endif /* not XpmAllocCloseColors */
7512 #endif /* ALLOC_XPM_COLORS */
7513
7514 /* If image specification contains symbolic color definitions, add
7515 these to `attrs'. */
7516 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7517 if (CONSP (color_symbols))
7518 {
7519 Lisp_Object tail;
7520 XpmColorSymbol *xpm_syms;
7521 int i, size;
7522
7523 attrs.valuemask |= XpmColorSymbols;
7524
7525 /* Count number of symbols. */
7526 attrs.numsymbols = 0;
7527 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7528 ++attrs.numsymbols;
7529
7530 /* Allocate an XpmColorSymbol array. */
7531 size = attrs.numsymbols * sizeof *xpm_syms;
7532 xpm_syms = (XpmColorSymbol *) alloca (size);
7533 bzero (xpm_syms, size);
7534 attrs.colorsymbols = xpm_syms;
7535
7536 /* Fill the color symbol array. */
7537 for (tail = color_symbols, i = 0;
7538 CONSP (tail);
7539 ++i, tail = XCDR (tail))
7540 {
7541 Lisp_Object name = XCAR (XCAR (tail));
7542 Lisp_Object color = XCDR (XCAR (tail));
7543 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7544 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7545 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7546 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7547 }
7548 }
7549
7550 /* Create a pixmap for the image, either from a file, or from a
7551 string buffer containing data in the same format as an XPM file. */
7552 #ifdef ALLOC_XPM_COLORS
7553 xpm_init_color_cache (f, &attrs);
7554 #endif
7555
7556 specified_file = image_spec_value (img->spec, QCfile, NULL);
7557 if (STRINGP (specified_file))
7558 {
7559 Lisp_Object file = x_find_image_file (specified_file);
7560 if (!STRINGP (file))
7561 {
7562 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7563 return 0;
7564 }
7565
7566 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7567 XSTRING (file)->data, &img->pixmap, &img->mask,
7568 &attrs);
7569 }
7570 else
7571 {
7572 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7573 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7574 XSTRING (buffer)->data,
7575 &img->pixmap, &img->mask,
7576 &attrs);
7577 }
7578
7579 if (rc == XpmSuccess)
7580 {
7581 #ifdef ALLOC_XPM_COLORS
7582 img->colors = colors_in_color_table (&img->ncolors);
7583 #else /* not ALLOC_XPM_COLORS */
7584 int i;
7585
7586 img->ncolors = attrs.nalloc_pixels;
7587 img->colors = (unsigned long *) xmalloc (img->ncolors
7588 * sizeof *img->colors);
7589 for (i = 0; i < attrs.nalloc_pixels; ++i)
7590 {
7591 img->colors[i] = attrs.alloc_pixels[i];
7592 #ifdef DEBUG_X_COLORS
7593 register_color (img->colors[i]);
7594 #endif
7595 }
7596 #endif /* not ALLOC_XPM_COLORS */
7597
7598 img->width = attrs.width;
7599 img->height = attrs.height;
7600 xassert (img->width > 0 && img->height > 0);
7601
7602 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
7603 XpmFreeAttributes (&attrs);
7604 }
7605 else
7606 {
7607 switch (rc)
7608 {
7609 case XpmOpenFailed:
7610 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7611 break;
7612
7613 case XpmFileInvalid:
7614 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7615 break;
7616
7617 case XpmNoMemory:
7618 image_error ("Out of memory (%s)", img->spec, Qnil);
7619 break;
7620
7621 case XpmColorFailed:
7622 image_error ("Color allocation error (%s)", img->spec, Qnil);
7623 break;
7624
7625 default:
7626 image_error ("Unknown error (%s)", img->spec, Qnil);
7627 break;
7628 }
7629 }
7630
7631 #ifdef ALLOC_XPM_COLORS
7632 xpm_free_color_cache ();
7633 #endif
7634 return rc == XpmSuccess;
7635 }
7636
7637 #endif /* HAVE_XPM != 0 */
7638
7639 \f
7640 /***********************************************************************
7641 Color table
7642 ***********************************************************************/
7643
7644 /* An entry in the color table mapping an RGB color to a pixel color. */
7645
7646 struct ct_color
7647 {
7648 int r, g, b;
7649 unsigned long pixel;
7650
7651 /* Next in color table collision list. */
7652 struct ct_color *next;
7653 };
7654
7655 /* The bucket vector size to use. Must be prime. */
7656
7657 #define CT_SIZE 101
7658
7659 /* Value is a hash of the RGB color given by R, G, and B. */
7660
7661 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7662
7663 /* The color hash table. */
7664
7665 struct ct_color **ct_table;
7666
7667 /* Number of entries in the color table. */
7668
7669 int ct_colors_allocated;
7670
7671 /* Initialize the color table. */
7672
7673 static void
7674 init_color_table ()
7675 {
7676 int size = CT_SIZE * sizeof (*ct_table);
7677 ct_table = (struct ct_color **) xmalloc (size);
7678 bzero (ct_table, size);
7679 ct_colors_allocated = 0;
7680 }
7681
7682
7683 /* Free memory associated with the color table. */
7684
7685 static void
7686 free_color_table ()
7687 {
7688 int i;
7689 struct ct_color *p, *next;
7690
7691 for (i = 0; i < CT_SIZE; ++i)
7692 for (p = ct_table[i]; p; p = next)
7693 {
7694 next = p->next;
7695 xfree (p);
7696 }
7697
7698 xfree (ct_table);
7699 ct_table = NULL;
7700 }
7701
7702
7703 /* Value is a pixel color for RGB color R, G, B on frame F. If an
7704 entry for that color already is in the color table, return the
7705 pixel color of that entry. Otherwise, allocate a new color for R,
7706 G, B, and make an entry in the color table. */
7707
7708 static unsigned long
7709 lookup_rgb_color (f, r, g, b)
7710 struct frame *f;
7711 int r, g, b;
7712 {
7713 unsigned hash = CT_HASH_RGB (r, g, b);
7714 int i = hash % CT_SIZE;
7715 struct ct_color *p;
7716
7717 for (p = ct_table[i]; p; p = p->next)
7718 if (p->r == r && p->g == g && p->b == b)
7719 break;
7720
7721 if (p == NULL)
7722 {
7723 XColor color;
7724 Colormap cmap;
7725 int rc;
7726
7727 color.red = r;
7728 color.green = g;
7729 color.blue = b;
7730
7731 cmap = FRAME_X_COLORMAP (f);
7732 rc = x_alloc_nearest_color (f, cmap, &color);
7733
7734 if (rc)
7735 {
7736 ++ct_colors_allocated;
7737
7738 p = (struct ct_color *) xmalloc (sizeof *p);
7739 p->r = r;
7740 p->g = g;
7741 p->b = b;
7742 p->pixel = color.pixel;
7743 p->next = ct_table[i];
7744 ct_table[i] = p;
7745 }
7746 else
7747 return FRAME_FOREGROUND_PIXEL (f);
7748 }
7749
7750 return p->pixel;
7751 }
7752
7753
7754 /* Look up pixel color PIXEL which is used on frame F in the color
7755 table. If not already present, allocate it. Value is PIXEL. */
7756
7757 static unsigned long
7758 lookup_pixel_color (f, pixel)
7759 struct frame *f;
7760 unsigned long pixel;
7761 {
7762 int i = pixel % CT_SIZE;
7763 struct ct_color *p;
7764
7765 for (p = ct_table[i]; p; p = p->next)
7766 if (p->pixel == pixel)
7767 break;
7768
7769 if (p == NULL)
7770 {
7771 XColor color;
7772 Colormap cmap;
7773 int rc;
7774
7775 cmap = FRAME_X_COLORMAP (f);
7776 color.pixel = pixel;
7777 x_query_color (f, &color);
7778 rc = x_alloc_nearest_color (f, cmap, &color);
7779
7780 if (rc)
7781 {
7782 ++ct_colors_allocated;
7783
7784 p = (struct ct_color *) xmalloc (sizeof *p);
7785 p->r = color.red;
7786 p->g = color.green;
7787 p->b = color.blue;
7788 p->pixel = pixel;
7789 p->next = ct_table[i];
7790 ct_table[i] = p;
7791 }
7792 else
7793 return FRAME_FOREGROUND_PIXEL (f);
7794 }
7795
7796 return p->pixel;
7797 }
7798
7799
7800 /* Value is a vector of all pixel colors contained in the color table,
7801 allocated via xmalloc. Set *N to the number of colors. */
7802
7803 static unsigned long *
7804 colors_in_color_table (n)
7805 int *n;
7806 {
7807 int i, j;
7808 struct ct_color *p;
7809 unsigned long *colors;
7810
7811 if (ct_colors_allocated == 0)
7812 {
7813 *n = 0;
7814 colors = NULL;
7815 }
7816 else
7817 {
7818 colors = (unsigned long *) xmalloc (ct_colors_allocated
7819 * sizeof *colors);
7820 *n = ct_colors_allocated;
7821
7822 for (i = j = 0; i < CT_SIZE; ++i)
7823 for (p = ct_table[i]; p; p = p->next)
7824 colors[j++] = p->pixel;
7825 }
7826
7827 return colors;
7828 }
7829
7830
7831 \f
7832 /***********************************************************************
7833 Algorithms
7834 ***********************************************************************/
7835
7836 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
7837 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
7838 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
7839
7840 /* Non-zero means draw a cross on images having `:conversion
7841 disabled'. */
7842
7843 int cross_disabled_images;
7844
7845 /* Edge detection matrices for different edge-detection
7846 strategies. */
7847
7848 static int emboss_matrix[9] = {
7849 /* x - 1 x x + 1 */
7850 2, -1, 0, /* y - 1 */
7851 -1, 0, 1, /* y */
7852 0, 1, -2 /* y + 1 */
7853 };
7854
7855 static int laplace_matrix[9] = {
7856 /* x - 1 x x + 1 */
7857 1, 0, 0, /* y - 1 */
7858 0, 0, 0, /* y */
7859 0, 0, -1 /* y + 1 */
7860 };
7861
7862 /* Value is the intensity of the color whose red/green/blue values
7863 are R, G, and B. */
7864
7865 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
7866
7867
7868 /* On frame F, return an array of XColor structures describing image
7869 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
7870 non-zero means also fill the red/green/blue members of the XColor
7871 structures. Value is a pointer to the array of XColors structures,
7872 allocated with xmalloc; it must be freed by the caller. */
7873
7874 static XColor *
7875 x_to_xcolors (f, img, rgb_p)
7876 struct frame *f;
7877 struct image *img;
7878 int rgb_p;
7879 {
7880 int x, y;
7881 XColor *colors, *p;
7882 XImage *ximg;
7883
7884 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
7885
7886 /* Get the X image IMG->pixmap. */
7887 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7888 0, 0, img->width, img->height, ~0, ZPixmap);
7889
7890 /* Fill the `pixel' members of the XColor array. I wished there
7891 were an easy and portable way to circumvent XGetPixel. */
7892 p = colors;
7893 for (y = 0; y < img->height; ++y)
7894 {
7895 XColor *row = p;
7896
7897 for (x = 0; x < img->width; ++x, ++p)
7898 p->pixel = XGetPixel (ximg, x, y);
7899
7900 if (rgb_p)
7901 x_query_colors (f, row, img->width);
7902 }
7903
7904 XDestroyImage (ximg);
7905 return colors;
7906 }
7907
7908
7909 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
7910 RGB members are set. F is the frame on which this all happens.
7911 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
7912
7913 static void
7914 x_from_xcolors (f, img, colors)
7915 struct frame *f;
7916 struct image *img;
7917 XColor *colors;
7918 {
7919 int x, y;
7920 XImage *oimg;
7921 Pixmap pixmap;
7922 XColor *p;
7923
7924 init_color_table ();
7925
7926 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
7927 &oimg, &pixmap);
7928 p = colors;
7929 for (y = 0; y < img->height; ++y)
7930 for (x = 0; x < img->width; ++x, ++p)
7931 {
7932 unsigned long pixel;
7933 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
7934 XPutPixel (oimg, x, y, pixel);
7935 }
7936
7937 xfree (colors);
7938 x_clear_image_1 (f, img, 1, 0, 1);
7939
7940 x_put_x_image (f, oimg, pixmap, img->width, img->height);
7941 x_destroy_x_image (oimg);
7942 img->pixmap = pixmap;
7943 img->colors = colors_in_color_table (&img->ncolors);
7944 free_color_table ();
7945 }
7946
7947
7948 /* On frame F, perform edge-detection on image IMG.
7949
7950 MATRIX is a nine-element array specifying the transformation
7951 matrix. See emboss_matrix for an example.
7952
7953 COLOR_ADJUST is a color adjustment added to each pixel of the
7954 outgoing image. */
7955
7956 static void
7957 x_detect_edges (f, img, matrix, color_adjust)
7958 struct frame *f;
7959 struct image *img;
7960 int matrix[9], color_adjust;
7961 {
7962 XColor *colors = x_to_xcolors (f, img, 1);
7963 XColor *new, *p;
7964 int x, y, i, sum;
7965
7966 for (i = sum = 0; i < 9; ++i)
7967 sum += abs (matrix[i]);
7968
7969 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
7970
7971 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
7972
7973 for (y = 0; y < img->height; ++y)
7974 {
7975 p = COLOR (new, 0, y);
7976 p->red = p->green = p->blue = 0xffff/2;
7977 p = COLOR (new, img->width - 1, y);
7978 p->red = p->green = p->blue = 0xffff/2;
7979 }
7980
7981 for (x = 1; x < img->width - 1; ++x)
7982 {
7983 p = COLOR (new, x, 0);
7984 p->red = p->green = p->blue = 0xffff/2;
7985 p = COLOR (new, x, img->height - 1);
7986 p->red = p->green = p->blue = 0xffff/2;
7987 }
7988
7989 for (y = 1; y < img->height - 1; ++y)
7990 {
7991 p = COLOR (new, 1, y);
7992
7993 for (x = 1; x < img->width - 1; ++x, ++p)
7994 {
7995 int r, g, b, y1, x1;
7996
7997 r = g = b = i = 0;
7998 for (y1 = y - 1; y1 < y + 2; ++y1)
7999 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
8000 if (matrix[i])
8001 {
8002 XColor *t = COLOR (colors, x1, y1);
8003 r += matrix[i] * t->red;
8004 g += matrix[i] * t->green;
8005 b += matrix[i] * t->blue;
8006 }
8007
8008 r = (r / sum + color_adjust) & 0xffff;
8009 g = (g / sum + color_adjust) & 0xffff;
8010 b = (b / sum + color_adjust) & 0xffff;
8011 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
8012 }
8013 }
8014
8015 xfree (colors);
8016 x_from_xcolors (f, img, new);
8017
8018 #undef COLOR
8019 }
8020
8021
8022 /* Perform the pre-defined `emboss' edge-detection on image IMG
8023 on frame F. */
8024
8025 static void
8026 x_emboss (f, img)
8027 struct frame *f;
8028 struct image *img;
8029 {
8030 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
8031 }
8032
8033
8034 /* Perform the pre-defined `laplace' edge-detection on image IMG
8035 on frame F. */
8036
8037 static void
8038 x_laplace (f, img)
8039 struct frame *f;
8040 struct image *img;
8041 {
8042 x_detect_edges (f, img, laplace_matrix, 45000);
8043 }
8044
8045
8046 /* Perform edge-detection on image IMG on frame F, with specified
8047 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
8048
8049 MATRIX must be either
8050
8051 - a list of at least 9 numbers in row-major form
8052 - a vector of at least 9 numbers
8053
8054 COLOR_ADJUST nil means use a default; otherwise it must be a
8055 number. */
8056
8057 static void
8058 x_edge_detection (f, img, matrix, color_adjust)
8059 struct frame *f;
8060 struct image *img;
8061 Lisp_Object matrix, color_adjust;
8062 {
8063 int i = 0;
8064 int trans[9];
8065
8066 if (CONSP (matrix))
8067 {
8068 for (i = 0;
8069 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
8070 ++i, matrix = XCDR (matrix))
8071 trans[i] = XFLOATINT (XCAR (matrix));
8072 }
8073 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
8074 {
8075 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
8076 trans[i] = XFLOATINT (AREF (matrix, i));
8077 }
8078
8079 if (NILP (color_adjust))
8080 color_adjust = make_number (0xffff / 2);
8081
8082 if (i == 9 && NUMBERP (color_adjust))
8083 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
8084 }
8085
8086
8087 /* Transform image IMG on frame F so that it looks disabled. */
8088
8089 static void
8090 x_disable_image (f, img)
8091 struct frame *f;
8092 struct image *img;
8093 {
8094 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8095
8096 if (dpyinfo->n_planes >= 2)
8097 {
8098 /* Color (or grayscale). Convert to gray, and equalize. Just
8099 drawing such images with a stipple can look very odd, so
8100 we're using this method instead. */
8101 XColor *colors = x_to_xcolors (f, img, 1);
8102 XColor *p, *end;
8103 const int h = 15000;
8104 const int l = 30000;
8105
8106 for (p = colors, end = colors + img->width * img->height;
8107 p < end;
8108 ++p)
8109 {
8110 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
8111 int i2 = (0xffff - h - l) * i / 0xffff + l;
8112 p->red = p->green = p->blue = i2;
8113 }
8114
8115 x_from_xcolors (f, img, colors);
8116 }
8117
8118 /* Draw a cross over the disabled image, if we must or if we
8119 should. */
8120 if (dpyinfo->n_planes < 2 || cross_disabled_images)
8121 {
8122 Display *dpy = FRAME_X_DISPLAY (f);
8123 GC gc;
8124
8125 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
8126 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
8127 XDrawLine (dpy, img->pixmap, gc, 0, 0,
8128 img->width - 1, img->height - 1);
8129 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
8130 img->width - 1, 0);
8131 XFreeGC (dpy, gc);
8132
8133 if (img->mask)
8134 {
8135 gc = XCreateGC (dpy, img->mask, 0, NULL);
8136 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
8137 XDrawLine (dpy, img->mask, gc, 0, 0,
8138 img->width - 1, img->height - 1);
8139 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
8140 img->width - 1, 0);
8141 XFreeGC (dpy, gc);
8142 }
8143 }
8144 }
8145
8146
8147 /* Build a mask for image IMG which is used on frame F. FILE is the
8148 name of an image file, for error messages. HOW determines how to
8149 determine the background color of IMG. If it is a list '(R G B)',
8150 with R, G, and B being integers >= 0, take that as the color of the
8151 background. Otherwise, determine the background color of IMG
8152 heuristically. Value is non-zero if successful. */
8153
8154 static int
8155 x_build_heuristic_mask (f, img, how)
8156 struct frame *f;
8157 struct image *img;
8158 Lisp_Object how;
8159 {
8160 Display *dpy = FRAME_X_DISPLAY (f);
8161 XImage *ximg, *mask_img;
8162 int x, y, rc, use_img_background;
8163 unsigned long bg = 0;
8164
8165 if (img->mask)
8166 {
8167 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8168 img->mask = None;
8169 img->background_transparent_valid = 0;
8170 }
8171
8172 /* Create an image and pixmap serving as mask. */
8173 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
8174 &mask_img, &img->mask);
8175 if (!rc)
8176 return 0;
8177
8178 /* Get the X image of IMG->pixmap. */
8179 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
8180 ~0, ZPixmap);
8181
8182 /* Determine the background color of ximg. If HOW is `(R G B)'
8183 take that as color. Otherwise, use the image's background color. */
8184 use_img_background = 1;
8185
8186 if (CONSP (how))
8187 {
8188 int rgb[3], i;
8189
8190 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
8191 {
8192 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
8193 how = XCDR (how);
8194 }
8195
8196 if (i == 3 && NILP (how))
8197 {
8198 char color_name[30];
8199 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
8200 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
8201 use_img_background = 0;
8202 }
8203 }
8204
8205 if (use_img_background)
8206 bg = IMAGE_BACKGROUND (img, f, ximg);
8207
8208 /* Set all bits in mask_img to 1 whose color in ximg is different
8209 from the background color bg. */
8210 for (y = 0; y < img->height; ++y)
8211 for (x = 0; x < img->width; ++x)
8212 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
8213
8214 /* Fill in the background_transparent field while we have the mask handy. */
8215 image_background_transparent (img, f, mask_img);
8216
8217 /* Put mask_img into img->mask. */
8218 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8219 x_destroy_x_image (mask_img);
8220 XDestroyImage (ximg);
8221
8222 return 1;
8223 }
8224
8225
8226 \f
8227 /***********************************************************************
8228 PBM (mono, gray, color)
8229 ***********************************************************************/
8230
8231 static int pbm_image_p P_ ((Lisp_Object object));
8232 static int pbm_load P_ ((struct frame *f, struct image *img));
8233 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
8234
8235 /* The symbol `pbm' identifying images of this type. */
8236
8237 Lisp_Object Qpbm;
8238
8239 /* Indices of image specification fields in gs_format, below. */
8240
8241 enum pbm_keyword_index
8242 {
8243 PBM_TYPE,
8244 PBM_FILE,
8245 PBM_DATA,
8246 PBM_ASCENT,
8247 PBM_MARGIN,
8248 PBM_RELIEF,
8249 PBM_ALGORITHM,
8250 PBM_HEURISTIC_MASK,
8251 PBM_MASK,
8252 PBM_FOREGROUND,
8253 PBM_BACKGROUND,
8254 PBM_LAST
8255 };
8256
8257 /* Vector of image_keyword structures describing the format
8258 of valid user-defined image specifications. */
8259
8260 static struct image_keyword pbm_format[PBM_LAST] =
8261 {
8262 {":type", IMAGE_SYMBOL_VALUE, 1},
8263 {":file", IMAGE_STRING_VALUE, 0},
8264 {":data", IMAGE_STRING_VALUE, 0},
8265 {":ascent", IMAGE_ASCENT_VALUE, 0},
8266 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8267 {":relief", IMAGE_INTEGER_VALUE, 0},
8268 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8269 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8270 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8271 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8272 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8273 };
8274
8275 /* Structure describing the image type `pbm'. */
8276
8277 static struct image_type pbm_type =
8278 {
8279 &Qpbm,
8280 pbm_image_p,
8281 pbm_load,
8282 x_clear_image,
8283 NULL
8284 };
8285
8286
8287 /* Return non-zero if OBJECT is a valid PBM image specification. */
8288
8289 static int
8290 pbm_image_p (object)
8291 Lisp_Object object;
8292 {
8293 struct image_keyword fmt[PBM_LAST];
8294
8295 bcopy (pbm_format, fmt, sizeof fmt);
8296
8297 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
8298 return 0;
8299
8300 /* Must specify either :data or :file. */
8301 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
8302 }
8303
8304
8305 /* Scan a decimal number from *S and return it. Advance *S while
8306 reading the number. END is the end of the string. Value is -1 at
8307 end of input. */
8308
8309 static int
8310 pbm_scan_number (s, end)
8311 unsigned char **s, *end;
8312 {
8313 int c = 0, val = -1;
8314
8315 while (*s < end)
8316 {
8317 /* Skip white-space. */
8318 while (*s < end && (c = *(*s)++, isspace (c)))
8319 ;
8320
8321 if (c == '#')
8322 {
8323 /* Skip comment to end of line. */
8324 while (*s < end && (c = *(*s)++, c != '\n'))
8325 ;
8326 }
8327 else if (isdigit (c))
8328 {
8329 /* Read decimal number. */
8330 val = c - '0';
8331 while (*s < end && (c = *(*s)++, isdigit (c)))
8332 val = 10 * val + c - '0';
8333 break;
8334 }
8335 else
8336 break;
8337 }
8338
8339 return val;
8340 }
8341
8342
8343 /* Load PBM image IMG for use on frame F. */
8344
8345 static int
8346 pbm_load (f, img)
8347 struct frame *f;
8348 struct image *img;
8349 {
8350 int raw_p, x, y;
8351 int width, height, max_color_idx = 0;
8352 XImage *ximg;
8353 Lisp_Object file, specified_file;
8354 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8355 struct gcpro gcpro1;
8356 unsigned char *contents = NULL;
8357 unsigned char *end, *p;
8358 int size;
8359
8360 specified_file = image_spec_value (img->spec, QCfile, NULL);
8361 file = Qnil;
8362 GCPRO1 (file);
8363
8364 if (STRINGP (specified_file))
8365 {
8366 file = x_find_image_file (specified_file);
8367 if (!STRINGP (file))
8368 {
8369 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8370 UNGCPRO;
8371 return 0;
8372 }
8373
8374 contents = slurp_file (XSTRING (file)->data, &size);
8375 if (contents == NULL)
8376 {
8377 image_error ("Error reading `%s'", file, Qnil);
8378 UNGCPRO;
8379 return 0;
8380 }
8381
8382 p = contents;
8383 end = contents + size;
8384 }
8385 else
8386 {
8387 Lisp_Object data;
8388 data = image_spec_value (img->spec, QCdata, NULL);
8389 p = XSTRING (data)->data;
8390 end = p + STRING_BYTES (XSTRING (data));
8391 }
8392
8393 /* Check magic number. */
8394 if (end - p < 2 || *p++ != 'P')
8395 {
8396 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
8397 error:
8398 xfree (contents);
8399 UNGCPRO;
8400 return 0;
8401 }
8402
8403 switch (*p++)
8404 {
8405 case '1':
8406 raw_p = 0, type = PBM_MONO;
8407 break;
8408
8409 case '2':
8410 raw_p = 0, type = PBM_GRAY;
8411 break;
8412
8413 case '3':
8414 raw_p = 0, type = PBM_COLOR;
8415 break;
8416
8417 case '4':
8418 raw_p = 1, type = PBM_MONO;
8419 break;
8420
8421 case '5':
8422 raw_p = 1, type = PBM_GRAY;
8423 break;
8424
8425 case '6':
8426 raw_p = 1, type = PBM_COLOR;
8427 break;
8428
8429 default:
8430 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
8431 goto error;
8432 }
8433
8434 /* Read width, height, maximum color-component. Characters
8435 starting with `#' up to the end of a line are ignored. */
8436 width = pbm_scan_number (&p, end);
8437 height = pbm_scan_number (&p, end);
8438
8439 if (type != PBM_MONO)
8440 {
8441 max_color_idx = pbm_scan_number (&p, end);
8442 if (raw_p && max_color_idx > 255)
8443 max_color_idx = 255;
8444 }
8445
8446 if (width < 0
8447 || height < 0
8448 || (type != PBM_MONO && max_color_idx < 0))
8449 goto error;
8450
8451 if (!x_create_x_image_and_pixmap (f, width, height, 0,
8452 &ximg, &img->pixmap))
8453 goto error;
8454
8455 /* Initialize the color hash table. */
8456 init_color_table ();
8457
8458 if (type == PBM_MONO)
8459 {
8460 int c = 0, g;
8461 struct image_keyword fmt[PBM_LAST];
8462 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
8463 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
8464
8465 /* Parse the image specification. */
8466 bcopy (pbm_format, fmt, sizeof fmt);
8467 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
8468
8469 /* Get foreground and background colors, maybe allocate colors. */
8470 if (fmt[PBM_FOREGROUND].count
8471 && STRINGP (fmt[PBM_FOREGROUND].value))
8472 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
8473 if (fmt[PBM_BACKGROUND].count
8474 && STRINGP (fmt[PBM_BACKGROUND].value))
8475 {
8476 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
8477 img->background = bg;
8478 img->background_valid = 1;
8479 }
8480
8481 for (y = 0; y < height; ++y)
8482 for (x = 0; x < width; ++x)
8483 {
8484 if (raw_p)
8485 {
8486 if ((x & 7) == 0)
8487 c = *p++;
8488 g = c & 0x80;
8489 c <<= 1;
8490 }
8491 else
8492 g = pbm_scan_number (&p, end);
8493
8494 XPutPixel (ximg, x, y, g ? fg : bg);
8495 }
8496 }
8497 else
8498 {
8499 for (y = 0; y < height; ++y)
8500 for (x = 0; x < width; ++x)
8501 {
8502 int r, g, b;
8503
8504 if (type == PBM_GRAY)
8505 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
8506 else if (raw_p)
8507 {
8508 r = *p++;
8509 g = *p++;
8510 b = *p++;
8511 }
8512 else
8513 {
8514 r = pbm_scan_number (&p, end);
8515 g = pbm_scan_number (&p, end);
8516 b = pbm_scan_number (&p, end);
8517 }
8518
8519 if (r < 0 || g < 0 || b < 0)
8520 {
8521 xfree (ximg->data);
8522 ximg->data = NULL;
8523 XDestroyImage (ximg);
8524 image_error ("Invalid pixel value in image `%s'",
8525 img->spec, Qnil);
8526 goto error;
8527 }
8528
8529 /* RGB values are now in the range 0..max_color_idx.
8530 Scale this to the range 0..0xffff supported by X. */
8531 r = (double) r * 65535 / max_color_idx;
8532 g = (double) g * 65535 / max_color_idx;
8533 b = (double) b * 65535 / max_color_idx;
8534 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8535 }
8536 }
8537
8538 /* Store in IMG->colors the colors allocated for the image, and
8539 free the color table. */
8540 img->colors = colors_in_color_table (&img->ncolors);
8541 free_color_table ();
8542
8543 /* Maybe fill in the background field while we have ximg handy. */
8544 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8545 IMAGE_BACKGROUND (img, f, ximg);
8546
8547 /* Put the image into a pixmap. */
8548 x_put_x_image (f, ximg, img->pixmap, width, height);
8549 x_destroy_x_image (ximg);
8550
8551 img->width = width;
8552 img->height = height;
8553
8554 UNGCPRO;
8555 xfree (contents);
8556 return 1;
8557 }
8558
8559
8560 \f
8561 /***********************************************************************
8562 PNG
8563 ***********************************************************************/
8564
8565 #if HAVE_PNG
8566
8567 #include <png.h>
8568
8569 /* Function prototypes. */
8570
8571 static int png_image_p P_ ((Lisp_Object object));
8572 static int png_load P_ ((struct frame *f, struct image *img));
8573
8574 /* The symbol `png' identifying images of this type. */
8575
8576 Lisp_Object Qpng;
8577
8578 /* Indices of image specification fields in png_format, below. */
8579
8580 enum png_keyword_index
8581 {
8582 PNG_TYPE,
8583 PNG_DATA,
8584 PNG_FILE,
8585 PNG_ASCENT,
8586 PNG_MARGIN,
8587 PNG_RELIEF,
8588 PNG_ALGORITHM,
8589 PNG_HEURISTIC_MASK,
8590 PNG_MASK,
8591 PNG_BACKGROUND,
8592 PNG_LAST
8593 };
8594
8595 /* Vector of image_keyword structures describing the format
8596 of valid user-defined image specifications. */
8597
8598 static struct image_keyword png_format[PNG_LAST] =
8599 {
8600 {":type", IMAGE_SYMBOL_VALUE, 1},
8601 {":data", IMAGE_STRING_VALUE, 0},
8602 {":file", IMAGE_STRING_VALUE, 0},
8603 {":ascent", IMAGE_ASCENT_VALUE, 0},
8604 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8605 {":relief", IMAGE_INTEGER_VALUE, 0},
8606 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8607 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8608 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8609 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8610 };
8611
8612 /* Structure describing the image type `png'. */
8613
8614 static struct image_type png_type =
8615 {
8616 &Qpng,
8617 png_image_p,
8618 png_load,
8619 x_clear_image,
8620 NULL
8621 };
8622
8623
8624 /* Return non-zero if OBJECT is a valid PNG image specification. */
8625
8626 static int
8627 png_image_p (object)
8628 Lisp_Object object;
8629 {
8630 struct image_keyword fmt[PNG_LAST];
8631 bcopy (png_format, fmt, sizeof fmt);
8632
8633 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
8634 return 0;
8635
8636 /* Must specify either the :data or :file keyword. */
8637 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
8638 }
8639
8640
8641 /* Error and warning handlers installed when the PNG library
8642 is initialized. */
8643
8644 static void
8645 my_png_error (png_ptr, msg)
8646 png_struct *png_ptr;
8647 char *msg;
8648 {
8649 xassert (png_ptr != NULL);
8650 image_error ("PNG error: %s", build_string (msg), Qnil);
8651 longjmp (png_ptr->jmpbuf, 1);
8652 }
8653
8654
8655 static void
8656 my_png_warning (png_ptr, msg)
8657 png_struct *png_ptr;
8658 char *msg;
8659 {
8660 xassert (png_ptr != NULL);
8661 image_error ("PNG warning: %s", build_string (msg), Qnil);
8662 }
8663
8664 /* Memory source for PNG decoding. */
8665
8666 struct png_memory_storage
8667 {
8668 unsigned char *bytes; /* The data */
8669 size_t len; /* How big is it? */
8670 int index; /* Where are we? */
8671 };
8672
8673
8674 /* Function set as reader function when reading PNG image from memory.
8675 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8676 bytes from the input to DATA. */
8677
8678 static void
8679 png_read_from_memory (png_ptr, data, length)
8680 png_structp png_ptr;
8681 png_bytep data;
8682 png_size_t length;
8683 {
8684 struct png_memory_storage *tbr
8685 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
8686
8687 if (length > tbr->len - tbr->index)
8688 png_error (png_ptr, "Read error");
8689
8690 bcopy (tbr->bytes + tbr->index, data, length);
8691 tbr->index = tbr->index + length;
8692 }
8693
8694 /* Load PNG image IMG for use on frame F. Value is non-zero if
8695 successful. */
8696
8697 static int
8698 png_load (f, img)
8699 struct frame *f;
8700 struct image *img;
8701 {
8702 Lisp_Object file, specified_file;
8703 Lisp_Object specified_data;
8704 int x, y, i;
8705 XImage *ximg, *mask_img = NULL;
8706 struct gcpro gcpro1;
8707 png_struct *png_ptr = NULL;
8708 png_info *info_ptr = NULL, *end_info = NULL;
8709 FILE *volatile fp = NULL;
8710 png_byte sig[8];
8711 png_byte * volatile pixels = NULL;
8712 png_byte ** volatile rows = NULL;
8713 png_uint_32 width, height;
8714 int bit_depth, color_type, interlace_type;
8715 png_byte channels;
8716 png_uint_32 row_bytes;
8717 int transparent_p;
8718 char *gamma_str;
8719 double screen_gamma, image_gamma;
8720 int intent;
8721 struct png_memory_storage tbr; /* Data to be read */
8722
8723 /* Find out what file to load. */
8724 specified_file = image_spec_value (img->spec, QCfile, NULL);
8725 specified_data = image_spec_value (img->spec, QCdata, NULL);
8726 file = Qnil;
8727 GCPRO1 (file);
8728
8729 if (NILP (specified_data))
8730 {
8731 file = x_find_image_file (specified_file);
8732 if (!STRINGP (file))
8733 {
8734 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8735 UNGCPRO;
8736 return 0;
8737 }
8738
8739 /* Open the image file. */
8740 fp = fopen (XSTRING (file)->data, "rb");
8741 if (!fp)
8742 {
8743 image_error ("Cannot open image file `%s'", file, Qnil);
8744 UNGCPRO;
8745 fclose (fp);
8746 return 0;
8747 }
8748
8749 /* Check PNG signature. */
8750 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8751 || !png_check_sig (sig, sizeof sig))
8752 {
8753 image_error ("Not a PNG file: `%s'", file, Qnil);
8754 UNGCPRO;
8755 fclose (fp);
8756 return 0;
8757 }
8758 }
8759 else
8760 {
8761 /* Read from memory. */
8762 tbr.bytes = XSTRING (specified_data)->data;
8763 tbr.len = STRING_BYTES (XSTRING (specified_data));
8764 tbr.index = 0;
8765
8766 /* Check PNG signature. */
8767 if (tbr.len < sizeof sig
8768 || !png_check_sig (tbr.bytes, sizeof sig))
8769 {
8770 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
8771 UNGCPRO;
8772 return 0;
8773 }
8774
8775 /* Need to skip past the signature. */
8776 tbr.bytes += sizeof (sig);
8777 }
8778
8779 /* Initialize read and info structs for PNG lib. */
8780 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8781 my_png_error, my_png_warning);
8782 if (!png_ptr)
8783 {
8784 if (fp) fclose (fp);
8785 UNGCPRO;
8786 return 0;
8787 }
8788
8789 info_ptr = png_create_info_struct (png_ptr);
8790 if (!info_ptr)
8791 {
8792 png_destroy_read_struct (&png_ptr, NULL, NULL);
8793 if (fp) fclose (fp);
8794 UNGCPRO;
8795 return 0;
8796 }
8797
8798 end_info = png_create_info_struct (png_ptr);
8799 if (!end_info)
8800 {
8801 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
8802 if (fp) fclose (fp);
8803 UNGCPRO;
8804 return 0;
8805 }
8806
8807 /* Set error jump-back. We come back here when the PNG library
8808 detects an error. */
8809 if (setjmp (png_ptr->jmpbuf))
8810 {
8811 error:
8812 if (png_ptr)
8813 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8814 xfree (pixels);
8815 xfree (rows);
8816 if (fp) fclose (fp);
8817 UNGCPRO;
8818 return 0;
8819 }
8820
8821 /* Read image info. */
8822 if (!NILP (specified_data))
8823 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
8824 else
8825 png_init_io (png_ptr, fp);
8826
8827 png_set_sig_bytes (png_ptr, sizeof sig);
8828 png_read_info (png_ptr, info_ptr);
8829 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
8830 &interlace_type, NULL, NULL);
8831
8832 /* If image contains simply transparency data, we prefer to
8833 construct a clipping mask. */
8834 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
8835 transparent_p = 1;
8836 else
8837 transparent_p = 0;
8838
8839 /* This function is easier to write if we only have to handle
8840 one data format: RGB or RGBA with 8 bits per channel. Let's
8841 transform other formats into that format. */
8842
8843 /* Strip more than 8 bits per channel. */
8844 if (bit_depth == 16)
8845 png_set_strip_16 (png_ptr);
8846
8847 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
8848 if available. */
8849 png_set_expand (png_ptr);
8850
8851 /* Convert grayscale images to RGB. */
8852 if (color_type == PNG_COLOR_TYPE_GRAY
8853 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8854 png_set_gray_to_rgb (png_ptr);
8855
8856 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
8857 gamma_str = getenv ("SCREEN_GAMMA");
8858 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
8859
8860 /* Tell the PNG lib to handle gamma correction for us. */
8861
8862 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
8863 if (png_get_sRGB (png_ptr, info_ptr, &intent))
8864 /* There is a special chunk in the image specifying the gamma. */
8865 png_set_sRGB (png_ptr, info_ptr, intent);
8866 else
8867 #endif
8868 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
8869 /* Image contains gamma information. */
8870 png_set_gamma (png_ptr, screen_gamma, image_gamma);
8871 else
8872 /* Use a default of 0.5 for the image gamma. */
8873 png_set_gamma (png_ptr, screen_gamma, 0.5);
8874
8875 /* Handle alpha channel by combining the image with a background
8876 color. Do this only if a real alpha channel is supplied. For
8877 simple transparency, we prefer a clipping mask. */
8878 if (!transparent_p)
8879 {
8880 png_color_16 *image_bg;
8881 Lisp_Object specified_bg
8882 = image_spec_value (img->spec, QCbackground, NULL);
8883
8884 if (STRINGP (specified_bg))
8885 /* The user specified `:background', use that. */
8886 {
8887 XColor color;
8888 if (x_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
8889 {
8890 png_color_16 user_bg;
8891
8892 bzero (&user_bg, sizeof user_bg);
8893 user_bg.red = color.red;
8894 user_bg.green = color.green;
8895 user_bg.blue = color.blue;
8896
8897 png_set_background (png_ptr, &user_bg,
8898 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
8899 }
8900 }
8901 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
8902 /* Image contains a background color with which to
8903 combine the image. */
8904 png_set_background (png_ptr, image_bg,
8905 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
8906 else
8907 {
8908 /* Image does not contain a background color with which
8909 to combine the image data via an alpha channel. Use
8910 the frame's background instead. */
8911 XColor color;
8912 Colormap cmap;
8913 png_color_16 frame_background;
8914
8915 cmap = FRAME_X_COLORMAP (f);
8916 color.pixel = FRAME_BACKGROUND_PIXEL (f);
8917 x_query_color (f, &color);
8918
8919 bzero (&frame_background, sizeof frame_background);
8920 frame_background.red = color.red;
8921 frame_background.green = color.green;
8922 frame_background.blue = color.blue;
8923
8924 png_set_background (png_ptr, &frame_background,
8925 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
8926 }
8927 }
8928
8929 /* Update info structure. */
8930 png_read_update_info (png_ptr, info_ptr);
8931
8932 /* Get number of channels. Valid values are 1 for grayscale images
8933 and images with a palette, 2 for grayscale images with transparency
8934 information (alpha channel), 3 for RGB images, and 4 for RGB
8935 images with alpha channel, i.e. RGBA. If conversions above were
8936 sufficient we should only have 3 or 4 channels here. */
8937 channels = png_get_channels (png_ptr, info_ptr);
8938 xassert (channels == 3 || channels == 4);
8939
8940 /* Number of bytes needed for one row of the image. */
8941 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
8942
8943 /* Allocate memory for the image. */
8944 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
8945 rows = (png_byte **) xmalloc (height * sizeof *rows);
8946 for (i = 0; i < height; ++i)
8947 rows[i] = pixels + i * row_bytes;
8948
8949 /* Read the entire image. */
8950 png_read_image (png_ptr, rows);
8951 png_read_end (png_ptr, info_ptr);
8952 if (fp)
8953 {
8954 fclose (fp);
8955 fp = NULL;
8956 }
8957
8958 /* Create the X image and pixmap. */
8959 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
8960 &img->pixmap))
8961 goto error;
8962
8963 /* Create an image and pixmap serving as mask if the PNG image
8964 contains an alpha channel. */
8965 if (channels == 4
8966 && !transparent_p
8967 && !x_create_x_image_and_pixmap (f, width, height, 1,
8968 &mask_img, &img->mask))
8969 {
8970 x_destroy_x_image (ximg);
8971 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8972 img->pixmap = None;
8973 goto error;
8974 }
8975
8976 /* Fill the X image and mask from PNG data. */
8977 init_color_table ();
8978
8979 for (y = 0; y < height; ++y)
8980 {
8981 png_byte *p = rows[y];
8982
8983 for (x = 0; x < width; ++x)
8984 {
8985 unsigned r, g, b;
8986
8987 r = *p++ << 8;
8988 g = *p++ << 8;
8989 b = *p++ << 8;
8990 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8991
8992 /* An alpha channel, aka mask channel, associates variable
8993 transparency with an image. Where other image formats
8994 support binary transparency---fully transparent or fully
8995 opaque---PNG allows up to 254 levels of partial transparency.
8996 The PNG library implements partial transparency by combining
8997 the image with a specified background color.
8998
8999 I'm not sure how to handle this here nicely: because the
9000 background on which the image is displayed may change, for
9001 real alpha channel support, it would be necessary to create
9002 a new image for each possible background.
9003
9004 What I'm doing now is that a mask is created if we have
9005 boolean transparency information. Otherwise I'm using
9006 the frame's background color to combine the image with. */
9007
9008 if (channels == 4)
9009 {
9010 if (mask_img)
9011 XPutPixel (mask_img, x, y, *p > 0);
9012 ++p;
9013 }
9014 }
9015 }
9016
9017 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9018 /* Set IMG's background color from the PNG image, unless the user
9019 overrode it. */
9020 {
9021 png_color_16 *bg;
9022 if (png_get_bKGD (png_ptr, info_ptr, &bg))
9023 {
9024 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
9025 img->background_valid = 1;
9026 }
9027 }
9028
9029 /* Remember colors allocated for this image. */
9030 img->colors = colors_in_color_table (&img->ncolors);
9031 free_color_table ();
9032
9033 /* Clean up. */
9034 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9035 xfree (rows);
9036 xfree (pixels);
9037
9038 img->width = width;
9039 img->height = height;
9040
9041 /* Maybe fill in the background field while we have ximg handy. */
9042 IMAGE_BACKGROUND (img, f, ximg);
9043
9044 /* Put the image into the pixmap, then free the X image and its buffer. */
9045 x_put_x_image (f, ximg, img->pixmap, width, height);
9046 x_destroy_x_image (ximg);
9047
9048 /* Same for the mask. */
9049 if (mask_img)
9050 {
9051 /* Fill in the background_transparent field while we have the mask
9052 handy. */
9053 image_background_transparent (img, f, mask_img);
9054
9055 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9056 x_destroy_x_image (mask_img);
9057 }
9058
9059 UNGCPRO;
9060 return 1;
9061 }
9062
9063 #endif /* HAVE_PNG != 0 */
9064
9065
9066 \f
9067 /***********************************************************************
9068 JPEG
9069 ***********************************************************************/
9070
9071 #if HAVE_JPEG
9072
9073 /* Work around a warning about HAVE_STDLIB_H being redefined in
9074 jconfig.h. */
9075 #ifdef HAVE_STDLIB_H
9076 #define HAVE_STDLIB_H_1
9077 #undef HAVE_STDLIB_H
9078 #endif /* HAVE_STLIB_H */
9079
9080 #include <jpeglib.h>
9081 #include <jerror.h>
9082 #include <setjmp.h>
9083
9084 #ifdef HAVE_STLIB_H_1
9085 #define HAVE_STDLIB_H 1
9086 #endif
9087
9088 static int jpeg_image_p P_ ((Lisp_Object object));
9089 static int jpeg_load P_ ((struct frame *f, struct image *img));
9090
9091 /* The symbol `jpeg' identifying images of this type. */
9092
9093 Lisp_Object Qjpeg;
9094
9095 /* Indices of image specification fields in gs_format, below. */
9096
9097 enum jpeg_keyword_index
9098 {
9099 JPEG_TYPE,
9100 JPEG_DATA,
9101 JPEG_FILE,
9102 JPEG_ASCENT,
9103 JPEG_MARGIN,
9104 JPEG_RELIEF,
9105 JPEG_ALGORITHM,
9106 JPEG_HEURISTIC_MASK,
9107 JPEG_MASK,
9108 JPEG_BACKGROUND,
9109 JPEG_LAST
9110 };
9111
9112 /* Vector of image_keyword structures describing the format
9113 of valid user-defined image specifications. */
9114
9115 static struct image_keyword jpeg_format[JPEG_LAST] =
9116 {
9117 {":type", IMAGE_SYMBOL_VALUE, 1},
9118 {":data", IMAGE_STRING_VALUE, 0},
9119 {":file", IMAGE_STRING_VALUE, 0},
9120 {":ascent", IMAGE_ASCENT_VALUE, 0},
9121 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9122 {":relief", IMAGE_INTEGER_VALUE, 0},
9123 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9124 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9125 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9126 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9127 };
9128
9129 /* Structure describing the image type `jpeg'. */
9130
9131 static struct image_type jpeg_type =
9132 {
9133 &Qjpeg,
9134 jpeg_image_p,
9135 jpeg_load,
9136 x_clear_image,
9137 NULL
9138 };
9139
9140
9141 /* Return non-zero if OBJECT is a valid JPEG image specification. */
9142
9143 static int
9144 jpeg_image_p (object)
9145 Lisp_Object object;
9146 {
9147 struct image_keyword fmt[JPEG_LAST];
9148
9149 bcopy (jpeg_format, fmt, sizeof fmt);
9150
9151 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
9152 return 0;
9153
9154 /* Must specify either the :data or :file keyword. */
9155 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
9156 }
9157
9158
9159 struct my_jpeg_error_mgr
9160 {
9161 struct jpeg_error_mgr pub;
9162 jmp_buf setjmp_buffer;
9163 };
9164
9165
9166 static void
9167 my_error_exit (cinfo)
9168 j_common_ptr cinfo;
9169 {
9170 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
9171 longjmp (mgr->setjmp_buffer, 1);
9172 }
9173
9174
9175 /* Init source method for JPEG data source manager. Called by
9176 jpeg_read_header() before any data is actually read. See
9177 libjpeg.doc from the JPEG lib distribution. */
9178
9179 static void
9180 our_init_source (cinfo)
9181 j_decompress_ptr cinfo;
9182 {
9183 }
9184
9185
9186 /* Fill input buffer method for JPEG data source manager. Called
9187 whenever more data is needed. We read the whole image in one step,
9188 so this only adds a fake end of input marker at the end. */
9189
9190 static boolean
9191 our_fill_input_buffer (cinfo)
9192 j_decompress_ptr cinfo;
9193 {
9194 /* Insert a fake EOI marker. */
9195 struct jpeg_source_mgr *src = cinfo->src;
9196 static JOCTET buffer[2];
9197
9198 buffer[0] = (JOCTET) 0xFF;
9199 buffer[1] = (JOCTET) JPEG_EOI;
9200
9201 src->next_input_byte = buffer;
9202 src->bytes_in_buffer = 2;
9203 return TRUE;
9204 }
9205
9206
9207 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
9208 is the JPEG data source manager. */
9209
9210 static void
9211 our_skip_input_data (cinfo, num_bytes)
9212 j_decompress_ptr cinfo;
9213 long num_bytes;
9214 {
9215 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
9216
9217 if (src)
9218 {
9219 if (num_bytes > src->bytes_in_buffer)
9220 ERREXIT (cinfo, JERR_INPUT_EOF);
9221
9222 src->bytes_in_buffer -= num_bytes;
9223 src->next_input_byte += num_bytes;
9224 }
9225 }
9226
9227
9228 /* Method to terminate data source. Called by
9229 jpeg_finish_decompress() after all data has been processed. */
9230
9231 static void
9232 our_term_source (cinfo)
9233 j_decompress_ptr cinfo;
9234 {
9235 }
9236
9237
9238 /* Set up the JPEG lib for reading an image from DATA which contains
9239 LEN bytes. CINFO is the decompression info structure created for
9240 reading the image. */
9241
9242 static void
9243 jpeg_memory_src (cinfo, data, len)
9244 j_decompress_ptr cinfo;
9245 JOCTET *data;
9246 unsigned int len;
9247 {
9248 struct jpeg_source_mgr *src;
9249
9250 if (cinfo->src == NULL)
9251 {
9252 /* First time for this JPEG object? */
9253 cinfo->src = (struct jpeg_source_mgr *)
9254 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
9255 sizeof (struct jpeg_source_mgr));
9256 src = (struct jpeg_source_mgr *) cinfo->src;
9257 src->next_input_byte = data;
9258 }
9259
9260 src = (struct jpeg_source_mgr *) cinfo->src;
9261 src->init_source = our_init_source;
9262 src->fill_input_buffer = our_fill_input_buffer;
9263 src->skip_input_data = our_skip_input_data;
9264 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
9265 src->term_source = our_term_source;
9266 src->bytes_in_buffer = len;
9267 src->next_input_byte = data;
9268 }
9269
9270
9271 /* Load image IMG for use on frame F. Patterned after example.c
9272 from the JPEG lib. */
9273
9274 static int
9275 jpeg_load (f, img)
9276 struct frame *f;
9277 struct image *img;
9278 {
9279 struct jpeg_decompress_struct cinfo;
9280 struct my_jpeg_error_mgr mgr;
9281 Lisp_Object file, specified_file;
9282 Lisp_Object specified_data;
9283 FILE * volatile fp = NULL;
9284 JSAMPARRAY buffer;
9285 int row_stride, x, y;
9286 XImage *ximg = NULL;
9287 int rc;
9288 unsigned long *colors;
9289 int width, height;
9290 struct gcpro gcpro1;
9291
9292 /* Open the JPEG file. */
9293 specified_file = image_spec_value (img->spec, QCfile, NULL);
9294 specified_data = image_spec_value (img->spec, QCdata, NULL);
9295 file = Qnil;
9296 GCPRO1 (file);
9297
9298 if (NILP (specified_data))
9299 {
9300 file = x_find_image_file (specified_file);
9301 if (!STRINGP (file))
9302 {
9303 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9304 UNGCPRO;
9305 return 0;
9306 }
9307
9308 fp = fopen (XSTRING (file)->data, "r");
9309 if (fp == NULL)
9310 {
9311 image_error ("Cannot open `%s'", file, Qnil);
9312 UNGCPRO;
9313 return 0;
9314 }
9315 }
9316
9317 /* Customize libjpeg's error handling to call my_error_exit when an
9318 error is detected. This function will perform a longjmp. */
9319 cinfo.err = jpeg_std_error (&mgr.pub);
9320 mgr.pub.error_exit = my_error_exit;
9321
9322 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9323 {
9324 if (rc == 1)
9325 {
9326 /* Called from my_error_exit. Display a JPEG error. */
9327 char buffer[JMSG_LENGTH_MAX];
9328 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
9329 image_error ("Error reading JPEG image `%s': %s", img->spec,
9330 build_string (buffer));
9331 }
9332
9333 /* Close the input file and destroy the JPEG object. */
9334 if (fp)
9335 fclose ((FILE *) fp);
9336 jpeg_destroy_decompress (&cinfo);
9337
9338 /* If we already have an XImage, free that. */
9339 x_destroy_x_image (ximg);
9340
9341 /* Free pixmap and colors. */
9342 x_clear_image (f, img);
9343
9344 UNGCPRO;
9345 return 0;
9346 }
9347
9348 /* Create the JPEG decompression object. Let it read from fp.
9349 Read the JPEG image header. */
9350 jpeg_create_decompress (&cinfo);
9351
9352 if (NILP (specified_data))
9353 jpeg_stdio_src (&cinfo, (FILE *) fp);
9354 else
9355 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
9356 STRING_BYTES (XSTRING (specified_data)));
9357
9358 jpeg_read_header (&cinfo, TRUE);
9359
9360 /* Customize decompression so that color quantization will be used.
9361 Start decompression. */
9362 cinfo.quantize_colors = TRUE;
9363 jpeg_start_decompress (&cinfo);
9364 width = img->width = cinfo.output_width;
9365 height = img->height = cinfo.output_height;
9366
9367 /* Create X image and pixmap. */
9368 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
9369 longjmp (mgr.setjmp_buffer, 2);
9370
9371 /* Allocate colors. When color quantization is used,
9372 cinfo.actual_number_of_colors has been set with the number of
9373 colors generated, and cinfo.colormap is a two-dimensional array
9374 of color indices in the range 0..cinfo.actual_number_of_colors.
9375 No more than 255 colors will be generated. */
9376 {
9377 int i, ir, ig, ib;
9378
9379 if (cinfo.out_color_components > 2)
9380 ir = 0, ig = 1, ib = 2;
9381 else if (cinfo.out_color_components > 1)
9382 ir = 0, ig = 1, ib = 0;
9383 else
9384 ir = 0, ig = 0, ib = 0;
9385
9386 /* Use the color table mechanism because it handles colors that
9387 cannot be allocated nicely. Such colors will be replaced with
9388 a default color, and we don't have to care about which colors
9389 can be freed safely, and which can't. */
9390 init_color_table ();
9391 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9392 * sizeof *colors);
9393
9394 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9395 {
9396 /* Multiply RGB values with 255 because X expects RGB values
9397 in the range 0..0xffff. */
9398 int r = cinfo.colormap[ir][i] << 8;
9399 int g = cinfo.colormap[ig][i] << 8;
9400 int b = cinfo.colormap[ib][i] << 8;
9401 colors[i] = lookup_rgb_color (f, r, g, b);
9402 }
9403
9404 /* Remember those colors actually allocated. */
9405 img->colors = colors_in_color_table (&img->ncolors);
9406 free_color_table ();
9407 }
9408
9409 /* Read pixels. */
9410 row_stride = width * cinfo.output_components;
9411 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
9412 row_stride, 1);
9413 for (y = 0; y < height; ++y)
9414 {
9415 jpeg_read_scanlines (&cinfo, buffer, 1);
9416 for (x = 0; x < cinfo.output_width; ++x)
9417 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
9418 }
9419
9420 /* Clean up. */
9421 jpeg_finish_decompress (&cinfo);
9422 jpeg_destroy_decompress (&cinfo);
9423 if (fp)
9424 fclose ((FILE *) fp);
9425
9426 /* Maybe fill in the background field while we have ximg handy. */
9427 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9428 IMAGE_BACKGROUND (img, f, ximg);
9429
9430 /* Put the image into the pixmap. */
9431 x_put_x_image (f, ximg, img->pixmap, width, height);
9432 x_destroy_x_image (ximg);
9433 UNGCPRO;
9434 return 1;
9435 }
9436
9437 #endif /* HAVE_JPEG */
9438
9439
9440 \f
9441 /***********************************************************************
9442 TIFF
9443 ***********************************************************************/
9444
9445 #if HAVE_TIFF
9446
9447 #include <tiffio.h>
9448
9449 static int tiff_image_p P_ ((Lisp_Object object));
9450 static int tiff_load P_ ((struct frame *f, struct image *img));
9451
9452 /* The symbol `tiff' identifying images of this type. */
9453
9454 Lisp_Object Qtiff;
9455
9456 /* Indices of image specification fields in tiff_format, below. */
9457
9458 enum tiff_keyword_index
9459 {
9460 TIFF_TYPE,
9461 TIFF_DATA,
9462 TIFF_FILE,
9463 TIFF_ASCENT,
9464 TIFF_MARGIN,
9465 TIFF_RELIEF,
9466 TIFF_ALGORITHM,
9467 TIFF_HEURISTIC_MASK,
9468 TIFF_MASK,
9469 TIFF_BACKGROUND,
9470 TIFF_LAST
9471 };
9472
9473 /* Vector of image_keyword structures describing the format
9474 of valid user-defined image specifications. */
9475
9476 static struct image_keyword tiff_format[TIFF_LAST] =
9477 {
9478 {":type", IMAGE_SYMBOL_VALUE, 1},
9479 {":data", IMAGE_STRING_VALUE, 0},
9480 {":file", IMAGE_STRING_VALUE, 0},
9481 {":ascent", IMAGE_ASCENT_VALUE, 0},
9482 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9483 {":relief", IMAGE_INTEGER_VALUE, 0},
9484 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9485 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9486 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9487 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9488 };
9489
9490 /* Structure describing the image type `tiff'. */
9491
9492 static struct image_type tiff_type =
9493 {
9494 &Qtiff,
9495 tiff_image_p,
9496 tiff_load,
9497 x_clear_image,
9498 NULL
9499 };
9500
9501
9502 /* Return non-zero if OBJECT is a valid TIFF image specification. */
9503
9504 static int
9505 tiff_image_p (object)
9506 Lisp_Object object;
9507 {
9508 struct image_keyword fmt[TIFF_LAST];
9509 bcopy (tiff_format, fmt, sizeof fmt);
9510
9511 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
9512 return 0;
9513
9514 /* Must specify either the :data or :file keyword. */
9515 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
9516 }
9517
9518
9519 /* Reading from a memory buffer for TIFF images Based on the PNG
9520 memory source, but we have to provide a lot of extra functions.
9521 Blah.
9522
9523 We really only need to implement read and seek, but I am not
9524 convinced that the TIFF library is smart enough not to destroy
9525 itself if we only hand it the function pointers we need to
9526 override. */
9527
9528 typedef struct
9529 {
9530 unsigned char *bytes;
9531 size_t len;
9532 int index;
9533 }
9534 tiff_memory_source;
9535
9536
9537 static size_t
9538 tiff_read_from_memory (data, buf, size)
9539 thandle_t data;
9540 tdata_t buf;
9541 tsize_t size;
9542 {
9543 tiff_memory_source *src = (tiff_memory_source *) data;
9544
9545 if (size > src->len - src->index)
9546 return (size_t) -1;
9547 bcopy (src->bytes + src->index, buf, size);
9548 src->index += size;
9549 return size;
9550 }
9551
9552
9553 static size_t
9554 tiff_write_from_memory (data, buf, size)
9555 thandle_t data;
9556 tdata_t buf;
9557 tsize_t size;
9558 {
9559 return (size_t) -1;
9560 }
9561
9562
9563 static toff_t
9564 tiff_seek_in_memory (data, off, whence)
9565 thandle_t data;
9566 toff_t off;
9567 int whence;
9568 {
9569 tiff_memory_source *src = (tiff_memory_source *) data;
9570 int idx;
9571
9572 switch (whence)
9573 {
9574 case SEEK_SET: /* Go from beginning of source. */
9575 idx = off;
9576 break;
9577
9578 case SEEK_END: /* Go from end of source. */
9579 idx = src->len + off;
9580 break;
9581
9582 case SEEK_CUR: /* Go from current position. */
9583 idx = src->index + off;
9584 break;
9585
9586 default: /* Invalid `whence'. */
9587 return -1;
9588 }
9589
9590 if (idx > src->len || idx < 0)
9591 return -1;
9592
9593 src->index = idx;
9594 return src->index;
9595 }
9596
9597
9598 static int
9599 tiff_close_memory (data)
9600 thandle_t data;
9601 {
9602 /* NOOP */
9603 return 0;
9604 }
9605
9606
9607 static int
9608 tiff_mmap_memory (data, pbase, psize)
9609 thandle_t data;
9610 tdata_t *pbase;
9611 toff_t *psize;
9612 {
9613 /* It is already _IN_ memory. */
9614 return 0;
9615 }
9616
9617
9618 static void
9619 tiff_unmap_memory (data, base, size)
9620 thandle_t data;
9621 tdata_t base;
9622 toff_t size;
9623 {
9624 /* We don't need to do this. */
9625 }
9626
9627
9628 static toff_t
9629 tiff_size_of_memory (data)
9630 thandle_t data;
9631 {
9632 return ((tiff_memory_source *) data)->len;
9633 }
9634
9635
9636 static void
9637 tiff_error_handler (title, format, ap)
9638 const char *title, *format;
9639 va_list ap;
9640 {
9641 char buf[512];
9642 int len;
9643
9644 len = sprintf (buf, "TIFF error: %s ", title);
9645 vsprintf (buf + len, format, ap);
9646 add_to_log (buf, Qnil, Qnil);
9647 }
9648
9649
9650 static void
9651 tiff_warning_handler (title, format, ap)
9652 const char *title, *format;
9653 va_list ap;
9654 {
9655 char buf[512];
9656 int len;
9657
9658 len = sprintf (buf, "TIFF warning: %s ", title);
9659 vsprintf (buf + len, format, ap);
9660 add_to_log (buf, Qnil, Qnil);
9661 }
9662
9663
9664 /* Load TIFF image IMG for use on frame F. Value is non-zero if
9665 successful. */
9666
9667 static int
9668 tiff_load (f, img)
9669 struct frame *f;
9670 struct image *img;
9671 {
9672 Lisp_Object file, specified_file;
9673 Lisp_Object specified_data;
9674 TIFF *tiff;
9675 int width, height, x, y;
9676 uint32 *buf;
9677 int rc;
9678 XImage *ximg;
9679 struct gcpro gcpro1;
9680 tiff_memory_source memsrc;
9681
9682 specified_file = image_spec_value (img->spec, QCfile, NULL);
9683 specified_data = image_spec_value (img->spec, QCdata, NULL);
9684 file = Qnil;
9685 GCPRO1 (file);
9686
9687 TIFFSetErrorHandler (tiff_error_handler);
9688 TIFFSetWarningHandler (tiff_warning_handler);
9689
9690 if (NILP (specified_data))
9691 {
9692 /* Read from a file */
9693 file = x_find_image_file (specified_file);
9694 if (!STRINGP (file))
9695 {
9696 image_error ("Cannot find image file `%s'", file, Qnil);
9697 UNGCPRO;
9698 return 0;
9699 }
9700
9701 /* Try to open the image file. */
9702 tiff = TIFFOpen (XSTRING (file)->data, "r");
9703 if (tiff == NULL)
9704 {
9705 image_error ("Cannot open `%s'", file, Qnil);
9706 UNGCPRO;
9707 return 0;
9708 }
9709 }
9710 else
9711 {
9712 /* Memory source! */
9713 memsrc.bytes = XSTRING (specified_data)->data;
9714 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9715 memsrc.index = 0;
9716
9717 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9718 (TIFFReadWriteProc) tiff_read_from_memory,
9719 (TIFFReadWriteProc) tiff_write_from_memory,
9720 tiff_seek_in_memory,
9721 tiff_close_memory,
9722 tiff_size_of_memory,
9723 tiff_mmap_memory,
9724 tiff_unmap_memory);
9725
9726 if (!tiff)
9727 {
9728 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
9729 UNGCPRO;
9730 return 0;
9731 }
9732 }
9733
9734 /* Get width and height of the image, and allocate a raster buffer
9735 of width x height 32-bit values. */
9736 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9737 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9738 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9739
9740 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9741 TIFFClose (tiff);
9742 if (!rc)
9743 {
9744 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
9745 xfree (buf);
9746 UNGCPRO;
9747 return 0;
9748 }
9749
9750 /* Create the X image and pixmap. */
9751 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
9752 {
9753 xfree (buf);
9754 UNGCPRO;
9755 return 0;
9756 }
9757
9758 /* Initialize the color table. */
9759 init_color_table ();
9760
9761 /* Process the pixel raster. Origin is in the lower-left corner. */
9762 for (y = 0; y < height; ++y)
9763 {
9764 uint32 *row = buf + y * width;
9765
9766 for (x = 0; x < width; ++x)
9767 {
9768 uint32 abgr = row[x];
9769 int r = TIFFGetR (abgr) << 8;
9770 int g = TIFFGetG (abgr) << 8;
9771 int b = TIFFGetB (abgr) << 8;
9772 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9773 }
9774 }
9775
9776 /* Remember the colors allocated for the image. Free the color table. */
9777 img->colors = colors_in_color_table (&img->ncolors);
9778 free_color_table ();
9779
9780 img->width = width;
9781 img->height = height;
9782
9783 /* Maybe fill in the background field while we have ximg handy. */
9784 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9785 IMAGE_BACKGROUND (img, f, ximg);
9786
9787 /* Put the image into the pixmap, then free the X image and its buffer. */
9788 x_put_x_image (f, ximg, img->pixmap, width, height);
9789 x_destroy_x_image (ximg);
9790 xfree (buf);
9791
9792 UNGCPRO;
9793 return 1;
9794 }
9795
9796 #endif /* HAVE_TIFF != 0 */
9797
9798
9799 \f
9800 /***********************************************************************
9801 GIF
9802 ***********************************************************************/
9803
9804 #if HAVE_GIF
9805
9806 #include <gif_lib.h>
9807
9808 static int gif_image_p P_ ((Lisp_Object object));
9809 static int gif_load P_ ((struct frame *f, struct image *img));
9810
9811 /* The symbol `gif' identifying images of this type. */
9812
9813 Lisp_Object Qgif;
9814
9815 /* Indices of image specification fields in gif_format, below. */
9816
9817 enum gif_keyword_index
9818 {
9819 GIF_TYPE,
9820 GIF_DATA,
9821 GIF_FILE,
9822 GIF_ASCENT,
9823 GIF_MARGIN,
9824 GIF_RELIEF,
9825 GIF_ALGORITHM,
9826 GIF_HEURISTIC_MASK,
9827 GIF_MASK,
9828 GIF_IMAGE,
9829 GIF_BACKGROUND,
9830 GIF_LAST
9831 };
9832
9833 /* Vector of image_keyword structures describing the format
9834 of valid user-defined image specifications. */
9835
9836 static struct image_keyword gif_format[GIF_LAST] =
9837 {
9838 {":type", IMAGE_SYMBOL_VALUE, 1},
9839 {":data", IMAGE_STRING_VALUE, 0},
9840 {":file", IMAGE_STRING_VALUE, 0},
9841 {":ascent", IMAGE_ASCENT_VALUE, 0},
9842 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9843 {":relief", IMAGE_INTEGER_VALUE, 0},
9844 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9845 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9846 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9847 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9848 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9849 };
9850
9851 /* Structure describing the image type `gif'. */
9852
9853 static struct image_type gif_type =
9854 {
9855 &Qgif,
9856 gif_image_p,
9857 gif_load,
9858 x_clear_image,
9859 NULL
9860 };
9861
9862
9863 /* Return non-zero if OBJECT is a valid GIF image specification. */
9864
9865 static int
9866 gif_image_p (object)
9867 Lisp_Object object;
9868 {
9869 struct image_keyword fmt[GIF_LAST];
9870 bcopy (gif_format, fmt, sizeof fmt);
9871
9872 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
9873 return 0;
9874
9875 /* Must specify either the :data or :file keyword. */
9876 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
9877 }
9878
9879
9880 /* Reading a GIF image from memory
9881 Based on the PNG memory stuff to a certain extent. */
9882
9883 typedef struct
9884 {
9885 unsigned char *bytes;
9886 size_t len;
9887 int index;
9888 }
9889 gif_memory_source;
9890
9891
9892 /* Make the current memory source available to gif_read_from_memory.
9893 It's done this way because not all versions of libungif support
9894 a UserData field in the GifFileType structure. */
9895 static gif_memory_source *current_gif_memory_src;
9896
9897 static int
9898 gif_read_from_memory (file, buf, len)
9899 GifFileType *file;
9900 GifByteType *buf;
9901 int len;
9902 {
9903 gif_memory_source *src = current_gif_memory_src;
9904
9905 if (len > src->len - src->index)
9906 return -1;
9907
9908 bcopy (src->bytes + src->index, buf, len);
9909 src->index += len;
9910 return len;
9911 }
9912
9913
9914 /* Load GIF image IMG for use on frame F. Value is non-zero if
9915 successful. */
9916
9917 static int
9918 gif_load (f, img)
9919 struct frame *f;
9920 struct image *img;
9921 {
9922 Lisp_Object file, specified_file;
9923 Lisp_Object specified_data;
9924 int rc, width, height, x, y, i;
9925 XImage *ximg;
9926 ColorMapObject *gif_color_map;
9927 unsigned long pixel_colors[256];
9928 GifFileType *gif;
9929 struct gcpro gcpro1;
9930 Lisp_Object image;
9931 int ino, image_left, image_top, image_width, image_height;
9932 gif_memory_source memsrc;
9933 unsigned char *raster;
9934
9935 specified_file = image_spec_value (img->spec, QCfile, NULL);
9936 specified_data = image_spec_value (img->spec, QCdata, NULL);
9937 file = Qnil;
9938 GCPRO1 (file);
9939
9940 if (NILP (specified_data))
9941 {
9942 file = x_find_image_file (specified_file);
9943 if (!STRINGP (file))
9944 {
9945 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9946 UNGCPRO;
9947 return 0;
9948 }
9949
9950 /* Open the GIF file. */
9951 gif = DGifOpenFileName (XSTRING (file)->data);
9952 if (gif == NULL)
9953 {
9954 image_error ("Cannot open `%s'", file, Qnil);
9955 UNGCPRO;
9956 return 0;
9957 }
9958 }
9959 else
9960 {
9961 /* Read from memory! */
9962 current_gif_memory_src = &memsrc;
9963 memsrc.bytes = XSTRING (specified_data)->data;
9964 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9965 memsrc.index = 0;
9966
9967 gif = DGifOpen(&memsrc, gif_read_from_memory);
9968 if (!gif)
9969 {
9970 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
9971 UNGCPRO;
9972 return 0;
9973 }
9974 }
9975
9976 /* Read entire contents. */
9977 rc = DGifSlurp (gif);
9978 if (rc == GIF_ERROR)
9979 {
9980 image_error ("Error reading `%s'", img->spec, Qnil);
9981 DGifCloseFile (gif);
9982 UNGCPRO;
9983 return 0;
9984 }
9985
9986 image = image_spec_value (img->spec, QCindex, NULL);
9987 ino = INTEGERP (image) ? XFASTINT (image) : 0;
9988 if (ino >= gif->ImageCount)
9989 {
9990 image_error ("Invalid image number `%s' in image `%s'",
9991 image, img->spec);
9992 DGifCloseFile (gif);
9993 UNGCPRO;
9994 return 0;
9995 }
9996
9997 width = img->width = gif->SWidth;
9998 height = img->height = gif->SHeight;
9999
10000 /* Create the X image and pixmap. */
10001 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
10002 {
10003 DGifCloseFile (gif);
10004 UNGCPRO;
10005 return 0;
10006 }
10007
10008 /* Allocate colors. */
10009 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10010 if (!gif_color_map)
10011 gif_color_map = gif->SColorMap;
10012 init_color_table ();
10013 bzero (pixel_colors, sizeof pixel_colors);
10014
10015 for (i = 0; i < gif_color_map->ColorCount; ++i)
10016 {
10017 int r = gif_color_map->Colors[i].Red << 8;
10018 int g = gif_color_map->Colors[i].Green << 8;
10019 int b = gif_color_map->Colors[i].Blue << 8;
10020 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10021 }
10022
10023 img->colors = colors_in_color_table (&img->ncolors);
10024 free_color_table ();
10025
10026 /* Clear the part of the screen image that are not covered by
10027 the image from the GIF file. Full animated GIF support
10028 requires more than can be done here (see the gif89 spec,
10029 disposal methods). Let's simply assume that the part
10030 not covered by a sub-image is in the frame's background color. */
10031 image_top = gif->SavedImages[ino].ImageDesc.Top;
10032 image_left = gif->SavedImages[ino].ImageDesc.Left;
10033 image_width = gif->SavedImages[ino].ImageDesc.Width;
10034 image_height = gif->SavedImages[ino].ImageDesc.Height;
10035
10036 for (y = 0; y < image_top; ++y)
10037 for (x = 0; x < width; ++x)
10038 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10039
10040 for (y = image_top + image_height; y < height; ++y)
10041 for (x = 0; x < width; ++x)
10042 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10043
10044 for (y = image_top; y < image_top + image_height; ++y)
10045 {
10046 for (x = 0; x < image_left; ++x)
10047 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10048 for (x = image_left + image_width; x < width; ++x)
10049 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10050 }
10051
10052 /* Read the GIF image into the X image. We use a local variable
10053 `raster' here because RasterBits below is a char *, and invites
10054 problems with bytes >= 0x80. */
10055 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
10056
10057 if (gif->SavedImages[ino].ImageDesc.Interlace)
10058 {
10059 static int interlace_start[] = {0, 4, 2, 1};
10060 static int interlace_increment[] = {8, 8, 4, 2};
10061 int pass;
10062 int row = interlace_start[0];
10063
10064 pass = 0;
10065
10066 for (y = 0; y < image_height; y++)
10067 {
10068 if (row >= image_height)
10069 {
10070 row = interlace_start[++pass];
10071 while (row >= image_height)
10072 row = interlace_start[++pass];
10073 }
10074
10075 for (x = 0; x < image_width; x++)
10076 {
10077 int i = raster[(y * image_width) + x];
10078 XPutPixel (ximg, x + image_left, row + image_top,
10079 pixel_colors[i]);
10080 }
10081
10082 row += interlace_increment[pass];
10083 }
10084 }
10085 else
10086 {
10087 for (y = 0; y < image_height; ++y)
10088 for (x = 0; x < image_width; ++x)
10089 {
10090 int i = raster[y * image_width + x];
10091 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
10092 }
10093 }
10094
10095 DGifCloseFile (gif);
10096
10097 /* Maybe fill in the background field while we have ximg handy. */
10098 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10099 IMAGE_BACKGROUND (img, f, ximg);
10100
10101 /* Put the image into the pixmap, then free the X image and its buffer. */
10102 x_put_x_image (f, ximg, img->pixmap, width, height);
10103 x_destroy_x_image (ximg);
10104
10105 UNGCPRO;
10106 return 1;
10107 }
10108
10109 #endif /* HAVE_GIF != 0 */
10110
10111
10112 \f
10113 /***********************************************************************
10114 Ghostscript
10115 ***********************************************************************/
10116
10117 static int gs_image_p P_ ((Lisp_Object object));
10118 static int gs_load P_ ((struct frame *f, struct image *img));
10119 static void gs_clear_image P_ ((struct frame *f, struct image *img));
10120
10121 /* The symbol `postscript' identifying images of this type. */
10122
10123 Lisp_Object Qpostscript;
10124
10125 /* Keyword symbols. */
10126
10127 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
10128
10129 /* Indices of image specification fields in gs_format, below. */
10130
10131 enum gs_keyword_index
10132 {
10133 GS_TYPE,
10134 GS_PT_WIDTH,
10135 GS_PT_HEIGHT,
10136 GS_FILE,
10137 GS_LOADER,
10138 GS_BOUNDING_BOX,
10139 GS_ASCENT,
10140 GS_MARGIN,
10141 GS_RELIEF,
10142 GS_ALGORITHM,
10143 GS_HEURISTIC_MASK,
10144 GS_MASK,
10145 GS_BACKGROUND,
10146 GS_LAST
10147 };
10148
10149 /* Vector of image_keyword structures describing the format
10150 of valid user-defined image specifications. */
10151
10152 static struct image_keyword gs_format[GS_LAST] =
10153 {
10154 {":type", IMAGE_SYMBOL_VALUE, 1},
10155 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10156 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10157 {":file", IMAGE_STRING_VALUE, 1},
10158 {":loader", IMAGE_FUNCTION_VALUE, 0},
10159 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
10160 {":ascent", IMAGE_ASCENT_VALUE, 0},
10161 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10162 {":relief", IMAGE_INTEGER_VALUE, 0},
10163 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10164 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10165 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10166 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10167 };
10168
10169 /* Structure describing the image type `ghostscript'. */
10170
10171 static struct image_type gs_type =
10172 {
10173 &Qpostscript,
10174 gs_image_p,
10175 gs_load,
10176 gs_clear_image,
10177 NULL
10178 };
10179
10180
10181 /* Free X resources of Ghostscript image IMG which is used on frame F. */
10182
10183 static void
10184 gs_clear_image (f, img)
10185 struct frame *f;
10186 struct image *img;
10187 {
10188 /* IMG->data.ptr_val may contain a recorded colormap. */
10189 xfree (img->data.ptr_val);
10190 x_clear_image (f, img);
10191 }
10192
10193
10194 /* Return non-zero if OBJECT is a valid Ghostscript image
10195 specification. */
10196
10197 static int
10198 gs_image_p (object)
10199 Lisp_Object object;
10200 {
10201 struct image_keyword fmt[GS_LAST];
10202 Lisp_Object tem;
10203 int i;
10204
10205 bcopy (gs_format, fmt, sizeof fmt);
10206
10207 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
10208 return 0;
10209
10210 /* Bounding box must be a list or vector containing 4 integers. */
10211 tem = fmt[GS_BOUNDING_BOX].value;
10212 if (CONSP (tem))
10213 {
10214 for (i = 0; i < 4; ++i, tem = XCDR (tem))
10215 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
10216 return 0;
10217 if (!NILP (tem))
10218 return 0;
10219 }
10220 else if (VECTORP (tem))
10221 {
10222 if (XVECTOR (tem)->size != 4)
10223 return 0;
10224 for (i = 0; i < 4; ++i)
10225 if (!INTEGERP (XVECTOR (tem)->contents[i]))
10226 return 0;
10227 }
10228 else
10229 return 0;
10230
10231 return 1;
10232 }
10233
10234
10235 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
10236 if successful. */
10237
10238 static int
10239 gs_load (f, img)
10240 struct frame *f;
10241 struct image *img;
10242 {
10243 char buffer[100];
10244 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
10245 struct gcpro gcpro1, gcpro2;
10246 Lisp_Object frame;
10247 double in_width, in_height;
10248 Lisp_Object pixel_colors = Qnil;
10249
10250 /* Compute pixel size of pixmap needed from the given size in the
10251 image specification. Sizes in the specification are in pt. 1 pt
10252 = 1/72 in, xdpi and ydpi are stored in the frame's X display
10253 info. */
10254 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
10255 in_width = XFASTINT (pt_width) / 72.0;
10256 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
10257 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
10258 in_height = XFASTINT (pt_height) / 72.0;
10259 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
10260
10261 /* Create the pixmap. */
10262 xassert (img->pixmap == None);
10263 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10264 img->width, img->height,
10265 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
10266
10267 if (!img->pixmap)
10268 {
10269 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
10270 return 0;
10271 }
10272
10273 /* Call the loader to fill the pixmap. It returns a process object
10274 if successful. We do not record_unwind_protect here because
10275 other places in redisplay like calling window scroll functions
10276 don't either. Let the Lisp loader use `unwind-protect' instead. */
10277 GCPRO2 (window_and_pixmap_id, pixel_colors);
10278
10279 sprintf (buffer, "%lu %lu",
10280 (unsigned long) FRAME_X_WINDOW (f),
10281 (unsigned long) img->pixmap);
10282 window_and_pixmap_id = build_string (buffer);
10283
10284 sprintf (buffer, "%lu %lu",
10285 FRAME_FOREGROUND_PIXEL (f),
10286 FRAME_BACKGROUND_PIXEL (f));
10287 pixel_colors = build_string (buffer);
10288
10289 XSETFRAME (frame, f);
10290 loader = image_spec_value (img->spec, QCloader, NULL);
10291 if (NILP (loader))
10292 loader = intern ("gs-load-image");
10293
10294 img->data.lisp_val = call6 (loader, frame, img->spec,
10295 make_number (img->width),
10296 make_number (img->height),
10297 window_and_pixmap_id,
10298 pixel_colors);
10299 UNGCPRO;
10300 return PROCESSP (img->data.lisp_val);
10301 }
10302
10303
10304 /* Kill the Ghostscript process that was started to fill PIXMAP on
10305 frame F. Called from XTread_socket when receiving an event
10306 telling Emacs that Ghostscript has finished drawing. */
10307
10308 void
10309 x_kill_gs_process (pixmap, f)
10310 Pixmap pixmap;
10311 struct frame *f;
10312 {
10313 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
10314 int class, i;
10315 struct image *img;
10316
10317 /* Find the image containing PIXMAP. */
10318 for (i = 0; i < c->used; ++i)
10319 if (c->images[i]->pixmap == pixmap)
10320 break;
10321
10322 /* Should someone in between have cleared the image cache, for
10323 instance, give up. */
10324 if (i == c->used)
10325 return;
10326
10327 /* Kill the GS process. We should have found PIXMAP in the image
10328 cache and its image should contain a process object. */
10329 img = c->images[i];
10330 xassert (PROCESSP (img->data.lisp_val));
10331 Fkill_process (img->data.lisp_val, Qnil);
10332 img->data.lisp_val = Qnil;
10333
10334 /* On displays with a mutable colormap, figure out the colors
10335 allocated for the image by looking at the pixels of an XImage for
10336 img->pixmap. */
10337 class = FRAME_X_VISUAL (f)->class;
10338 if (class != StaticColor && class != StaticGray && class != TrueColor)
10339 {
10340 XImage *ximg;
10341
10342 BLOCK_INPUT;
10343
10344 /* Try to get an XImage for img->pixmep. */
10345 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10346 0, 0, img->width, img->height, ~0, ZPixmap);
10347 if (ximg)
10348 {
10349 int x, y;
10350
10351 /* Initialize the color table. */
10352 init_color_table ();
10353
10354 /* For each pixel of the image, look its color up in the
10355 color table. After having done so, the color table will
10356 contain an entry for each color used by the image. */
10357 for (y = 0; y < img->height; ++y)
10358 for (x = 0; x < img->width; ++x)
10359 {
10360 unsigned long pixel = XGetPixel (ximg, x, y);
10361 lookup_pixel_color (f, pixel);
10362 }
10363
10364 /* Record colors in the image. Free color table and XImage. */
10365 img->colors = colors_in_color_table (&img->ncolors);
10366 free_color_table ();
10367 XDestroyImage (ximg);
10368
10369 #if 0 /* This doesn't seem to be the case. If we free the colors
10370 here, we get a BadAccess later in x_clear_image when
10371 freeing the colors. */
10372 /* We have allocated colors once, but Ghostscript has also
10373 allocated colors on behalf of us. So, to get the
10374 reference counts right, free them once. */
10375 if (img->ncolors)
10376 x_free_colors (f, img->colors, img->ncolors);
10377 #endif
10378 }
10379 else
10380 image_error ("Cannot get X image of `%s'; colors will not be freed",
10381 img->spec, Qnil);
10382
10383 UNBLOCK_INPUT;
10384 }
10385
10386 /* Now that we have the pixmap, compute mask and transform the
10387 image if requested. */
10388 BLOCK_INPUT;
10389 postprocess_image (f, img);
10390 UNBLOCK_INPUT;
10391 }
10392
10393
10394 \f
10395 /***********************************************************************
10396 Window properties
10397 ***********************************************************************/
10398
10399 DEFUN ("x-change-window-property", Fx_change_window_property,
10400 Sx_change_window_property, 2, 3, 0,
10401 doc: /* Change window property PROP to VALUE on the X window of FRAME.
10402 PROP and VALUE must be strings. FRAME nil or omitted means use the
10403 selected frame. Value is VALUE. */)
10404 (prop, value, frame)
10405 Lisp_Object frame, prop, value;
10406 {
10407 struct frame *f = check_x_frame (frame);
10408 Atom prop_atom;
10409
10410 CHECK_STRING (prop, 1);
10411 CHECK_STRING (value, 2);
10412
10413 BLOCK_INPUT;
10414 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10415 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10416 prop_atom, XA_STRING, 8, PropModeReplace,
10417 XSTRING (value)->data, XSTRING (value)->size);
10418
10419 /* Make sure the property is set when we return. */
10420 XFlush (FRAME_X_DISPLAY (f));
10421 UNBLOCK_INPUT;
10422
10423 return value;
10424 }
10425
10426
10427 DEFUN ("x-delete-window-property", Fx_delete_window_property,
10428 Sx_delete_window_property, 1, 2, 0,
10429 doc: /* Remove window property PROP from X window of FRAME.
10430 FRAME nil or omitted means use the selected frame. Value is PROP. */)
10431 (prop, frame)
10432 Lisp_Object prop, frame;
10433 {
10434 struct frame *f = check_x_frame (frame);
10435 Atom prop_atom;
10436
10437 CHECK_STRING (prop, 1);
10438 BLOCK_INPUT;
10439 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10440 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10441
10442 /* Make sure the property is removed when we return. */
10443 XFlush (FRAME_X_DISPLAY (f));
10444 UNBLOCK_INPUT;
10445
10446 return prop;
10447 }
10448
10449
10450 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10451 1, 2, 0,
10452 doc: /* Value is the value of window property PROP on FRAME.
10453 If FRAME is nil or omitted, use the selected frame. Value is nil
10454 if FRAME hasn't a property with name PROP or if PROP has no string
10455 value. */)
10456 (prop, frame)
10457 Lisp_Object prop, frame;
10458 {
10459 struct frame *f = check_x_frame (frame);
10460 Atom prop_atom;
10461 int rc;
10462 Lisp_Object prop_value = Qnil;
10463 char *tmp_data = NULL;
10464 Atom actual_type;
10465 int actual_format;
10466 unsigned long actual_size, bytes_remaining;
10467
10468 CHECK_STRING (prop, 1);
10469 BLOCK_INPUT;
10470 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10471 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10472 prop_atom, 0, 0, False, XA_STRING,
10473 &actual_type, &actual_format, &actual_size,
10474 &bytes_remaining, (unsigned char **) &tmp_data);
10475 if (rc == Success)
10476 {
10477 int size = bytes_remaining;
10478
10479 XFree (tmp_data);
10480 tmp_data = NULL;
10481
10482 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10483 prop_atom, 0, bytes_remaining,
10484 False, XA_STRING,
10485 &actual_type, &actual_format,
10486 &actual_size, &bytes_remaining,
10487 (unsigned char **) &tmp_data);
10488 if (rc == Success && tmp_data)
10489 prop_value = make_string (tmp_data, size);
10490
10491 XFree (tmp_data);
10492 }
10493
10494 UNBLOCK_INPUT;
10495 return prop_value;
10496 }
10497
10498
10499 \f
10500 /***********************************************************************
10501 Busy cursor
10502 ***********************************************************************/
10503
10504 /* If non-null, an asynchronous timer that, when it expires, displays
10505 an hourglass cursor on all frames. */
10506
10507 static struct atimer *hourglass_atimer;
10508
10509 /* Non-zero means an hourglass cursor is currently shown. */
10510
10511 static int hourglass_shown_p;
10512
10513 /* Number of seconds to wait before displaying an hourglass cursor. */
10514
10515 static Lisp_Object Vhourglass_delay;
10516
10517 /* Default number of seconds to wait before displaying an hourglass
10518 cursor. */
10519
10520 #define DEFAULT_HOURGLASS_DELAY 1
10521
10522 /* Function prototypes. */
10523
10524 static void show_hourglass P_ ((struct atimer *));
10525 static void hide_hourglass P_ ((void));
10526
10527
10528 /* Cancel a currently active hourglass timer, and start a new one. */
10529
10530 void
10531 start_hourglass ()
10532 {
10533 EMACS_TIME delay;
10534 int secs, usecs = 0;
10535
10536 cancel_hourglass ();
10537
10538 if (INTEGERP (Vhourglass_delay)
10539 && XINT (Vhourglass_delay) > 0)
10540 secs = XFASTINT (Vhourglass_delay);
10541 else if (FLOATP (Vhourglass_delay)
10542 && XFLOAT_DATA (Vhourglass_delay) > 0)
10543 {
10544 Lisp_Object tem;
10545 tem = Ftruncate (Vhourglass_delay, Qnil);
10546 secs = XFASTINT (tem);
10547 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
10548 }
10549 else
10550 secs = DEFAULT_HOURGLASS_DELAY;
10551
10552 EMACS_SET_SECS_USECS (delay, secs, usecs);
10553 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
10554 show_hourglass, NULL);
10555 }
10556
10557
10558 /* Cancel the hourglass cursor timer if active, hide a busy cursor if
10559 shown. */
10560
10561 void
10562 cancel_hourglass ()
10563 {
10564 if (hourglass_atimer)
10565 {
10566 cancel_atimer (hourglass_atimer);
10567 hourglass_atimer = NULL;
10568 }
10569
10570 if (hourglass_shown_p)
10571 hide_hourglass ();
10572 }
10573
10574
10575 /* Timer function of hourglass_atimer. TIMER is equal to
10576 hourglass_atimer.
10577
10578 Display an hourglass pointer on all frames by mapping the frames'
10579 hourglass_window. Set the hourglass_p flag in the frames'
10580 output_data.x structure to indicate that an hourglass cursor is
10581 shown on the frames. */
10582
10583 static void
10584 show_hourglass (timer)
10585 struct atimer *timer;
10586 {
10587 /* The timer implementation will cancel this timer automatically
10588 after this function has run. Set hourglass_atimer to null
10589 so that we know the timer doesn't have to be canceled. */
10590 hourglass_atimer = NULL;
10591
10592 if (!hourglass_shown_p)
10593 {
10594 Lisp_Object rest, frame;
10595
10596 BLOCK_INPUT;
10597
10598 FOR_EACH_FRAME (rest, frame)
10599 {
10600 struct frame *f = XFRAME (frame);
10601
10602 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
10603 {
10604 Display *dpy = FRAME_X_DISPLAY (f);
10605
10606 #ifdef USE_X_TOOLKIT
10607 if (f->output_data.x->widget)
10608 #else
10609 if (FRAME_OUTER_WINDOW (f))
10610 #endif
10611 {
10612 f->output_data.x->hourglass_p = 1;
10613
10614 if (!f->output_data.x->hourglass_window)
10615 {
10616 unsigned long mask = CWCursor;
10617 XSetWindowAttributes attrs;
10618
10619 attrs.cursor = f->output_data.x->hourglass_cursor;
10620
10621 f->output_data.x->hourglass_window
10622 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
10623 0, 0, 32000, 32000, 0, 0,
10624 InputOnly,
10625 CopyFromParent,
10626 mask, &attrs);
10627 }
10628
10629 XMapRaised (dpy, f->output_data.x->hourglass_window);
10630 XFlush (dpy);
10631 }
10632 }
10633 }
10634
10635 hourglass_shown_p = 1;
10636 UNBLOCK_INPUT;
10637 }
10638 }
10639
10640
10641 /* Hide the hourglass pointer on all frames, if it is currently
10642 shown. */
10643
10644 static void
10645 hide_hourglass ()
10646 {
10647 if (hourglass_shown_p)
10648 {
10649 Lisp_Object rest, frame;
10650
10651 BLOCK_INPUT;
10652 FOR_EACH_FRAME (rest, frame)
10653 {
10654 struct frame *f = XFRAME (frame);
10655
10656 if (FRAME_X_P (f)
10657 /* Watch out for newly created frames. */
10658 && f->output_data.x->hourglass_window)
10659 {
10660 XUnmapWindow (FRAME_X_DISPLAY (f),
10661 f->output_data.x->hourglass_window);
10662 /* Sync here because XTread_socket looks at the
10663 hourglass_p flag that is reset to zero below. */
10664 XSync (FRAME_X_DISPLAY (f), False);
10665 f->output_data.x->hourglass_p = 0;
10666 }
10667 }
10668
10669 hourglass_shown_p = 0;
10670 UNBLOCK_INPUT;
10671 }
10672 }
10673
10674
10675 \f
10676 /***********************************************************************
10677 Tool tips
10678 ***********************************************************************/
10679
10680 static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
10681 Lisp_Object, Lisp_Object));
10682 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
10683 Lisp_Object, int, int, int *, int *));
10684
10685 /* The frame of a currently visible tooltip. */
10686
10687 Lisp_Object tip_frame;
10688
10689 /* If non-nil, a timer started that hides the last tooltip when it
10690 fires. */
10691
10692 Lisp_Object tip_timer;
10693 Window tip_window;
10694
10695 /* If non-nil, a vector of 3 elements containing the last args
10696 with which x-show-tip was called. See there. */
10697
10698 Lisp_Object last_show_tip_args;
10699
10700 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
10701
10702 Lisp_Object Vx_max_tooltip_size;
10703
10704
10705 static Lisp_Object
10706 unwind_create_tip_frame (frame)
10707 Lisp_Object frame;
10708 {
10709 Lisp_Object deleted;
10710
10711 deleted = unwind_create_frame (frame);
10712 if (EQ (deleted, Qt))
10713 {
10714 tip_window = None;
10715 tip_frame = Qnil;
10716 }
10717
10718 return deleted;
10719 }
10720
10721
10722 /* Create a frame for a tooltip on the display described by DPYINFO.
10723 PARMS is a list of frame parameters. TEXT is the string to
10724 display in the tip frame. Value is the frame.
10725
10726 Note that functions called here, esp. x_default_parameter can
10727 signal errors, for instance when a specified color name is
10728 undefined. We have to make sure that we're in a consistent state
10729 when this happens. */
10730
10731 static Lisp_Object
10732 x_create_tip_frame (dpyinfo, parms, text)
10733 struct x_display_info *dpyinfo;
10734 Lisp_Object parms, text;
10735 {
10736 struct frame *f;
10737 Lisp_Object frame, tem;
10738 Lisp_Object name;
10739 long window_prompting = 0;
10740 int width, height;
10741 int count = BINDING_STACK_SIZE ();
10742 struct gcpro gcpro1, gcpro2, gcpro3;
10743 struct kboard *kb;
10744 int face_change_count_before = face_change_count;
10745 Lisp_Object buffer;
10746 struct buffer *old_buffer;
10747
10748 check_x ();
10749
10750 /* Use this general default value to start with until we know if
10751 this frame has a specified name. */
10752 Vx_resource_name = Vinvocation_name;
10753
10754 #ifdef MULTI_KBOARD
10755 kb = dpyinfo->kboard;
10756 #else
10757 kb = &the_only_kboard;
10758 #endif
10759
10760 /* Get the name of the frame to use for resource lookup. */
10761 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10762 if (!STRINGP (name)
10763 && !EQ (name, Qunbound)
10764 && !NILP (name))
10765 error ("Invalid frame name--not a string or nil");
10766 Vx_resource_name = name;
10767
10768 frame = Qnil;
10769 GCPRO3 (parms, name, frame);
10770 f = make_frame (1);
10771 XSETFRAME (frame, f);
10772
10773 buffer = Fget_buffer_create (build_string (" *tip*"));
10774 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10775 old_buffer = current_buffer;
10776 set_buffer_internal_1 (XBUFFER (buffer));
10777 current_buffer->truncate_lines = Qnil;
10778 Ferase_buffer ();
10779 Finsert (1, &text);
10780 set_buffer_internal_1 (old_buffer);
10781
10782 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
10783 record_unwind_protect (unwind_create_tip_frame, frame);
10784
10785 /* By setting the output method, we're essentially saying that
10786 the frame is live, as per FRAME_LIVE_P. If we get a signal
10787 from this point on, x_destroy_window might screw up reference
10788 counts etc. */
10789 f->output_method = output_x_window;
10790 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10791 bzero (f->output_data.x, sizeof (struct x_output));
10792 f->output_data.x->icon_bitmap = -1;
10793 f->output_data.x->fontset = -1;
10794 f->output_data.x->scroll_bar_foreground_pixel = -1;
10795 f->output_data.x->scroll_bar_background_pixel = -1;
10796 #ifdef USE_TOOLKIT_SCROLL_BARS
10797 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
10798 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
10799 #endif /* USE_TOOLKIT_SCROLL_BARS */
10800 f->icon_name = Qnil;
10801 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
10802 #if GLYPH_DEBUG
10803 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
10804 dpyinfo_refcount = dpyinfo->reference_count;
10805 #endif /* GLYPH_DEBUG */
10806 #ifdef MULTI_KBOARD
10807 FRAME_KBOARD (f) = kb;
10808 #endif
10809 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10810 f->output_data.x->explicit_parent = 0;
10811
10812 /* These colors will be set anyway later, but it's important
10813 to get the color reference counts right, so initialize them! */
10814 {
10815 Lisp_Object black;
10816 struct gcpro gcpro1;
10817
10818 black = build_string ("black");
10819 GCPRO1 (black);
10820 f->output_data.x->foreground_pixel
10821 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10822 f->output_data.x->background_pixel
10823 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10824 f->output_data.x->cursor_pixel
10825 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10826 f->output_data.x->cursor_foreground_pixel
10827 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10828 f->output_data.x->border_pixel
10829 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10830 f->output_data.x->mouse_pixel
10831 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10832 UNGCPRO;
10833 }
10834
10835 /* Set the name; the functions to which we pass f expect the name to
10836 be set. */
10837 if (EQ (name, Qunbound) || NILP (name))
10838 {
10839 f->name = build_string (dpyinfo->x_id_name);
10840 f->explicit_name = 0;
10841 }
10842 else
10843 {
10844 f->name = name;
10845 f->explicit_name = 1;
10846 /* use the frame's title when getting resources for this frame. */
10847 specbind (Qx_resource_name, name);
10848 }
10849
10850 /* Extract the window parameters from the supplied values that are
10851 needed to determine window geometry. */
10852 {
10853 Lisp_Object font;
10854
10855 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
10856
10857 BLOCK_INPUT;
10858 /* First, try whatever font the caller has specified. */
10859 if (STRINGP (font))
10860 {
10861 tem = Fquery_fontset (font, Qnil);
10862 if (STRINGP (tem))
10863 font = x_new_fontset (f, XSTRING (tem)->data);
10864 else
10865 font = x_new_font (f, XSTRING (font)->data);
10866 }
10867
10868 /* Try out a font which we hope has bold and italic variations. */
10869 if (!STRINGP (font))
10870 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
10871 if (!STRINGP (font))
10872 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
10873 if (! STRINGP (font))
10874 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
10875 if (! STRINGP (font))
10876 /* This was formerly the first thing tried, but it finds too many fonts
10877 and takes too long. */
10878 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
10879 /* If those didn't work, look for something which will at least work. */
10880 if (! STRINGP (font))
10881 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
10882 UNBLOCK_INPUT;
10883 if (! STRINGP (font))
10884 font = build_string ("fixed");
10885
10886 x_default_parameter (f, parms, Qfont, font,
10887 "font", "Font", RES_TYPE_STRING);
10888 }
10889
10890 x_default_parameter (f, parms, Qborder_width, make_number (2),
10891 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
10892
10893 /* This defaults to 2 in order to match xterm. We recognize either
10894 internalBorderWidth or internalBorder (which is what xterm calls
10895 it). */
10896 if (NILP (Fassq (Qinternal_border_width, parms)))
10897 {
10898 Lisp_Object value;
10899
10900 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
10901 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
10902 if (! EQ (value, Qunbound))
10903 parms = Fcons (Fcons (Qinternal_border_width, value),
10904 parms);
10905 }
10906
10907 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
10908 "internalBorderWidth", "internalBorderWidth",
10909 RES_TYPE_NUMBER);
10910
10911 /* Also do the stuff which must be set before the window exists. */
10912 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
10913 "foreground", "Foreground", RES_TYPE_STRING);
10914 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
10915 "background", "Background", RES_TYPE_STRING);
10916 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
10917 "pointerColor", "Foreground", RES_TYPE_STRING);
10918 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
10919 "cursorColor", "Foreground", RES_TYPE_STRING);
10920 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
10921 "borderColor", "BorderColor", RES_TYPE_STRING);
10922
10923 /* Init faces before x_default_parameter is called for scroll-bar
10924 parameters because that function calls x_set_scroll_bar_width,
10925 which calls change_frame_size, which calls Fset_window_buffer,
10926 which runs hooks, which call Fvertical_motion. At the end, we
10927 end up in init_iterator with a null face cache, which should not
10928 happen. */
10929 init_frame_faces (f);
10930
10931 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10932 window_prompting = x_figure_window_size (f, parms);
10933
10934 if (window_prompting & XNegative)
10935 {
10936 if (window_prompting & YNegative)
10937 f->output_data.x->win_gravity = SouthEastGravity;
10938 else
10939 f->output_data.x->win_gravity = NorthEastGravity;
10940 }
10941 else
10942 {
10943 if (window_prompting & YNegative)
10944 f->output_data.x->win_gravity = SouthWestGravity;
10945 else
10946 f->output_data.x->win_gravity = NorthWestGravity;
10947 }
10948
10949 f->output_data.x->size_hint_flags = window_prompting;
10950 {
10951 XSetWindowAttributes attrs;
10952 unsigned long mask;
10953
10954 BLOCK_INPUT;
10955 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
10956 if (DoesSaveUnders (dpyinfo->screen))
10957 mask |= CWSaveUnder;
10958
10959 /* Window managers look at the override-redirect flag to determine
10960 whether or net to give windows a decoration (Xlib spec, chapter
10961 3.2.8). */
10962 attrs.override_redirect = True;
10963 attrs.save_under = True;
10964 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
10965 /* Arrange for getting MapNotify and UnmapNotify events. */
10966 attrs.event_mask = StructureNotifyMask;
10967 tip_window
10968 = FRAME_X_WINDOW (f)
10969 = XCreateWindow (FRAME_X_DISPLAY (f),
10970 FRAME_X_DISPLAY_INFO (f)->root_window,
10971 /* x, y, width, height */
10972 0, 0, 1, 1,
10973 /* Border. */
10974 1,
10975 CopyFromParent, InputOutput, CopyFromParent,
10976 mask, &attrs);
10977 UNBLOCK_INPUT;
10978 }
10979
10980 x_make_gc (f);
10981
10982 x_default_parameter (f, parms, Qauto_raise, Qnil,
10983 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10984 x_default_parameter (f, parms, Qauto_lower, Qnil,
10985 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10986 x_default_parameter (f, parms, Qcursor_type, Qbox,
10987 "cursorType", "CursorType", RES_TYPE_SYMBOL);
10988
10989 /* Dimensions, especially f->height, must be done via change_frame_size.
10990 Change will not be effected unless different from the current
10991 f->height. */
10992 width = f->width;
10993 height = f->height;
10994 f->height = 0;
10995 SET_FRAME_WIDTH (f, 0);
10996 change_frame_size (f, height, width, 1, 0, 0);
10997
10998 /* Set up faces after all frame parameters are known. This call
10999 also merges in face attributes specified for new frames.
11000
11001 Frame parameters may be changed if .Xdefaults contains
11002 specifications for the default font. For example, if there is an
11003 `Emacs.default.attributeBackground: pink', the `background-color'
11004 attribute of the frame get's set, which let's the internal border
11005 of the tooltip frame appear in pink. Prevent this. */
11006 {
11007 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
11008
11009 /* Set tip_frame here, so that */
11010 tip_frame = frame;
11011 call1 (Qface_set_after_frame_default, frame);
11012
11013 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
11014 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
11015 Qnil));
11016 }
11017
11018 f->no_split = 1;
11019
11020 UNGCPRO;
11021
11022 /* It is now ok to make the frame official even if we get an error
11023 below. And the frame needs to be on Vframe_list or making it
11024 visible won't work. */
11025 Vframe_list = Fcons (frame, Vframe_list);
11026
11027 /* Now that the frame is official, it counts as a reference to
11028 its display. */
11029 FRAME_X_DISPLAY_INFO (f)->reference_count++;
11030
11031 /* Setting attributes of faces of the tooltip frame from resources
11032 and similar will increment face_change_count, which leads to the
11033 clearing of all current matrices. Since this isn't necessary
11034 here, avoid it by resetting face_change_count to the value it
11035 had before we created the tip frame. */
11036 face_change_count = face_change_count_before;
11037
11038 /* Discard the unwind_protect. */
11039 return unbind_to (count, frame);
11040 }
11041
11042
11043 /* Compute where to display tip frame F. PARMS is the list of frame
11044 parameters for F. DX and DY are specified offsets from the current
11045 location of the mouse. WIDTH and HEIGHT are the width and height
11046 of the tooltip. Return coordinates relative to the root window of
11047 the display in *ROOT_X, and *ROOT_Y. */
11048
11049 static void
11050 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
11051 struct frame *f;
11052 Lisp_Object parms, dx, dy;
11053 int width, height;
11054 int *root_x, *root_y;
11055 {
11056 Lisp_Object left, top;
11057 int win_x, win_y;
11058 Window root, child;
11059 unsigned pmask;
11060
11061 /* User-specified position? */
11062 left = Fcdr (Fassq (Qleft, parms));
11063 top = Fcdr (Fassq (Qtop, parms));
11064
11065 /* Move the tooltip window where the mouse pointer is. Resize and
11066 show it. */
11067 if (!INTEGERP (left) && !INTEGERP (top))
11068 {
11069 BLOCK_INPUT;
11070 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
11071 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
11072 UNBLOCK_INPUT;
11073 }
11074
11075 if (INTEGERP (top))
11076 *root_y = XINT (top);
11077 else if (*root_y + XINT (dy) - height < 0)
11078 *root_y -= XINT (dy);
11079 else
11080 {
11081 *root_y -= height;
11082 *root_y += XINT (dy);
11083 }
11084
11085 if (INTEGERP (left))
11086 *root_x = XINT (left);
11087 else if (*root_x + XINT (dx) + width > FRAME_X_DISPLAY_INFO (f)->width)
11088 *root_x -= width + XINT (dx);
11089 else
11090 *root_x += XINT (dx);
11091 }
11092
11093
11094 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
11095 doc: /* Show STRING in a "tooltip" window on frame FRAME.
11096 A tooltip window is a small X window displaying a string.
11097
11098 FRAME nil or omitted means use the selected frame.
11099
11100 PARMS is an optional list of frame parameters which can be used to
11101 change the tooltip's appearance.
11102
11103 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
11104 means use the default timeout of 5 seconds.
11105
11106 If the list of frame parameters PARAMS contains a `left' parameters,
11107 the tooltip is displayed at that x-position. Otherwise it is
11108 displayed at the mouse position, with offset DX added (default is 5 if
11109 DX isn't specified). Likewise for the y-position; if a `top' frame
11110 parameter is specified, it determines the y-position of the tooltip
11111 window, otherwise it is displayed at the mouse position, with offset
11112 DY added (default is -10).
11113
11114 A tooltip's maximum size is specified by `x-max-tooltip-size'.
11115 Text larger than the specified size is clipped. */)
11116 (string, frame, parms, timeout, dx, dy)
11117 Lisp_Object string, frame, parms, timeout, dx, dy;
11118 {
11119 struct frame *f;
11120 struct window *w;
11121 int root_x, root_y;
11122 struct buffer *old_buffer;
11123 struct text_pos pos;
11124 int i, width, height;
11125 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
11126 int old_windows_or_buffers_changed = windows_or_buffers_changed;
11127 int count = BINDING_STACK_SIZE ();
11128
11129 specbind (Qinhibit_redisplay, Qt);
11130
11131 GCPRO4 (string, parms, frame, timeout);
11132
11133 CHECK_STRING (string, 0);
11134 f = check_x_frame (frame);
11135 if (NILP (timeout))
11136 timeout = make_number (5);
11137 else
11138 CHECK_NATNUM (timeout, 2);
11139
11140 if (NILP (dx))
11141 dx = make_number (5);
11142 else
11143 CHECK_NUMBER (dx, 5);
11144
11145 if (NILP (dy))
11146 dy = make_number (-10);
11147 else
11148 CHECK_NUMBER (dy, 6);
11149
11150 if (NILP (last_show_tip_args))
11151 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
11152
11153 if (!NILP (tip_frame))
11154 {
11155 Lisp_Object last_string = AREF (last_show_tip_args, 0);
11156 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
11157 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
11158
11159 if (EQ (frame, last_frame)
11160 && !NILP (Fequal (last_string, string))
11161 && !NILP (Fequal (last_parms, parms)))
11162 {
11163 struct frame *f = XFRAME (tip_frame);
11164
11165 /* Only DX and DY have changed. */
11166 if (!NILP (tip_timer))
11167 {
11168 Lisp_Object timer = tip_timer;
11169 tip_timer = Qnil;
11170 call1 (Qcancel_timer, timer);
11171 }
11172
11173 BLOCK_INPUT;
11174 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
11175 PIXEL_HEIGHT (f), &root_x, &root_y);
11176 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11177 root_x, root_y);
11178 UNBLOCK_INPUT;
11179 goto start_timer;
11180 }
11181 }
11182
11183 /* Hide a previous tip, if any. */
11184 Fx_hide_tip ();
11185
11186 ASET (last_show_tip_args, 0, string);
11187 ASET (last_show_tip_args, 1, frame);
11188 ASET (last_show_tip_args, 2, parms);
11189
11190 /* Add default values to frame parameters. */
11191 if (NILP (Fassq (Qname, parms)))
11192 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11193 if (NILP (Fassq (Qinternal_border_width, parms)))
11194 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11195 if (NILP (Fassq (Qborder_width, parms)))
11196 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11197 if (NILP (Fassq (Qborder_color, parms)))
11198 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11199 if (NILP (Fassq (Qbackground_color, parms)))
11200 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11201 parms);
11202
11203 /* Create a frame for the tooltip, and record it in the global
11204 variable tip_frame. */
11205 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
11206 f = XFRAME (frame);
11207
11208 /* Set up the frame's root window. */
11209 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11210 w->left = w->top = make_number (0);
11211
11212 if (CONSP (Vx_max_tooltip_size)
11213 && INTEGERP (XCAR (Vx_max_tooltip_size))
11214 && XINT (XCAR (Vx_max_tooltip_size)) > 0
11215 && INTEGERP (XCDR (Vx_max_tooltip_size))
11216 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
11217 {
11218 w->width = XCAR (Vx_max_tooltip_size);
11219 w->height = XCDR (Vx_max_tooltip_size);
11220 }
11221 else
11222 {
11223 w->width = make_number (80);
11224 w->height = make_number (40);
11225 }
11226
11227 f->window_width = XINT (w->width);
11228 adjust_glyphs (f);
11229 w->pseudo_window_p = 1;
11230
11231 /* Display the tooltip text in a temporary buffer. */
11232 old_buffer = current_buffer;
11233 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
11234 current_buffer->truncate_lines = Qnil;
11235 clear_glyph_matrix (w->desired_matrix);
11236 clear_glyph_matrix (w->current_matrix);
11237 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11238 try_window (FRAME_ROOT_WINDOW (f), pos);
11239
11240 /* Compute width and height of the tooltip. */
11241 width = height = 0;
11242 for (i = 0; i < w->desired_matrix->nrows; ++i)
11243 {
11244 struct glyph_row *row = &w->desired_matrix->rows[i];
11245 struct glyph *last;
11246 int row_width;
11247
11248 /* Stop at the first empty row at the end. */
11249 if (!row->enabled_p || !row->displays_text_p)
11250 break;
11251
11252 /* Let the row go over the full width of the frame. */
11253 row->full_width_p = 1;
11254
11255 /* There's a glyph at the end of rows that is used to place
11256 the cursor there. Don't include the width of this glyph. */
11257 if (row->used[TEXT_AREA])
11258 {
11259 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11260 row_width = row->pixel_width - last->pixel_width;
11261 }
11262 else
11263 row_width = row->pixel_width;
11264
11265 height += row->height;
11266 width = max (width, row_width);
11267 }
11268
11269 /* Add the frame's internal border to the width and height the X
11270 window should have. */
11271 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11272 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11273
11274 /* Move the tooltip window where the mouse pointer is. Resize and
11275 show it. */
11276 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
11277
11278 BLOCK_INPUT;
11279 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11280 root_x, root_y, width, height);
11281 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11282 UNBLOCK_INPUT;
11283
11284 /* Draw into the window. */
11285 w->must_be_updated_p = 1;
11286 update_single_window (w, 1);
11287
11288 /* Restore original current buffer. */
11289 set_buffer_internal_1 (old_buffer);
11290 windows_or_buffers_changed = old_windows_or_buffers_changed;
11291
11292 start_timer:
11293 /* Let the tip disappear after timeout seconds. */
11294 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11295 intern ("x-hide-tip"));
11296
11297 UNGCPRO;
11298 return unbind_to (count, Qnil);
11299 }
11300
11301
11302 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
11303 doc: /* Hide the current tooltip window, if there is any.
11304 Value is t if tooltip was open, nil otherwise. */)
11305 ()
11306 {
11307 int count;
11308 Lisp_Object deleted, frame, timer;
11309 struct gcpro gcpro1, gcpro2;
11310
11311 /* Return quickly if nothing to do. */
11312 if (NILP (tip_timer) && NILP (tip_frame))
11313 return Qnil;
11314
11315 frame = tip_frame;
11316 timer = tip_timer;
11317 GCPRO2 (frame, timer);
11318 tip_frame = tip_timer = deleted = Qnil;
11319
11320 count = BINDING_STACK_SIZE ();
11321 specbind (Qinhibit_redisplay, Qt);
11322 specbind (Qinhibit_quit, Qt);
11323
11324 if (!NILP (timer))
11325 call1 (Qcancel_timer, timer);
11326
11327 if (FRAMEP (frame))
11328 {
11329 Fdelete_frame (frame, Qnil);
11330 deleted = Qt;
11331
11332 #ifdef USE_LUCID
11333 /* Bloodcurdling hack alert: The Lucid menu bar widget's
11334 redisplay procedure is not called when a tip frame over menu
11335 items is unmapped. Redisplay the menu manually... */
11336 {
11337 struct frame *f = SELECTED_FRAME ();
11338 Widget w = f->output_data.x->menubar_widget;
11339 extern void xlwmenu_redisplay P_ ((Widget));
11340
11341 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
11342 && w != NULL)
11343 {
11344 BLOCK_INPUT;
11345 xlwmenu_redisplay (w);
11346 UNBLOCK_INPUT;
11347 }
11348 }
11349 #endif /* USE_LUCID */
11350 }
11351
11352 UNGCPRO;
11353 return unbind_to (count, deleted);
11354 }
11355
11356
11357 \f
11358 /***********************************************************************
11359 File selection dialog
11360 ***********************************************************************/
11361
11362 #ifdef USE_MOTIF
11363
11364 /* Callback for "OK" and "Cancel" on file selection dialog. */
11365
11366 static void
11367 file_dialog_cb (widget, client_data, call_data)
11368 Widget widget;
11369 XtPointer call_data, client_data;
11370 {
11371 int *result = (int *) client_data;
11372 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
11373 *result = cb->reason;
11374 }
11375
11376
11377 /* Callback for unmapping a file selection dialog. This is used to
11378 capture the case where a dialog is closed via a window manager's
11379 closer button, for example. Using a XmNdestroyCallback didn't work
11380 in this case. */
11381
11382 static void
11383 file_dialog_unmap_cb (widget, client_data, call_data)
11384 Widget widget;
11385 XtPointer call_data, client_data;
11386 {
11387 int *result = (int *) client_data;
11388 *result = XmCR_CANCEL;
11389 }
11390
11391
11392 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
11393 doc: /* Read file name, prompting with PROMPT in directory DIR.
11394 Use a file selection dialog.
11395 Select DEFAULT-FILENAME in the dialog's file selection box, if
11396 specified. Don't let the user enter a file name in the file
11397 selection dialog's entry field, if MUSTMATCH is non-nil. */)
11398 (prompt, dir, default_filename, mustmatch)
11399 Lisp_Object prompt, dir, default_filename, mustmatch;
11400 {
11401 int result;
11402 struct frame *f = SELECTED_FRAME ();
11403 Lisp_Object file = Qnil;
11404 Widget dialog, text, list, help;
11405 Arg al[10];
11406 int ac = 0;
11407 extern XtAppContext Xt_app_con;
11408 XmString dir_xmstring, pattern_xmstring;
11409 int count = specpdl_ptr - specpdl;
11410 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
11411
11412 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
11413 CHECK_STRING (prompt, 0);
11414 CHECK_STRING (dir, 1);
11415
11416 /* Prevent redisplay. */
11417 specbind (Qinhibit_redisplay, Qt);
11418
11419 BLOCK_INPUT;
11420
11421 /* Create the dialog with PROMPT as title, using DIR as initial
11422 directory and using "*" as pattern. */
11423 dir = Fexpand_file_name (dir, Qnil);
11424 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
11425 pattern_xmstring = XmStringCreateLocalized ("*");
11426
11427 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
11428 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
11429 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
11430 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
11431 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
11432 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
11433 "fsb", al, ac);
11434 XmStringFree (dir_xmstring);
11435 XmStringFree (pattern_xmstring);
11436
11437 /* Add callbacks for OK and Cancel. */
11438 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
11439 (XtPointer) &result);
11440 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
11441 (XtPointer) &result);
11442 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
11443 (XtPointer) &result);
11444
11445 /* Disable the help button since we can't display help. */
11446 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
11447 XtSetSensitive (help, False);
11448
11449 /* Mark OK button as default. */
11450 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
11451 XmNshowAsDefault, True, NULL);
11452
11453 /* If MUSTMATCH is non-nil, disable the file entry field of the
11454 dialog, so that the user must select a file from the files list
11455 box. We can't remove it because we wouldn't have a way to get at
11456 the result file name, then. */
11457 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
11458 if (!NILP (mustmatch))
11459 {
11460 Widget label;
11461 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
11462 XtSetSensitive (text, False);
11463 XtSetSensitive (label, False);
11464 }
11465
11466 /* Manage the dialog, so that list boxes get filled. */
11467 XtManageChild (dialog);
11468
11469 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
11470 must include the path for this to work. */
11471 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
11472 if (STRINGP (default_filename))
11473 {
11474 XmString default_xmstring;
11475 int item_pos;
11476
11477 default_xmstring
11478 = XmStringCreateLocalized (XSTRING (default_filename)->data);
11479
11480 if (!XmListItemExists (list, default_xmstring))
11481 {
11482 /* Add a new item if DEFAULT_FILENAME is not in the list. */
11483 XmListAddItem (list, default_xmstring, 0);
11484 item_pos = 0;
11485 }
11486 else
11487 item_pos = XmListItemPos (list, default_xmstring);
11488 XmStringFree (default_xmstring);
11489
11490 /* Select the item and scroll it into view. */
11491 XmListSelectPos (list, item_pos, True);
11492 XmListSetPos (list, item_pos);
11493 }
11494
11495 /* Process events until the user presses Cancel or OK. Block
11496 and unblock input here so that we get a chance of processing
11497 expose events. */
11498 UNBLOCK_INPUT;
11499 result = 0;
11500 while (result == 0)
11501 {
11502 BLOCK_INPUT;
11503 XtAppProcessEvent (Xt_app_con, XtIMAll);
11504 UNBLOCK_INPUT;
11505 }
11506 BLOCK_INPUT;
11507
11508 /* Get the result. */
11509 if (result == XmCR_OK)
11510 {
11511 XmString text;
11512 String data;
11513
11514 XtVaGetValues (dialog, XmNtextString, &text, NULL);
11515 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
11516 XmStringFree (text);
11517 file = build_string (data);
11518 XtFree (data);
11519 }
11520 else
11521 file = Qnil;
11522
11523 /* Clean up. */
11524 XtUnmanageChild (dialog);
11525 XtDestroyWidget (dialog);
11526 UNBLOCK_INPUT;
11527 UNGCPRO;
11528
11529 /* Make "Cancel" equivalent to C-g. */
11530 if (NILP (file))
11531 Fsignal (Qquit, Qnil);
11532
11533 return unbind_to (count, file);
11534 }
11535
11536 #endif /* USE_MOTIF */
11537
11538
11539 \f
11540 /***********************************************************************
11541 Keyboard
11542 ***********************************************************************/
11543
11544 #ifdef HAVE_XKBGETKEYBOARD
11545 #include <X11/XKBlib.h>
11546 #include <X11/keysym.h>
11547 #endif
11548
11549 DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
11550 Sx_backspace_delete_keys_p, 0, 1, 0,
11551 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
11552 FRAME nil means use the selected frame.
11553 Value is t if we know that both keys are present, and are mapped to the
11554 usual X keysyms. */)
11555 (frame)
11556 Lisp_Object frame;
11557 {
11558 #ifdef HAVE_XKBGETKEYBOARD
11559 XkbDescPtr kb;
11560 struct frame *f = check_x_frame (frame);
11561 Display *dpy = FRAME_X_DISPLAY (f);
11562 Lisp_Object have_keys;
11563 int major, minor, op, event, error;
11564
11565 BLOCK_INPUT;
11566
11567 /* Check library version in case we're dynamically linked. */
11568 major = XkbMajorVersion;
11569 minor = XkbMinorVersion;
11570 if (!XkbLibraryVersion (&major, &minor))
11571 {
11572 UNBLOCK_INPUT;
11573 return Qnil;
11574 }
11575
11576 /* Check that the server supports XKB. */
11577 major = XkbMajorVersion;
11578 minor = XkbMinorVersion;
11579 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
11580 {
11581 UNBLOCK_INPUT;
11582 return Qnil;
11583 }
11584
11585 have_keys = Qnil;
11586 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
11587 if (kb)
11588 {
11589 int delete_keycode = 0, backspace_keycode = 0, i;
11590
11591 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
11592 {
11593 for (i = kb->min_key_code;
11594 (i < kb->max_key_code
11595 && (delete_keycode == 0 || backspace_keycode == 0));
11596 ++i)
11597 {
11598 /* The XKB symbolic key names can be seen most easily in
11599 the PS file generated by `xkbprint -label name
11600 $DISPLAY'. */
11601 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
11602 delete_keycode = i;
11603 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
11604 backspace_keycode = i;
11605 }
11606
11607 XkbFreeNames (kb, 0, True);
11608 }
11609
11610 XkbFreeClientMap (kb, 0, True);
11611
11612 if (delete_keycode
11613 && backspace_keycode
11614 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
11615 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
11616 have_keys = Qt;
11617 }
11618 UNBLOCK_INPUT;
11619 return have_keys;
11620 #else /* not HAVE_XKBGETKEYBOARD */
11621 return Qnil;
11622 #endif /* not HAVE_XKBGETKEYBOARD */
11623 }
11624
11625
11626 \f
11627 /***********************************************************************
11628 Initialization
11629 ***********************************************************************/
11630
11631 void
11632 syms_of_xfns ()
11633 {
11634 /* This is zero if not using X windows. */
11635 x_in_use = 0;
11636
11637 /* The section below is built by the lisp expression at the top of the file,
11638 just above where these variables are declared. */
11639 /*&&& init symbols here &&&*/
11640 Qauto_raise = intern ("auto-raise");
11641 staticpro (&Qauto_raise);
11642 Qauto_lower = intern ("auto-lower");
11643 staticpro (&Qauto_lower);
11644 Qbar = intern ("bar");
11645 staticpro (&Qbar);
11646 Qborder_color = intern ("border-color");
11647 staticpro (&Qborder_color);
11648 Qborder_width = intern ("border-width");
11649 staticpro (&Qborder_width);
11650 Qbox = intern ("box");
11651 staticpro (&Qbox);
11652 Qcursor_color = intern ("cursor-color");
11653 staticpro (&Qcursor_color);
11654 Qcursor_type = intern ("cursor-type");
11655 staticpro (&Qcursor_type);
11656 Qgeometry = intern ("geometry");
11657 staticpro (&Qgeometry);
11658 Qicon_left = intern ("icon-left");
11659 staticpro (&Qicon_left);
11660 Qicon_top = intern ("icon-top");
11661 staticpro (&Qicon_top);
11662 Qicon_type = intern ("icon-type");
11663 staticpro (&Qicon_type);
11664 Qicon_name = intern ("icon-name");
11665 staticpro (&Qicon_name);
11666 Qinternal_border_width = intern ("internal-border-width");
11667 staticpro (&Qinternal_border_width);
11668 Qleft = intern ("left");
11669 staticpro (&Qleft);
11670 Qright = intern ("right");
11671 staticpro (&Qright);
11672 Qmouse_color = intern ("mouse-color");
11673 staticpro (&Qmouse_color);
11674 Qnone = intern ("none");
11675 staticpro (&Qnone);
11676 Qparent_id = intern ("parent-id");
11677 staticpro (&Qparent_id);
11678 Qscroll_bar_width = intern ("scroll-bar-width");
11679 staticpro (&Qscroll_bar_width);
11680 Qsuppress_icon = intern ("suppress-icon");
11681 staticpro (&Qsuppress_icon);
11682 Qundefined_color = intern ("undefined-color");
11683 staticpro (&Qundefined_color);
11684 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11685 staticpro (&Qvertical_scroll_bars);
11686 Qvisibility = intern ("visibility");
11687 staticpro (&Qvisibility);
11688 Qwindow_id = intern ("window-id");
11689 staticpro (&Qwindow_id);
11690 Qouter_window_id = intern ("outer-window-id");
11691 staticpro (&Qouter_window_id);
11692 Qx_frame_parameter = intern ("x-frame-parameter");
11693 staticpro (&Qx_frame_parameter);
11694 Qx_resource_name = intern ("x-resource-name");
11695 staticpro (&Qx_resource_name);
11696 Quser_position = intern ("user-position");
11697 staticpro (&Quser_position);
11698 Quser_size = intern ("user-size");
11699 staticpro (&Quser_size);
11700 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11701 staticpro (&Qscroll_bar_foreground);
11702 Qscroll_bar_background = intern ("scroll-bar-background");
11703 staticpro (&Qscroll_bar_background);
11704 Qscreen_gamma = intern ("screen-gamma");
11705 staticpro (&Qscreen_gamma);
11706 Qline_spacing = intern ("line-spacing");
11707 staticpro (&Qline_spacing);
11708 Qcenter = intern ("center");
11709 staticpro (&Qcenter);
11710 Qcompound_text = intern ("compound-text");
11711 staticpro (&Qcompound_text);
11712 Qcancel_timer = intern ("cancel-timer");
11713 staticpro (&Qcancel_timer);
11714 Qwait_for_wm = intern ("wait-for-wm");
11715 staticpro (&Qwait_for_wm);
11716 /* This is the end of symbol initialization. */
11717
11718 /* Text property `display' should be nonsticky by default. */
11719 Vtext_property_default_nonsticky
11720 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11721
11722
11723 Qlaplace = intern ("laplace");
11724 staticpro (&Qlaplace);
11725 Qemboss = intern ("emboss");
11726 staticpro (&Qemboss);
11727 Qedge_detection = intern ("edge-detection");
11728 staticpro (&Qedge_detection);
11729 Qheuristic = intern ("heuristic");
11730 staticpro (&Qheuristic);
11731 QCmatrix = intern (":matrix");
11732 staticpro (&QCmatrix);
11733 QCcolor_adjustment = intern (":color-adjustment");
11734 staticpro (&QCcolor_adjustment);
11735 QCmask = intern (":mask");
11736 staticpro (&QCmask);
11737
11738 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11739 staticpro (&Qface_set_after_frame_default);
11740
11741 Fput (Qundefined_color, Qerror_conditions,
11742 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11743 Fput (Qundefined_color, Qerror_message,
11744 build_string ("Undefined color"));
11745
11746 init_x_parm_symbols ();
11747
11748 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
11749 doc: /* Non-nil means always draw a cross over disabled images.
11750 Disabled images are those having an `:conversion disabled' property.
11751 A cross is always drawn on black & white displays. */);
11752 cross_disabled_images = 0;
11753
11754 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11755 doc: /* List of directories to search for bitmap files for X. */);
11756 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
11757
11758 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
11759 doc: /* The shape of the pointer when over text.
11760 Changing the value does not affect existing frames
11761 unless you set the mouse color. */);
11762 Vx_pointer_shape = Qnil;
11763
11764 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
11765 doc: /* The name Emacs uses to look up X resources.
11766 `x-get-resource' uses this as the first component of the instance name
11767 when requesting resource values.
11768 Emacs initially sets `x-resource-name' to the name under which Emacs
11769 was invoked, or to the value specified with the `-name' or `-rn'
11770 switches, if present.
11771
11772 It may be useful to bind this variable locally around a call
11773 to `x-get-resource'. See also the variable `x-resource-class'. */);
11774 Vx_resource_name = Qnil;
11775
11776 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11777 doc: /* The class Emacs uses to look up X resources.
11778 `x-get-resource' uses this as the first component of the instance class
11779 when requesting resource values.
11780
11781 Emacs initially sets `x-resource-class' to "Emacs".
11782
11783 Setting this variable permanently is not a reasonable thing to do,
11784 but binding this variable locally around a call to `x-get-resource'
11785 is a reasonable practice. See also the variable `x-resource-name'. */);
11786 Vx_resource_class = build_string (EMACS_CLASS);
11787
11788 #if 0 /* This doesn't really do anything. */
11789 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
11790 doc: /* The shape of the pointer when not over text.
11791 This variable takes effect when you create a new frame
11792 or when you set the mouse color. */);
11793 #endif
11794 Vx_nontext_pointer_shape = Qnil;
11795
11796 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
11797 doc: /* The shape of the pointer when Emacs is busy.
11798 This variable takes effect when you create a new frame
11799 or when you set the mouse color. */);
11800 Vx_hourglass_pointer_shape = Qnil;
11801
11802 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
11803 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
11804 display_hourglass_p = 1;
11805
11806 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
11807 doc: /* *Seconds to wait before displaying an hourglass pointer.
11808 Value must be an integer or float. */);
11809 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
11810
11811 #if 0 /* This doesn't really do anything. */
11812 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
11813 doc: /* The shape of the pointer when over the mode line.
11814 This variable takes effect when you create a new frame
11815 or when you set the mouse color. */);
11816 #endif
11817 Vx_mode_pointer_shape = Qnil;
11818
11819 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
11820 &Vx_sensitive_text_pointer_shape,
11821 doc: /* The shape of the pointer when over mouse-sensitive text.
11822 This variable takes effect when you create a new frame
11823 or when you set the mouse color. */);
11824 Vx_sensitive_text_pointer_shape = Qnil;
11825
11826 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
11827 &Vx_window_horizontal_drag_shape,
11828 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
11829 This variable takes effect when you create a new frame
11830 or when you set the mouse color. */);
11831 Vx_window_horizontal_drag_shape = Qnil;
11832
11833 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
11834 doc: /* A string indicating the foreground color of the cursor box. */);
11835 Vx_cursor_fore_pixel = Qnil;
11836
11837 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
11838 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
11839 Text larger than this is clipped. */);
11840 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
11841
11842 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
11843 doc: /* Non-nil if no X window manager is in use.
11844 Emacs doesn't try to figure this out; this is always nil
11845 unless you set it to something else. */);
11846 /* We don't have any way to find this out, so set it to nil
11847 and maybe the user would like to set it to t. */
11848 Vx_no_window_manager = Qnil;
11849
11850 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
11851 &Vx_pixel_size_width_font_regexp,
11852 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
11853
11854 Since Emacs gets width of a font matching with this regexp from
11855 PIXEL_SIZE field of the name, font finding mechanism gets faster for
11856 such a font. This is especially effective for such large fonts as
11857 Chinese, Japanese, and Korean. */);
11858 Vx_pixel_size_width_font_regexp = Qnil;
11859
11860 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
11861 doc: /* Time after which cached images are removed from the cache.
11862 When an image has not been displayed this many seconds, remove it
11863 from the image cache. Value must be an integer or nil with nil
11864 meaning don't clear the cache. */);
11865 Vimage_cache_eviction_delay = make_number (30 * 60);
11866
11867 #ifdef USE_X_TOOLKIT
11868 Fprovide (intern ("x-toolkit"), Qnil);
11869 #ifdef USE_MOTIF
11870 Fprovide (intern ("motif"), Qnil);
11871
11872 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
11873 doc: /* Version info for LessTif/Motif. */);
11874 Vmotif_version_string = build_string (XmVERSION_STRING);
11875 #endif /* USE_MOTIF */
11876 #endif /* USE_X_TOOLKIT */
11877
11878 defsubr (&Sx_get_resource);
11879
11880 /* X window properties. */
11881 defsubr (&Sx_change_window_property);
11882 defsubr (&Sx_delete_window_property);
11883 defsubr (&Sx_window_property);
11884
11885 defsubr (&Sxw_display_color_p);
11886 defsubr (&Sx_display_grayscale_p);
11887 defsubr (&Sxw_color_defined_p);
11888 defsubr (&Sxw_color_values);
11889 defsubr (&Sx_server_max_request_size);
11890 defsubr (&Sx_server_vendor);
11891 defsubr (&Sx_server_version);
11892 defsubr (&Sx_display_pixel_width);
11893 defsubr (&Sx_display_pixel_height);
11894 defsubr (&Sx_display_mm_width);
11895 defsubr (&Sx_display_mm_height);
11896 defsubr (&Sx_display_screens);
11897 defsubr (&Sx_display_planes);
11898 defsubr (&Sx_display_color_cells);
11899 defsubr (&Sx_display_visual_class);
11900 defsubr (&Sx_display_backing_store);
11901 defsubr (&Sx_display_save_under);
11902 defsubr (&Sx_parse_geometry);
11903 defsubr (&Sx_create_frame);
11904 defsubr (&Sx_open_connection);
11905 defsubr (&Sx_close_connection);
11906 defsubr (&Sx_display_list);
11907 defsubr (&Sx_synchronize);
11908 defsubr (&Sx_focus_frame);
11909 defsubr (&Sx_backspace_delete_keys_p);
11910
11911 /* Setting callback functions for fontset handler. */
11912 get_font_info_func = x_get_font_info;
11913
11914 #if 0 /* This function pointer doesn't seem to be used anywhere.
11915 And the pointer assigned has the wrong type, anyway. */
11916 list_fonts_func = x_list_fonts;
11917 #endif
11918
11919 load_font_func = x_load_font;
11920 find_ccl_program_func = x_find_ccl_program;
11921 query_font_func = x_query_font;
11922 set_frame_fontset_func = x_set_font;
11923 check_window_system_func = check_x;
11924
11925 /* Images. */
11926 Qxbm = intern ("xbm");
11927 staticpro (&Qxbm);
11928 QCtype = intern (":type");
11929 staticpro (&QCtype);
11930 QCconversion = intern (":conversion");
11931 staticpro (&QCconversion);
11932 QCheuristic_mask = intern (":heuristic-mask");
11933 staticpro (&QCheuristic_mask);
11934 QCcolor_symbols = intern (":color-symbols");
11935 staticpro (&QCcolor_symbols);
11936 QCascent = intern (":ascent");
11937 staticpro (&QCascent);
11938 QCmargin = intern (":margin");
11939 staticpro (&QCmargin);
11940 QCrelief = intern (":relief");
11941 staticpro (&QCrelief);
11942 Qpostscript = intern ("postscript");
11943 staticpro (&Qpostscript);
11944 QCloader = intern (":loader");
11945 staticpro (&QCloader);
11946 QCbounding_box = intern (":bounding-box");
11947 staticpro (&QCbounding_box);
11948 QCpt_width = intern (":pt-width");
11949 staticpro (&QCpt_width);
11950 QCpt_height = intern (":pt-height");
11951 staticpro (&QCpt_height);
11952 QCindex = intern (":index");
11953 staticpro (&QCindex);
11954 Qpbm = intern ("pbm");
11955 staticpro (&Qpbm);
11956
11957 #if HAVE_XPM
11958 Qxpm = intern ("xpm");
11959 staticpro (&Qxpm);
11960 #endif
11961
11962 #if HAVE_JPEG
11963 Qjpeg = intern ("jpeg");
11964 staticpro (&Qjpeg);
11965 #endif
11966
11967 #if HAVE_TIFF
11968 Qtiff = intern ("tiff");
11969 staticpro (&Qtiff);
11970 #endif
11971
11972 #if HAVE_GIF
11973 Qgif = intern ("gif");
11974 staticpro (&Qgif);
11975 #endif
11976
11977 #if HAVE_PNG
11978 Qpng = intern ("png");
11979 staticpro (&Qpng);
11980 #endif
11981
11982 defsubr (&Sclear_image_cache);
11983 defsubr (&Simage_size);
11984 defsubr (&Simage_mask_p);
11985
11986 hourglass_atimer = NULL;
11987 hourglass_shown_p = 0;
11988
11989 defsubr (&Sx_show_tip);
11990 defsubr (&Sx_hide_tip);
11991 tip_timer = Qnil;
11992 staticpro (&tip_timer);
11993 tip_frame = Qnil;
11994 staticpro (&tip_frame);
11995
11996 last_show_tip_args = Qnil;
11997 staticpro (&last_show_tip_args);
11998
11999 #ifdef USE_MOTIF
12000 defsubr (&Sx_file_dialog);
12001 #endif
12002 }
12003
12004
12005 void
12006 init_xfns ()
12007 {
12008 image_types = NULL;
12009 Vimage_types = Qnil;
12010
12011 define_image_type (&xbm_type);
12012 define_image_type (&gs_type);
12013 define_image_type (&pbm_type);
12014
12015 #if HAVE_XPM
12016 define_image_type (&xpm_type);
12017 #endif
12018
12019 #if HAVE_JPEG
12020 define_image_type (&jpeg_type);
12021 #endif
12022
12023 #if HAVE_TIFF
12024 define_image_type (&tiff_type);
12025 #endif
12026
12027 #if HAVE_GIF
12028 define_image_type (&gif_type);
12029 #endif
12030
12031 #if HAVE_PNG
12032 define_image_type (&png_type);
12033 #endif
12034 }
12035
12036 #endif /* HAVE_X_WINDOWS */