("german-prefix"): Fix typo in the docstring.
[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
231d6cfb
JD
3529 /* Set the WM leader property. GTK does this itself, so this is not
3530 needed when using GTK. */
3531 if (dpyinfo->client_leader_window != 0)
3532 {
3533 BLOCK_INPUT;
3534 XChangeProperty (FRAME_X_DISPLAY (f),
3535 FRAME_OUTER_WINDOW (f),
3536 dpyinfo->Xatom_wm_client_leader,
3537 XA_WINDOW, 32, PropModeReplace,
3538 (char *) &dpyinfo->client_leader_window, 1);
3539 UNBLOCK_INPUT;
3540 }
3541
495fa05e 3542 UNGCPRO;
9e57df62
GM
3543
3544 /* Make sure windows on this frame appear in calls to next-window
3545 and similar functions. */
3546 Vwindow_list = Qnil;
177c0ea7 3547
9ef48a9d 3548 return unbind_to (count, frame);
01f1ba30
JB
3549}
3550
eaf1eea9 3551
0d17d282
KH
3552/* FRAME is used only to get a handle on the X display. We don't pass the
3553 display info directly because we're called from frame.c, which doesn't
3554 know about that structure. */
e4f79258 3555
87498171 3556Lisp_Object
0d17d282
KH
3557x_get_focus_frame (frame)
3558 struct frame *frame;
87498171 3559{
0d17d282 3560 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (frame);
87498171 3561 Lisp_Object xfocus;
0d17d282 3562 if (! dpyinfo->x_focus_frame)
87498171
KH
3563 return Qnil;
3564
0d17d282 3565 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
87498171
KH
3566 return xfocus;
3567}
f0614854 3568
3decc1e7
GM
3569
3570/* In certain situations, when the window manager follows a
3571 click-to-focus policy, there seems to be no way around calling
3572 XSetInputFocus to give another frame the input focus .
3573
3574 In an ideal world, XSetInputFocus should generally be avoided so
3575 that applications don't interfere with the window manager's focus
3576 policy. But I think it's okay to use when it's clearly done
3577 following a user-command. */
3578
3579DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
7ee72033
MB
3580 doc: /* Set the input focus to FRAME.
3581FRAME nil means use the selected frame. */)
3582 (frame)
3decc1e7
GM
3583 Lisp_Object frame;
3584{
3585 struct frame *f = check_x_frame (frame);
3586 Display *dpy = FRAME_X_DISPLAY (f);
3587 int count;
3588
3589 BLOCK_INPUT;
3590 count = x_catch_errors (dpy);
3591 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3592 RevertToParent, CurrentTime);
3593 x_uncatch_errors (dpy, count);
3594 UNBLOCK_INPUT;
177c0ea7 3595
3decc1e7
GM
3596 return Qnil;
3597}
3598
f0614854 3599\f
2d764c78 3600DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7ee72033
MB
3601 doc: /* Internal function called by `color-defined-p', which see. */)
3602 (color, frame)
b9dc4443 3603 Lisp_Object color, frame;
e12d55b2 3604{
b9dc4443
RS
3605 XColor foo;
3606 FRAME_PTR f = check_x_frame (frame);
e12d55b2 3607
b7826503 3608 CHECK_STRING (color);
b9dc4443 3609
d5db4077 3610 if (x_defined_color (f, SDATA (color), &foo, 0))
e12d55b2
RS
3611 return Qt;
3612 else
3613 return Qnil;
3614}
3615
2d764c78 3616DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7ee72033
MB
3617 doc: /* Internal function called by `color-values', which see. */)
3618 (color, frame)
b9dc4443 3619 Lisp_Object color, frame;
01f1ba30 3620{
b9dc4443
RS
3621 XColor foo;
3622 FRAME_PTR f = check_x_frame (frame);
3623
b7826503 3624 CHECK_STRING (color);
01f1ba30 3625
d5db4077 3626 if (x_defined_color (f, SDATA (color), &foo, 0))
57c82a63
RS
3627 {
3628 Lisp_Object rgb[3];
3629
3630 rgb[0] = make_number (foo.red);
3631 rgb[1] = make_number (foo.green);
3632 rgb[2] = make_number (foo.blue);
3633 return Flist (3, rgb);
3634 }
01f1ba30
JB
3635 else
3636 return Qnil;
3637}
3638
2d764c78 3639DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7ee72033
MB
3640 doc: /* Internal function called by `display-color-p', which see. */)
3641 (display)
08a90d6a 3642 Lisp_Object display;
01f1ba30 3643{
08a90d6a 3644 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 3645
b9dc4443 3646 if (dpyinfo->n_planes <= 2)
01f1ba30
JB
3647 return Qnil;
3648
b9dc4443 3649 switch (dpyinfo->visual->class)
01f1ba30
JB
3650 {
3651 case StaticColor:
3652 case PseudoColor:
3653 case TrueColor:
3654 case DirectColor:
3655 return Qt;
3656
3657 default:
3658 return Qnil;
3659 }
3660}
3661
d0c9d219 3662DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
c061c855 3663 0, 1, 0,
7ee72033 3664 doc: /* Return t if the X display supports shades of gray.
c061c855
GM
3665Note that color displays do support shades of gray.
3666The optional argument DISPLAY specifies which display to ask about.
3667DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3668If omitted or nil, that stands for the selected frame's display. */)
3669 (display)
08a90d6a 3670 Lisp_Object display;
d0c9d219 3671{
08a90d6a 3672 struct x_display_info *dpyinfo = check_x_display_info (display);
d0c9d219 3673
ae6b58f9 3674 if (dpyinfo->n_planes <= 1)
b9dc4443
RS
3675 return Qnil;
3676
ae6b58f9
RS
3677 switch (dpyinfo->visual->class)
3678 {
3679 case StaticColor:
3680 case PseudoColor:
3681 case TrueColor:
3682 case DirectColor:
3683 case StaticGray:
3684 case GrayScale:
3685 return Qt;
3686
3687 default:
3688 return Qnil;
3689 }
d0c9d219
RS
3690}
3691
41beb8fc 3692DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
c061c855 3693 0, 1, 0,
7ee72033 3694 doc: /* Returns the width in pixels of the X display DISPLAY.
c061c855
GM
3695The optional argument DISPLAY specifies which display to ask about.
3696DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3697If omitted or nil, that stands for the selected frame's display. */)
3698 (display)
08a90d6a 3699 Lisp_Object display;
41beb8fc 3700{
08a90d6a 3701 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3702
3703 return make_number (dpyinfo->width);
41beb8fc
RS
3704}
3705
3706DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
c061c855 3707 Sx_display_pixel_height, 0, 1, 0,
7ee72033 3708 doc: /* Returns the height in pixels of the X display DISPLAY.
c061c855
GM
3709The optional argument DISPLAY specifies which display to ask about.
3710DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3711If omitted or nil, that stands for the selected frame's display. */)
3712 (display)
08a90d6a 3713 Lisp_Object display;
41beb8fc 3714{
08a90d6a 3715 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3716
3717 return make_number (dpyinfo->height);
41beb8fc
RS
3718}
3719
3720DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
c061c855 3721 0, 1, 0,
7ee72033 3722 doc: /* Returns the number of bitplanes of the X display DISPLAY.
c061c855
GM
3723The optional argument DISPLAY specifies which display to ask about.
3724DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3725If omitted or nil, that stands for the selected frame's display. */)
3726 (display)
08a90d6a 3727 Lisp_Object display;
41beb8fc 3728{
08a90d6a 3729 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3730
3731 return make_number (dpyinfo->n_planes);
41beb8fc
RS
3732}
3733
3734DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
c061c855 3735 0, 1, 0,
7ee72033 3736 doc: /* Returns the number of color cells of the X display DISPLAY.
c061c855
GM
3737The optional argument DISPLAY specifies which display to ask about.
3738DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3739If omitted or nil, that stands for the selected frame's display. */)
3740 (display)
08a90d6a 3741 Lisp_Object display;
41beb8fc 3742{
08a90d6a 3743 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3744
3745 return make_number (DisplayCells (dpyinfo->display,
3746 XScreenNumberOfScreen (dpyinfo->screen)));
41beb8fc
RS
3747}
3748
9d317b2c
RS
3749DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
3750 Sx_server_max_request_size,
c061c855 3751 0, 1, 0,
7ee72033 3752 doc: /* Returns the maximum request size 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;
9d317b2c 3758{
08a90d6a 3759 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3760
3761 return make_number (MAXREQUEST (dpyinfo->display));
9d317b2c
RS
3762}
3763
41beb8fc 3764DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7ee72033 3765 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
c061c855
GM
3766The optional argument DISPLAY specifies which display to ask about.
3767DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3768If omitted or nil, that stands for the selected frame's display. */)
3769 (display)
08a90d6a 3770 Lisp_Object display;
41beb8fc 3771{
08a90d6a 3772 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3773 char *vendor = ServerVendor (dpyinfo->display);
3774
41beb8fc
RS
3775 if (! vendor) vendor = "";
3776 return build_string (vendor);
3777}
3778
3779DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7ee72033 3780 doc: /* Returns the version numbers of the X server of display DISPLAY.
c061c855
GM
3781The value is a list of three integers: the major and minor
3782version numbers of the X Protocol in use, and the vendor-specific release
3783number. See also the function `x-server-vendor'.
3784
3785The optional argument DISPLAY specifies which display to ask about.
3786DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3787If omitted or nil, that stands for the selected frame's display. */)
3788 (display)
08a90d6a 3789 Lisp_Object display;
41beb8fc 3790{
08a90d6a 3791 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443 3792 Display *dpy = dpyinfo->display;
11ae94fe 3793
41beb8fc
RS
3794 return Fcons (make_number (ProtocolVersion (dpy)),
3795 Fcons (make_number (ProtocolRevision (dpy)),
3796 Fcons (make_number (VendorRelease (dpy)), Qnil)));
3797}
3798
3799DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7ee72033 3800 doc: /* Return the number of screens on the X server of 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 (ScreenCount (dpyinfo->display));
41beb8fc
RS
3810}
3811
3812DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7ee72033 3813 doc: /* Return the height 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 (HeightMMOfScreen (dpyinfo->screen));
41beb8fc
RS
3823}
3824
3825DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7ee72033 3826 doc: /* Return the width in millimeters of the X display DISPLAY.
c061c855
GM
3827The optional argument DISPLAY specifies which display to ask about.
3828DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3829If omitted or nil, that stands for the selected frame's display. */)
3830 (display)
08a90d6a 3831 Lisp_Object display;
41beb8fc 3832{
08a90d6a 3833 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
3834
3835 return make_number (WidthMMOfScreen (dpyinfo->screen));
41beb8fc
RS
3836}
3837
3838DEFUN ("x-display-backing-store", Fx_display_backing_store,
c061c855 3839 Sx_display_backing_store, 0, 1, 0,
7ee72033 3840 doc: /* Returns an indication of whether X display DISPLAY does backing store.
c061c855
GM
3841The value may be `always', `when-mapped', or `not-useful'.
3842The optional argument DISPLAY specifies which display to ask about.
3843DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3844If omitted or nil, that stands for the selected frame's display. */)
3845 (display)
08a90d6a 3846 Lisp_Object display;
41beb8fc 3847{
08a90d6a 3848 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 3849 Lisp_Object result;
11ae94fe 3850
b9dc4443 3851 switch (DoesBackingStore (dpyinfo->screen))
41beb8fc
RS
3852 {
3853 case Always:
8ec8a5ec
GM
3854 result = intern ("always");
3855 break;
41beb8fc
RS
3856
3857 case WhenMapped:
8ec8a5ec
GM
3858 result = intern ("when-mapped");
3859 break;
41beb8fc
RS
3860
3861 case NotUseful:
8ec8a5ec
GM
3862 result = intern ("not-useful");
3863 break;
41beb8fc
RS
3864
3865 default:
3866 error ("Strange value for BackingStore parameter of screen");
8ec8a5ec 3867 result = Qnil;
41beb8fc 3868 }
8ec8a5ec
GM
3869
3870 return result;
41beb8fc
RS
3871}
3872
3873DEFUN ("x-display-visual-class", Fx_display_visual_class,
c061c855 3874 Sx_display_visual_class, 0, 1, 0,
7ee72033 3875 doc: /* Return the visual class of the X display DISPLAY.
c061c855
GM
3876The value is one of the symbols `static-gray', `gray-scale',
3877`static-color', `pseudo-color', `true-color', or `direct-color'.
3878
3879The optional argument DISPLAY specifies which display to ask about.
3880DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3881If omitted or nil, that stands for the selected frame's display. */)
3882 (display)
08a90d6a 3883 Lisp_Object display;
41beb8fc 3884{
08a90d6a 3885 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 3886 Lisp_Object result;
11ae94fe 3887
b9dc4443 3888 switch (dpyinfo->visual->class)
41beb8fc 3889 {
8ec8a5ec
GM
3890 case StaticGray:
3891 result = intern ("static-gray");
3892 break;
3893 case GrayScale:
3894 result = intern ("gray-scale");
3895 break;
3896 case StaticColor:
3897 result = intern ("static-color");
3898 break;
3899 case PseudoColor:
3900 result = intern ("pseudo-color");
3901 break;
3902 case TrueColor:
3903 result = intern ("true-color");
3904 break;
3905 case DirectColor:
3906 result = intern ("direct-color");
3907 break;
41beb8fc
RS
3908 default:
3909 error ("Display has an unknown visual class");
8ec8a5ec 3910 result = Qnil;
41beb8fc 3911 }
177c0ea7 3912
8ec8a5ec 3913 return result;
41beb8fc
RS
3914}
3915
3916DEFUN ("x-display-save-under", Fx_display_save_under,
c061c855 3917 Sx_display_save_under, 0, 1, 0,
7ee72033 3918 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
c061c855
GM
3919The optional argument DISPLAY specifies which display to ask about.
3920DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
3921If omitted or nil, that stands for the selected frame's display. */)
3922 (display)
08a90d6a 3923 Lisp_Object display;
41beb8fc 3924{
08a90d6a 3925 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 3926
b9dc4443 3927 if (DoesSaveUnders (dpyinfo->screen) == True)
41beb8fc
RS
3928 return Qt;
3929 else
3930 return Qnil;
3931}
3932\f
b9dc4443 3933int
55caf99c
RS
3934x_pixel_width (f)
3935 register struct frame *f;
01f1ba30 3936{
be786000 3937 return FRAME_PIXEL_WIDTH (f);
01f1ba30
JB
3938}
3939
b9dc4443 3940int
55caf99c
RS
3941x_pixel_height (f)
3942 register struct frame *f;
01f1ba30 3943{
be786000 3944 return FRAME_PIXEL_HEIGHT (f);
55caf99c
RS
3945}
3946
b9dc4443 3947int
55caf99c
RS
3948x_char_width (f)
3949 register struct frame *f;
3950{
be786000 3951 return FRAME_COLUMN_WIDTH (f);
55caf99c
RS
3952}
3953
b9dc4443 3954int
55caf99c
RS
3955x_char_height (f)
3956 register struct frame *f;
3957{
be786000 3958 return FRAME_LINE_HEIGHT (f);
01f1ba30 3959}
b9dc4443
RS
3960
3961int
f03f2489
RS
3962x_screen_planes (f)
3963 register struct frame *f;
b9dc4443 3964{
f03f2489 3965 return FRAME_X_DISPLAY_INFO (f)->n_planes;
b9dc4443 3966}
01f1ba30 3967
a6ad00c0
GM
3968
3969\f
3970/************************************************************************
3971 X Displays
3972 ************************************************************************/
3973
01f1ba30 3974\f
a6ad00c0
GM
3975/* Mapping visual names to visuals. */
3976
3977static struct visual_class
3978{
3979 char *name;
3980 int class;
3981}
3982visual_classes[] =
3983{
3984 {"StaticGray", StaticGray},
3985 {"GrayScale", GrayScale},
3986 {"StaticColor", StaticColor},
3987 {"PseudoColor", PseudoColor},
3988 {"TrueColor", TrueColor},
3989 {"DirectColor", DirectColor},
9908a324 3990 {NULL, 0}
a6ad00c0
GM
3991};
3992
3993
404daac1 3994#ifndef HAVE_XSCREENNUMBEROFSCREEN
a6ad00c0
GM
3995
3996/* Value is the screen number of screen SCR. This is a substitute for
3997 the X function with the same name when that doesn't exist. */
3998
404daac1
RS
3999int
4000XScreenNumberOfScreen (scr)
4001 register Screen *scr;
4002{
a6ad00c0
GM
4003 Display *dpy = scr->display;
4004 int i;
3df34fdb 4005
a6ad00c0 4006 for (i = 0; i < dpy->nscreens; ++i)
fbd5ceb2 4007 if (scr == dpy->screens + i)
a6ad00c0 4008 break;
404daac1 4009
a6ad00c0 4010 return i;
404daac1 4011}
a6ad00c0 4012
404daac1
RS
4013#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
4014
01f1ba30 4015
a6ad00c0
GM
4016/* Select the visual that should be used on display DPYINFO. Set
4017 members of DPYINFO appropriately. Called from x_term_init. */
fe24a618 4018
a6ad00c0
GM
4019void
4020select_visual (dpyinfo)
4021 struct x_display_info *dpyinfo;
4022{
4023 Display *dpy = dpyinfo->display;
4024 Screen *screen = dpyinfo->screen;
4025 Lisp_Object value;
fe24a618 4026
a6ad00c0
GM
4027 /* See if a visual is specified. */
4028 value = display_x_get_resource (dpyinfo,
4029 build_string ("visualClass"),
4030 build_string ("VisualClass"),
4031 Qnil, Qnil);
4032 if (STRINGP (value))
4033 {
4034 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
4035 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
4036 depth, a decimal number. NAME is compared with case ignored. */
d5db4077 4037 char *s = (char *) alloca (SBYTES (value) + 1);
a6ad00c0
GM
4038 char *dash;
4039 int i, class = -1;
4040 XVisualInfo vinfo;
4041
d5db4077 4042 strcpy (s, SDATA (value));
a6ad00c0
GM
4043 dash = index (s, '-');
4044 if (dash)
4045 {
4046 dpyinfo->n_planes = atoi (dash + 1);
4047 *dash = '\0';
4048 }
4049 else
4050 /* We won't find a matching visual with depth 0, so that
4051 an error will be printed below. */
4052 dpyinfo->n_planes = 0;
f0614854 4053
a6ad00c0
GM
4054 /* Determine the visual class. */
4055 for (i = 0; visual_classes[i].name; ++i)
4056 if (xstricmp (s, visual_classes[i].name) == 0)
4057 {
4058 class = visual_classes[i].class;
4059 break;
4060 }
01f1ba30 4061
a6ad00c0
GM
4062 /* Look up a matching visual for the specified class. */
4063 if (class == -1
4064 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
4065 dpyinfo->n_planes, class, &vinfo))
d5db4077 4066 fatal ("Invalid visual specification `%s'", SDATA (value));
177c0ea7 4067
a6ad00c0
GM
4068 dpyinfo->visual = vinfo.visual;
4069 }
01f1ba30
JB
4070 else
4071 {
a6ad00c0
GM
4072 int n_visuals;
4073 XVisualInfo *vinfo, vinfo_template;
177c0ea7 4074
a6ad00c0
GM
4075 dpyinfo->visual = DefaultVisualOfScreen (screen);
4076
4077#ifdef HAVE_X11R4
4078 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
4079#else
4080 vinfo_template.visualid = dpyinfo->visual->visualid;
4081#endif
4082 vinfo_template.screen = XScreenNumberOfScreen (screen);
4083 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
4084 &vinfo_template, &n_visuals);
4085 if (n_visuals != 1)
4086 fatal ("Can't get proper X visual info");
4087
94ac875b 4088 dpyinfo->n_planes = vinfo->depth;
a6ad00c0
GM
4089 XFree ((char *) vinfo);
4090 }
01f1ba30 4091}
01f1ba30 4092
a6ad00c0 4093
b9dc4443
RS
4094/* Return the X display structure for the display named NAME.
4095 Open a new connection if necessary. */
4096
4097struct x_display_info *
4098x_display_info_for_name (name)
4099 Lisp_Object name;
4100{
08a90d6a 4101 Lisp_Object names;
b9dc4443
RS
4102 struct x_display_info *dpyinfo;
4103
b7826503 4104 CHECK_STRING (name);
b9dc4443 4105
806048df
RS
4106 if (! EQ (Vwindow_system, intern ("x")))
4107 error ("Not using X Windows");
4108
08a90d6a
RS
4109 for (dpyinfo = x_display_list, names = x_display_name_list;
4110 dpyinfo;
8e713be6 4111 dpyinfo = dpyinfo->next, names = XCDR (names))
b9dc4443
RS
4112 {
4113 Lisp_Object tem;
8e713be6 4114 tem = Fstring_equal (XCAR (XCAR (names)), name);
08a90d6a 4115 if (!NILP (tem))
b9dc4443
RS
4116 return dpyinfo;
4117 }
4118
b7975ee4
KH
4119 /* Use this general default value to start with. */
4120 Vx_resource_name = Vinvocation_name;
4121
b9dc4443
RS
4122 validate_x_resource_name ();
4123
9b207e8e 4124 dpyinfo = x_term_init (name, (char *)0,
d5db4077 4125 (char *) SDATA (Vx_resource_name));
b9dc4443 4126
08a90d6a 4127 if (dpyinfo == 0)
d5db4077 4128 error ("Cannot connect to X server %s", SDATA (name));
08a90d6a 4129
b9dc4443
RS
4130 x_in_use = 1;
4131 XSETFASTINT (Vwindow_system_version, 11);
4132
4133 return dpyinfo;
4134}
4135
a6ad00c0 4136
01f1ba30 4137DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
c061c855 4138 1, 3, 0,
7ee72033 4139 doc: /* Open a connection to an X server.
c061c855
GM
4140DISPLAY is the name of the display to connect to.
4141Optional second arg XRM-STRING is a string of resources in xrdb format.
4142If the optional third arg MUST-SUCCEED is non-nil,
7ee72033
MB
4143terminate Emacs if we can't open the connection. */)
4144 (display, xrm_string, must_succeed)
08a90d6a 4145 Lisp_Object display, xrm_string, must_succeed;
01f1ba30 4146{
01f1ba30 4147 unsigned char *xrm_option;
b9dc4443 4148 struct x_display_info *dpyinfo;
01f1ba30 4149
b7826503 4150 CHECK_STRING (display);
d387c960 4151 if (! NILP (xrm_string))
b7826503 4152 CHECK_STRING (xrm_string);
01f1ba30 4153
806048df
RS
4154 if (! EQ (Vwindow_system, intern ("x")))
4155 error ("Not using X Windows");
4156
d387c960 4157 if (! NILP (xrm_string))
d5db4077 4158 xrm_option = (unsigned char *) SDATA (xrm_string);
01f1ba30
JB
4159 else
4160 xrm_option = (unsigned char *) 0;
d387c960
JB
4161
4162 validate_x_resource_name ();
4163
e1b1bee8 4164 /* This is what opens the connection and sets x_current_display.
b9dc4443
RS
4165 This also initializes many symbols, such as those used for input. */
4166 dpyinfo = x_term_init (display, xrm_option,
d5db4077 4167 (char *) SDATA (Vx_resource_name));
f1c16f36 4168
08a90d6a
RS
4169 if (dpyinfo == 0)
4170 {
4171 if (!NILP (must_succeed))
10ffbc14
GM
4172 fatal ("Cannot connect to X server %s.\n\
4173Check the DISPLAY environment variable or use `-d'.\n\
842a9389
JB
4174Also use the `xauth' program to verify that you have the proper\n\
4175authorization information needed to connect the X server.\n\
bf770132 4176An insecure way to solve the problem may be to use `xhost'.\n",
d5db4077 4177 SDATA (display));
08a90d6a 4178 else
d5db4077 4179 error ("Cannot connect to X server %s", SDATA (display));
08a90d6a
RS
4180 }
4181
b9dc4443 4182 x_in_use = 1;
01f1ba30 4183
b9dc4443 4184 XSETFASTINT (Vwindow_system_version, 11);
01f1ba30
JB
4185 return Qnil;
4186}
4187
08a90d6a
RS
4188DEFUN ("x-close-connection", Fx_close_connection,
4189 Sx_close_connection, 1, 1, 0,
7ee72033 4190 doc: /* Close the connection to DISPLAY's X server.
c061c855 4191For DISPLAY, specify either a frame or a display name (a string).
7ee72033
MB
4192If DISPLAY is nil, that stands for the selected frame's display. */)
4193 (display)
c061c855 4194 Lisp_Object display;
01f1ba30 4195{
08a90d6a 4196 struct x_display_info *dpyinfo = check_x_display_info (display);
08a90d6a 4197 int i;
3457bc6e 4198
08a90d6a
RS
4199 if (dpyinfo->reference_count > 0)
4200 error ("Display still has frames on it");
01f1ba30 4201
08a90d6a
RS
4202 BLOCK_INPUT;
4203 /* Free the fonts in the font table. */
4204 for (i = 0; i < dpyinfo->n_fonts; i++)
333b20bb
GM
4205 if (dpyinfo->font_table[i].name)
4206 {
6ecb43ce
KH
4207 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
4208 xfree (dpyinfo->font_table[i].full_name);
333b20bb 4209 xfree (dpyinfo->font_table[i].name);
333b20bb
GM
4210 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
4211 }
4212
08a90d6a
RS
4213 x_destroy_all_bitmaps (dpyinfo);
4214 XSetCloseDownMode (dpyinfo->display, DestroyAll);
82c90203
RS
4215
4216#ifdef USE_X_TOOLKIT
4217 XtCloseDisplay (dpyinfo->display);
4218#else
08a90d6a 4219 XCloseDisplay (dpyinfo->display);
82c90203 4220#endif
08a90d6a
RS
4221
4222 x_delete_display (dpyinfo);
4223 UNBLOCK_INPUT;
3457bc6e 4224
01f1ba30
JB
4225 return Qnil;
4226}
4227
08a90d6a 4228DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7ee72033
MB
4229 doc: /* Return the list of display names that Emacs has connections to. */)
4230 ()
08a90d6a
RS
4231{
4232 Lisp_Object tail, result;
4233
4234 result = Qnil;
8e713be6
KR
4235 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
4236 result = Fcons (XCAR (XCAR (tail)), result);
08a90d6a
RS
4237
4238 return result;
4239}
4240
4241DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7ee72033 4242 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
c061c855
GM
4243If ON is nil, allow buffering of requests.
4244Turning on synchronization prohibits the Xlib routines from buffering
4245requests and seriously degrades performance, but makes debugging much
4246easier.
4247The optional second argument DISPLAY specifies which display to act on.
4248DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4249If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
4250 (on, display)
08a90d6a 4251 Lisp_Object display, on;
01f1ba30 4252{
08a90d6a 4253 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 4254
b9dc4443 4255 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
01f1ba30
JB
4256
4257 return Qnil;
4258}
4259
b9dc4443 4260/* Wait for responses to all X commands issued so far for frame F. */
6b7b1820
RS
4261
4262void
b9dc4443
RS
4263x_sync (f)
4264 FRAME_PTR f;
6b7b1820 4265{
4e87f4d2 4266 BLOCK_INPUT;
b9dc4443 4267 XSync (FRAME_X_DISPLAY (f), False);
4e87f4d2 4268 UNBLOCK_INPUT;
6b7b1820 4269}
333b20bb 4270
01f1ba30 4271\f
333b20bb
GM
4272/***********************************************************************
4273 Image types
4274 ***********************************************************************/
f1c16f36 4275
333b20bb
GM
4276/* Value is the number of elements of vector VECTOR. */
4277
4278#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
4279
4280/* List of supported image types. Use define_image_type to add new
4281 types. Use lookup_image_type to find a type for a given symbol. */
4282
4283static struct image_type *image_types;
4284
333b20bb
GM
4285/* The symbol `image' which is the car of the lists used to represent
4286 images in Lisp. */
4287
4288extern Lisp_Object Qimage;
4289
4290/* The symbol `xbm' which is used as the type symbol for XBM images. */
4291
4292Lisp_Object Qxbm;
4293
4294/* Keywords. */
4295
0fe92f72 4296extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
4297extern Lisp_Object QCdata, QCtype;
4298Lisp_Object QCascent, QCmargin, QCrelief;
d2dc8167 4299Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4a8e312c 4300Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
333b20bb
GM
4301
4302/* Other symbols. */
4303
4a8e312c 4304Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
333b20bb
GM
4305
4306/* Time in seconds after which images should be removed from the cache
4307 if not displayed. */
4308
fcf431dc 4309Lisp_Object Vimage_cache_eviction_delay;
333b20bb
GM
4310
4311/* Function prototypes. */
4312
4313static void define_image_type P_ ((struct image_type *type));
4314static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
4315static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
4316static void x_laplace P_ ((struct frame *, struct image *));
4a8e312c 4317static void x_emboss P_ ((struct frame *, struct image *));
45158a91
GM
4318static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
4319 Lisp_Object));
333b20bb
GM
4320
4321
4322/* Define a new image type from TYPE. This adds a copy of TYPE to
4323 image_types and adds the symbol *TYPE->type to Vimage_types. */
4324
4325static void
4326define_image_type (type)
4327 struct image_type *type;
4328{
4329 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
4330 The initialized data segment is read-only. */
4331 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
4332 bcopy (type, p, sizeof *p);
4333 p->next = image_types;
4334 image_types = p;
4335 Vimage_types = Fcons (*p->type, Vimage_types);
4336}
4337
4338
4339/* Look up image type SYMBOL, and return a pointer to its image_type
4340 structure. Value is null if SYMBOL is not a known image type. */
4341
4342static INLINE struct image_type *
4343lookup_image_type (symbol)
4344 Lisp_Object symbol;
4345{
4346 struct image_type *type;
4347
4348 for (type = image_types; type; type = type->next)
4349 if (EQ (symbol, *type->type))
4350 break;
4351
4352 return type;
4353}
4354
4355
4356/* Value is non-zero if OBJECT is a valid Lisp image specification. A
4357 valid image specification is a list whose car is the symbol
4358 `image', and whose rest is a property list. The property list must
4359 contain a value for key `:type'. That value must be the name of a
4360 supported image type. The rest of the property list depends on the
4361 image type. */
4362
4363int
4364valid_image_p (object)
4365 Lisp_Object object;
4366{
4367 int valid_p = 0;
177c0ea7 4368
333b20bb
GM
4369 if (CONSP (object) && EQ (XCAR (object), Qimage))
4370 {
1783ffa2
GM
4371 Lisp_Object tem;
4372
4373 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
4374 if (EQ (XCAR (tem), QCtype))
4375 {
4376 tem = XCDR (tem);
4377 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
4378 {
4379 struct image_type *type;
4380 type = lookup_image_type (XCAR (tem));
4381 if (type)
4382 valid_p = type->valid_p (object);
4383 }
177c0ea7 4384
1783ffa2
GM
4385 break;
4386 }
333b20bb
GM
4387 }
4388
4389 return valid_p;
4390}
4391
4392
7ab1745f
GM
4393/* Log error message with format string FORMAT and argument ARG.
4394 Signaling an error, e.g. when an image cannot be loaded, is not a
4395 good idea because this would interrupt redisplay, and the error
4396 message display would lead to another redisplay. This function
4397 therefore simply displays a message. */
333b20bb
GM
4398
4399static void
4400image_error (format, arg1, arg2)
4401 char *format;
4402 Lisp_Object arg1, arg2;
4403{
7ab1745f 4404 add_to_log (format, arg1, arg2);
333b20bb
GM
4405}
4406
4407
4408\f
4409/***********************************************************************
4410 Image specifications
4411 ***********************************************************************/
4412
4413enum image_value_type
4414{
4415 IMAGE_DONT_CHECK_VALUE_TYPE,
4416 IMAGE_STRING_VALUE,
6f1be3b9 4417 IMAGE_STRING_OR_NIL_VALUE,
333b20bb
GM
4418 IMAGE_SYMBOL_VALUE,
4419 IMAGE_POSITIVE_INTEGER_VALUE,
3ed61e75 4420 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
333b20bb 4421 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7c7ff7f5 4422 IMAGE_ASCENT_VALUE,
333b20bb
GM
4423 IMAGE_INTEGER_VALUE,
4424 IMAGE_FUNCTION_VALUE,
4425 IMAGE_NUMBER_VALUE,
4426 IMAGE_BOOL_VALUE
4427};
4428
4429/* Structure used when parsing image specifications. */
4430
4431struct image_keyword
4432{
4433 /* Name of keyword. */
4434 char *name;
4435
4436 /* The type of value allowed. */
4437 enum image_value_type type;
4438
4439 /* Non-zero means key must be present. */
4440 int mandatory_p;
4441
4442 /* Used to recognize duplicate keywords in a property list. */
4443 int count;
4444
4445 /* The value that was found. */
4446 Lisp_Object value;
4447};
4448
4449
bfd2209f
GM
4450static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
4451 int, Lisp_Object));
333b20bb
GM
4452static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
4453
4454
4455/* Parse image spec SPEC according to KEYWORDS. A valid image spec
4456 has the format (image KEYWORD VALUE ...). One of the keyword/
4457 value pairs must be `:type TYPE'. KEYWORDS is a vector of
4458 image_keywords structures of size NKEYWORDS describing other
bfd2209f 4459 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
333b20bb
GM
4460
4461static int
bfd2209f 4462parse_image_spec (spec, keywords, nkeywords, type)
333b20bb
GM
4463 Lisp_Object spec;
4464 struct image_keyword *keywords;
4465 int nkeywords;
4466 Lisp_Object type;
333b20bb
GM
4467{
4468 int i;
4469 Lisp_Object plist;
4470
4471 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
4472 return 0;
4473
4474 plist = XCDR (spec);
4475 while (CONSP (plist))
4476 {
4477 Lisp_Object key, value;
4478
4479 /* First element of a pair must be a symbol. */
4480 key = XCAR (plist);
4481 plist = XCDR (plist);
4482 if (!SYMBOLP (key))
4483 return 0;
4484
4485 /* There must follow a value. */
4486 if (!CONSP (plist))
4487 return 0;
4488 value = XCAR (plist);
4489 plist = XCDR (plist);
4490
4491 /* Find key in KEYWORDS. Error if not found. */
4492 for (i = 0; i < nkeywords; ++i)
d5db4077 4493 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
333b20bb
GM
4494 break;
4495
4496 if (i == nkeywords)
bfd2209f 4497 continue;
333b20bb
GM
4498
4499 /* Record that we recognized the keyword. If a keywords
4500 was found more than once, it's an error. */
4501 keywords[i].value = value;
4502 ++keywords[i].count;
177c0ea7 4503
333b20bb
GM
4504 if (keywords[i].count > 1)
4505 return 0;
4506
4507 /* Check type of value against allowed type. */
4508 switch (keywords[i].type)
4509 {
4510 case IMAGE_STRING_VALUE:
4511 if (!STRINGP (value))
4512 return 0;
4513 break;
4514
6f1be3b9
GM
4515 case IMAGE_STRING_OR_NIL_VALUE:
4516 if (!STRINGP (value) && !NILP (value))
4517 return 0;
4518 break;
4519
333b20bb
GM
4520 case IMAGE_SYMBOL_VALUE:
4521 if (!SYMBOLP (value))
4522 return 0;
4523 break;
4524
4525 case IMAGE_POSITIVE_INTEGER_VALUE:
4526 if (!INTEGERP (value) || XINT (value) <= 0)
4527 return 0;
4528 break;
4529
3ed61e75
GM
4530 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
4531 if (INTEGERP (value) && XINT (value) >= 0)
4532 break;
4533 if (CONSP (value)
4534 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
4535 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
4536 break;
4537 return 0;
4538
7c7ff7f5
GM
4539 case IMAGE_ASCENT_VALUE:
4540 if (SYMBOLP (value) && EQ (value, Qcenter))
4541 break;
4542 else if (INTEGERP (value)
4543 && XINT (value) >= 0
4544 && XINT (value) <= 100)
4545 break;
4546 return 0;
177c0ea7 4547
333b20bb
GM
4548 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
4549 if (!INTEGERP (value) || XINT (value) < 0)
4550 return 0;
4551 break;
4552
4553 case IMAGE_DONT_CHECK_VALUE_TYPE:
4554 break;
4555
4556 case IMAGE_FUNCTION_VALUE:
4557 value = indirect_function (value);
177c0ea7 4558 if (SUBRP (value)
333b20bb
GM
4559 || COMPILEDP (value)
4560 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
4561 break;
4562 return 0;
4563
4564 case IMAGE_NUMBER_VALUE:
4565 if (!INTEGERP (value) && !FLOATP (value))
4566 return 0;
4567 break;
4568
4569 case IMAGE_INTEGER_VALUE:
4570 if (!INTEGERP (value))
4571 return 0;
4572 break;
4573
4574 case IMAGE_BOOL_VALUE:
4575 if (!NILP (value) && !EQ (value, Qt))
4576 return 0;
4577 break;
4578
4579 default:
4580 abort ();
4581 break;
4582 }
4583
4584 if (EQ (key, QCtype) && !EQ (type, value))
4585 return 0;
4586 }
4587
4588 /* Check that all mandatory fields are present. */
4589 for (i = 0; i < nkeywords; ++i)
4590 if (keywords[i].mandatory_p && keywords[i].count == 0)
4591 return 0;
4592
4593 return NILP (plist);
4594}
4595
4596
4597/* Return the value of KEY in image specification SPEC. Value is nil
4598 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
4599 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
4600
4601static Lisp_Object
4602image_spec_value (spec, key, found)
4603 Lisp_Object spec, key;
4604 int *found;
4605{
4606 Lisp_Object tail;
177c0ea7 4607
333b20bb
GM
4608 xassert (valid_image_p (spec));
4609
4610 for (tail = XCDR (spec);
4611 CONSP (tail) && CONSP (XCDR (tail));
4612 tail = XCDR (XCDR (tail)))
4613 {
4614 if (EQ (XCAR (tail), key))
4615 {
4616 if (found)
4617 *found = 1;
4618 return XCAR (XCDR (tail));
4619 }
4620 }
177c0ea7 4621
333b20bb
GM
4622 if (found)
4623 *found = 0;
4624 return Qnil;
4625}
177c0ea7 4626
333b20bb 4627
42677916 4628DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
7ee72033 4629 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
c061c855
GM
4630PIXELS non-nil means return the size in pixels, otherwise return the
4631size in canonical character units.
4632FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
4633or omitted means use the selected frame. */)
4634 (spec, pixels, frame)
42677916
GM
4635 Lisp_Object spec, pixels, frame;
4636{
4637 Lisp_Object size;
4638
4639 size = Qnil;
4640 if (valid_image_p (spec))
4641 {
4642 struct frame *f = check_x_frame (frame);
83676598 4643 int id = lookup_image (f, spec);
42677916 4644 struct image *img = IMAGE_FROM_ID (f, id);
3ed61e75
GM
4645 int width = img->width + 2 * img->hmargin;
4646 int height = img->height + 2 * img->vmargin;
177c0ea7 4647
42677916 4648 if (NILP (pixels))
be786000
KS
4649 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
4650 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
42677916
GM
4651 else
4652 size = Fcons (make_number (width), make_number (height));
4653 }
4654 else
4655 error ("Invalid image specification");
4656
4657 return size;
4658}
4659
333b20bb 4660
b243755a 4661DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
7ee72033 4662 doc: /* Return t if image SPEC has a mask bitmap.
c061c855 4663FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
4664or omitted means use the selected frame. */)
4665 (spec, frame)
b243755a
GM
4666 Lisp_Object spec, frame;
4667{
4668 Lisp_Object mask;
4669
4670 mask = Qnil;
4671 if (valid_image_p (spec))
4672 {
4673 struct frame *f = check_x_frame (frame);
83676598 4674 int id = lookup_image (f, spec);
b243755a
GM
4675 struct image *img = IMAGE_FROM_ID (f, id);
4676 if (img->mask)
4677 mask = Qt;
4678 }
4679 else
4680 error ("Invalid image specification");
4681
4682 return mask;
4683}
4684
4685
333b20bb
GM
4686\f
4687/***********************************************************************
4688 Image type independent image structures
4689 ***********************************************************************/
4690
4691static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
4692static void free_image P_ ((struct frame *f, struct image *img));
4693
4694
4695/* Allocate and return a new image structure for image specification
4696 SPEC. SPEC has a hash value of HASH. */
4697
4698static struct image *
4699make_image (spec, hash)
4700 Lisp_Object spec;
4701 unsigned hash;
4702{
4703 struct image *img = (struct image *) xmalloc (sizeof *img);
177c0ea7 4704
333b20bb
GM
4705 xassert (valid_image_p (spec));
4706 bzero (img, sizeof *img);
4707 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
4708 xassert (img->type != NULL);
4709 img->spec = spec;
4710 img->data.lisp_val = Qnil;
4711 img->ascent = DEFAULT_IMAGE_ASCENT;
4712 img->hash = hash;
4713 return img;
4714}
4715
4716
4717/* Free image IMG which was used on frame F, including its resources. */
4718
4719static void
4720free_image (f, img)
4721 struct frame *f;
4722 struct image *img;
4723{
4724 if (img)
4725 {
4726 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4727
4728 /* Remove IMG from the hash table of its cache. */
4729 if (img->prev)
4730 img->prev->next = img->next;
4731 else
4732 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
4733
4734 if (img->next)
4735 img->next->prev = img->prev;
4736
4737 c->images[img->id] = NULL;
4738
4739 /* Free resources, then free IMG. */
4740 img->type->free (f, img);
4741 xfree (img);
4742 }
4743}
4744
4745
4746/* Prepare image IMG for display on frame F. Must be called before
4747 drawing an image. */
4748
4749void
4750prepare_image_for_display (f, img)
4751 struct frame *f;
4752 struct image *img;
4753{
4754 EMACS_TIME t;
4755
4756 /* We're about to display IMG, so set its timestamp to `now'. */
4757 EMACS_GET_TIME (t);
4758 img->timestamp = EMACS_SECS (t);
4759
4760 /* If IMG doesn't have a pixmap yet, load it now, using the image
4761 type dependent loader function. */
dd00328a 4762 if (img->pixmap == None && !img->load_failed_p)
209061be 4763 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb 4764}
177c0ea7 4765
333b20bb 4766
7c7ff7f5
GM
4767/* Value is the number of pixels for the ascent of image IMG when
4768 drawn in face FACE. */
4769
4770int
4771image_ascent (img, face)
4772 struct image *img;
4773 struct face *face;
4774{
3ed61e75 4775 int height = img->height + img->vmargin;
7c7ff7f5
GM
4776 int ascent;
4777
4778 if (img->ascent == CENTERED_IMAGE_ASCENT)
4779 {
4780 if (face->font)
3694cb3f
MB
4781 /* This expression is arranged so that if the image can't be
4782 exactly centered, it will be moved slightly up. This is
4783 because a typical font is `top-heavy' (due to the presence
4784 uppercase letters), so the image placement should err towards
4785 being top-heavy too. It also just generally looks better. */
4786 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
7c7ff7f5
GM
4787 else
4788 ascent = height / 2;
4789 }
4790 else
4791 ascent = height * img->ascent / 100.0;
4792
4793 return ascent;
4794}
4795
f20a3b7a
MB
4796\f
4797/* Image background colors. */
4798
4799static unsigned long
4800four_corners_best (ximg, width, height)
4801 XImage *ximg;
4802 unsigned long width, height;
4803{
b350c2e5
GM
4804 unsigned long corners[4], best;
4805 int i, best_count;
f20a3b7a 4806
b350c2e5
GM
4807 /* Get the colors at the corners of ximg. */
4808 corners[0] = XGetPixel (ximg, 0, 0);
4809 corners[1] = XGetPixel (ximg, width - 1, 0);
4810 corners[2] = XGetPixel (ximg, width - 1, height - 1);
4811 corners[3] = XGetPixel (ximg, 0, height - 1);
f20a3b7a 4812
b350c2e5
GM
4813 /* Choose the most frequently found color as background. */
4814 for (i = best_count = 0; i < 4; ++i)
4815 {
4816 int j, n;
177c0ea7 4817
b350c2e5
GM
4818 for (j = n = 0; j < 4; ++j)
4819 if (corners[i] == corners[j])
4820 ++n;
f20a3b7a 4821
b350c2e5
GM
4822 if (n > best_count)
4823 best = corners[i], best_count = n;
4824 }
f20a3b7a 4825
b350c2e5 4826 return best;
f20a3b7a
MB
4827}
4828
4829/* Return the `background' field of IMG. If IMG doesn't have one yet,
4830 it is guessed heuristically. If non-zero, XIMG is an existing XImage
4831 object to use for the heuristic. */
4832
4833unsigned long
4834image_background (img, f, ximg)
4835 struct image *img;
4836 struct frame *f;
4837 XImage *ximg;
4838{
4839 if (! img->background_valid)
4840 /* IMG doesn't have a background yet, try to guess a reasonable value. */
4841 {
4842 int free_ximg = !ximg;
4843
4844 if (! ximg)
4845 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4846 0, 0, img->width, img->height, ~0, ZPixmap);
4847
4848 img->background = four_corners_best (ximg, img->width, img->height);
4849
4850 if (free_ximg)
4851 XDestroyImage (ximg);
4852
4853 img->background_valid = 1;
4854 }
4855
4856 return img->background;
4857}
4858
4859/* Return the `background_transparent' field of IMG. If IMG doesn't
4860 have one yet, it is guessed heuristically. If non-zero, MASK is an
4861 existing XImage object to use for the heuristic. */
4862
4863int
4864image_background_transparent (img, f, mask)
4865 struct image *img;
4866 struct frame *f;
4867 XImage *mask;
4868{
4869 if (! img->background_transparent_valid)
4870 /* IMG doesn't have a background yet, try to guess a reasonable value. */
4871 {
4872 if (img->mask)
4873 {
4874 int free_mask = !mask;
4875
4876 if (! mask)
4877 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
4878 0, 0, img->width, img->height, ~0, ZPixmap);
4879
4880 img->background_transparent
4881 = !four_corners_best (mask, img->width, img->height);
4882
4883 if (free_mask)
4884 XDestroyImage (mask);
4885 }
4886 else
4887 img->background_transparent = 0;
4888
4889 img->background_transparent_valid = 1;
4890 }
4891
4892 return img->background_transparent;
4893}
7c7ff7f5 4894
333b20bb
GM
4895\f
4896/***********************************************************************
4897 Helper functions for X image types
4898 ***********************************************************************/
4899
dd00328a
GM
4900static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
4901 int, int));
333b20bb
GM
4902static void x_clear_image P_ ((struct frame *f, struct image *img));
4903static unsigned long x_alloc_image_color P_ ((struct frame *f,
4904 struct image *img,
4905 Lisp_Object color_name,
4906 unsigned long dflt));
4907
dd00328a
GM
4908
4909/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
4910 free the pixmap if any. MASK_P non-zero means clear the mask
4911 pixmap if any. COLORS_P non-zero means free colors allocated for
4912 the image, if any. */
333b20bb
GM
4913
4914static void
dd00328a 4915x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
333b20bb
GM
4916 struct frame *f;
4917 struct image *img;
dd00328a 4918 int pixmap_p, mask_p, colors_p;
333b20bb 4919{
dd00328a 4920 if (pixmap_p && img->pixmap)
333b20bb 4921 {
333b20bb 4922 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 4923 img->pixmap = None;
f20a3b7a 4924 img->background_valid = 0;
f4779de9
GM
4925 }
4926
dd00328a 4927 if (mask_p && img->mask)
f4779de9
GM
4928 {
4929 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 4930 img->mask = None;
f20a3b7a 4931 img->background_transparent_valid = 0;
333b20bb 4932 }
177c0ea7 4933
dd00328a 4934 if (colors_p && img->ncolors)
333b20bb 4935 {
462d5d40 4936 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
4937 xfree (img->colors);
4938 img->colors = NULL;
4939 img->ncolors = 0;
4940 }
dd00328a
GM
4941}
4942
4943/* Free X resources of image IMG which is used on frame F. */
4944
4945static void
4946x_clear_image (f, img)
4947 struct frame *f;
4948 struct image *img;
4949{
4950 BLOCK_INPUT;
4951 x_clear_image_1 (f, img, 1, 1, 1);
f4779de9 4952 UNBLOCK_INPUT;
333b20bb
GM
4953}
4954
4955
4956/* Allocate color COLOR_NAME for image IMG on frame F. If color
4957 cannot be allocated, use DFLT. Add a newly allocated color to
4958 IMG->colors, so that it can be freed again. Value is the pixel
4959 color. */
4960
4961static unsigned long
4962x_alloc_image_color (f, img, color_name, dflt)
4963 struct frame *f;
4964 struct image *img;
4965 Lisp_Object color_name;
4966 unsigned long dflt;
4967{
4968 XColor color;
4969 unsigned long result;
4970
4971 xassert (STRINGP (color_name));
4972
d5db4077 4973 if (x_defined_color (f, SDATA (color_name), &color, 1))
333b20bb
GM
4974 {
4975 /* This isn't called frequently so we get away with simply
4976 reallocating the color vector to the needed size, here. */
4977 ++img->ncolors;
4978 img->colors =
4979 (unsigned long *) xrealloc (img->colors,
4980 img->ncolors * sizeof *img->colors);
4981 img->colors[img->ncolors - 1] = color.pixel;
4982 result = color.pixel;
4983 }
4984 else
4985 result = dflt;
4986
4987 return result;
4988}
4989
4990
4991\f
4992/***********************************************************************
4993 Image Cache
4994 ***********************************************************************/
4995
4996static void cache_image P_ ((struct frame *f, struct image *img));
ad18ffb1 4997static void postprocess_image P_ ((struct frame *, struct image *));
333b20bb
GM
4998
4999
5000/* Return a new, initialized image cache that is allocated from the
5001 heap. Call free_image_cache to free an image cache. */
5002
5003struct image_cache *
5004make_image_cache ()
5005{
5006 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
5007 int size;
177c0ea7 5008
333b20bb
GM
5009 bzero (c, sizeof *c);
5010 c->size = 50;
5011 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
5012 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
5013 c->buckets = (struct image **) xmalloc (size);
5014 bzero (c->buckets, size);
5015 return c;
5016}
5017
5018
5019/* Free image cache of frame F. Be aware that X frames share images
5020 caches. */
5021
5022void
5023free_image_cache (f)
5024 struct frame *f;
5025{
5026 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5027 if (c)
5028 {
5029 int i;
5030
5031 /* Cache should not be referenced by any frame when freed. */
5032 xassert (c->refcount == 0);
177c0ea7 5033
333b20bb
GM
5034 for (i = 0; i < c->used; ++i)
5035 free_image (f, c->images[i]);
5036 xfree (c->images);
333b20bb 5037 xfree (c->buckets);
e3130015 5038 xfree (c);
333b20bb
GM
5039 FRAME_X_IMAGE_CACHE (f) = NULL;
5040 }
5041}
5042
5043
5044/* Clear image cache of frame F. FORCE_P non-zero means free all
5045 images. FORCE_P zero means clear only images that haven't been
5046 displayed for some time. Should be called from time to time to
5047 reduce the number of loaded images. If image-eviction-seconds is
5048 non-nil, this frees images in the cache which weren't displayed for
5049 at least that many seconds. */
5050
5051void
5052clear_image_cache (f, force_p)
5053 struct frame *f;
5054 int force_p;
5055{
5056 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5057
83676598 5058 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
5059 {
5060 EMACS_TIME t;
5061 unsigned long old;
f4779de9 5062 int i, nfreed;
333b20bb
GM
5063
5064 EMACS_GET_TIME (t);
fcf431dc 5065 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
f4779de9
GM
5066
5067 /* Block input so that we won't be interrupted by a SIGIO
5068 while being in an inconsistent state. */
5069 BLOCK_INPUT;
177c0ea7 5070
f4779de9 5071 for (i = nfreed = 0; i < c->used; ++i)
333b20bb
GM
5072 {
5073 struct image *img = c->images[i];
5074 if (img != NULL
f4779de9 5075 && (force_p || img->timestamp < old))
333b20bb
GM
5076 {
5077 free_image (f, img);
f4779de9 5078 ++nfreed;
333b20bb
GM
5079 }
5080 }
5081
5082 /* We may be clearing the image cache because, for example,
5083 Emacs was iconified for a longer period of time. In that
5084 case, current matrices may still contain references to
5085 images freed above. So, clear these matrices. */
f4779de9 5086 if (nfreed)
333b20bb 5087 {
f4779de9 5088 Lisp_Object tail, frame;
177c0ea7 5089
f4779de9
GM
5090 FOR_EACH_FRAME (tail, frame)
5091 {
5092 struct frame *f = XFRAME (frame);
5093 if (FRAME_X_P (f)
5094 && FRAME_X_IMAGE_CACHE (f) == c)
83676598 5095 clear_current_matrices (f);
f4779de9
GM
5096 }
5097
333b20bb
GM
5098 ++windows_or_buffers_changed;
5099 }
f4779de9
GM
5100
5101 UNBLOCK_INPUT;
333b20bb
GM
5102 }
5103}
5104
5105
5106DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
5107 0, 1, 0,
7ee72033 5108 doc: /* Clear the image cache of FRAME.
c061c855 5109FRAME nil or omitted means use the selected frame.
7ee72033
MB
5110FRAME t means clear the image caches of all frames. */)
5111 (frame)
333b20bb
GM
5112 Lisp_Object frame;
5113{
5114 if (EQ (frame, Qt))
5115 {
5116 Lisp_Object tail;
177c0ea7 5117
333b20bb
GM
5118 FOR_EACH_FRAME (tail, frame)
5119 if (FRAME_X_P (XFRAME (frame)))
5120 clear_image_cache (XFRAME (frame), 1);
5121 }
5122 else
5123 clear_image_cache (check_x_frame (frame), 1);
5124
5125 return Qnil;
5126}
5127
5128
ad18ffb1
GM
5129/* Compute masks and transform image IMG on frame F, as specified
5130 by the image's specification, */
5131
5132static void
5133postprocess_image (f, img)
5134 struct frame *f;
5135 struct image *img;
5136{
5137 /* Manipulation of the image's mask. */
5138 if (img->pixmap)
5139 {
5140 Lisp_Object conversion, spec;
5141 Lisp_Object mask;
5142
5143 spec = img->spec;
177c0ea7 5144
ad18ffb1
GM
5145 /* `:heuristic-mask t'
5146 `:mask heuristic'
5147 means build a mask heuristically.
5148 `:heuristic-mask (R G B)'
5149 `:mask (heuristic (R G B))'
5150 means build a mask from color (R G B) in the
5151 image.
5152 `:mask nil'
5153 means remove a mask, if any. */
177c0ea7 5154
ad18ffb1
GM
5155 mask = image_spec_value (spec, QCheuristic_mask, NULL);
5156 if (!NILP (mask))
5157 x_build_heuristic_mask (f, img, mask);
5158 else
5159 {
5160 int found_p;
177c0ea7 5161
ad18ffb1 5162 mask = image_spec_value (spec, QCmask, &found_p);
177c0ea7 5163
ad18ffb1
GM
5164 if (EQ (mask, Qheuristic))
5165 x_build_heuristic_mask (f, img, Qt);
5166 else if (CONSP (mask)
5167 && EQ (XCAR (mask), Qheuristic))
5168 {
5169 if (CONSP (XCDR (mask)))
5170 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
5171 else
5172 x_build_heuristic_mask (f, img, XCDR (mask));
5173 }
5174 else if (NILP (mask) && found_p && img->mask)
5175 {
5176 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
5177 img->mask = None;
5178 }
5179 }
177c0ea7
JB
5180
5181
ad18ffb1
GM
5182 /* Should we apply an image transformation algorithm? */
5183 conversion = image_spec_value (spec, QCconversion, NULL);
5184 if (EQ (conversion, Qdisabled))
5185 x_disable_image (f, img);
5186 else if (EQ (conversion, Qlaplace))
5187 x_laplace (f, img);
5188 else if (EQ (conversion, Qemboss))
5189 x_emboss (f, img);
5190 else if (CONSP (conversion)
5191 && EQ (XCAR (conversion), Qedge_detection))
5192 {
5193 Lisp_Object tem;
5194 tem = XCDR (conversion);
5195 if (CONSP (tem))
5196 x_edge_detection (f, img,
5197 Fplist_get (tem, QCmatrix),
5198 Fplist_get (tem, QCcolor_adjustment));
5199 }
5200 }
5201}
5202
5203
333b20bb 5204/* Return the id of image with Lisp specification SPEC on frame F.
83676598 5205 SPEC must be a valid Lisp image specification (see valid_image_p). */
333b20bb
GM
5206
5207int
83676598 5208lookup_image (f, spec)
333b20bb
GM
5209 struct frame *f;
5210 Lisp_Object spec;
5211{
5212 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5213 struct image *img;
5214 int i;
5215 unsigned hash;
5216 struct gcpro gcpro1;
4f7ca1f1 5217 EMACS_TIME now;
333b20bb
GM
5218
5219 /* F must be a window-system frame, and SPEC must be a valid image
5220 specification. */
5221 xassert (FRAME_WINDOW_P (f));
5222 xassert (valid_image_p (spec));
177c0ea7 5223
333b20bb
GM
5224 GCPRO1 (spec);
5225
5226 /* Look up SPEC in the hash table of the image cache. */
5227 hash = sxhash (spec, 0);
5228 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
5229
5230 for (img = c->buckets[i]; img; img = img->next)
5231 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
5232 break;
5233
5234 /* If not found, create a new image and cache it. */
5235 if (img == NULL)
5236 {
ad18ffb1 5237 extern Lisp_Object Qpostscript;
177c0ea7 5238
28c7826c 5239 BLOCK_INPUT;
333b20bb
GM
5240 img = make_image (spec, hash);
5241 cache_image (f, img);
83676598 5242 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
5243
5244 /* If we can't load the image, and we don't have a width and
5245 height, use some arbitrary width and height so that we can
5246 draw a rectangle for it. */
83676598 5247 if (img->load_failed_p)
333b20bb
GM
5248 {
5249 Lisp_Object value;
5250
5251 value = image_spec_value (spec, QCwidth, NULL);
5252 img->width = (INTEGERP (value)
5253 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
5254 value = image_spec_value (spec, QCheight, NULL);
5255 img->height = (INTEGERP (value)
5256 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
5257 }
5258 else
5259 {
5260 /* Handle image type independent image attributes
f20a3b7a
MB
5261 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
5262 `:background COLOR'. */
5263 Lisp_Object ascent, margin, relief, bg;
333b20bb
GM
5264
5265 ascent = image_spec_value (spec, QCascent, NULL);
5266 if (INTEGERP (ascent))
5267 img->ascent = XFASTINT (ascent);
7c7ff7f5
GM
5268 else if (EQ (ascent, Qcenter))
5269 img->ascent = CENTERED_IMAGE_ASCENT;
177c0ea7 5270
333b20bb
GM
5271 margin = image_spec_value (spec, QCmargin, NULL);
5272 if (INTEGERP (margin) && XINT (margin) >= 0)
3ed61e75
GM
5273 img->vmargin = img->hmargin = XFASTINT (margin);
5274 else if (CONSP (margin) && INTEGERP (XCAR (margin))
5275 && INTEGERP (XCDR (margin)))
5276 {
5277 if (XINT (XCAR (margin)) > 0)
5278 img->hmargin = XFASTINT (XCAR (margin));
5279 if (XINT (XCDR (margin)) > 0)
5280 img->vmargin = XFASTINT (XCDR (margin));
5281 }
177c0ea7 5282
333b20bb
GM
5283 relief = image_spec_value (spec, QCrelief, NULL);
5284 if (INTEGERP (relief))
5285 {
5286 img->relief = XINT (relief);
3ed61e75
GM
5287 img->hmargin += abs (img->relief);
5288 img->vmargin += abs (img->relief);
333b20bb
GM
5289 }
5290
f20a3b7a
MB
5291 if (! img->background_valid)
5292 {
5293 bg = image_spec_value (img->spec, QCbackground, NULL);
5294 if (!NILP (bg))
5295 {
5296 img->background
5297 = x_alloc_image_color (f, img, bg,
5298 FRAME_BACKGROUND_PIXEL (f));
5299 img->background_valid = 1;
5300 }
5301 }
5302
ad18ffb1
GM
5303 /* Do image transformations and compute masks, unless we
5304 don't have the image yet. */
5305 if (!EQ (*img->type->type, Qpostscript))
5306 postprocess_image (f, img);
333b20bb 5307 }
dd00328a 5308
28c7826c
GM
5309 UNBLOCK_INPUT;
5310 xassert (!interrupt_input_blocked);
333b20bb
GM
5311 }
5312
4f7ca1f1
GM
5313 /* We're using IMG, so set its timestamp to `now'. */
5314 EMACS_GET_TIME (now);
5315 img->timestamp = EMACS_SECS (now);
177c0ea7 5316
333b20bb 5317 UNGCPRO;
177c0ea7 5318
333b20bb
GM
5319 /* Value is the image id. */
5320 return img->id;
5321}
5322
5323
5324/* Cache image IMG in the image cache of frame F. */
5325
5326static void
5327cache_image (f, img)
5328 struct frame *f;
5329 struct image *img;
5330{
5331 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5332 int i;
5333
5334 /* Find a free slot in c->images. */
5335 for (i = 0; i < c->used; ++i)
5336 if (c->images[i] == NULL)
5337 break;
5338
5339 /* If no free slot found, maybe enlarge c->images. */
5340 if (i == c->used && c->used == c->size)
5341 {
5342 c->size *= 2;
5343 c->images = (struct image **) xrealloc (c->images,
5344 c->size * sizeof *c->images);
5345 }
5346
5347 /* Add IMG to c->images, and assign IMG an id. */
5348 c->images[i] = img;
5349 img->id = i;
5350 if (i == c->used)
5351 ++c->used;
5352
5353 /* Add IMG to the cache's hash table. */
5354 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
5355 img->next = c->buckets[i];
5356 if (img->next)
5357 img->next->prev = img;
5358 img->prev = NULL;
5359 c->buckets[i] = img;
5360}
5361
5362
5363/* Call FN on every image in the image cache of frame F. Used to mark
5364 Lisp Objects in the image cache. */
5365
5366void
5367forall_images_in_image_cache (f, fn)
5368 struct frame *f;
5369 void (*fn) P_ ((struct image *img));
5370{
5371 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
5372 {
5373 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5374 if (c)
5375 {
5376 int i;
5377 for (i = 0; i < c->used; ++i)
5378 if (c->images[i])
5379 fn (c->images[i]);
5380 }
5381 }
5382}
5383
5384
5385\f
5386/***********************************************************************
5387 X support code
5388 ***********************************************************************/
5389
45158a91
GM
5390static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
5391 XImage **, Pixmap *));
333b20bb
GM
5392static void x_destroy_x_image P_ ((XImage *));
5393static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
5394
5395
5396/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
5397 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
5398 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
5399 via xmalloc. Print error messages via image_error if an error
45158a91 5400 occurs. Value is non-zero if successful. */
333b20bb
GM
5401
5402static int
45158a91 5403x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
333b20bb 5404 struct frame *f;
333b20bb
GM
5405 int width, height, depth;
5406 XImage **ximg;
5407 Pixmap *pixmap;
5408{
5409 Display *display = FRAME_X_DISPLAY (f);
5410 Screen *screen = FRAME_X_SCREEN (f);
5411 Window window = FRAME_X_WINDOW (f);
5412
5413 xassert (interrupt_input_blocked);
5414
5415 if (depth <= 0)
5416 depth = DefaultDepthOfScreen (screen);
5417 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
5418 depth, ZPixmap, 0, NULL, width, height,
5419 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
5420 if (*ximg == NULL)
5421 {
45158a91 5422 image_error ("Unable to allocate X image", Qnil, Qnil);
333b20bb
GM
5423 return 0;
5424 }
5425
5426 /* Allocate image raster. */
5427 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
5428
5429 /* Allocate a pixmap of the same size. */
5430 *pixmap = XCreatePixmap (display, window, width, height, depth);
dd00328a 5431 if (*pixmap == None)
333b20bb
GM
5432 {
5433 x_destroy_x_image (*ximg);
5434 *ximg = NULL;
45158a91 5435 image_error ("Unable to create X pixmap", Qnil, Qnil);
333b20bb
GM
5436 return 0;
5437 }
5438
5439 return 1;
5440}
5441
5442
5443/* Destroy XImage XIMG. Free XIMG->data. */
5444
5445static void
5446x_destroy_x_image (ximg)
5447 XImage *ximg;
5448{
5449 xassert (interrupt_input_blocked);
5450 if (ximg)
5451 {
5452 xfree (ximg->data);
5453 ximg->data = NULL;
5454 XDestroyImage (ximg);
5455 }
5456}
5457
5458
5459/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
5460 are width and height of both the image and pixmap. */
5461
ea6b19ca 5462static void
333b20bb
GM
5463x_put_x_image (f, ximg, pixmap, width, height)
5464 struct frame *f;
5465 XImage *ximg;
5466 Pixmap pixmap;
caeea55a 5467 int width, height;
333b20bb
GM
5468{
5469 GC gc;
177c0ea7 5470
333b20bb
GM
5471 xassert (interrupt_input_blocked);
5472 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
5473 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
5474 XFreeGC (FRAME_X_DISPLAY (f), gc);
5475}
5476
5477
5478\f
5479/***********************************************************************
5be6c3b0 5480 File Handling
333b20bb
GM
5481 ***********************************************************************/
5482
5483static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5be6c3b0
GM
5484static char *slurp_file P_ ((char *, int *));
5485
333b20bb
GM
5486
5487/* Find image file FILE. Look in data-directory, then
5488 x-bitmap-file-path. Value is the full name of the file found, or
5489 nil if not found. */
5490
5491static Lisp_Object
5492x_find_image_file (file)
5493 Lisp_Object file;
5494{
5495 Lisp_Object file_found, search_path;
5496 struct gcpro gcpro1, gcpro2;
5497 int fd;
5498
5499 file_found = Qnil;
5500 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
5501 GCPRO2 (file_found, search_path);
5502
5503 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 5504 fd = openp (search_path, file, Qnil, &file_found, Qnil);
177c0ea7 5505
939d6465 5506 if (fd == -1)
333b20bb
GM
5507 file_found = Qnil;
5508 else
5509 close (fd);
5510
5511 UNGCPRO;
5512 return file_found;
5513}
5514
5515
5be6c3b0
GM
5516/* Read FILE into memory. Value is a pointer to a buffer allocated
5517 with xmalloc holding FILE's contents. Value is null if an error
b243755a 5518 occurred. *SIZE is set to the size of the file. */
5be6c3b0
GM
5519
5520static char *
5521slurp_file (file, size)
5522 char *file;
5523 int *size;
5524{
5525 FILE *fp = NULL;
5526 char *buf = NULL;
5527 struct stat st;
5528
5529 if (stat (file, &st) == 0
5530 && (fp = fopen (file, "r")) != NULL
5531 && (buf = (char *) xmalloc (st.st_size),
5532 fread (buf, 1, st.st_size, fp) == st.st_size))
5533 {
5534 *size = st.st_size;
5535 fclose (fp);
5536 }
5537 else
5538 {
5539 if (fp)
5540 fclose (fp);
5541 if (buf)
5542 {
5543 xfree (buf);
5544 buf = NULL;
5545 }
5546 }
177c0ea7 5547
5be6c3b0
GM
5548 return buf;
5549}
5550
5551
333b20bb
GM
5552\f
5553/***********************************************************************
5554 XBM images
5555 ***********************************************************************/
5556
5be6c3b0 5557static int xbm_scan P_ ((char **, char *, char *, int *));
333b20bb 5558static int xbm_load P_ ((struct frame *f, struct image *img));
5be6c3b0
GM
5559static int xbm_load_image P_ ((struct frame *f, struct image *img,
5560 char *, char *));
333b20bb 5561static int xbm_image_p P_ ((Lisp_Object object));
5be6c3b0
GM
5562static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
5563 unsigned char **));
5564static int xbm_file_p P_ ((Lisp_Object));
333b20bb
GM
5565
5566
5567/* Indices of image specification fields in xbm_format, below. */
5568
5569enum xbm_keyword_index
5570{
5571 XBM_TYPE,
5572 XBM_FILE,
5573 XBM_WIDTH,
5574 XBM_HEIGHT,
5575 XBM_DATA,
5576 XBM_FOREGROUND,
5577 XBM_BACKGROUND,
5578 XBM_ASCENT,
5579 XBM_MARGIN,
5580 XBM_RELIEF,
5581 XBM_ALGORITHM,
5582 XBM_HEURISTIC_MASK,
4a8e312c 5583 XBM_MASK,
333b20bb
GM
5584 XBM_LAST
5585};
5586
5587/* Vector of image_keyword structures describing the format
5588 of valid XBM image specifications. */
5589
5590static struct image_keyword xbm_format[XBM_LAST] =
5591{
5592 {":type", IMAGE_SYMBOL_VALUE, 1},
5593 {":file", IMAGE_STRING_VALUE, 0},
5594 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5595 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5596 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
5597 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5598 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
7c7ff7f5 5599 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 5600 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 5601 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 5602 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
5603 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5604 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
5605};
5606
5607/* Structure describing the image type XBM. */
5608
5609static struct image_type xbm_type =
5610{
5611 &Qxbm,
5612 xbm_image_p,
5613 xbm_load,
5614 x_clear_image,
5615 NULL
5616};
5617
5618/* Tokens returned from xbm_scan. */
5619
5620enum xbm_token
5621{
5622 XBM_TK_IDENT = 256,
5623 XBM_TK_NUMBER
5624};
5625
177c0ea7 5626
333b20bb
GM
5627/* Return non-zero if OBJECT is a valid XBM-type image specification.
5628 A valid specification is a list starting with the symbol `image'
5629 The rest of the list is a property list which must contain an
5630 entry `:type xbm..
5631
5632 If the specification specifies a file to load, it must contain
5633 an entry `:file FILENAME' where FILENAME is a string.
5634
5635 If the specification is for a bitmap loaded from memory it must
5636 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
5637 WIDTH and HEIGHT are integers > 0. DATA may be:
5638
5639 1. a string large enough to hold the bitmap data, i.e. it must
5640 have a size >= (WIDTH + 7) / 8 * HEIGHT
5641
5642 2. a bool-vector of size >= WIDTH * HEIGHT
5643
5644 3. a vector of strings or bool-vectors, one for each line of the
5645 bitmap.
5646
5be6c3b0
GM
5647 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
5648 may not be specified in this case because they are defined in the
5649 XBM file.
5650
333b20bb
GM
5651 Both the file and data forms may contain the additional entries
5652 `:background COLOR' and `:foreground COLOR'. If not present,
5653 foreground and background of the frame on which the image is
e3130015 5654 displayed is used. */
333b20bb
GM
5655
5656static int
5657xbm_image_p (object)
5658 Lisp_Object object;
5659{
5660 struct image_keyword kw[XBM_LAST];
177c0ea7 5661
333b20bb 5662 bcopy (xbm_format, kw, sizeof kw);
bfd2209f 5663 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
333b20bb
GM
5664 return 0;
5665
5666 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
5667
5668 if (kw[XBM_FILE].count)
5669 {
5670 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
5671 return 0;
5672 }
5be6c3b0
GM
5673 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
5674 {
5675 /* In-memory XBM file. */
5676 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
5677 return 0;
5678 }
333b20bb
GM
5679 else
5680 {
5681 Lisp_Object data;
5682 int width, height;
5683
5684 /* Entries for `:width', `:height' and `:data' must be present. */
5685 if (!kw[XBM_WIDTH].count
5686 || !kw[XBM_HEIGHT].count
5687 || !kw[XBM_DATA].count)
5688 return 0;
5689
5690 data = kw[XBM_DATA].value;
5691 width = XFASTINT (kw[XBM_WIDTH].value);
5692 height = XFASTINT (kw[XBM_HEIGHT].value);
177c0ea7 5693
333b20bb
GM
5694 /* Check type of data, and width and height against contents of
5695 data. */
5696 if (VECTORP (data))
5697 {
5698 int i;
177c0ea7 5699
333b20bb
GM
5700 /* Number of elements of the vector must be >= height. */
5701 if (XVECTOR (data)->size < height)
5702 return 0;
5703
5704 /* Each string or bool-vector in data must be large enough
5705 for one line of the image. */
5706 for (i = 0; i < height; ++i)
5707 {
5708 Lisp_Object elt = XVECTOR (data)->contents[i];
5709
5710 if (STRINGP (elt))
5711 {
d5db4077 5712 if (SCHARS (elt)
333b20bb
GM
5713 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
5714 return 0;
5715 }
5716 else if (BOOL_VECTOR_P (elt))
5717 {
5718 if (XBOOL_VECTOR (elt)->size < width)
5719 return 0;
5720 }
5721 else
5722 return 0;
5723 }
5724 }
5725 else if (STRINGP (data))
5726 {
d5db4077 5727 if (SCHARS (data)
333b20bb
GM
5728 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
5729 return 0;
5730 }
5731 else if (BOOL_VECTOR_P (data))
5732 {
5733 if (XBOOL_VECTOR (data)->size < width * height)
5734 return 0;
5735 }
5736 else
5737 return 0;
5738 }
5739
333b20bb
GM
5740 return 1;
5741}
5742
5743
5744/* Scan a bitmap file. FP is the stream to read from. Value is
5745 either an enumerator from enum xbm_token, or a character for a
5746 single-character token, or 0 at end of file. If scanning an
5747 identifier, store the lexeme of the identifier in SVAL. If
5748 scanning a number, store its value in *IVAL. */
5749
5750static int
5be6c3b0
GM
5751xbm_scan (s, end, sval, ival)
5752 char **s, *end;
333b20bb
GM
5753 char *sval;
5754 int *ival;
5755{
5756 int c;
0a695da7
GM
5757
5758 loop:
177c0ea7 5759
333b20bb 5760 /* Skip white space. */
5be6c3b0 5761 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
5762 ;
5763
5be6c3b0 5764 if (*s >= end)
333b20bb
GM
5765 c = 0;
5766 else if (isdigit (c))
5767 {
5768 int value = 0, digit;
177c0ea7 5769
5be6c3b0 5770 if (c == '0' && *s < end)
333b20bb 5771 {
5be6c3b0 5772 c = *(*s)++;
333b20bb
GM
5773 if (c == 'x' || c == 'X')
5774 {
5be6c3b0 5775 while (*s < end)
333b20bb 5776 {
5be6c3b0 5777 c = *(*s)++;
333b20bb
GM
5778 if (isdigit (c))
5779 digit = c - '0';
5780 else if (c >= 'a' && c <= 'f')
5781 digit = c - 'a' + 10;
5782 else if (c >= 'A' && c <= 'F')
5783 digit = c - 'A' + 10;
5784 else
5785 break;
5786 value = 16 * value + digit;
5787 }
5788 }
5789 else if (isdigit (c))
5790 {
5791 value = c - '0';
5be6c3b0
GM
5792 while (*s < end
5793 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
5794 value = 8 * value + c - '0';
5795 }
5796 }
5797 else
5798 {
5799 value = c - '0';
5be6c3b0
GM
5800 while (*s < end
5801 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
5802 value = 10 * value + c - '0';
5803 }
5804
5be6c3b0
GM
5805 if (*s < end)
5806 *s = *s - 1;
333b20bb
GM
5807 *ival = value;
5808 c = XBM_TK_NUMBER;
5809 }
5810 else if (isalpha (c) || c == '_')
5811 {
5812 *sval++ = c;
5be6c3b0
GM
5813 while (*s < end
5814 && (c = *(*s)++, (isalnum (c) || c == '_')))
333b20bb
GM
5815 *sval++ = c;
5816 *sval = 0;
5be6c3b0
GM
5817 if (*s < end)
5818 *s = *s - 1;
333b20bb
GM
5819 c = XBM_TK_IDENT;
5820 }
0a695da7
GM
5821 else if (c == '/' && **s == '*')
5822 {
5823 /* C-style comment. */
5824 ++*s;
5825 while (**s && (**s != '*' || *(*s + 1) != '/'))
5826 ++*s;
5827 if (**s)
5828 {
5829 *s += 2;
5830 goto loop;
5831 }
5832 }
333b20bb
GM
5833
5834 return c;
5835}
5836
5837
5838/* Replacement for XReadBitmapFileData which isn't available under old
5be6c3b0
GM
5839 X versions. CONTENTS is a pointer to a buffer to parse; END is the
5840 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
5841 the image. Return in *DATA the bitmap data allocated with xmalloc.
5842 Value is non-zero if successful. DATA null means just test if
b243755a 5843 CONTENTS looks like an in-memory XBM file. */
333b20bb
GM
5844
5845static int
5be6c3b0
GM
5846xbm_read_bitmap_data (contents, end, width, height, data)
5847 char *contents, *end;
333b20bb
GM
5848 int *width, *height;
5849 unsigned char **data;
5850{
5be6c3b0 5851 char *s = contents;
333b20bb
GM
5852 char buffer[BUFSIZ];
5853 int padding_p = 0;
5854 int v10 = 0;
5855 int bytes_per_line, i, nbytes;
5856 unsigned char *p;
5857 int value;
5858 int LA1;
5859
5860#define match() \
5be6c3b0 5861 LA1 = xbm_scan (&s, end, buffer, &value)
333b20bb
GM
5862
5863#define expect(TOKEN) \
5864 if (LA1 != (TOKEN)) \
5865 goto failure; \
5866 else \
177c0ea7 5867 match ()
333b20bb
GM
5868
5869#define expect_ident(IDENT) \
5870 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
5871 match (); \
5872 else \
5873 goto failure
5874
333b20bb 5875 *width = *height = -1;
5be6c3b0
GM
5876 if (data)
5877 *data = NULL;
5878 LA1 = xbm_scan (&s, end, buffer, &value);
333b20bb
GM
5879
5880 /* Parse defines for width, height and hot-spots. */
5881 while (LA1 == '#')
5882 {
333b20bb
GM
5883 match ();
5884 expect_ident ("define");
5885 expect (XBM_TK_IDENT);
5886
5887 if (LA1 == XBM_TK_NUMBER);
5888 {
5889 char *p = strrchr (buffer, '_');
5890 p = p ? p + 1 : buffer;
5891 if (strcmp (p, "width") == 0)
5892 *width = value;
5893 else if (strcmp (p, "height") == 0)
5894 *height = value;
5895 }
5896 expect (XBM_TK_NUMBER);
5897 }
5898
5899 if (*width < 0 || *height < 0)
5900 goto failure;
5be6c3b0
GM
5901 else if (data == NULL)
5902 goto success;
333b20bb
GM
5903
5904 /* Parse bits. Must start with `static'. */
5905 expect_ident ("static");
5906 if (LA1 == XBM_TK_IDENT)
5907 {
5908 if (strcmp (buffer, "unsigned") == 0)
5909 {
177c0ea7 5910 match ();
333b20bb
GM
5911 expect_ident ("char");
5912 }
5913 else if (strcmp (buffer, "short") == 0)
5914 {
5915 match ();
5916 v10 = 1;
5917 if (*width % 16 && *width % 16 < 9)
5918 padding_p = 1;
5919 }
5920 else if (strcmp (buffer, "char") == 0)
5921 match ();
5922 else
5923 goto failure;
5924 }
177c0ea7 5925 else
333b20bb
GM
5926 goto failure;
5927
5928 expect (XBM_TK_IDENT);
5929 expect ('[');
5930 expect (']');
5931 expect ('=');
5932 expect ('{');
5933
5934 bytes_per_line = (*width + 7) / 8 + padding_p;
5935 nbytes = bytes_per_line * *height;
5936 p = *data = (char *) xmalloc (nbytes);
5937
5938 if (v10)
5939 {
333b20bb
GM
5940 for (i = 0; i < nbytes; i += 2)
5941 {
5942 int val = value;
5943 expect (XBM_TK_NUMBER);
5944
5945 *p++ = val;
5946 if (!padding_p || ((i + 2) % bytes_per_line))
5947 *p++ = value >> 8;
177c0ea7 5948
333b20bb
GM
5949 if (LA1 == ',' || LA1 == '}')
5950 match ();
5951 else
5952 goto failure;
5953 }
5954 }
5955 else
5956 {
5957 for (i = 0; i < nbytes; ++i)
5958 {
5959 int val = value;
5960 expect (XBM_TK_NUMBER);
177c0ea7 5961
333b20bb 5962 *p++ = val;
177c0ea7 5963
333b20bb
GM
5964 if (LA1 == ',' || LA1 == '}')
5965 match ();
5966 else
5967 goto failure;
5968 }
5969 }
5970
5be6c3b0 5971 success:
333b20bb
GM
5972 return 1;
5973
5974 failure:
177c0ea7 5975
5be6c3b0 5976 if (data && *data)
333b20bb
GM
5977 {
5978 xfree (*data);
5979 *data = NULL;
5980 }
5981 return 0;
5982
5983#undef match
5984#undef expect
5985#undef expect_ident
5986}
5987
5988
5be6c3b0
GM
5989/* Load XBM image IMG which will be displayed on frame F from buffer
5990 CONTENTS. END is the end of the buffer. Value is non-zero if
5991 successful. */
333b20bb
GM
5992
5993static int
5be6c3b0 5994xbm_load_image (f, img, contents, end)
333b20bb
GM
5995 struct frame *f;
5996 struct image *img;
5be6c3b0 5997 char *contents, *end;
333b20bb
GM
5998{
5999 int rc;
6000 unsigned char *data;
6001 int success_p = 0;
177c0ea7 6002
5be6c3b0 6003 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
333b20bb
GM
6004 if (rc)
6005 {
6006 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6007 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
6008 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
6009 Lisp_Object value;
177c0ea7 6010
333b20bb
GM
6011 xassert (img->width > 0 && img->height > 0);
6012
6013 /* Get foreground and background colors, maybe allocate colors. */
6014 value = image_spec_value (img->spec, QCforeground, NULL);
6015 if (!NILP (value))
6016 foreground = x_alloc_image_color (f, img, value, foreground);
333b20bb
GM
6017 value = image_spec_value (img->spec, QCbackground, NULL);
6018 if (!NILP (value))
f20a3b7a
MB
6019 {
6020 background = x_alloc_image_color (f, img, value, background);
6021 img->background = background;
6022 img->background_valid = 1;
6023 }
333b20bb 6024
333b20bb
GM
6025 img->pixmap
6026 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
6027 FRAME_X_WINDOW (f),
6028 data,
6029 img->width, img->height,
6030 foreground, background,
6031 depth);
6032 xfree (data);
6033
dd00328a 6034 if (img->pixmap == None)
333b20bb
GM
6035 {
6036 x_clear_image (f, img);
5be6c3b0 6037 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
6038 }
6039 else
6040 success_p = 1;
333b20bb
GM
6041 }
6042 else
45158a91 6043 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
333b20bb 6044
333b20bb
GM
6045 return success_p;
6046}
6047
6048
5be6c3b0
GM
6049/* Value is non-zero if DATA looks like an in-memory XBM file. */
6050
6051static int
6052xbm_file_p (data)
6053 Lisp_Object data;
6054{
6055 int w, h;
6056 return (STRINGP (data)
d5db4077
KR
6057 && xbm_read_bitmap_data (SDATA (data),
6058 (SDATA (data)
6059 + SBYTES (data)),
5be6c3b0
GM
6060 &w, &h, NULL));
6061}
6062
177c0ea7 6063
333b20bb
GM
6064/* Fill image IMG which is used on frame F with pixmap data. Value is
6065 non-zero if successful. */
6066
6067static int
6068xbm_load (f, img)
6069 struct frame *f;
6070 struct image *img;
6071{
6072 int success_p = 0;
6073 Lisp_Object file_name;
6074
6075 xassert (xbm_image_p (img->spec));
6076
6077 /* If IMG->spec specifies a file name, create a non-file spec from it. */
6078 file_name = image_spec_value (img->spec, QCfile, NULL);
6079 if (STRINGP (file_name))
5be6c3b0
GM
6080 {
6081 Lisp_Object file;
6082 char *contents;
6083 int size;
6084 struct gcpro gcpro1;
177c0ea7 6085
5be6c3b0
GM
6086 file = x_find_image_file (file_name);
6087 GCPRO1 (file);
6088 if (!STRINGP (file))
6089 {
6090 image_error ("Cannot find image file `%s'", file_name, Qnil);
6091 UNGCPRO;
6092 return 0;
6093 }
6094
d5db4077 6095 contents = slurp_file (SDATA (file), &size);
5be6c3b0
GM
6096 if (contents == NULL)
6097 {
6098 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
6099 UNGCPRO;
6100 return 0;
6101 }
6102
6103 success_p = xbm_load_image (f, img, contents, contents + size);
6104 UNGCPRO;
6105 }
333b20bb
GM
6106 else
6107 {
6108 struct image_keyword fmt[XBM_LAST];
6109 Lisp_Object data;
6110 int depth;
6111 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
6112 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
6113 char *bits;
9b207e8e 6114 int parsed_p;
5be6c3b0
GM
6115 int in_memory_file_p = 0;
6116
6117 /* See if data looks like an in-memory XBM file. */
6118 data = image_spec_value (img->spec, QCdata, NULL);
6119 in_memory_file_p = xbm_file_p (data);
333b20bb 6120
5be6c3b0 6121 /* Parse the image specification. */
333b20bb 6122 bcopy (xbm_format, fmt, sizeof fmt);
bfd2209f 6123 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
333b20bb
GM
6124 xassert (parsed_p);
6125
6126 /* Get specified width, and height. */
5be6c3b0
GM
6127 if (!in_memory_file_p)
6128 {
6129 img->width = XFASTINT (fmt[XBM_WIDTH].value);
6130 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
6131 xassert (img->width > 0 && img->height > 0);
6132 }
333b20bb 6133
333b20bb 6134 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
6135 if (fmt[XBM_FOREGROUND].count
6136 && STRINGP (fmt[XBM_FOREGROUND].value))
333b20bb
GM
6137 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
6138 foreground);
6f1be3b9
GM
6139 if (fmt[XBM_BACKGROUND].count
6140 && STRINGP (fmt[XBM_BACKGROUND].value))
333b20bb
GM
6141 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
6142 background);
6143
5be6c3b0 6144 if (in_memory_file_p)
d5db4077
KR
6145 success_p = xbm_load_image (f, img, SDATA (data),
6146 (SDATA (data)
6147 + SBYTES (data)));
5be6c3b0 6148 else
333b20bb 6149 {
5be6c3b0
GM
6150 if (VECTORP (data))
6151 {
6152 int i;
6153 char *p;
6154 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
177c0ea7 6155
5be6c3b0
GM
6156 p = bits = (char *) alloca (nbytes * img->height);
6157 for (i = 0; i < img->height; ++i, p += nbytes)
6158 {
6159 Lisp_Object line = XVECTOR (data)->contents[i];
6160 if (STRINGP (line))
d5db4077 6161 bcopy (SDATA (line), p, nbytes);
5be6c3b0
GM
6162 else
6163 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
6164 }
6165 }
6166 else if (STRINGP (data))
d5db4077 6167 bits = SDATA (data);
5be6c3b0
GM
6168 else
6169 bits = XBOOL_VECTOR (data)->data;
6170
6171 /* Create the pixmap. */
6172 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6173 img->pixmap
6174 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
6175 FRAME_X_WINDOW (f),
6176 bits,
6177 img->width, img->height,
6178 foreground, background,
6179 depth);
6180 if (img->pixmap)
6181 success_p = 1;
6182 else
333b20bb 6183 {
5be6c3b0
GM
6184 image_error ("Unable to create pixmap for XBM image `%s'",
6185 img->spec, Qnil);
6186 x_clear_image (f, img);
333b20bb
GM
6187 }
6188 }
333b20bb
GM
6189 }
6190
6191 return success_p;
6192}
177c0ea7 6193
333b20bb
GM
6194
6195\f
6196/***********************************************************************
6197 XPM images
6198 ***********************************************************************/
6199
177c0ea7 6200#if HAVE_XPM
333b20bb
GM
6201
6202static int xpm_image_p P_ ((Lisp_Object object));
6203static int xpm_load P_ ((struct frame *f, struct image *img));
6204static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
6205
6206#include "X11/xpm.h"
6207
6208/* The symbol `xpm' identifying XPM-format images. */
6209
6210Lisp_Object Qxpm;
6211
6212/* Indices of image specification fields in xpm_format, below. */
6213
6214enum xpm_keyword_index
6215{
6216 XPM_TYPE,
6217 XPM_FILE,
6218 XPM_DATA,
6219 XPM_ASCENT,
6220 XPM_MARGIN,
6221 XPM_RELIEF,
6222 XPM_ALGORITHM,
6223 XPM_HEURISTIC_MASK,
4a8e312c 6224 XPM_MASK,
333b20bb 6225 XPM_COLOR_SYMBOLS,
f20a3b7a 6226 XPM_BACKGROUND,
333b20bb
GM
6227 XPM_LAST
6228};
6229
6230/* Vector of image_keyword structures describing the format
6231 of valid XPM image specifications. */
6232
6233static struct image_keyword xpm_format[XPM_LAST] =
6234{
6235 {":type", IMAGE_SYMBOL_VALUE, 1},
6236 {":file", IMAGE_STRING_VALUE, 0},
6237 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 6238 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 6239 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 6240 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 6241 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 6242 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 6243 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
6244 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6245 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
6246};
6247
6248/* Structure describing the image type XBM. */
6249
6250static struct image_type xpm_type =
6251{
6252 &Qxpm,
6253 xpm_image_p,
6254 xpm_load,
6255 x_clear_image,
6256 NULL
6257};
6258
6259
b243755a
GM
6260/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
6261 functions for allocating image colors. Our own functions handle
6262 color allocation failures more gracefully than the ones on the XPM
6263 lib. */
6264
6265#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
6266#define ALLOC_XPM_COLORS
6267#endif
6268
6269#ifdef ALLOC_XPM_COLORS
6270
f72c62ad 6271static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
b243755a
GM
6272static void xpm_free_color_cache P_ ((void));
6273static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
f72c62ad
GM
6274static int xpm_color_bucket P_ ((char *));
6275static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
6276 XColor *, int));
b243755a
GM
6277
6278/* An entry in a hash table used to cache color definitions of named
6279 colors. This cache is necessary to speed up XPM image loading in
6280 case we do color allocations ourselves. Without it, we would need
6281 a call to XParseColor per pixel in the image. */
6282
6283struct xpm_cached_color
6284{
6285 /* Next in collision chain. */
6286 struct xpm_cached_color *next;
6287
6288 /* Color definition (RGB and pixel color). */
6289 XColor color;
6290
6291 /* Color name. */
6292 char name[1];
6293};
6294
6295/* The hash table used for the color cache, and its bucket vector
6296 size. */
6297
6298#define XPM_COLOR_CACHE_BUCKETS 1001
6299struct xpm_cached_color **xpm_color_cache;
6300
b243755a
GM
6301/* Initialize the color cache. */
6302
6303static void
f72c62ad
GM
6304xpm_init_color_cache (f, attrs)
6305 struct frame *f;
6306 XpmAttributes *attrs;
b243755a
GM
6307{
6308 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
6309 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
6310 memset (xpm_color_cache, 0, nbytes);
6311 init_color_table ();
f72c62ad
GM
6312
6313 if (attrs->valuemask & XpmColorSymbols)
6314 {
6315 int i;
6316 XColor color;
177c0ea7 6317
f72c62ad
GM
6318 for (i = 0; i < attrs->numsymbols; ++i)
6319 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
6320 attrs->colorsymbols[i].value, &color))
6321 {
6322 color.pixel = lookup_rgb_color (f, color.red, color.green,
6323 color.blue);
6324 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
6325 }
6326 }
b243755a
GM
6327}
6328
6329
6330/* Free the color cache. */
6331
6332static void
6333xpm_free_color_cache ()
6334{
6335 struct xpm_cached_color *p, *next;
6336 int i;
6337
6338 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
6339 for (p = xpm_color_cache[i]; p; p = next)
6340 {
6341 next = p->next;
6342 xfree (p);
6343 }
6344
6345 xfree (xpm_color_cache);
6346 xpm_color_cache = NULL;
6347 free_color_table ();
6348}
6349
6350
f72c62ad
GM
6351/* Return the bucket index for color named COLOR_NAME in the color
6352 cache. */
6353
6354static int
6355xpm_color_bucket (color_name)
6356 char *color_name;
6357{
6358 unsigned h = 0;
6359 char *s;
177c0ea7 6360
f72c62ad
GM
6361 for (s = color_name; *s; ++s)
6362 h = (h << 2) ^ *s;
6363 return h %= XPM_COLOR_CACHE_BUCKETS;
6364}
6365
6366
6367/* On frame F, cache values COLOR for color with name COLOR_NAME.
6368 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
6369 entry added. */
6370
6371static struct xpm_cached_color *
6372xpm_cache_color (f, color_name, color, bucket)
6373 struct frame *f;
6374 char *color_name;
6375 XColor *color;
6376 int bucket;
6377{
6378 size_t nbytes;
6379 struct xpm_cached_color *p;
177c0ea7 6380
f72c62ad
GM
6381 if (bucket < 0)
6382 bucket = xpm_color_bucket (color_name);
177c0ea7 6383
f72c62ad
GM
6384 nbytes = sizeof *p + strlen (color_name);
6385 p = (struct xpm_cached_color *) xmalloc (nbytes);
6386 strcpy (p->name, color_name);
6387 p->color = *color;
6388 p->next = xpm_color_cache[bucket];
6389 xpm_color_cache[bucket] = p;
6390 return p;
6391}
6392
6393
b243755a
GM
6394/* Look up color COLOR_NAME for frame F in the color cache. If found,
6395 return the cached definition in *COLOR. Otherwise, make a new
6396 entry in the cache and allocate the color. Value is zero if color
6397 allocation failed. */
6398
6399static int
6400xpm_lookup_color (f, color_name, color)
6401 struct frame *f;
6402 char *color_name;
6403 XColor *color;
6404{
b243755a 6405 struct xpm_cached_color *p;
83676598 6406 int h = xpm_color_bucket (color_name);
b243755a
GM
6407
6408 for (p = xpm_color_cache[h]; p; p = p->next)
6409 if (strcmp (p->name, color_name) == 0)
6410 break;
6411
6412 if (p != NULL)
6413 *color = p->color;
6414 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
6415 color_name, color))
6416 {
b243755a
GM
6417 color->pixel = lookup_rgb_color (f, color->red, color->green,
6418 color->blue);
f72c62ad 6419 p = xpm_cache_color (f, color_name, color, h);
b243755a 6420 }
9b8a0941
DL
6421 /* You get `opaque' at least from ImageMagick converting pbm to xpm
6422 with transparency, and it's useful. */
6423 else if (strcmp ("opaque", color_name) == 0)
6424 {
6425 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
6426 color->pixel = FRAME_FOREGROUND_PIXEL (f);
6427 p = xpm_cache_color (f, color_name, color, h);
6428 }
177c0ea7 6429
b243755a
GM
6430 return p != NULL;
6431}
6432
6433
6434/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
6435 CLOSURE is a pointer to the frame on which we allocate the
6436 color. Return in *COLOR the allocated color. Value is non-zero
6437 if successful. */
6438
6439static int
6440xpm_alloc_color (dpy, cmap, color_name, color, closure)
6441 Display *dpy;
6442 Colormap cmap;
6443 char *color_name;
6444 XColor *color;
6445 void *closure;
6446{
6447 return xpm_lookup_color ((struct frame *) closure, color_name, color);
6448}
6449
6450
6451/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
6452 is a pointer to the frame on which we allocate the color. Value is
6453 non-zero if successful. */
6454
6455static int
6456xpm_free_colors (dpy, cmap, pixels, npixels, closure)
6457 Display *dpy;
6458 Colormap cmap;
6459 Pixel *pixels;
6460 int npixels;
6461 void *closure;
6462{
6463 return 1;
6464}
6465
6466#endif /* ALLOC_XPM_COLORS */
6467
6468
333b20bb
GM
6469/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
6470 for XPM images. Such a list must consist of conses whose car and
6471 cdr are strings. */
6472
6473static int
6474xpm_valid_color_symbols_p (color_symbols)
6475 Lisp_Object color_symbols;
6476{
6477 while (CONSP (color_symbols))
6478 {
6479 Lisp_Object sym = XCAR (color_symbols);
6480 if (!CONSP (sym)
6481 || !STRINGP (XCAR (sym))
6482 || !STRINGP (XCDR (sym)))
6483 break;
6484 color_symbols = XCDR (color_symbols);
6485 }
6486
6487 return NILP (color_symbols);
6488}
6489
6490
6491/* Value is non-zero if OBJECT is a valid XPM image specification. */
6492
6493static int
6494xpm_image_p (object)
6495 Lisp_Object object;
6496{
6497 struct image_keyword fmt[XPM_LAST];
6498 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 6499 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
6500 /* Either `:file' or `:data' must be present. */
6501 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
6502 /* Either no `:color-symbols' or it's a list of conses
6503 whose car and cdr are strings. */
6504 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7c7ff7f5 6505 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
333b20bb
GM
6506}
6507
6508
6509/* Load image IMG which will be displayed on frame F. Value is
6510 non-zero if successful. */
6511
6512static int
6513xpm_load (f, img)
6514 struct frame *f;
6515 struct image *img;
6516{
9b207e8e 6517 int rc;
333b20bb
GM
6518 XpmAttributes attrs;
6519 Lisp_Object specified_file, color_symbols;
6520
6521 /* Configure the XPM lib. Use the visual of frame F. Allocate
6522 close colors. Return colors allocated. */
6523 bzero (&attrs, sizeof attrs);
9b2956e2
GM
6524 attrs.visual = FRAME_X_VISUAL (f);
6525 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 6526 attrs.valuemask |= XpmVisual;
9b2956e2 6527 attrs.valuemask |= XpmColormap;
b243755a
GM
6528
6529#ifdef ALLOC_XPM_COLORS
6530 /* Allocate colors with our own functions which handle
6531 failing color allocation more gracefully. */
6532 attrs.color_closure = f;
6533 attrs.alloc_color = xpm_alloc_color;
6534 attrs.free_colors = xpm_free_colors;
6535 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
6536#else /* not ALLOC_XPM_COLORS */
6537 /* Let the XPM lib allocate colors. */
333b20bb 6538 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 6539#ifdef XpmAllocCloseColors
333b20bb
GM
6540 attrs.alloc_close_colors = 1;
6541 attrs.valuemask |= XpmAllocCloseColors;
b243755a 6542#else /* not XpmAllocCloseColors */
e4c082be
RS
6543 attrs.closeness = 600;
6544 attrs.valuemask |= XpmCloseness;
b243755a
GM
6545#endif /* not XpmAllocCloseColors */
6546#endif /* ALLOC_XPM_COLORS */
333b20bb
GM
6547
6548 /* If image specification contains symbolic color definitions, add
6549 these to `attrs'. */
6550 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
6551 if (CONSP (color_symbols))
6552 {
6553 Lisp_Object tail;
6554 XpmColorSymbol *xpm_syms;
6555 int i, size;
177c0ea7 6556
333b20bb
GM
6557 attrs.valuemask |= XpmColorSymbols;
6558
6559 /* Count number of symbols. */
6560 attrs.numsymbols = 0;
6561 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
6562 ++attrs.numsymbols;
6563
6564 /* Allocate an XpmColorSymbol array. */
6565 size = attrs.numsymbols * sizeof *xpm_syms;
6566 xpm_syms = (XpmColorSymbol *) alloca (size);
6567 bzero (xpm_syms, size);
6568 attrs.colorsymbols = xpm_syms;
6569
6570 /* Fill the color symbol array. */
6571 for (tail = color_symbols, i = 0;
6572 CONSP (tail);
6573 ++i, tail = XCDR (tail))
6574 {
6575 Lisp_Object name = XCAR (XCAR (tail));
6576 Lisp_Object color = XCDR (XCAR (tail));
d5db4077
KR
6577 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
6578 strcpy (xpm_syms[i].name, SDATA (name));
6579 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
6580 strcpy (xpm_syms[i].value, SDATA (color));
333b20bb
GM
6581 }
6582 }
6583
6584 /* Create a pixmap for the image, either from a file, or from a
6585 string buffer containing data in the same format as an XPM file. */
b243755a 6586#ifdef ALLOC_XPM_COLORS
f72c62ad 6587 xpm_init_color_cache (f, &attrs);
b243755a 6588#endif
177c0ea7 6589
333b20bb
GM
6590 specified_file = image_spec_value (img->spec, QCfile, NULL);
6591 if (STRINGP (specified_file))
6592 {
6593 Lisp_Object file = x_find_image_file (specified_file);
6594 if (!STRINGP (file))
6595 {
45158a91 6596 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
6597 return 0;
6598 }
177c0ea7 6599
333b20bb 6600 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 6601 SDATA (file), &img->pixmap, &img->mask,
333b20bb
GM
6602 &attrs);
6603 }
6604 else
6605 {
6606 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
6607 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 6608 SDATA (buffer),
333b20bb
GM
6609 &img->pixmap, &img->mask,
6610 &attrs);
6611 }
333b20bb
GM
6612
6613 if (rc == XpmSuccess)
6614 {
b243755a
GM
6615#ifdef ALLOC_XPM_COLORS
6616 img->colors = colors_in_color_table (&img->ncolors);
6617#else /* not ALLOC_XPM_COLORS */
f47a9ec4
KR
6618 int i;
6619
333b20bb
GM
6620 img->ncolors = attrs.nalloc_pixels;
6621 img->colors = (unsigned long *) xmalloc (img->ncolors
6622 * sizeof *img->colors);
6623 for (i = 0; i < attrs.nalloc_pixels; ++i)
3b4ae1cc
GM
6624 {
6625 img->colors[i] = attrs.alloc_pixels[i];
6626#ifdef DEBUG_X_COLORS
6627 register_color (img->colors[i]);
6628#endif
6629 }
b243755a 6630#endif /* not ALLOC_XPM_COLORS */
333b20bb
GM
6631
6632 img->width = attrs.width;
6633 img->height = attrs.height;
6634 xassert (img->width > 0 && img->height > 0);
6635
6636 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
333b20bb 6637 XpmFreeAttributes (&attrs);
333b20bb
GM
6638 }
6639 else
6640 {
6641 switch (rc)
6642 {
6643 case XpmOpenFailed:
6644 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
6645 break;
177c0ea7 6646
333b20bb
GM
6647 case XpmFileInvalid:
6648 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
6649 break;
177c0ea7 6650
333b20bb
GM
6651 case XpmNoMemory:
6652 image_error ("Out of memory (%s)", img->spec, Qnil);
6653 break;
177c0ea7 6654
333b20bb
GM
6655 case XpmColorFailed:
6656 image_error ("Color allocation error (%s)", img->spec, Qnil);
6657 break;
177c0ea7 6658
333b20bb
GM
6659 default:
6660 image_error ("Unknown error (%s)", img->spec, Qnil);
6661 break;
6662 }
6663 }
6664
b243755a
GM
6665#ifdef ALLOC_XPM_COLORS
6666 xpm_free_color_cache ();
6667#endif
333b20bb
GM
6668 return rc == XpmSuccess;
6669}
6670
6671#endif /* HAVE_XPM != 0 */
6672
6673\f
6674/***********************************************************************
6675 Color table
6676 ***********************************************************************/
6677
6678/* An entry in the color table mapping an RGB color to a pixel color. */
6679
6680struct ct_color
6681{
6682 int r, g, b;
6683 unsigned long pixel;
6684
6685 /* Next in color table collision list. */
6686 struct ct_color *next;
6687};
6688
6689/* The bucket vector size to use. Must be prime. */
6690
6691#define CT_SIZE 101
6692
6693/* Value is a hash of the RGB color given by R, G, and B. */
6694
6695#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
6696
6697/* The color hash table. */
6698
6699struct ct_color **ct_table;
6700
6701/* Number of entries in the color table. */
6702
6703int ct_colors_allocated;
6704
333b20bb
GM
6705/* Initialize the color table. */
6706
6707static void
6708init_color_table ()
6709{
6710 int size = CT_SIZE * sizeof (*ct_table);
6711 ct_table = (struct ct_color **) xmalloc (size);
6712 bzero (ct_table, size);
6713 ct_colors_allocated = 0;
6714}
6715
6716
6717/* Free memory associated with the color table. */
6718
6719static void
6720free_color_table ()
6721{
6722 int i;
6723 struct ct_color *p, *next;
6724
6725 for (i = 0; i < CT_SIZE; ++i)
6726 for (p = ct_table[i]; p; p = next)
6727 {
6728 next = p->next;
6729 xfree (p);
6730 }
6731
6732 xfree (ct_table);
6733 ct_table = NULL;
6734}
6735
6736
6737/* Value is a pixel color for RGB color R, G, B on frame F. If an
6738 entry for that color already is in the color table, return the
6739 pixel color of that entry. Otherwise, allocate a new color for R,
6740 G, B, and make an entry in the color table. */
6741
6742static unsigned long
6743lookup_rgb_color (f, r, g, b)
6744 struct frame *f;
6745 int r, g, b;
6746{
6747 unsigned hash = CT_HASH_RGB (r, g, b);
6748 int i = hash % CT_SIZE;
6749 struct ct_color *p;
6750
6751 for (p = ct_table[i]; p; p = p->next)
6752 if (p->r == r && p->g == g && p->b == b)
6753 break;
6754
6755 if (p == NULL)
6756 {
6757 XColor color;
6758 Colormap cmap;
6759 int rc;
6760
6761 color.red = r;
6762 color.green = g;
6763 color.blue = b;
177c0ea7 6764
9b2956e2 6765 cmap = FRAME_X_COLORMAP (f);
d62c8769 6766 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
6767
6768 if (rc)
6769 {
6770 ++ct_colors_allocated;
177c0ea7 6771
333b20bb
GM
6772 p = (struct ct_color *) xmalloc (sizeof *p);
6773 p->r = r;
6774 p->g = g;
6775 p->b = b;
6776 p->pixel = color.pixel;
6777 p->next = ct_table[i];
6778 ct_table[i] = p;
6779 }
6780 else
6781 return FRAME_FOREGROUND_PIXEL (f);
6782 }
6783
6784 return p->pixel;
6785}
6786
6787
6788/* Look up pixel color PIXEL which is used on frame F in the color
6789 table. If not already present, allocate it. Value is PIXEL. */
6790
6791static unsigned long
6792lookup_pixel_color (f, pixel)
6793 struct frame *f;
6794 unsigned long pixel;
6795{
6796 int i = pixel % CT_SIZE;
6797 struct ct_color *p;
6798
6799 for (p = ct_table[i]; p; p = p->next)
6800 if (p->pixel == pixel)
6801 break;
6802
6803 if (p == NULL)
6804 {
6805 XColor color;
6806 Colormap cmap;
6807 int rc;
6808
9b2956e2 6809 cmap = FRAME_X_COLORMAP (f);
333b20bb 6810 color.pixel = pixel;
a31fedb7 6811 x_query_color (f, &color);
d62c8769 6812 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
6813
6814 if (rc)
6815 {
6816 ++ct_colors_allocated;
177c0ea7 6817
333b20bb
GM
6818 p = (struct ct_color *) xmalloc (sizeof *p);
6819 p->r = color.red;
6820 p->g = color.green;
6821 p->b = color.blue;
6822 p->pixel = pixel;
6823 p->next = ct_table[i];
6824 ct_table[i] = p;
6825 }
6826 else
6827 return FRAME_FOREGROUND_PIXEL (f);
6828 }
177c0ea7 6829
333b20bb
GM
6830 return p->pixel;
6831}
6832
6833
6834/* Value is a vector of all pixel colors contained in the color table,
6835 allocated via xmalloc. Set *N to the number of colors. */
6836
6837static unsigned long *
6838colors_in_color_table (n)
6839 int *n;
6840{
6841 int i, j;
6842 struct ct_color *p;
6843 unsigned long *colors;
6844
6845 if (ct_colors_allocated == 0)
6846 {
6847 *n = 0;
6848 colors = NULL;
6849 }
6850 else
6851 {
6852 colors = (unsigned long *) xmalloc (ct_colors_allocated
6853 * sizeof *colors);
6854 *n = ct_colors_allocated;
177c0ea7 6855
333b20bb
GM
6856 for (i = j = 0; i < CT_SIZE; ++i)
6857 for (p = ct_table[i]; p; p = p->next)
6858 colors[j++] = p->pixel;
6859 }
6860
6861 return colors;
6862}
6863
6864
6865\f
6866/***********************************************************************
6867 Algorithms
6868 ***********************************************************************/
6869
4a8e312c
GM
6870static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
6871static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
6872static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
6873
d2dc8167 6874/* Non-zero means draw a cross on images having `:conversion
14819cb3
GM
6875 disabled'. */
6876
6877int cross_disabled_images;
6878
4a8e312c
GM
6879/* Edge detection matrices for different edge-detection
6880 strategies. */
6881
6882static int emboss_matrix[9] = {
6883 /* x - 1 x x + 1 */
6884 2, -1, 0, /* y - 1 */
6885 -1, 0, 1, /* y */
6886 0, 1, -2 /* y + 1 */
6887};
333b20bb 6888
4a8e312c
GM
6889static int laplace_matrix[9] = {
6890 /* x - 1 x x + 1 */
6891 1, 0, 0, /* y - 1 */
6892 0, 0, 0, /* y */
6893 0, 0, -1 /* y + 1 */
6894};
333b20bb 6895
14819cb3
GM
6896/* Value is the intensity of the color whose red/green/blue values
6897 are R, G, and B. */
6898
6899#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
6900
333b20bb 6901
4a8e312c
GM
6902/* On frame F, return an array of XColor structures describing image
6903 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
6904 non-zero means also fill the red/green/blue members of the XColor
6905 structures. Value is a pointer to the array of XColors structures,
6906 allocated with xmalloc; it must be freed by the caller. */
6907
6908static XColor *
6909x_to_xcolors (f, img, rgb_p)
333b20bb 6910 struct frame *f;
4a8e312c
GM
6911 struct image *img;
6912 int rgb_p;
333b20bb 6913{
4a8e312c
GM
6914 int x, y;
6915 XColor *colors, *p;
6916 XImage *ximg;
333b20bb 6917
4a8e312c
GM
6918 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
6919
6920 /* Get the X image IMG->pixmap. */
6921 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
6922 0, 0, img->width, img->height, ~0, ZPixmap);
333b20bb 6923
4a8e312c
GM
6924 /* Fill the `pixel' members of the XColor array. I wished there
6925 were an easy and portable way to circumvent XGetPixel. */
6926 p = colors;
6927 for (y = 0; y < img->height; ++y)
6928 {
6929 XColor *row = p;
177c0ea7 6930
4a8e312c
GM
6931 for (x = 0; x < img->width; ++x, ++p)
6932 p->pixel = XGetPixel (ximg, x, y);
6933
6934 if (rgb_p)
a31fedb7 6935 x_query_colors (f, row, img->width);
4a8e312c
GM
6936 }
6937
6938 XDestroyImage (ximg);
4a8e312c 6939 return colors;
333b20bb
GM
6940}
6941
6942
4a8e312c
GM
6943/* Create IMG->pixmap from an array COLORS of XColor structures, whose
6944 RGB members are set. F is the frame on which this all happens.
6945 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
333b20bb
GM
6946
6947static void
4a8e312c 6948x_from_xcolors (f, img, colors)
333b20bb 6949 struct frame *f;
4a8e312c
GM
6950 struct image *img;
6951 XColor *colors;
333b20bb 6952{
4a8e312c
GM
6953 int x, y;
6954 XImage *oimg;
6955 Pixmap pixmap;
6956 XColor *p;
177c0ea7 6957
4a8e312c 6958 init_color_table ();
177c0ea7 6959
4a8e312c
GM
6960 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
6961 &oimg, &pixmap);
6962 p = colors;
6963 for (y = 0; y < img->height; ++y)
6964 for (x = 0; x < img->width; ++x, ++p)
6965 {
6966 unsigned long pixel;
6967 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
6968 XPutPixel (oimg, x, y, pixel);
6969 }
6970
6971 xfree (colors);
dd00328a 6972 x_clear_image_1 (f, img, 1, 0, 1);
4a8e312c
GM
6973
6974 x_put_x_image (f, oimg, pixmap, img->width, img->height);
6975 x_destroy_x_image (oimg);
6976 img->pixmap = pixmap;
6977 img->colors = colors_in_color_table (&img->ncolors);
6978 free_color_table ();
333b20bb
GM
6979}
6980
6981
4a8e312c
GM
6982/* On frame F, perform edge-detection on image IMG.
6983
6984 MATRIX is a nine-element array specifying the transformation
6985 matrix. See emboss_matrix for an example.
177c0ea7 6986
4a8e312c
GM
6987 COLOR_ADJUST is a color adjustment added to each pixel of the
6988 outgoing image. */
333b20bb
GM
6989
6990static void
4a8e312c 6991x_detect_edges (f, img, matrix, color_adjust)
333b20bb
GM
6992 struct frame *f;
6993 struct image *img;
4a8e312c 6994 int matrix[9], color_adjust;
333b20bb 6995{
4a8e312c
GM
6996 XColor *colors = x_to_xcolors (f, img, 1);
6997 XColor *new, *p;
6998 int x, y, i, sum;
333b20bb 6999
4a8e312c
GM
7000 for (i = sum = 0; i < 9; ++i)
7001 sum += abs (matrix[i]);
333b20bb 7002
4a8e312c 7003#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
333b20bb 7004
4a8e312c 7005 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
333b20bb 7006
4a8e312c
GM
7007 for (y = 0; y < img->height; ++y)
7008 {
7009 p = COLOR (new, 0, y);
7010 p->red = p->green = p->blue = 0xffff/2;
7011 p = COLOR (new, img->width - 1, y);
7012 p->red = p->green = p->blue = 0xffff/2;
7013 }
177c0ea7 7014
4a8e312c
GM
7015 for (x = 1; x < img->width - 1; ++x)
7016 {
7017 p = COLOR (new, x, 0);
7018 p->red = p->green = p->blue = 0xffff/2;
7019 p = COLOR (new, x, img->height - 1);
7020 p->red = p->green = p->blue = 0xffff/2;
7021 }
333b20bb 7022
4a8e312c 7023 for (y = 1; y < img->height - 1; ++y)
333b20bb 7024 {
4a8e312c 7025 p = COLOR (new, 1, y);
177c0ea7 7026
4a8e312c
GM
7027 for (x = 1; x < img->width - 1; ++x, ++p)
7028 {
14819cb3 7029 int r, g, b, y1, x1;
4a8e312c
GM
7030
7031 r = g = b = i = 0;
7032 for (y1 = y - 1; y1 < y + 2; ++y1)
7033 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
7034 if (matrix[i])
7035 {
7036 XColor *t = COLOR (colors, x1, y1);
7037 r += matrix[i] * t->red;
7038 g += matrix[i] * t->green;
7039 b += matrix[i] * t->blue;
7040 }
333b20bb 7041
4a8e312c
GM
7042 r = (r / sum + color_adjust) & 0xffff;
7043 g = (g / sum + color_adjust) & 0xffff;
7044 b = (b / sum + color_adjust) & 0xffff;
14819cb3 7045 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
333b20bb 7046 }
333b20bb
GM
7047 }
7048
4a8e312c
GM
7049 xfree (colors);
7050 x_from_xcolors (f, img, new);
333b20bb 7051
4a8e312c
GM
7052#undef COLOR
7053}
7054
7055
7056/* Perform the pre-defined `emboss' edge-detection on image IMG
7057 on frame F. */
7058
7059static void
7060x_emboss (f, img)
7061 struct frame *f;
7062 struct image *img;
7063{
7064 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
7065}
7066
7067
7068/* Perform the pre-defined `laplace' edge-detection on image IMG
7069 on frame F. */
7070
7071static void
7072x_laplace (f, img)
7073 struct frame *f;
7074 struct image *img;
7075{
7076 x_detect_edges (f, img, laplace_matrix, 45000);
7077}
7078
7079
7080/* Perform edge-detection on image IMG on frame F, with specified
7081 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
7082
7083 MATRIX must be either
7084
7085 - a list of at least 9 numbers in row-major form
7086 - a vector of at least 9 numbers
7087
7088 COLOR_ADJUST nil means use a default; otherwise it must be a
7089 number. */
7090
7091static void
7092x_edge_detection (f, img, matrix, color_adjust)
7093 struct frame *f;
7094 struct image *img;
7095 Lisp_Object matrix, color_adjust;
7096{
7097 int i = 0;
7098 int trans[9];
177c0ea7 7099
4a8e312c
GM
7100 if (CONSP (matrix))
7101 {
7102 for (i = 0;
7103 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
7104 ++i, matrix = XCDR (matrix))
7105 trans[i] = XFLOATINT (XCAR (matrix));
7106 }
7107 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
7108 {
7109 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
7110 trans[i] = XFLOATINT (AREF (matrix, i));
7111 }
333b20bb 7112
4a8e312c
GM
7113 if (NILP (color_adjust))
7114 color_adjust = make_number (0xffff / 2);
333b20bb 7115
4a8e312c
GM
7116 if (i == 9 && NUMBERP (color_adjust))
7117 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
333b20bb
GM
7118}
7119
7120
14819cb3
GM
7121/* Transform image IMG on frame F so that it looks disabled. */
7122
7123static void
7124x_disable_image (f, img)
7125 struct frame *f;
7126 struct image *img;
7127{
7128 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dd00328a 7129
14819cb3
GM
7130 if (dpyinfo->n_planes >= 2)
7131 {
7132 /* Color (or grayscale). Convert to gray, and equalize. Just
7133 drawing such images with a stipple can look very odd, so
7134 we're using this method instead. */
7135 XColor *colors = x_to_xcolors (f, img, 1);
7136 XColor *p, *end;
7137 const int h = 15000;
7138 const int l = 30000;
7139
7140 for (p = colors, end = colors + img->width * img->height;
7141 p < end;
7142 ++p)
7143 {
7144 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
7145 int i2 = (0xffff - h - l) * i / 0xffff + l;
7146 p->red = p->green = p->blue = i2;
7147 }
7148
7149 x_from_xcolors (f, img, colors);
7150 }
7151
7152 /* Draw a cross over the disabled image, if we must or if we
7153 should. */
7154 if (dpyinfo->n_planes < 2 || cross_disabled_images)
7155 {
7156 Display *dpy = FRAME_X_DISPLAY (f);
7157 GC gc;
7158
14819cb3
GM
7159 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
7160 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
7161 XDrawLine (dpy, img->pixmap, gc, 0, 0,
7162 img->width - 1, img->height - 1);
7163 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
7164 img->width - 1, 0);
7165 XFreeGC (dpy, gc);
7166
7167 if (img->mask)
7168 {
7169 gc = XCreateGC (dpy, img->mask, 0, NULL);
7170 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
7171 XDrawLine (dpy, img->mask, gc, 0, 0,
7172 img->width - 1, img->height - 1);
7173 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
7174 img->width - 1, 0);
7175 XFreeGC (dpy, gc);
7176 }
14819cb3
GM
7177 }
7178}
7179
7180
333b20bb
GM
7181/* Build a mask for image IMG which is used on frame F. FILE is the
7182 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
7183 determine the background color of IMG. If it is a list '(R G B)',
7184 with R, G, and B being integers >= 0, take that as the color of the
7185 background. Otherwise, determine the background color of IMG
7186 heuristically. Value is non-zero if successful. */
333b20bb
GM
7187
7188static int
45158a91 7189x_build_heuristic_mask (f, img, how)
333b20bb 7190 struct frame *f;
333b20bb
GM
7191 struct image *img;
7192 Lisp_Object how;
7193{
7194 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 7195 XImage *ximg, *mask_img;
f20a3b7a 7196 int x, y, rc, use_img_background;
8ec8a5ec 7197 unsigned long bg = 0;
333b20bb 7198
4a8e312c
GM
7199 if (img->mask)
7200 {
7201 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 7202 img->mask = None;
f20a3b7a 7203 img->background_transparent_valid = 0;
4a8e312c 7204 }
dd00328a 7205
333b20bb 7206 /* Create an image and pixmap serving as mask. */
45158a91 7207 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
7208 &mask_img, &img->mask);
7209 if (!rc)
28c7826c 7210 return 0;
333b20bb
GM
7211
7212 /* Get the X image of IMG->pixmap. */
7213 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
7214 ~0, ZPixmap);
7215
fcf431dc 7216 /* Determine the background color of ximg. If HOW is `(R G B)'
f20a3b7a
MB
7217 take that as color. Otherwise, use the image's background color. */
7218 use_img_background = 1;
177c0ea7 7219
fcf431dc
GM
7220 if (CONSP (how))
7221 {
cac1daf0 7222 int rgb[3], i;
fcf431dc 7223
cac1daf0 7224 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
fcf431dc
GM
7225 {
7226 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
7227 how = XCDR (how);
7228 }
7229
7230 if (i == 3 && NILP (how))
7231 {
7232 char color_name[30];
fcf431dc 7233 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
053b3256
GM
7234 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
7235 use_img_background = 0;
fcf431dc
GM
7236 }
7237 }
177c0ea7 7238
f20a3b7a 7239 if (use_img_background)
43f7c3ea 7240 bg = four_corners_best (ximg, img->width, img->height);
333b20bb
GM
7241
7242 /* Set all bits in mask_img to 1 whose color in ximg is different
7243 from the background color bg. */
7244 for (y = 0; y < img->height; ++y)
7245 for (x = 0; x < img->width; ++x)
7246 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
7247
f20a3b7a
MB
7248 /* Fill in the background_transparent field while we have the mask handy. */
7249 image_background_transparent (img, f, mask_img);
7250
333b20bb
GM
7251 /* Put mask_img into img->mask. */
7252 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7253 x_destroy_x_image (mask_img);
7254 XDestroyImage (ximg);
177c0ea7 7255
333b20bb
GM
7256 return 1;
7257}
7258
7259
7260\f
7261/***********************************************************************
7262 PBM (mono, gray, color)
7263 ***********************************************************************/
7264
7265static int pbm_image_p P_ ((Lisp_Object object));
7266static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 7267static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
7268
7269/* The symbol `pbm' identifying images of this type. */
7270
7271Lisp_Object Qpbm;
7272
7273/* Indices of image specification fields in gs_format, below. */
7274
7275enum pbm_keyword_index
7276{
7277 PBM_TYPE,
7278 PBM_FILE,
63cec32f 7279 PBM_DATA,
333b20bb
GM
7280 PBM_ASCENT,
7281 PBM_MARGIN,
7282 PBM_RELIEF,
7283 PBM_ALGORITHM,
7284 PBM_HEURISTIC_MASK,
4a8e312c 7285 PBM_MASK,
be0b1fac
GM
7286 PBM_FOREGROUND,
7287 PBM_BACKGROUND,
333b20bb
GM
7288 PBM_LAST
7289};
7290
7291/* Vector of image_keyword structures describing the format
7292 of valid user-defined image specifications. */
7293
7294static struct image_keyword pbm_format[PBM_LAST] =
7295{
7296 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
7297 {":file", IMAGE_STRING_VALUE, 0},
7298 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7299 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 7300 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 7301 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 7302 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 7303 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
be0b1fac 7304 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
7305 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
7306 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
7307};
7308
7309/* Structure describing the image type `pbm'. */
7310
7311static struct image_type pbm_type =
7312{
7313 &Qpbm,
7314 pbm_image_p,
7315 pbm_load,
7316 x_clear_image,
7317 NULL
7318};
7319
7320
7321/* Return non-zero if OBJECT is a valid PBM image specification. */
7322
7323static int
7324pbm_image_p (object)
7325 Lisp_Object object;
7326{
7327 struct image_keyword fmt[PBM_LAST];
177c0ea7 7328
333b20bb 7329 bcopy (pbm_format, fmt, sizeof fmt);
177c0ea7 7330
7c7ff7f5 7331 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
333b20bb 7332 return 0;
63cec32f
GM
7333
7334 /* Must specify either :data or :file. */
7335 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
7336}
7337
7338
63cec32f
GM
7339/* Scan a decimal number from *S and return it. Advance *S while
7340 reading the number. END is the end of the string. Value is -1 at
7341 end of input. */
333b20bb
GM
7342
7343static int
63cec32f
GM
7344pbm_scan_number (s, end)
7345 unsigned char **s, *end;
333b20bb 7346{
8ec8a5ec 7347 int c = 0, val = -1;
333b20bb 7348
63cec32f 7349 while (*s < end)
333b20bb
GM
7350 {
7351 /* Skip white-space. */
63cec32f 7352 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
7353 ;
7354
7355 if (c == '#')
7356 {
7357 /* Skip comment to end of line. */
63cec32f 7358 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
7359 ;
7360 }
7361 else if (isdigit (c))
7362 {
7363 /* Read decimal number. */
7364 val = c - '0';
63cec32f 7365 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
7366 val = 10 * val + c - '0';
7367 break;
7368 }
7369 else
7370 break;
7371 }
7372
7373 return val;
7374}
7375
7376
7377/* Load PBM image IMG for use on frame F. */
7378
177c0ea7 7379static int
333b20bb
GM
7380pbm_load (f, img)
7381 struct frame *f;
7382 struct image *img;
7383{
333b20bb 7384 int raw_p, x, y;
b6d7acec 7385 int width, height, max_color_idx = 0;
333b20bb
GM
7386 XImage *ximg;
7387 Lisp_Object file, specified_file;
7388 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
7389 struct gcpro gcpro1;
63cec32f
GM
7390 unsigned char *contents = NULL;
7391 unsigned char *end, *p;
7392 int size;
333b20bb
GM
7393
7394 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 7395 file = Qnil;
333b20bb 7396 GCPRO1 (file);
333b20bb 7397
63cec32f 7398 if (STRINGP (specified_file))
333b20bb 7399 {
63cec32f
GM
7400 file = x_find_image_file (specified_file);
7401 if (!STRINGP (file))
7402 {
7403 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7404 UNGCPRO;
7405 return 0;
7406 }
333b20bb 7407
d5db4077 7408 contents = slurp_file (SDATA (file), &size);
63cec32f
GM
7409 if (contents == NULL)
7410 {
7411 image_error ("Error reading `%s'", file, Qnil);
7412 UNGCPRO;
7413 return 0;
7414 }
7415
7416 p = contents;
7417 end = contents + size;
7418 }
7419 else
333b20bb 7420 {
63cec32f
GM
7421 Lisp_Object data;
7422 data = image_spec_value (img->spec, QCdata, NULL);
d5db4077
KR
7423 p = SDATA (data);
7424 end = p + SBYTES (data);
333b20bb
GM
7425 }
7426
63cec32f
GM
7427 /* Check magic number. */
7428 if (end - p < 2 || *p++ != 'P')
333b20bb 7429 {
45158a91 7430 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
7431 error:
7432 xfree (contents);
333b20bb
GM
7433 UNGCPRO;
7434 return 0;
7435 }
7436
63cec32f 7437 switch (*p++)
333b20bb
GM
7438 {
7439 case '1':
7440 raw_p = 0, type = PBM_MONO;
7441 break;
177c0ea7 7442
333b20bb
GM
7443 case '2':
7444 raw_p = 0, type = PBM_GRAY;
7445 break;
7446
7447 case '3':
7448 raw_p = 0, type = PBM_COLOR;
7449 break;
7450
7451 case '4':
7452 raw_p = 1, type = PBM_MONO;
7453 break;
177c0ea7 7454
333b20bb
GM
7455 case '5':
7456 raw_p = 1, type = PBM_GRAY;
7457 break;
177c0ea7 7458
333b20bb
GM
7459 case '6':
7460 raw_p = 1, type = PBM_COLOR;
7461 break;
7462
7463 default:
45158a91 7464 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 7465 goto error;
333b20bb
GM
7466 }
7467
7468 /* Read width, height, maximum color-component. Characters
7469 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
7470 width = pbm_scan_number (&p, end);
7471 height = pbm_scan_number (&p, end);
333b20bb
GM
7472
7473 if (type != PBM_MONO)
7474 {
63cec32f 7475 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
7476 if (raw_p && max_color_idx > 255)
7477 max_color_idx = 255;
7478 }
177c0ea7 7479
63cec32f
GM
7480 if (width < 0
7481 || height < 0
333b20bb 7482 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 7483 goto error;
333b20bb 7484
45158a91 7485 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb 7486 &ximg, &img->pixmap))
28c7826c 7487 goto error;
177c0ea7 7488
333b20bb
GM
7489 /* Initialize the color hash table. */
7490 init_color_table ();
7491
7492 if (type == PBM_MONO)
7493 {
7494 int c = 0, g;
be0b1fac
GM
7495 struct image_keyword fmt[PBM_LAST];
7496 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
7497 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
7498
7499 /* Parse the image specification. */
7500 bcopy (pbm_format, fmt, sizeof fmt);
7501 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
177c0ea7 7502
be0b1fac 7503 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
7504 if (fmt[PBM_FOREGROUND].count
7505 && STRINGP (fmt[PBM_FOREGROUND].value))
be0b1fac 7506 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6f1be3b9
GM
7507 if (fmt[PBM_BACKGROUND].count
7508 && STRINGP (fmt[PBM_BACKGROUND].value))
f20a3b7a
MB
7509 {
7510 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
7511 img->background = bg;
7512 img->background_valid = 1;
7513 }
177c0ea7 7514
333b20bb
GM
7515 for (y = 0; y < height; ++y)
7516 for (x = 0; x < width; ++x)
7517 {
7518 if (raw_p)
7519 {
7520 if ((x & 7) == 0)
63cec32f 7521 c = *p++;
333b20bb
GM
7522 g = c & 0x80;
7523 c <<= 1;
7524 }
7525 else
63cec32f 7526 g = pbm_scan_number (&p, end);
333b20bb 7527
be0b1fac 7528 XPutPixel (ximg, x, y, g ? fg : bg);
333b20bb
GM
7529 }
7530 }
7531 else
7532 {
7533 for (y = 0; y < height; ++y)
7534 for (x = 0; x < width; ++x)
7535 {
7536 int r, g, b;
177c0ea7 7537
333b20bb 7538 if (type == PBM_GRAY)
63cec32f 7539 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
7540 else if (raw_p)
7541 {
63cec32f
GM
7542 r = *p++;
7543 g = *p++;
7544 b = *p++;
333b20bb
GM
7545 }
7546 else
7547 {
63cec32f
GM
7548 r = pbm_scan_number (&p, end);
7549 g = pbm_scan_number (&p, end);
7550 b = pbm_scan_number (&p, end);
333b20bb 7551 }
177c0ea7 7552
333b20bb
GM
7553 if (r < 0 || g < 0 || b < 0)
7554 {
333b20bb
GM
7555 xfree (ximg->data);
7556 ximg->data = NULL;
7557 XDestroyImage (ximg);
45158a91
GM
7558 image_error ("Invalid pixel value in image `%s'",
7559 img->spec, Qnil);
63cec32f 7560 goto error;
333b20bb 7561 }
177c0ea7 7562
333b20bb
GM
7563 /* RGB values are now in the range 0..max_color_idx.
7564 Scale this to the range 0..0xffff supported by X. */
7565 r = (double) r * 65535 / max_color_idx;
7566 g = (double) g * 65535 / max_color_idx;
7567 b = (double) b * 65535 / max_color_idx;
7568 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7569 }
7570 }
177c0ea7 7571
333b20bb
GM
7572 /* Store in IMG->colors the colors allocated for the image, and
7573 free the color table. */
7574 img->colors = colors_in_color_table (&img->ncolors);
7575 free_color_table ();
f20a3b7a
MB
7576
7577 /* Maybe fill in the background field while we have ximg handy. */
7578 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7579 IMAGE_BACKGROUND (img, f, ximg);
177c0ea7 7580
333b20bb
GM
7581 /* Put the image into a pixmap. */
7582 x_put_x_image (f, ximg, img->pixmap, width, height);
7583 x_destroy_x_image (ximg);
177c0ea7 7584
333b20bb
GM
7585 img->width = width;
7586 img->height = height;
7587
7588 UNGCPRO;
63cec32f 7589 xfree (contents);
333b20bb
GM
7590 return 1;
7591}
7592
7593
7594\f
7595/***********************************************************************
7596 PNG
7597 ***********************************************************************/
7598
7599#if HAVE_PNG
7600
d2398db3
SM
7601#if defined HAVE_LIBPNG_PNG_H
7602# include <libpng/png.h>
34e8c597 7603#else
d2398db3 7604# include <png.h>
34e8c597 7605#endif
333b20bb
GM
7606
7607/* Function prototypes. */
7608
7609static int png_image_p P_ ((Lisp_Object object));
7610static int png_load P_ ((struct frame *f, struct image *img));
7611
7612/* The symbol `png' identifying images of this type. */
7613
7614Lisp_Object Qpng;
7615
7616/* Indices of image specification fields in png_format, below. */
7617
7618enum png_keyword_index
7619{
7620 PNG_TYPE,
63448a4d 7621 PNG_DATA,
333b20bb
GM
7622 PNG_FILE,
7623 PNG_ASCENT,
7624 PNG_MARGIN,
7625 PNG_RELIEF,
7626 PNG_ALGORITHM,
7627 PNG_HEURISTIC_MASK,
4a8e312c 7628 PNG_MASK,
f20a3b7a 7629 PNG_BACKGROUND,
333b20bb
GM
7630 PNG_LAST
7631};
7632
7633/* Vector of image_keyword structures describing the format
7634 of valid user-defined image specifications. */
7635
7636static struct image_keyword png_format[PNG_LAST] =
7637{
7638 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 7639 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 7640 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7641 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 7642 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 7643 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 7644 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 7645 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 7646 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a 7647 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
7648};
7649
06482119 7650/* Structure describing the image type `png'. */
333b20bb
GM
7651
7652static struct image_type png_type =
7653{
7654 &Qpng,
7655 png_image_p,
7656 png_load,
7657 x_clear_image,
7658 NULL
7659};
7660
7661
7662/* Return non-zero if OBJECT is a valid PNG image specification. */
7663
7664static int
7665png_image_p (object)
7666 Lisp_Object object;
7667{
7668 struct image_keyword fmt[PNG_LAST];
7669 bcopy (png_format, fmt, sizeof fmt);
177c0ea7 7670
7c7ff7f5 7671 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
333b20bb 7672 return 0;
63448a4d 7673
63cec32f
GM
7674 /* Must specify either the :data or :file keyword. */
7675 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
7676}
7677
7678
7679/* Error and warning handlers installed when the PNG library
7680 is initialized. */
7681
7682static void
7683my_png_error (png_ptr, msg)
7684 png_struct *png_ptr;
7685 char *msg;
7686{
7687 xassert (png_ptr != NULL);
7688 image_error ("PNG error: %s", build_string (msg), Qnil);
7689 longjmp (png_ptr->jmpbuf, 1);
7690}
7691
7692
7693static void
7694my_png_warning (png_ptr, msg)
7695 png_struct *png_ptr;
7696 char *msg;
7697{
7698 xassert (png_ptr != NULL);
7699 image_error ("PNG warning: %s", build_string (msg), Qnil);
7700}
7701
5ad6a5fb
GM
7702/* Memory source for PNG decoding. */
7703
63448a4d
WP
7704struct png_memory_storage
7705{
5ad6a5fb
GM
7706 unsigned char *bytes; /* The data */
7707 size_t len; /* How big is it? */
7708 int index; /* Where are we? */
63448a4d
WP
7709};
7710
5ad6a5fb
GM
7711
7712/* Function set as reader function when reading PNG image from memory.
7713 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
7714 bytes from the input to DATA. */
7715
63448a4d 7716static void
5ad6a5fb
GM
7717png_read_from_memory (png_ptr, data, length)
7718 png_structp png_ptr;
7719 png_bytep data;
7720 png_size_t length;
63448a4d 7721{
5ad6a5fb
GM
7722 struct png_memory_storage *tbr
7723 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 7724
5ad6a5fb
GM
7725 if (length > tbr->len - tbr->index)
7726 png_error (png_ptr, "Read error");
177c0ea7 7727
5ad6a5fb
GM
7728 bcopy (tbr->bytes + tbr->index, data, length);
7729 tbr->index = tbr->index + length;
63448a4d 7730}
333b20bb
GM
7731
7732/* Load PNG image IMG for use on frame F. Value is non-zero if
7733 successful. */
7734
7735static int
7736png_load (f, img)
7737 struct frame *f;
7738 struct image *img;
7739{
7740 Lisp_Object file, specified_file;
63448a4d 7741 Lisp_Object specified_data;
b6d7acec 7742 int x, y, i;
333b20bb
GM
7743 XImage *ximg, *mask_img = NULL;
7744 struct gcpro gcpro1;
7745 png_struct *png_ptr = NULL;
7746 png_info *info_ptr = NULL, *end_info = NULL;
8ec8a5ec 7747 FILE *volatile fp = NULL;
333b20bb 7748 png_byte sig[8];
8ec8a5ec
GM
7749 png_byte * volatile pixels = NULL;
7750 png_byte ** volatile rows = NULL;
333b20bb
GM
7751 png_uint_32 width, height;
7752 int bit_depth, color_type, interlace_type;
7753 png_byte channels;
7754 png_uint_32 row_bytes;
7755 int transparent_p;
8972820c 7756 double screen_gamma;
63448a4d 7757 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
7758
7759 /* Find out what file to load. */
7760 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 7761 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
7762 file = Qnil;
7763 GCPRO1 (file);
333b20bb 7764
63448a4d 7765 if (NILP (specified_data))
5ad6a5fb
GM
7766 {
7767 file = x_find_image_file (specified_file);
7768 if (!STRINGP (file))
63448a4d 7769 {
45158a91 7770 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
7771 UNGCPRO;
7772 return 0;
7773 }
333b20bb 7774
5ad6a5fb 7775 /* Open the image file. */
d5db4077 7776 fp = fopen (SDATA (file), "rb");
5ad6a5fb
GM
7777 if (!fp)
7778 {
45158a91 7779 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
7780 UNGCPRO;
7781 fclose (fp);
7782 return 0;
7783 }
63448a4d 7784
5ad6a5fb
GM
7785 /* Check PNG signature. */
7786 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7787 || !png_check_sig (sig, sizeof sig))
7788 {
45158a91 7789 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
7790 UNGCPRO;
7791 fclose (fp);
7792 return 0;
63448a4d 7793 }
5ad6a5fb 7794 }
63448a4d 7795 else
5ad6a5fb
GM
7796 {
7797 /* Read from memory. */
d5db4077
KR
7798 tbr.bytes = SDATA (specified_data);
7799 tbr.len = SBYTES (specified_data);
5ad6a5fb 7800 tbr.index = 0;
63448a4d 7801
5ad6a5fb
GM
7802 /* Check PNG signature. */
7803 if (tbr.len < sizeof sig
7804 || !png_check_sig (tbr.bytes, sizeof sig))
7805 {
45158a91 7806 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
7807 UNGCPRO;
7808 return 0;
63448a4d 7809 }
333b20bb 7810
5ad6a5fb
GM
7811 /* Need to skip past the signature. */
7812 tbr.bytes += sizeof (sig);
7813 }
7814
333b20bb
GM
7815 /* Initialize read and info structs for PNG lib. */
7816 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
7817 my_png_error, my_png_warning);
7818 if (!png_ptr)
7819 {
63448a4d 7820 if (fp) fclose (fp);
333b20bb
GM
7821 UNGCPRO;
7822 return 0;
7823 }
7824
7825 info_ptr = png_create_info_struct (png_ptr);
7826 if (!info_ptr)
7827 {
7828 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 7829 if (fp) fclose (fp);
333b20bb
GM
7830 UNGCPRO;
7831 return 0;
7832 }
7833
7834 end_info = png_create_info_struct (png_ptr);
7835 if (!end_info)
7836 {
7837 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 7838 if (fp) fclose (fp);
333b20bb
GM
7839 UNGCPRO;
7840 return 0;
7841 }
7842
7843 /* Set error jump-back. We come back here when the PNG library
7844 detects an error. */
7845 if (setjmp (png_ptr->jmpbuf))
7846 {
7847 error:
7848 if (png_ptr)
7849 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7850 xfree (pixels);
7851 xfree (rows);
63448a4d 7852 if (fp) fclose (fp);
333b20bb
GM
7853 UNGCPRO;
7854 return 0;
7855 }
7856
7857 /* Read image info. */
63448a4d 7858 if (!NILP (specified_data))
5ad6a5fb 7859 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 7860 else
5ad6a5fb 7861 png_init_io (png_ptr, fp);
63448a4d 7862
333b20bb
GM
7863 png_set_sig_bytes (png_ptr, sizeof sig);
7864 png_read_info (png_ptr, info_ptr);
7865 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
7866 &interlace_type, NULL, NULL);
7867
177c0ea7 7868 /* If image contains simply transparency data, we prefer to
333b20bb
GM
7869 construct a clipping mask. */
7870 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
7871 transparent_p = 1;
7872 else
7873 transparent_p = 0;
7874
177c0ea7 7875 /* This function is easier to write if we only have to handle
333b20bb
GM
7876 one data format: RGB or RGBA with 8 bits per channel. Let's
7877 transform other formats into that format. */
7878
7879 /* Strip more than 8 bits per channel. */
7880 if (bit_depth == 16)
7881 png_set_strip_16 (png_ptr);
7882
7883 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
7884 if available. */
7885 png_set_expand (png_ptr);
7886
7887 /* Convert grayscale images to RGB. */
177c0ea7 7888 if (color_type == PNG_COLOR_TYPE_GRAY
333b20bb
GM
7889 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7890 png_set_gray_to_rgb (png_ptr);
7891
d4405ed7 7892 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
333b20bb 7893
bfa261c0 7894#if 0 /* Avoid double gamma correction for PNG images. */
8972820c
SM
7895 { /* Tell the PNG lib to handle gamma correction for us. */
7896 int intent;
7897 double image_gamma;
6c1aa34d 7898#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
8972820c
SM
7899 if (png_get_sRGB (png_ptr, info_ptr, &intent))
7900 /* The libpng documentation says this is right in this case. */
7901 png_set_gamma (png_ptr, screen_gamma, 0.45455);
7902 else
6c1aa34d 7903#endif
8972820c
SM
7904 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
7905 /* Image contains gamma information. */
7906 png_set_gamma (png_ptr, screen_gamma, image_gamma);
7907 else
7908 /* Use the standard default for the image gamma. */
7909 png_set_gamma (png_ptr, screen_gamma, 0.45455);
7910 }
7273d100 7911#endif /* if 0 */
333b20bb
GM
7912
7913 /* Handle alpha channel by combining the image with a background
7914 color. Do this only if a real alpha channel is supplied. For
7915 simple transparency, we prefer a clipping mask. */
7916 if (!transparent_p)
7917 {
f20a3b7a
MB
7918 png_color_16 *image_bg;
7919 Lisp_Object specified_bg
7920 = image_spec_value (img->spec, QCbackground, NULL);
7921
f2f0a644 7922 if (STRINGP (specified_bg))
f20a3b7a
MB
7923 /* The user specified `:background', use that. */
7924 {
7925 XColor color;
d5db4077 7926 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
f20a3b7a
MB
7927 {
7928 png_color_16 user_bg;
7929
7930 bzero (&user_bg, sizeof user_bg);
7931 user_bg.red = color.red;
7932 user_bg.green = color.green;
7933 user_bg.blue = color.blue;
333b20bb 7934
f20a3b7a
MB
7935 png_set_background (png_ptr, &user_bg,
7936 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7937 }
7938 }
7939 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
177c0ea7 7940 /* Image contains a background color with which to
333b20bb 7941 combine the image. */
f20a3b7a 7942 png_set_background (png_ptr, image_bg,
333b20bb
GM
7943 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
7944 else
7945 {
7946 /* Image does not contain a background color with which
177c0ea7 7947 to combine the image data via an alpha channel. Use
333b20bb
GM
7948 the frame's background instead. */
7949 XColor color;
7950 Colormap cmap;
7951 png_color_16 frame_background;
7952
9b2956e2 7953 cmap = FRAME_X_COLORMAP (f);
333b20bb 7954 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a31fedb7 7955 x_query_color (f, &color);
333b20bb
GM
7956
7957 bzero (&frame_background, sizeof frame_background);
7958 frame_background.red = color.red;
7959 frame_background.green = color.green;
7960 frame_background.blue = color.blue;
7961
7962 png_set_background (png_ptr, &frame_background,
7963 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7964 }
7965 }
7966
7967 /* Update info structure. */
7968 png_read_update_info (png_ptr, info_ptr);
7969
7970 /* Get number of channels. Valid values are 1 for grayscale images
7971 and images with a palette, 2 for grayscale images with transparency
7972 information (alpha channel), 3 for RGB images, and 4 for RGB
7973 images with alpha channel, i.e. RGBA. If conversions above were
7974 sufficient we should only have 3 or 4 channels here. */
7975 channels = png_get_channels (png_ptr, info_ptr);
7976 xassert (channels == 3 || channels == 4);
7977
7978 /* Number of bytes needed for one row of the image. */
7979 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
7980
7981 /* Allocate memory for the image. */
7982 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
7983 rows = (png_byte **) xmalloc (height * sizeof *rows);
7984 for (i = 0; i < height; ++i)
7985 rows[i] = pixels + i * row_bytes;
7986
7987 /* Read the entire image. */
7988 png_read_image (png_ptr, rows);
7989 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
7990 if (fp)
7991 {
7992 fclose (fp);
7993 fp = NULL;
7994 }
177c0ea7 7995
333b20bb 7996 /* Create the X image and pixmap. */
45158a91 7997 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb 7998 &img->pixmap))
28c7826c 7999 goto error;
177c0ea7 8000
333b20bb
GM
8001 /* Create an image and pixmap serving as mask if the PNG image
8002 contains an alpha channel. */
8003 if (channels == 4
8004 && !transparent_p
45158a91 8005 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
8006 &mask_img, &img->mask))
8007 {
8008 x_destroy_x_image (ximg);
8009 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 8010 img->pixmap = None;
333b20bb
GM
8011 goto error;
8012 }
8013
8014 /* Fill the X image and mask from PNG data. */
8015 init_color_table ();
8016
8017 for (y = 0; y < height; ++y)
8018 {
8019 png_byte *p = rows[y];
8020
8021 for (x = 0; x < width; ++x)
8022 {
8023 unsigned r, g, b;
8024
8025 r = *p++ << 8;
8026 g = *p++ << 8;
8027 b = *p++ << 8;
8028 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8029
8030 /* An alpha channel, aka mask channel, associates variable
177c0ea7
JB
8031 transparency with an image. Where other image formats
8032 support binary transparency---fully transparent or fully
333b20bb
GM
8033 opaque---PNG allows up to 254 levels of partial transparency.
8034 The PNG library implements partial transparency by combining
8035 the image with a specified background color.
8036
8037 I'm not sure how to handle this here nicely: because the
8038 background on which the image is displayed may change, for
177c0ea7
JB
8039 real alpha channel support, it would be necessary to create
8040 a new image for each possible background.
333b20bb
GM
8041
8042 What I'm doing now is that a mask is created if we have
8043 boolean transparency information. Otherwise I'm using
8044 the frame's background color to combine the image with. */
8045
8046 if (channels == 4)
8047 {
8048 if (mask_img)
8049 XPutPixel (mask_img, x, y, *p > 0);
8050 ++p;
8051 }
8052 }
8053 }
8054
f20a3b7a
MB
8055 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8056 /* Set IMG's background color from the PNG image, unless the user
8057 overrode it. */
8058 {
8059 png_color_16 *bg;
8060 if (png_get_bKGD (png_ptr, info_ptr, &bg))
8061 {
f2f0a644 8062 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
f20a3b7a
MB
8063 img->background_valid = 1;
8064 }
8065 }
8066
333b20bb
GM
8067 /* Remember colors allocated for this image. */
8068 img->colors = colors_in_color_table (&img->ncolors);
8069 free_color_table ();
8070
8071 /* Clean up. */
8072 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8073 xfree (rows);
8074 xfree (pixels);
8075
8076 img->width = width;
8077 img->height = height;
8078
f20a3b7a
MB
8079 /* Maybe fill in the background field while we have ximg handy. */
8080 IMAGE_BACKGROUND (img, f, ximg);
8081
333b20bb
GM
8082 /* Put the image into the pixmap, then free the X image and its buffer. */
8083 x_put_x_image (f, ximg, img->pixmap, width, height);
8084 x_destroy_x_image (ximg);
8085
8086 /* Same for the mask. */
8087 if (mask_img)
8088 {
f20a3b7a
MB
8089 /* Fill in the background_transparent field while we have the mask
8090 handy. */
8091 image_background_transparent (img, f, mask_img);
8092
333b20bb
GM
8093 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8094 x_destroy_x_image (mask_img);
8095 }
8096
333b20bb
GM
8097 UNGCPRO;
8098 return 1;
8099}
8100
8101#endif /* HAVE_PNG != 0 */
8102
8103
8104\f
8105/***********************************************************************
8106 JPEG
8107 ***********************************************************************/
8108
8109#if HAVE_JPEG
8110
ba06aba4
GM
8111/* Work around a warning about HAVE_STDLIB_H being redefined in
8112 jconfig.h. */
8113#ifdef HAVE_STDLIB_H
8114#define HAVE_STDLIB_H_1
8115#undef HAVE_STDLIB_H
8116#endif /* HAVE_STLIB_H */
8117
333b20bb
GM
8118#include <jpeglib.h>
8119#include <jerror.h>
8120#include <setjmp.h>
8121
ba06aba4
GM
8122#ifdef HAVE_STLIB_H_1
8123#define HAVE_STDLIB_H 1
8124#endif
8125
333b20bb
GM
8126static int jpeg_image_p P_ ((Lisp_Object object));
8127static int jpeg_load P_ ((struct frame *f, struct image *img));
8128
8129/* The symbol `jpeg' identifying images of this type. */
8130
8131Lisp_Object Qjpeg;
8132
8133/* Indices of image specification fields in gs_format, below. */
8134
8135enum jpeg_keyword_index
8136{
8137 JPEG_TYPE,
8e39770a 8138 JPEG_DATA,
333b20bb
GM
8139 JPEG_FILE,
8140 JPEG_ASCENT,
8141 JPEG_MARGIN,
8142 JPEG_RELIEF,
8143 JPEG_ALGORITHM,
8144 JPEG_HEURISTIC_MASK,
4a8e312c 8145 JPEG_MASK,
f20a3b7a 8146 JPEG_BACKGROUND,
333b20bb
GM
8147 JPEG_LAST
8148};
8149
8150/* Vector of image_keyword structures describing the format
8151 of valid user-defined image specifications. */
8152
8153static struct image_keyword jpeg_format[JPEG_LAST] =
8154{
8155 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8156 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 8157 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8158 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8159 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8160 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8161 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8162 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
8163 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8164 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8165};
8166
8167/* Structure describing the image type `jpeg'. */
8168
8169static struct image_type jpeg_type =
8170{
8171 &Qjpeg,
8172 jpeg_image_p,
8173 jpeg_load,
8174 x_clear_image,
8175 NULL
8176};
8177
8178
8179/* Return non-zero if OBJECT is a valid JPEG image specification. */
8180
8181static int
8182jpeg_image_p (object)
8183 Lisp_Object object;
8184{
8185 struct image_keyword fmt[JPEG_LAST];
177c0ea7 8186
333b20bb 8187 bcopy (jpeg_format, fmt, sizeof fmt);
177c0ea7 8188
7c7ff7f5 8189 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
333b20bb 8190 return 0;
8e39770a 8191
63cec32f
GM
8192 /* Must specify either the :data or :file keyword. */
8193 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
8194}
8195
8e39770a 8196
333b20bb
GM
8197struct my_jpeg_error_mgr
8198{
8199 struct jpeg_error_mgr pub;
8200 jmp_buf setjmp_buffer;
8201};
8202
e3130015 8203
333b20bb
GM
8204static void
8205my_error_exit (cinfo)
8206 j_common_ptr cinfo;
8207{
8208 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
8209 longjmp (mgr->setjmp_buffer, 1);
8210}
8211
e3130015 8212
8e39770a
GM
8213/* Init source method for JPEG data source manager. Called by
8214 jpeg_read_header() before any data is actually read. See
8215 libjpeg.doc from the JPEG lib distribution. */
8216
8217static void
8218our_init_source (cinfo)
8219 j_decompress_ptr cinfo;
8220{
8221}
8222
8223
8224/* Fill input buffer method for JPEG data source manager. Called
8225 whenever more data is needed. We read the whole image in one step,
8226 so this only adds a fake end of input marker at the end. */
8227
8228static boolean
8229our_fill_input_buffer (cinfo)
8230 j_decompress_ptr cinfo;
8231{
8232 /* Insert a fake EOI marker. */
8233 struct jpeg_source_mgr *src = cinfo->src;
8234 static JOCTET buffer[2];
8235
8236 buffer[0] = (JOCTET) 0xFF;
8237 buffer[1] = (JOCTET) JPEG_EOI;
8238
8239 src->next_input_byte = buffer;
8240 src->bytes_in_buffer = 2;
8241 return TRUE;
8242}
8243
8244
8245/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
8246 is the JPEG data source manager. */
8247
8248static void
8249our_skip_input_data (cinfo, num_bytes)
8250 j_decompress_ptr cinfo;
8251 long num_bytes;
8252{
8253 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
8254
8255 if (src)
8256 {
8257 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 8258 ERREXIT (cinfo, JERR_INPUT_EOF);
177c0ea7 8259
8e39770a
GM
8260 src->bytes_in_buffer -= num_bytes;
8261 src->next_input_byte += num_bytes;
8262 }
8263}
8264
8265
8266/* Method to terminate data source. Called by
8267 jpeg_finish_decompress() after all data has been processed. */
8268
8269static void
8270our_term_source (cinfo)
8271 j_decompress_ptr cinfo;
8272{
8273}
8274
8275
8276/* Set up the JPEG lib for reading an image from DATA which contains
8277 LEN bytes. CINFO is the decompression info structure created for
8278 reading the image. */
8279
8280static void
8281jpeg_memory_src (cinfo, data, len)
8282 j_decompress_ptr cinfo;
8283 JOCTET *data;
8284 unsigned int len;
8285{
8286 struct jpeg_source_mgr *src;
8287
8288 if (cinfo->src == NULL)
8289 {
8290 /* First time for this JPEG object? */
8291 cinfo->src = (struct jpeg_source_mgr *)
8292 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
8293 sizeof (struct jpeg_source_mgr));
8294 src = (struct jpeg_source_mgr *) cinfo->src;
8295 src->next_input_byte = data;
8296 }
177c0ea7 8297
8e39770a
GM
8298 src = (struct jpeg_source_mgr *) cinfo->src;
8299 src->init_source = our_init_source;
8300 src->fill_input_buffer = our_fill_input_buffer;
8301 src->skip_input_data = our_skip_input_data;
8302 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
8303 src->term_source = our_term_source;
8304 src->bytes_in_buffer = len;
8305 src->next_input_byte = data;
8306}
8307
5ad6a5fb 8308
333b20bb
GM
8309/* Load image IMG for use on frame F. Patterned after example.c
8310 from the JPEG lib. */
8311
177c0ea7 8312static int
333b20bb
GM
8313jpeg_load (f, img)
8314 struct frame *f;
8315 struct image *img;
8316{
8317 struct jpeg_decompress_struct cinfo;
8318 struct my_jpeg_error_mgr mgr;
8319 Lisp_Object file, specified_file;
8e39770a 8320 Lisp_Object specified_data;
8ec8a5ec 8321 FILE * volatile fp = NULL;
333b20bb
GM
8322 JSAMPARRAY buffer;
8323 int row_stride, x, y;
8324 XImage *ximg = NULL;
b6d7acec 8325 int rc;
333b20bb
GM
8326 unsigned long *colors;
8327 int width, height;
8328 struct gcpro gcpro1;
8329
8330 /* Open the JPEG file. */
8331 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 8332 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8333 file = Qnil;
8334 GCPRO1 (file);
8e39770a 8335
8e39770a 8336 if (NILP (specified_data))
333b20bb 8337 {
8e39770a 8338 file = x_find_image_file (specified_file);
8e39770a
GM
8339 if (!STRINGP (file))
8340 {
45158a91 8341 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
8342 UNGCPRO;
8343 return 0;
8344 }
177c0ea7 8345
d5db4077 8346 fp = fopen (SDATA (file), "r");
8e39770a
GM
8347 if (fp == NULL)
8348 {
8349 image_error ("Cannot open `%s'", file, Qnil);
8350 UNGCPRO;
8351 return 0;
8352 }
333b20bb
GM
8353 }
8354
5ad6a5fb
GM
8355 /* Customize libjpeg's error handling to call my_error_exit when an
8356 error is detected. This function will perform a longjmp. */
333b20bb 8357 cinfo.err = jpeg_std_error (&mgr.pub);
14358466 8358 mgr.pub.error_exit = my_error_exit;
177c0ea7 8359
333b20bb
GM
8360 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
8361 {
5ad6a5fb
GM
8362 if (rc == 1)
8363 {
8364 /* Called from my_error_exit. Display a JPEG error. */
8365 char buffer[JMSG_LENGTH_MAX];
8366 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 8367 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
8368 build_string (buffer));
8369 }
177c0ea7 8370
333b20bb 8371 /* Close the input file and destroy the JPEG object. */
5ad6a5fb 8372 if (fp)
8ec8a5ec 8373 fclose ((FILE *) fp);
333b20bb
GM
8374 jpeg_destroy_decompress (&cinfo);
8375
5ad6a5fb
GM
8376 /* If we already have an XImage, free that. */
8377 x_destroy_x_image (ximg);
333b20bb 8378
5ad6a5fb
GM
8379 /* Free pixmap and colors. */
8380 x_clear_image (f, img);
177c0ea7 8381
5ad6a5fb
GM
8382 UNGCPRO;
8383 return 0;
333b20bb
GM
8384 }
8385
8386 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 8387 Read the JPEG image header. */
333b20bb 8388 jpeg_create_decompress (&cinfo);
8e39770a
GM
8389
8390 if (NILP (specified_data))
8ec8a5ec 8391 jpeg_stdio_src (&cinfo, (FILE *) fp);
8e39770a 8392 else
d5db4077
KR
8393 jpeg_memory_src (&cinfo, SDATA (specified_data),
8394 SBYTES (specified_data));
63448a4d 8395
333b20bb
GM
8396 jpeg_read_header (&cinfo, TRUE);
8397
8398 /* Customize decompression so that color quantization will be used.
63448a4d 8399 Start decompression. */
333b20bb
GM
8400 cinfo.quantize_colors = TRUE;
8401 jpeg_start_decompress (&cinfo);
8402 width = img->width = cinfo.output_width;
8403 height = img->height = cinfo.output_height;
8404
333b20bb 8405 /* Create X image and pixmap. */
45158a91 8406 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
28c7826c 8407 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
8408
8409 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
8410 cinfo.actual_number_of_colors has been set with the number of
8411 colors generated, and cinfo.colormap is a two-dimensional array
8412 of color indices in the range 0..cinfo.actual_number_of_colors.
8413 No more than 255 colors will be generated. */
333b20bb 8414 {
5ad6a5fb
GM
8415 int i, ir, ig, ib;
8416
8417 if (cinfo.out_color_components > 2)
8418 ir = 0, ig = 1, ib = 2;
8419 else if (cinfo.out_color_components > 1)
8420 ir = 0, ig = 1, ib = 0;
8421 else
8422 ir = 0, ig = 0, ib = 0;
8423
8424 /* Use the color table mechanism because it handles colors that
8425 cannot be allocated nicely. Such colors will be replaced with
8426 a default color, and we don't have to care about which colors
8427 can be freed safely, and which can't. */
8428 init_color_table ();
8429 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
8430 * sizeof *colors);
177c0ea7 8431
5ad6a5fb
GM
8432 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
8433 {
8434 /* Multiply RGB values with 255 because X expects RGB values
8435 in the range 0..0xffff. */
8436 int r = cinfo.colormap[ir][i] << 8;
8437 int g = cinfo.colormap[ig][i] << 8;
8438 int b = cinfo.colormap[ib][i] << 8;
8439 colors[i] = lookup_rgb_color (f, r, g, b);
8440 }
333b20bb 8441
5ad6a5fb
GM
8442 /* Remember those colors actually allocated. */
8443 img->colors = colors_in_color_table (&img->ncolors);
8444 free_color_table ();
333b20bb
GM
8445 }
8446
8447 /* Read pixels. */
8448 row_stride = width * cinfo.output_components;
8449 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 8450 row_stride, 1);
333b20bb
GM
8451 for (y = 0; y < height; ++y)
8452 {
5ad6a5fb
GM
8453 jpeg_read_scanlines (&cinfo, buffer, 1);
8454 for (x = 0; x < cinfo.output_width; ++x)
8455 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
8456 }
8457
8458 /* Clean up. */
8459 jpeg_finish_decompress (&cinfo);
8460 jpeg_destroy_decompress (&cinfo);
5ad6a5fb 8461 if (fp)
8ec8a5ec 8462 fclose ((FILE *) fp);
f20a3b7a
MB
8463
8464 /* Maybe fill in the background field while we have ximg handy. */
8465 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8466 IMAGE_BACKGROUND (img, f, ximg);
177c0ea7 8467
333b20bb
GM
8468 /* Put the image into the pixmap. */
8469 x_put_x_image (f, ximg, img->pixmap, width, height);
8470 x_destroy_x_image (ximg);
333b20bb
GM
8471 UNGCPRO;
8472 return 1;
8473}
8474
8475#endif /* HAVE_JPEG */
8476
8477
8478\f
8479/***********************************************************************
8480 TIFF
8481 ***********************************************************************/
8482
8483#if HAVE_TIFF
8484
cf4790ad 8485#include <tiffio.h>
333b20bb
GM
8486
8487static int tiff_image_p P_ ((Lisp_Object object));
8488static int tiff_load P_ ((struct frame *f, struct image *img));
8489
8490/* The symbol `tiff' identifying images of this type. */
8491
8492Lisp_Object Qtiff;
8493
8494/* Indices of image specification fields in tiff_format, below. */
8495
8496enum tiff_keyword_index
8497{
8498 TIFF_TYPE,
63448a4d 8499 TIFF_DATA,
333b20bb
GM
8500 TIFF_FILE,
8501 TIFF_ASCENT,
8502 TIFF_MARGIN,
8503 TIFF_RELIEF,
8504 TIFF_ALGORITHM,
8505 TIFF_HEURISTIC_MASK,
4a8e312c 8506 TIFF_MASK,
f20a3b7a 8507 TIFF_BACKGROUND,
333b20bb
GM
8508 TIFF_LAST
8509};
8510
8511/* Vector of image_keyword structures describing the format
8512 of valid user-defined image specifications. */
8513
8514static struct image_keyword tiff_format[TIFF_LAST] =
8515{
8516 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8517 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8518 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8519 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8520 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8521 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8522 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8523 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
8524 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8525 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8526};
8527
8528/* Structure describing the image type `tiff'. */
8529
8530static struct image_type tiff_type =
8531{
8532 &Qtiff,
8533 tiff_image_p,
8534 tiff_load,
8535 x_clear_image,
8536 NULL
8537};
8538
8539
8540/* Return non-zero if OBJECT is a valid TIFF image specification. */
8541
8542static int
8543tiff_image_p (object)
8544 Lisp_Object object;
8545{
8546 struct image_keyword fmt[TIFF_LAST];
8547 bcopy (tiff_format, fmt, sizeof fmt);
177c0ea7 8548
7c7ff7f5 8549 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
333b20bb 8550 return 0;
177c0ea7 8551
63cec32f
GM
8552 /* Must specify either the :data or :file keyword. */
8553 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
8554}
8555
5ad6a5fb
GM
8556
8557/* Reading from a memory buffer for TIFF images Based on the PNG
8558 memory source, but we have to provide a lot of extra functions.
8559 Blah.
63448a4d
WP
8560
8561 We really only need to implement read and seek, but I am not
8562 convinced that the TIFF library is smart enough not to destroy
8563 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
8564 override. */
8565
8566typedef struct
8567{
63448a4d
WP
8568 unsigned char *bytes;
8569 size_t len;
8570 int index;
5ad6a5fb
GM
8571}
8572tiff_memory_source;
63448a4d 8573
e3130015 8574
5ad6a5fb
GM
8575static size_t
8576tiff_read_from_memory (data, buf, size)
8577 thandle_t data;
8578 tdata_t buf;
8579 tsize_t size;
63448a4d 8580{
5ad6a5fb 8581 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
8582
8583 if (size > src->len - src->index)
5ad6a5fb
GM
8584 return (size_t) -1;
8585 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
8586 src->index += size;
8587 return size;
8588}
8589
e3130015 8590
5ad6a5fb
GM
8591static size_t
8592tiff_write_from_memory (data, buf, size)
8593 thandle_t data;
8594 tdata_t buf;
8595 tsize_t size;
63448a4d
WP
8596{
8597 return (size_t) -1;
8598}
8599
e3130015 8600
5ad6a5fb
GM
8601static toff_t
8602tiff_seek_in_memory (data, off, whence)
8603 thandle_t data;
8604 toff_t off;
8605 int whence;
63448a4d 8606{
5ad6a5fb 8607 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
8608 int idx;
8609
8610 switch (whence)
5ad6a5fb
GM
8611 {
8612 case SEEK_SET: /* Go from beginning of source. */
8613 idx = off;
8614 break;
177c0ea7 8615
5ad6a5fb
GM
8616 case SEEK_END: /* Go from end of source. */
8617 idx = src->len + off;
8618 break;
177c0ea7 8619
5ad6a5fb
GM
8620 case SEEK_CUR: /* Go from current position. */
8621 idx = src->index + off;
8622 break;
177c0ea7 8623
5ad6a5fb
GM
8624 default: /* Invalid `whence'. */
8625 return -1;
8626 }
177c0ea7 8627
5ad6a5fb
GM
8628 if (idx > src->len || idx < 0)
8629 return -1;
177c0ea7 8630
63448a4d
WP
8631 src->index = idx;
8632 return src->index;
8633}
8634
e3130015 8635
5ad6a5fb
GM
8636static int
8637tiff_close_memory (data)
8638 thandle_t data;
63448a4d
WP
8639{
8640 /* NOOP */
5ad6a5fb 8641 return 0;
63448a4d
WP
8642}
8643
e3130015 8644
5ad6a5fb
GM
8645static int
8646tiff_mmap_memory (data, pbase, psize)
8647 thandle_t data;
8648 tdata_t *pbase;
8649 toff_t *psize;
63448a4d
WP
8650{
8651 /* It is already _IN_ memory. */
5ad6a5fb 8652 return 0;
63448a4d
WP
8653}
8654
e3130015 8655
5ad6a5fb
GM
8656static void
8657tiff_unmap_memory (data, base, size)
8658 thandle_t data;
8659 tdata_t base;
8660 toff_t size;
63448a4d
WP
8661{
8662 /* We don't need to do this. */
63448a4d
WP
8663}
8664
e3130015 8665
5ad6a5fb
GM
8666static toff_t
8667tiff_size_of_memory (data)
8668 thandle_t data;
63448a4d 8669{
5ad6a5fb 8670 return ((tiff_memory_source *) data)->len;
63448a4d 8671}
333b20bb 8672
e3130015 8673
c6892044
GM
8674static void
8675tiff_error_handler (title, format, ap)
8676 const char *title, *format;
8677 va_list ap;
8678{
8679 char buf[512];
8680 int len;
177c0ea7 8681
c6892044
GM
8682 len = sprintf (buf, "TIFF error: %s ", title);
8683 vsprintf (buf + len, format, ap);
8684 add_to_log (buf, Qnil, Qnil);
8685}
8686
8687
8688static void
8689tiff_warning_handler (title, format, ap)
8690 const char *title, *format;
8691 va_list ap;
8692{
8693 char buf[512];
8694 int len;
177c0ea7 8695
c6892044
GM
8696 len = sprintf (buf, "TIFF warning: %s ", title);
8697 vsprintf (buf + len, format, ap);
8698 add_to_log (buf, Qnil, Qnil);
8699}
8700
8701
333b20bb
GM
8702/* Load TIFF image IMG for use on frame F. Value is non-zero if
8703 successful. */
8704
8705static int
8706tiff_load (f, img)
8707 struct frame *f;
8708 struct image *img;
8709{
8710 Lisp_Object file, specified_file;
63448a4d 8711 Lisp_Object specified_data;
333b20bb
GM
8712 TIFF *tiff;
8713 int width, height, x, y;
8714 uint32 *buf;
8715 int rc;
8716 XImage *ximg;
8717 struct gcpro gcpro1;
63448a4d 8718 tiff_memory_source memsrc;
333b20bb
GM
8719
8720 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8721 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8722 file = Qnil;
8723 GCPRO1 (file);
63448a4d 8724
c6892044
GM
8725 TIFFSetErrorHandler (tiff_error_handler);
8726 TIFFSetWarningHandler (tiff_warning_handler);
8727
63448a4d 8728 if (NILP (specified_data))
5ad6a5fb
GM
8729 {
8730 /* Read from a file */
8731 file = x_find_image_file (specified_file);
8732 if (!STRINGP (file))
63448a4d 8733 {
45158a91 8734 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
8735 UNGCPRO;
8736 return 0;
8737 }
177c0ea7 8738
5ad6a5fb 8739 /* Try to open the image file. */
d5db4077 8740 tiff = TIFFOpen (SDATA (file), "r");
5ad6a5fb
GM
8741 if (tiff == NULL)
8742 {
8743 image_error ("Cannot open `%s'", file, Qnil);
8744 UNGCPRO;
8745 return 0;
63448a4d 8746 }
5ad6a5fb 8747 }
63448a4d 8748 else
5ad6a5fb
GM
8749 {
8750 /* Memory source! */
d5db4077
KR
8751 memsrc.bytes = SDATA (specified_data);
8752 memsrc.len = SBYTES (specified_data);
5ad6a5fb
GM
8753 memsrc.index = 0;
8754
8755 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
8756 (TIFFReadWriteProc) tiff_read_from_memory,
8757 (TIFFReadWriteProc) tiff_write_from_memory,
8758 tiff_seek_in_memory,
8759 tiff_close_memory,
8760 tiff_size_of_memory,
8761 tiff_mmap_memory,
8762 tiff_unmap_memory);
8763
8764 if (!tiff)
63448a4d 8765 {
45158a91 8766 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
8767 UNGCPRO;
8768 return 0;
63448a4d 8769 }
5ad6a5fb 8770 }
333b20bb
GM
8771
8772 /* Get width and height of the image, and allocate a raster buffer
8773 of width x height 32-bit values. */
8774 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8775 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8776 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
177c0ea7 8777
333b20bb
GM
8778 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8779 TIFFClose (tiff);
8780 if (!rc)
8781 {
45158a91 8782 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
8783 xfree (buf);
8784 UNGCPRO;
8785 return 0;
8786 }
8787
333b20bb 8788 /* Create the X image and pixmap. */
45158a91 8789 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 8790 {
333b20bb
GM
8791 xfree (buf);
8792 UNGCPRO;
8793 return 0;
8794 }
8795
8796 /* Initialize the color table. */
8797 init_color_table ();
8798
8799 /* Process the pixel raster. Origin is in the lower-left corner. */
8800 for (y = 0; y < height; ++y)
8801 {
8802 uint32 *row = buf + y * width;
177c0ea7 8803
333b20bb
GM
8804 for (x = 0; x < width; ++x)
8805 {
8806 uint32 abgr = row[x];
8807 int r = TIFFGetR (abgr) << 8;
8808 int g = TIFFGetG (abgr) << 8;
8809 int b = TIFFGetB (abgr) << 8;
177c0ea7 8810 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
333b20bb
GM
8811 }
8812 }
8813
8814 /* Remember the colors allocated for the image. Free the color table. */
8815 img->colors = colors_in_color_table (&img->ncolors);
8816 free_color_table ();
177c0ea7 8817
f20a3b7a
MB
8818 img->width = width;
8819 img->height = height;
8820
8821 /* Maybe fill in the background field while we have ximg handy. */
8822 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8823 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
8824
8825 /* Put the image into the pixmap, then free the X image and its buffer. */
8826 x_put_x_image (f, ximg, img->pixmap, width, height);
8827 x_destroy_x_image (ximg);
8828 xfree (buf);
333b20bb
GM
8829
8830 UNGCPRO;
8831 return 1;
8832}
8833
8834#endif /* HAVE_TIFF != 0 */
8835
8836
8837\f
8838/***********************************************************************
8839 GIF
8840 ***********************************************************************/
8841
8842#if HAVE_GIF
8843
8844#include <gif_lib.h>
8845
8846static int gif_image_p P_ ((Lisp_Object object));
8847static int gif_load P_ ((struct frame *f, struct image *img));
8848
8849/* The symbol `gif' identifying images of this type. */
8850
8851Lisp_Object Qgif;
8852
8853/* Indices of image specification fields in gif_format, below. */
8854
8855enum gif_keyword_index
8856{
8857 GIF_TYPE,
63448a4d 8858 GIF_DATA,
333b20bb
GM
8859 GIF_FILE,
8860 GIF_ASCENT,
8861 GIF_MARGIN,
8862 GIF_RELIEF,
8863 GIF_ALGORITHM,
8864 GIF_HEURISTIC_MASK,
4a8e312c 8865 GIF_MASK,
333b20bb 8866 GIF_IMAGE,
f20a3b7a 8867 GIF_BACKGROUND,
333b20bb
GM
8868 GIF_LAST
8869};
8870
8871/* Vector of image_keyword structures describing the format
8872 of valid user-defined image specifications. */
8873
8874static struct image_keyword gif_format[GIF_LAST] =
8875{
8876 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8877 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8878 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8879 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8880 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8881 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8882 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 8883 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8884 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 8885 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
f20a3b7a 8886 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8887};
8888
8889/* Structure describing the image type `gif'. */
8890
8891static struct image_type gif_type =
8892{
8893 &Qgif,
8894 gif_image_p,
8895 gif_load,
8896 x_clear_image,
8897 NULL
8898};
8899
e3130015 8900
333b20bb
GM
8901/* Return non-zero if OBJECT is a valid GIF image specification. */
8902
8903static int
8904gif_image_p (object)
8905 Lisp_Object object;
8906{
8907 struct image_keyword fmt[GIF_LAST];
8908 bcopy (gif_format, fmt, sizeof fmt);
177c0ea7 8909
7c7ff7f5 8910 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
333b20bb 8911 return 0;
177c0ea7 8912
63cec32f
GM
8913 /* Must specify either the :data or :file keyword. */
8914 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
8915}
8916
e3130015 8917
63448a4d
WP
8918/* Reading a GIF image from memory
8919 Based on the PNG memory stuff to a certain extent. */
8920
5ad6a5fb
GM
8921typedef struct
8922{
63448a4d
WP
8923 unsigned char *bytes;
8924 size_t len;
8925 int index;
5ad6a5fb
GM
8926}
8927gif_memory_source;
63448a4d 8928
e3130015 8929
f036834a
GM
8930/* Make the current memory source available to gif_read_from_memory.
8931 It's done this way because not all versions of libungif support
8932 a UserData field in the GifFileType structure. */
8933static gif_memory_source *current_gif_memory_src;
8934
5ad6a5fb
GM
8935static int
8936gif_read_from_memory (file, buf, len)
8937 GifFileType *file;
8938 GifByteType *buf;
8939 int len;
63448a4d 8940{
f036834a 8941 gif_memory_source *src = current_gif_memory_src;
63448a4d 8942
5ad6a5fb
GM
8943 if (len > src->len - src->index)
8944 return -1;
63448a4d 8945
5ad6a5fb 8946 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
8947 src->index += len;
8948 return len;
8949}
333b20bb 8950
5ad6a5fb 8951
333b20bb
GM
8952/* Load GIF image IMG for use on frame F. Value is non-zero if
8953 successful. */
8954
8955static int
8956gif_load (f, img)
8957 struct frame *f;
8958 struct image *img;
8959{
8960 Lisp_Object file, specified_file;
63448a4d 8961 Lisp_Object specified_data;
333b20bb
GM
8962 int rc, width, height, x, y, i;
8963 XImage *ximg;
8964 ColorMapObject *gif_color_map;
8965 unsigned long pixel_colors[256];
8966 GifFileType *gif;
8967 struct gcpro gcpro1;
8968 Lisp_Object image;
8969 int ino, image_left, image_top, image_width, image_height;
63448a4d 8970 gif_memory_source memsrc;
9b784e96 8971 unsigned char *raster;
333b20bb
GM
8972
8973 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8974 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8975 file = Qnil;
8976 GCPRO1 (file);
63448a4d
WP
8977
8978 if (NILP (specified_data))
5ad6a5fb
GM
8979 {
8980 file = x_find_image_file (specified_file);
8981 if (!STRINGP (file))
63448a4d 8982 {
45158a91 8983 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8984 UNGCPRO;
8985 return 0;
8986 }
177c0ea7 8987
5ad6a5fb 8988 /* Open the GIF file. */
d5db4077 8989 gif = DGifOpenFileName (SDATA (file));
5ad6a5fb
GM
8990 if (gif == NULL)
8991 {
8992 image_error ("Cannot open `%s'", file, Qnil);
8993 UNGCPRO;
8994 return 0;
63448a4d 8995 }
5ad6a5fb 8996 }
63448a4d 8997 else
5ad6a5fb
GM
8998 {
8999 /* Read from memory! */
f036834a 9000 current_gif_memory_src = &memsrc;
d5db4077
KR
9001 memsrc.bytes = SDATA (specified_data);
9002 memsrc.len = SBYTES (specified_data);
5ad6a5fb 9003 memsrc.index = 0;
63448a4d 9004
5ad6a5fb
GM
9005 gif = DGifOpen(&memsrc, gif_read_from_memory);
9006 if (!gif)
9007 {
45158a91 9008 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
9009 UNGCPRO;
9010 return 0;
63448a4d 9011 }
5ad6a5fb 9012 }
333b20bb
GM
9013
9014 /* Read entire contents. */
9015 rc = DGifSlurp (gif);
9016 if (rc == GIF_ERROR)
9017 {
45158a91 9018 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
9019 DGifCloseFile (gif);
9020 UNGCPRO;
9021 return 0;
9022 }
9023
3ccff1e3 9024 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
9025 ino = INTEGERP (image) ? XFASTINT (image) : 0;
9026 if (ino >= gif->ImageCount)
9027 {
45158a91
GM
9028 image_error ("Invalid image number `%s' in image `%s'",
9029 image, img->spec);
333b20bb
GM
9030 DGifCloseFile (gif);
9031 UNGCPRO;
9032 return 0;
9033 }
9034
c7f07c4c
PJ
9035 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
9036 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
333b20bb 9037
333b20bb 9038 /* Create the X image and pixmap. */
45158a91 9039 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9040 {
333b20bb
GM
9041 DGifCloseFile (gif);
9042 UNGCPRO;
9043 return 0;
9044 }
177c0ea7 9045
333b20bb
GM
9046 /* Allocate colors. */
9047 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
9048 if (!gif_color_map)
9049 gif_color_map = gif->SColorMap;
9050 init_color_table ();
9051 bzero (pixel_colors, sizeof pixel_colors);
177c0ea7 9052
333b20bb
GM
9053 for (i = 0; i < gif_color_map->ColorCount; ++i)
9054 {
9055 int r = gif_color_map->Colors[i].Red << 8;
9056 int g = gif_color_map->Colors[i].Green << 8;
9057 int b = gif_color_map->Colors[i].Blue << 8;
9058 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
9059 }
9060
9061 img->colors = colors_in_color_table (&img->ncolors);
9062 free_color_table ();
9063
9064 /* Clear the part of the screen image that are not covered by
177c0ea7 9065 the image from the GIF file. Full animated GIF support
333b20bb
GM
9066 requires more than can be done here (see the gif89 spec,
9067 disposal methods). Let's simply assume that the part
9068 not covered by a sub-image is in the frame's background color. */
9069 image_top = gif->SavedImages[ino].ImageDesc.Top;
9070 image_left = gif->SavedImages[ino].ImageDesc.Left;
9071 image_width = gif->SavedImages[ino].ImageDesc.Width;
9072 image_height = gif->SavedImages[ino].ImageDesc.Height;
9073
9074 for (y = 0; y < image_top; ++y)
9075 for (x = 0; x < width; ++x)
9076 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9077
9078 for (y = image_top + image_height; y < height; ++y)
9079 for (x = 0; x < width; ++x)
9080 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9081
9082 for (y = image_top; y < image_top + image_height; ++y)
9083 {
9084 for (x = 0; x < image_left; ++x)
9085 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9086 for (x = image_left + image_width; x < width; ++x)
9087 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9088 }
9089
9b784e96
GM
9090 /* Read the GIF image into the X image. We use a local variable
9091 `raster' here because RasterBits below is a char *, and invites
9092 problems with bytes >= 0x80. */
9093 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
177c0ea7 9094
333b20bb
GM
9095 if (gif->SavedImages[ino].ImageDesc.Interlace)
9096 {
9097 static int interlace_start[] = {0, 4, 2, 1};
9098 static int interlace_increment[] = {8, 8, 4, 2};
9b207e8e 9099 int pass;
06482119
GM
9100 int row = interlace_start[0];
9101
9102 pass = 0;
333b20bb 9103
06482119 9104 for (y = 0; y < image_height; y++)
333b20bb 9105 {
06482119
GM
9106 if (row >= image_height)
9107 {
9108 row = interlace_start[++pass];
9109 while (row >= image_height)
9110 row = interlace_start[++pass];
9111 }
177c0ea7 9112
06482119
GM
9113 for (x = 0; x < image_width; x++)
9114 {
9b784e96 9115 int i = raster[(y * image_width) + x];
06482119
GM
9116 XPutPixel (ximg, x + image_left, row + image_top,
9117 pixel_colors[i]);
9118 }
177c0ea7 9119
06482119 9120 row += interlace_increment[pass];
333b20bb
GM
9121 }
9122 }
9123 else
9124 {
9125 for (y = 0; y < image_height; ++y)
9126 for (x = 0; x < image_width; ++x)
9127 {
9b784e96 9128 int i = raster[y * image_width + x];
333b20bb
GM
9129 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
9130 }
9131 }
177c0ea7 9132
333b20bb 9133 DGifCloseFile (gif);
f20a3b7a
MB
9134
9135 /* Maybe fill in the background field while we have ximg handy. */
9136 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9137 IMAGE_BACKGROUND (img, f, ximg);
177c0ea7 9138
333b20bb
GM
9139 /* Put the image into the pixmap, then free the X image and its buffer. */
9140 x_put_x_image (f, ximg, img->pixmap, width, height);
9141 x_destroy_x_image (ximg);
177c0ea7 9142
333b20bb
GM
9143 UNGCPRO;
9144 return 1;
9145}
9146
9147#endif /* HAVE_GIF != 0 */
9148
9149
9150\f
9151/***********************************************************************
9152 Ghostscript
9153 ***********************************************************************/
9154
9155static int gs_image_p P_ ((Lisp_Object object));
9156static int gs_load P_ ((struct frame *f, struct image *img));
9157static void gs_clear_image P_ ((struct frame *f, struct image *img));
9158
fcf431dc 9159/* The symbol `postscript' identifying images of this type. */
333b20bb 9160
fcf431dc 9161Lisp_Object Qpostscript;
333b20bb
GM
9162
9163/* Keyword symbols. */
9164
9165Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
9166
9167/* Indices of image specification fields in gs_format, below. */
9168
9169enum gs_keyword_index
9170{
9171 GS_TYPE,
9172 GS_PT_WIDTH,
9173 GS_PT_HEIGHT,
9174 GS_FILE,
9175 GS_LOADER,
9176 GS_BOUNDING_BOX,
9177 GS_ASCENT,
9178 GS_MARGIN,
9179 GS_RELIEF,
9180 GS_ALGORITHM,
9181 GS_HEURISTIC_MASK,
4a8e312c 9182 GS_MASK,
f20a3b7a 9183 GS_BACKGROUND,
333b20bb
GM
9184 GS_LAST
9185};
9186
9187/* Vector of image_keyword structures describing the format
9188 of valid user-defined image specifications. */
9189
9190static struct image_keyword gs_format[GS_LAST] =
9191{
9192 {":type", IMAGE_SYMBOL_VALUE, 1},
9193 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9194 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9195 {":file", IMAGE_STRING_VALUE, 1},
9196 {":loader", IMAGE_FUNCTION_VALUE, 0},
9197 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7c7ff7f5 9198 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9199 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9200 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9201 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9202 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9203 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9204 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9205};
9206
9207/* Structure describing the image type `ghostscript'. */
9208
9209static struct image_type gs_type =
9210{
fcf431dc 9211 &Qpostscript,
333b20bb
GM
9212 gs_image_p,
9213 gs_load,
9214 gs_clear_image,
9215 NULL
9216};
9217
9218
9219/* Free X resources of Ghostscript image IMG which is used on frame F. */
9220
9221static void
9222gs_clear_image (f, img)
9223 struct frame *f;
9224 struct image *img;
9225{
9226 /* IMG->data.ptr_val may contain a recorded colormap. */
9227 xfree (img->data.ptr_val);
9228 x_clear_image (f, img);
9229}
9230
9231
9232/* Return non-zero if OBJECT is a valid Ghostscript image
9233 specification. */
9234
9235static int
9236gs_image_p (object)
9237 Lisp_Object object;
9238{
9239 struct image_keyword fmt[GS_LAST];
9240 Lisp_Object tem;
9241 int i;
177c0ea7 9242
333b20bb 9243 bcopy (gs_format, fmt, sizeof fmt);
177c0ea7 9244
7c7ff7f5 9245 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
333b20bb
GM
9246 return 0;
9247
9248 /* Bounding box must be a list or vector containing 4 integers. */
9249 tem = fmt[GS_BOUNDING_BOX].value;
9250 if (CONSP (tem))
9251 {
9252 for (i = 0; i < 4; ++i, tem = XCDR (tem))
9253 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
9254 return 0;
9255 if (!NILP (tem))
9256 return 0;
9257 }
9258 else if (VECTORP (tem))
9259 {
9260 if (XVECTOR (tem)->size != 4)
9261 return 0;
9262 for (i = 0; i < 4; ++i)
9263 if (!INTEGERP (XVECTOR (tem)->contents[i]))
9264 return 0;
9265 }
9266 else
9267 return 0;
9268
9269 return 1;
9270}
9271
9272
9273/* Load Ghostscript image IMG for use on frame F. Value is non-zero
9274 if successful. */
9275
9276static int
9277gs_load (f, img)
9278 struct frame *f;
9279 struct image *img;
9280{
9281 char buffer[100];
9282 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
9283 struct gcpro gcpro1, gcpro2;
9284 Lisp_Object frame;
9285 double in_width, in_height;
9286 Lisp_Object pixel_colors = Qnil;
9287
9288 /* Compute pixel size of pixmap needed from the given size in the
9289 image specification. Sizes in the specification are in pt. 1 pt
9290 = 1/72 in, xdpi and ydpi are stored in the frame's X display
9291 info. */
9292 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
9293 in_width = XFASTINT (pt_width) / 72.0;
9294 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
9295 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
9296 in_height = XFASTINT (pt_height) / 72.0;
9297 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
9298
9299 /* Create the pixmap. */
dd00328a 9300 xassert (img->pixmap == None);
333b20bb
GM
9301 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9302 img->width, img->height,
9303 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
333b20bb
GM
9304
9305 if (!img->pixmap)
9306 {
45158a91 9307 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
9308 return 0;
9309 }
177c0ea7 9310
333b20bb
GM
9311 /* Call the loader to fill the pixmap. It returns a process object
9312 if successful. We do not record_unwind_protect here because
9313 other places in redisplay like calling window scroll functions
9314 don't either. Let the Lisp loader use `unwind-protect' instead. */
9315 GCPRO2 (window_and_pixmap_id, pixel_colors);
9316
9317 sprintf (buffer, "%lu %lu",
9318 (unsigned long) FRAME_X_WINDOW (f),
9319 (unsigned long) img->pixmap);
9320 window_and_pixmap_id = build_string (buffer);
177c0ea7 9321
333b20bb
GM
9322 sprintf (buffer, "%lu %lu",
9323 FRAME_FOREGROUND_PIXEL (f),
9324 FRAME_BACKGROUND_PIXEL (f));
9325 pixel_colors = build_string (buffer);
177c0ea7 9326
333b20bb
GM
9327 XSETFRAME (frame, f);
9328 loader = image_spec_value (img->spec, QCloader, NULL);
9329 if (NILP (loader))
9330 loader = intern ("gs-load-image");
9331
9332 img->data.lisp_val = call6 (loader, frame, img->spec,
9333 make_number (img->width),
9334 make_number (img->height),
9335 window_and_pixmap_id,
9336 pixel_colors);
9337 UNGCPRO;
9338 return PROCESSP (img->data.lisp_val);
9339}
9340
9341
9342/* Kill the Ghostscript process that was started to fill PIXMAP on
9343 frame F. Called from XTread_socket when receiving an event
9344 telling Emacs that Ghostscript has finished drawing. */
9345
9346void
9347x_kill_gs_process (pixmap, f)
9348 Pixmap pixmap;
9349 struct frame *f;
9350{
9351 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9352 int class, i;
9353 struct image *img;
9354
9355 /* Find the image containing PIXMAP. */
9356 for (i = 0; i < c->used; ++i)
9357 if (c->images[i]->pixmap == pixmap)
9358 break;
9359
daba7643
GM
9360 /* Should someone in between have cleared the image cache, for
9361 instance, give up. */
9362 if (i == c->used)
9363 return;
177c0ea7 9364
333b20bb
GM
9365 /* Kill the GS process. We should have found PIXMAP in the image
9366 cache and its image should contain a process object. */
333b20bb
GM
9367 img = c->images[i];
9368 xassert (PROCESSP (img->data.lisp_val));
9369 Fkill_process (img->data.lisp_val, Qnil);
9370 img->data.lisp_val = Qnil;
9371
9372 /* On displays with a mutable colormap, figure out the colors
9373 allocated for the image by looking at the pixels of an XImage for
9374 img->pixmap. */
383d6ffc 9375 class = FRAME_X_VISUAL (f)->class;
333b20bb
GM
9376 if (class != StaticColor && class != StaticGray && class != TrueColor)
9377 {
9378 XImage *ximg;
9379
9380 BLOCK_INPUT;
9381
9382 /* Try to get an XImage for img->pixmep. */
9383 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
9384 0, 0, img->width, img->height, ~0, ZPixmap);
9385 if (ximg)
9386 {
9387 int x, y;
177c0ea7 9388
333b20bb
GM
9389 /* Initialize the color table. */
9390 init_color_table ();
177c0ea7 9391
333b20bb
GM
9392 /* For each pixel of the image, look its color up in the
9393 color table. After having done so, the color table will
9394 contain an entry for each color used by the image. */
9395 for (y = 0; y < img->height; ++y)
9396 for (x = 0; x < img->width; ++x)
9397 {
9398 unsigned long pixel = XGetPixel (ximg, x, y);
9399 lookup_pixel_color (f, pixel);
9400 }
9401
9402 /* Record colors in the image. Free color table and XImage. */
9403 img->colors = colors_in_color_table (&img->ncolors);
9404 free_color_table ();
9405 XDestroyImage (ximg);
9406
9407#if 0 /* This doesn't seem to be the case. If we free the colors
9408 here, we get a BadAccess later in x_clear_image when
9409 freeing the colors. */
9410 /* We have allocated colors once, but Ghostscript has also
9411 allocated colors on behalf of us. So, to get the
9412 reference counts right, free them once. */
9413 if (img->ncolors)
462d5d40 9414 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
9415#endif
9416 }
9417 else
9418 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 9419 img->spec, Qnil);
177c0ea7 9420
333b20bb
GM
9421 UNBLOCK_INPUT;
9422 }
ad18ffb1
GM
9423
9424 /* Now that we have the pixmap, compute mask and transform the
9425 image if requested. */
9426 BLOCK_INPUT;
9427 postprocess_image (f, img);
9428 UNBLOCK_INPUT;
333b20bb
GM
9429}
9430
9431
9432\f
9433/***********************************************************************
9434 Window properties
9435 ***********************************************************************/
9436
9437DEFUN ("x-change-window-property", Fx_change_window_property,
9438 Sx_change_window_property, 2, 3, 0,
7ee72033 9439 doc: /* Change window property PROP to VALUE on the X window of FRAME.
c061c855 9440PROP and VALUE must be strings. FRAME nil or omitted means use the
7ee72033
MB
9441selected frame. Value is VALUE. */)
9442 (prop, value, frame)
333b20bb
GM
9443 Lisp_Object frame, prop, value;
9444{
9445 struct frame *f = check_x_frame (frame);
9446 Atom prop_atom;
9447
b7826503
PJ
9448 CHECK_STRING (prop);
9449 CHECK_STRING (value);
333b20bb
GM
9450
9451 BLOCK_INPUT;
d5db4077 9452 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
333b20bb
GM
9453 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9454 prop_atom, XA_STRING, 8, PropModeReplace,
d5db4077 9455 SDATA (value), SCHARS (value));
333b20bb
GM
9456
9457 /* Make sure the property is set when we return. */
9458 XFlush (FRAME_X_DISPLAY (f));
9459 UNBLOCK_INPUT;
9460
9461 return value;
9462}
9463
9464
9465DEFUN ("x-delete-window-property", Fx_delete_window_property,
9466 Sx_delete_window_property, 1, 2, 0,
7ee72033
MB
9467 doc: /* Remove window property PROP from X window of FRAME.
9468FRAME nil or omitted means use the selected frame. Value is PROP. */)
9469 (prop, frame)
333b20bb
GM
9470 Lisp_Object prop, frame;
9471{
9472 struct frame *f = check_x_frame (frame);
9473 Atom prop_atom;
9474
b7826503 9475 CHECK_STRING (prop);
333b20bb 9476 BLOCK_INPUT;
d5db4077 9477 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
333b20bb
GM
9478 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
9479
9480 /* Make sure the property is removed when we return. */
9481 XFlush (FRAME_X_DISPLAY (f));
9482 UNBLOCK_INPUT;
9483
9484 return prop;
9485}
9486
9487
9488DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
9489 1, 2, 0,
7ee72033 9490 doc: /* Value is the value of window property PROP on FRAME.
c061c855
GM
9491If FRAME is nil or omitted, use the selected frame. Value is nil
9492if FRAME hasn't a property with name PROP or if PROP has no string
7ee72033
MB
9493value. */)
9494 (prop, frame)
333b20bb
GM
9495 Lisp_Object prop, frame;
9496{
9497 struct frame *f = check_x_frame (frame);
9498 Atom prop_atom;
9499 int rc;
9500 Lisp_Object prop_value = Qnil;
9501 char *tmp_data = NULL;
9502 Atom actual_type;
9503 int actual_format;
9504 unsigned long actual_size, bytes_remaining;
9505
b7826503 9506 CHECK_STRING (prop);
333b20bb 9507 BLOCK_INPUT;
d5db4077 9508 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
333b20bb
GM
9509 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9510 prop_atom, 0, 0, False, XA_STRING,
9511 &actual_type, &actual_format, &actual_size,
9512 &bytes_remaining, (unsigned char **) &tmp_data);
9513 if (rc == Success)
9514 {
9515 int size = bytes_remaining;
9516
9517 XFree (tmp_data);
9518 tmp_data = NULL;
9519
9520 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9521 prop_atom, 0, bytes_remaining,
9522 False, XA_STRING,
177c0ea7
JB
9523 &actual_type, &actual_format,
9524 &actual_size, &bytes_remaining,
333b20bb 9525 (unsigned char **) &tmp_data);
4c8c7926 9526 if (rc == Success && tmp_data)
333b20bb
GM
9527 prop_value = make_string (tmp_data, size);
9528
9529 XFree (tmp_data);
9530 }
9531
9532 UNBLOCK_INPUT;
9533 return prop_value;
9534}
9535
9536
9537\f
9538/***********************************************************************
9539 Busy cursor
9540 ***********************************************************************/
9541
4ae9a85e 9542/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 9543 an hourglass cursor on all frames. */
333b20bb 9544
0af913d7 9545static struct atimer *hourglass_atimer;
333b20bb 9546
0af913d7 9547/* Non-zero means an hourglass cursor is currently shown. */
333b20bb 9548
0af913d7 9549static int hourglass_shown_p;
333b20bb 9550
0af913d7 9551/* Number of seconds to wait before displaying an hourglass cursor. */
333b20bb 9552
0af913d7 9553static Lisp_Object Vhourglass_delay;
333b20bb 9554
0af913d7 9555/* Default number of seconds to wait before displaying an hourglass
4ae9a85e
GM
9556 cursor. */
9557
0af913d7 9558#define DEFAULT_HOURGLASS_DELAY 1
4ae9a85e
GM
9559
9560/* Function prototypes. */
9561
0af913d7
GM
9562static void show_hourglass P_ ((struct atimer *));
9563static void hide_hourglass P_ ((void));
4ae9a85e
GM
9564
9565
0af913d7 9566/* Cancel a currently active hourglass timer, and start a new one. */
4ae9a85e
GM
9567
9568void
0af913d7 9569start_hourglass ()
333b20bb 9570{
4ae9a85e 9571 EMACS_TIME delay;
3caa99d3 9572 int secs, usecs = 0;
177c0ea7 9573
0af913d7 9574 cancel_hourglass ();
4ae9a85e 9575
0af913d7
GM
9576 if (INTEGERP (Vhourglass_delay)
9577 && XINT (Vhourglass_delay) > 0)
9578 secs = XFASTINT (Vhourglass_delay);
9579 else if (FLOATP (Vhourglass_delay)
9580 && XFLOAT_DATA (Vhourglass_delay) > 0)
3caa99d3
GM
9581 {
9582 Lisp_Object tem;
0af913d7 9583 tem = Ftruncate (Vhourglass_delay, Qnil);
3caa99d3 9584 secs = XFASTINT (tem);
0af913d7 9585 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
3caa99d3 9586 }
4ae9a85e 9587 else
0af913d7 9588 secs = DEFAULT_HOURGLASS_DELAY;
177c0ea7 9589
3caa99d3 9590 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
9591 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
9592 show_hourglass, NULL);
4ae9a85e
GM
9593}
9594
9595
0af913d7 9596/* Cancel the hourglass cursor timer if active, hide a busy cursor if
4ae9a85e
GM
9597 shown. */
9598
9599void
0af913d7 9600cancel_hourglass ()
4ae9a85e 9601{
0af913d7 9602 if (hourglass_atimer)
99f01f62 9603 {
0af913d7
GM
9604 cancel_atimer (hourglass_atimer);
9605 hourglass_atimer = NULL;
99f01f62 9606 }
177c0ea7 9607
0af913d7
GM
9608 if (hourglass_shown_p)
9609 hide_hourglass ();
4ae9a85e
GM
9610}
9611
9612
0af913d7
GM
9613/* Timer function of hourglass_atimer. TIMER is equal to
9614 hourglass_atimer.
4ae9a85e 9615
0af913d7
GM
9616 Display an hourglass pointer on all frames by mapping the frames'
9617 hourglass_window. Set the hourglass_p flag in the frames'
9618 output_data.x structure to indicate that an hourglass cursor is
9619 shown on the frames. */
4ae9a85e
GM
9620
9621static void
0af913d7 9622show_hourglass (timer)
4ae9a85e
GM
9623 struct atimer *timer;
9624{
9625 /* The timer implementation will cancel this timer automatically
0af913d7 9626 after this function has run. Set hourglass_atimer to null
4ae9a85e 9627 so that we know the timer doesn't have to be canceled. */
0af913d7 9628 hourglass_atimer = NULL;
4ae9a85e 9629
0af913d7 9630 if (!hourglass_shown_p)
333b20bb
GM
9631 {
9632 Lisp_Object rest, frame;
177c0ea7 9633
4ae9a85e 9634 BLOCK_INPUT;
177c0ea7 9635
333b20bb 9636 FOR_EACH_FRAME (rest, frame)
5f7a1890
GM
9637 {
9638 struct frame *f = XFRAME (frame);
177c0ea7 9639
5f7a1890
GM
9640 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
9641 {
9642 Display *dpy = FRAME_X_DISPLAY (f);
177c0ea7 9643
5f7a1890
GM
9644#ifdef USE_X_TOOLKIT
9645 if (f->output_data.x->widget)
9646#else
9647 if (FRAME_OUTER_WINDOW (f))
9648#endif
9649 {
0af913d7 9650 f->output_data.x->hourglass_p = 1;
177c0ea7 9651
0af913d7 9652 if (!f->output_data.x->hourglass_window)
5f7a1890
GM
9653 {
9654 unsigned long mask = CWCursor;
9655 XSetWindowAttributes attrs;
177c0ea7 9656
0af913d7 9657 attrs.cursor = f->output_data.x->hourglass_cursor;
177c0ea7 9658
0af913d7 9659 f->output_data.x->hourglass_window
5f7a1890
GM
9660 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
9661 0, 0, 32000, 32000, 0, 0,
9662 InputOnly,
9663 CopyFromParent,
9664 mask, &attrs);
9665 }
177c0ea7 9666
0af913d7 9667 XMapRaised (dpy, f->output_data.x->hourglass_window);
5f7a1890
GM
9668 XFlush (dpy);
9669 }
9670 }
9671 }
333b20bb 9672
0af913d7 9673 hourglass_shown_p = 1;
4ae9a85e
GM
9674 UNBLOCK_INPUT;
9675 }
333b20bb
GM
9676}
9677
9678
0af913d7
GM
9679/* Hide the hourglass pointer on all frames, if it is currently
9680 shown. */
333b20bb 9681
4ae9a85e 9682static void
0af913d7 9683hide_hourglass ()
4ae9a85e 9684{
0af913d7 9685 if (hourglass_shown_p)
333b20bb 9686 {
4ae9a85e
GM
9687 Lisp_Object rest, frame;
9688
9689 BLOCK_INPUT;
9690 FOR_EACH_FRAME (rest, frame)
333b20bb 9691 {
4ae9a85e 9692 struct frame *f = XFRAME (frame);
177c0ea7 9693
4ae9a85e
GM
9694 if (FRAME_X_P (f)
9695 /* Watch out for newly created frames. */
0af913d7 9696 && f->output_data.x->hourglass_window)
4ae9a85e 9697 {
0af913d7
GM
9698 XUnmapWindow (FRAME_X_DISPLAY (f),
9699 f->output_data.x->hourglass_window);
9700 /* Sync here because XTread_socket looks at the
9701 hourglass_p flag that is reset to zero below. */
4ae9a85e 9702 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 9703 f->output_data.x->hourglass_p = 0;
4ae9a85e 9704 }
333b20bb 9705 }
333b20bb 9706
0af913d7 9707 hourglass_shown_p = 0;
4ae9a85e
GM
9708 UNBLOCK_INPUT;
9709 }
333b20bb
GM
9710}
9711
9712
9713\f
9714/***********************************************************************
9715 Tool tips
9716 ***********************************************************************/
9717
9718static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
275841bf 9719 Lisp_Object, Lisp_Object));
06d62053 9720static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
ab452f99 9721 Lisp_Object, int, int, int *, int *));
177c0ea7 9722
44b5a125 9723/* The frame of a currently visible tooltip. */
333b20bb 9724
44b5a125 9725Lisp_Object tip_frame;
333b20bb
GM
9726
9727/* If non-nil, a timer started that hides the last tooltip when it
9728 fires. */
9729
9730Lisp_Object tip_timer;
9731Window tip_window;
9732
06d62053
GM
9733/* If non-nil, a vector of 3 elements containing the last args
9734 with which x-show-tip was called. See there. */
9735
9736Lisp_Object last_show_tip_args;
9737
d63931a2
GM
9738/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
9739
9740Lisp_Object Vx_max_tooltip_size;
9741
eaf1eea9
GM
9742
9743static Lisp_Object
9744unwind_create_tip_frame (frame)
9745 Lisp_Object frame;
9746{
c844a81a
GM
9747 Lisp_Object deleted;
9748
9749 deleted = unwind_create_frame (frame);
9750 if (EQ (deleted, Qt))
9751 {
9752 tip_window = None;
9753 tip_frame = Qnil;
9754 }
177c0ea7 9755
c844a81a 9756 return deleted;
eaf1eea9
GM
9757}
9758
9759
333b20bb 9760/* Create a frame for a tooltip on the display described by DPYINFO.
275841bf
GM
9761 PARMS is a list of frame parameters. TEXT is the string to
9762 display in the tip frame. Value is the frame.
eaf1eea9
GM
9763
9764 Note that functions called here, esp. x_default_parameter can
9765 signal errors, for instance when a specified color name is
9766 undefined. We have to make sure that we're in a consistent state
9767 when this happens. */
333b20bb
GM
9768
9769static Lisp_Object
275841bf 9770x_create_tip_frame (dpyinfo, parms, text)
333b20bb 9771 struct x_display_info *dpyinfo;
275841bf 9772 Lisp_Object parms, text;
333b20bb
GM
9773{
9774 struct frame *f;
9775 Lisp_Object frame, tem;
9776 Lisp_Object name;
333b20bb
GM
9777 long window_prompting = 0;
9778 int width, height;
331379bf 9779 int count = SPECPDL_INDEX ();
b6d7acec 9780 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb 9781 struct kboard *kb;
06d62053 9782 int face_change_count_before = face_change_count;
275841bf
GM
9783 Lisp_Object buffer;
9784 struct buffer *old_buffer;
333b20bb
GM
9785
9786 check_x ();
9787
9788 /* Use this general default value to start with until we know if
9789 this frame has a specified name. */
9790 Vx_resource_name = Vinvocation_name;
9791
9792#ifdef MULTI_KBOARD
9793 kb = dpyinfo->kboard;
9794#else
9795 kb = &the_only_kboard;
9796#endif
9797
9798 /* Get the name of the frame to use for resource lookup. */
9799 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
9800 if (!STRINGP (name)
9801 && !EQ (name, Qunbound)
9802 && !NILP (name))
9803 error ("Invalid frame name--not a string or nil");
9804 Vx_resource_name = name;
9805
9806 frame = Qnil;
9807 GCPRO3 (parms, name, frame);
44b5a125 9808 f = make_frame (1);
333b20bb 9809 XSETFRAME (frame, f);
275841bf
GM
9810
9811 buffer = Fget_buffer_create (build_string (" *tip*"));
be786000 9812 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer, Qnil);
275841bf
GM
9813 old_buffer = current_buffer;
9814 set_buffer_internal_1 (XBUFFER (buffer));
d63931a2 9815 current_buffer->truncate_lines = Qnil;
275841bf
GM
9816 Ferase_buffer ();
9817 Finsert (1, &text);
9818 set_buffer_internal_1 (old_buffer);
177c0ea7 9819
333b20bb 9820 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
8a1a7743 9821 record_unwind_protect (unwind_create_tip_frame, frame);
333b20bb 9822
eaf1eea9
GM
9823 /* By setting the output method, we're essentially saying that
9824 the frame is live, as per FRAME_LIVE_P. If we get a signal
9825 from this point on, x_destroy_window might screw up reference
9826 counts etc. */
333b20bb
GM
9827 f->output_method = output_x_window;
9828 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
9829 bzero (f->output_data.x, sizeof (struct x_output));
9830 f->output_data.x->icon_bitmap = -1;
be786000 9831 FRAME_FONTSET (f) = -1;
61d461a8
GM
9832 f->output_data.x->scroll_bar_foreground_pixel = -1;
9833 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
9834#ifdef USE_TOOLKIT_SCROLL_BARS
9835 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
9836 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
9837#endif /* USE_TOOLKIT_SCROLL_BARS */
333b20bb
GM
9838 f->icon_name = Qnil;
9839 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 9840#if GLYPH_DEBUG
eaf1eea9
GM
9841 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
9842 dpyinfo_refcount = dpyinfo->reference_count;
9843#endif /* GLYPH_DEBUG */
333b20bb
GM
9844#ifdef MULTI_KBOARD
9845 FRAME_KBOARD (f) = kb;
9846#endif
9847 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
9848 f->output_data.x->explicit_parent = 0;
9849
61d461a8
GM
9850 /* These colors will be set anyway later, but it's important
9851 to get the color reference counts right, so initialize them! */
9852 {
9853 Lisp_Object black;
9854 struct gcpro gcpro1;
177c0ea7 9855
61d461a8
GM
9856 black = build_string ("black");
9857 GCPRO1 (black);
9858 f->output_data.x->foreground_pixel
9859 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
9860 f->output_data.x->background_pixel
9861 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
9862 f->output_data.x->cursor_pixel
9863 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
9864 f->output_data.x->cursor_foreground_pixel
9865 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
9866 f->output_data.x->border_pixel
9867 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
9868 f->output_data.x->mouse_pixel
9869 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
9870 UNGCPRO;
9871 }
9872
333b20bb
GM
9873 /* Set the name; the functions to which we pass f expect the name to
9874 be set. */
9875 if (EQ (name, Qunbound) || NILP (name))
9876 {
9877 f->name = build_string (dpyinfo->x_id_name);
9878 f->explicit_name = 0;
9879 }
9880 else
9881 {
9882 f->name = name;
9883 f->explicit_name = 1;
9884 /* use the frame's title when getting resources for this frame. */
9885 specbind (Qx_resource_name, name);
9886 }
9887
eaf1eea9
GM
9888 /* Extract the window parameters from the supplied values that are
9889 needed to determine window geometry. */
333b20bb
GM
9890 {
9891 Lisp_Object font;
9892
9893 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
9894
9895 BLOCK_INPUT;
9896 /* First, try whatever font the caller has specified. */
9897 if (STRINGP (font))
9898 {
9899 tem = Fquery_fontset (font, Qnil);
9900 if (STRINGP (tem))
d5db4077 9901 font = x_new_fontset (f, SDATA (tem));
333b20bb 9902 else
d5db4077 9903 font = x_new_font (f, SDATA (font));
333b20bb 9904 }
177c0ea7 9905
333b20bb
GM
9906 /* Try out a font which we hope has bold and italic variations. */
9907 if (!STRINGP (font))
9908 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
9909 if (!STRINGP (font))
9910 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9911 if (! STRINGP (font))
9912 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9913 if (! STRINGP (font))
9914 /* This was formerly the first thing tried, but it finds too many fonts
9915 and takes too long. */
9916 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
9917 /* If those didn't work, look for something which will at least work. */
9918 if (! STRINGP (font))
9919 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
9920 UNBLOCK_INPUT;
9921 if (! STRINGP (font))
9922 font = build_string ("fixed");
9923
9924 x_default_parameter (f, parms, Qfont, font,
9925 "font", "Font", RES_TYPE_STRING);
9926 }
9927
9928 x_default_parameter (f, parms, Qborder_width, make_number (2),
9929 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
177c0ea7 9930
333b20bb
GM
9931 /* This defaults to 2 in order to match xterm. We recognize either
9932 internalBorderWidth or internalBorder (which is what xterm calls
9933 it). */
9934 if (NILP (Fassq (Qinternal_border_width, parms)))
9935 {
9936 Lisp_Object value;
9937
9938 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
9939 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
9940 if (! EQ (value, Qunbound))
9941 parms = Fcons (Fcons (Qinternal_border_width, value),
9942 parms);
9943 }
9944
9945 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
9946 "internalBorderWidth", "internalBorderWidth",
9947 RES_TYPE_NUMBER);
9948
9949 /* Also do the stuff which must be set before the window exists. */
9950 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
9951 "foreground", "Foreground", RES_TYPE_STRING);
9952 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
9953 "background", "Background", RES_TYPE_STRING);
9954 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
9955 "pointerColor", "Foreground", RES_TYPE_STRING);
9956 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
9957 "cursorColor", "Foreground", RES_TYPE_STRING);
9958 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
9959 "borderColor", "BorderColor", RES_TYPE_STRING);
9960
9961 /* Init faces before x_default_parameter is called for scroll-bar
9962 parameters because that function calls x_set_scroll_bar_width,
9963 which calls change_frame_size, which calls Fset_window_buffer,
9964 which runs hooks, which call Fvertical_motion. At the end, we
9965 end up in init_iterator with a null face cache, which should not
9966 happen. */
9967 init_frame_faces (f);
177c0ea7 9968
333b20bb 9969 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
333b20bb 9970
7c0d3ed8 9971 window_prompting = x_figure_window_size (f, parms, 0);
333b20bb 9972
333b20bb
GM
9973 {
9974 XSetWindowAttributes attrs;
9975 unsigned long mask;
177c0ea7 9976
333b20bb 9977 BLOCK_INPUT;
c51d2b5e
GM
9978 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
9979 if (DoesSaveUnders (dpyinfo->screen))
9980 mask |= CWSaveUnder;
177c0ea7 9981
9b2956e2
GM
9982 /* Window managers look at the override-redirect flag to determine
9983 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
9984 3.2.8). */
9985 attrs.override_redirect = True;
9986 attrs.save_under = True;
9987 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
9988 /* Arrange for getting MapNotify and UnmapNotify events. */
9989 attrs.event_mask = StructureNotifyMask;
9990 tip_window
9991 = FRAME_X_WINDOW (f)
9992 = XCreateWindow (FRAME_X_DISPLAY (f),
9993 FRAME_X_DISPLAY_INFO (f)->root_window,
9994 /* x, y, width, height */
9995 0, 0, 1, 1,
9996 /* Border. */
9997 1,
9998 CopyFromParent, InputOutput, CopyFromParent,
9999 mask, &attrs);
10000 UNBLOCK_INPUT;
10001 }
10002
10003 x_make_gc (f);
10004
333b20bb
GM
10005 x_default_parameter (f, parms, Qauto_raise, Qnil,
10006 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10007 x_default_parameter (f, parms, Qauto_lower, Qnil,
10008 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10009 x_default_parameter (f, parms, Qcursor_type, Qbox,
10010 "cursorType", "CursorType", RES_TYPE_SYMBOL);
10011
be786000 10012 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
333b20bb 10013 Change will not be effected unless different from the current
be786000
KS
10014 FRAME_LINES (f). */
10015 width = FRAME_COLS (f);
10016 height = FRAME_LINES (f);
10017 SET_FRAME_COLS (f, 0);
10018 FRAME_LINES (f) = 0;
8938a4fb 10019 change_frame_size (f, height, width, 1, 0, 0);
177c0ea7 10020
cd1d850f
JPW
10021 /* Add `tooltip' frame parameter's default value. */
10022 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
10023 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
10024 Qnil));
177c0ea7 10025
035d5114 10026 /* Set up faces after all frame parameters are known. This call
6801a572
GM
10027 also merges in face attributes specified for new frames.
10028
10029 Frame parameters may be changed if .Xdefaults contains
10030 specifications for the default font. For example, if there is an
10031 `Emacs.default.attributeBackground: pink', the `background-color'
10032 attribute of the frame get's set, which let's the internal border
10033 of the tooltip frame appear in pink. Prevent this. */
10034 {
10035 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
10036
10037 /* Set tip_frame here, so that */
10038 tip_frame = frame;
10039 call1 (Qface_set_after_frame_default, frame);
177c0ea7 10040
6801a572
GM
10041 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
10042 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
10043 Qnil));
10044 }
177c0ea7 10045
333b20bb
GM
10046 f->no_split = 1;
10047
10048 UNGCPRO;
10049
10050 /* It is now ok to make the frame official even if we get an error
10051 below. And the frame needs to be on Vframe_list or making it
10052 visible won't work. */
10053 Vframe_list = Fcons (frame, Vframe_list);
10054
10055 /* Now that the frame is official, it counts as a reference to
10056 its display. */
10057 FRAME_X_DISPLAY_INFO (f)->reference_count++;
10058
06d62053
GM
10059 /* Setting attributes of faces of the tooltip frame from resources
10060 and similar will increment face_change_count, which leads to the
10061 clearing of all current matrices. Since this isn't necessary
10062 here, avoid it by resetting face_change_count to the value it
10063 had before we created the tip frame. */
10064 face_change_count = face_change_count_before;
10065
eaf1eea9 10066 /* Discard the unwind_protect. */
333b20bb
GM
10067 return unbind_to (count, frame);
10068}
10069
10070
06d62053
GM
10071/* Compute where to display tip frame F. PARMS is the list of frame
10072 parameters for F. DX and DY are specified offsets from the current
ab452f99
GM
10073 location of the mouse. WIDTH and HEIGHT are the width and height
10074 of the tooltip. Return coordinates relative to the root window of
10075 the display in *ROOT_X, and *ROOT_Y. */
06d62053
GM
10076
10077static void
ab452f99 10078compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
06d62053
GM
10079 struct frame *f;
10080 Lisp_Object parms, dx, dy;
ab452f99 10081 int width, height;
06d62053
GM
10082 int *root_x, *root_y;
10083{
10084 Lisp_Object left, top;
10085 int win_x, win_y;
10086 Window root, child;
10087 unsigned pmask;
177c0ea7 10088
06d62053
GM
10089 /* User-specified position? */
10090 left = Fcdr (Fassq (Qleft, parms));
10091 top = Fcdr (Fassq (Qtop, parms));
177c0ea7 10092
06d62053
GM
10093 /* Move the tooltip window where the mouse pointer is. Resize and
10094 show it. */
570d22b0 10095 if (!INTEGERP (left) || !INTEGERP (top))
ab452f99
GM
10096 {
10097 BLOCK_INPUT;
10098 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
10099 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
10100 UNBLOCK_INPUT;
10101 }
06d62053 10102
06d62053
GM
10103 if (INTEGERP (top))
10104 *root_y = XINT (top);
ab452f99
GM
10105 else if (*root_y + XINT (dy) - height < 0)
10106 *root_y -= XINT (dy);
10107 else
10108 {
10109 *root_y -= height;
10110 *root_y += XINT (dy);
10111 }
10112
10113 if (INTEGERP (left))
10114 *root_x = XINT (left);
d682d3df
RS
10115 else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
10116 /* It fits to the right of the pointer. */
10117 *root_x += XINT (dx);
10118 else if (width + XINT (dx) <= *root_x)
10119 /* It fits to the left of the pointer. */
ab452f99
GM
10120 *root_x -= width + XINT (dx);
10121 else
d682d3df
RS
10122 /* Put it left-justified on the screen--it ought to fit that way. */
10123 *root_x = 0;
06d62053
GM
10124}
10125
10126
0634ce98 10127DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
7ee72033 10128 doc: /* Show STRING in a "tooltip" window on frame FRAME.
c061c855
GM
10129A tooltip window is a small X window displaying a string.
10130
10131FRAME nil or omitted means use the selected frame.
10132
10133PARMS is an optional list of frame parameters which can be used to
10134change the tooltip's appearance.
10135
10136Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
10137means use the default timeout of 5 seconds.
10138
10139If the list of frame parameters PARAMS contains a `left' parameters,
10140the tooltip is displayed at that x-position. Otherwise it is
10141displayed at the mouse position, with offset DX added (default is 5 if
10142DX isn't specified). Likewise for the y-position; if a `top' frame
10143parameter is specified, it determines the y-position of the tooltip
10144window, otherwise it is displayed at the mouse position, with offset
10145DY added (default is -10).
10146
10147A tooltip's maximum size is specified by `x-max-tooltip-size'.
7ee72033
MB
10148Text larger than the specified size is clipped. */)
10149 (string, frame, parms, timeout, dx, dy)
0634ce98 10150 Lisp_Object string, frame, parms, timeout, dx, dy;
333b20bb
GM
10151{
10152 struct frame *f;
10153 struct window *w;
06d62053 10154 int root_x, root_y;
333b20bb
GM
10155 struct buffer *old_buffer;
10156 struct text_pos pos;
10157 int i, width, height;
393f2d14 10158 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb 10159 int old_windows_or_buffers_changed = windows_or_buffers_changed;
331379bf 10160 int count = SPECPDL_INDEX ();
177c0ea7 10161
333b20bb
GM
10162 specbind (Qinhibit_redisplay, Qt);
10163
393f2d14 10164 GCPRO4 (string, parms, frame, timeout);
333b20bb 10165
b7826503 10166 CHECK_STRING (string);
333b20bb
GM
10167 f = check_x_frame (frame);
10168 if (NILP (timeout))
10169 timeout = make_number (5);
10170 else
b7826503 10171 CHECK_NATNUM (timeout);
177c0ea7 10172
0634ce98
GM
10173 if (NILP (dx))
10174 dx = make_number (5);
10175 else
b7826503 10176 CHECK_NUMBER (dx);
177c0ea7 10177
0634ce98 10178 if (NILP (dy))
12c67a7f 10179 dy = make_number (-10);
0634ce98 10180 else
b7826503 10181 CHECK_NUMBER (dy);
333b20bb 10182
06d62053
GM
10183 if (NILP (last_show_tip_args))
10184 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
10185
10186 if (!NILP (tip_frame))
10187 {
10188 Lisp_Object last_string = AREF (last_show_tip_args, 0);
10189 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
10190 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
10191
10192 if (EQ (frame, last_frame)
10193 && !NILP (Fequal (last_string, string))
10194 && !NILP (Fequal (last_parms, parms)))
10195 {
10196 struct frame *f = XFRAME (tip_frame);
177c0ea7 10197
06d62053
GM
10198 /* Only DX and DY have changed. */
10199 if (!NILP (tip_timer))
ae782866
GM
10200 {
10201 Lisp_Object timer = tip_timer;
10202 tip_timer = Qnil;
10203 call1 (Qcancel_timer, timer);
10204 }
06d62053
GM
10205
10206 BLOCK_INPUT;
be786000
KS
10207 compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
10208 FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
06d62053 10209 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 10210 root_x, root_y);
06d62053
GM
10211 UNBLOCK_INPUT;
10212 goto start_timer;
10213 }
10214 }
10215
333b20bb
GM
10216 /* Hide a previous tip, if any. */
10217 Fx_hide_tip ();
10218
06d62053
GM
10219 ASET (last_show_tip_args, 0, string);
10220 ASET (last_show_tip_args, 1, frame);
10221 ASET (last_show_tip_args, 2, parms);
10222
333b20bb
GM
10223 /* Add default values to frame parameters. */
10224 if (NILP (Fassq (Qname, parms)))
10225 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
10226 if (NILP (Fassq (Qinternal_border_width, parms)))
10227 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
10228 if (NILP (Fassq (Qborder_width, parms)))
10229 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
10230 if (NILP (Fassq (Qborder_color, parms)))
10231 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
10232 if (NILP (Fassq (Qbackground_color, parms)))
10233 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
10234 parms);
10235
10236 /* Create a frame for the tooltip, and record it in the global
10237 variable tip_frame. */
275841bf 10238 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
44b5a125 10239 f = XFRAME (frame);
333b20bb 10240
d63931a2 10241 /* Set up the frame's root window. */
333b20bb 10242 w = XWINDOW (FRAME_ROOT_WINDOW (f));
be786000 10243 w->left_col = w->top_line = make_number (0);
177c0ea7 10244
d63931a2
GM
10245 if (CONSP (Vx_max_tooltip_size)
10246 && INTEGERP (XCAR (Vx_max_tooltip_size))
10247 && XINT (XCAR (Vx_max_tooltip_size)) > 0
10248 && INTEGERP (XCDR (Vx_max_tooltip_size))
10249 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
10250 {
be786000
KS
10251 w->total_cols = XCAR (Vx_max_tooltip_size);
10252 w->total_lines = XCDR (Vx_max_tooltip_size);
d63931a2
GM
10253 }
10254 else
10255 {
be786000
KS
10256 w->total_cols = make_number (80);
10257 w->total_lines = make_number (40);
d63931a2 10258 }
177c0ea7 10259
be786000 10260 FRAME_TOTAL_COLS (f) = XINT (w->total_cols);
333b20bb
GM
10261 adjust_glyphs (f);
10262 w->pseudo_window_p = 1;
10263
10264 /* Display the tooltip text in a temporary buffer. */
333b20bb 10265 old_buffer = current_buffer;
275841bf 10266 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
d63931a2 10267 current_buffer->truncate_lines = Qnil;
333b20bb
GM
10268 clear_glyph_matrix (w->desired_matrix);
10269 clear_glyph_matrix (w->current_matrix);
10270 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
10271 try_window (FRAME_ROOT_WINDOW (f), pos);
10272
10273 /* Compute width and height of the tooltip. */
10274 width = height = 0;
10275 for (i = 0; i < w->desired_matrix->nrows; ++i)
10276 {
10277 struct glyph_row *row = &w->desired_matrix->rows[i];
10278 struct glyph *last;
10279 int row_width;
10280
10281 /* Stop at the first empty row at the end. */
10282 if (!row->enabled_p || !row->displays_text_p)
10283 break;
10284
d7bf0342
GM
10285 /* Let the row go over the full width of the frame. */
10286 row->full_width_p = 1;
333b20bb 10287
e3130015 10288 /* There's a glyph at the end of rows that is used to place
333b20bb
GM
10289 the cursor there. Don't include the width of this glyph. */
10290 if (row->used[TEXT_AREA])
10291 {
10292 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
10293 row_width = row->pixel_width - last->pixel_width;
10294 }
10295 else
10296 row_width = row->pixel_width;
177c0ea7 10297
333b20bb
GM
10298 height += row->height;
10299 width = max (width, row_width);
10300 }
10301
10302 /* Add the frame's internal border to the width and height the X
10303 window should have. */
10304 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
10305 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
10306
10307 /* Move the tooltip window where the mouse pointer is. Resize and
10308 show it. */
ab452f99 10309 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
0634ce98 10310
0634ce98 10311 BLOCK_INPUT;
333b20bb 10312 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 10313 root_x, root_y, width, height);
333b20bb
GM
10314 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
10315 UNBLOCK_INPUT;
177c0ea7 10316
333b20bb
GM
10317 /* Draw into the window. */
10318 w->must_be_updated_p = 1;
10319 update_single_window (w, 1);
10320
10321 /* Restore original current buffer. */
10322 set_buffer_internal_1 (old_buffer);
10323 windows_or_buffers_changed = old_windows_or_buffers_changed;
10324
06d62053 10325 start_timer:
333b20bb
GM
10326 /* Let the tip disappear after timeout seconds. */
10327 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
10328 intern ("x-hide-tip"));
a744a2ec
DL
10329
10330 UNGCPRO;
333b20bb
GM
10331 return unbind_to (count, Qnil);
10332}
10333
10334
10335DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
7ee72033
MB
10336 doc: /* Hide the current tooltip window, if there is any.
10337Value is t if tooltip was open, nil otherwise. */)
10338 ()
333b20bb 10339{
44b5a125 10340 int count;
c0006262
GM
10341 Lisp_Object deleted, frame, timer;
10342 struct gcpro gcpro1, gcpro2;
44b5a125
GM
10343
10344 /* Return quickly if nothing to do. */
c0006262 10345 if (NILP (tip_timer) && NILP (tip_frame))
44b5a125 10346 return Qnil;
177c0ea7 10347
c0006262
GM
10348 frame = tip_frame;
10349 timer = tip_timer;
10350 GCPRO2 (frame, timer);
10351 tip_frame = tip_timer = deleted = Qnil;
177c0ea7 10352
331379bf 10353 count = SPECPDL_INDEX ();
333b20bb 10354 specbind (Qinhibit_redisplay, Qt);
44b5a125 10355 specbind (Qinhibit_quit, Qt);
177c0ea7 10356
c0006262 10357 if (!NILP (timer))
ae782866 10358 call1 (Qcancel_timer, timer);
333b20bb 10359
c0006262 10360 if (FRAMEP (frame))
333b20bb 10361 {
44b5a125
GM
10362 Fdelete_frame (frame, Qnil);
10363 deleted = Qt;
f6c44811
GM
10364
10365#ifdef USE_LUCID
10366 /* Bloodcurdling hack alert: The Lucid menu bar widget's
10367 redisplay procedure is not called when a tip frame over menu
10368 items is unmapped. Redisplay the menu manually... */
10369 {
10370 struct frame *f = SELECTED_FRAME ();
10371 Widget w = f->output_data.x->menubar_widget;
10372 extern void xlwmenu_redisplay P_ ((Widget));
9180dc8c 10373
f6c44811 10374 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
dbc64aa7 10375 && w != NULL)
f6c44811
GM
10376 {
10377 BLOCK_INPUT;
10378 xlwmenu_redisplay (w);
10379 UNBLOCK_INPUT;
10380 }
10381 }
10382#endif /* USE_LUCID */
333b20bb
GM
10383 }
10384
c0006262 10385 UNGCPRO;
44b5a125 10386 return unbind_to (count, deleted);
333b20bb
GM
10387}
10388
10389
10390\f
10391/***********************************************************************
10392 File selection dialog
10393 ***********************************************************************/
10394
10395#ifdef USE_MOTIF
10396
10397/* Callback for "OK" and "Cancel" on file selection dialog. */
10398
10399static void
10400file_dialog_cb (widget, client_data, call_data)
10401 Widget widget;
10402 XtPointer call_data, client_data;
10403{
10404 int *result = (int *) client_data;
10405 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
10406 *result = cb->reason;
10407}
10408
10409
a779d213
GM
10410/* Callback for unmapping a file selection dialog. This is used to
10411 capture the case where a dialog is closed via a window manager's
10412 closer button, for example. Using a XmNdestroyCallback didn't work
10413 in this case. */
10414
10415static void
10416file_dialog_unmap_cb (widget, client_data, call_data)
10417 Widget widget;
10418 XtPointer call_data, client_data;
10419{
10420 int *result = (int *) client_data;
10421 *result = XmCR_CANCEL;
10422}
10423
10424
333b20bb 10425DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
7ee72033 10426 doc: /* Read file name, prompting with PROMPT in directory DIR.
c061c855
GM
10427Use a file selection dialog.
10428Select DEFAULT-FILENAME in the dialog's file selection box, if
10429specified. Don't let the user enter a file name in the file
7ee72033
MB
10430selection dialog's entry field, if MUSTMATCH is non-nil. */)
10431 (prompt, dir, default_filename, mustmatch)
333b20bb
GM
10432 Lisp_Object prompt, dir, default_filename, mustmatch;
10433{
10434 int result;
0fe92f72 10435 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
10436 Lisp_Object file = Qnil;
10437 Widget dialog, text, list, help;
10438 Arg al[10];
10439 int ac = 0;
10440 extern XtAppContext Xt_app_con;
333b20bb 10441 XmString dir_xmstring, pattern_xmstring;
65b21658 10442 int count = SPECPDL_INDEX ();
333b20bb
GM
10443 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
10444
10445 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
10446 CHECK_STRING (prompt);
10447 CHECK_STRING (dir);
333b20bb
GM
10448
10449 /* Prevent redisplay. */
10450 specbind (Qinhibit_redisplay, Qt);
10451
10452 BLOCK_INPUT;
10453
10454 /* Create the dialog with PROMPT as title, using DIR as initial
10455 directory and using "*" as pattern. */
10456 dir = Fexpand_file_name (dir, Qnil);
d5db4077 10457 dir_xmstring = XmStringCreateLocalized (SDATA (dir));
333b20bb 10458 pattern_xmstring = XmStringCreateLocalized ("*");
177c0ea7 10459
d5db4077 10460 XtSetArg (al[ac], XmNtitle, SDATA (prompt)); ++ac;
333b20bb
GM
10461 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
10462 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
10463 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
10464 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
10465 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
10466 "fsb", al, ac);
10467 XmStringFree (dir_xmstring);
10468 XmStringFree (pattern_xmstring);
10469
10470 /* Add callbacks for OK and Cancel. */
10471 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
10472 (XtPointer) &result);
10473 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
10474 (XtPointer) &result);
a779d213
GM
10475 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
10476 (XtPointer) &result);
333b20bb
GM
10477
10478 /* Disable the help button since we can't display help. */
10479 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
10480 XtSetSensitive (help, False);
10481
177c0ea7 10482 /* Mark OK button as default. */
333b20bb
GM
10483 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
10484 XmNshowAsDefault, True, NULL);
10485
10486 /* If MUSTMATCH is non-nil, disable the file entry field of the
10487 dialog, so that the user must select a file from the files list
10488 box. We can't remove it because we wouldn't have a way to get at
10489 the result file name, then. */
10490 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
10491 if (!NILP (mustmatch))
10492 {
10493 Widget label;
10494 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
10495 XtSetSensitive (text, False);
10496 XtSetSensitive (label, False);
10497 }
10498
10499 /* Manage the dialog, so that list boxes get filled. */
10500 XtManageChild (dialog);
10501
10502 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
10503 must include the path for this to work. */
10504 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
10505 if (STRINGP (default_filename))
10506 {
10507 XmString default_xmstring;
10508 int item_pos;
10509
10510 default_xmstring
d5db4077 10511 = XmStringCreateLocalized (SDATA (default_filename));
333b20bb
GM
10512
10513 if (!XmListItemExists (list, default_xmstring))
10514 {
10515 /* Add a new item if DEFAULT_FILENAME is not in the list. */
10516 XmListAddItem (list, default_xmstring, 0);
10517 item_pos = 0;
10518 }
10519 else
10520 item_pos = XmListItemPos (list, default_xmstring);
10521 XmStringFree (default_xmstring);
10522
10523 /* Select the item and scroll it into view. */
10524 XmListSelectPos (list, item_pos, True);
10525 XmListSetPos (list, item_pos);
10526 }
10527
bf338245 10528 /* Process events until the user presses Cancel or OK. */
03100098 10529 result = 0;
a779d213 10530 while (result == 0)
563b384d 10531 {
bf338245
JD
10532 XEvent event;
10533 XtAppNextEvent (Xt_app_con, &event);
1fcfb866 10534 (void) x_dispatch_event (&event, FRAME_X_DISPLAY (f) );
563b384d 10535 }
03100098 10536
333b20bb
GM
10537 /* Get the result. */
10538 if (result == XmCR_OK)
10539 {
10540 XmString text;
10541 String data;
177c0ea7 10542
d1670063 10543 XtVaGetValues (dialog, XmNtextString, &text, NULL);
333b20bb
GM
10544 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
10545 XmStringFree (text);
10546 file = build_string (data);
10547 XtFree (data);
10548 }
10549 else
10550 file = Qnil;
10551
10552 /* Clean up. */
10553 XtUnmanageChild (dialog);
10554 XtDestroyWidget (dialog);
10555 UNBLOCK_INPUT;
10556 UNGCPRO;
10557
10558 /* Make "Cancel" equivalent to C-g. */
10559 if (NILP (file))
10560 Fsignal (Qquit, Qnil);
177c0ea7 10561
333b20bb
GM
10562 return unbind_to (count, file);
10563}
10564
10565#endif /* USE_MOTIF */
10566
488dd4c4
JD
10567#ifdef USE_GTK
10568
10569DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
10570 "Read file name, prompting with PROMPT in directory DIR.\n\
10571Use a file selection dialog.\n\
10572Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
10573specified. Don't let the user enter a file name in the file\n\
10574selection dialog's entry field, if MUSTMATCH is non-nil.")
10575 (prompt, dir, default_filename, mustmatch)
10576 Lisp_Object prompt, dir, default_filename, mustmatch;
10577{
10578 FRAME_PTR f = SELECTED_FRAME ();
10579 char *fn;
10580 Lisp_Object file = Qnil;
10581 int count = specpdl_ptr - specpdl;
10582 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
10583 char *cdef_file;
10584 char *cprompt;
177c0ea7 10585
488dd4c4
JD
10586 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
10587 CHECK_STRING (prompt);
10588 CHECK_STRING (dir);
10589
10590 /* Prevent redisplay. */
10591 specbind (Qinhibit_redisplay, Qt);
10592
10593 BLOCK_INPUT;
10594
10595 if (STRINGP (default_filename))
10596 cdef_file = SDATA (default_filename);
10597 else
10598 cdef_file = SDATA (dir);
10599
10600 fn = xg_get_file_name (f, SDATA (prompt), cdef_file, ! NILP (mustmatch));
177c0ea7 10601
488dd4c4
JD
10602 if (fn)
10603 {
10604 file = build_string (fn);
10605 xfree (fn);
10606 }
10607
10608 UNBLOCK_INPUT;
10609 UNGCPRO;
10610
10611 /* Make "Cancel" equivalent to C-g. */
10612 if (NILP (file))
10613 Fsignal (Qquit, Qnil);
177c0ea7 10614
488dd4c4
JD
10615 return unbind_to (count, file);
10616}
10617
10618#endif /* USE_GTK */
333b20bb
GM
10619
10620\f
82bab41c
GM
10621/***********************************************************************
10622 Keyboard
10623 ***********************************************************************/
10624
10625#ifdef HAVE_XKBGETKEYBOARD
10626#include <X11/XKBlib.h>
10627#include <X11/keysym.h>
10628#endif
10629
10630DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
10631 Sx_backspace_delete_keys_p, 0, 1, 0,
7ee72033 10632 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
c061c855
GM
10633FRAME nil means use the selected frame.
10634Value is t if we know that both keys are present, and are mapped to the
7ee72033
MB
10635usual X keysyms. */)
10636 (frame)
82bab41c
GM
10637 Lisp_Object frame;
10638{
10639#ifdef HAVE_XKBGETKEYBOARD
10640 XkbDescPtr kb;
10641 struct frame *f = check_x_frame (frame);
10642 Display *dpy = FRAME_X_DISPLAY (f);
10643 Lisp_Object have_keys;
46f6a258 10644 int major, minor, op, event, error;
82bab41c
GM
10645
10646 BLOCK_INPUT;
46f6a258
GM
10647
10648 /* Check library version in case we're dynamically linked. */
10649 major = XkbMajorVersion;
10650 minor = XkbMinorVersion;
10651 if (!XkbLibraryVersion (&major, &minor))
c1efd260
GM
10652 {
10653 UNBLOCK_INPUT;
10654 return Qnil;
10655 }
46f6a258
GM
10656
10657 /* Check that the server supports XKB. */
10658 major = XkbMajorVersion;
10659 minor = XkbMinorVersion;
10660 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
c1efd260
GM
10661 {
10662 UNBLOCK_INPUT;
10663 return Qnil;
10664 }
177c0ea7 10665
46f6a258 10666 have_keys = Qnil;
c1efd260 10667 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
82bab41c
GM
10668 if (kb)
10669 {
10670 int delete_keycode = 0, backspace_keycode = 0, i;
c1efd260
GM
10671
10672 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
82bab41c 10673 {
c1efd260
GM
10674 for (i = kb->min_key_code;
10675 (i < kb->max_key_code
10676 && (delete_keycode == 0 || backspace_keycode == 0));
10677 ++i)
10678 {
d63931a2
GM
10679 /* The XKB symbolic key names can be seen most easily in
10680 the PS file generated by `xkbprint -label name
10681 $DISPLAY'. */
c1efd260
GM
10682 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
10683 delete_keycode = i;
10684 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
10685 backspace_keycode = i;
10686 }
10687
10688 XkbFreeNames (kb, 0, True);
82bab41c
GM
10689 }
10690
c1efd260 10691 XkbFreeClientMap (kb, 0, True);
177c0ea7 10692
82bab41c
GM
10693 if (delete_keycode
10694 && backspace_keycode
10695 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
10696 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
10697 have_keys = Qt;
10698 }
10699 UNBLOCK_INPUT;
10700 return have_keys;
10701#else /* not HAVE_XKBGETKEYBOARD */
10702 return Qnil;
10703#endif /* not HAVE_XKBGETKEYBOARD */
10704}
10705
10706
10707\f
333b20bb
GM
10708/***********************************************************************
10709 Initialization
10710 ***********************************************************************/
10711
4dacadcc 10712/* Keep this list in the same order as frame_parms in frame.c.
7c0d3ed8
KS
10713 Use 0 for unsupported frame parameters. */
10714
10715frame_parm_handler x_frame_parm_handlers[] =
10716{
10717 x_set_autoraise,
10718 x_set_autolower,
10719 x_set_background_color,
10720 x_set_border_color,
10721 x_set_border_width,
10722 x_set_cursor_color,
10723 x_set_cursor_type,
10724 x_set_font,
10725 x_set_foreground_color,
10726 x_set_icon_name,
10727 x_set_icon_type,
10728 x_set_internal_border_width,
10729 x_set_menu_bar_lines,
10730 x_set_mouse_color,
10731 x_explicitly_set_name,
10732 x_set_scroll_bar_width,
10733 x_set_title,
10734 x_set_unsplittable,
10735 x_set_vertical_scroll_bars,
10736 x_set_visibility,
10737 x_set_tool_bar_lines,
10738 x_set_scroll_bar_foreground,
10739 x_set_scroll_bar_background,
10740 x_set_screen_gamma,
10741 x_set_line_spacing,
10742 x_set_fringe_width,
10743 x_set_fringe_width,
10744 x_set_wait_for_wm,
10745 x_set_fullscreen,
10746};
10747
333b20bb
GM
10748void
10749syms_of_xfns ()
10750{
10751 /* This is zero if not using X windows. */
10752 x_in_use = 0;
10753
10754 /* The section below is built by the lisp expression at the top of the file,
10755 just above where these variables are declared. */
10756 /*&&& init symbols here &&&*/
baaed68e
JB
10757 Qnone = intern ("none");
10758 staticpro (&Qnone);
8af1d7ca
JB
10759 Qsuppress_icon = intern ("suppress-icon");
10760 staticpro (&Qsuppress_icon);
01f1ba30 10761 Qundefined_color = intern ("undefined-color");
f9942c9e 10762 staticpro (&Qundefined_color);
7c7ff7f5
GM
10763 Qcenter = intern ("center");
10764 staticpro (&Qcenter);
96db09e4
KH
10765 Qcompound_text = intern ("compound-text");
10766 staticpro (&Qcompound_text);
ae782866
GM
10767 Qcancel_timer = intern ("cancel-timer");
10768 staticpro (&Qcancel_timer);
f9942c9e
JB
10769 /* This is the end of symbol initialization. */
10770
58cad5ed
KH
10771 /* Text property `display' should be nonsticky by default. */
10772 Vtext_property_default_nonsticky
10773 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
10774
10775
333b20bb
GM
10776 Qlaplace = intern ("laplace");
10777 staticpro (&Qlaplace);
4a8e312c
GM
10778 Qemboss = intern ("emboss");
10779 staticpro (&Qemboss);
10780 Qedge_detection = intern ("edge-detection");
10781 staticpro (&Qedge_detection);
10782 Qheuristic = intern ("heuristic");
10783 staticpro (&Qheuristic);
10784 QCmatrix = intern (":matrix");
10785 staticpro (&QCmatrix);
10786 QCcolor_adjustment = intern (":color-adjustment");
10787 staticpro (&QCcolor_adjustment);
10788 QCmask = intern (":mask");
10789 staticpro (&QCmask);
177c0ea7 10790
01f1ba30
JB
10791 Fput (Qundefined_color, Qerror_conditions,
10792 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
10793 Fput (Qundefined_color, Qerror_message,
10794 build_string ("Undefined color"));
10795
7ee72033
MB
10796 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
10797 doc: /* Non-nil means always draw a cross over disabled images.
c061c855
GM
10798Disabled images are those having an `:conversion disabled' property.
10799A cross is always drawn on black & white displays. */);
14819cb3
GM
10800 cross_disabled_images = 0;
10801
7ee72033 10802 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
c5903437 10803 doc: /* List of directories to search for window system bitmap files. */);
e241c09b 10804 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 10805
7ee72033
MB
10806 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
10807 doc: /* The shape of the pointer when over text.
c061c855
GM
10808Changing the value does not affect existing frames
10809unless you set the mouse color. */);
01f1ba30
JB
10810 Vx_pointer_shape = Qnil;
10811
ca0ecbf5 10812#if 0 /* This doesn't really do anything. */
7ee72033
MB
10813 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
10814 doc: /* The shape of the pointer when not over text.
c061c855
GM
10815This variable takes effect when you create a new frame
10816or when you set the mouse color. */);
af01ef26 10817#endif
01f1ba30
JB
10818 Vx_nontext_pointer_shape = Qnil;
10819
7ee72033
MB
10820 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
10821 doc: /* The shape of the pointer when Emacs is busy.
c061c855
GM
10822This variable takes effect when you create a new frame
10823or when you set the mouse color. */);
0af913d7 10824 Vx_hourglass_pointer_shape = Qnil;
333b20bb 10825
7ee72033
MB
10826 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
10827 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 10828 display_hourglass_p = 1;
177c0ea7 10829
7ee72033
MB
10830 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
10831 doc: /* *Seconds to wait before displaying an hourglass pointer.
c061c855 10832Value must be an integer or float. */);
0af913d7 10833 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
4ae9a85e 10834
ca0ecbf5 10835#if 0 /* This doesn't really do anything. */
7ee72033
MB
10836 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
10837 doc: /* The shape of the pointer when over the mode line.
c061c855
GM
10838This variable takes effect when you create a new frame
10839or when you set the mouse color. */);
af01ef26 10840#endif
01f1ba30
JB
10841 Vx_mode_pointer_shape = Qnil;
10842
d3b06468 10843 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
7ee72033
MB
10844 &Vx_sensitive_text_pointer_shape,
10845 doc: /* The shape of the pointer when over mouse-sensitive text.
c061c855
GM
10846This variable takes effect when you create a new frame
10847or when you set the mouse color. */);
ca0ecbf5 10848 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 10849
8fb4ec9c 10850 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
7ee72033
MB
10851 &Vx_window_horizontal_drag_shape,
10852 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
c061c855
GM
10853This variable takes effect when you create a new frame
10854or when you set the mouse color. */);
8fb4ec9c
GM
10855 Vx_window_horizontal_drag_shape = Qnil;
10856
7ee72033
MB
10857 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
10858 doc: /* A string indicating the foreground color of the cursor box. */);
01f1ba30
JB
10859 Vx_cursor_fore_pixel = Qnil;
10860
7ee72033
MB
10861 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
10862 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
c061c855 10863Text larger than this is clipped. */);
d63931a2 10864 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
177c0ea7 10865
7ee72033
MB
10866 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
10867 doc: /* Non-nil if no X window manager is in use.
c061c855
GM
10868Emacs doesn't try to figure this out; this is always nil
10869unless you set it to something else. */);
2d38195d
RS
10870 /* We don't have any way to find this out, so set it to nil
10871 and maybe the user would like to set it to t. */
10872 Vx_no_window_manager = Qnil;
1d3dac41 10873
942ea06d 10874 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7ee72033
MB
10875 &Vx_pixel_size_width_font_regexp,
10876 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
c061c855
GM
10877
10878Since Emacs gets width of a font matching with this regexp from
10879PIXEL_SIZE field of the name, font finding mechanism gets faster for
10880such a font. This is especially effective for such large fonts as
10881Chinese, Japanese, and Korean. */);
942ea06d
KH
10882 Vx_pixel_size_width_font_regexp = Qnil;
10883
7ee72033
MB
10884 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
10885 doc: /* Time after which cached images are removed from the cache.
c061c855
GM
10886When an image has not been displayed this many seconds, remove it
10887from the image cache. Value must be an integer or nil with nil
10888meaning don't clear the cache. */);
fcf431dc 10889 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb 10890
1d3dac41 10891#ifdef USE_X_TOOLKIT
6f3f6a8d 10892 Fprovide (intern ("x-toolkit"), Qnil);
5b827abb 10893#ifdef USE_MOTIF
6f3f6a8d 10894 Fprovide (intern ("motif"), Qnil);
fc2cdd9a 10895
7ee72033
MB
10896 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
10897 doc: /* Version info for LessTif/Motif. */);
fc2cdd9a
GM
10898 Vmotif_version_string = build_string (XmVERSION_STRING);
10899#endif /* USE_MOTIF */
10900#endif /* USE_X_TOOLKIT */
01f1ba30 10901
333b20bb
GM
10902 /* X window properties. */
10903 defsubr (&Sx_change_window_property);
10904 defsubr (&Sx_delete_window_property);
10905 defsubr (&Sx_window_property);
10906
2d764c78 10907 defsubr (&Sxw_display_color_p);
d0c9d219 10908 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
10909 defsubr (&Sxw_color_defined_p);
10910 defsubr (&Sxw_color_values);
9d317b2c 10911 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
10912 defsubr (&Sx_server_vendor);
10913 defsubr (&Sx_server_version);
10914 defsubr (&Sx_display_pixel_width);
10915 defsubr (&Sx_display_pixel_height);
10916 defsubr (&Sx_display_mm_width);
10917 defsubr (&Sx_display_mm_height);
10918 defsubr (&Sx_display_screens);
10919 defsubr (&Sx_display_planes);
10920 defsubr (&Sx_display_color_cells);
10921 defsubr (&Sx_display_visual_class);
10922 defsubr (&Sx_display_backing_store);
10923 defsubr (&Sx_display_save_under);
f676886a 10924 defsubr (&Sx_create_frame);
01f1ba30 10925 defsubr (&Sx_open_connection);
08a90d6a
RS
10926 defsubr (&Sx_close_connection);
10927 defsubr (&Sx_display_list);
01f1ba30 10928 defsubr (&Sx_synchronize);
3decc1e7 10929 defsubr (&Sx_focus_frame);
82bab41c 10930 defsubr (&Sx_backspace_delete_keys_p);
177c0ea7 10931
942ea06d
KH
10932 /* Setting callback functions for fontset handler. */
10933 get_font_info_func = x_get_font_info;
333b20bb
GM
10934
10935#if 0 /* This function pointer doesn't seem to be used anywhere.
10936 And the pointer assigned has the wrong type, anyway. */
942ea06d 10937 list_fonts_func = x_list_fonts;
333b20bb 10938#endif
177c0ea7 10939
942ea06d 10940 load_font_func = x_load_font;
bc1958c4 10941 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
10942 query_font_func = x_query_font;
10943 set_frame_fontset_func = x_set_font;
10944 check_window_system_func = check_x;
333b20bb
GM
10945
10946 /* Images. */
10947 Qxbm = intern ("xbm");
10948 staticpro (&Qxbm);
d2dc8167
GM
10949 QCconversion = intern (":conversion");
10950 staticpro (&QCconversion);
333b20bb
GM
10951 QCheuristic_mask = intern (":heuristic-mask");
10952 staticpro (&QCheuristic_mask);
10953 QCcolor_symbols = intern (":color-symbols");
10954 staticpro (&QCcolor_symbols);
333b20bb
GM
10955 QCascent = intern (":ascent");
10956 staticpro (&QCascent);
10957 QCmargin = intern (":margin");
10958 staticpro (&QCmargin);
10959 QCrelief = intern (":relief");
10960 staticpro (&QCrelief);
fcf431dc
GM
10961 Qpostscript = intern ("postscript");
10962 staticpro (&Qpostscript);
333b20bb
GM
10963 QCloader = intern (":loader");
10964 staticpro (&QCloader);
10965 QCbounding_box = intern (":bounding-box");
10966 staticpro (&QCbounding_box);
10967 QCpt_width = intern (":pt-width");
10968 staticpro (&QCpt_width);
10969 QCpt_height = intern (":pt-height");
10970 staticpro (&QCpt_height);
3ccff1e3
GM
10971 QCindex = intern (":index");
10972 staticpro (&QCindex);
333b20bb
GM
10973 Qpbm = intern ("pbm");
10974 staticpro (&Qpbm);
10975
10976#if HAVE_XPM
10977 Qxpm = intern ("xpm");
10978 staticpro (&Qxpm);
10979#endif
177c0ea7 10980
333b20bb
GM
10981#if HAVE_JPEG
10982 Qjpeg = intern ("jpeg");
10983 staticpro (&Qjpeg);
177c0ea7 10984#endif
333b20bb
GM
10985
10986#if HAVE_TIFF
10987 Qtiff = intern ("tiff");
10988 staticpro (&Qtiff);
177c0ea7 10989#endif
333b20bb
GM
10990
10991#if HAVE_GIF
10992 Qgif = intern ("gif");
10993 staticpro (&Qgif);
10994#endif
10995
10996#if HAVE_PNG
10997 Qpng = intern ("png");
10998 staticpro (&Qpng);
10999#endif
11000
11001 defsubr (&Sclear_image_cache);
42677916 11002 defsubr (&Simage_size);
b243755a 11003 defsubr (&Simage_mask_p);
333b20bb 11004
0af913d7
GM
11005 hourglass_atimer = NULL;
11006 hourglass_shown_p = 0;
333b20bb
GM
11007
11008 defsubr (&Sx_show_tip);
11009 defsubr (&Sx_hide_tip);
333b20bb 11010 tip_timer = Qnil;
44b5a125
GM
11011 staticpro (&tip_timer);
11012 tip_frame = Qnil;
11013 staticpro (&tip_frame);
333b20bb 11014
06d62053
GM
11015 last_show_tip_args = Qnil;
11016 staticpro (&last_show_tip_args);
11017
333b20bb
GM
11018#ifdef USE_MOTIF
11019 defsubr (&Sx_file_dialog);
11020#endif
11021}
11022
11023
11024void
11025init_xfns ()
11026{
11027 image_types = NULL;
11028 Vimage_types = Qnil;
177c0ea7 11029
333b20bb
GM
11030 define_image_type (&xbm_type);
11031 define_image_type (&gs_type);
11032 define_image_type (&pbm_type);
177c0ea7 11033
333b20bb
GM
11034#if HAVE_XPM
11035 define_image_type (&xpm_type);
11036#endif
177c0ea7 11037
333b20bb
GM
11038#if HAVE_JPEG
11039 define_image_type (&jpeg_type);
11040#endif
177c0ea7 11041
333b20bb
GM
11042#if HAVE_TIFF
11043 define_image_type (&tiff_type);
11044#endif
177c0ea7 11045
333b20bb
GM
11046#if HAVE_GIF
11047 define_image_type (&gif_type);
11048#endif
177c0ea7 11049
333b20bb
GM
11050#if HAVE_PNG
11051 define_image_type (&png_type);
11052#endif
01f1ba30
JB
11053}
11054
11055#endif /* HAVE_X_WINDOWS */