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