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