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