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