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