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