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