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