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