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