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