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