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