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