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