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