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