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