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