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