(gnus-article-display-xface): Don't convert PBM
[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
f72c62ad 6826static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
b243755a
GM
6827static void xpm_free_color_cache P_ ((void));
6828static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
f72c62ad
GM
6829static int xpm_color_bucket P_ ((char *));
6830static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
6831 XColor *, int));
b243755a
GM
6832
6833/* An entry in a hash table used to cache color definitions of named
6834 colors. This cache is necessary to speed up XPM image loading in
6835 case we do color allocations ourselves. Without it, we would need
6836 a call to XParseColor per pixel in the image. */
6837
6838struct xpm_cached_color
6839{
6840 /* Next in collision chain. */
6841 struct xpm_cached_color *next;
6842
6843 /* Color definition (RGB and pixel color). */
6844 XColor color;
6845
6846 /* Color name. */
6847 char name[1];
6848};
6849
6850/* The hash table used for the color cache, and its bucket vector
6851 size. */
6852
6853#define XPM_COLOR_CACHE_BUCKETS 1001
6854struct xpm_cached_color **xpm_color_cache;
6855
b243755a
GM
6856/* Initialize the color cache. */
6857
6858static void
f72c62ad
GM
6859xpm_init_color_cache (f, attrs)
6860 struct frame *f;
6861 XpmAttributes *attrs;
b243755a
GM
6862{
6863 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
6864 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
6865 memset (xpm_color_cache, 0, nbytes);
6866 init_color_table ();
f72c62ad
GM
6867
6868 if (attrs->valuemask & XpmColorSymbols)
6869 {
6870 int i;
6871 XColor color;
6872
6873 for (i = 0; i < attrs->numsymbols; ++i)
6874 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
6875 attrs->colorsymbols[i].value, &color))
6876 {
6877 color.pixel = lookup_rgb_color (f, color.red, color.green,
6878 color.blue);
6879 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
6880 }
6881 }
b243755a
GM
6882}
6883
6884
6885/* Free the color cache. */
6886
6887static void
6888xpm_free_color_cache ()
6889{
6890 struct xpm_cached_color *p, *next;
6891 int i;
6892
6893 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
6894 for (p = xpm_color_cache[i]; p; p = next)
6895 {
6896 next = p->next;
6897 xfree (p);
6898 }
6899
6900 xfree (xpm_color_cache);
6901 xpm_color_cache = NULL;
6902 free_color_table ();
6903}
6904
6905
f72c62ad
GM
6906/* Return the bucket index for color named COLOR_NAME in the color
6907 cache. */
6908
6909static int
6910xpm_color_bucket (color_name)
6911 char *color_name;
6912{
6913 unsigned h = 0;
6914 char *s;
6915
6916 for (s = color_name; *s; ++s)
6917 h = (h << 2) ^ *s;
6918 return h %= XPM_COLOR_CACHE_BUCKETS;
6919}
6920
6921
6922/* On frame F, cache values COLOR for color with name COLOR_NAME.
6923 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
6924 entry added. */
6925
6926static struct xpm_cached_color *
6927xpm_cache_color (f, color_name, color, bucket)
6928 struct frame *f;
6929 char *color_name;
6930 XColor *color;
6931 int bucket;
6932{
6933 size_t nbytes;
6934 struct xpm_cached_color *p;
6935
6936 if (bucket < 0)
6937 bucket = xpm_color_bucket (color_name);
6938
6939 nbytes = sizeof *p + strlen (color_name);
6940 p = (struct xpm_cached_color *) xmalloc (nbytes);
6941 strcpy (p->name, color_name);
6942 p->color = *color;
6943 p->next = xpm_color_cache[bucket];
6944 xpm_color_cache[bucket] = p;
6945 return p;
6946}
6947
6948
b243755a
GM
6949/* Look up color COLOR_NAME for frame F in the color cache. If found,
6950 return the cached definition in *COLOR. Otherwise, make a new
6951 entry in the cache and allocate the color. Value is zero if color
6952 allocation failed. */
6953
6954static int
6955xpm_lookup_color (f, color_name, color)
6956 struct frame *f;
6957 char *color_name;
6958 XColor *color;
6959{
b243755a 6960 struct xpm_cached_color *p;
f72c62ad 6961 int h = xpm_color_bucket (color_name);
b243755a
GM
6962
6963 for (p = xpm_color_cache[h]; p; p = p->next)
6964 if (strcmp (p->name, color_name) == 0)
6965 break;
6966
6967 if (p != NULL)
6968 *color = p->color;
6969 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
6970 color_name, color))
6971 {
b243755a
GM
6972 color->pixel = lookup_rgb_color (f, color->red, color->green,
6973 color->blue);
f72c62ad 6974 p = xpm_cache_color (f, color_name, color, h);
b243755a 6975 }
f72c62ad 6976
b243755a
GM
6977 return p != NULL;
6978}
6979
6980
6981/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
6982 CLOSURE is a pointer to the frame on which we allocate the
6983 color. Return in *COLOR the allocated color. Value is non-zero
6984 if successful. */
6985
6986static int
6987xpm_alloc_color (dpy, cmap, color_name, color, closure)
6988 Display *dpy;
6989 Colormap cmap;
6990 char *color_name;
6991 XColor *color;
6992 void *closure;
6993{
6994 return xpm_lookup_color ((struct frame *) closure, color_name, color);
6995}
6996
6997
6998/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
6999 is a pointer to the frame on which we allocate the color. Value is
7000 non-zero if successful. */
7001
7002static int
7003xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7004 Display *dpy;
7005 Colormap cmap;
7006 Pixel *pixels;
7007 int npixels;
7008 void *closure;
7009{
7010 return 1;
7011}
7012
7013#endif /* ALLOC_XPM_COLORS */
7014
7015
333b20bb
GM
7016/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7017 for XPM images. Such a list must consist of conses whose car and
7018 cdr are strings. */
7019
7020static int
7021xpm_valid_color_symbols_p (color_symbols)
7022 Lisp_Object color_symbols;
7023{
7024 while (CONSP (color_symbols))
7025 {
7026 Lisp_Object sym = XCAR (color_symbols);
7027 if (!CONSP (sym)
7028 || !STRINGP (XCAR (sym))
7029 || !STRINGP (XCDR (sym)))
7030 break;
7031 color_symbols = XCDR (color_symbols);
7032 }
7033
7034 return NILP (color_symbols);
7035}
7036
7037
7038/* Value is non-zero if OBJECT is a valid XPM image specification. */
7039
7040static int
7041xpm_image_p (object)
7042 Lisp_Object object;
7043{
7044 struct image_keyword fmt[XPM_LAST];
7045 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 7046 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
7047 /* Either `:file' or `:data' must be present. */
7048 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7049 /* Either no `:color-symbols' or it's a list of conses
7050 whose car and cdr are strings. */
7051 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7c7ff7f5 7052 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
333b20bb
GM
7053}
7054
7055
7056/* Load image IMG which will be displayed on frame F. Value is
7057 non-zero if successful. */
7058
7059static int
7060xpm_load (f, img)
7061 struct frame *f;
7062 struct image *img;
7063{
7064 int rc, i;
7065 XpmAttributes attrs;
7066 Lisp_Object specified_file, color_symbols;
7067
7068 /* Configure the XPM lib. Use the visual of frame F. Allocate
7069 close colors. Return colors allocated. */
7070 bzero (&attrs, sizeof attrs);
9b2956e2
GM
7071 attrs.visual = FRAME_X_VISUAL (f);
7072 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 7073 attrs.valuemask |= XpmVisual;
9b2956e2 7074 attrs.valuemask |= XpmColormap;
b243755a
GM
7075
7076#ifdef ALLOC_XPM_COLORS
7077 /* Allocate colors with our own functions which handle
7078 failing color allocation more gracefully. */
7079 attrs.color_closure = f;
7080 attrs.alloc_color = xpm_alloc_color;
7081 attrs.free_colors = xpm_free_colors;
7082 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7083#else /* not ALLOC_XPM_COLORS */
7084 /* Let the XPM lib allocate colors. */
333b20bb 7085 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7086#ifdef XpmAllocCloseColors
333b20bb
GM
7087 attrs.alloc_close_colors = 1;
7088 attrs.valuemask |= XpmAllocCloseColors;
b243755a 7089#else /* not XpmAllocCloseColors */
e4c082be
RS
7090 attrs.closeness = 600;
7091 attrs.valuemask |= XpmCloseness;
b243755a
GM
7092#endif /* not XpmAllocCloseColors */
7093#endif /* ALLOC_XPM_COLORS */
333b20bb
GM
7094
7095 /* If image specification contains symbolic color definitions, add
7096 these to `attrs'. */
7097 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7098 if (CONSP (color_symbols))
7099 {
7100 Lisp_Object tail;
7101 XpmColorSymbol *xpm_syms;
7102 int i, size;
7103
7104 attrs.valuemask |= XpmColorSymbols;
7105
7106 /* Count number of symbols. */
7107 attrs.numsymbols = 0;
7108 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7109 ++attrs.numsymbols;
7110
7111 /* Allocate an XpmColorSymbol array. */
7112 size = attrs.numsymbols * sizeof *xpm_syms;
7113 xpm_syms = (XpmColorSymbol *) alloca (size);
7114 bzero (xpm_syms, size);
7115 attrs.colorsymbols = xpm_syms;
7116
7117 /* Fill the color symbol array. */
7118 for (tail = color_symbols, i = 0;
7119 CONSP (tail);
7120 ++i, tail = XCDR (tail))
7121 {
7122 Lisp_Object name = XCAR (XCAR (tail));
7123 Lisp_Object color = XCDR (XCAR (tail));
7124 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7125 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7126 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7127 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7128 }
7129 }
7130
7131 /* Create a pixmap for the image, either from a file, or from a
7132 string buffer containing data in the same format as an XPM file. */
b243755a 7133#ifdef ALLOC_XPM_COLORS
f72c62ad 7134 xpm_init_color_cache (f, &attrs);
b243755a
GM
7135#endif
7136
333b20bb
GM
7137 specified_file = image_spec_value (img->spec, QCfile, NULL);
7138 if (STRINGP (specified_file))
7139 {
7140 Lisp_Object file = x_find_image_file (specified_file);
7141 if (!STRINGP (file))
7142 {
45158a91 7143 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
7144 return 0;
7145 }
7146
7147 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7148 XSTRING (file)->data, &img->pixmap, &img->mask,
7149 &attrs);
7150 }
7151 else
7152 {
7153 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7154 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7155 XSTRING (buffer)->data,
7156 &img->pixmap, &img->mask,
7157 &attrs);
7158 }
333b20bb
GM
7159
7160 if (rc == XpmSuccess)
7161 {
b243755a
GM
7162#ifdef ALLOC_XPM_COLORS
7163 img->colors = colors_in_color_table (&img->ncolors);
7164#else /* not ALLOC_XPM_COLORS */
333b20bb
GM
7165 img->ncolors = attrs.nalloc_pixels;
7166 img->colors = (unsigned long *) xmalloc (img->ncolors
7167 * sizeof *img->colors);
7168 for (i = 0; i < attrs.nalloc_pixels; ++i)
3b4ae1cc
GM
7169 {
7170 img->colors[i] = attrs.alloc_pixels[i];
7171#ifdef DEBUG_X_COLORS
7172 register_color (img->colors[i]);
7173#endif
7174 }
b243755a 7175#endif /* not ALLOC_XPM_COLORS */
333b20bb
GM
7176
7177 img->width = attrs.width;
7178 img->height = attrs.height;
7179 xassert (img->width > 0 && img->height > 0);
7180
7181 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
333b20bb 7182 XpmFreeAttributes (&attrs);
333b20bb
GM
7183 }
7184 else
7185 {
7186 switch (rc)
7187 {
7188 case XpmOpenFailed:
7189 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7190 break;
7191
7192 case XpmFileInvalid:
7193 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7194 break;
7195
7196 case XpmNoMemory:
7197 image_error ("Out of memory (%s)", img->spec, Qnil);
7198 break;
7199
7200 case XpmColorFailed:
7201 image_error ("Color allocation error (%s)", img->spec, Qnil);
7202 break;
7203
7204 default:
7205 image_error ("Unknown error (%s)", img->spec, Qnil);
7206 break;
7207 }
7208 }
7209
b243755a
GM
7210#ifdef ALLOC_XPM_COLORS
7211 xpm_free_color_cache ();
7212#endif
333b20bb
GM
7213 return rc == XpmSuccess;
7214}
7215
7216#endif /* HAVE_XPM != 0 */
7217
7218\f
7219/***********************************************************************
7220 Color table
7221 ***********************************************************************/
7222
7223/* An entry in the color table mapping an RGB color to a pixel color. */
7224
7225struct ct_color
7226{
7227 int r, g, b;
7228 unsigned long pixel;
7229
7230 /* Next in color table collision list. */
7231 struct ct_color *next;
7232};
7233
7234/* The bucket vector size to use. Must be prime. */
7235
7236#define CT_SIZE 101
7237
7238/* Value is a hash of the RGB color given by R, G, and B. */
7239
7240#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7241
7242/* The color hash table. */
7243
7244struct ct_color **ct_table;
7245
7246/* Number of entries in the color table. */
7247
7248int ct_colors_allocated;
7249
333b20bb
GM
7250/* Initialize the color table. */
7251
7252static void
7253init_color_table ()
7254{
7255 int size = CT_SIZE * sizeof (*ct_table);
7256 ct_table = (struct ct_color **) xmalloc (size);
7257 bzero (ct_table, size);
7258 ct_colors_allocated = 0;
7259}
7260
7261
7262/* Free memory associated with the color table. */
7263
7264static void
7265free_color_table ()
7266{
7267 int i;
7268 struct ct_color *p, *next;
7269
7270 for (i = 0; i < CT_SIZE; ++i)
7271 for (p = ct_table[i]; p; p = next)
7272 {
7273 next = p->next;
7274 xfree (p);
7275 }
7276
7277 xfree (ct_table);
7278 ct_table = NULL;
7279}
7280
7281
7282/* Value is a pixel color for RGB color R, G, B on frame F. If an
7283 entry for that color already is in the color table, return the
7284 pixel color of that entry. Otherwise, allocate a new color for R,
7285 G, B, and make an entry in the color table. */
7286
7287static unsigned long
7288lookup_rgb_color (f, r, g, b)
7289 struct frame *f;
7290 int r, g, b;
7291{
7292 unsigned hash = CT_HASH_RGB (r, g, b);
7293 int i = hash % CT_SIZE;
7294 struct ct_color *p;
7295
7296 for (p = ct_table[i]; p; p = p->next)
7297 if (p->r == r && p->g == g && p->b == b)
7298 break;
7299
7300 if (p == NULL)
7301 {
7302 XColor color;
7303 Colormap cmap;
7304 int rc;
7305
7306 color.red = r;
7307 color.green = g;
7308 color.blue = b;
7309
9b2956e2 7310 cmap = FRAME_X_COLORMAP (f);
d62c8769 7311 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7312
7313 if (rc)
7314 {
7315 ++ct_colors_allocated;
7316
7317 p = (struct ct_color *) xmalloc (sizeof *p);
7318 p->r = r;
7319 p->g = g;
7320 p->b = b;
7321 p->pixel = color.pixel;
7322 p->next = ct_table[i];
7323 ct_table[i] = p;
7324 }
7325 else
7326 return FRAME_FOREGROUND_PIXEL (f);
7327 }
7328
7329 return p->pixel;
7330}
7331
7332
7333/* Look up pixel color PIXEL which is used on frame F in the color
7334 table. If not already present, allocate it. Value is PIXEL. */
7335
7336static unsigned long
7337lookup_pixel_color (f, pixel)
7338 struct frame *f;
7339 unsigned long pixel;
7340{
7341 int i = pixel % CT_SIZE;
7342 struct ct_color *p;
7343
7344 for (p = ct_table[i]; p; p = p->next)
7345 if (p->pixel == pixel)
7346 break;
7347
7348 if (p == NULL)
7349 {
7350 XColor color;
7351 Colormap cmap;
7352 int rc;
7353
9b2956e2 7354 cmap = FRAME_X_COLORMAP (f);
333b20bb
GM
7355 color.pixel = pixel;
7356 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
d62c8769 7357 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7358
7359 if (rc)
7360 {
7361 ++ct_colors_allocated;
7362
7363 p = (struct ct_color *) xmalloc (sizeof *p);
7364 p->r = color.red;
7365 p->g = color.green;
7366 p->b = color.blue;
7367 p->pixel = pixel;
7368 p->next = ct_table[i];
7369 ct_table[i] = p;
7370 }
7371 else
7372 return FRAME_FOREGROUND_PIXEL (f);
7373 }
7374
7375 return p->pixel;
7376}
7377
7378
7379/* Value is a vector of all pixel colors contained in the color table,
7380 allocated via xmalloc. Set *N to the number of colors. */
7381
7382static unsigned long *
7383colors_in_color_table (n)
7384 int *n;
7385{
7386 int i, j;
7387 struct ct_color *p;
7388 unsigned long *colors;
7389
7390 if (ct_colors_allocated == 0)
7391 {
7392 *n = 0;
7393 colors = NULL;
7394 }
7395 else
7396 {
7397 colors = (unsigned long *) xmalloc (ct_colors_allocated
7398 * sizeof *colors);
7399 *n = ct_colors_allocated;
7400
7401 for (i = j = 0; i < CT_SIZE; ++i)
7402 for (p = ct_table[i]; p; p = p->next)
7403 colors[j++] = p->pixel;
7404 }
7405
7406 return colors;
7407}
7408
7409
7410\f
7411/***********************************************************************
7412 Algorithms
7413 ***********************************************************************/
7414
7415static void x_laplace_write_row P_ ((struct frame *, long *,
7416 int, XImage *, int));
7417static void x_laplace_read_row P_ ((struct frame *, Colormap,
7418 XColor *, int, XImage *, int));
4a8e312c
GM
7419static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
7420static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
7421static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
7422
14819cb3
GM
7423/* Non-zero means draw a cross on images having `:algorithm
7424 disabled'. */
7425
7426int cross_disabled_images;
7427
4a8e312c
GM
7428/* Edge detection matrices for different edge-detection
7429 strategies. */
7430
7431static int emboss_matrix[9] = {
7432 /* x - 1 x x + 1 */
7433 2, -1, 0, /* y - 1 */
7434 -1, 0, 1, /* y */
7435 0, 1, -2 /* y + 1 */
7436};
333b20bb 7437
4a8e312c
GM
7438static int laplace_matrix[9] = {
7439 /* x - 1 x x + 1 */
7440 1, 0, 0, /* y - 1 */
7441 0, 0, 0, /* y */
7442 0, 0, -1 /* y + 1 */
7443};
333b20bb 7444
14819cb3
GM
7445/* Value is the intensity of the color whose red/green/blue values
7446 are R, G, and B. */
7447
7448#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
7449
333b20bb 7450
4a8e312c
GM
7451/* On frame F, return an array of XColor structures describing image
7452 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
7453 non-zero means also fill the red/green/blue members of the XColor
7454 structures. Value is a pointer to the array of XColors structures,
7455 allocated with xmalloc; it must be freed by the caller. */
7456
7457static XColor *
7458x_to_xcolors (f, img, rgb_p)
333b20bb 7459 struct frame *f;
4a8e312c
GM
7460 struct image *img;
7461 int rgb_p;
333b20bb 7462{
4a8e312c
GM
7463 int x, y;
7464 XColor *colors, *p;
7465 XImage *ximg;
333b20bb 7466
4a8e312c
GM
7467 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
7468
7469 /* Get the X image IMG->pixmap. */
7470 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7471 0, 0, img->width, img->height, ~0, ZPixmap);
333b20bb 7472
4a8e312c
GM
7473 /* Fill the `pixel' members of the XColor array. I wished there
7474 were an easy and portable way to circumvent XGetPixel. */
7475 p = colors;
7476 for (y = 0; y < img->height; ++y)
7477 {
7478 XColor *row = p;
7479
7480 for (x = 0; x < img->width; ++x, ++p)
7481 p->pixel = XGetPixel (ximg, x, y);
7482
7483 if (rgb_p)
7484 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7485 row, img->width);
7486 }
7487
7488 XDestroyImage (ximg);
4a8e312c 7489 return colors;
333b20bb
GM
7490}
7491
7492
4a8e312c
GM
7493/* Create IMG->pixmap from an array COLORS of XColor structures, whose
7494 RGB members are set. F is the frame on which this all happens.
7495 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
333b20bb
GM
7496
7497static void
4a8e312c 7498x_from_xcolors (f, img, colors)
333b20bb 7499 struct frame *f;
4a8e312c
GM
7500 struct image *img;
7501 XColor *colors;
333b20bb 7502{
4a8e312c
GM
7503 int x, y;
7504 XImage *oimg;
7505 Pixmap pixmap;
7506 XColor *p;
7507
4a8e312c 7508 init_color_table ();
333b20bb 7509
4a8e312c
GM
7510 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
7511 &oimg, &pixmap);
7512 p = colors;
7513 for (y = 0; y < img->height; ++y)
7514 for (x = 0; x < img->width; ++x, ++p)
7515 {
7516 unsigned long pixel;
7517 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
7518 XPutPixel (oimg, x, y, pixel);
7519 }
7520
7521 xfree (colors);
dd00328a 7522 x_clear_image_1 (f, img, 1, 0, 1);
4a8e312c
GM
7523
7524 x_put_x_image (f, oimg, pixmap, img->width, img->height);
7525 x_destroy_x_image (oimg);
7526 img->pixmap = pixmap;
7527 img->colors = colors_in_color_table (&img->ncolors);
7528 free_color_table ();
333b20bb
GM
7529}
7530
7531
4a8e312c
GM
7532/* On frame F, perform edge-detection on image IMG.
7533
7534 MATRIX is a nine-element array specifying the transformation
7535 matrix. See emboss_matrix for an example.
7536
7537 COLOR_ADJUST is a color adjustment added to each pixel of the
7538 outgoing image. */
333b20bb
GM
7539
7540static void
4a8e312c 7541x_detect_edges (f, img, matrix, color_adjust)
333b20bb
GM
7542 struct frame *f;
7543 struct image *img;
4a8e312c 7544 int matrix[9], color_adjust;
333b20bb 7545{
4a8e312c
GM
7546 XColor *colors = x_to_xcolors (f, img, 1);
7547 XColor *new, *p;
7548 int x, y, i, sum;
333b20bb 7549
4a8e312c
GM
7550 for (i = sum = 0; i < 9; ++i)
7551 sum += abs (matrix[i]);
333b20bb 7552
4a8e312c 7553#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
333b20bb 7554
4a8e312c 7555 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
333b20bb 7556
4a8e312c
GM
7557 for (y = 0; y < img->height; ++y)
7558 {
7559 p = COLOR (new, 0, y);
7560 p->red = p->green = p->blue = 0xffff/2;
7561 p = COLOR (new, img->width - 1, y);
7562 p->red = p->green = p->blue = 0xffff/2;
7563 }
7564
7565 for (x = 1; x < img->width - 1; ++x)
7566 {
7567 p = COLOR (new, x, 0);
7568 p->red = p->green = p->blue = 0xffff/2;
7569 p = COLOR (new, x, img->height - 1);
7570 p->red = p->green = p->blue = 0xffff/2;
7571 }
333b20bb 7572
4a8e312c 7573 for (y = 1; y < img->height - 1; ++y)
333b20bb 7574 {
4a8e312c
GM
7575 p = COLOR (new, 1, y);
7576
7577 for (x = 1; x < img->width - 1; ++x, ++p)
7578 {
14819cb3 7579 int r, g, b, y1, x1;
4a8e312c
GM
7580
7581 r = g = b = i = 0;
7582 for (y1 = y - 1; y1 < y + 2; ++y1)
7583 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
7584 if (matrix[i])
7585 {
7586 XColor *t = COLOR (colors, x1, y1);
7587 r += matrix[i] * t->red;
7588 g += matrix[i] * t->green;
7589 b += matrix[i] * t->blue;
7590 }
333b20bb 7591
4a8e312c
GM
7592 r = (r / sum + color_adjust) & 0xffff;
7593 g = (g / sum + color_adjust) & 0xffff;
7594 b = (b / sum + color_adjust) & 0xffff;
14819cb3 7595 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
333b20bb 7596 }
333b20bb
GM
7597 }
7598
4a8e312c
GM
7599 xfree (colors);
7600 x_from_xcolors (f, img, new);
333b20bb 7601
4a8e312c
GM
7602#undef COLOR
7603}
7604
7605
7606/* Perform the pre-defined `emboss' edge-detection on image IMG
7607 on frame F. */
7608
7609static void
7610x_emboss (f, img)
7611 struct frame *f;
7612 struct image *img;
7613{
7614 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
7615}
7616
7617
7618/* Perform the pre-defined `laplace' edge-detection on image IMG
7619 on frame F. */
7620
7621static void
7622x_laplace (f, img)
7623 struct frame *f;
7624 struct image *img;
7625{
7626 x_detect_edges (f, img, laplace_matrix, 45000);
7627}
7628
7629
7630/* Perform edge-detection on image IMG on frame F, with specified
7631 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
7632
7633 MATRIX must be either
7634
7635 - a list of at least 9 numbers in row-major form
7636 - a vector of at least 9 numbers
7637
7638 COLOR_ADJUST nil means use a default; otherwise it must be a
7639 number. */
7640
7641static void
7642x_edge_detection (f, img, matrix, color_adjust)
7643 struct frame *f;
7644 struct image *img;
7645 Lisp_Object matrix, color_adjust;
7646{
7647 int i = 0;
7648 int trans[9];
333b20bb 7649
4a8e312c
GM
7650 if (CONSP (matrix))
7651 {
7652 for (i = 0;
7653 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
7654 ++i, matrix = XCDR (matrix))
7655 trans[i] = XFLOATINT (XCAR (matrix));
7656 }
7657 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
7658 {
7659 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
7660 trans[i] = XFLOATINT (AREF (matrix, i));
7661 }
333b20bb 7662
4a8e312c
GM
7663 if (NILP (color_adjust))
7664 color_adjust = make_number (0xffff / 2);
333b20bb 7665
4a8e312c
GM
7666 if (i == 9 && NUMBERP (color_adjust))
7667 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
333b20bb
GM
7668}
7669
7670
14819cb3
GM
7671/* Transform image IMG on frame F so that it looks disabled. */
7672
7673static void
7674x_disable_image (f, img)
7675 struct frame *f;
7676 struct image *img;
7677{
7678 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dd00328a 7679
14819cb3
GM
7680 if (dpyinfo->n_planes >= 2)
7681 {
7682 /* Color (or grayscale). Convert to gray, and equalize. Just
7683 drawing such images with a stipple can look very odd, so
7684 we're using this method instead. */
7685 XColor *colors = x_to_xcolors (f, img, 1);
7686 XColor *p, *end;
7687 const int h = 15000;
7688 const int l = 30000;
7689
7690 for (p = colors, end = colors + img->width * img->height;
7691 p < end;
7692 ++p)
7693 {
7694 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
7695 int i2 = (0xffff - h - l) * i / 0xffff + l;
7696 p->red = p->green = p->blue = i2;
7697 }
7698
7699 x_from_xcolors (f, img, colors);
7700 }
7701
7702 /* Draw a cross over the disabled image, if we must or if we
7703 should. */
7704 if (dpyinfo->n_planes < 2 || cross_disabled_images)
7705 {
7706 Display *dpy = FRAME_X_DISPLAY (f);
7707 GC gc;
7708
14819cb3
GM
7709 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
7710 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
7711 XDrawLine (dpy, img->pixmap, gc, 0, 0,
7712 img->width - 1, img->height - 1);
7713 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
7714 img->width - 1, 0);
7715 XFreeGC (dpy, gc);
7716
7717 if (img->mask)
7718 {
7719 gc = XCreateGC (dpy, img->mask, 0, NULL);
7720 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
7721 XDrawLine (dpy, img->mask, gc, 0, 0,
7722 img->width - 1, img->height - 1);
7723 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
7724 img->width - 1, 0);
7725 XFreeGC (dpy, gc);
7726 }
14819cb3
GM
7727 }
7728}
7729
7730
333b20bb
GM
7731/* Build a mask for image IMG which is used on frame F. FILE is the
7732 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
7733 determine the background color of IMG. If it is a list '(R G B)',
7734 with R, G, and B being integers >= 0, take that as the color of the
7735 background. Otherwise, determine the background color of IMG
7736 heuristically. Value is non-zero if successful. */
333b20bb
GM
7737
7738static int
45158a91 7739x_build_heuristic_mask (f, img, how)
333b20bb 7740 struct frame *f;
333b20bb
GM
7741 struct image *img;
7742 Lisp_Object how;
7743{
7744 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 7745 XImage *ximg, *mask_img;
fcf431dc 7746 int x, y, rc, look_at_corners_p;
8ec8a5ec 7747 unsigned long bg = 0;
333b20bb 7748
4a8e312c
GM
7749 if (img->mask)
7750 {
7751 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 7752 img->mask = None;
4a8e312c 7753 }
dd00328a 7754
333b20bb 7755 /* Create an image and pixmap serving as mask. */
45158a91 7756 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
7757 &mask_img, &img->mask);
7758 if (!rc)
28c7826c 7759 return 0;
333b20bb
GM
7760
7761 /* Get the X image of IMG->pixmap. */
7762 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
7763 ~0, ZPixmap);
7764
fcf431dc
GM
7765 /* Determine the background color of ximg. If HOW is `(R G B)'
7766 take that as color. Otherwise, try to determine the color
7767 heuristically. */
7768 look_at_corners_p = 1;
7769
7770 if (CONSP (how))
7771 {
7772 int rgb[3], i = 0;
7773
7774 while (i < 3
7775 && CONSP (how)
7776 && NATNUMP (XCAR (how)))
7777 {
7778 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
7779 how = XCDR (how);
7780 }
7781
7782 if (i == 3 && NILP (how))
7783 {
7784 char color_name[30];
7785 XColor exact, color;
7786 Colormap cmap;
7787
7788 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
7789
9b2956e2 7790 cmap = FRAME_X_COLORMAP (f);
fcf431dc
GM
7791 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
7792 {
7793 bg = color.pixel;
7794 look_at_corners_p = 0;
7795 }
7796 }
7797 }
7798
7799 if (look_at_corners_p)
333b20bb
GM
7800 {
7801 unsigned long corners[4];
7802 int i, best_count;
7803
7804 /* Get the colors at the corners of ximg. */
7805 corners[0] = XGetPixel (ximg, 0, 0);
7806 corners[1] = XGetPixel (ximg, img->width - 1, 0);
7807 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
7808 corners[3] = XGetPixel (ximg, 0, img->height - 1);
7809
7810 /* Choose the most frequently found color as background. */
7811 for (i = best_count = 0; i < 4; ++i)
7812 {
7813 int j, n;
7814
7815 for (j = n = 0; j < 4; ++j)
7816 if (corners[i] == corners[j])
7817 ++n;
7818
7819 if (n > best_count)
7820 bg = corners[i], best_count = n;
7821 }
7822 }
7823
7824 /* Set all bits in mask_img to 1 whose color in ximg is different
7825 from the background color bg. */
7826 for (y = 0; y < img->height; ++y)
7827 for (x = 0; x < img->width; ++x)
7828 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
7829
7830 /* Put mask_img into img->mask. */
7831 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7832 x_destroy_x_image (mask_img);
7833 XDestroyImage (ximg);
7834
333b20bb
GM
7835 return 1;
7836}
7837
7838
7839\f
7840/***********************************************************************
7841 PBM (mono, gray, color)
7842 ***********************************************************************/
7843
7844static int pbm_image_p P_ ((Lisp_Object object));
7845static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 7846static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
7847
7848/* The symbol `pbm' identifying images of this type. */
7849
7850Lisp_Object Qpbm;
7851
7852/* Indices of image specification fields in gs_format, below. */
7853
7854enum pbm_keyword_index
7855{
7856 PBM_TYPE,
7857 PBM_FILE,
63cec32f 7858 PBM_DATA,
333b20bb
GM
7859 PBM_ASCENT,
7860 PBM_MARGIN,
7861 PBM_RELIEF,
7862 PBM_ALGORITHM,
7863 PBM_HEURISTIC_MASK,
4a8e312c 7864 PBM_MASK,
333b20bb
GM
7865 PBM_LAST
7866};
7867
7868/* Vector of image_keyword structures describing the format
7869 of valid user-defined image specifications. */
7870
7871static struct image_keyword pbm_format[PBM_LAST] =
7872{
7873 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
7874 {":file", IMAGE_STRING_VALUE, 0},
7875 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7876 {":ascent", IMAGE_ASCENT_VALUE, 0},
333b20bb
GM
7877 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7878 {":relief", IMAGE_INTEGER_VALUE, 0},
7879 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
7880 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7881 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
7882};
7883
7884/* Structure describing the image type `pbm'. */
7885
7886static struct image_type pbm_type =
7887{
7888 &Qpbm,
7889 pbm_image_p,
7890 pbm_load,
7891 x_clear_image,
7892 NULL
7893};
7894
7895
7896/* Return non-zero if OBJECT is a valid PBM image specification. */
7897
7898static int
7899pbm_image_p (object)
7900 Lisp_Object object;
7901{
7902 struct image_keyword fmt[PBM_LAST];
7903
7904 bcopy (pbm_format, fmt, sizeof fmt);
7905
7c7ff7f5 7906 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
333b20bb 7907 return 0;
63cec32f
GM
7908
7909 /* Must specify either :data or :file. */
7910 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
7911}
7912
7913
63cec32f
GM
7914/* Scan a decimal number from *S and return it. Advance *S while
7915 reading the number. END is the end of the string. Value is -1 at
7916 end of input. */
333b20bb
GM
7917
7918static int
63cec32f
GM
7919pbm_scan_number (s, end)
7920 unsigned char **s, *end;
333b20bb 7921{
8ec8a5ec 7922 int c = 0, val = -1;
333b20bb 7923
63cec32f 7924 while (*s < end)
333b20bb
GM
7925 {
7926 /* Skip white-space. */
63cec32f 7927 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
7928 ;
7929
7930 if (c == '#')
7931 {
7932 /* Skip comment to end of line. */
63cec32f 7933 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
7934 ;
7935 }
7936 else if (isdigit (c))
7937 {
7938 /* Read decimal number. */
7939 val = c - '0';
63cec32f 7940 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
7941 val = 10 * val + c - '0';
7942 break;
7943 }
7944 else
7945 break;
7946 }
7947
7948 return val;
7949}
7950
7951
7952/* Load PBM image IMG for use on frame F. */
7953
7954static int
7955pbm_load (f, img)
7956 struct frame *f;
7957 struct image *img;
7958{
333b20bb 7959 int raw_p, x, y;
b6d7acec 7960 int width, height, max_color_idx = 0;
333b20bb
GM
7961 XImage *ximg;
7962 Lisp_Object file, specified_file;
7963 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
7964 struct gcpro gcpro1;
63cec32f
GM
7965 unsigned char *contents = NULL;
7966 unsigned char *end, *p;
7967 int size;
333b20bb
GM
7968
7969 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 7970 file = Qnil;
333b20bb 7971 GCPRO1 (file);
333b20bb 7972
63cec32f 7973 if (STRINGP (specified_file))
333b20bb 7974 {
63cec32f
GM
7975 file = x_find_image_file (specified_file);
7976 if (!STRINGP (file))
7977 {
7978 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7979 UNGCPRO;
7980 return 0;
7981 }
333b20bb 7982
5be6c3b0 7983 contents = slurp_file (XSTRING (file)->data, &size);
63cec32f
GM
7984 if (contents == NULL)
7985 {
7986 image_error ("Error reading `%s'", file, Qnil);
7987 UNGCPRO;
7988 return 0;
7989 }
7990
7991 p = contents;
7992 end = contents + size;
7993 }
7994 else
333b20bb 7995 {
63cec32f
GM
7996 Lisp_Object data;
7997 data = image_spec_value (img->spec, QCdata, NULL);
7998 p = XSTRING (data)->data;
7999 end = p + STRING_BYTES (XSTRING (data));
333b20bb
GM
8000 }
8001
63cec32f
GM
8002 /* Check magic number. */
8003 if (end - p < 2 || *p++ != 'P')
333b20bb 8004 {
45158a91 8005 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
8006 error:
8007 xfree (contents);
333b20bb
GM
8008 UNGCPRO;
8009 return 0;
8010 }
8011
63cec32f 8012 switch (*p++)
333b20bb
GM
8013 {
8014 case '1':
8015 raw_p = 0, type = PBM_MONO;
8016 break;
8017
8018 case '2':
8019 raw_p = 0, type = PBM_GRAY;
8020 break;
8021
8022 case '3':
8023 raw_p = 0, type = PBM_COLOR;
8024 break;
8025
8026 case '4':
8027 raw_p = 1, type = PBM_MONO;
8028 break;
8029
8030 case '5':
8031 raw_p = 1, type = PBM_GRAY;
8032 break;
8033
8034 case '6':
8035 raw_p = 1, type = PBM_COLOR;
8036 break;
8037
8038 default:
45158a91 8039 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 8040 goto error;
333b20bb
GM
8041 }
8042
8043 /* Read width, height, maximum color-component. Characters
8044 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
8045 width = pbm_scan_number (&p, end);
8046 height = pbm_scan_number (&p, end);
333b20bb
GM
8047
8048 if (type != PBM_MONO)
8049 {
63cec32f 8050 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
8051 if (raw_p && max_color_idx > 255)
8052 max_color_idx = 255;
8053 }
8054
63cec32f
GM
8055 if (width < 0
8056 || height < 0
333b20bb 8057 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 8058 goto error;
333b20bb 8059
45158a91 8060 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb 8061 &ximg, &img->pixmap))
28c7826c 8062 goto error;
333b20bb
GM
8063
8064 /* Initialize the color hash table. */
8065 init_color_table ();
8066
8067 if (type == PBM_MONO)
8068 {
8069 int c = 0, g;
8070
8071 for (y = 0; y < height; ++y)
8072 for (x = 0; x < width; ++x)
8073 {
8074 if (raw_p)
8075 {
8076 if ((x & 7) == 0)
63cec32f 8077 c = *p++;
333b20bb
GM
8078 g = c & 0x80;
8079 c <<= 1;
8080 }
8081 else
63cec32f 8082 g = pbm_scan_number (&p, end);
333b20bb
GM
8083
8084 XPutPixel (ximg, x, y, (g
8085 ? FRAME_FOREGROUND_PIXEL (f)
8086 : FRAME_BACKGROUND_PIXEL (f)));
8087 }
8088 }
8089 else
8090 {
8091 for (y = 0; y < height; ++y)
8092 for (x = 0; x < width; ++x)
8093 {
8094 int r, g, b;
8095
8096 if (type == PBM_GRAY)
63cec32f 8097 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
8098 else if (raw_p)
8099 {
63cec32f
GM
8100 r = *p++;
8101 g = *p++;
8102 b = *p++;
333b20bb
GM
8103 }
8104 else
8105 {
63cec32f
GM
8106 r = pbm_scan_number (&p, end);
8107 g = pbm_scan_number (&p, end);
8108 b = pbm_scan_number (&p, end);
333b20bb
GM
8109 }
8110
8111 if (r < 0 || g < 0 || b < 0)
8112 {
333b20bb
GM
8113 xfree (ximg->data);
8114 ximg->data = NULL;
8115 XDestroyImage (ximg);
45158a91
GM
8116 image_error ("Invalid pixel value in image `%s'",
8117 img->spec, Qnil);
63cec32f 8118 goto error;
333b20bb
GM
8119 }
8120
8121 /* RGB values are now in the range 0..max_color_idx.
8122 Scale this to the range 0..0xffff supported by X. */
8123 r = (double) r * 65535 / max_color_idx;
8124 g = (double) g * 65535 / max_color_idx;
8125 b = (double) b * 65535 / max_color_idx;
8126 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8127 }
8128 }
8129
333b20bb
GM
8130 /* Store in IMG->colors the colors allocated for the image, and
8131 free the color table. */
8132 img->colors = colors_in_color_table (&img->ncolors);
8133 free_color_table ();
8134
8135 /* Put the image into a pixmap. */
8136 x_put_x_image (f, ximg, img->pixmap, width, height);
8137 x_destroy_x_image (ximg);
333b20bb
GM
8138
8139 img->width = width;
8140 img->height = height;
8141
8142 UNGCPRO;
63cec32f 8143 xfree (contents);
333b20bb
GM
8144 return 1;
8145}
8146
8147
8148\f
8149/***********************************************************************
8150 PNG
8151 ***********************************************************************/
8152
8153#if HAVE_PNG
8154
8155#include <png.h>
8156
8157/* Function prototypes. */
8158
8159static int png_image_p P_ ((Lisp_Object object));
8160static int png_load P_ ((struct frame *f, struct image *img));
8161
8162/* The symbol `png' identifying images of this type. */
8163
8164Lisp_Object Qpng;
8165
8166/* Indices of image specification fields in png_format, below. */
8167
8168enum png_keyword_index
8169{
8170 PNG_TYPE,
63448a4d 8171 PNG_DATA,
333b20bb
GM
8172 PNG_FILE,
8173 PNG_ASCENT,
8174 PNG_MARGIN,
8175 PNG_RELIEF,
8176 PNG_ALGORITHM,
8177 PNG_HEURISTIC_MASK,
4a8e312c 8178 PNG_MASK,
333b20bb
GM
8179 PNG_LAST
8180};
8181
8182/* Vector of image_keyword structures describing the format
8183 of valid user-defined image specifications. */
8184
8185static struct image_keyword png_format[PNG_LAST] =
8186{
8187 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8188 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8189 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8190 {":ascent", IMAGE_ASCENT_VALUE, 0},
333b20bb
GM
8191 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8192 {":relief", IMAGE_INTEGER_VALUE, 0},
8193 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
8194 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8195 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
8196};
8197
06482119 8198/* Structure describing the image type `png'. */
333b20bb
GM
8199
8200static struct image_type png_type =
8201{
8202 &Qpng,
8203 png_image_p,
8204 png_load,
8205 x_clear_image,
8206 NULL
8207};
8208
8209
8210/* Return non-zero if OBJECT is a valid PNG image specification. */
8211
8212static int
8213png_image_p (object)
8214 Lisp_Object object;
8215{
8216 struct image_keyword fmt[PNG_LAST];
8217 bcopy (png_format, fmt, sizeof fmt);
8218
7c7ff7f5 8219 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
333b20bb 8220 return 0;
63448a4d 8221
63cec32f
GM
8222 /* Must specify either the :data or :file keyword. */
8223 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
8224}
8225
8226
8227/* Error and warning handlers installed when the PNG library
8228 is initialized. */
8229
8230static void
8231my_png_error (png_ptr, msg)
8232 png_struct *png_ptr;
8233 char *msg;
8234{
8235 xassert (png_ptr != NULL);
8236 image_error ("PNG error: %s", build_string (msg), Qnil);
8237 longjmp (png_ptr->jmpbuf, 1);
8238}
8239
8240
8241static void
8242my_png_warning (png_ptr, msg)
8243 png_struct *png_ptr;
8244 char *msg;
8245{
8246 xassert (png_ptr != NULL);
8247 image_error ("PNG warning: %s", build_string (msg), Qnil);
8248}
8249
5ad6a5fb
GM
8250/* Memory source for PNG decoding. */
8251
63448a4d
WP
8252struct png_memory_storage
8253{
5ad6a5fb
GM
8254 unsigned char *bytes; /* The data */
8255 size_t len; /* How big is it? */
8256 int index; /* Where are we? */
63448a4d
WP
8257};
8258
5ad6a5fb
GM
8259
8260/* Function set as reader function when reading PNG image from memory.
8261 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8262 bytes from the input to DATA. */
8263
63448a4d 8264static void
5ad6a5fb
GM
8265png_read_from_memory (png_ptr, data, length)
8266 png_structp png_ptr;
8267 png_bytep data;
8268 png_size_t length;
63448a4d 8269{
5ad6a5fb
GM
8270 struct png_memory_storage *tbr
8271 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 8272
5ad6a5fb
GM
8273 if (length > tbr->len - tbr->index)
8274 png_error (png_ptr, "Read error");
8275
8276 bcopy (tbr->bytes + tbr->index, data, length);
8277 tbr->index = tbr->index + length;
63448a4d 8278}
333b20bb
GM
8279
8280/* Load PNG image IMG for use on frame F. Value is non-zero if
8281 successful. */
8282
8283static int
8284png_load (f, img)
8285 struct frame *f;
8286 struct image *img;
8287{
8288 Lisp_Object file, specified_file;
63448a4d 8289 Lisp_Object specified_data;
b6d7acec 8290 int x, y, i;
333b20bb
GM
8291 XImage *ximg, *mask_img = NULL;
8292 struct gcpro gcpro1;
8293 png_struct *png_ptr = NULL;
8294 png_info *info_ptr = NULL, *end_info = NULL;
8ec8a5ec 8295 FILE *volatile fp = NULL;
333b20bb 8296 png_byte sig[8];
8ec8a5ec
GM
8297 png_byte * volatile pixels = NULL;
8298 png_byte ** volatile rows = NULL;
333b20bb
GM
8299 png_uint_32 width, height;
8300 int bit_depth, color_type, interlace_type;
8301 png_byte channels;
8302 png_uint_32 row_bytes;
8303 int transparent_p;
8304 char *gamma_str;
8305 double screen_gamma, image_gamma;
8306 int intent;
63448a4d 8307 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
8308
8309 /* Find out what file to load. */
8310 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8311 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8312 file = Qnil;
8313 GCPRO1 (file);
333b20bb 8314
63448a4d 8315 if (NILP (specified_data))
5ad6a5fb
GM
8316 {
8317 file = x_find_image_file (specified_file);
8318 if (!STRINGP (file))
63448a4d 8319 {
45158a91 8320 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8321 UNGCPRO;
8322 return 0;
8323 }
333b20bb 8324
5ad6a5fb
GM
8325 /* Open the image file. */
8326 fp = fopen (XSTRING (file)->data, "rb");
8327 if (!fp)
8328 {
45158a91 8329 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
8330 UNGCPRO;
8331 fclose (fp);
8332 return 0;
8333 }
63448a4d 8334
5ad6a5fb
GM
8335 /* Check PNG signature. */
8336 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8337 || !png_check_sig (sig, sizeof sig))
8338 {
45158a91 8339 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
8340 UNGCPRO;
8341 fclose (fp);
8342 return 0;
63448a4d 8343 }
5ad6a5fb 8344 }
63448a4d 8345 else
5ad6a5fb
GM
8346 {
8347 /* Read from memory. */
8348 tbr.bytes = XSTRING (specified_data)->data;
8349 tbr.len = STRING_BYTES (XSTRING (specified_data));
8350 tbr.index = 0;
63448a4d 8351
5ad6a5fb
GM
8352 /* Check PNG signature. */
8353 if (tbr.len < sizeof sig
8354 || !png_check_sig (tbr.bytes, sizeof sig))
8355 {
45158a91 8356 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
8357 UNGCPRO;
8358 return 0;
63448a4d 8359 }
333b20bb 8360
5ad6a5fb
GM
8361 /* Need to skip past the signature. */
8362 tbr.bytes += sizeof (sig);
8363 }
8364
333b20bb
GM
8365 /* Initialize read and info structs for PNG lib. */
8366 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8367 my_png_error, my_png_warning);
8368 if (!png_ptr)
8369 {
63448a4d 8370 if (fp) fclose (fp);
333b20bb
GM
8371 UNGCPRO;
8372 return 0;
8373 }
8374
8375 info_ptr = png_create_info_struct (png_ptr);
8376 if (!info_ptr)
8377 {
8378 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 8379 if (fp) fclose (fp);
333b20bb
GM
8380 UNGCPRO;
8381 return 0;
8382 }
8383
8384 end_info = png_create_info_struct (png_ptr);
8385 if (!end_info)
8386 {
8387 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 8388 if (fp) fclose (fp);
333b20bb
GM
8389 UNGCPRO;
8390 return 0;
8391 }
8392
8393 /* Set error jump-back. We come back here when the PNG library
8394 detects an error. */
8395 if (setjmp (png_ptr->jmpbuf))
8396 {
8397 error:
8398 if (png_ptr)
8399 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8400 xfree (pixels);
8401 xfree (rows);
63448a4d 8402 if (fp) fclose (fp);
333b20bb
GM
8403 UNGCPRO;
8404 return 0;
8405 }
8406
8407 /* Read image info. */
63448a4d 8408 if (!NILP (specified_data))
5ad6a5fb 8409 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 8410 else
5ad6a5fb 8411 png_init_io (png_ptr, fp);
63448a4d 8412
333b20bb
GM
8413 png_set_sig_bytes (png_ptr, sizeof sig);
8414 png_read_info (png_ptr, info_ptr);
8415 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
8416 &interlace_type, NULL, NULL);
8417
8418 /* If image contains simply transparency data, we prefer to
8419 construct a clipping mask. */
8420 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
8421 transparent_p = 1;
8422 else
8423 transparent_p = 0;
8424
8425 /* This function is easier to write if we only have to handle
8426 one data format: RGB or RGBA with 8 bits per channel. Let's
8427 transform other formats into that format. */
8428
8429 /* Strip more than 8 bits per channel. */
8430 if (bit_depth == 16)
8431 png_set_strip_16 (png_ptr);
8432
8433 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
8434 if available. */
8435 png_set_expand (png_ptr);
8436
8437 /* Convert grayscale images to RGB. */
8438 if (color_type == PNG_COLOR_TYPE_GRAY
8439 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8440 png_set_gray_to_rgb (png_ptr);
8441
8442 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
8443 gamma_str = getenv ("SCREEN_GAMMA");
8444 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
8445
8446 /* Tell the PNG lib to handle gamma correction for us. */
8447
6c1aa34d 8448#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb
GM
8449 if (png_get_sRGB (png_ptr, info_ptr, &intent))
8450 /* There is a special chunk in the image specifying the gamma. */
8451 png_set_sRGB (png_ptr, info_ptr, intent);
6c1aa34d
GM
8452 else
8453#endif
8454 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
8455 /* Image contains gamma information. */
8456 png_set_gamma (png_ptr, screen_gamma, image_gamma);
8457 else
8458 /* Use a default of 0.5 for the image gamma. */
8459 png_set_gamma (png_ptr, screen_gamma, 0.5);
8460
8461 /* Handle alpha channel by combining the image with a background
8462 color. Do this only if a real alpha channel is supplied. For
8463 simple transparency, we prefer a clipping mask. */
8464 if (!transparent_p)
8465 {
8466 png_color_16 *image_background;
8467
8468 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
8469 /* Image contains a background color with which to
8470 combine the image. */
8471 png_set_background (png_ptr, image_background,
8472 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
8473 else
8474 {
8475 /* Image does not contain a background color with which
8476 to combine the image data via an alpha channel. Use
8477 the frame's background instead. */
8478 XColor color;
8479 Colormap cmap;
8480 png_color_16 frame_background;
8481
9b2956e2 8482 cmap = FRAME_X_COLORMAP (f);
333b20bb
GM
8483 color.pixel = FRAME_BACKGROUND_PIXEL (f);
8484 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
333b20bb
GM
8485
8486 bzero (&frame_background, sizeof frame_background);
8487 frame_background.red = color.red;
8488 frame_background.green = color.green;
8489 frame_background.blue = color.blue;
8490
8491 png_set_background (png_ptr, &frame_background,
8492 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
8493 }
8494 }
8495
8496 /* Update info structure. */
8497 png_read_update_info (png_ptr, info_ptr);
8498
8499 /* Get number of channels. Valid values are 1 for grayscale images
8500 and images with a palette, 2 for grayscale images with transparency
8501 information (alpha channel), 3 for RGB images, and 4 for RGB
8502 images with alpha channel, i.e. RGBA. If conversions above were
8503 sufficient we should only have 3 or 4 channels here. */
8504 channels = png_get_channels (png_ptr, info_ptr);
8505 xassert (channels == 3 || channels == 4);
8506
8507 /* Number of bytes needed for one row of the image. */
8508 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
8509
8510 /* Allocate memory for the image. */
8511 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
8512 rows = (png_byte **) xmalloc (height * sizeof *rows);
8513 for (i = 0; i < height; ++i)
8514 rows[i] = pixels + i * row_bytes;
8515
8516 /* Read the entire image. */
8517 png_read_image (png_ptr, rows);
8518 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
8519 if (fp)
8520 {
8521 fclose (fp);
8522 fp = NULL;
8523 }
333b20bb 8524
333b20bb 8525 /* Create the X image and pixmap. */
45158a91 8526 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb 8527 &img->pixmap))
28c7826c 8528 goto error;
333b20bb
GM
8529
8530 /* Create an image and pixmap serving as mask if the PNG image
8531 contains an alpha channel. */
8532 if (channels == 4
8533 && !transparent_p
45158a91 8534 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
8535 &mask_img, &img->mask))
8536 {
8537 x_destroy_x_image (ximg);
8538 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 8539 img->pixmap = None;
333b20bb
GM
8540 goto error;
8541 }
8542
8543 /* Fill the X image and mask from PNG data. */
8544 init_color_table ();
8545
8546 for (y = 0; y < height; ++y)
8547 {
8548 png_byte *p = rows[y];
8549
8550 for (x = 0; x < width; ++x)
8551 {
8552 unsigned r, g, b;
8553
8554 r = *p++ << 8;
8555 g = *p++ << 8;
8556 b = *p++ << 8;
8557 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8558
8559 /* An alpha channel, aka mask channel, associates variable
8560 transparency with an image. Where other image formats
8561 support binary transparency---fully transparent or fully
8562 opaque---PNG allows up to 254 levels of partial transparency.
8563 The PNG library implements partial transparency by combining
8564 the image with a specified background color.
8565
8566 I'm not sure how to handle this here nicely: because the
8567 background on which the image is displayed may change, for
8568 real alpha channel support, it would be necessary to create
8569 a new image for each possible background.
8570
8571 What I'm doing now is that a mask is created if we have
8572 boolean transparency information. Otherwise I'm using
8573 the frame's background color to combine the image with. */
8574
8575 if (channels == 4)
8576 {
8577 if (mask_img)
8578 XPutPixel (mask_img, x, y, *p > 0);
8579 ++p;
8580 }
8581 }
8582 }
8583
8584 /* Remember colors allocated for this image. */
8585 img->colors = colors_in_color_table (&img->ncolors);
8586 free_color_table ();
8587
8588 /* Clean up. */
8589 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8590 xfree (rows);
8591 xfree (pixels);
8592
8593 img->width = width;
8594 img->height = height;
8595
8596 /* Put the image into the pixmap, then free the X image and its buffer. */
8597 x_put_x_image (f, ximg, img->pixmap, width, height);
8598 x_destroy_x_image (ximg);
8599
8600 /* Same for the mask. */
8601 if (mask_img)
8602 {
8603 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8604 x_destroy_x_image (mask_img);
8605 }
8606
333b20bb
GM
8607 UNGCPRO;
8608 return 1;
8609}
8610
8611#endif /* HAVE_PNG != 0 */
8612
8613
8614\f
8615/***********************************************************************
8616 JPEG
8617 ***********************************************************************/
8618
8619#if HAVE_JPEG
8620
ba06aba4
GM
8621/* Work around a warning about HAVE_STDLIB_H being redefined in
8622 jconfig.h. */
8623#ifdef HAVE_STDLIB_H
8624#define HAVE_STDLIB_H_1
8625#undef HAVE_STDLIB_H
8626#endif /* HAVE_STLIB_H */
8627
333b20bb
GM
8628#include <jpeglib.h>
8629#include <jerror.h>
8630#include <setjmp.h>
8631
ba06aba4
GM
8632#ifdef HAVE_STLIB_H_1
8633#define HAVE_STDLIB_H 1
8634#endif
8635
333b20bb
GM
8636static int jpeg_image_p P_ ((Lisp_Object object));
8637static int jpeg_load P_ ((struct frame *f, struct image *img));
8638
8639/* The symbol `jpeg' identifying images of this type. */
8640
8641Lisp_Object Qjpeg;
8642
8643/* Indices of image specification fields in gs_format, below. */
8644
8645enum jpeg_keyword_index
8646{
8647 JPEG_TYPE,
8e39770a 8648 JPEG_DATA,
333b20bb
GM
8649 JPEG_FILE,
8650 JPEG_ASCENT,
8651 JPEG_MARGIN,
8652 JPEG_RELIEF,
8653 JPEG_ALGORITHM,
8654 JPEG_HEURISTIC_MASK,
4a8e312c 8655 JPEG_MASK,
333b20bb
GM
8656 JPEG_LAST
8657};
8658
8659/* Vector of image_keyword structures describing the format
8660 of valid user-defined image specifications. */
8661
8662static struct image_keyword jpeg_format[JPEG_LAST] =
8663{
8664 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8665 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 8666 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8667 {":ascent", IMAGE_ASCENT_VALUE, 0},
333b20bb
GM
8668 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8669 {":relief", IMAGE_INTEGER_VALUE, 0},
8670 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
8671 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8672 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
8673};
8674
8675/* Structure describing the image type `jpeg'. */
8676
8677static struct image_type jpeg_type =
8678{
8679 &Qjpeg,
8680 jpeg_image_p,
8681 jpeg_load,
8682 x_clear_image,
8683 NULL
8684};
8685
8686
8687/* Return non-zero if OBJECT is a valid JPEG image specification. */
8688
8689static int
8690jpeg_image_p (object)
8691 Lisp_Object object;
8692{
8693 struct image_keyword fmt[JPEG_LAST];
8694
8695 bcopy (jpeg_format, fmt, sizeof fmt);
8696
7c7ff7f5 8697 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
333b20bb 8698 return 0;
8e39770a 8699
63cec32f
GM
8700 /* Must specify either the :data or :file keyword. */
8701 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
8702}
8703
8e39770a 8704
333b20bb
GM
8705struct my_jpeg_error_mgr
8706{
8707 struct jpeg_error_mgr pub;
8708 jmp_buf setjmp_buffer;
8709};
8710
e3130015 8711
333b20bb
GM
8712static void
8713my_error_exit (cinfo)
8714 j_common_ptr cinfo;
8715{
8716 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
8717 longjmp (mgr->setjmp_buffer, 1);
8718}
8719
e3130015 8720
8e39770a
GM
8721/* Init source method for JPEG data source manager. Called by
8722 jpeg_read_header() before any data is actually read. See
8723 libjpeg.doc from the JPEG lib distribution. */
8724
8725static void
8726our_init_source (cinfo)
8727 j_decompress_ptr cinfo;
8728{
8729}
8730
8731
8732/* Fill input buffer method for JPEG data source manager. Called
8733 whenever more data is needed. We read the whole image in one step,
8734 so this only adds a fake end of input marker at the end. */
8735
8736static boolean
8737our_fill_input_buffer (cinfo)
8738 j_decompress_ptr cinfo;
8739{
8740 /* Insert a fake EOI marker. */
8741 struct jpeg_source_mgr *src = cinfo->src;
8742 static JOCTET buffer[2];
8743
8744 buffer[0] = (JOCTET) 0xFF;
8745 buffer[1] = (JOCTET) JPEG_EOI;
8746
8747 src->next_input_byte = buffer;
8748 src->bytes_in_buffer = 2;
8749 return TRUE;
8750}
8751
8752
8753/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
8754 is the JPEG data source manager. */
8755
8756static void
8757our_skip_input_data (cinfo, num_bytes)
8758 j_decompress_ptr cinfo;
8759 long num_bytes;
8760{
8761 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
8762
8763 if (src)
8764 {
8765 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 8766 ERREXIT (cinfo, JERR_INPUT_EOF);
8e39770a
GM
8767
8768 src->bytes_in_buffer -= num_bytes;
8769 src->next_input_byte += num_bytes;
8770 }
8771}
8772
8773
8774/* Method to terminate data source. Called by
8775 jpeg_finish_decompress() after all data has been processed. */
8776
8777static void
8778our_term_source (cinfo)
8779 j_decompress_ptr cinfo;
8780{
8781}
8782
8783
8784/* Set up the JPEG lib for reading an image from DATA which contains
8785 LEN bytes. CINFO is the decompression info structure created for
8786 reading the image. */
8787
8788static void
8789jpeg_memory_src (cinfo, data, len)
8790 j_decompress_ptr cinfo;
8791 JOCTET *data;
8792 unsigned int len;
8793{
8794 struct jpeg_source_mgr *src;
8795
8796 if (cinfo->src == NULL)
8797 {
8798 /* First time for this JPEG object? */
8799 cinfo->src = (struct jpeg_source_mgr *)
8800 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
8801 sizeof (struct jpeg_source_mgr));
8802 src = (struct jpeg_source_mgr *) cinfo->src;
8803 src->next_input_byte = data;
8804 }
8805
8806 src = (struct jpeg_source_mgr *) cinfo->src;
8807 src->init_source = our_init_source;
8808 src->fill_input_buffer = our_fill_input_buffer;
8809 src->skip_input_data = our_skip_input_data;
8810 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
8811 src->term_source = our_term_source;
8812 src->bytes_in_buffer = len;
8813 src->next_input_byte = data;
8814}
8815
5ad6a5fb 8816
333b20bb
GM
8817/* Load image IMG for use on frame F. Patterned after example.c
8818 from the JPEG lib. */
8819
8820static int
8821jpeg_load (f, img)
8822 struct frame *f;
8823 struct image *img;
8824{
8825 struct jpeg_decompress_struct cinfo;
8826 struct my_jpeg_error_mgr mgr;
8827 Lisp_Object file, specified_file;
8e39770a 8828 Lisp_Object specified_data;
8ec8a5ec 8829 FILE * volatile fp = NULL;
333b20bb
GM
8830 JSAMPARRAY buffer;
8831 int row_stride, x, y;
8832 XImage *ximg = NULL;
b6d7acec 8833 int rc;
333b20bb
GM
8834 unsigned long *colors;
8835 int width, height;
8836 struct gcpro gcpro1;
8837
8838 /* Open the JPEG file. */
8839 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 8840 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8841 file = Qnil;
8842 GCPRO1 (file);
8e39770a 8843
8e39770a 8844 if (NILP (specified_data))
333b20bb 8845 {
8e39770a 8846 file = x_find_image_file (specified_file);
8e39770a
GM
8847 if (!STRINGP (file))
8848 {
45158a91 8849 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
8850 UNGCPRO;
8851 return 0;
8852 }
333b20bb 8853
8e39770a
GM
8854 fp = fopen (XSTRING (file)->data, "r");
8855 if (fp == NULL)
8856 {
8857 image_error ("Cannot open `%s'", file, Qnil);
8858 UNGCPRO;
8859 return 0;
8860 }
333b20bb
GM
8861 }
8862
5ad6a5fb
GM
8863 /* Customize libjpeg's error handling to call my_error_exit when an
8864 error is detected. This function will perform a longjmp. */
333b20bb 8865 cinfo.err = jpeg_std_error (&mgr.pub);
14358466 8866 mgr.pub.error_exit = my_error_exit;
333b20bb
GM
8867
8868 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
8869 {
5ad6a5fb
GM
8870 if (rc == 1)
8871 {
8872 /* Called from my_error_exit. Display a JPEG error. */
8873 char buffer[JMSG_LENGTH_MAX];
8874 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 8875 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
8876 build_string (buffer));
8877 }
333b20bb
GM
8878
8879 /* Close the input file and destroy the JPEG object. */
5ad6a5fb 8880 if (fp)
8ec8a5ec 8881 fclose ((FILE *) fp);
333b20bb
GM
8882 jpeg_destroy_decompress (&cinfo);
8883
5ad6a5fb
GM
8884 /* If we already have an XImage, free that. */
8885 x_destroy_x_image (ximg);
333b20bb 8886
5ad6a5fb
GM
8887 /* Free pixmap and colors. */
8888 x_clear_image (f, img);
333b20bb 8889
5ad6a5fb
GM
8890 UNGCPRO;
8891 return 0;
333b20bb
GM
8892 }
8893
8894 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 8895 Read the JPEG image header. */
333b20bb 8896 jpeg_create_decompress (&cinfo);
8e39770a
GM
8897
8898 if (NILP (specified_data))
8ec8a5ec 8899 jpeg_stdio_src (&cinfo, (FILE *) fp);
8e39770a
GM
8900 else
8901 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
8902 STRING_BYTES (XSTRING (specified_data)));
63448a4d 8903
333b20bb
GM
8904 jpeg_read_header (&cinfo, TRUE);
8905
8906 /* Customize decompression so that color quantization will be used.
63448a4d 8907 Start decompression. */
333b20bb
GM
8908 cinfo.quantize_colors = TRUE;
8909 jpeg_start_decompress (&cinfo);
8910 width = img->width = cinfo.output_width;
8911 height = img->height = cinfo.output_height;
8912
333b20bb 8913 /* Create X image and pixmap. */
45158a91 8914 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
28c7826c 8915 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
8916
8917 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
8918 cinfo.actual_number_of_colors has been set with the number of
8919 colors generated, and cinfo.colormap is a two-dimensional array
8920 of color indices in the range 0..cinfo.actual_number_of_colors.
8921 No more than 255 colors will be generated. */
333b20bb 8922 {
5ad6a5fb
GM
8923 int i, ir, ig, ib;
8924
8925 if (cinfo.out_color_components > 2)
8926 ir = 0, ig = 1, ib = 2;
8927 else if (cinfo.out_color_components > 1)
8928 ir = 0, ig = 1, ib = 0;
8929 else
8930 ir = 0, ig = 0, ib = 0;
8931
8932 /* Use the color table mechanism because it handles colors that
8933 cannot be allocated nicely. Such colors will be replaced with
8934 a default color, and we don't have to care about which colors
8935 can be freed safely, and which can't. */
8936 init_color_table ();
8937 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
8938 * sizeof *colors);
333b20bb 8939
5ad6a5fb
GM
8940 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
8941 {
8942 /* Multiply RGB values with 255 because X expects RGB values
8943 in the range 0..0xffff. */
8944 int r = cinfo.colormap[ir][i] << 8;
8945 int g = cinfo.colormap[ig][i] << 8;
8946 int b = cinfo.colormap[ib][i] << 8;
8947 colors[i] = lookup_rgb_color (f, r, g, b);
8948 }
333b20bb 8949
5ad6a5fb
GM
8950 /* Remember those colors actually allocated. */
8951 img->colors = colors_in_color_table (&img->ncolors);
8952 free_color_table ();
333b20bb
GM
8953 }
8954
8955 /* Read pixels. */
8956 row_stride = width * cinfo.output_components;
8957 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 8958 row_stride, 1);
333b20bb
GM
8959 for (y = 0; y < height; ++y)
8960 {
5ad6a5fb
GM
8961 jpeg_read_scanlines (&cinfo, buffer, 1);
8962 for (x = 0; x < cinfo.output_width; ++x)
8963 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
8964 }
8965
8966 /* Clean up. */
8967 jpeg_finish_decompress (&cinfo);
8968 jpeg_destroy_decompress (&cinfo);
5ad6a5fb 8969 if (fp)
8ec8a5ec 8970 fclose ((FILE *) fp);
333b20bb
GM
8971
8972 /* Put the image into the pixmap. */
8973 x_put_x_image (f, ximg, img->pixmap, width, height);
8974 x_destroy_x_image (ximg);
333b20bb
GM
8975 UNGCPRO;
8976 return 1;
8977}
8978
8979#endif /* HAVE_JPEG */
8980
8981
8982\f
8983/***********************************************************************
8984 TIFF
8985 ***********************************************************************/
8986
8987#if HAVE_TIFF
8988
cf4790ad 8989#include <tiffio.h>
333b20bb
GM
8990
8991static int tiff_image_p P_ ((Lisp_Object object));
8992static int tiff_load P_ ((struct frame *f, struct image *img));
8993
8994/* The symbol `tiff' identifying images of this type. */
8995
8996Lisp_Object Qtiff;
8997
8998/* Indices of image specification fields in tiff_format, below. */
8999
9000enum tiff_keyword_index
9001{
9002 TIFF_TYPE,
63448a4d 9003 TIFF_DATA,
333b20bb
GM
9004 TIFF_FILE,
9005 TIFF_ASCENT,
9006 TIFF_MARGIN,
9007 TIFF_RELIEF,
9008 TIFF_ALGORITHM,
9009 TIFF_HEURISTIC_MASK,
4a8e312c 9010 TIFF_MASK,
333b20bb
GM
9011 TIFF_LAST
9012};
9013
9014/* Vector of image_keyword structures describing the format
9015 of valid user-defined image specifications. */
9016
9017static struct image_keyword tiff_format[TIFF_LAST] =
9018{
9019 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9020 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9021 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9022 {":ascent", IMAGE_ASCENT_VALUE, 0},
333b20bb
GM
9023 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9024 {":relief", IMAGE_INTEGER_VALUE, 0},
9025 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
9026 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9027 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
9028};
9029
9030/* Structure describing the image type `tiff'. */
9031
9032static struct image_type tiff_type =
9033{
9034 &Qtiff,
9035 tiff_image_p,
9036 tiff_load,
9037 x_clear_image,
9038 NULL
9039};
9040
9041
9042/* Return non-zero if OBJECT is a valid TIFF image specification. */
9043
9044static int
9045tiff_image_p (object)
9046 Lisp_Object object;
9047{
9048 struct image_keyword fmt[TIFF_LAST];
9049 bcopy (tiff_format, fmt, sizeof fmt);
9050
7c7ff7f5 9051 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
333b20bb 9052 return 0;
5ad6a5fb 9053
63cec32f
GM
9054 /* Must specify either the :data or :file keyword. */
9055 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
9056}
9057
5ad6a5fb
GM
9058
9059/* Reading from a memory buffer for TIFF images Based on the PNG
9060 memory source, but we have to provide a lot of extra functions.
9061 Blah.
63448a4d
WP
9062
9063 We really only need to implement read and seek, but I am not
9064 convinced that the TIFF library is smart enough not to destroy
9065 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
9066 override. */
9067
9068typedef struct
9069{
63448a4d
WP
9070 unsigned char *bytes;
9071 size_t len;
9072 int index;
5ad6a5fb
GM
9073}
9074tiff_memory_source;
63448a4d 9075
e3130015 9076
5ad6a5fb
GM
9077static size_t
9078tiff_read_from_memory (data, buf, size)
9079 thandle_t data;
9080 tdata_t buf;
9081 tsize_t size;
63448a4d 9082{
5ad6a5fb 9083 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9084
9085 if (size > src->len - src->index)
5ad6a5fb
GM
9086 return (size_t) -1;
9087 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
9088 src->index += size;
9089 return size;
9090}
9091
e3130015 9092
5ad6a5fb
GM
9093static size_t
9094tiff_write_from_memory (data, buf, size)
9095 thandle_t data;
9096 tdata_t buf;
9097 tsize_t size;
63448a4d
WP
9098{
9099 return (size_t) -1;
9100}
9101
e3130015 9102
5ad6a5fb
GM
9103static toff_t
9104tiff_seek_in_memory (data, off, whence)
9105 thandle_t data;
9106 toff_t off;
9107 int whence;
63448a4d 9108{
5ad6a5fb 9109 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9110 int idx;
9111
9112 switch (whence)
5ad6a5fb
GM
9113 {
9114 case SEEK_SET: /* Go from beginning of source. */
9115 idx = off;
9116 break;
9117
9118 case SEEK_END: /* Go from end of source. */
9119 idx = src->len + off;
9120 break;
9121
9122 case SEEK_CUR: /* Go from current position. */
9123 idx = src->index + off;
9124 break;
9125
9126 default: /* Invalid `whence'. */
9127 return -1;
9128 }
9129
9130 if (idx > src->len || idx < 0)
9131 return -1;
9132
63448a4d
WP
9133 src->index = idx;
9134 return src->index;
9135}
9136
e3130015 9137
5ad6a5fb
GM
9138static int
9139tiff_close_memory (data)
9140 thandle_t data;
63448a4d
WP
9141{
9142 /* NOOP */
5ad6a5fb 9143 return 0;
63448a4d
WP
9144}
9145
e3130015 9146
5ad6a5fb
GM
9147static int
9148tiff_mmap_memory (data, pbase, psize)
9149 thandle_t data;
9150 tdata_t *pbase;
9151 toff_t *psize;
63448a4d
WP
9152{
9153 /* It is already _IN_ memory. */
5ad6a5fb 9154 return 0;
63448a4d
WP
9155}
9156
e3130015 9157
5ad6a5fb
GM
9158static void
9159tiff_unmap_memory (data, base, size)
9160 thandle_t data;
9161 tdata_t base;
9162 toff_t size;
63448a4d
WP
9163{
9164 /* We don't need to do this. */
63448a4d
WP
9165}
9166
e3130015 9167
5ad6a5fb
GM
9168static toff_t
9169tiff_size_of_memory (data)
9170 thandle_t data;
63448a4d 9171{
5ad6a5fb 9172 return ((tiff_memory_source *) data)->len;
63448a4d 9173}
333b20bb 9174
e3130015 9175
333b20bb
GM
9176/* Load TIFF image IMG for use on frame F. Value is non-zero if
9177 successful. */
9178
9179static int
9180tiff_load (f, img)
9181 struct frame *f;
9182 struct image *img;
9183{
9184 Lisp_Object file, specified_file;
63448a4d 9185 Lisp_Object specified_data;
333b20bb
GM
9186 TIFF *tiff;
9187 int width, height, x, y;
9188 uint32 *buf;
9189 int rc;
9190 XImage *ximg;
9191 struct gcpro gcpro1;
63448a4d 9192 tiff_memory_source memsrc;
333b20bb
GM
9193
9194 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9195 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9196 file = Qnil;
9197 GCPRO1 (file);
63448a4d
WP
9198
9199 if (NILP (specified_data))
5ad6a5fb
GM
9200 {
9201 /* Read from a file */
9202 file = x_find_image_file (specified_file);
9203 if (!STRINGP (file))
63448a4d 9204 {
45158a91 9205 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
9206 UNGCPRO;
9207 return 0;
9208 }
63448a4d 9209
5ad6a5fb
GM
9210 /* Try to open the image file. */
9211 tiff = TIFFOpen (XSTRING (file)->data, "r");
9212 if (tiff == NULL)
9213 {
9214 image_error ("Cannot open `%s'", file, Qnil);
9215 UNGCPRO;
9216 return 0;
63448a4d 9217 }
5ad6a5fb 9218 }
63448a4d 9219 else
5ad6a5fb
GM
9220 {
9221 /* Memory source! */
9222 memsrc.bytes = XSTRING (specified_data)->data;
9223 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9224 memsrc.index = 0;
9225
9226 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9227 (TIFFReadWriteProc) tiff_read_from_memory,
9228 (TIFFReadWriteProc) tiff_write_from_memory,
9229 tiff_seek_in_memory,
9230 tiff_close_memory,
9231 tiff_size_of_memory,
9232 tiff_mmap_memory,
9233 tiff_unmap_memory);
9234
9235 if (!tiff)
63448a4d 9236 {
45158a91 9237 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
9238 UNGCPRO;
9239 return 0;
63448a4d 9240 }
5ad6a5fb 9241 }
333b20bb
GM
9242
9243 /* Get width and height of the image, and allocate a raster buffer
9244 of width x height 32-bit values. */
9245 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9246 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9247 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9248
9249 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9250 TIFFClose (tiff);
9251 if (!rc)
9252 {
45158a91 9253 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
9254 xfree (buf);
9255 UNGCPRO;
9256 return 0;
9257 }
9258
333b20bb 9259 /* Create the X image and pixmap. */
45158a91 9260 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9261 {
333b20bb
GM
9262 xfree (buf);
9263 UNGCPRO;
9264 return 0;
9265 }
9266
9267 /* Initialize the color table. */
9268 init_color_table ();
9269
9270 /* Process the pixel raster. Origin is in the lower-left corner. */
9271 for (y = 0; y < height; ++y)
9272 {
9273 uint32 *row = buf + y * width;
9274
9275 for (x = 0; x < width; ++x)
9276 {
9277 uint32 abgr = row[x];
9278 int r = TIFFGetR (abgr) << 8;
9279 int g = TIFFGetG (abgr) << 8;
9280 int b = TIFFGetB (abgr) << 8;
9281 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9282 }
9283 }
9284
9285 /* Remember the colors allocated for the image. Free the color table. */
9286 img->colors = colors_in_color_table (&img->ncolors);
9287 free_color_table ();
9288
9289 /* Put the image into the pixmap, then free the X image and its buffer. */
9290 x_put_x_image (f, ximg, img->pixmap, width, height);
9291 x_destroy_x_image (ximg);
9292 xfree (buf);
333b20bb
GM
9293
9294 img->width = width;
9295 img->height = height;
9296
9297 UNGCPRO;
9298 return 1;
9299}
9300
9301#endif /* HAVE_TIFF != 0 */
9302
9303
9304\f
9305/***********************************************************************
9306 GIF
9307 ***********************************************************************/
9308
9309#if HAVE_GIF
9310
9311#include <gif_lib.h>
9312
9313static int gif_image_p P_ ((Lisp_Object object));
9314static int gif_load P_ ((struct frame *f, struct image *img));
9315
9316/* The symbol `gif' identifying images of this type. */
9317
9318Lisp_Object Qgif;
9319
9320/* Indices of image specification fields in gif_format, below. */
9321
9322enum gif_keyword_index
9323{
9324 GIF_TYPE,
63448a4d 9325 GIF_DATA,
333b20bb
GM
9326 GIF_FILE,
9327 GIF_ASCENT,
9328 GIF_MARGIN,
9329 GIF_RELIEF,
9330 GIF_ALGORITHM,
9331 GIF_HEURISTIC_MASK,
4a8e312c 9332 GIF_MASK,
333b20bb
GM
9333 GIF_IMAGE,
9334 GIF_LAST
9335};
9336
9337/* Vector of image_keyword structures describing the format
9338 of valid user-defined image specifications. */
9339
9340static struct image_keyword gif_format[GIF_LAST] =
9341{
9342 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9343 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9344 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9345 {":ascent", IMAGE_ASCENT_VALUE, 0},
333b20bb
GM
9346 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9347 {":relief", IMAGE_INTEGER_VALUE, 0},
9348 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9349 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9350 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb
GM
9351 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
9352};
9353
9354/* Structure describing the image type `gif'. */
9355
9356static struct image_type gif_type =
9357{
9358 &Qgif,
9359 gif_image_p,
9360 gif_load,
9361 x_clear_image,
9362 NULL
9363};
9364
e3130015 9365
333b20bb
GM
9366/* Return non-zero if OBJECT is a valid GIF image specification. */
9367
9368static int
9369gif_image_p (object)
9370 Lisp_Object object;
9371{
9372 struct image_keyword fmt[GIF_LAST];
9373 bcopy (gif_format, fmt, sizeof fmt);
9374
7c7ff7f5 9375 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
333b20bb 9376 return 0;
5ad6a5fb 9377
63cec32f
GM
9378 /* Must specify either the :data or :file keyword. */
9379 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
9380}
9381
e3130015 9382
63448a4d
WP
9383/* Reading a GIF image from memory
9384 Based on the PNG memory stuff to a certain extent. */
9385
5ad6a5fb
GM
9386typedef struct
9387{
63448a4d
WP
9388 unsigned char *bytes;
9389 size_t len;
9390 int index;
5ad6a5fb
GM
9391}
9392gif_memory_source;
63448a4d 9393
e3130015 9394
f036834a
GM
9395/* Make the current memory source available to gif_read_from_memory.
9396 It's done this way because not all versions of libungif support
9397 a UserData field in the GifFileType structure. */
9398static gif_memory_source *current_gif_memory_src;
9399
5ad6a5fb
GM
9400static int
9401gif_read_from_memory (file, buf, len)
9402 GifFileType *file;
9403 GifByteType *buf;
9404 int len;
63448a4d 9405{
f036834a 9406 gif_memory_source *src = current_gif_memory_src;
63448a4d 9407
5ad6a5fb
GM
9408 if (len > src->len - src->index)
9409 return -1;
63448a4d 9410
5ad6a5fb 9411 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
9412 src->index += len;
9413 return len;
9414}
333b20bb 9415
5ad6a5fb 9416
333b20bb
GM
9417/* Load GIF image IMG for use on frame F. Value is non-zero if
9418 successful. */
9419
9420static int
9421gif_load (f, img)
9422 struct frame *f;
9423 struct image *img;
9424{
9425 Lisp_Object file, specified_file;
63448a4d 9426 Lisp_Object specified_data;
333b20bb
GM
9427 int rc, width, height, x, y, i;
9428 XImage *ximg;
9429 ColorMapObject *gif_color_map;
9430 unsigned long pixel_colors[256];
9431 GifFileType *gif;
9432 struct gcpro gcpro1;
9433 Lisp_Object image;
9434 int ino, image_left, image_top, image_width, image_height;
63448a4d 9435 gif_memory_source memsrc;
9b784e96 9436 unsigned char *raster;
333b20bb
GM
9437
9438 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9439 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9440 file = Qnil;
9441 GCPRO1 (file);
63448a4d
WP
9442
9443 if (NILP (specified_data))
5ad6a5fb
GM
9444 {
9445 file = x_find_image_file (specified_file);
9446 if (!STRINGP (file))
63448a4d 9447 {
45158a91 9448 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
9449 UNGCPRO;
9450 return 0;
9451 }
333b20bb 9452
5ad6a5fb
GM
9453 /* Open the GIF file. */
9454 gif = DGifOpenFileName (XSTRING (file)->data);
9455 if (gif == NULL)
9456 {
9457 image_error ("Cannot open `%s'", file, Qnil);
9458 UNGCPRO;
9459 return 0;
63448a4d 9460 }
5ad6a5fb 9461 }
63448a4d 9462 else
5ad6a5fb
GM
9463 {
9464 /* Read from memory! */
f036834a 9465 current_gif_memory_src = &memsrc;
5ad6a5fb
GM
9466 memsrc.bytes = XSTRING (specified_data)->data;
9467 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9468 memsrc.index = 0;
63448a4d 9469
5ad6a5fb
GM
9470 gif = DGifOpen(&memsrc, gif_read_from_memory);
9471 if (!gif)
9472 {
45158a91 9473 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
9474 UNGCPRO;
9475 return 0;
63448a4d 9476 }
5ad6a5fb 9477 }
333b20bb
GM
9478
9479 /* Read entire contents. */
9480 rc = DGifSlurp (gif);
9481 if (rc == GIF_ERROR)
9482 {
45158a91 9483 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
9484 DGifCloseFile (gif);
9485 UNGCPRO;
9486 return 0;
9487 }
9488
3ccff1e3 9489 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
9490 ino = INTEGERP (image) ? XFASTINT (image) : 0;
9491 if (ino >= gif->ImageCount)
9492 {
45158a91
GM
9493 image_error ("Invalid image number `%s' in image `%s'",
9494 image, img->spec);
333b20bb
GM
9495 DGifCloseFile (gif);
9496 UNGCPRO;
9497 return 0;
9498 }
9499
9500 width = img->width = gif->SWidth;
9501 height = img->height = gif->SHeight;
9502
333b20bb 9503 /* Create the X image and pixmap. */
45158a91 9504 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9505 {
333b20bb
GM
9506 DGifCloseFile (gif);
9507 UNGCPRO;
9508 return 0;
9509 }
9510
9511 /* Allocate colors. */
9512 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
9513 if (!gif_color_map)
9514 gif_color_map = gif->SColorMap;
9515 init_color_table ();
9516 bzero (pixel_colors, sizeof pixel_colors);
9517
9518 for (i = 0; i < gif_color_map->ColorCount; ++i)
9519 {
9520 int r = gif_color_map->Colors[i].Red << 8;
9521 int g = gif_color_map->Colors[i].Green << 8;
9522 int b = gif_color_map->Colors[i].Blue << 8;
9523 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
9524 }
9525
9526 img->colors = colors_in_color_table (&img->ncolors);
9527 free_color_table ();
9528
9529 /* Clear the part of the screen image that are not covered by
9530 the image from the GIF file. Full animated GIF support
9531 requires more than can be done here (see the gif89 spec,
9532 disposal methods). Let's simply assume that the part
9533 not covered by a sub-image is in the frame's background color. */
9534 image_top = gif->SavedImages[ino].ImageDesc.Top;
9535 image_left = gif->SavedImages[ino].ImageDesc.Left;
9536 image_width = gif->SavedImages[ino].ImageDesc.Width;
9537 image_height = gif->SavedImages[ino].ImageDesc.Height;
9538
9539 for (y = 0; y < image_top; ++y)
9540 for (x = 0; x < width; ++x)
9541 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9542
9543 for (y = image_top + image_height; y < height; ++y)
9544 for (x = 0; x < width; ++x)
9545 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9546
9547 for (y = image_top; y < image_top + image_height; ++y)
9548 {
9549 for (x = 0; x < image_left; ++x)
9550 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9551 for (x = image_left + image_width; x < width; ++x)
9552 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9553 }
9554
9b784e96
GM
9555 /* Read the GIF image into the X image. We use a local variable
9556 `raster' here because RasterBits below is a char *, and invites
9557 problems with bytes >= 0x80. */
9558 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
9559
333b20bb
GM
9560 if (gif->SavedImages[ino].ImageDesc.Interlace)
9561 {
9562 static int interlace_start[] = {0, 4, 2, 1};
9563 static int interlace_increment[] = {8, 8, 4, 2};
9564 int pass, inc;
06482119
GM
9565 int row = interlace_start[0];
9566
9567 pass = 0;
333b20bb 9568
06482119 9569 for (y = 0; y < image_height; y++)
333b20bb 9570 {
06482119
GM
9571 if (row >= image_height)
9572 {
9573 row = interlace_start[++pass];
9574 while (row >= image_height)
9575 row = interlace_start[++pass];
9576 }
9577
9578 for (x = 0; x < image_width; x++)
9579 {
9b784e96 9580 int i = raster[(y * image_width) + x];
06482119
GM
9581 XPutPixel (ximg, x + image_left, row + image_top,
9582 pixel_colors[i]);
9583 }
9584
9585 row += interlace_increment[pass];
333b20bb
GM
9586 }
9587 }
9588 else
9589 {
9590 for (y = 0; y < image_height; ++y)
9591 for (x = 0; x < image_width; ++x)
9592 {
9b784e96 9593 int i = raster[y * image_width + x];
333b20bb
GM
9594 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
9595 }
9596 }
9597
9598 DGifCloseFile (gif);
9599
9600 /* Put the image into the pixmap, then free the X image and its buffer. */
9601 x_put_x_image (f, ximg, img->pixmap, width, height);
9602 x_destroy_x_image (ximg);
333b20bb
GM
9603
9604 UNGCPRO;
9605 return 1;
9606}
9607
9608#endif /* HAVE_GIF != 0 */
9609
9610
9611\f
9612/***********************************************************************
9613 Ghostscript
9614 ***********************************************************************/
9615
9616static int gs_image_p P_ ((Lisp_Object object));
9617static int gs_load P_ ((struct frame *f, struct image *img));
9618static void gs_clear_image P_ ((struct frame *f, struct image *img));
9619
fcf431dc 9620/* The symbol `postscript' identifying images of this type. */
333b20bb 9621
fcf431dc 9622Lisp_Object Qpostscript;
333b20bb
GM
9623
9624/* Keyword symbols. */
9625
9626Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
9627
9628/* Indices of image specification fields in gs_format, below. */
9629
9630enum gs_keyword_index
9631{
9632 GS_TYPE,
9633 GS_PT_WIDTH,
9634 GS_PT_HEIGHT,
9635 GS_FILE,
9636 GS_LOADER,
9637 GS_BOUNDING_BOX,
9638 GS_ASCENT,
9639 GS_MARGIN,
9640 GS_RELIEF,
9641 GS_ALGORITHM,
9642 GS_HEURISTIC_MASK,
4a8e312c 9643 GS_MASK,
333b20bb
GM
9644 GS_LAST
9645};
9646
9647/* Vector of image_keyword structures describing the format
9648 of valid user-defined image specifications. */
9649
9650static struct image_keyword gs_format[GS_LAST] =
9651{
9652 {":type", IMAGE_SYMBOL_VALUE, 1},
9653 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9654 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9655 {":file", IMAGE_STRING_VALUE, 1},
9656 {":loader", IMAGE_FUNCTION_VALUE, 0},
9657 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7c7ff7f5 9658 {":ascent", IMAGE_ASCENT_VALUE, 0},
333b20bb
GM
9659 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9660 {":relief", IMAGE_INTEGER_VALUE, 0},
9661 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
9662 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9663 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
9664};
9665
9666/* Structure describing the image type `ghostscript'. */
9667
9668static struct image_type gs_type =
9669{
fcf431dc 9670 &Qpostscript,
333b20bb
GM
9671 gs_image_p,
9672 gs_load,
9673 gs_clear_image,
9674 NULL
9675};
9676
9677
9678/* Free X resources of Ghostscript image IMG which is used on frame F. */
9679
9680static void
9681gs_clear_image (f, img)
9682 struct frame *f;
9683 struct image *img;
9684{
9685 /* IMG->data.ptr_val may contain a recorded colormap. */
9686 xfree (img->data.ptr_val);
9687 x_clear_image (f, img);
9688}
9689
9690
9691/* Return non-zero if OBJECT is a valid Ghostscript image
9692 specification. */
9693
9694static int
9695gs_image_p (object)
9696 Lisp_Object object;
9697{
9698 struct image_keyword fmt[GS_LAST];
9699 Lisp_Object tem;
9700 int i;
9701
9702 bcopy (gs_format, fmt, sizeof fmt);
9703
7c7ff7f5 9704 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
333b20bb
GM
9705 return 0;
9706
9707 /* Bounding box must be a list or vector containing 4 integers. */
9708 tem = fmt[GS_BOUNDING_BOX].value;
9709 if (CONSP (tem))
9710 {
9711 for (i = 0; i < 4; ++i, tem = XCDR (tem))
9712 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
9713 return 0;
9714 if (!NILP (tem))
9715 return 0;
9716 }
9717 else if (VECTORP (tem))
9718 {
9719 if (XVECTOR (tem)->size != 4)
9720 return 0;
9721 for (i = 0; i < 4; ++i)
9722 if (!INTEGERP (XVECTOR (tem)->contents[i]))
9723 return 0;
9724 }
9725 else
9726 return 0;
9727
9728 return 1;
9729}
9730
9731
9732/* Load Ghostscript image IMG for use on frame F. Value is non-zero
9733 if successful. */
9734
9735static int
9736gs_load (f, img)
9737 struct frame *f;
9738 struct image *img;
9739{
9740 char buffer[100];
9741 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
9742 struct gcpro gcpro1, gcpro2;
9743 Lisp_Object frame;
9744 double in_width, in_height;
9745 Lisp_Object pixel_colors = Qnil;
9746
9747 /* Compute pixel size of pixmap needed from the given size in the
9748 image specification. Sizes in the specification are in pt. 1 pt
9749 = 1/72 in, xdpi and ydpi are stored in the frame's X display
9750 info. */
9751 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
9752 in_width = XFASTINT (pt_width) / 72.0;
9753 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
9754 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
9755 in_height = XFASTINT (pt_height) / 72.0;
9756 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
9757
9758 /* Create the pixmap. */
dd00328a 9759 xassert (img->pixmap == None);
333b20bb
GM
9760 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9761 img->width, img->height,
9762 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
333b20bb
GM
9763
9764 if (!img->pixmap)
9765 {
45158a91 9766 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
9767 return 0;
9768 }
9769
9770 /* Call the loader to fill the pixmap. It returns a process object
9771 if successful. We do not record_unwind_protect here because
9772 other places in redisplay like calling window scroll functions
9773 don't either. Let the Lisp loader use `unwind-protect' instead. */
9774 GCPRO2 (window_and_pixmap_id, pixel_colors);
9775
9776 sprintf (buffer, "%lu %lu",
9777 (unsigned long) FRAME_X_WINDOW (f),
9778 (unsigned long) img->pixmap);
9779 window_and_pixmap_id = build_string (buffer);
9780
9781 sprintf (buffer, "%lu %lu",
9782 FRAME_FOREGROUND_PIXEL (f),
9783 FRAME_BACKGROUND_PIXEL (f));
9784 pixel_colors = build_string (buffer);
9785
9786 XSETFRAME (frame, f);
9787 loader = image_spec_value (img->spec, QCloader, NULL);
9788 if (NILP (loader))
9789 loader = intern ("gs-load-image");
9790
9791 img->data.lisp_val = call6 (loader, frame, img->spec,
9792 make_number (img->width),
9793 make_number (img->height),
9794 window_and_pixmap_id,
9795 pixel_colors);
9796 UNGCPRO;
9797 return PROCESSP (img->data.lisp_val);
9798}
9799
9800
9801/* Kill the Ghostscript process that was started to fill PIXMAP on
9802 frame F. Called from XTread_socket when receiving an event
9803 telling Emacs that Ghostscript has finished drawing. */
9804
9805void
9806x_kill_gs_process (pixmap, f)
9807 Pixmap pixmap;
9808 struct frame *f;
9809{
9810 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9811 int class, i;
9812 struct image *img;
9813
9814 /* Find the image containing PIXMAP. */
9815 for (i = 0; i < c->used; ++i)
9816 if (c->images[i]->pixmap == pixmap)
9817 break;
9818
9819 /* Kill the GS process. We should have found PIXMAP in the image
9820 cache and its image should contain a process object. */
9821 xassert (i < c->used);
9822 img = c->images[i];
9823 xassert (PROCESSP (img->data.lisp_val));
9824 Fkill_process (img->data.lisp_val, Qnil);
9825 img->data.lisp_val = Qnil;
9826
9827 /* On displays with a mutable colormap, figure out the colors
9828 allocated for the image by looking at the pixels of an XImage for
9829 img->pixmap. */
383d6ffc 9830 class = FRAME_X_VISUAL (f)->class;
333b20bb
GM
9831 if (class != StaticColor && class != StaticGray && class != TrueColor)
9832 {
9833 XImage *ximg;
9834
9835 BLOCK_INPUT;
9836
9837 /* Try to get an XImage for img->pixmep. */
9838 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
9839 0, 0, img->width, img->height, ~0, ZPixmap);
9840 if (ximg)
9841 {
9842 int x, y;
9843
9844 /* Initialize the color table. */
9845 init_color_table ();
9846
9847 /* For each pixel of the image, look its color up in the
9848 color table. After having done so, the color table will
9849 contain an entry for each color used by the image. */
9850 for (y = 0; y < img->height; ++y)
9851 for (x = 0; x < img->width; ++x)
9852 {
9853 unsigned long pixel = XGetPixel (ximg, x, y);
9854 lookup_pixel_color (f, pixel);
9855 }
9856
9857 /* Record colors in the image. Free color table and XImage. */
9858 img->colors = colors_in_color_table (&img->ncolors);
9859 free_color_table ();
9860 XDestroyImage (ximg);
9861
9862#if 0 /* This doesn't seem to be the case. If we free the colors
9863 here, we get a BadAccess later in x_clear_image when
9864 freeing the colors. */
9865 /* We have allocated colors once, but Ghostscript has also
9866 allocated colors on behalf of us. So, to get the
9867 reference counts right, free them once. */
9868 if (img->ncolors)
462d5d40 9869 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
9870#endif
9871 }
9872 else
9873 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 9874 img->spec, Qnil);
333b20bb
GM
9875
9876 UNBLOCK_INPUT;
9877 }
9878}
9879
9880
9881\f
9882/***********************************************************************
9883 Window properties
9884 ***********************************************************************/
9885
9886DEFUN ("x-change-window-property", Fx_change_window_property,
9887 Sx_change_window_property, 2, 3, 0,
9888 "Change window property PROP to VALUE on the X window of FRAME.\n\
9889PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
9890selected frame. Value is VALUE.")
9891 (prop, value, frame)
9892 Lisp_Object frame, prop, value;
9893{
9894 struct frame *f = check_x_frame (frame);
9895 Atom prop_atom;
9896
9897 CHECK_STRING (prop, 1);
9898 CHECK_STRING (value, 2);
9899
9900 BLOCK_INPUT;
9901 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
9902 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9903 prop_atom, XA_STRING, 8, PropModeReplace,
9904 XSTRING (value)->data, XSTRING (value)->size);
9905
9906 /* Make sure the property is set when we return. */
9907 XFlush (FRAME_X_DISPLAY (f));
9908 UNBLOCK_INPUT;
9909
9910 return value;
9911}
9912
9913
9914DEFUN ("x-delete-window-property", Fx_delete_window_property,
9915 Sx_delete_window_property, 1, 2, 0,
9916 "Remove window property PROP from X window of FRAME.\n\
9917FRAME nil or omitted means use the selected frame. Value is PROP.")
9918 (prop, frame)
9919 Lisp_Object prop, frame;
9920{
9921 struct frame *f = check_x_frame (frame);
9922 Atom prop_atom;
9923
9924 CHECK_STRING (prop, 1);
9925 BLOCK_INPUT;
9926 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
9927 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
9928
9929 /* Make sure the property is removed when we return. */
9930 XFlush (FRAME_X_DISPLAY (f));
9931 UNBLOCK_INPUT;
9932
9933 return prop;
9934}
9935
9936
9937DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
9938 1, 2, 0,
9939 "Value is the value of window property PROP on FRAME.\n\
9940If FRAME is nil or omitted, use the selected frame. Value is nil\n\
9941if FRAME hasn't a property with name PROP or if PROP has no string\n\
9942value.")
9943 (prop, frame)
9944 Lisp_Object prop, frame;
9945{
9946 struct frame *f = check_x_frame (frame);
9947 Atom prop_atom;
9948 int rc;
9949 Lisp_Object prop_value = Qnil;
9950 char *tmp_data = NULL;
9951 Atom actual_type;
9952 int actual_format;
9953 unsigned long actual_size, bytes_remaining;
9954
9955 CHECK_STRING (prop, 1);
9956 BLOCK_INPUT;
9957 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
9958 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9959 prop_atom, 0, 0, False, XA_STRING,
9960 &actual_type, &actual_format, &actual_size,
9961 &bytes_remaining, (unsigned char **) &tmp_data);
9962 if (rc == Success)
9963 {
9964 int size = bytes_remaining;
9965
9966 XFree (tmp_data);
9967 tmp_data = NULL;
9968
9969 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9970 prop_atom, 0, bytes_remaining,
9971 False, XA_STRING,
9972 &actual_type, &actual_format,
9973 &actual_size, &bytes_remaining,
9974 (unsigned char **) &tmp_data);
9975 if (rc == Success)
9976 prop_value = make_string (tmp_data, size);
9977
9978 XFree (tmp_data);
9979 }
9980
9981 UNBLOCK_INPUT;
9982 return prop_value;
9983}
9984
9985
9986\f
9987/***********************************************************************
9988 Busy cursor
9989 ***********************************************************************/
9990
4ae9a85e
GM
9991/* If non-null, an asynchronous timer that, when it expires, displays
9992 a busy cursor on all frames. */
333b20bb 9993
4ae9a85e 9994static struct atimer *busy_cursor_atimer;
333b20bb 9995
4ae9a85e 9996/* Non-zero means a busy cursor is currently shown. */
333b20bb 9997
4ae9a85e 9998static int busy_cursor_shown_p;
333b20bb 9999
4ae9a85e 10000/* Number of seconds to wait before displaying a busy cursor. */
333b20bb 10001
4ae9a85e 10002static Lisp_Object Vbusy_cursor_delay;
333b20bb 10003
4ae9a85e
GM
10004/* Default number of seconds to wait before displaying a busy
10005 cursor. */
10006
10007#define DEFAULT_BUSY_CURSOR_DELAY 1
10008
10009/* Function prototypes. */
10010
10011static void show_busy_cursor P_ ((struct atimer *));
10012static void hide_busy_cursor P_ ((void));
10013
10014
10015/* Cancel a currently active busy-cursor timer, and start a new one. */
10016
10017void
10018start_busy_cursor ()
333b20bb 10019{
4ae9a85e 10020 EMACS_TIME delay;
3caa99d3 10021 int secs, usecs = 0;
4ae9a85e
GM
10022
10023 cancel_busy_cursor ();
10024
10025 if (INTEGERP (Vbusy_cursor_delay)
10026 && XINT (Vbusy_cursor_delay) > 0)
10027 secs = XFASTINT (Vbusy_cursor_delay);
3caa99d3
GM
10028 else if (FLOATP (Vbusy_cursor_delay)
10029 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
10030 {
10031 Lisp_Object tem;
10032 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
10033 secs = XFASTINT (tem);
10034 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
10035 }
4ae9a85e
GM
10036 else
10037 secs = DEFAULT_BUSY_CURSOR_DELAY;
10038
3caa99d3 10039 EMACS_SET_SECS_USECS (delay, secs, usecs);
4ae9a85e
GM
10040 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
10041 show_busy_cursor, NULL);
10042}
10043
10044
10045/* Cancel the busy cursor timer if active, hide a busy cursor if
10046 shown. */
10047
10048void
10049cancel_busy_cursor ()
10050{
10051 if (busy_cursor_atimer)
99f01f62
GM
10052 {
10053 cancel_atimer (busy_cursor_atimer);
10054 busy_cursor_atimer = NULL;
10055 }
10056
4ae9a85e
GM
10057 if (busy_cursor_shown_p)
10058 hide_busy_cursor ();
10059}
10060
10061
10062/* Timer function of busy_cursor_atimer. TIMER is equal to
10063 busy_cursor_atimer.
10064
10065 Display a busy cursor on all frames by mapping the frames'
10066 busy_window. Set the busy_p flag in the frames' output_data.x
10067 structure to indicate that a busy cursor is shown on the
10068 frames. */
10069
10070static void
10071show_busy_cursor (timer)
10072 struct atimer *timer;
10073{
10074 /* The timer implementation will cancel this timer automatically
10075 after this function has run. Set busy_cursor_atimer to null
10076 so that we know the timer doesn't have to be canceled. */
10077 busy_cursor_atimer = NULL;
10078
10079 if (!busy_cursor_shown_p)
333b20bb
GM
10080 {
10081 Lisp_Object rest, frame;
4ae9a85e
GM
10082
10083 BLOCK_INPUT;
10084
333b20bb
GM
10085 FOR_EACH_FRAME (rest, frame)
10086 if (FRAME_X_P (XFRAME (frame)))
10087 {
10088 struct frame *f = XFRAME (frame);
4ae9a85e 10089
333b20bb 10090 f->output_data.x->busy_p = 1;
4ae9a85e 10091
333b20bb
GM
10092 if (!f->output_data.x->busy_window)
10093 {
10094 unsigned long mask = CWCursor;
10095 XSetWindowAttributes attrs;
4ae9a85e 10096
333b20bb 10097 attrs.cursor = f->output_data.x->busy_cursor;
4ae9a85e 10098
333b20bb
GM
10099 f->output_data.x->busy_window
10100 = XCreateWindow (FRAME_X_DISPLAY (f),
10101 FRAME_OUTER_WINDOW (f),
10102 0, 0, 32000, 32000, 0, 0,
dc6f74cf
GM
10103 InputOnly,
10104 CopyFromParent,
333b20bb
GM
10105 mask, &attrs);
10106 }
4ae9a85e 10107
333b20bb 10108 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
4ae9a85e 10109 XFlush (FRAME_X_DISPLAY (f));
333b20bb 10110 }
333b20bb 10111
4ae9a85e
GM
10112 busy_cursor_shown_p = 1;
10113 UNBLOCK_INPUT;
10114 }
333b20bb
GM
10115}
10116
10117
4ae9a85e 10118/* Hide the busy cursor on all frames, if it is currently shown. */
333b20bb 10119
4ae9a85e
GM
10120static void
10121hide_busy_cursor ()
10122{
10123 if (busy_cursor_shown_p)
333b20bb 10124 {
4ae9a85e
GM
10125 Lisp_Object rest, frame;
10126
10127 BLOCK_INPUT;
10128 FOR_EACH_FRAME (rest, frame)
333b20bb 10129 {
4ae9a85e
GM
10130 struct frame *f = XFRAME (frame);
10131
10132 if (FRAME_X_P (f)
10133 /* Watch out for newly created frames. */
10134 && f->output_data.x->busy_window)
10135 {
10136 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
10137 /* Sync here because XTread_socket looks at the busy_p flag
10138 that is reset to zero below. */
10139 XSync (FRAME_X_DISPLAY (f), False);
10140 f->output_data.x->busy_p = 0;
10141 }
333b20bb 10142 }
333b20bb 10143
4ae9a85e
GM
10144 busy_cursor_shown_p = 0;
10145 UNBLOCK_INPUT;
10146 }
333b20bb
GM
10147}
10148
10149
10150\f
10151/***********************************************************************
10152 Tool tips
10153 ***********************************************************************/
10154
10155static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
10156 Lisp_Object));
10157
10158/* The frame of a currently visible tooltip, or null. */
10159
10160struct frame *tip_frame;
10161
10162/* If non-nil, a timer started that hides the last tooltip when it
10163 fires. */
10164
10165Lisp_Object tip_timer;
10166Window tip_window;
10167
10168/* Create a frame for a tooltip on the display described by DPYINFO.
10169 PARMS is a list of frame parameters. Value is the frame. */
10170
10171static Lisp_Object
10172x_create_tip_frame (dpyinfo, parms)
10173 struct x_display_info *dpyinfo;
10174 Lisp_Object parms;
10175{
10176 struct frame *f;
10177 Lisp_Object frame, tem;
10178 Lisp_Object name;
333b20bb
GM
10179 long window_prompting = 0;
10180 int width, height;
10181 int count = specpdl_ptr - specpdl;
b6d7acec 10182 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb
GM
10183 struct kboard *kb;
10184
10185 check_x ();
10186
10187 /* Use this general default value to start with until we know if
10188 this frame has a specified name. */
10189 Vx_resource_name = Vinvocation_name;
10190
10191#ifdef MULTI_KBOARD
10192 kb = dpyinfo->kboard;
10193#else
10194 kb = &the_only_kboard;
10195#endif
10196
10197 /* Get the name of the frame to use for resource lookup. */
10198 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10199 if (!STRINGP (name)
10200 && !EQ (name, Qunbound)
10201 && !NILP (name))
10202 error ("Invalid frame name--not a string or nil");
10203 Vx_resource_name = name;
10204
10205 frame = Qnil;
10206 GCPRO3 (parms, name, frame);
10207 tip_frame = f = make_frame (1);
10208 XSETFRAME (frame, f);
10209 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
10210
10211 f->output_method = output_x_window;
10212 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10213 bzero (f->output_data.x, sizeof (struct x_output));
10214 f->output_data.x->icon_bitmap = -1;
10215 f->output_data.x->fontset = -1;
61d461a8
GM
10216 f->output_data.x->scroll_bar_foreground_pixel = -1;
10217 f->output_data.x->scroll_bar_background_pixel = -1;
333b20bb
GM
10218 f->icon_name = Qnil;
10219 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
10220#ifdef MULTI_KBOARD
10221 FRAME_KBOARD (f) = kb;
10222#endif
10223 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10224 f->output_data.x->explicit_parent = 0;
10225
61d461a8
GM
10226 /* These colors will be set anyway later, but it's important
10227 to get the color reference counts right, so initialize them! */
10228 {
10229 Lisp_Object black;
10230 struct gcpro gcpro1;
10231
10232 black = build_string ("black");
10233 GCPRO1 (black);
10234 f->output_data.x->foreground_pixel
10235 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10236 f->output_data.x->background_pixel
10237 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10238 f->output_data.x->cursor_pixel
10239 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10240 f->output_data.x->cursor_foreground_pixel
10241 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10242 f->output_data.x->border_pixel
10243 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10244 f->output_data.x->mouse_pixel
10245 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
10246 UNGCPRO;
10247 }
10248
333b20bb
GM
10249 /* Set the name; the functions to which we pass f expect the name to
10250 be set. */
10251 if (EQ (name, Qunbound) || NILP (name))
10252 {
10253 f->name = build_string (dpyinfo->x_id_name);
10254 f->explicit_name = 0;
10255 }
10256 else
10257 {
10258 f->name = name;
10259 f->explicit_name = 1;
10260 /* use the frame's title when getting resources for this frame. */
10261 specbind (Qx_resource_name, name);
10262 }
10263
333b20bb
GM
10264 /* Extract the window parameters from the supplied values
10265 that are needed to determine window geometry. */
10266 {
10267 Lisp_Object font;
10268
10269 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
10270
10271 BLOCK_INPUT;
10272 /* First, try whatever font the caller has specified. */
10273 if (STRINGP (font))
10274 {
10275 tem = Fquery_fontset (font, Qnil);
10276 if (STRINGP (tem))
10277 font = x_new_fontset (f, XSTRING (tem)->data);
10278 else
10279 font = x_new_font (f, XSTRING (font)->data);
10280 }
10281
10282 /* Try out a font which we hope has bold and italic variations. */
10283 if (!STRINGP (font))
10284 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
10285 if (!STRINGP (font))
10286 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
10287 if (! STRINGP (font))
10288 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
10289 if (! STRINGP (font))
10290 /* This was formerly the first thing tried, but it finds too many fonts
10291 and takes too long. */
10292 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
10293 /* If those didn't work, look for something which will at least work. */
10294 if (! STRINGP (font))
10295 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
10296 UNBLOCK_INPUT;
10297 if (! STRINGP (font))
10298 font = build_string ("fixed");
10299
10300 x_default_parameter (f, parms, Qfont, font,
10301 "font", "Font", RES_TYPE_STRING);
10302 }
10303
10304 x_default_parameter (f, parms, Qborder_width, make_number (2),
10305 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
10306
10307 /* This defaults to 2 in order to match xterm. We recognize either
10308 internalBorderWidth or internalBorder (which is what xterm calls
10309 it). */
10310 if (NILP (Fassq (Qinternal_border_width, parms)))
10311 {
10312 Lisp_Object value;
10313
10314 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
10315 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
10316 if (! EQ (value, Qunbound))
10317 parms = Fcons (Fcons (Qinternal_border_width, value),
10318 parms);
10319 }
10320
10321 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
10322 "internalBorderWidth", "internalBorderWidth",
10323 RES_TYPE_NUMBER);
10324
10325 /* Also do the stuff which must be set before the window exists. */
10326 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
10327 "foreground", "Foreground", RES_TYPE_STRING);
10328 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
10329 "background", "Background", RES_TYPE_STRING);
10330 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
10331 "pointerColor", "Foreground", RES_TYPE_STRING);
10332 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
10333 "cursorColor", "Foreground", RES_TYPE_STRING);
10334 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
10335 "borderColor", "BorderColor", RES_TYPE_STRING);
10336
10337 /* Init faces before x_default_parameter is called for scroll-bar
10338 parameters because that function calls x_set_scroll_bar_width,
10339 which calls change_frame_size, which calls Fset_window_buffer,
10340 which runs hooks, which call Fvertical_motion. At the end, we
10341 end up in init_iterator with a null face cache, which should not
10342 happen. */
10343 init_frame_faces (f);
10344
10345 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10346 window_prompting = x_figure_window_size (f, parms);
10347
10348 if (window_prompting & XNegative)
10349 {
10350 if (window_prompting & YNegative)
10351 f->output_data.x->win_gravity = SouthEastGravity;
10352 else
10353 f->output_data.x->win_gravity = NorthEastGravity;
10354 }
10355 else
10356 {
10357 if (window_prompting & YNegative)
10358 f->output_data.x->win_gravity = SouthWestGravity;
10359 else
10360 f->output_data.x->win_gravity = NorthWestGravity;
10361 }
10362
10363 f->output_data.x->size_hint_flags = window_prompting;
10364 {
10365 XSetWindowAttributes attrs;
10366 unsigned long mask;
10367
10368 BLOCK_INPUT;
10369 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
9b2956e2
GM
10370 /* Window managers look at the override-redirect flag to determine
10371 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
10372 3.2.8). */
10373 attrs.override_redirect = True;
10374 attrs.save_under = True;
10375 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
10376 /* Arrange for getting MapNotify and UnmapNotify events. */
10377 attrs.event_mask = StructureNotifyMask;
10378 tip_window
10379 = FRAME_X_WINDOW (f)
10380 = XCreateWindow (FRAME_X_DISPLAY (f),
10381 FRAME_X_DISPLAY_INFO (f)->root_window,
10382 /* x, y, width, height */
10383 0, 0, 1, 1,
10384 /* Border. */
10385 1,
10386 CopyFromParent, InputOutput, CopyFromParent,
10387 mask, &attrs);
10388 UNBLOCK_INPUT;
10389 }
10390
10391 x_make_gc (f);
10392
333b20bb
GM
10393 x_default_parameter (f, parms, Qauto_raise, Qnil,
10394 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10395 x_default_parameter (f, parms, Qauto_lower, Qnil,
10396 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10397 x_default_parameter (f, parms, Qcursor_type, Qbox,
10398 "cursorType", "CursorType", RES_TYPE_SYMBOL);
10399
10400 /* Dimensions, especially f->height, must be done via change_frame_size.
10401 Change will not be effected unless different from the current
10402 f->height. */
10403 width = f->width;
10404 height = f->height;
10405 f->height = 0;
10406 SET_FRAME_WIDTH (f, 0);
8938a4fb 10407 change_frame_size (f, height, width, 1, 0, 0);
333b20bb
GM
10408
10409 f->no_split = 1;
10410
10411 UNGCPRO;
10412
10413 /* It is now ok to make the frame official even if we get an error
10414 below. And the frame needs to be on Vframe_list or making it
10415 visible won't work. */
10416 Vframe_list = Fcons (frame, Vframe_list);
10417
10418 /* Now that the frame is official, it counts as a reference to
10419 its display. */
10420 FRAME_X_DISPLAY_INFO (f)->reference_count++;
10421
10422 return unbind_to (count, frame);
10423}
10424
10425
0634ce98 10426DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
e82d09c9 10427 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
0634ce98
GM
10428A tooltip window is a small X window displaying a string.\n\
10429\n\
333b20bb 10430FRAME nil or omitted means use the selected frame.\n\
0634ce98 10431\n\
333b20bb
GM
10432PARMS is an optional list of frame parameters which can be\n\
10433used to change the tooltip's appearance.\n\
0634ce98 10434\n\
333b20bb 10435Automatically hide the tooltip after TIMEOUT seconds.\n\
0634ce98
GM
10436TIMEOUT nil means use the default timeout of 5 seconds.\n\
10437\n\
10438If the list of frame parameters PARAMS contains a `left' parameters,\n\
10439the tooltip is displayed at that x-position. Otherwise it is\n\
10440displayed at the mouse position, with offset DX added (default is 5 if\n\
10441DX isn't specified). Likewise for the y-position; if a `top' frame\n\
10442parameter is specified, it determines the y-position of the tooltip\n\
10443window, otherwise it is displayed at the mouse position, with offset\n\
10444DY added (default is -5).")
10445 (string, frame, parms, timeout, dx, dy)
10446 Lisp_Object string, frame, parms, timeout, dx, dy;
333b20bb
GM
10447{
10448 struct frame *f;
10449 struct window *w;
10450 Window root, child;
0634ce98 10451 Lisp_Object buffer, top, left;
333b20bb
GM
10452 struct buffer *old_buffer;
10453 struct text_pos pos;
10454 int i, width, height;
10455 int root_x, root_y, win_x, win_y;
10456 unsigned pmask;
393f2d14 10457 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb
GM
10458 int old_windows_or_buffers_changed = windows_or_buffers_changed;
10459 int count = specpdl_ptr - specpdl;
10460
10461 specbind (Qinhibit_redisplay, Qt);
10462
393f2d14 10463 GCPRO4 (string, parms, frame, timeout);
333b20bb
GM
10464
10465 CHECK_STRING (string, 0);
10466 f = check_x_frame (frame);
10467 if (NILP (timeout))
10468 timeout = make_number (5);
10469 else
10470 CHECK_NATNUM (timeout, 2);
0634ce98
GM
10471
10472 if (NILP (dx))
10473 dx = make_number (5);
10474 else
10475 CHECK_NUMBER (dx, 5);
10476
10477 if (NILP (dy))
10478 dy = make_number (-5);
10479 else
10480 CHECK_NUMBER (dy, 6);
333b20bb
GM
10481
10482 /* Hide a previous tip, if any. */
10483 Fx_hide_tip ();
10484
10485 /* Add default values to frame parameters. */
10486 if (NILP (Fassq (Qname, parms)))
10487 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
10488 if (NILP (Fassq (Qinternal_border_width, parms)))
10489 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
10490 if (NILP (Fassq (Qborder_width, parms)))
10491 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
10492 if (NILP (Fassq (Qborder_color, parms)))
10493 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
10494 if (NILP (Fassq (Qbackground_color, parms)))
10495 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
10496 parms);
10497
10498 /* Create a frame for the tooltip, and record it in the global
10499 variable tip_frame. */
10500 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms);
10501 tip_frame = f = XFRAME (frame);
10502
10503 /* Set up the frame's root window. Currently we use a size of 80
10504 columns x 40 lines. If someone wants to show a larger tip, he
10505 will loose. I don't think this is a realistic case. */
10506 w = XWINDOW (FRAME_ROOT_WINDOW (f));
10507 w->left = w->top = make_number (0);
6fc556fd
KR
10508 w->width = make_number (80);
10509 w->height = make_number (40);
333b20bb
GM
10510 adjust_glyphs (f);
10511 w->pseudo_window_p = 1;
10512
10513 /* Display the tooltip text in a temporary buffer. */
10514 buffer = Fget_buffer_create (build_string (" *tip*"));
10515 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10516 old_buffer = current_buffer;
10517 set_buffer_internal_1 (XBUFFER (buffer));
10518 Ferase_buffer ();
6fc556fd 10519 Finsert (1, &string);
333b20bb
GM
10520 clear_glyph_matrix (w->desired_matrix);
10521 clear_glyph_matrix (w->current_matrix);
10522 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
10523 try_window (FRAME_ROOT_WINDOW (f), pos);
10524
10525 /* Compute width and height of the tooltip. */
10526 width = height = 0;
10527 for (i = 0; i < w->desired_matrix->nrows; ++i)
10528 {
10529 struct glyph_row *row = &w->desired_matrix->rows[i];
10530 struct glyph *last;
10531 int row_width;
10532
10533 /* Stop at the first empty row at the end. */
10534 if (!row->enabled_p || !row->displays_text_p)
10535 break;
10536
d7bf0342
GM
10537 /* Let the row go over the full width of the frame. */
10538 row->full_width_p = 1;
333b20bb 10539
e3130015 10540 /* There's a glyph at the end of rows that is used to place
333b20bb
GM
10541 the cursor there. Don't include the width of this glyph. */
10542 if (row->used[TEXT_AREA])
10543 {
10544 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
10545 row_width = row->pixel_width - last->pixel_width;
10546 }
10547 else
10548 row_width = row->pixel_width;
10549
10550 height += row->height;
10551 width = max (width, row_width);
10552 }
10553
10554 /* Add the frame's internal border to the width and height the X
10555 window should have. */
10556 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
10557 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
10558
0634ce98
GM
10559 /* User-specified position? */
10560 left = Fcdr (Fassq (Qleft, parms));
10561 top = Fcdr (Fassq (Qtop, parms));
10562
333b20bb
GM
10563 /* Move the tooltip window where the mouse pointer is. Resize and
10564 show it. */
10565 BLOCK_INPUT;
10566 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
10567 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
0634ce98
GM
10568 UNBLOCK_INPUT;
10569
10570 root_x += XINT (dx);
10571 root_y += XINT (dy);
10572
10573 if (INTEGERP (left))
10574 root_x = XINT (left);
10575 if (INTEGERP (top))
10576 root_y = XINT (top);
10577
10578 BLOCK_INPUT;
333b20bb 10579 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0634ce98 10580 root_x, root_y - height, width, height);
333b20bb
GM
10581 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
10582 UNBLOCK_INPUT;
10583
10584 /* Draw into the window. */
10585 w->must_be_updated_p = 1;
10586 update_single_window (w, 1);
10587
10588 /* Restore original current buffer. */
10589 set_buffer_internal_1 (old_buffer);
10590 windows_or_buffers_changed = old_windows_or_buffers_changed;
10591
10592 /* Let the tip disappear after timeout seconds. */
10593 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
10594 intern ("x-hide-tip"));
a744a2ec
DL
10595
10596 UNGCPRO;
333b20bb
GM
10597 return unbind_to (count, Qnil);
10598}
10599
10600
10601DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
e82d09c9 10602 "Hide the current tooltip window, if there is any.\n\
333b20bb
GM
10603Value is t is tooltip was open, nil otherwise.")
10604 ()
10605{
10606 int count = specpdl_ptr - specpdl;
10607 int deleted_p = 0;
10608
10609 specbind (Qinhibit_redisplay, Qt);
10610
10611 if (!NILP (tip_timer))
10612 {
10613 call1 (intern ("cancel-timer"), tip_timer);
10614 tip_timer = Qnil;
10615 }
10616
10617 if (tip_frame)
10618 {
10619 Lisp_Object frame;
10620
10621 XSETFRAME (frame, tip_frame);
10622 Fdelete_frame (frame, Qt);
10623 tip_frame = NULL;
10624 deleted_p = 1;
10625 }
10626
10627 return unbind_to (count, deleted_p ? Qt : Qnil);
10628}
10629
10630
10631\f
10632/***********************************************************************
10633 File selection dialog
10634 ***********************************************************************/
10635
10636#ifdef USE_MOTIF
10637
10638/* Callback for "OK" and "Cancel" on file selection dialog. */
10639
10640static void
10641file_dialog_cb (widget, client_data, call_data)
10642 Widget widget;
10643 XtPointer call_data, client_data;
10644{
10645 int *result = (int *) client_data;
10646 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
10647 *result = cb->reason;
10648}
10649
10650
10651DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
10652 "Read file name, prompting with PROMPT in directory DIR.\n\
10653Use a file selection dialog.\n\
10654Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
10655specified. Don't let the user enter a file name in the file\n\
10656selection dialog's entry field, if MUSTMATCH is non-nil.")
10657 (prompt, dir, default_filename, mustmatch)
10658 Lisp_Object prompt, dir, default_filename, mustmatch;
10659{
10660 int result;
0fe92f72 10661 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
10662 Lisp_Object file = Qnil;
10663 Widget dialog, text, list, help;
10664 Arg al[10];
10665 int ac = 0;
10666 extern XtAppContext Xt_app_con;
10667 char *title;
10668 XmString dir_xmstring, pattern_xmstring;
10669 int popup_activated_flag;
10670 int count = specpdl_ptr - specpdl;
10671 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
10672
10673 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
10674 CHECK_STRING (prompt, 0);
10675 CHECK_STRING (dir, 1);
10676
10677 /* Prevent redisplay. */
10678 specbind (Qinhibit_redisplay, Qt);
10679
10680 BLOCK_INPUT;
10681
10682 /* Create the dialog with PROMPT as title, using DIR as initial
10683 directory and using "*" as pattern. */
10684 dir = Fexpand_file_name (dir, Qnil);
10685 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
10686 pattern_xmstring = XmStringCreateLocalized ("*");
10687
10688 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
10689 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
10690 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
10691 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
10692 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
10693 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
10694 "fsb", al, ac);
10695 XmStringFree (dir_xmstring);
10696 XmStringFree (pattern_xmstring);
10697
10698 /* Add callbacks for OK and Cancel. */
10699 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
10700 (XtPointer) &result);
10701 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
10702 (XtPointer) &result);
10703
10704 /* Disable the help button since we can't display help. */
10705 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
10706 XtSetSensitive (help, False);
10707
10708 /* Mark OK button as default. */
10709 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
10710 XmNshowAsDefault, True, NULL);
10711
10712 /* If MUSTMATCH is non-nil, disable the file entry field of the
10713 dialog, so that the user must select a file from the files list
10714 box. We can't remove it because we wouldn't have a way to get at
10715 the result file name, then. */
10716 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
10717 if (!NILP (mustmatch))
10718 {
10719 Widget label;
10720 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
10721 XtSetSensitive (text, False);
10722 XtSetSensitive (label, False);
10723 }
10724
10725 /* Manage the dialog, so that list boxes get filled. */
10726 XtManageChild (dialog);
10727
10728 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
10729 must include the path for this to work. */
10730 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
10731 if (STRINGP (default_filename))
10732 {
10733 XmString default_xmstring;
10734 int item_pos;
10735
10736 default_xmstring
10737 = XmStringCreateLocalized (XSTRING (default_filename)->data);
10738
10739 if (!XmListItemExists (list, default_xmstring))
10740 {
10741 /* Add a new item if DEFAULT_FILENAME is not in the list. */
10742 XmListAddItem (list, default_xmstring, 0);
10743 item_pos = 0;
10744 }
10745 else
10746 item_pos = XmListItemPos (list, default_xmstring);
10747 XmStringFree (default_xmstring);
10748
10749 /* Select the item and scroll it into view. */
10750 XmListSelectPos (list, item_pos, True);
10751 XmListSetPos (list, item_pos);
10752 }
10753
03100098
GM
10754#ifdef HAVE_MOTIF_2_1
10755
10756 /* Process events until the user presses Cancel or OK. */
10757 result = 0;
10758 while (result == 0 || XtAppPending (Xt_app_con))
10759 XtAppProcessEvent (Xt_app_con, XtIMAll);
10760
10761#else /* not HAVE_MOTIF_2_1 */
10762
333b20bb
GM
10763 /* Process all events until the user presses Cancel or OK. */
10764 for (result = 0; result == 0;)
10765 {
10766 XEvent event;
10767 Widget widget, parent;
10768
10769 XtAppNextEvent (Xt_app_con, &event);
10770
10771 /* See if the receiver of the event is one of the widgets of
10772 the file selection dialog. If so, dispatch it. If not,
10773 discard it. */
10774 widget = XtWindowToWidget (event.xany.display, event.xany.window);
10775 parent = widget;
10776 while (parent && parent != dialog)
10777 parent = XtParent (parent);
03100098 10778
333b20bb
GM
10779 if (parent == dialog
10780 || (event.type == Expose
10781 && !process_expose_from_menu (event)))
10782 XtDispatchEvent (&event);
10783 }
10784
03100098
GM
10785#endif /* not HAVE_MOTIF_2_1 */
10786
333b20bb
GM
10787 /* Get the result. */
10788 if (result == XmCR_OK)
10789 {
10790 XmString text;
10791 String data;
10792
d1670063 10793 XtVaGetValues (dialog, XmNtextString, &text, NULL);
333b20bb
GM
10794 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
10795 XmStringFree (text);
10796 file = build_string (data);
10797 XtFree (data);
10798 }
10799 else
10800 file = Qnil;
10801
10802 /* Clean up. */
10803 XtUnmanageChild (dialog);
10804 XtDestroyWidget (dialog);
10805 UNBLOCK_INPUT;
10806 UNGCPRO;
10807
10808 /* Make "Cancel" equivalent to C-g. */
10809 if (NILP (file))
10810 Fsignal (Qquit, Qnil);
10811
10812 return unbind_to (count, file);
10813}
10814
10815#endif /* USE_MOTIF */
10816
333b20bb
GM
10817
10818\f
10819/***********************************************************************
10820 Initialization
10821 ***********************************************************************/
10822
10823void
10824syms_of_xfns ()
10825{
10826 /* This is zero if not using X windows. */
10827 x_in_use = 0;
10828
10829 /* The section below is built by the lisp expression at the top of the file,
10830 just above where these variables are declared. */
10831 /*&&& init symbols here &&&*/
10832 Qauto_raise = intern ("auto-raise");
10833 staticpro (&Qauto_raise);
10834 Qauto_lower = intern ("auto-lower");
10835 staticpro (&Qauto_lower);
10836 Qbar = intern ("bar");
dbc4e1c1 10837 staticpro (&Qbar);
f9942c9e
JB
10838 Qborder_color = intern ("border-color");
10839 staticpro (&Qborder_color);
10840 Qborder_width = intern ("border-width");
10841 staticpro (&Qborder_width);
dbc4e1c1
JB
10842 Qbox = intern ("box");
10843 staticpro (&Qbox);
f9942c9e
JB
10844 Qcursor_color = intern ("cursor-color");
10845 staticpro (&Qcursor_color);
dbc4e1c1
JB
10846 Qcursor_type = intern ("cursor-type");
10847 staticpro (&Qcursor_type);
f9942c9e
JB
10848 Qgeometry = intern ("geometry");
10849 staticpro (&Qgeometry);
f9942c9e
JB
10850 Qicon_left = intern ("icon-left");
10851 staticpro (&Qicon_left);
10852 Qicon_top = intern ("icon-top");
10853 staticpro (&Qicon_top);
10854 Qicon_type = intern ("icon-type");
10855 staticpro (&Qicon_type);
80534dd6
KH
10856 Qicon_name = intern ("icon-name");
10857 staticpro (&Qicon_name);
f9942c9e
JB
10858 Qinternal_border_width = intern ("internal-border-width");
10859 staticpro (&Qinternal_border_width);
10860 Qleft = intern ("left");
10861 staticpro (&Qleft);
1ab3d87e
RS
10862 Qright = intern ("right");
10863 staticpro (&Qright);
f9942c9e
JB
10864 Qmouse_color = intern ("mouse-color");
10865 staticpro (&Qmouse_color);
baaed68e
JB
10866 Qnone = intern ("none");
10867 staticpro (&Qnone);
f9942c9e
JB
10868 Qparent_id = intern ("parent-id");
10869 staticpro (&Qparent_id);
4701395c
KH
10870 Qscroll_bar_width = intern ("scroll-bar-width");
10871 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
10872 Qsuppress_icon = intern ("suppress-icon");
10873 staticpro (&Qsuppress_icon);
01f1ba30 10874 Qundefined_color = intern ("undefined-color");
f9942c9e 10875 staticpro (&Qundefined_color);
a3c87d4e
JB
10876 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
10877 staticpro (&Qvertical_scroll_bars);
49795535
JB
10878 Qvisibility = intern ("visibility");
10879 staticpro (&Qvisibility);
f9942c9e
JB
10880 Qwindow_id = intern ("window-id");
10881 staticpro (&Qwindow_id);
2cbebefb
RS
10882 Qouter_window_id = intern ("outer-window-id");
10883 staticpro (&Qouter_window_id);
f9942c9e
JB
10884 Qx_frame_parameter = intern ("x-frame-parameter");
10885 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
10886 Qx_resource_name = intern ("x-resource-name");
10887 staticpro (&Qx_resource_name);
4fe1de12
RS
10888 Quser_position = intern ("user-position");
10889 staticpro (&Quser_position);
10890 Quser_size = intern ("user-size");
10891 staticpro (&Quser_size);
333b20bb
GM
10892 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
10893 staticpro (&Qscroll_bar_foreground);
10894 Qscroll_bar_background = intern ("scroll-bar-background");
10895 staticpro (&Qscroll_bar_background);
d62c8769
GM
10896 Qscreen_gamma = intern ("screen-gamma");
10897 staticpro (&Qscreen_gamma);
563b67aa
GM
10898 Qline_spacing = intern ("line-spacing");
10899 staticpro (&Qline_spacing);
7c7ff7f5
GM
10900 Qcenter = intern ("center");
10901 staticpro (&Qcenter);
96db09e4
KH
10902 Qcompound_text = intern ("compound-text");
10903 staticpro (&Qcompound_text);
f9942c9e
JB
10904 /* This is the end of symbol initialization. */
10905
58cad5ed
KH
10906 /* Text property `display' should be nonsticky by default. */
10907 Vtext_property_default_nonsticky
10908 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
10909
10910
333b20bb
GM
10911 Qlaplace = intern ("laplace");
10912 staticpro (&Qlaplace);
4a8e312c
GM
10913 Qemboss = intern ("emboss");
10914 staticpro (&Qemboss);
10915 Qedge_detection = intern ("edge-detection");
10916 staticpro (&Qedge_detection);
10917 Qheuristic = intern ("heuristic");
10918 staticpro (&Qheuristic);
10919 QCmatrix = intern (":matrix");
10920 staticpro (&QCmatrix);
10921 QCcolor_adjustment = intern (":color-adjustment");
10922 staticpro (&QCcolor_adjustment);
10923 QCmask = intern (":mask");
10924 staticpro (&QCmask);
10925
a367641f
RS
10926 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
10927 staticpro (&Qface_set_after_frame_default);
10928
01f1ba30
JB
10929 Fput (Qundefined_color, Qerror_conditions,
10930 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
10931 Fput (Qundefined_color, Qerror_message,
10932 build_string ("Undefined color"));
10933
f9942c9e
JB
10934 init_x_parm_symbols ();
10935
14819cb3
GM
10936 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
10937 "Non-nil means always draw a cross over disabled images.\n\
10938Disabled images are those having an `:algorithm disabled' property.\n\
10939A cross is always drawn on black & white displays.");
10940 cross_disabled_images = 0;
10941
f1c7b5a6
RS
10942 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
10943 "List of directories to search for bitmap files for X.");
e241c09b 10944 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 10945
16ae08a9 10946 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
d387c960 10947 "The shape of the pointer when over text.\n\
af01ef26
RS
10948Changing the value does not affect existing frames\n\
10949unless you set the mouse color.");
01f1ba30
JB
10950 Vx_pointer_shape = Qnil;
10951
d387c960 10952 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
498e9ac3 10953 "The name Emacs uses to look up X resources.\n\
d387c960
JB
10954`x-get-resource' uses this as the first component of the instance name\n\
10955when requesting resource values.\n\
10956Emacs initially sets `x-resource-name' to the name under which Emacs\n\
10957was invoked, or to the value specified with the `-name' or `-rn'\n\
498e9ac3
RS
10958switches, if present.\n\
10959\n\
10960It may be useful to bind this variable locally around a call\n\
10961to `x-get-resource'. See also the variable `x-resource-class'.");
d387c960 10962 Vx_resource_name = Qnil;
ac63d3d6 10963
498e9ac3
RS
10964 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
10965 "The class Emacs uses to look up X resources.\n\
10966`x-get-resource' uses this as the first component of the instance class\n\
10967when requesting resource values.\n\
10968Emacs initially sets `x-resource-class' to \"Emacs\".\n\
10969\n\
10970Setting this variable permanently is not a reasonable thing to do,\n\
10971but binding this variable locally around a call to `x-get-resource'\n\
333b20bb 10972is a reasonable practice. See also the variable `x-resource-name'.");
498e9ac3
RS
10973 Vx_resource_class = build_string (EMACS_CLASS);
10974
ca0ecbf5 10975#if 0 /* This doesn't really do anything. */
d3b06468 10976 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
ca0ecbf5
RS
10977 "The shape of the pointer when not over text.\n\
10978This variable takes effect when you create a new frame\n\
10979or when you set the mouse color.");
af01ef26 10980#endif
01f1ba30
JB
10981 Vx_nontext_pointer_shape = Qnil;
10982
333b20bb
GM
10983 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
10984 "The shape of the pointer when Emacs is busy.\n\
10985This variable takes effect when you create a new frame\n\
10986or when you set the mouse color.");
10987 Vx_busy_pointer_shape = Qnil;
10988
10989 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
10990 "Non-zero means Emacs displays a busy cursor on window systems.");
10991 display_busy_cursor_p = 1;
10992
4ae9a85e
GM
10993 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
10994 "*Seconds to wait before displaying a busy-cursor.\n\
3caa99d3 10995Value must be an integer or float.");
4ae9a85e
GM
10996 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
10997
ca0ecbf5 10998#if 0 /* This doesn't really do anything. */
d3b06468 10999 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
ca0ecbf5
RS
11000 "The shape of the pointer when over the mode line.\n\
11001This variable takes effect when you create a new frame\n\
11002or when you set the mouse color.");
af01ef26 11003#endif
01f1ba30
JB
11004 Vx_mode_pointer_shape = Qnil;
11005
d3b06468 11006 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ca0ecbf5
RS
11007 &Vx_sensitive_text_pointer_shape,
11008 "The shape of the pointer when over mouse-sensitive text.\n\
11009This variable takes effect when you create a new frame\n\
11010or when you set the mouse color.");
11011 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 11012
01f1ba30
JB
11013 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
11014 "A string indicating the foreground color of the cursor box.");
11015 Vx_cursor_fore_pixel = Qnil;
11016
01f1ba30 11017 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
2d38195d
RS
11018 "Non-nil if no X window manager is in use.\n\
11019Emacs doesn't try to figure this out; this is always nil\n\
11020unless you set it to something else.");
11021 /* We don't have any way to find this out, so set it to nil
11022 and maybe the user would like to set it to t. */
11023 Vx_no_window_manager = Qnil;
1d3dac41 11024
942ea06d
KH
11025 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
11026 &Vx_pixel_size_width_font_regexp,
11027 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
11028\n\
dcc13cda 11029Since Emacs gets width of a font matching with this regexp from\n\
942ea06d
KH
11030PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
11031such a font. This is especially effective for such large fonts as\n\
11032Chinese, Japanese, and Korean.");
11033 Vx_pixel_size_width_font_regexp = Qnil;
11034
fcf431dc 11035 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
333b20bb
GM
11036 "Time after which cached images are removed from the cache.\n\
11037When an image has not been displayed this many seconds, remove it\n\
11038from the image cache. Value must be an integer or nil with nil\n\
11039meaning don't clear the cache.");
fcf431dc 11040 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb 11041
1d3dac41 11042#ifdef USE_X_TOOLKIT
f1d238ef 11043 Fprovide (intern ("x-toolkit"));
1d3dac41 11044#endif
5b827abb
KH
11045#ifdef USE_MOTIF
11046 Fprovide (intern ("motif"));
11047#endif
01f1ba30 11048
01f1ba30 11049 defsubr (&Sx_get_resource);
333b20bb
GM
11050
11051 /* X window properties. */
11052 defsubr (&Sx_change_window_property);
11053 defsubr (&Sx_delete_window_property);
11054 defsubr (&Sx_window_property);
11055
2d764c78 11056 defsubr (&Sxw_display_color_p);
d0c9d219 11057 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
11058 defsubr (&Sxw_color_defined_p);
11059 defsubr (&Sxw_color_values);
9d317b2c 11060 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
11061 defsubr (&Sx_server_vendor);
11062 defsubr (&Sx_server_version);
11063 defsubr (&Sx_display_pixel_width);
11064 defsubr (&Sx_display_pixel_height);
11065 defsubr (&Sx_display_mm_width);
11066 defsubr (&Sx_display_mm_height);
11067 defsubr (&Sx_display_screens);
11068 defsubr (&Sx_display_planes);
11069 defsubr (&Sx_display_color_cells);
11070 defsubr (&Sx_display_visual_class);
11071 defsubr (&Sx_display_backing_store);
11072 defsubr (&Sx_display_save_under);
8af1d7ca 11073 defsubr (&Sx_parse_geometry);
f676886a 11074 defsubr (&Sx_create_frame);
01f1ba30 11075 defsubr (&Sx_open_connection);
08a90d6a
RS
11076 defsubr (&Sx_close_connection);
11077 defsubr (&Sx_display_list);
01f1ba30 11078 defsubr (&Sx_synchronize);
3decc1e7 11079 defsubr (&Sx_focus_frame);
942ea06d
KH
11080
11081 /* Setting callback functions for fontset handler. */
11082 get_font_info_func = x_get_font_info;
333b20bb
GM
11083
11084#if 0 /* This function pointer doesn't seem to be used anywhere.
11085 And the pointer assigned has the wrong type, anyway. */
942ea06d 11086 list_fonts_func = x_list_fonts;
333b20bb
GM
11087#endif
11088
942ea06d 11089 load_font_func = x_load_font;
bc1958c4 11090 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
11091 query_font_func = x_query_font;
11092 set_frame_fontset_func = x_set_font;
11093 check_window_system_func = check_x;
333b20bb
GM
11094
11095 /* Images. */
11096 Qxbm = intern ("xbm");
11097 staticpro (&Qxbm);
11098 QCtype = intern (":type");
11099 staticpro (&QCtype);
333b20bb
GM
11100 QCalgorithm = intern (":algorithm");
11101 staticpro (&QCalgorithm);
11102 QCheuristic_mask = intern (":heuristic-mask");
11103 staticpro (&QCheuristic_mask);
11104 QCcolor_symbols = intern (":color-symbols");
11105 staticpro (&QCcolor_symbols);
333b20bb
GM
11106 QCascent = intern (":ascent");
11107 staticpro (&QCascent);
11108 QCmargin = intern (":margin");
11109 staticpro (&QCmargin);
11110 QCrelief = intern (":relief");
11111 staticpro (&QCrelief);
fcf431dc
GM
11112 Qpostscript = intern ("postscript");
11113 staticpro (&Qpostscript);
333b20bb
GM
11114 QCloader = intern (":loader");
11115 staticpro (&QCloader);
11116 QCbounding_box = intern (":bounding-box");
11117 staticpro (&QCbounding_box);
11118 QCpt_width = intern (":pt-width");
11119 staticpro (&QCpt_width);
11120 QCpt_height = intern (":pt-height");
11121 staticpro (&QCpt_height);
3ccff1e3
GM
11122 QCindex = intern (":index");
11123 staticpro (&QCindex);
333b20bb
GM
11124 Qpbm = intern ("pbm");
11125 staticpro (&Qpbm);
11126
11127#if HAVE_XPM
11128 Qxpm = intern ("xpm");
11129 staticpro (&Qxpm);
11130#endif
11131
11132#if HAVE_JPEG
11133 Qjpeg = intern ("jpeg");
11134 staticpro (&Qjpeg);
11135#endif
11136
11137#if HAVE_TIFF
11138 Qtiff = intern ("tiff");
11139 staticpro (&Qtiff);
11140#endif
11141
11142#if HAVE_GIF
11143 Qgif = intern ("gif");
11144 staticpro (&Qgif);
11145#endif
11146
11147#if HAVE_PNG
11148 Qpng = intern ("png");
11149 staticpro (&Qpng);
11150#endif
11151
11152 defsubr (&Sclear_image_cache);
42677916 11153 defsubr (&Simage_size);
b243755a 11154 defsubr (&Simage_mask_p);
333b20bb 11155
4ae9a85e
GM
11156 busy_cursor_atimer = NULL;
11157 busy_cursor_shown_p = 0;
333b20bb
GM
11158
11159 defsubr (&Sx_show_tip);
11160 defsubr (&Sx_hide_tip);
11161 staticpro (&tip_timer);
11162 tip_timer = Qnil;
11163
11164#ifdef USE_MOTIF
11165 defsubr (&Sx_file_dialog);
11166#endif
11167}
11168
11169
11170void
11171init_xfns ()
11172{
11173 image_types = NULL;
11174 Vimage_types = Qnil;
11175
11176 define_image_type (&xbm_type);
11177 define_image_type (&gs_type);
11178 define_image_type (&pbm_type);
11179
11180#if HAVE_XPM
11181 define_image_type (&xpm_type);
11182#endif
11183
11184#if HAVE_JPEG
11185 define_image_type (&jpeg_type);
11186#endif
11187
11188#if HAVE_TIFF
11189 define_image_type (&tiff_type);
11190#endif
11191
11192#if HAVE_GIF
11193 define_image_type (&gif_type);
11194#endif
11195
11196#if HAVE_PNG
11197 define_image_type (&png_type);
11198#endif
01f1ba30
JB
11199}
11200
11201#endif /* HAVE_X_WINDOWS */