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