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