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