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