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