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