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