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