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