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