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