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