Patch from rms.
[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;
9fb5e03d 5444Lisp_Object QCindex, QCuser_data;
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
9fb5e03d
GM
5625 /* Always ignore :user-data DATA. */
5626 if (EQ (key, QCuser_data))
5627 continue;
5628
333b20bb
GM
5629 /* Find key in KEYWORDS. Error if not found. */
5630 for (i = 0; i < nkeywords; ++i)
5631 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
5632 break;
5633
5634 if (i == nkeywords)
5635 {
5636 if (!allow_other_keys_p)
5637 return 0;
5638 continue;
5639 }
5640
5641 /* Record that we recognized the keyword. If a keywords
5642 was found more than once, it's an error. */
5643 keywords[i].value = value;
5644 ++keywords[i].count;
5645
5646 if (keywords[i].count > 1)
5647 return 0;
5648
5649 /* Check type of value against allowed type. */
5650 switch (keywords[i].type)
5651 {
5652 case IMAGE_STRING_VALUE:
5653 if (!STRINGP (value))
5654 return 0;
5655 break;
5656
5657 case IMAGE_SYMBOL_VALUE:
5658 if (!SYMBOLP (value))
5659 return 0;
5660 break;
5661
5662 case IMAGE_POSITIVE_INTEGER_VALUE:
5663 if (!INTEGERP (value) || XINT (value) <= 0)
5664 return 0;
5665 break;
5666
5667 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5668 if (!INTEGERP (value) || XINT (value) < 0)
5669 return 0;
5670 break;
5671
5672 case IMAGE_DONT_CHECK_VALUE_TYPE:
5673 break;
5674
5675 case IMAGE_FUNCTION_VALUE:
5676 value = indirect_function (value);
5677 if (SUBRP (value)
5678 || COMPILEDP (value)
5679 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5680 break;
5681 return 0;
5682
5683 case IMAGE_NUMBER_VALUE:
5684 if (!INTEGERP (value) && !FLOATP (value))
5685 return 0;
5686 break;
5687
5688 case IMAGE_INTEGER_VALUE:
5689 if (!INTEGERP (value))
5690 return 0;
5691 break;
5692
5693 case IMAGE_BOOL_VALUE:
5694 if (!NILP (value) && !EQ (value, Qt))
5695 return 0;
5696 break;
5697
5698 default:
5699 abort ();
5700 break;
5701 }
5702
5703 if (EQ (key, QCtype) && !EQ (type, value))
5704 return 0;
5705 }
5706
5707 /* Check that all mandatory fields are present. */
5708 for (i = 0; i < nkeywords; ++i)
5709 if (keywords[i].mandatory_p && keywords[i].count == 0)
5710 return 0;
5711
5712 return NILP (plist);
5713}
5714
5715
5716/* Return the value of KEY in image specification SPEC. Value is nil
5717 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5718 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5719
5720static Lisp_Object
5721image_spec_value (spec, key, found)
5722 Lisp_Object spec, key;
5723 int *found;
5724{
5725 Lisp_Object tail;
5726
5727 xassert (valid_image_p (spec));
5728
5729 for (tail = XCDR (spec);
5730 CONSP (tail) && CONSP (XCDR (tail));
5731 tail = XCDR (XCDR (tail)))
5732 {
5733 if (EQ (XCAR (tail), key))
5734 {
5735 if (found)
5736 *found = 1;
5737 return XCAR (XCDR (tail));
5738 }
5739 }
5740
5741 if (found)
5742 *found = 0;
5743 return Qnil;
5744}
5745
5746
5747
5748\f
5749/***********************************************************************
5750 Image type independent image structures
5751 ***********************************************************************/
5752
5753static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5754static void free_image P_ ((struct frame *f, struct image *img));
5755
5756
5757/* Allocate and return a new image structure for image specification
5758 SPEC. SPEC has a hash value of HASH. */
5759
5760static struct image *
5761make_image (spec, hash)
5762 Lisp_Object spec;
5763 unsigned hash;
5764{
5765 struct image *img = (struct image *) xmalloc (sizeof *img);
5766
5767 xassert (valid_image_p (spec));
5768 bzero (img, sizeof *img);
5769 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5770 xassert (img->type != NULL);
5771 img->spec = spec;
5772 img->data.lisp_val = Qnil;
5773 img->ascent = DEFAULT_IMAGE_ASCENT;
5774 img->hash = hash;
5775 return img;
5776}
5777
5778
5779/* Free image IMG which was used on frame F, including its resources. */
5780
5781static void
5782free_image (f, img)
5783 struct frame *f;
5784 struct image *img;
5785{
5786 if (img)
5787 {
5788 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5789
5790 /* Remove IMG from the hash table of its cache. */
5791 if (img->prev)
5792 img->prev->next = img->next;
5793 else
5794 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5795
5796 if (img->next)
5797 img->next->prev = img->prev;
5798
5799 c->images[img->id] = NULL;
5800
5801 /* Free resources, then free IMG. */
5802 img->type->free (f, img);
5803 xfree (img);
5804 }
5805}
5806
5807
5808/* Prepare image IMG for display on frame F. Must be called before
5809 drawing an image. */
5810
5811void
5812prepare_image_for_display (f, img)
5813 struct frame *f;
5814 struct image *img;
5815{
5816 EMACS_TIME t;
5817
5818 /* We're about to display IMG, so set its timestamp to `now'. */
5819 EMACS_GET_TIME (t);
5820 img->timestamp = EMACS_SECS (t);
5821
5822 /* If IMG doesn't have a pixmap yet, load it now, using the image
5823 type dependent loader function. */
209061be
GM
5824 if (img->pixmap == 0 && !img->load_failed_p)
5825 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
5826}
5827
5828
5829\f
5830/***********************************************************************
5831 Helper functions for X image types
5832 ***********************************************************************/
5833
5834static void x_clear_image P_ ((struct frame *f, struct image *img));
5835static unsigned long x_alloc_image_color P_ ((struct frame *f,
5836 struct image *img,
5837 Lisp_Object color_name,
5838 unsigned long dflt));
5839
5840/* Free X resources of image IMG which is used on frame F. */
5841
5842static void
5843x_clear_image (f, img)
5844 struct frame *f;
5845 struct image *img;
5846{
5847 if (img->pixmap)
5848 {
5849 BLOCK_INPUT;
5850 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
5851 img->pixmap = 0;
5852 UNBLOCK_INPUT;
5853 }
5854
5855 if (img->ncolors)
5856 {
5857 int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
5858
5859 /* If display has an immutable color map, freeing colors is not
5860 necessary and some servers don't allow it. So don't do it. */
5861 if (class != StaticColor
5862 && class != StaticGray
5863 && class != TrueColor)
5864 {
5865 Colormap cmap;
5866 BLOCK_INPUT;
5867 cmap = DefaultColormapOfScreen (FRAME_X_DISPLAY_INFO (f)->screen);
5868 XFreeColors (FRAME_X_DISPLAY (f), cmap, img->colors,
5869 img->ncolors, 0);
5870 UNBLOCK_INPUT;
5871 }
5872
5873 xfree (img->colors);
5874 img->colors = NULL;
5875 img->ncolors = 0;
5876 }
5877}
5878
5879
5880/* Allocate color COLOR_NAME for image IMG on frame F. If color
5881 cannot be allocated, use DFLT. Add a newly allocated color to
5882 IMG->colors, so that it can be freed again. Value is the pixel
5883 color. */
5884
5885static unsigned long
5886x_alloc_image_color (f, img, color_name, dflt)
5887 struct frame *f;
5888 struct image *img;
5889 Lisp_Object color_name;
5890 unsigned long dflt;
5891{
5892 XColor color;
5893 unsigned long result;
5894
5895 xassert (STRINGP (color_name));
5896
5897 if (defined_color (f, XSTRING (color_name)->data, &color, 1))
5898 {
5899 /* This isn't called frequently so we get away with simply
5900 reallocating the color vector to the needed size, here. */
5901 ++img->ncolors;
5902 img->colors =
5903 (unsigned long *) xrealloc (img->colors,
5904 img->ncolors * sizeof *img->colors);
5905 img->colors[img->ncolors - 1] = color.pixel;
5906 result = color.pixel;
5907 }
5908 else
5909 result = dflt;
5910
5911 return result;
5912}
5913
5914
5915\f
5916/***********************************************************************
5917 Image Cache
5918 ***********************************************************************/
5919
5920static void cache_image P_ ((struct frame *f, struct image *img));
5921
5922
5923/* Return a new, initialized image cache that is allocated from the
5924 heap. Call free_image_cache to free an image cache. */
5925
5926struct image_cache *
5927make_image_cache ()
5928{
5929 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
5930 int size;
5931
5932 bzero (c, sizeof *c);
5933 c->size = 50;
5934 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
5935 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
5936 c->buckets = (struct image **) xmalloc (size);
5937 bzero (c->buckets, size);
5938 return c;
5939}
5940
5941
5942/* Free image cache of frame F. Be aware that X frames share images
5943 caches. */
5944
5945void
5946free_image_cache (f)
5947 struct frame *f;
5948{
5949 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5950 if (c)
5951 {
5952 int i;
5953
5954 /* Cache should not be referenced by any frame when freed. */
5955 xassert (c->refcount == 0);
5956
5957 for (i = 0; i < c->used; ++i)
5958 free_image (f, c->images[i]);
5959 xfree (c->images);
5960 xfree (c);
5961 xfree (c->buckets);
5962 FRAME_X_IMAGE_CACHE (f) = NULL;
5963 }
5964}
5965
5966
5967/* Clear image cache of frame F. FORCE_P non-zero means free all
5968 images. FORCE_P zero means clear only images that haven't been
5969 displayed for some time. Should be called from time to time to
5970 reduce the number of loaded images. If image-eviction-seconds is
5971 non-nil, this frees images in the cache which weren't displayed for
5972 at least that many seconds. */
5973
5974void
5975clear_image_cache (f, force_p)
5976 struct frame *f;
5977 int force_p;
5978{
5979 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5980
fcf431dc 5981 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
5982 {
5983 EMACS_TIME t;
5984 unsigned long old;
5985 int i, any_freed_p = 0;
5986
5987 EMACS_GET_TIME (t);
fcf431dc 5988 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
333b20bb
GM
5989
5990 for (i = 0; i < c->used; ++i)
5991 {
5992 struct image *img = c->images[i];
5993 if (img != NULL
5994 && (force_p
5995 || (img->timestamp > old)))
5996 {
5997 free_image (f, img);
5998 any_freed_p = 1;
5999 }
6000 }
6001
6002 /* We may be clearing the image cache because, for example,
6003 Emacs was iconified for a longer period of time. In that
6004 case, current matrices may still contain references to
6005 images freed above. So, clear these matrices. */
6006 if (any_freed_p)
6007 {
6008 clear_current_matrices (f);
6009 ++windows_or_buffers_changed;
6010 }
6011 }
6012}
6013
6014
6015DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6016 0, 1, 0,
6017 "Clear the image cache of FRAME.\n\
6018FRAME nil or omitted means use the selected frame.\n\
6019FRAME t means clear the image caches of all frames.")
6020 (frame)
6021 Lisp_Object frame;
6022{
6023 if (EQ (frame, Qt))
6024 {
6025 Lisp_Object tail;
6026
6027 FOR_EACH_FRAME (tail, frame)
6028 if (FRAME_X_P (XFRAME (frame)))
6029 clear_image_cache (XFRAME (frame), 1);
6030 }
6031 else
6032 clear_image_cache (check_x_frame (frame), 1);
6033
6034 return Qnil;
6035}
6036
6037
6038/* Return the id of image with Lisp specification SPEC on frame F.
6039 SPEC must be a valid Lisp image specification (see valid_image_p). */
6040
6041int
6042lookup_image (f, spec)
6043 struct frame *f;
6044 Lisp_Object spec;
6045{
6046 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6047 struct image *img;
6048 int i;
6049 unsigned hash;
6050 struct gcpro gcpro1;
4f7ca1f1 6051 EMACS_TIME now;
333b20bb
GM
6052
6053 /* F must be a window-system frame, and SPEC must be a valid image
6054 specification. */
6055 xassert (FRAME_WINDOW_P (f));
6056 xassert (valid_image_p (spec));
6057
6058 GCPRO1 (spec);
6059
6060 /* Look up SPEC in the hash table of the image cache. */
6061 hash = sxhash (spec, 0);
6062 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6063
6064 for (img = c->buckets[i]; img; img = img->next)
6065 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6066 break;
6067
6068 /* If not found, create a new image and cache it. */
6069 if (img == NULL)
6070 {
333b20bb
GM
6071 img = make_image (spec, hash);
6072 cache_image (f, img);
209061be
GM
6073 img->load_failed_p = img->type->load (f, img) == 0;
6074 xassert (!interrupt_input_blocked);
333b20bb
GM
6075
6076 /* If we can't load the image, and we don't have a width and
6077 height, use some arbitrary width and height so that we can
6078 draw a rectangle for it. */
209061be 6079 if (img->load_failed_p)
333b20bb
GM
6080 {
6081 Lisp_Object value;
6082
6083 value = image_spec_value (spec, QCwidth, NULL);
6084 img->width = (INTEGERP (value)
6085 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6086 value = image_spec_value (spec, QCheight, NULL);
6087 img->height = (INTEGERP (value)
6088 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6089 }
6090 else
6091 {
6092 /* Handle image type independent image attributes
6093 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
6094 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
6095 Lisp_Object file;
6096
6097 ascent = image_spec_value (spec, QCascent, NULL);
6098 if (INTEGERP (ascent))
6099 img->ascent = XFASTINT (ascent);
6100
6101 margin = image_spec_value (spec, QCmargin, NULL);
6102 if (INTEGERP (margin) && XINT (margin) >= 0)
6103 img->margin = XFASTINT (margin);
6104
6105 relief = image_spec_value (spec, QCrelief, NULL);
6106 if (INTEGERP (relief))
6107 {
6108 img->relief = XINT (relief);
6109 img->margin += abs (img->relief);
6110 }
6111
6112 /* Should we apply a Laplace edge-detection algorithm? */
6113 algorithm = image_spec_value (spec, QCalgorithm, NULL);
6114 if (img->pixmap && EQ (algorithm, Qlaplace))
6115 x_laplace (f, img);
6116
6117 /* Should we built a mask heuristically? */
6118 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
6119 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
6120 {
6121 file = image_spec_value (spec, QCfile, NULL);
6122 x_build_heuristic_mask (f, file, img, heuristic_mask);
6123 }
6124 }
6125 }
6126
4f7ca1f1
GM
6127 /* We're using IMG, so set its timestamp to `now'. */
6128 EMACS_GET_TIME (now);
6129 img->timestamp = EMACS_SECS (now);
6130
333b20bb
GM
6131 UNGCPRO;
6132
6133 /* Value is the image id. */
6134 return img->id;
6135}
6136
6137
6138/* Cache image IMG in the image cache of frame F. */
6139
6140static void
6141cache_image (f, img)
6142 struct frame *f;
6143 struct image *img;
6144{
6145 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6146 int i;
6147
6148 /* Find a free slot in c->images. */
6149 for (i = 0; i < c->used; ++i)
6150 if (c->images[i] == NULL)
6151 break;
6152
6153 /* If no free slot found, maybe enlarge c->images. */
6154 if (i == c->used && c->used == c->size)
6155 {
6156 c->size *= 2;
6157 c->images = (struct image **) xrealloc (c->images,
6158 c->size * sizeof *c->images);
6159 }
6160
6161 /* Add IMG to c->images, and assign IMG an id. */
6162 c->images[i] = img;
6163 img->id = i;
6164 if (i == c->used)
6165 ++c->used;
6166
6167 /* Add IMG to the cache's hash table. */
6168 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6169 img->next = c->buckets[i];
6170 if (img->next)
6171 img->next->prev = img;
6172 img->prev = NULL;
6173 c->buckets[i] = img;
6174}
6175
6176
6177/* Call FN on every image in the image cache of frame F. Used to mark
6178 Lisp Objects in the image cache. */
6179
6180void
6181forall_images_in_image_cache (f, fn)
6182 struct frame *f;
6183 void (*fn) P_ ((struct image *img));
6184{
6185 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6186 {
6187 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6188 if (c)
6189 {
6190 int i;
6191 for (i = 0; i < c->used; ++i)
6192 if (c->images[i])
6193 fn (c->images[i]);
6194 }
6195 }
6196}
6197
6198
6199\f
6200/***********************************************************************
6201 X support code
6202 ***********************************************************************/
6203
6204static int x_create_x_image_and_pixmap P_ ((struct frame *, Lisp_Object,
6205 int, int, int, XImage **,
6206 Pixmap *));
6207static void x_destroy_x_image P_ ((XImage *));
6208static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6209
6210
6211/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6212 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6213 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6214 via xmalloc. Print error messages via image_error if an error
6215 occurs. FILE is the name of an image file being processed, for
6216 error messages. Value is non-zero if successful. */
6217
6218static int
6219x_create_x_image_and_pixmap (f, file, width, height, depth, ximg, pixmap)
6220 struct frame *f;
6221 Lisp_Object file;
6222 int width, height, depth;
6223 XImage **ximg;
6224 Pixmap *pixmap;
6225{
6226 Display *display = FRAME_X_DISPLAY (f);
6227 Screen *screen = FRAME_X_SCREEN (f);
6228 Window window = FRAME_X_WINDOW (f);
6229
6230 xassert (interrupt_input_blocked);
6231
6232 if (depth <= 0)
6233 depth = DefaultDepthOfScreen (screen);
6234 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6235 depth, ZPixmap, 0, NULL, width, height,
6236 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6237 if (*ximg == NULL)
6238 {
6239 image_error ("Unable to allocate X image for %s", file, Qnil);
6240 return 0;
6241 }
6242
6243 /* Allocate image raster. */
6244 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6245
6246 /* Allocate a pixmap of the same size. */
6247 *pixmap = XCreatePixmap (display, window, width, height, depth);
6248 if (*pixmap == 0)
6249 {
6250 x_destroy_x_image (*ximg);
6251 *ximg = NULL;
6252 image_error ("Unable to create pixmap for `%s'", file, Qnil);
6253 return 0;
6254 }
6255
6256 return 1;
6257}
6258
6259
6260/* Destroy XImage XIMG. Free XIMG->data. */
6261
6262static void
6263x_destroy_x_image (ximg)
6264 XImage *ximg;
6265{
6266 xassert (interrupt_input_blocked);
6267 if (ximg)
6268 {
6269 xfree (ximg->data);
6270 ximg->data = NULL;
6271 XDestroyImage (ximg);
6272 }
6273}
6274
6275
6276/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6277 are width and height of both the image and pixmap. */
6278
ea6b19ca 6279static void
333b20bb
GM
6280x_put_x_image (f, ximg, pixmap, width, height)
6281 struct frame *f;
6282 XImage *ximg;
6283 Pixmap pixmap;
6284{
6285 GC gc;
6286
6287 xassert (interrupt_input_blocked);
6288 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6289 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6290 XFreeGC (FRAME_X_DISPLAY (f), gc);
6291}
6292
6293
6294\f
6295/***********************************************************************
6296 Searching files
6297 ***********************************************************************/
6298
6299static Lisp_Object x_find_image_file P_ ((Lisp_Object));
6300
6301/* Find image file FILE. Look in data-directory, then
6302 x-bitmap-file-path. Value is the full name of the file found, or
6303 nil if not found. */
6304
6305static Lisp_Object
6306x_find_image_file (file)
6307 Lisp_Object file;
6308{
6309 Lisp_Object file_found, search_path;
6310 struct gcpro gcpro1, gcpro2;
6311 int fd;
6312
6313 file_found = Qnil;
6314 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6315 GCPRO2 (file_found, search_path);
6316
6317 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
6318 fd = openp (search_path, file, "", &file_found, 0);
6319
6320 if (fd < 0)
6321 file_found = Qnil;
6322 else
6323 close (fd);
6324
6325 UNGCPRO;
6326 return file_found;
6327}
6328
6329
6330\f
6331/***********************************************************************
6332 XBM images
6333 ***********************************************************************/
6334
6335static int xbm_load P_ ((struct frame *f, struct image *img));
6336static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
6337 Lisp_Object file));
6338static int xbm_image_p P_ ((Lisp_Object object));
6339static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
6340 unsigned char **));
333b20bb
GM
6341
6342
6343/* Indices of image specification fields in xbm_format, below. */
6344
6345enum xbm_keyword_index
6346{
6347 XBM_TYPE,
6348 XBM_FILE,
6349 XBM_WIDTH,
6350 XBM_HEIGHT,
6351 XBM_DATA,
6352 XBM_FOREGROUND,
6353 XBM_BACKGROUND,
6354 XBM_ASCENT,
6355 XBM_MARGIN,
6356 XBM_RELIEF,
6357 XBM_ALGORITHM,
6358 XBM_HEURISTIC_MASK,
6359 XBM_LAST
6360};
6361
6362/* Vector of image_keyword structures describing the format
6363 of valid XBM image specifications. */
6364
6365static struct image_keyword xbm_format[XBM_LAST] =
6366{
6367 {":type", IMAGE_SYMBOL_VALUE, 1},
6368 {":file", IMAGE_STRING_VALUE, 0},
6369 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6370 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6371 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6372 {":foreground", IMAGE_STRING_VALUE, 0},
6373 {":background", IMAGE_STRING_VALUE, 0},
6374 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6375 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6376 {":relief", IMAGE_INTEGER_VALUE, 0},
6377 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6378 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6379};
6380
6381/* Structure describing the image type XBM. */
6382
6383static struct image_type xbm_type =
6384{
6385 &Qxbm,
6386 xbm_image_p,
6387 xbm_load,
6388 x_clear_image,
6389 NULL
6390};
6391
6392/* Tokens returned from xbm_scan. */
6393
6394enum xbm_token
6395{
6396 XBM_TK_IDENT = 256,
6397 XBM_TK_NUMBER
6398};
6399
6400
6401/* Return non-zero if OBJECT is a valid XBM-type image specification.
6402 A valid specification is a list starting with the symbol `image'
6403 The rest of the list is a property list which must contain an
6404 entry `:type xbm..
6405
6406 If the specification specifies a file to load, it must contain
6407 an entry `:file FILENAME' where FILENAME is a string.
6408
6409 If the specification is for a bitmap loaded from memory it must
6410 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6411 WIDTH and HEIGHT are integers > 0. DATA may be:
6412
6413 1. a string large enough to hold the bitmap data, i.e. it must
6414 have a size >= (WIDTH + 7) / 8 * HEIGHT
6415
6416 2. a bool-vector of size >= WIDTH * HEIGHT
6417
6418 3. a vector of strings or bool-vectors, one for each line of the
6419 bitmap.
6420
6421 Both the file and data forms may contain the additional entries
6422 `:background COLOR' and `:foreground COLOR'. If not present,
6423 foreground and background of the frame on which the image is
6424 displayed, is used. */
6425
6426static int
6427xbm_image_p (object)
6428 Lisp_Object object;
6429{
6430 struct image_keyword kw[XBM_LAST];
6431
6432 bcopy (xbm_format, kw, sizeof kw);
6433 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm, 0))
6434 return 0;
6435
6436 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6437
6438 if (kw[XBM_FILE].count)
6439 {
6440 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6441 return 0;
6442 }
6443 else
6444 {
6445 Lisp_Object data;
6446 int width, height;
6447
6448 /* Entries for `:width', `:height' and `:data' must be present. */
6449 if (!kw[XBM_WIDTH].count
6450 || !kw[XBM_HEIGHT].count
6451 || !kw[XBM_DATA].count)
6452 return 0;
6453
6454 data = kw[XBM_DATA].value;
6455 width = XFASTINT (kw[XBM_WIDTH].value);
6456 height = XFASTINT (kw[XBM_HEIGHT].value);
6457
6458 /* Check type of data, and width and height against contents of
6459 data. */
6460 if (VECTORP (data))
6461 {
6462 int i;
6463
6464 /* Number of elements of the vector must be >= height. */
6465 if (XVECTOR (data)->size < height)
6466 return 0;
6467
6468 /* Each string or bool-vector in data must be large enough
6469 for one line of the image. */
6470 for (i = 0; i < height; ++i)
6471 {
6472 Lisp_Object elt = XVECTOR (data)->contents[i];
6473
6474 if (STRINGP (elt))
6475 {
6476 if (XSTRING (elt)->size
6477 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6478 return 0;
6479 }
6480 else if (BOOL_VECTOR_P (elt))
6481 {
6482 if (XBOOL_VECTOR (elt)->size < width)
6483 return 0;
6484 }
6485 else
6486 return 0;
6487 }
6488 }
6489 else if (STRINGP (data))
6490 {
6491 if (XSTRING (data)->size
6492 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6493 return 0;
6494 }
6495 else if (BOOL_VECTOR_P (data))
6496 {
6497 if (XBOOL_VECTOR (data)->size < width * height)
6498 return 0;
6499 }
6500 else
6501 return 0;
6502 }
6503
6504 /* Baseline must be a value between 0 and 100 (a percentage). */
6505 if (kw[XBM_ASCENT].count
6506 && XFASTINT (kw[XBM_ASCENT].value) > 100)
6507 return 0;
6508
6509 return 1;
6510}
6511
6512
6513/* Scan a bitmap file. FP is the stream to read from. Value is
6514 either an enumerator from enum xbm_token, or a character for a
6515 single-character token, or 0 at end of file. If scanning an
6516 identifier, store the lexeme of the identifier in SVAL. If
6517 scanning a number, store its value in *IVAL. */
6518
6519static int
6520xbm_scan (fp, sval, ival)
6521 FILE *fp;
6522 char *sval;
6523 int *ival;
6524{
6525 int c;
6526
6527 /* Skip white space. */
6528 while ((c = fgetc (fp)) != EOF && isspace (c))
6529 ;
6530
6531 if (c == EOF)
6532 c = 0;
6533 else if (isdigit (c))
6534 {
6535 int value = 0, digit;
6536
6537 if (c == '0')
6538 {
6539 c = fgetc (fp);
6540 if (c == 'x' || c == 'X')
6541 {
6542 while ((c = fgetc (fp)) != EOF)
6543 {
6544 if (isdigit (c))
6545 digit = c - '0';
6546 else if (c >= 'a' && c <= 'f')
6547 digit = c - 'a' + 10;
6548 else if (c >= 'A' && c <= 'F')
6549 digit = c - 'A' + 10;
6550 else
6551 break;
6552 value = 16 * value + digit;
6553 }
6554 }
6555 else if (isdigit (c))
6556 {
6557 value = c - '0';
6558 while ((c = fgetc (fp)) != EOF
6559 && isdigit (c))
6560 value = 8 * value + c - '0';
6561 }
6562 }
6563 else
6564 {
6565 value = c - '0';
6566 while ((c = fgetc (fp)) != EOF
6567 && isdigit (c))
6568 value = 10 * value + c - '0';
6569 }
6570
6571 if (c != EOF)
6572 ungetc (c, fp);
6573 *ival = value;
6574 c = XBM_TK_NUMBER;
6575 }
6576 else if (isalpha (c) || c == '_')
6577 {
6578 *sval++ = c;
6579 while ((c = fgetc (fp)) != EOF
6580 && (isalnum (c) || c == '_'))
6581 *sval++ = c;
6582 *sval = 0;
6583 if (c != EOF)
6584 ungetc (c, fp);
6585 c = XBM_TK_IDENT;
6586 }
6587
6588 return c;
6589}
6590
6591
6592/* Replacement for XReadBitmapFileData which isn't available under old
6593 X versions. FILE is the name of the bitmap file to read. Set
6594 *WIDTH and *HEIGHT to the width and height of the image. Return in
6595 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
6596 successful. */
6597
6598static int
6599xbm_read_bitmap_file_data (file, width, height, data)
6600 char *file;
6601 int *width, *height;
6602 unsigned char **data;
6603{
6604 FILE *fp;
6605 char buffer[BUFSIZ];
6606 int padding_p = 0;
6607 int v10 = 0;
6608 int bytes_per_line, i, nbytes;
6609 unsigned char *p;
6610 int value;
6611 int LA1;
6612
6613#define match() \
6614 LA1 = xbm_scan (fp, buffer, &value)
6615
6616#define expect(TOKEN) \
6617 if (LA1 != (TOKEN)) \
6618 goto failure; \
6619 else \
6620 match ()
6621
6622#define expect_ident(IDENT) \
6623 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
6624 match (); \
6625 else \
6626 goto failure
6627
6628 fp = fopen (file, "r");
6629 if (fp == NULL)
6630 return 0;
6631
6632 *width = *height = -1;
6633 *data = NULL;
6634 LA1 = xbm_scan (fp, buffer, &value);
6635
6636 /* Parse defines for width, height and hot-spots. */
6637 while (LA1 == '#')
6638 {
333b20bb
GM
6639 match ();
6640 expect_ident ("define");
6641 expect (XBM_TK_IDENT);
6642
6643 if (LA1 == XBM_TK_NUMBER);
6644 {
6645 char *p = strrchr (buffer, '_');
6646 p = p ? p + 1 : buffer;
6647 if (strcmp (p, "width") == 0)
6648 *width = value;
6649 else if (strcmp (p, "height") == 0)
6650 *height = value;
6651 }
6652 expect (XBM_TK_NUMBER);
6653 }
6654
6655 if (*width < 0 || *height < 0)
6656 goto failure;
6657
6658 /* Parse bits. Must start with `static'. */
6659 expect_ident ("static");
6660 if (LA1 == XBM_TK_IDENT)
6661 {
6662 if (strcmp (buffer, "unsigned") == 0)
6663 {
6664 match ();
6665 expect_ident ("char");
6666 }
6667 else if (strcmp (buffer, "short") == 0)
6668 {
6669 match ();
6670 v10 = 1;
6671 if (*width % 16 && *width % 16 < 9)
6672 padding_p = 1;
6673 }
6674 else if (strcmp (buffer, "char") == 0)
6675 match ();
6676 else
6677 goto failure;
6678 }
6679 else
6680 goto failure;
6681
6682 expect (XBM_TK_IDENT);
6683 expect ('[');
6684 expect (']');
6685 expect ('=');
6686 expect ('{');
6687
6688 bytes_per_line = (*width + 7) / 8 + padding_p;
6689 nbytes = bytes_per_line * *height;
6690 p = *data = (char *) xmalloc (nbytes);
6691
6692 if (v10)
6693 {
6694
6695 for (i = 0; i < nbytes; i += 2)
6696 {
6697 int val = value;
6698 expect (XBM_TK_NUMBER);
6699
6700 *p++ = val;
6701 if (!padding_p || ((i + 2) % bytes_per_line))
6702 *p++ = value >> 8;
6703
6704 if (LA1 == ',' || LA1 == '}')
6705 match ();
6706 else
6707 goto failure;
6708 }
6709 }
6710 else
6711 {
6712 for (i = 0; i < nbytes; ++i)
6713 {
6714 int val = value;
6715 expect (XBM_TK_NUMBER);
6716
6717 *p++ = val;
6718
6719 if (LA1 == ',' || LA1 == '}')
6720 match ();
6721 else
6722 goto failure;
6723 }
6724 }
6725
6726 fclose (fp);
6727 return 1;
6728
6729 failure:
6730
6731 fclose (fp);
6732 if (*data)
6733 {
6734 xfree (*data);
6735 *data = NULL;
6736 }
6737 return 0;
6738
6739#undef match
6740#undef expect
6741#undef expect_ident
6742}
6743
6744
6745/* Load XBM image IMG which will be displayed on frame F from file
6746 SPECIFIED_FILE. Value is non-zero if successful. */
6747
6748static int
6749xbm_load_image_from_file (f, img, specified_file)
6750 struct frame *f;
6751 struct image *img;
6752 Lisp_Object specified_file;
6753{
6754 int rc;
6755 unsigned char *data;
6756 int success_p = 0;
6757 Lisp_Object file;
6758 struct gcpro gcpro1;
6759
6760 xassert (STRINGP (specified_file));
6761 file = Qnil;
6762 GCPRO1 (file);
6763
6764 file = x_find_image_file (specified_file);
6765 if (!STRINGP (file))
6766 {
6767 image_error ("Cannot find image file %s", specified_file, Qnil);
6768 UNGCPRO;
6769 return 0;
6770 }
6771
6772 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
6773 &img->height, &data);
6774 if (rc)
6775 {
6776 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6777 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
6778 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
6779 Lisp_Object value;
6780
6781 xassert (img->width > 0 && img->height > 0);
6782
6783 /* Get foreground and background colors, maybe allocate colors. */
6784 value = image_spec_value (img->spec, QCforeground, NULL);
6785 if (!NILP (value))
6786 foreground = x_alloc_image_color (f, img, value, foreground);
6787
6788 value = image_spec_value (img->spec, QCbackground, NULL);
6789 if (!NILP (value))
6790 background = x_alloc_image_color (f, img, value, background);
6791
6792 BLOCK_INPUT;
6793 img->pixmap
6794 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
6795 FRAME_X_WINDOW (f),
6796 data,
6797 img->width, img->height,
6798 foreground, background,
6799 depth);
6800 xfree (data);
6801
6802 if (img->pixmap == 0)
6803 {
6804 x_clear_image (f, img);
6805 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
6806 }
6807 else
6808 success_p = 1;
6809
6810 UNBLOCK_INPUT;
6811 }
6812 else
6813 image_error ("Error loading XBM image %s", img->spec, Qnil);
6814
6815 UNGCPRO;
6816 return success_p;
6817}
6818
6819
6820/* Fill image IMG which is used on frame F with pixmap data. Value is
6821 non-zero if successful. */
6822
6823static int
6824xbm_load (f, img)
6825 struct frame *f;
6826 struct image *img;
6827{
6828 int success_p = 0;
6829 Lisp_Object file_name;
6830
6831 xassert (xbm_image_p (img->spec));
6832
6833 /* If IMG->spec specifies a file name, create a non-file spec from it. */
6834 file_name = image_spec_value (img->spec, QCfile, NULL);
6835 if (STRINGP (file_name))
6836 success_p = xbm_load_image_from_file (f, img, file_name);
6837 else
6838 {
6839 struct image_keyword fmt[XBM_LAST];
6840 Lisp_Object data;
6841 int depth;
6842 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
6843 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
6844 char *bits;
6845 int parsed_p;
6846
6847 /* Parse the list specification. */
6848 bcopy (xbm_format, fmt, sizeof fmt);
6849 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm, 0);
6850 xassert (parsed_p);
6851
6852 /* Get specified width, and height. */
6853 img->width = XFASTINT (fmt[XBM_WIDTH].value);
6854 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
6855 xassert (img->width > 0 && img->height > 0);
6856
6857 BLOCK_INPUT;
6858
6859 if (fmt[XBM_ASCENT].count)
6860 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
6861
6862 /* Get foreground and background colors, maybe allocate colors. */
6863 if (fmt[XBM_FOREGROUND].count)
6864 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
6865 foreground);
6866 if (fmt[XBM_BACKGROUND].count)
6867 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
6868 background);
6869
6870 /* Set bits to the bitmap image data. */
6871 data = fmt[XBM_DATA].value;
6872 if (VECTORP (data))
6873 {
6874 int i;
6875 char *p;
6876 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6877
6878 p = bits = (char *) alloca (nbytes * img->height);
6879 for (i = 0; i < img->height; ++i, p += nbytes)
6880 {
6881 Lisp_Object line = XVECTOR (data)->contents[i];
6882 if (STRINGP (line))
6883 bcopy (XSTRING (line)->data, p, nbytes);
6884 else
6885 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
6886 }
6887 }
6888 else if (STRINGP (data))
6889 bits = XSTRING (data)->data;
6890 else
6891 bits = XBOOL_VECTOR (data)->data;
6892
6893 /* Create the pixmap. */
6894 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6895 img->pixmap
6896 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
6897 FRAME_X_WINDOW (f),
6898 bits,
6899 img->width, img->height,
6900 foreground, background,
6901 depth);
6902 if (img->pixmap)
6903 success_p = 1;
6904 else
6905 {
6906 image_error ("Unable to create pixmap for XBM image", Qnil, Qnil);
6907 x_clear_image (f, img);
6908 }
6909
6910 UNBLOCK_INPUT;
6911 }
6912
6913 return success_p;
6914}
6915
6916
6917\f
6918/***********************************************************************
6919 XPM images
6920 ***********************************************************************/
6921
6922#if HAVE_XPM
6923
6924static int xpm_image_p P_ ((Lisp_Object object));
6925static int xpm_load P_ ((struct frame *f, struct image *img));
6926static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
6927
6928#include "X11/xpm.h"
6929
6930/* The symbol `xpm' identifying XPM-format images. */
6931
6932Lisp_Object Qxpm;
6933
6934/* Indices of image specification fields in xpm_format, below. */
6935
6936enum xpm_keyword_index
6937{
6938 XPM_TYPE,
6939 XPM_FILE,
6940 XPM_DATA,
6941 XPM_ASCENT,
6942 XPM_MARGIN,
6943 XPM_RELIEF,
6944 XPM_ALGORITHM,
6945 XPM_HEURISTIC_MASK,
6946 XPM_COLOR_SYMBOLS,
6947 XPM_LAST
6948};
6949
6950/* Vector of image_keyword structures describing the format
6951 of valid XPM image specifications. */
6952
6953static struct image_keyword xpm_format[XPM_LAST] =
6954{
6955 {":type", IMAGE_SYMBOL_VALUE, 1},
6956 {":file", IMAGE_STRING_VALUE, 0},
6957 {":data", IMAGE_STRING_VALUE, 0},
6958 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6959 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6960 {":relief", IMAGE_INTEGER_VALUE, 0},
6961 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6962 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6963 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6964};
6965
6966/* Structure describing the image type XBM. */
6967
6968static struct image_type xpm_type =
6969{
6970 &Qxpm,
6971 xpm_image_p,
6972 xpm_load,
6973 x_clear_image,
6974 NULL
6975};
6976
6977
6978/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
6979 for XPM images. Such a list must consist of conses whose car and
6980 cdr are strings. */
6981
6982static int
6983xpm_valid_color_symbols_p (color_symbols)
6984 Lisp_Object color_symbols;
6985{
6986 while (CONSP (color_symbols))
6987 {
6988 Lisp_Object sym = XCAR (color_symbols);
6989 if (!CONSP (sym)
6990 || !STRINGP (XCAR (sym))
6991 || !STRINGP (XCDR (sym)))
6992 break;
6993 color_symbols = XCDR (color_symbols);
6994 }
6995
6996 return NILP (color_symbols);
6997}
6998
6999
7000/* Value is non-zero if OBJECT is a valid XPM image specification. */
7001
7002static int
7003xpm_image_p (object)
7004 Lisp_Object object;
7005{
7006 struct image_keyword fmt[XPM_LAST];
7007 bcopy (xpm_format, fmt, sizeof fmt);
7008 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm, 0)
7009 /* Either `:file' or `:data' must be present. */
7010 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7011 /* Either no `:color-symbols' or it's a list of conses
7012 whose car and cdr are strings. */
7013 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7014 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
7015 && (fmt[XPM_ASCENT].count == 0
7016 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
7017}
7018
7019
7020/* Load image IMG which will be displayed on frame F. Value is
7021 non-zero if successful. */
7022
7023static int
7024xpm_load (f, img)
7025 struct frame *f;
7026 struct image *img;
7027{
7028 int rc, i;
7029 XpmAttributes attrs;
7030 Lisp_Object specified_file, color_symbols;
7031
7032 /* Configure the XPM lib. Use the visual of frame F. Allocate
7033 close colors. Return colors allocated. */
7034 bzero (&attrs, sizeof attrs);
7035 attrs.visual = FRAME_X_DISPLAY_INFO (f)->visual;
7036 attrs.valuemask |= XpmVisual;
7037 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7038#ifdef XpmAllocCloseColors
333b20bb
GM
7039 attrs.alloc_close_colors = 1;
7040 attrs.valuemask |= XpmAllocCloseColors;
e4c082be
RS
7041#else
7042 attrs.closeness = 600;
7043 attrs.valuemask |= XpmCloseness;
7044#endif
333b20bb
GM
7045
7046 /* If image specification contains symbolic color definitions, add
7047 these to `attrs'. */
7048 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7049 if (CONSP (color_symbols))
7050 {
7051 Lisp_Object tail;
7052 XpmColorSymbol *xpm_syms;
7053 int i, size;
7054
7055 attrs.valuemask |= XpmColorSymbols;
7056
7057 /* Count number of symbols. */
7058 attrs.numsymbols = 0;
7059 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7060 ++attrs.numsymbols;
7061
7062 /* Allocate an XpmColorSymbol array. */
7063 size = attrs.numsymbols * sizeof *xpm_syms;
7064 xpm_syms = (XpmColorSymbol *) alloca (size);
7065 bzero (xpm_syms, size);
7066 attrs.colorsymbols = xpm_syms;
7067
7068 /* Fill the color symbol array. */
7069 for (tail = color_symbols, i = 0;
7070 CONSP (tail);
7071 ++i, tail = XCDR (tail))
7072 {
7073 Lisp_Object name = XCAR (XCAR (tail));
7074 Lisp_Object color = XCDR (XCAR (tail));
7075 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7076 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7077 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7078 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7079 }
7080 }
7081
7082 /* Create a pixmap for the image, either from a file, or from a
7083 string buffer containing data in the same format as an XPM file. */
7084 BLOCK_INPUT;
7085 specified_file = image_spec_value (img->spec, QCfile, NULL);
7086 if (STRINGP (specified_file))
7087 {
7088 Lisp_Object file = x_find_image_file (specified_file);
7089 if (!STRINGP (file))
7090 {
7091 image_error ("Cannot find image file %s", specified_file, Qnil);
209061be 7092 UNBLOCK_INPUT;
333b20bb
GM
7093 return 0;
7094 }
7095
7096 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7097 XSTRING (file)->data, &img->pixmap, &img->mask,
7098 &attrs);
7099 }
7100 else
7101 {
7102 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7103 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7104 XSTRING (buffer)->data,
7105 &img->pixmap, &img->mask,
7106 &attrs);
7107 }
7108 UNBLOCK_INPUT;
7109
7110 if (rc == XpmSuccess)
7111 {
7112 /* Remember allocated colors. */
7113 img->ncolors = attrs.nalloc_pixels;
7114 img->colors = (unsigned long *) xmalloc (img->ncolors
7115 * sizeof *img->colors);
7116 for (i = 0; i < attrs.nalloc_pixels; ++i)
7117 img->colors[i] = attrs.alloc_pixels[i];
7118
7119 img->width = attrs.width;
7120 img->height = attrs.height;
7121 xassert (img->width > 0 && img->height > 0);
7122
7123 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
7124 BLOCK_INPUT;
7125 XpmFreeAttributes (&attrs);
7126 UNBLOCK_INPUT;
7127 }
7128 else
7129 {
7130 switch (rc)
7131 {
7132 case XpmOpenFailed:
7133 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7134 break;
7135
7136 case XpmFileInvalid:
7137 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7138 break;
7139
7140 case XpmNoMemory:
7141 image_error ("Out of memory (%s)", img->spec, Qnil);
7142 break;
7143
7144 case XpmColorFailed:
7145 image_error ("Color allocation error (%s)", img->spec, Qnil);
7146 break;
7147
7148 default:
7149 image_error ("Unknown error (%s)", img->spec, Qnil);
7150 break;
7151 }
7152 }
7153
7154 return rc == XpmSuccess;
7155}
7156
7157#endif /* HAVE_XPM != 0 */
7158
7159\f
7160/***********************************************************************
7161 Color table
7162 ***********************************************************************/
7163
7164/* An entry in the color table mapping an RGB color to a pixel color. */
7165
7166struct ct_color
7167{
7168 int r, g, b;
7169 unsigned long pixel;
7170
7171 /* Next in color table collision list. */
7172 struct ct_color *next;
7173};
7174
7175/* The bucket vector size to use. Must be prime. */
7176
7177#define CT_SIZE 101
7178
7179/* Value is a hash of the RGB color given by R, G, and B. */
7180
7181#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7182
7183/* The color hash table. */
7184
7185struct ct_color **ct_table;
7186
7187/* Number of entries in the color table. */
7188
7189int ct_colors_allocated;
7190
7191/* Function prototypes. */
7192
7193static void init_color_table P_ ((void));
7194static void free_color_table P_ ((void));
7195static unsigned long *colors_in_color_table P_ ((int *n));
7196static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
7197static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
7198
7199
7200/* Initialize the color table. */
7201
7202static void
7203init_color_table ()
7204{
7205 int size = CT_SIZE * sizeof (*ct_table);
7206 ct_table = (struct ct_color **) xmalloc (size);
7207 bzero (ct_table, size);
7208 ct_colors_allocated = 0;
7209}
7210
7211
7212/* Free memory associated with the color table. */
7213
7214static void
7215free_color_table ()
7216{
7217 int i;
7218 struct ct_color *p, *next;
7219
7220 for (i = 0; i < CT_SIZE; ++i)
7221 for (p = ct_table[i]; p; p = next)
7222 {
7223 next = p->next;
7224 xfree (p);
7225 }
7226
7227 xfree (ct_table);
7228 ct_table = NULL;
7229}
7230
7231
7232/* Value is a pixel color for RGB color R, G, B on frame F. If an
7233 entry for that color already is in the color table, return the
7234 pixel color of that entry. Otherwise, allocate a new color for R,
7235 G, B, and make an entry in the color table. */
7236
7237static unsigned long
7238lookup_rgb_color (f, r, g, b)
7239 struct frame *f;
7240 int r, g, b;
7241{
7242 unsigned hash = CT_HASH_RGB (r, g, b);
7243 int i = hash % CT_SIZE;
7244 struct ct_color *p;
7245
7246 for (p = ct_table[i]; p; p = p->next)
7247 if (p->r == r && p->g == g && p->b == b)
7248 break;
7249
7250 if (p == NULL)
7251 {
7252 XColor color;
7253 Colormap cmap;
7254 int rc;
7255
7256 color.red = r;
7257 color.green = g;
7258 color.blue = b;
7259
7260 BLOCK_INPUT;
7261 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
d62c8769 7262 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7263 UNBLOCK_INPUT;
7264
7265 if (rc)
7266 {
7267 ++ct_colors_allocated;
7268
7269 p = (struct ct_color *) xmalloc (sizeof *p);
7270 p->r = r;
7271 p->g = g;
7272 p->b = b;
7273 p->pixel = color.pixel;
7274 p->next = ct_table[i];
7275 ct_table[i] = p;
7276 }
7277 else
7278 return FRAME_FOREGROUND_PIXEL (f);
7279 }
7280
7281 return p->pixel;
7282}
7283
7284
7285/* Look up pixel color PIXEL which is used on frame F in the color
7286 table. If not already present, allocate it. Value is PIXEL. */
7287
7288static unsigned long
7289lookup_pixel_color (f, pixel)
7290 struct frame *f;
7291 unsigned long pixel;
7292{
7293 int i = pixel % CT_SIZE;
7294 struct ct_color *p;
7295
7296 for (p = ct_table[i]; p; p = p->next)
7297 if (p->pixel == pixel)
7298 break;
7299
7300 if (p == NULL)
7301 {
7302 XColor color;
7303 Colormap cmap;
7304 int rc;
7305
7306 BLOCK_INPUT;
7307
7308 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
7309 color.pixel = pixel;
7310 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
d62c8769 7311 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7312 UNBLOCK_INPUT;
7313
7314 if (rc)
7315 {
7316 ++ct_colors_allocated;
7317
7318 p = (struct ct_color *) xmalloc (sizeof *p);
7319 p->r = color.red;
7320 p->g = color.green;
7321 p->b = color.blue;
7322 p->pixel = pixel;
7323 p->next = ct_table[i];
7324 ct_table[i] = p;
7325 }
7326 else
7327 return FRAME_FOREGROUND_PIXEL (f);
7328 }
7329
7330 return p->pixel;
7331}
7332
7333
7334/* Value is a vector of all pixel colors contained in the color table,
7335 allocated via xmalloc. Set *N to the number of colors. */
7336
7337static unsigned long *
7338colors_in_color_table (n)
7339 int *n;
7340{
7341 int i, j;
7342 struct ct_color *p;
7343 unsigned long *colors;
7344
7345 if (ct_colors_allocated == 0)
7346 {
7347 *n = 0;
7348 colors = NULL;
7349 }
7350 else
7351 {
7352 colors = (unsigned long *) xmalloc (ct_colors_allocated
7353 * sizeof *colors);
7354 *n = ct_colors_allocated;
7355
7356 for (i = j = 0; i < CT_SIZE; ++i)
7357 for (p = ct_table[i]; p; p = p->next)
7358 colors[j++] = p->pixel;
7359 }
7360
7361 return colors;
7362}
7363
7364
7365\f
7366/***********************************************************************
7367 Algorithms
7368 ***********************************************************************/
7369
7370static void x_laplace_write_row P_ ((struct frame *, long *,
7371 int, XImage *, int));
7372static void x_laplace_read_row P_ ((struct frame *, Colormap,
7373 XColor *, int, XImage *, int));
7374
7375
7376/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
7377 frame we operate on, CMAP is the color-map in effect, and WIDTH is
7378 the width of one row in the image. */
7379
7380static void
7381x_laplace_read_row (f, cmap, colors, width, ximg, y)
7382 struct frame *f;
7383 Colormap cmap;
7384 XColor *colors;
7385 int width;
7386 XImage *ximg;
7387 int y;
7388{
7389 int x;
7390
7391 for (x = 0; x < width; ++x)
7392 colors[x].pixel = XGetPixel (ximg, x, y);
7393
7394 XQueryColors (FRAME_X_DISPLAY (f), cmap, colors, width);
7395}
7396
7397
7398/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
7399 containing the pixel colors to write. F is the frame we are
7400 working on. */
7401
7402static void
7403x_laplace_write_row (f, pixels, width, ximg, y)
7404 struct frame *f;
7405 long *pixels;
7406 int width;
7407 XImage *ximg;
7408 int y;
7409{
7410 int x;
7411
7412 for (x = 0; x < width; ++x)
7413 XPutPixel (ximg, x, y, pixels[x]);
7414}
7415
7416
7417/* Transform image IMG which is used on frame F with a Laplace
7418 edge-detection algorithm. The result is an image that can be used
7419 to draw disabled buttons, for example. */
7420
7421static void
7422x_laplace (f, img)
7423 struct frame *f;
7424 struct image *img;
7425{
7426 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
7427 XImage *ximg, *oimg;
7428 XColor *in[3];
7429 long *out;
7430 Pixmap pixmap;
7431 int x, y, i;
7432 long pixel;
7433 int in_y, out_y, rc;
7434 int mv2 = 45000;
7435
7436 BLOCK_INPUT;
7437
7438 /* Get the X image IMG->pixmap. */
7439 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7440 0, 0, img->width, img->height, ~0, ZPixmap);
7441
7442 /* Allocate 3 input rows, and one output row of colors. */
7443 for (i = 0; i < 3; ++i)
7444 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
7445 out = (long *) alloca (img->width * sizeof (long));
7446
7447 /* Create an X image for output. */
7448 rc = x_create_x_image_and_pixmap (f, Qnil, img->width, img->height, 0,
7449 &oimg, &pixmap);
7450
7451 /* Fill first two rows. */
7452 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
7453 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
7454 in_y = 2;
7455
7456 /* Write first row, all zeros. */
7457 init_color_table ();
7458 pixel = lookup_rgb_color (f, 0, 0, 0);
7459 for (x = 0; x < img->width; ++x)
7460 out[x] = pixel;
7461 x_laplace_write_row (f, out, img->width, oimg, 0);
7462 out_y = 1;
7463
7464 for (y = 2; y < img->height; ++y)
7465 {
7466 int rowa = y % 3;
7467 int rowb = (y + 2) % 3;
7468
7469 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
7470
7471 for (x = 0; x < img->width - 2; ++x)
7472 {
7473 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
7474 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
7475 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
7476
7477 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
7478 b & 0xffff);
7479 }
7480
7481 x_laplace_write_row (f, out, img->width, oimg, out_y++);
7482 }
7483
7484 /* Write last line, all zeros. */
7485 for (x = 0; x < img->width; ++x)
7486 out[x] = pixel;
7487 x_laplace_write_row (f, out, img->width, oimg, out_y);
7488
7489 /* Free the input image, and free resources of IMG. */
7490 XDestroyImage (ximg);
7491 x_clear_image (f, img);
7492
7493 /* Put the output image into pixmap, and destroy it. */
7494 x_put_x_image (f, oimg, pixmap, img->width, img->height);
7495 x_destroy_x_image (oimg);
7496
7497 /* Remember new pixmap and colors in IMG. */
7498 img->pixmap = pixmap;
7499 img->colors = colors_in_color_table (&img->ncolors);
7500 free_color_table ();
7501
7502 UNBLOCK_INPUT;
7503}
7504
7505
7506/* Build a mask for image IMG which is used on frame F. FILE is the
7507 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
7508 determine the background color of IMG. If it is a list '(R G B)',
7509 with R, G, and B being integers >= 0, take that as the color of the
7510 background. Otherwise, determine the background color of IMG
7511 heuristically. Value is non-zero if successful. */
333b20bb
GM
7512
7513static int
7514x_build_heuristic_mask (f, file, img, how)
7515 struct frame *f;
7516 Lisp_Object file;
7517 struct image *img;
7518 Lisp_Object how;
7519{
7520 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 7521 XImage *ximg, *mask_img;
fcf431dc 7522 int x, y, rc, look_at_corners_p;
333b20bb
GM
7523 unsigned long bg;
7524
7525 BLOCK_INPUT;
7526
7527 /* Create an image and pixmap serving as mask. */
7528 rc = x_create_x_image_and_pixmap (f, file, img->width, img->height, 1,
7529 &mask_img, &img->mask);
7530 if (!rc)
7531 {
7532 UNBLOCK_INPUT;
7533 return 0;
7534 }
7535
7536 /* Get the X image of IMG->pixmap. */
7537 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
7538 ~0, ZPixmap);
7539
fcf431dc
GM
7540 /* Determine the background color of ximg. If HOW is `(R G B)'
7541 take that as color. Otherwise, try to determine the color
7542 heuristically. */
7543 look_at_corners_p = 1;
7544
7545 if (CONSP (how))
7546 {
7547 int rgb[3], i = 0;
7548
7549 while (i < 3
7550 && CONSP (how)
7551 && NATNUMP (XCAR (how)))
7552 {
7553 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
7554 how = XCDR (how);
7555 }
7556
7557 if (i == 3 && NILP (how))
7558 {
7559 char color_name[30];
7560 XColor exact, color;
7561 Colormap cmap;
7562
7563 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
7564
7565 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
7566 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
7567 {
7568 bg = color.pixel;
7569 look_at_corners_p = 0;
7570 }
7571 }
7572 }
7573
7574 if (look_at_corners_p)
333b20bb
GM
7575 {
7576 unsigned long corners[4];
7577 int i, best_count;
7578
7579 /* Get the colors at the corners of ximg. */
7580 corners[0] = XGetPixel (ximg, 0, 0);
7581 corners[1] = XGetPixel (ximg, img->width - 1, 0);
7582 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
7583 corners[3] = XGetPixel (ximg, 0, img->height - 1);
7584
7585 /* Choose the most frequently found color as background. */
7586 for (i = best_count = 0; i < 4; ++i)
7587 {
7588 int j, n;
7589
7590 for (j = n = 0; j < 4; ++j)
7591 if (corners[i] == corners[j])
7592 ++n;
7593
7594 if (n > best_count)
7595 bg = corners[i], best_count = n;
7596 }
7597 }
7598
7599 /* Set all bits in mask_img to 1 whose color in ximg is different
7600 from the background color bg. */
7601 for (y = 0; y < img->height; ++y)
7602 for (x = 0; x < img->width; ++x)
7603 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
7604
7605 /* Put mask_img into img->mask. */
7606 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7607 x_destroy_x_image (mask_img);
7608 XDestroyImage (ximg);
7609
7610 UNBLOCK_INPUT;
7611 return 1;
7612}
7613
7614
7615\f
7616/***********************************************************************
7617 PBM (mono, gray, color)
7618 ***********************************************************************/
7619
7620static int pbm_image_p P_ ((Lisp_Object object));
7621static int pbm_load P_ ((struct frame *f, struct image *img));
7622static int pbm_scan_number P_ ((FILE *fp));
7623
7624/* The symbol `pbm' identifying images of this type. */
7625
7626Lisp_Object Qpbm;
7627
7628/* Indices of image specification fields in gs_format, below. */
7629
7630enum pbm_keyword_index
7631{
7632 PBM_TYPE,
7633 PBM_FILE,
7634 PBM_ASCENT,
7635 PBM_MARGIN,
7636 PBM_RELIEF,
7637 PBM_ALGORITHM,
7638 PBM_HEURISTIC_MASK,
7639 PBM_LAST
7640};
7641
7642/* Vector of image_keyword structures describing the format
7643 of valid user-defined image specifications. */
7644
7645static struct image_keyword pbm_format[PBM_LAST] =
7646{
7647 {":type", IMAGE_SYMBOL_VALUE, 1},
7648 {":file", IMAGE_STRING_VALUE, 1},
7649 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7650 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7651 {":relief", IMAGE_INTEGER_VALUE, 0},
7652 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7653 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7654};
7655
7656/* Structure describing the image type `pbm'. */
7657
7658static struct image_type pbm_type =
7659{
7660 &Qpbm,
7661 pbm_image_p,
7662 pbm_load,
7663 x_clear_image,
7664 NULL
7665};
7666
7667
7668/* Return non-zero if OBJECT is a valid PBM image specification. */
7669
7670static int
7671pbm_image_p (object)
7672 Lisp_Object object;
7673{
7674 struct image_keyword fmt[PBM_LAST];
7675
7676 bcopy (pbm_format, fmt, sizeof fmt);
7677
7678 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm, 0)
7679 || (fmt[PBM_ASCENT].count
7680 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
7681 return 0;
7682 return 1;
7683}
7684
7685
7686/* Scan a decimal number from PBM input file FP and return it. Value
7687 is -1 at end of file or if an error occurs. */
7688
7689static int
7690pbm_scan_number (fp)
7691 FILE *fp;
7692{
7693 int c, val = -1;
7694
7695 while (!feof (fp))
7696 {
7697 /* Skip white-space. */
7698 while ((c = fgetc (fp)) != EOF && isspace (c))
7699 ;
7700
7701 if (c == '#')
7702 {
7703 /* Skip comment to end of line. */
7704 while ((c = fgetc (fp)) != EOF && c != '\n')
7705 ;
7706 }
7707 else if (isdigit (c))
7708 {
7709 /* Read decimal number. */
7710 val = c - '0';
7711 while ((c = fgetc (fp)) != EOF && isdigit (c))
7712 val = 10 * val + c - '0';
7713 break;
7714 }
7715 else
7716 break;
7717 }
7718
7719 return val;
7720}
7721
7722
7723/* Load PBM image IMG for use on frame F. */
7724
7725static int
7726pbm_load (f, img)
7727 struct frame *f;
7728 struct image *img;
7729{
7730 FILE *fp;
7731 char magic[2];
7732 int raw_p, x, y;
b6d7acec 7733 int width, height, max_color_idx = 0;
333b20bb
GM
7734 XImage *ximg;
7735 Lisp_Object file, specified_file;
7736 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
7737 struct gcpro gcpro1;
7738
7739 specified_file = image_spec_value (img->spec, QCfile, NULL);
7740 file = x_find_image_file (specified_file);
7741 GCPRO1 (file);
7742 if (!STRINGP (file))
7743 {
7744 image_error ("Cannot find image file %s", specified_file, Qnil);
7745 UNGCPRO;
7746 return 0;
7747 }
7748
7749 fp = fopen (XSTRING (file)->data, "r");
7750 if (fp == NULL)
7751 {
7752 UNGCPRO;
7753 return 0;
7754 }
7755
7756 /* Read first two characters. */
7757 if (fread (magic, sizeof *magic, 2, fp) != 2)
7758 {
7759 fclose (fp);
7760 image_error ("Not a PBM image file: %s", file, Qnil);
7761 UNGCPRO;
7762 return 0;
7763 }
7764
7765 if (*magic != 'P')
7766 {
7767 fclose (fp);
7768 image_error ("Not a PBM image file: %s", file, Qnil);
7769 UNGCPRO;
7770 return 0;
7771 }
7772
7773 switch (magic[1])
7774 {
7775 case '1':
7776 raw_p = 0, type = PBM_MONO;
7777 break;
7778
7779 case '2':
7780 raw_p = 0, type = PBM_GRAY;
7781 break;
7782
7783 case '3':
7784 raw_p = 0, type = PBM_COLOR;
7785 break;
7786
7787 case '4':
7788 raw_p = 1, type = PBM_MONO;
7789 break;
7790
7791 case '5':
7792 raw_p = 1, type = PBM_GRAY;
7793 break;
7794
7795 case '6':
7796 raw_p = 1, type = PBM_COLOR;
7797 break;
7798
7799 default:
7800 fclose (fp);
7801 image_error ("Not a PBM image file: %s", file, Qnil);
7802 UNGCPRO;
7803 return 0;
7804 }
7805
7806 /* Read width, height, maximum color-component. Characters
7807 starting with `#' up to the end of a line are ignored. */
7808 width = pbm_scan_number (fp);
7809 height = pbm_scan_number (fp);
7810
7811 if (type != PBM_MONO)
7812 {
7813 max_color_idx = pbm_scan_number (fp);
7814 if (raw_p && max_color_idx > 255)
7815 max_color_idx = 255;
7816 }
7817
7818 if (width < 0 || height < 0
7819 || (type != PBM_MONO && max_color_idx < 0))
7820 {
7821 fclose (fp);
7822 UNGCPRO;
7823 return 0;
7824 }
7825
7826 BLOCK_INPUT;
7827 if (!x_create_x_image_and_pixmap (f, file, width, height, 0,
7828 &ximg, &img->pixmap))
7829 {
7830 fclose (fp);
7831 UNBLOCK_INPUT;
7832 UNGCPRO;
7833 return 0;
7834 }
7835
7836 /* Initialize the color hash table. */
7837 init_color_table ();
7838
7839 if (type == PBM_MONO)
7840 {
7841 int c = 0, g;
7842
7843 for (y = 0; y < height; ++y)
7844 for (x = 0; x < width; ++x)
7845 {
7846 if (raw_p)
7847 {
7848 if ((x & 7) == 0)
7849 c = fgetc (fp);
7850 g = c & 0x80;
7851 c <<= 1;
7852 }
7853 else
7854 g = pbm_scan_number (fp);
7855
7856 XPutPixel (ximg, x, y, (g
7857 ? FRAME_FOREGROUND_PIXEL (f)
7858 : FRAME_BACKGROUND_PIXEL (f)));
7859 }
7860 }
7861 else
7862 {
7863 for (y = 0; y < height; ++y)
7864 for (x = 0; x < width; ++x)
7865 {
7866 int r, g, b;
7867
7868 if (type == PBM_GRAY)
7869 r = g = b = raw_p ? fgetc (fp) : pbm_scan_number (fp);
7870 else if (raw_p)
7871 {
7872 r = fgetc (fp);
7873 g = fgetc (fp);
7874 b = fgetc (fp);
7875 }
7876 else
7877 {
7878 r = pbm_scan_number (fp);
7879 g = pbm_scan_number (fp);
7880 b = pbm_scan_number (fp);
7881 }
7882
7883 if (r < 0 || g < 0 || b < 0)
7884 {
7885 fclose (fp);
7886 xfree (ximg->data);
7887 ximg->data = NULL;
7888 XDestroyImage (ximg);
7889 UNBLOCK_INPUT;
7890 image_error ("Invalid pixel value in file `%s'",
7891 file, Qnil);
7892 UNGCPRO;
7893 return 0;
7894 }
7895
7896 /* RGB values are now in the range 0..max_color_idx.
7897 Scale this to the range 0..0xffff supported by X. */
7898 r = (double) r * 65535 / max_color_idx;
7899 g = (double) g * 65535 / max_color_idx;
7900 b = (double) b * 65535 / max_color_idx;
7901 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7902 }
7903 }
7904
7905 fclose (fp);
7906
7907 /* Store in IMG->colors the colors allocated for the image, and
7908 free the color table. */
7909 img->colors = colors_in_color_table (&img->ncolors);
7910 free_color_table ();
7911
7912 /* Put the image into a pixmap. */
7913 x_put_x_image (f, ximg, img->pixmap, width, height);
7914 x_destroy_x_image (ximg);
7915 UNBLOCK_INPUT;
7916
7917 img->width = width;
7918 img->height = height;
7919
7920 UNGCPRO;
7921 return 1;
7922}
7923
7924
7925\f
7926/***********************************************************************
7927 PNG
7928 ***********************************************************************/
7929
7930#if HAVE_PNG
7931
7932#include <png.h>
7933
7934/* Function prototypes. */
7935
7936static int png_image_p P_ ((Lisp_Object object));
7937static int png_load P_ ((struct frame *f, struct image *img));
7938
7939/* The symbol `png' identifying images of this type. */
7940
7941Lisp_Object Qpng;
7942
7943/* Indices of image specification fields in png_format, below. */
7944
7945enum png_keyword_index
7946{
7947 PNG_TYPE,
7948 PNG_FILE,
7949 PNG_ASCENT,
7950 PNG_MARGIN,
7951 PNG_RELIEF,
7952 PNG_ALGORITHM,
7953 PNG_HEURISTIC_MASK,
7954 PNG_LAST
7955};
7956
7957/* Vector of image_keyword structures describing the format
7958 of valid user-defined image specifications. */
7959
7960static struct image_keyword png_format[PNG_LAST] =
7961{
7962 {":type", IMAGE_SYMBOL_VALUE, 1},
7963 {":file", IMAGE_STRING_VALUE, 1},
7964 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7965 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7966 {":relief", IMAGE_INTEGER_VALUE, 0},
7967 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7968 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7969};
7970
06482119 7971/* Structure describing the image type `png'. */
333b20bb
GM
7972
7973static struct image_type png_type =
7974{
7975 &Qpng,
7976 png_image_p,
7977 png_load,
7978 x_clear_image,
7979 NULL
7980};
7981
7982
7983/* Return non-zero if OBJECT is a valid PNG image specification. */
7984
7985static int
7986png_image_p (object)
7987 Lisp_Object object;
7988{
7989 struct image_keyword fmt[PNG_LAST];
7990 bcopy (png_format, fmt, sizeof fmt);
7991
7992 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng, 1)
7993 || (fmt[PNG_ASCENT].count
7994 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
7995 return 0;
7996 return 1;
7997}
7998
7999
8000/* Error and warning handlers installed when the PNG library
8001 is initialized. */
8002
8003static void
8004my_png_error (png_ptr, msg)
8005 png_struct *png_ptr;
8006 char *msg;
8007{
8008 xassert (png_ptr != NULL);
8009 image_error ("PNG error: %s", build_string (msg), Qnil);
8010 longjmp (png_ptr->jmpbuf, 1);
8011}
8012
8013
8014static void
8015my_png_warning (png_ptr, msg)
8016 png_struct *png_ptr;
8017 char *msg;
8018{
8019 xassert (png_ptr != NULL);
8020 image_error ("PNG warning: %s", build_string (msg), Qnil);
8021}
8022
8023
8024/* Load PNG image IMG for use on frame F. Value is non-zero if
8025 successful. */
8026
8027static int
8028png_load (f, img)
8029 struct frame *f;
8030 struct image *img;
8031{
8032 Lisp_Object file, specified_file;
b6d7acec 8033 int x, y, i;
333b20bb
GM
8034 XImage *ximg, *mask_img = NULL;
8035 struct gcpro gcpro1;
8036 png_struct *png_ptr = NULL;
8037 png_info *info_ptr = NULL, *end_info = NULL;
8038 FILE *fp;
8039 png_byte sig[8];
8040 png_byte *pixels = NULL;
8041 png_byte **rows = NULL;
8042 png_uint_32 width, height;
8043 int bit_depth, color_type, interlace_type;
8044 png_byte channels;
8045 png_uint_32 row_bytes;
8046 int transparent_p;
8047 char *gamma_str;
8048 double screen_gamma, image_gamma;
8049 int intent;
8050
8051 /* Find out what file to load. */
8052 specified_file = image_spec_value (img->spec, QCfile, NULL);
8053 file = x_find_image_file (specified_file);
8054 GCPRO1 (file);
8055 if (!STRINGP (file))
8056 {
8057 image_error ("Cannot find image file %s", specified_file, Qnil);
8058 UNGCPRO;
8059 return 0;
8060 }
8061
8062 /* Open the image file. */
8063 fp = fopen (XSTRING (file)->data, "rb");
8064 if (!fp)
8065 {
8066 image_error ("Cannot open image file %s", file, Qnil);
8067 UNGCPRO;
8068 fclose (fp);
8069 return 0;
8070 }
8071
8072 /* Check PNG signature. */
8073 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8074 || !png_check_sig (sig, sizeof sig))
8075 {
8076 image_error ("Not a PNG file: %s", file, Qnil);
8077 UNGCPRO;
8078 fclose (fp);
8079 return 0;
8080 }
8081
8082 /* Initialize read and info structs for PNG lib. */
8083 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8084 my_png_error, my_png_warning);
8085 if (!png_ptr)
8086 {
8087 fclose (fp);
8088 UNGCPRO;
8089 return 0;
8090 }
8091
8092 info_ptr = png_create_info_struct (png_ptr);
8093 if (!info_ptr)
8094 {
8095 png_destroy_read_struct (&png_ptr, NULL, NULL);
8096 fclose (fp);
8097 UNGCPRO;
8098 return 0;
8099 }
8100
8101 end_info = png_create_info_struct (png_ptr);
8102 if (!end_info)
8103 {
8104 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
8105 fclose (fp);
8106 UNGCPRO;
8107 return 0;
8108 }
8109
8110 /* Set error jump-back. We come back here when the PNG library
8111 detects an error. */
8112 if (setjmp (png_ptr->jmpbuf))
8113 {
8114 error:
8115 if (png_ptr)
8116 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8117 xfree (pixels);
8118 xfree (rows);
8119 if (fp)
8120 fclose (fp);
8121 UNGCPRO;
8122 return 0;
8123 }
8124
8125 /* Read image info. */
8126 png_init_io (png_ptr, fp);
8127 png_set_sig_bytes (png_ptr, sizeof sig);
8128 png_read_info (png_ptr, info_ptr);
8129 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
8130 &interlace_type, NULL, NULL);
8131
8132 /* If image contains simply transparency data, we prefer to
8133 construct a clipping mask. */
8134 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
8135 transparent_p = 1;
8136 else
8137 transparent_p = 0;
8138
8139 /* This function is easier to write if we only have to handle
8140 one data format: RGB or RGBA with 8 bits per channel. Let's
8141 transform other formats into that format. */
8142
8143 /* Strip more than 8 bits per channel. */
8144 if (bit_depth == 16)
8145 png_set_strip_16 (png_ptr);
8146
8147 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
8148 if available. */
8149 png_set_expand (png_ptr);
8150
8151 /* Convert grayscale images to RGB. */
8152 if (color_type == PNG_COLOR_TYPE_GRAY
8153 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8154 png_set_gray_to_rgb (png_ptr);
8155
8156 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
8157 gamma_str = getenv ("SCREEN_GAMMA");
8158 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
8159
8160 /* Tell the PNG lib to handle gamma correction for us. */
8161
6c1aa34d 8162#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb
GM
8163 if (png_get_sRGB (png_ptr, info_ptr, &intent))
8164 /* There is a special chunk in the image specifying the gamma. */
8165 png_set_sRGB (png_ptr, info_ptr, intent);
6c1aa34d
GM
8166 else
8167#endif
8168 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
8169 /* Image contains gamma information. */
8170 png_set_gamma (png_ptr, screen_gamma, image_gamma);
8171 else
8172 /* Use a default of 0.5 for the image gamma. */
8173 png_set_gamma (png_ptr, screen_gamma, 0.5);
8174
8175 /* Handle alpha channel by combining the image with a background
8176 color. Do this only if a real alpha channel is supplied. For
8177 simple transparency, we prefer a clipping mask. */
8178 if (!transparent_p)
8179 {
8180 png_color_16 *image_background;
8181
8182 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
8183 /* Image contains a background color with which to
8184 combine the image. */
8185 png_set_background (png_ptr, image_background,
8186 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
8187 else
8188 {
8189 /* Image does not contain a background color with which
8190 to combine the image data via an alpha channel. Use
8191 the frame's background instead. */
8192 XColor color;
8193 Colormap cmap;
8194 png_color_16 frame_background;
8195
8196 BLOCK_INPUT;
8197 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
8198 color.pixel = FRAME_BACKGROUND_PIXEL (f);
8199 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
8200 UNBLOCK_INPUT;
8201
8202 bzero (&frame_background, sizeof frame_background);
8203 frame_background.red = color.red;
8204 frame_background.green = color.green;
8205 frame_background.blue = color.blue;
8206
8207 png_set_background (png_ptr, &frame_background,
8208 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
8209 }
8210 }
8211
8212 /* Update info structure. */
8213 png_read_update_info (png_ptr, info_ptr);
8214
8215 /* Get number of channels. Valid values are 1 for grayscale images
8216 and images with a palette, 2 for grayscale images with transparency
8217 information (alpha channel), 3 for RGB images, and 4 for RGB
8218 images with alpha channel, i.e. RGBA. If conversions above were
8219 sufficient we should only have 3 or 4 channels here. */
8220 channels = png_get_channels (png_ptr, info_ptr);
8221 xassert (channels == 3 || channels == 4);
8222
8223 /* Number of bytes needed for one row of the image. */
8224 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
8225
8226 /* Allocate memory for the image. */
8227 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
8228 rows = (png_byte **) xmalloc (height * sizeof *rows);
8229 for (i = 0; i < height; ++i)
8230 rows[i] = pixels + i * row_bytes;
8231
8232 /* Read the entire image. */
8233 png_read_image (png_ptr, rows);
8234 png_read_end (png_ptr, info_ptr);
8235 fclose (fp);
8236 fp = NULL;
8237
8238 BLOCK_INPUT;
8239
8240 /* Create the X image and pixmap. */
8241 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
8242 &img->pixmap))
8243 {
8244 UNBLOCK_INPUT;
8245 goto error;
8246 }
8247
8248 /* Create an image and pixmap serving as mask if the PNG image
8249 contains an alpha channel. */
8250 if (channels == 4
8251 && !transparent_p
8252 && !x_create_x_image_and_pixmap (f, file, width, height, 1,
8253 &mask_img, &img->mask))
8254 {
8255 x_destroy_x_image (ximg);
8256 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8257 img->pixmap = 0;
8258 UNBLOCK_INPUT;
8259 goto error;
8260 }
8261
8262 /* Fill the X image and mask from PNG data. */
8263 init_color_table ();
8264
8265 for (y = 0; y < height; ++y)
8266 {
8267 png_byte *p = rows[y];
8268
8269 for (x = 0; x < width; ++x)
8270 {
8271 unsigned r, g, b;
8272
8273 r = *p++ << 8;
8274 g = *p++ << 8;
8275 b = *p++ << 8;
8276 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8277
8278 /* An alpha channel, aka mask channel, associates variable
8279 transparency with an image. Where other image formats
8280 support binary transparency---fully transparent or fully
8281 opaque---PNG allows up to 254 levels of partial transparency.
8282 The PNG library implements partial transparency by combining
8283 the image with a specified background color.
8284
8285 I'm not sure how to handle this here nicely: because the
8286 background on which the image is displayed may change, for
8287 real alpha channel support, it would be necessary to create
8288 a new image for each possible background.
8289
8290 What I'm doing now is that a mask is created if we have
8291 boolean transparency information. Otherwise I'm using
8292 the frame's background color to combine the image with. */
8293
8294 if (channels == 4)
8295 {
8296 if (mask_img)
8297 XPutPixel (mask_img, x, y, *p > 0);
8298 ++p;
8299 }
8300 }
8301 }
8302
8303 /* Remember colors allocated for this image. */
8304 img->colors = colors_in_color_table (&img->ncolors);
8305 free_color_table ();
8306
8307 /* Clean up. */
8308 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8309 xfree (rows);
8310 xfree (pixels);
8311
8312 img->width = width;
8313 img->height = height;
8314
8315 /* Put the image into the pixmap, then free the X image and its buffer. */
8316 x_put_x_image (f, ximg, img->pixmap, width, height);
8317 x_destroy_x_image (ximg);
8318
8319 /* Same for the mask. */
8320 if (mask_img)
8321 {
8322 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8323 x_destroy_x_image (mask_img);
8324 }
8325
8326 UNBLOCK_INPUT;
8327 UNGCPRO;
8328 return 1;
8329}
8330
8331#endif /* HAVE_PNG != 0 */
8332
8333
8334\f
8335/***********************************************************************
8336 JPEG
8337 ***********************************************************************/
8338
8339#if HAVE_JPEG
8340
ba06aba4
GM
8341/* Work around a warning about HAVE_STDLIB_H being redefined in
8342 jconfig.h. */
8343#ifdef HAVE_STDLIB_H
8344#define HAVE_STDLIB_H_1
8345#undef HAVE_STDLIB_H
8346#endif /* HAVE_STLIB_H */
8347
333b20bb
GM
8348#include <jpeglib.h>
8349#include <jerror.h>
8350#include <setjmp.h>
8351
ba06aba4
GM
8352#ifdef HAVE_STLIB_H_1
8353#define HAVE_STDLIB_H 1
8354#endif
8355
333b20bb
GM
8356static int jpeg_image_p P_ ((Lisp_Object object));
8357static int jpeg_load P_ ((struct frame *f, struct image *img));
8358
8359/* The symbol `jpeg' identifying images of this type. */
8360
8361Lisp_Object Qjpeg;
8362
8363/* Indices of image specification fields in gs_format, below. */
8364
8365enum jpeg_keyword_index
8366{
8367 JPEG_TYPE,
8368 JPEG_FILE,
8369 JPEG_ASCENT,
8370 JPEG_MARGIN,
8371 JPEG_RELIEF,
8372 JPEG_ALGORITHM,
8373 JPEG_HEURISTIC_MASK,
8374 JPEG_LAST
8375};
8376
8377/* Vector of image_keyword structures describing the format
8378 of valid user-defined image specifications. */
8379
8380static struct image_keyword jpeg_format[JPEG_LAST] =
8381{
8382 {":type", IMAGE_SYMBOL_VALUE, 1},
8383 {":file", IMAGE_STRING_VALUE, 1},
8384 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8385 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8386 {":relief", IMAGE_INTEGER_VALUE, 0},
8387 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8388 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8389};
8390
8391/* Structure describing the image type `jpeg'. */
8392
8393static struct image_type jpeg_type =
8394{
8395 &Qjpeg,
8396 jpeg_image_p,
8397 jpeg_load,
8398 x_clear_image,
8399 NULL
8400};
8401
8402
8403/* Return non-zero if OBJECT is a valid JPEG image specification. */
8404
8405static int
8406jpeg_image_p (object)
8407 Lisp_Object object;
8408{
8409 struct image_keyword fmt[JPEG_LAST];
8410
8411 bcopy (jpeg_format, fmt, sizeof fmt);
8412
8413 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg, 0)
8414 || (fmt[JPEG_ASCENT].count
8415 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
8416 return 0;
8417 return 1;
8418}
8419
8420struct my_jpeg_error_mgr
8421{
8422 struct jpeg_error_mgr pub;
8423 jmp_buf setjmp_buffer;
8424};
8425
8426static void
8427my_error_exit (cinfo)
8428 j_common_ptr cinfo;
8429{
8430 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
8431 longjmp (mgr->setjmp_buffer, 1);
8432}
8433
8434/* Load image IMG for use on frame F. Patterned after example.c
8435 from the JPEG lib. */
8436
8437static int
8438jpeg_load (f, img)
8439 struct frame *f;
8440 struct image *img;
8441{
8442 struct jpeg_decompress_struct cinfo;
8443 struct my_jpeg_error_mgr mgr;
8444 Lisp_Object file, specified_file;
8445 FILE *fp;
8446 JSAMPARRAY buffer;
8447 int row_stride, x, y;
8448 XImage *ximg = NULL;
b6d7acec 8449 int rc;
333b20bb
GM
8450 unsigned long *colors;
8451 int width, height;
8452 struct gcpro gcpro1;
8453
8454 /* Open the JPEG file. */
8455 specified_file = image_spec_value (img->spec, QCfile, NULL);
8456 file = x_find_image_file (specified_file);
8457 GCPRO1 (file);
8458 if (!STRINGP (file))
8459 {
8460 image_error ("Cannot find image file %s", specified_file, Qnil);
8461 UNGCPRO;
8462 return 0;
8463 }
8464
8465 fp = fopen (XSTRING (file)->data, "r");
8466 if (fp == NULL)
8467 {
8468 image_error ("Cannot open `%s'", file, Qnil);
8469 UNGCPRO;
8470 return 0;
8471 }
8472
8473 /* Customize libjpeg's error handling to call my_error_exit
8474 when an error is detected. This function will perform
8475 a longjmp. */
8476 mgr.pub.error_exit = my_error_exit;
8477 cinfo.err = jpeg_std_error (&mgr.pub);
8478
8479 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
8480 {
8481 if (rc == 1)
8482 {
8483 /* Called from my_error_exit. Display a JPEG error. */
8484 char buffer[JMSG_LENGTH_MAX];
8485 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
8486 image_error ("Error reading JPEG file `%s': %s", file,
8487 build_string (buffer));
8488 }
8489
8490 /* Close the input file and destroy the JPEG object. */
8491 fclose (fp);
8492 jpeg_destroy_decompress (&cinfo);
8493
8494 BLOCK_INPUT;
8495
8496 /* If we already have an XImage, free that. */
8497 x_destroy_x_image (ximg);
8498
8499 /* Free pixmap and colors. */
8500 x_clear_image (f, img);
8501
8502 UNBLOCK_INPUT;
8503 UNGCPRO;
8504 return 0;
8505 }
8506
8507 /* Create the JPEG decompression object. Let it read from fp.
8508 Read the JPEG image header. */
8509 jpeg_create_decompress (&cinfo);
8510 jpeg_stdio_src (&cinfo, fp);
8511 jpeg_read_header (&cinfo, TRUE);
8512
8513 /* Customize decompression so that color quantization will be used.
8514 Start decompression. */
8515 cinfo.quantize_colors = TRUE;
8516 jpeg_start_decompress (&cinfo);
8517 width = img->width = cinfo.output_width;
8518 height = img->height = cinfo.output_height;
8519
8520 BLOCK_INPUT;
8521
8522 /* Create X image and pixmap. */
8523 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
8524 &img->pixmap))
8525 {
8526 UNBLOCK_INPUT;
8527 longjmp (mgr.setjmp_buffer, 2);
8528 }
8529
8530 /* Allocate colors. When color quantization is used,
8531 cinfo.actual_number_of_colors has been set with the number of
8532 colors generated, and cinfo.colormap is a two-dimensional array
8533 of color indices in the range 0..cinfo.actual_number_of_colors.
8534 No more than 255 colors will be generated. */
8535 {
8536 int i, ir, ig, ib;
8537
8538 if (cinfo.out_color_components > 2)
8539 ir = 0, ig = 1, ib = 2;
8540 else if (cinfo.out_color_components > 1)
8541 ir = 0, ig = 1, ib = 0;
8542 else
8543 ir = 0, ig = 0, ib = 0;
8544
8545 /* Use the color table mechanism because it handles colors that
8546 cannot be allocated nicely. Such colors will be replaced with
8547 a default color, and we don't have to care about which colors
8548 can be freed safely, and which can't. */
8549 init_color_table ();
8550 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
8551 * sizeof *colors);
8552
8553 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
8554 {
8555 /* Multiply RGB values with 255 because X expects RGB values
8556 in the range 0..0xffff. */
8557 int r = cinfo.colormap[ir][i] << 8;
8558 int g = cinfo.colormap[ig][i] << 8;
8559 int b = cinfo.colormap[ib][i] << 8;
8560 colors[i] = lookup_rgb_color (f, r, g, b);
8561 }
8562
8563 /* Remember those colors actually allocated. */
8564 img->colors = colors_in_color_table (&img->ncolors);
8565 free_color_table ();
8566 }
8567
8568 /* Read pixels. */
8569 row_stride = width * cinfo.output_components;
8570 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
8571 row_stride, 1);
8572 for (y = 0; y < height; ++y)
8573 {
8574 jpeg_read_scanlines (&cinfo, buffer, 1);
8575 for (x = 0; x < cinfo.output_width; ++x)
8576 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
8577 }
8578
8579 /* Clean up. */
8580 jpeg_finish_decompress (&cinfo);
8581 jpeg_destroy_decompress (&cinfo);
8582 fclose (fp);
8583
8584 /* Put the image into the pixmap. */
8585 x_put_x_image (f, ximg, img->pixmap, width, height);
8586 x_destroy_x_image (ximg);
8587 UNBLOCK_INPUT;
8588 UNGCPRO;
8589 return 1;
8590}
8591
8592#endif /* HAVE_JPEG */
8593
8594
8595\f
8596/***********************************************************************
8597 TIFF
8598 ***********************************************************************/
8599
8600#if HAVE_TIFF
8601
cf4790ad 8602#include <tiffio.h>
333b20bb
GM
8603
8604static int tiff_image_p P_ ((Lisp_Object object));
8605static int tiff_load P_ ((struct frame *f, struct image *img));
8606
8607/* The symbol `tiff' identifying images of this type. */
8608
8609Lisp_Object Qtiff;
8610
8611/* Indices of image specification fields in tiff_format, below. */
8612
8613enum tiff_keyword_index
8614{
8615 TIFF_TYPE,
8616 TIFF_FILE,
8617 TIFF_ASCENT,
8618 TIFF_MARGIN,
8619 TIFF_RELIEF,
8620 TIFF_ALGORITHM,
8621 TIFF_HEURISTIC_MASK,
8622 TIFF_LAST
8623};
8624
8625/* Vector of image_keyword structures describing the format
8626 of valid user-defined image specifications. */
8627
8628static struct image_keyword tiff_format[TIFF_LAST] =
8629{
8630 {":type", IMAGE_SYMBOL_VALUE, 1},
8631 {":file", IMAGE_STRING_VALUE, 1},
8632 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8633 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8634 {":relief", IMAGE_INTEGER_VALUE, 0},
8635 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8636 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8637};
8638
8639/* Structure describing the image type `tiff'. */
8640
8641static struct image_type tiff_type =
8642{
8643 &Qtiff,
8644 tiff_image_p,
8645 tiff_load,
8646 x_clear_image,
8647 NULL
8648};
8649
8650
8651/* Return non-zero if OBJECT is a valid TIFF image specification. */
8652
8653static int
8654tiff_image_p (object)
8655 Lisp_Object object;
8656{
8657 struct image_keyword fmt[TIFF_LAST];
8658 bcopy (tiff_format, fmt, sizeof fmt);
8659
8660 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff, 1)
8661 || (fmt[TIFF_ASCENT].count
8662 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
8663 return 0;
8664 return 1;
8665}
8666
8667
8668/* Load TIFF image IMG for use on frame F. Value is non-zero if
8669 successful. */
8670
8671static int
8672tiff_load (f, img)
8673 struct frame *f;
8674 struct image *img;
8675{
8676 Lisp_Object file, specified_file;
8677 TIFF *tiff;
8678 int width, height, x, y;
8679 uint32 *buf;
8680 int rc;
8681 XImage *ximg;
8682 struct gcpro gcpro1;
8683
8684 specified_file = image_spec_value (img->spec, QCfile, NULL);
8685 file = x_find_image_file (specified_file);
8686 GCPRO1 (file);
8687 if (!STRINGP (file))
8688 {
8689 image_error ("Cannot find image file %s", file, Qnil);
8690 UNGCPRO;
8691 return 0;
8692 }
8693
8694 /* Try to open the image file. */
8695 tiff = TIFFOpen (XSTRING (file)->data, "r");
8696 if (tiff == NULL)
8697 {
8698 image_error ("Cannot open `%s'", file, Qnil);
8699 UNGCPRO;
8700 return 0;
8701 }
8702
8703 /* Get width and height of the image, and allocate a raster buffer
8704 of width x height 32-bit values. */
8705 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8706 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8707 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
8708
8709 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8710 TIFFClose (tiff);
8711 if (!rc)
8712 {
8713 image_error ("Error reading `%s'", file, Qnil);
8714 xfree (buf);
8715 UNGCPRO;
8716 return 0;
8717 }
8718
8719 BLOCK_INPUT;
8720
8721 /* Create the X image and pixmap. */
8722 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
8723 &img->pixmap))
8724 {
8725 UNBLOCK_INPUT;
8726 xfree (buf);
8727 UNGCPRO;
8728 return 0;
8729 }
8730
8731 /* Initialize the color table. */
8732 init_color_table ();
8733
8734 /* Process the pixel raster. Origin is in the lower-left corner. */
8735 for (y = 0; y < height; ++y)
8736 {
8737 uint32 *row = buf + y * width;
8738
8739 for (x = 0; x < width; ++x)
8740 {
8741 uint32 abgr = row[x];
8742 int r = TIFFGetR (abgr) << 8;
8743 int g = TIFFGetG (abgr) << 8;
8744 int b = TIFFGetB (abgr) << 8;
8745 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
8746 }
8747 }
8748
8749 /* Remember the colors allocated for the image. Free the color table. */
8750 img->colors = colors_in_color_table (&img->ncolors);
8751 free_color_table ();
8752
8753 /* Put the image into the pixmap, then free the X image and its buffer. */
8754 x_put_x_image (f, ximg, img->pixmap, width, height);
8755 x_destroy_x_image (ximg);
8756 xfree (buf);
8757 UNBLOCK_INPUT;
8758
8759 img->width = width;
8760 img->height = height;
8761
8762 UNGCPRO;
8763 return 1;
8764}
8765
8766#endif /* HAVE_TIFF != 0 */
8767
8768
8769\f
8770/***********************************************************************
8771 GIF
8772 ***********************************************************************/
8773
8774#if HAVE_GIF
8775
8776#include <gif_lib.h>
8777
8778static int gif_image_p P_ ((Lisp_Object object));
8779static int gif_load P_ ((struct frame *f, struct image *img));
8780
8781/* The symbol `gif' identifying images of this type. */
8782
8783Lisp_Object Qgif;
8784
8785/* Indices of image specification fields in gif_format, below. */
8786
8787enum gif_keyword_index
8788{
8789 GIF_TYPE,
8790 GIF_FILE,
8791 GIF_ASCENT,
8792 GIF_MARGIN,
8793 GIF_RELIEF,
8794 GIF_ALGORITHM,
8795 GIF_HEURISTIC_MASK,
8796 GIF_IMAGE,
8797 GIF_LAST
8798};
8799
8800/* Vector of image_keyword structures describing the format
8801 of valid user-defined image specifications. */
8802
8803static struct image_keyword gif_format[GIF_LAST] =
8804{
8805 {":type", IMAGE_SYMBOL_VALUE, 1},
8806 {":file", IMAGE_STRING_VALUE, 1},
8807 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8808 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8809 {":relief", IMAGE_INTEGER_VALUE, 0},
8810 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8811 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8812 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
8813};
8814
8815/* Structure describing the image type `gif'. */
8816
8817static struct image_type gif_type =
8818{
8819 &Qgif,
8820 gif_image_p,
8821 gif_load,
8822 x_clear_image,
8823 NULL
8824};
8825
8826
8827/* Return non-zero if OBJECT is a valid GIF image specification. */
8828
8829static int
8830gif_image_p (object)
8831 Lisp_Object object;
8832{
8833 struct image_keyword fmt[GIF_LAST];
8834 bcopy (gif_format, fmt, sizeof fmt);
8835
8836 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif, 1)
8837 || (fmt[GIF_ASCENT].count
8838 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
8839 return 0;
8840 return 1;
8841}
8842
8843
8844/* Load GIF image IMG for use on frame F. Value is non-zero if
8845 successful. */
8846
8847static int
8848gif_load (f, img)
8849 struct frame *f;
8850 struct image *img;
8851{
8852 Lisp_Object file, specified_file;
8853 int rc, width, height, x, y, i;
8854 XImage *ximg;
8855 ColorMapObject *gif_color_map;
8856 unsigned long pixel_colors[256];
8857 GifFileType *gif;
8858 struct gcpro gcpro1;
8859 Lisp_Object image;
8860 int ino, image_left, image_top, image_width, image_height;
333b20bb
GM
8861
8862 specified_file = image_spec_value (img->spec, QCfile, NULL);
8863 file = x_find_image_file (specified_file);
8864 GCPRO1 (file);
8865 if (!STRINGP (file))
8866 {
8867 image_error ("Cannot find image file %s", specified_file, Qnil);
8868 UNGCPRO;
8869 return 0;
8870 }
8871
8872 /* Open the GIF file. */
8873 gif = DGifOpenFileName (XSTRING (file)->data);
8874 if (gif == NULL)
8875 {
8876 image_error ("Cannot open `%s'", file, Qnil);
8877 UNGCPRO;
8878 return 0;
8879 }
8880
8881 /* Read entire contents. */
8882 rc = DGifSlurp (gif);
8883 if (rc == GIF_ERROR)
8884 {
8885 image_error ("Error reading `%s'", file, Qnil);
8886 DGifCloseFile (gif);
8887 UNGCPRO;
8888 return 0;
8889 }
8890
3ccff1e3 8891 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
8892 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8893 if (ino >= gif->ImageCount)
8894 {
8895 image_error ("Invalid image number `%s'", image, Qnil);
8896 DGifCloseFile (gif);
8897 UNGCPRO;
8898 return 0;
8899 }
8900
8901 width = img->width = gif->SWidth;
8902 height = img->height = gif->SHeight;
8903
8904 BLOCK_INPUT;
8905
8906 /* Create the X image and pixmap. */
8907 if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
8908 &img->pixmap))
8909 {
8910 UNBLOCK_INPUT;
8911 DGifCloseFile (gif);
8912 UNGCPRO;
8913 return 0;
8914 }
8915
8916 /* Allocate colors. */
8917 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
8918 if (!gif_color_map)
8919 gif_color_map = gif->SColorMap;
8920 init_color_table ();
8921 bzero (pixel_colors, sizeof pixel_colors);
8922
8923 for (i = 0; i < gif_color_map->ColorCount; ++i)
8924 {
8925 int r = gif_color_map->Colors[i].Red << 8;
8926 int g = gif_color_map->Colors[i].Green << 8;
8927 int b = gif_color_map->Colors[i].Blue << 8;
8928 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
8929 }
8930
8931 img->colors = colors_in_color_table (&img->ncolors);
8932 free_color_table ();
8933
8934 /* Clear the part of the screen image that are not covered by
8935 the image from the GIF file. Full animated GIF support
8936 requires more than can be done here (see the gif89 spec,
8937 disposal methods). Let's simply assume that the part
8938 not covered by a sub-image is in the frame's background color. */
8939 image_top = gif->SavedImages[ino].ImageDesc.Top;
8940 image_left = gif->SavedImages[ino].ImageDesc.Left;
8941 image_width = gif->SavedImages[ino].ImageDesc.Width;
8942 image_height = gif->SavedImages[ino].ImageDesc.Height;
8943
8944 for (y = 0; y < image_top; ++y)
8945 for (x = 0; x < width; ++x)
8946 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8947
8948 for (y = image_top + image_height; y < height; ++y)
8949 for (x = 0; x < width; ++x)
8950 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8951
8952 for (y = image_top; y < image_top + image_height; ++y)
8953 {
8954 for (x = 0; x < image_left; ++x)
8955 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8956 for (x = image_left + image_width; x < width; ++x)
8957 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8958 }
8959
8960 /* Read the GIF image into the X image. */
8961 if (gif->SavedImages[ino].ImageDesc.Interlace)
8962 {
8963 static int interlace_start[] = {0, 4, 2, 1};
8964 static int interlace_increment[] = {8, 8, 4, 2};
8965 int pass, inc;
06482119
GM
8966 int row = interlace_start[0];
8967
8968 pass = 0;
333b20bb 8969
06482119 8970 for (y = 0; y < image_height; y++)
333b20bb 8971 {
06482119
GM
8972 if (row >= image_height)
8973 {
8974 row = interlace_start[++pass];
8975 while (row >= image_height)
8976 row = interlace_start[++pass];
8977 }
8978
8979 for (x = 0; x < image_width; x++)
8980 {
8981 unsigned int i
8982 = gif->SavedImages[ino].RasterBits[(y * image_width) + x];
8983 XPutPixel (ximg, x + image_left, row + image_top,
8984 pixel_colors[i]);
8985 }
8986
8987 row += interlace_increment[pass];
333b20bb
GM
8988 }
8989 }
8990 else
8991 {
8992 for (y = 0; y < image_height; ++y)
8993 for (x = 0; x < image_width; ++x)
8994 {
8995 unsigned i = gif->SavedImages[ino].RasterBits[y * image_width + x];
8996 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
8997 }
8998 }
8999
9000 DGifCloseFile (gif);
9001
9002 /* Put the image into the pixmap, then free the X image and its buffer. */
9003 x_put_x_image (f, ximg, img->pixmap, width, height);
9004 x_destroy_x_image (ximg);
9005 UNBLOCK_INPUT;
9006
9007 UNGCPRO;
9008 return 1;
9009}
9010
9011#endif /* HAVE_GIF != 0 */
9012
9013
9014\f
9015/***********************************************************************
9016 Ghostscript
9017 ***********************************************************************/
9018
9019static int gs_image_p P_ ((Lisp_Object object));
9020static int gs_load P_ ((struct frame *f, struct image *img));
9021static void gs_clear_image P_ ((struct frame *f, struct image *img));
9022
fcf431dc 9023/* The symbol `postscript' identifying images of this type. */
333b20bb 9024
fcf431dc 9025Lisp_Object Qpostscript;
333b20bb
GM
9026
9027/* Keyword symbols. */
9028
9029Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
9030
9031/* Indices of image specification fields in gs_format, below. */
9032
9033enum gs_keyword_index
9034{
9035 GS_TYPE,
9036 GS_PT_WIDTH,
9037 GS_PT_HEIGHT,
9038 GS_FILE,
9039 GS_LOADER,
9040 GS_BOUNDING_BOX,
9041 GS_ASCENT,
9042 GS_MARGIN,
9043 GS_RELIEF,
9044 GS_ALGORITHM,
9045 GS_HEURISTIC_MASK,
9046 GS_LAST
9047};
9048
9049/* Vector of image_keyword structures describing the format
9050 of valid user-defined image specifications. */
9051
9052static struct image_keyword gs_format[GS_LAST] =
9053{
9054 {":type", IMAGE_SYMBOL_VALUE, 1},
9055 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9056 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9057 {":file", IMAGE_STRING_VALUE, 1},
9058 {":loader", IMAGE_FUNCTION_VALUE, 0},
9059 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
9060 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9061 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9062 {":relief", IMAGE_INTEGER_VALUE, 0},
9063 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9064 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9065};
9066
9067/* Structure describing the image type `ghostscript'. */
9068
9069static struct image_type gs_type =
9070{
fcf431dc 9071 &Qpostscript,
333b20bb
GM
9072 gs_image_p,
9073 gs_load,
9074 gs_clear_image,
9075 NULL
9076};
9077
9078
9079/* Free X resources of Ghostscript image IMG which is used on frame F. */
9080
9081static void
9082gs_clear_image (f, img)
9083 struct frame *f;
9084 struct image *img;
9085{
9086 /* IMG->data.ptr_val may contain a recorded colormap. */
9087 xfree (img->data.ptr_val);
9088 x_clear_image (f, img);
9089}
9090
9091
9092/* Return non-zero if OBJECT is a valid Ghostscript image
9093 specification. */
9094
9095static int
9096gs_image_p (object)
9097 Lisp_Object object;
9098{
9099 struct image_keyword fmt[GS_LAST];
9100 Lisp_Object tem;
9101 int i;
9102
9103 bcopy (gs_format, fmt, sizeof fmt);
9104
fcf431dc 9105 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript, 1)
333b20bb
GM
9106 || (fmt[GS_ASCENT].count
9107 && XFASTINT (fmt[GS_ASCENT].value) > 100))
9108 return 0;
9109
9110 /* Bounding box must be a list or vector containing 4 integers. */
9111 tem = fmt[GS_BOUNDING_BOX].value;
9112 if (CONSP (tem))
9113 {
9114 for (i = 0; i < 4; ++i, tem = XCDR (tem))
9115 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
9116 return 0;
9117 if (!NILP (tem))
9118 return 0;
9119 }
9120 else if (VECTORP (tem))
9121 {
9122 if (XVECTOR (tem)->size != 4)
9123 return 0;
9124 for (i = 0; i < 4; ++i)
9125 if (!INTEGERP (XVECTOR (tem)->contents[i]))
9126 return 0;
9127 }
9128 else
9129 return 0;
9130
9131 return 1;
9132}
9133
9134
9135/* Load Ghostscript image IMG for use on frame F. Value is non-zero
9136 if successful. */
9137
9138static int
9139gs_load (f, img)
9140 struct frame *f;
9141 struct image *img;
9142{
9143 char buffer[100];
9144 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
9145 struct gcpro gcpro1, gcpro2;
9146 Lisp_Object frame;
9147 double in_width, in_height;
9148 Lisp_Object pixel_colors = Qnil;
9149
9150 /* Compute pixel size of pixmap needed from the given size in the
9151 image specification. Sizes in the specification are in pt. 1 pt
9152 = 1/72 in, xdpi and ydpi are stored in the frame's X display
9153 info. */
9154 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
9155 in_width = XFASTINT (pt_width) / 72.0;
9156 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
9157 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
9158 in_height = XFASTINT (pt_height) / 72.0;
9159 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
9160
9161 /* Create the pixmap. */
9162 BLOCK_INPUT;
9163 xassert (img->pixmap == 0);
9164 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9165 img->width, img->height,
9166 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
9167 UNBLOCK_INPUT;
9168
9169 if (!img->pixmap)
9170 {
9171 image_error ("Unable to create pixmap for `%s'",
9172 image_spec_value (img->spec, QCfile, NULL), Qnil);
9173 return 0;
9174 }
9175
9176 /* Call the loader to fill the pixmap. It returns a process object
9177 if successful. We do not record_unwind_protect here because
9178 other places in redisplay like calling window scroll functions
9179 don't either. Let the Lisp loader use `unwind-protect' instead. */
9180 GCPRO2 (window_and_pixmap_id, pixel_colors);
9181
9182 sprintf (buffer, "%lu %lu",
9183 (unsigned long) FRAME_X_WINDOW (f),
9184 (unsigned long) img->pixmap);
9185 window_and_pixmap_id = build_string (buffer);
9186
9187 sprintf (buffer, "%lu %lu",
9188 FRAME_FOREGROUND_PIXEL (f),
9189 FRAME_BACKGROUND_PIXEL (f));
9190 pixel_colors = build_string (buffer);
9191
9192 XSETFRAME (frame, f);
9193 loader = image_spec_value (img->spec, QCloader, NULL);
9194 if (NILP (loader))
9195 loader = intern ("gs-load-image");
9196
9197 img->data.lisp_val = call6 (loader, frame, img->spec,
9198 make_number (img->width),
9199 make_number (img->height),
9200 window_and_pixmap_id,
9201 pixel_colors);
9202 UNGCPRO;
9203 return PROCESSP (img->data.lisp_val);
9204}
9205
9206
9207/* Kill the Ghostscript process that was started to fill PIXMAP on
9208 frame F. Called from XTread_socket when receiving an event
9209 telling Emacs that Ghostscript has finished drawing. */
9210
9211void
9212x_kill_gs_process (pixmap, f)
9213 Pixmap pixmap;
9214 struct frame *f;
9215{
9216 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9217 int class, i;
9218 struct image *img;
9219
9220 /* Find the image containing PIXMAP. */
9221 for (i = 0; i < c->used; ++i)
9222 if (c->images[i]->pixmap == pixmap)
9223 break;
9224
9225 /* Kill the GS process. We should have found PIXMAP in the image
9226 cache and its image should contain a process object. */
9227 xassert (i < c->used);
9228 img = c->images[i];
9229 xassert (PROCESSP (img->data.lisp_val));
9230 Fkill_process (img->data.lisp_val, Qnil);
9231 img->data.lisp_val = Qnil;
9232
9233 /* On displays with a mutable colormap, figure out the colors
9234 allocated for the image by looking at the pixels of an XImage for
9235 img->pixmap. */
9236 class = FRAME_X_DISPLAY_INFO (f)->visual->class;
9237 if (class != StaticColor && class != StaticGray && class != TrueColor)
9238 {
9239 XImage *ximg;
9240
9241 BLOCK_INPUT;
9242
9243 /* Try to get an XImage for img->pixmep. */
9244 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
9245 0, 0, img->width, img->height, ~0, ZPixmap);
9246 if (ximg)
9247 {
9248 int x, y;
9249
9250 /* Initialize the color table. */
9251 init_color_table ();
9252
9253 /* For each pixel of the image, look its color up in the
9254 color table. After having done so, the color table will
9255 contain an entry for each color used by the image. */
9256 for (y = 0; y < img->height; ++y)
9257 for (x = 0; x < img->width; ++x)
9258 {
9259 unsigned long pixel = XGetPixel (ximg, x, y);
9260 lookup_pixel_color (f, pixel);
9261 }
9262
9263 /* Record colors in the image. Free color table and XImage. */
9264 img->colors = colors_in_color_table (&img->ncolors);
9265 free_color_table ();
9266 XDestroyImage (ximg);
9267
9268#if 0 /* This doesn't seem to be the case. If we free the colors
9269 here, we get a BadAccess later in x_clear_image when
9270 freeing the colors. */
9271 /* We have allocated colors once, but Ghostscript has also
9272 allocated colors on behalf of us. So, to get the
9273 reference counts right, free them once. */
9274 if (img->ncolors)
9275 {
9276 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9277 XFreeColors (FRAME_X_DISPLAY (f), cmap,
9278 img->colors, img->ncolors, 0);
9279 }
9280#endif
9281 }
9282 else
9283 image_error ("Cannot get X image of `%s'; colors will not be freed",
9284 image_spec_value (img->spec, QCfile, NULL), Qnil);
9285
9286 UNBLOCK_INPUT;
9287 }
9288}
9289
9290
9291\f
9292/***********************************************************************
9293 Window properties
9294 ***********************************************************************/
9295
9296DEFUN ("x-change-window-property", Fx_change_window_property,
9297 Sx_change_window_property, 2, 3, 0,
9298 "Change window property PROP to VALUE on the X window of FRAME.\n\
9299PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
9300selected frame. Value is VALUE.")
9301 (prop, value, frame)
9302 Lisp_Object frame, prop, value;
9303{
9304 struct frame *f = check_x_frame (frame);
9305 Atom prop_atom;
9306
9307 CHECK_STRING (prop, 1);
9308 CHECK_STRING (value, 2);
9309
9310 BLOCK_INPUT;
9311 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
9312 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9313 prop_atom, XA_STRING, 8, PropModeReplace,
9314 XSTRING (value)->data, XSTRING (value)->size);
9315
9316 /* Make sure the property is set when we return. */
9317 XFlush (FRAME_X_DISPLAY (f));
9318 UNBLOCK_INPUT;
9319
9320 return value;
9321}
9322
9323
9324DEFUN ("x-delete-window-property", Fx_delete_window_property,
9325 Sx_delete_window_property, 1, 2, 0,
9326 "Remove window property PROP from X window of FRAME.\n\
9327FRAME nil or omitted means use the selected frame. Value is PROP.")
9328 (prop, frame)
9329 Lisp_Object prop, frame;
9330{
9331 struct frame *f = check_x_frame (frame);
9332 Atom prop_atom;
9333
9334 CHECK_STRING (prop, 1);
9335 BLOCK_INPUT;
9336 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
9337 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
9338
9339 /* Make sure the property is removed when we return. */
9340 XFlush (FRAME_X_DISPLAY (f));
9341 UNBLOCK_INPUT;
9342
9343 return prop;
9344}
9345
9346
9347DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
9348 1, 2, 0,
9349 "Value is the value of window property PROP on FRAME.\n\
9350If FRAME is nil or omitted, use the selected frame. Value is nil\n\
9351if FRAME hasn't a property with name PROP or if PROP has no string\n\
9352value.")
9353 (prop, frame)
9354 Lisp_Object prop, frame;
9355{
9356 struct frame *f = check_x_frame (frame);
9357 Atom prop_atom;
9358 int rc;
9359 Lisp_Object prop_value = Qnil;
9360 char *tmp_data = NULL;
9361 Atom actual_type;
9362 int actual_format;
9363 unsigned long actual_size, bytes_remaining;
9364
9365 CHECK_STRING (prop, 1);
9366 BLOCK_INPUT;
9367 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
9368 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9369 prop_atom, 0, 0, False, XA_STRING,
9370 &actual_type, &actual_format, &actual_size,
9371 &bytes_remaining, (unsigned char **) &tmp_data);
9372 if (rc == Success)
9373 {
9374 int size = bytes_remaining;
9375
9376 XFree (tmp_data);
9377 tmp_data = NULL;
9378
9379 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9380 prop_atom, 0, bytes_remaining,
9381 False, XA_STRING,
9382 &actual_type, &actual_format,
9383 &actual_size, &bytes_remaining,
9384 (unsigned char **) &tmp_data);
9385 if (rc == Success)
9386 prop_value = make_string (tmp_data, size);
9387
9388 XFree (tmp_data);
9389 }
9390
9391 UNBLOCK_INPUT;
9392 return prop_value;
9393}
9394
9395
9396\f
9397/***********************************************************************
9398 Busy cursor
9399 ***********************************************************************/
9400
9401/* The implementation partly follows a patch from
9402 F.Pierresteguy@frcl.bull.fr dated 1994. */
9403
9404/* Setting inhibit_busy_cursor to 2 inhibits busy-cursor display until
9405 the next X event is read and we enter XTread_socket again. Setting
9406 it to 1 inhibits busy-cursor display for direct commands. */
9407
9408int inhibit_busy_cursor;
9409
9410/* Incremented with each call to x-display-busy-cursor.
9411 Decremented in x-undisplay-busy-cursor. */
9412
9413static int busy_count;
9414
9415
9416DEFUN ("x-show-busy-cursor", Fx_show_busy_cursor,
9417 Sx_show_busy_cursor, 0, 0, 0,
9418 "Show a busy cursor, if not already shown.\n\
9419Each call to this function must be matched by a call to\n\
9420x-undisplay-busy-cursor to make the busy pointer disappear again.")
9421 ()
9422{
9423 ++busy_count;
9424 if (busy_count == 1)
9425 {
9426 Lisp_Object rest, frame;
9427
9428 FOR_EACH_FRAME (rest, frame)
9429 if (FRAME_X_P (XFRAME (frame)))
9430 {
9431 struct frame *f = XFRAME (frame);
9432
9433 BLOCK_INPUT;
9434 f->output_data.x->busy_p = 1;
9435
9436 if (!f->output_data.x->busy_window)
9437 {
9438 unsigned long mask = CWCursor;
9439 XSetWindowAttributes attrs;
9440
9441 attrs.cursor = f->output_data.x->busy_cursor;
9442 f->output_data.x->busy_window
9443 = XCreateWindow (FRAME_X_DISPLAY (f),
9444 FRAME_OUTER_WINDOW (f),
9445 0, 0, 32000, 32000, 0, 0,
9446 InputOnly, CopyFromParent,
9447 mask, &attrs);
9448 }
9449
9450 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
9451 UNBLOCK_INPUT;
9452 }
9453 }
9454
9455 return Qnil;
9456}
9457
9458
9459DEFUN ("x-hide-busy-cursor", Fx_hide_busy_cursor,
9460 Sx_hide_busy_cursor, 0, 1, 0,
9461 "Hide a busy-cursor.\n\
9462A busy-cursor will actually be undisplayed when a matching\n\
9463`x-undisplay-busy-cursor' is called for each `x-display-busy-cursor'\n\
9464issued. FORCE non-nil means undisplay the busy-cursor forcibly,\n\
9465not counting calls.")
9466 (force)
9467 Lisp_Object force;
9468{
9469 Lisp_Object rest, frame;
9470
9471 if (busy_count == 0)
9472 return Qnil;
9473
9474 if (!NILP (force) && busy_count != 0)
9475 busy_count = 1;
9476
9477 --busy_count;
9478 if (busy_count != 0)
9479 return Qnil;
9480
9481 FOR_EACH_FRAME (rest, frame)
9482 {
9483 struct frame *f = XFRAME (frame);
9484
9485 if (FRAME_X_P (f)
9486 /* Watch out for newly created frames. */
9487 && f->output_data.x->busy_window)
9488 {
9489
9490 BLOCK_INPUT;
9491 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
9492 /* Sync here because XTread_socket looks at the busy_p flag
9493 that is reset to zero below. */
9494 XSync (FRAME_X_DISPLAY (f), False);
9495 UNBLOCK_INPUT;
9496 f->output_data.x->busy_p = 0;
9497 }
9498 }
9499
9500 return Qnil;
9501}
9502
9503
9504\f
9505/***********************************************************************
9506 Tool tips
9507 ***********************************************************************/
9508
9509static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
9510 Lisp_Object));
9511
9512/* The frame of a currently visible tooltip, or null. */
9513
9514struct frame *tip_frame;
9515
9516/* If non-nil, a timer started that hides the last tooltip when it
9517 fires. */
9518
9519Lisp_Object tip_timer;
9520Window tip_window;
9521
9522/* Create a frame for a tooltip on the display described by DPYINFO.
9523 PARMS is a list of frame parameters. Value is the frame. */
9524
9525static Lisp_Object
9526x_create_tip_frame (dpyinfo, parms)
9527 struct x_display_info *dpyinfo;
9528 Lisp_Object parms;
9529{
9530 struct frame *f;
9531 Lisp_Object frame, tem;
9532 Lisp_Object name;
333b20bb
GM
9533 long window_prompting = 0;
9534 int width, height;
9535 int count = specpdl_ptr - specpdl;
b6d7acec 9536 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb
GM
9537 struct kboard *kb;
9538
9539 check_x ();
9540
9541 /* Use this general default value to start with until we know if
9542 this frame has a specified name. */
9543 Vx_resource_name = Vinvocation_name;
9544
9545#ifdef MULTI_KBOARD
9546 kb = dpyinfo->kboard;
9547#else
9548 kb = &the_only_kboard;
9549#endif
9550
9551 /* Get the name of the frame to use for resource lookup. */
9552 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
9553 if (!STRINGP (name)
9554 && !EQ (name, Qunbound)
9555 && !NILP (name))
9556 error ("Invalid frame name--not a string or nil");
9557 Vx_resource_name = name;
9558
9559 frame = Qnil;
9560 GCPRO3 (parms, name, frame);
9561 tip_frame = f = make_frame (1);
9562 XSETFRAME (frame, f);
9563 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
9564
9565 f->output_method = output_x_window;
9566 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
9567 bzero (f->output_data.x, sizeof (struct x_output));
9568 f->output_data.x->icon_bitmap = -1;
9569 f->output_data.x->fontset = -1;
9570 f->icon_name = Qnil;
9571 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
9572#ifdef MULTI_KBOARD
9573 FRAME_KBOARD (f) = kb;
9574#endif
9575 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
9576 f->output_data.x->explicit_parent = 0;
9577
9578 /* Set the name; the functions to which we pass f expect the name to
9579 be set. */
9580 if (EQ (name, Qunbound) || NILP (name))
9581 {
9582 f->name = build_string (dpyinfo->x_id_name);
9583 f->explicit_name = 0;
9584 }
9585 else
9586 {
9587 f->name = name;
9588 f->explicit_name = 1;
9589 /* use the frame's title when getting resources for this frame. */
9590 specbind (Qx_resource_name, name);
9591 }
9592
9593 /* Create fontsets from `global_fontset_alist' before handling fonts. */
8e713be6
KR
9594 for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCDR (tem))
9595 fs_register_fontset (f, XCAR (tem));
333b20bb
GM
9596
9597 /* Extract the window parameters from the supplied values
9598 that are needed to determine window geometry. */
9599 {
9600 Lisp_Object font;
9601
9602 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
9603
9604 BLOCK_INPUT;
9605 /* First, try whatever font the caller has specified. */
9606 if (STRINGP (font))
9607 {
9608 tem = Fquery_fontset (font, Qnil);
9609 if (STRINGP (tem))
9610 font = x_new_fontset (f, XSTRING (tem)->data);
9611 else
9612 font = x_new_font (f, XSTRING (font)->data);
9613 }
9614
9615 /* Try out a font which we hope has bold and italic variations. */
9616 if (!STRINGP (font))
9617 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
9618 if (!STRINGP (font))
9619 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9620 if (! STRINGP (font))
9621 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9622 if (! STRINGP (font))
9623 /* This was formerly the first thing tried, but it finds too many fonts
9624 and takes too long. */
9625 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
9626 /* If those didn't work, look for something which will at least work. */
9627 if (! STRINGP (font))
9628 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
9629 UNBLOCK_INPUT;
9630 if (! STRINGP (font))
9631 font = build_string ("fixed");
9632
9633 x_default_parameter (f, parms, Qfont, font,
9634 "font", "Font", RES_TYPE_STRING);
9635 }
9636
9637 x_default_parameter (f, parms, Qborder_width, make_number (2),
9638 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
9639
9640 /* This defaults to 2 in order to match xterm. We recognize either
9641 internalBorderWidth or internalBorder (which is what xterm calls
9642 it). */
9643 if (NILP (Fassq (Qinternal_border_width, parms)))
9644 {
9645 Lisp_Object value;
9646
9647 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
9648 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
9649 if (! EQ (value, Qunbound))
9650 parms = Fcons (Fcons (Qinternal_border_width, value),
9651 parms);
9652 }
9653
9654 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
9655 "internalBorderWidth", "internalBorderWidth",
9656 RES_TYPE_NUMBER);
9657
9658 /* Also do the stuff which must be set before the window exists. */
9659 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
9660 "foreground", "Foreground", RES_TYPE_STRING);
9661 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
9662 "background", "Background", RES_TYPE_STRING);
9663 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
9664 "pointerColor", "Foreground", RES_TYPE_STRING);
9665 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
9666 "cursorColor", "Foreground", RES_TYPE_STRING);
9667 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
9668 "borderColor", "BorderColor", RES_TYPE_STRING);
9669
9670 /* Init faces before x_default_parameter is called for scroll-bar
9671 parameters because that function calls x_set_scroll_bar_width,
9672 which calls change_frame_size, which calls Fset_window_buffer,
9673 which runs hooks, which call Fvertical_motion. At the end, we
9674 end up in init_iterator with a null face cache, which should not
9675 happen. */
9676 init_frame_faces (f);
9677
9678 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
9679 window_prompting = x_figure_window_size (f, parms);
9680
9681 if (window_prompting & XNegative)
9682 {
9683 if (window_prompting & YNegative)
9684 f->output_data.x->win_gravity = SouthEastGravity;
9685 else
9686 f->output_data.x->win_gravity = NorthEastGravity;
9687 }
9688 else
9689 {
9690 if (window_prompting & YNegative)
9691 f->output_data.x->win_gravity = SouthWestGravity;
9692 else
9693 f->output_data.x->win_gravity = NorthWestGravity;
9694 }
9695
9696 f->output_data.x->size_hint_flags = window_prompting;
9697 {
9698 XSetWindowAttributes attrs;
9699 unsigned long mask;
9700
9701 BLOCK_INPUT;
9702 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
9703 /* Window managers looks at the override-redirect flag to
9704 determine whether or net to give windows a decoration (Xlib
9705 3.2.8). */
9706 attrs.override_redirect = True;
9707 attrs.save_under = True;
9708 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
9709 /* Arrange for getting MapNotify and UnmapNotify events. */
9710 attrs.event_mask = StructureNotifyMask;
9711 tip_window
9712 = FRAME_X_WINDOW (f)
9713 = XCreateWindow (FRAME_X_DISPLAY (f),
9714 FRAME_X_DISPLAY_INFO (f)->root_window,
9715 /* x, y, width, height */
9716 0, 0, 1, 1,
9717 /* Border. */
9718 1,
9719 CopyFromParent, InputOutput, CopyFromParent,
9720 mask, &attrs);
9721 UNBLOCK_INPUT;
9722 }
9723
9724 x_make_gc (f);
9725
333b20bb
GM
9726 x_default_parameter (f, parms, Qauto_raise, Qnil,
9727 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9728 x_default_parameter (f, parms, Qauto_lower, Qnil,
9729 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9730 x_default_parameter (f, parms, Qcursor_type, Qbox,
9731 "cursorType", "CursorType", RES_TYPE_SYMBOL);
9732
9733 /* Dimensions, especially f->height, must be done via change_frame_size.
9734 Change will not be effected unless different from the current
9735 f->height. */
9736 width = f->width;
9737 height = f->height;
9738 f->height = 0;
9739 SET_FRAME_WIDTH (f, 0);
8938a4fb 9740 change_frame_size (f, height, width, 1, 0, 0);
333b20bb
GM
9741
9742 f->no_split = 1;
9743
9744 UNGCPRO;
9745
9746 /* It is now ok to make the frame official even if we get an error
9747 below. And the frame needs to be on Vframe_list or making it
9748 visible won't work. */
9749 Vframe_list = Fcons (frame, Vframe_list);
9750
9751 /* Now that the frame is official, it counts as a reference to
9752 its display. */
9753 FRAME_X_DISPLAY_INFO (f)->reference_count++;
9754
9755 return unbind_to (count, frame);
9756}
9757
9758
9759DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
e82d09c9
GM
9760 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
9761A tooltip window is a small X window displaying STRING at\n\
9762the current mouse position.\n\
333b20bb
GM
9763FRAME nil or omitted means use the selected frame.\n\
9764PARMS is an optional list of frame parameters which can be\n\
9765used to change the tooltip's appearance.\n\
9766Automatically hide the tooltip after TIMEOUT seconds.\n\
9767TIMEOUT nil means use the default timeout of 5 seconds.")
9768 (string, frame, parms, timeout)
68c45bf0 9769 Lisp_Object string, frame, parms, timeout;
333b20bb
GM
9770{
9771 struct frame *f;
9772 struct window *w;
9773 Window root, child;
333b20bb
GM
9774 Lisp_Object buffer;
9775 struct buffer *old_buffer;
9776 struct text_pos pos;
9777 int i, width, height;
9778 int root_x, root_y, win_x, win_y;
9779 unsigned pmask;
9780 struct gcpro gcpro1, gcpro2, gcpro3;
9781 int old_windows_or_buffers_changed = windows_or_buffers_changed;
9782 int count = specpdl_ptr - specpdl;
9783
9784 specbind (Qinhibit_redisplay, Qt);
9785
9786 GCPRO3 (string, parms, frame);
9787
9788 CHECK_STRING (string, 0);
9789 f = check_x_frame (frame);
9790 if (NILP (timeout))
9791 timeout = make_number (5);
9792 else
9793 CHECK_NATNUM (timeout, 2);
9794
9795 /* Hide a previous tip, if any. */
9796 Fx_hide_tip ();
9797
9798 /* Add default values to frame parameters. */
9799 if (NILP (Fassq (Qname, parms)))
9800 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
9801 if (NILP (Fassq (Qinternal_border_width, parms)))
9802 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
9803 if (NILP (Fassq (Qborder_width, parms)))
9804 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
9805 if (NILP (Fassq (Qborder_color, parms)))
9806 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
9807 if (NILP (Fassq (Qbackground_color, parms)))
9808 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
9809 parms);
9810
9811 /* Create a frame for the tooltip, and record it in the global
9812 variable tip_frame. */
9813 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms);
9814 tip_frame = f = XFRAME (frame);
9815
9816 /* Set up the frame's root window. Currently we use a size of 80
9817 columns x 40 lines. If someone wants to show a larger tip, he
9818 will loose. I don't think this is a realistic case. */
9819 w = XWINDOW (FRAME_ROOT_WINDOW (f));
9820 w->left = w->top = make_number (0);
9821 w->width = 80;
9822 w->height = 40;
9823 adjust_glyphs (f);
9824 w->pseudo_window_p = 1;
9825
9826 /* Display the tooltip text in a temporary buffer. */
9827 buffer = Fget_buffer_create (build_string (" *tip*"));
9828 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
9829 old_buffer = current_buffer;
9830 set_buffer_internal_1 (XBUFFER (buffer));
9831 Ferase_buffer ();
9832 Finsert (make_number (1), &string);
9833 clear_glyph_matrix (w->desired_matrix);
9834 clear_glyph_matrix (w->current_matrix);
9835 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
9836 try_window (FRAME_ROOT_WINDOW (f), pos);
9837
9838 /* Compute width and height of the tooltip. */
9839 width = height = 0;
9840 for (i = 0; i < w->desired_matrix->nrows; ++i)
9841 {
9842 struct glyph_row *row = &w->desired_matrix->rows[i];
9843 struct glyph *last;
9844 int row_width;
9845
9846 /* Stop at the first empty row at the end. */
9847 if (!row->enabled_p || !row->displays_text_p)
9848 break;
9849
d7bf0342
GM
9850 /* Let the row go over the full width of the frame. */
9851 row->full_width_p = 1;
333b20bb
GM
9852
9853 /* There's a glyph at the end of rows that is use to place
9854 the cursor there. Don't include the width of this glyph. */
9855 if (row->used[TEXT_AREA])
9856 {
9857 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
9858 row_width = row->pixel_width - last->pixel_width;
9859 }
9860 else
9861 row_width = row->pixel_width;
9862
9863 height += row->height;
9864 width = max (width, row_width);
9865 }
9866
9867 /* Add the frame's internal border to the width and height the X
9868 window should have. */
9869 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9870 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9871
9872 /* Move the tooltip window where the mouse pointer is. Resize and
9873 show it. */
9874 BLOCK_INPUT;
9875 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
9876 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
9877 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9878 root_x + 5, root_y - height - 5, width, height);
9879 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
9880 UNBLOCK_INPUT;
9881
9882 /* Draw into the window. */
9883 w->must_be_updated_p = 1;
9884 update_single_window (w, 1);
9885
9886 /* Restore original current buffer. */
9887 set_buffer_internal_1 (old_buffer);
9888 windows_or_buffers_changed = old_windows_or_buffers_changed;
9889
9890 /* Let the tip disappear after timeout seconds. */
9891 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
9892 intern ("x-hide-tip"));
9893
9894 return unbind_to (count, Qnil);
9895}
9896
9897
9898DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
e82d09c9 9899 "Hide the current tooltip window, if there is any.\n\
333b20bb
GM
9900Value is t is tooltip was open, nil otherwise.")
9901 ()
9902{
9903 int count = specpdl_ptr - specpdl;
9904 int deleted_p = 0;
9905
9906 specbind (Qinhibit_redisplay, Qt);
9907
9908 if (!NILP (tip_timer))
9909 {
9910 call1 (intern ("cancel-timer"), tip_timer);
9911 tip_timer = Qnil;
9912 }
9913
9914 if (tip_frame)
9915 {
9916 Lisp_Object frame;
9917
9918 XSETFRAME (frame, tip_frame);
9919 Fdelete_frame (frame, Qt);
9920 tip_frame = NULL;
9921 deleted_p = 1;
9922 }
9923
9924 return unbind_to (count, deleted_p ? Qt : Qnil);
9925}
9926
9927
9928\f
9929/***********************************************************************
9930 File selection dialog
9931 ***********************************************************************/
9932
9933#ifdef USE_MOTIF
9934
9935/* Callback for "OK" and "Cancel" on file selection dialog. */
9936
9937static void
9938file_dialog_cb (widget, client_data, call_data)
9939 Widget widget;
9940 XtPointer call_data, client_data;
9941{
9942 int *result = (int *) client_data;
9943 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
9944 *result = cb->reason;
9945}
9946
9947
9948DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
9949 "Read file name, prompting with PROMPT in directory DIR.\n\
9950Use a file selection dialog.\n\
9951Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
9952specified. Don't let the user enter a file name in the file\n\
9953selection dialog's entry field, if MUSTMATCH is non-nil.")
9954 (prompt, dir, default_filename, mustmatch)
9955 Lisp_Object prompt, dir, default_filename, mustmatch;
9956{
9957 int result;
0fe92f72 9958 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
9959 Lisp_Object file = Qnil;
9960 Widget dialog, text, list, help;
9961 Arg al[10];
9962 int ac = 0;
9963 extern XtAppContext Xt_app_con;
9964 char *title;
9965 XmString dir_xmstring, pattern_xmstring;
9966 int popup_activated_flag;
9967 int count = specpdl_ptr - specpdl;
9968 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
9969
9970 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
9971 CHECK_STRING (prompt, 0);
9972 CHECK_STRING (dir, 1);
9973
9974 /* Prevent redisplay. */
9975 specbind (Qinhibit_redisplay, Qt);
9976
9977 BLOCK_INPUT;
9978
9979 /* Create the dialog with PROMPT as title, using DIR as initial
9980 directory and using "*" as pattern. */
9981 dir = Fexpand_file_name (dir, Qnil);
9982 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
9983 pattern_xmstring = XmStringCreateLocalized ("*");
9984
9985 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
9986 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
9987 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
9988 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
9989 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
9990 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
9991 "fsb", al, ac);
9992 XmStringFree (dir_xmstring);
9993 XmStringFree (pattern_xmstring);
9994
9995 /* Add callbacks for OK and Cancel. */
9996 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
9997 (XtPointer) &result);
9998 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
9999 (XtPointer) &result);
10000
10001 /* Disable the help button since we can't display help. */
10002 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
10003 XtSetSensitive (help, False);
10004
10005 /* Mark OK button as default. */
10006 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
10007 XmNshowAsDefault, True, NULL);
10008
10009 /* If MUSTMATCH is non-nil, disable the file entry field of the
10010 dialog, so that the user must select a file from the files list
10011 box. We can't remove it because we wouldn't have a way to get at
10012 the result file name, then. */
10013 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
10014 if (!NILP (mustmatch))
10015 {
10016 Widget label;
10017 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
10018 XtSetSensitive (text, False);
10019 XtSetSensitive (label, False);
10020 }
10021
10022 /* Manage the dialog, so that list boxes get filled. */
10023 XtManageChild (dialog);
10024
10025 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
10026 must include the path for this to work. */
10027 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
10028 if (STRINGP (default_filename))
10029 {
10030 XmString default_xmstring;
10031 int item_pos;
10032
10033 default_xmstring
10034 = XmStringCreateLocalized (XSTRING (default_filename)->data);
10035
10036 if (!XmListItemExists (list, default_xmstring))
10037 {
10038 /* Add a new item if DEFAULT_FILENAME is not in the list. */
10039 XmListAddItem (list, default_xmstring, 0);
10040 item_pos = 0;
10041 }
10042 else
10043 item_pos = XmListItemPos (list, default_xmstring);
10044 XmStringFree (default_xmstring);
10045
10046 /* Select the item and scroll it into view. */
10047 XmListSelectPos (list, item_pos, True);
10048 XmListSetPos (list, item_pos);
10049 }
10050
10051 /* Process all events until the user presses Cancel or OK. */
10052 for (result = 0; result == 0;)
10053 {
10054 XEvent event;
10055 Widget widget, parent;
10056
10057 XtAppNextEvent (Xt_app_con, &event);
10058
10059 /* See if the receiver of the event is one of the widgets of
10060 the file selection dialog. If so, dispatch it. If not,
10061 discard it. */
10062 widget = XtWindowToWidget (event.xany.display, event.xany.window);
10063 parent = widget;
10064 while (parent && parent != dialog)
10065 parent = XtParent (parent);
10066
10067 if (parent == dialog
10068 || (event.type == Expose
10069 && !process_expose_from_menu (event)))
10070 XtDispatchEvent (&event);
10071 }
10072
10073 /* Get the result. */
10074 if (result == XmCR_OK)
10075 {
10076 XmString text;
10077 String data;
10078
10079 XtVaGetValues (dialog, XmNtextString, &text, 0);
10080 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
10081 XmStringFree (text);
10082 file = build_string (data);
10083 XtFree (data);
10084 }
10085 else
10086 file = Qnil;
10087
10088 /* Clean up. */
10089 XtUnmanageChild (dialog);
10090 XtDestroyWidget (dialog);
10091 UNBLOCK_INPUT;
10092 UNGCPRO;
10093
10094 /* Make "Cancel" equivalent to C-g. */
10095 if (NILP (file))
10096 Fsignal (Qquit, Qnil);
10097
10098 return unbind_to (count, file);
10099}
10100
10101#endif /* USE_MOTIF */
10102
10103\f
10104/***********************************************************************
10105 Tests
10106 ***********************************************************************/
10107
10108#if GLYPH_DEBUG
10109
10110DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
10111 "Value is non-nil if SPEC is a valid image specification.")
10112 (spec)
10113 Lisp_Object spec;
10114{
10115 return valid_image_p (spec) ? Qt : Qnil;
10116}
10117
10118
10119DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
10120 (spec)
10121 Lisp_Object spec;
10122{
10123 int id = -1;
10124
10125 if (valid_image_p (spec))
0fe92f72 10126 id = lookup_image (SELECTED_FRAME (), spec);
333b20bb
GM
10127
10128 debug_print (spec);
10129 return make_number (id);
10130}
10131
10132#endif /* GLYPH_DEBUG != 0 */
10133
10134
10135\f
10136/***********************************************************************
10137 Initialization
10138 ***********************************************************************/
10139
10140void
10141syms_of_xfns ()
10142{
10143 /* This is zero if not using X windows. */
10144 x_in_use = 0;
10145
10146 /* The section below is built by the lisp expression at the top of the file,
10147 just above where these variables are declared. */
10148 /*&&& init symbols here &&&*/
10149 Qauto_raise = intern ("auto-raise");
10150 staticpro (&Qauto_raise);
10151 Qauto_lower = intern ("auto-lower");
10152 staticpro (&Qauto_lower);
10153 Qbar = intern ("bar");
dbc4e1c1 10154 staticpro (&Qbar);
f9942c9e
JB
10155 Qborder_color = intern ("border-color");
10156 staticpro (&Qborder_color);
10157 Qborder_width = intern ("border-width");
10158 staticpro (&Qborder_width);
dbc4e1c1
JB
10159 Qbox = intern ("box");
10160 staticpro (&Qbox);
f9942c9e
JB
10161 Qcursor_color = intern ("cursor-color");
10162 staticpro (&Qcursor_color);
dbc4e1c1
JB
10163 Qcursor_type = intern ("cursor-type");
10164 staticpro (&Qcursor_type);
f9942c9e
JB
10165 Qgeometry = intern ("geometry");
10166 staticpro (&Qgeometry);
f9942c9e
JB
10167 Qicon_left = intern ("icon-left");
10168 staticpro (&Qicon_left);
10169 Qicon_top = intern ("icon-top");
10170 staticpro (&Qicon_top);
10171 Qicon_type = intern ("icon-type");
10172 staticpro (&Qicon_type);
80534dd6
KH
10173 Qicon_name = intern ("icon-name");
10174 staticpro (&Qicon_name);
f9942c9e
JB
10175 Qinternal_border_width = intern ("internal-border-width");
10176 staticpro (&Qinternal_border_width);
10177 Qleft = intern ("left");
10178 staticpro (&Qleft);
1ab3d87e
RS
10179 Qright = intern ("right");
10180 staticpro (&Qright);
f9942c9e
JB
10181 Qmouse_color = intern ("mouse-color");
10182 staticpro (&Qmouse_color);
baaed68e
JB
10183 Qnone = intern ("none");
10184 staticpro (&Qnone);
f9942c9e
JB
10185 Qparent_id = intern ("parent-id");
10186 staticpro (&Qparent_id);
4701395c
KH
10187 Qscroll_bar_width = intern ("scroll-bar-width");
10188 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
10189 Qsuppress_icon = intern ("suppress-icon");
10190 staticpro (&Qsuppress_icon);
01f1ba30 10191 Qundefined_color = intern ("undefined-color");
f9942c9e 10192 staticpro (&Qundefined_color);
a3c87d4e
JB
10193 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
10194 staticpro (&Qvertical_scroll_bars);
49795535
JB
10195 Qvisibility = intern ("visibility");
10196 staticpro (&Qvisibility);
f9942c9e
JB
10197 Qwindow_id = intern ("window-id");
10198 staticpro (&Qwindow_id);
2cbebefb
RS
10199 Qouter_window_id = intern ("outer-window-id");
10200 staticpro (&Qouter_window_id);
f9942c9e
JB
10201 Qx_frame_parameter = intern ("x-frame-parameter");
10202 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
10203 Qx_resource_name = intern ("x-resource-name");
10204 staticpro (&Qx_resource_name);
4fe1de12
RS
10205 Quser_position = intern ("user-position");
10206 staticpro (&Quser_position);
10207 Quser_size = intern ("user-size");
10208 staticpro (&Quser_size);
b9dc4443
RS
10209 Qdisplay = intern ("display");
10210 staticpro (&Qdisplay);
333b20bb
GM
10211 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
10212 staticpro (&Qscroll_bar_foreground);
10213 Qscroll_bar_background = intern ("scroll-bar-background");
10214 staticpro (&Qscroll_bar_background);
d62c8769
GM
10215 Qscreen_gamma = intern ("screen-gamma");
10216 staticpro (&Qscreen_gamma);
f9942c9e
JB
10217 /* This is the end of symbol initialization. */
10218
333b20bb
GM
10219 Qlaplace = intern ("laplace");
10220 staticpro (&Qlaplace);
10221
a367641f
RS
10222 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
10223 staticpro (&Qface_set_after_frame_default);
10224
01f1ba30
JB
10225 Fput (Qundefined_color, Qerror_conditions,
10226 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
10227 Fput (Qundefined_color, Qerror_message,
10228 build_string ("Undefined color"));
10229
f9942c9e
JB
10230 init_x_parm_symbols ();
10231
f1c7b5a6
RS
10232 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
10233 "List of directories to search for bitmap files for X.");
e241c09b 10234 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 10235
16ae08a9 10236 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
d387c960 10237 "The shape of the pointer when over text.\n\
af01ef26
RS
10238Changing the value does not affect existing frames\n\
10239unless you set the mouse color.");
01f1ba30
JB
10240 Vx_pointer_shape = Qnil;
10241
d387c960 10242 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
498e9ac3 10243 "The name Emacs uses to look up X resources.\n\
d387c960
JB
10244`x-get-resource' uses this as the first component of the instance name\n\
10245when requesting resource values.\n\
10246Emacs initially sets `x-resource-name' to the name under which Emacs\n\
10247was invoked, or to the value specified with the `-name' or `-rn'\n\
498e9ac3
RS
10248switches, if present.\n\
10249\n\
10250It may be useful to bind this variable locally around a call\n\
10251to `x-get-resource'. See also the variable `x-resource-class'.");
d387c960 10252 Vx_resource_name = Qnil;
ac63d3d6 10253
498e9ac3
RS
10254 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
10255 "The class Emacs uses to look up X resources.\n\
10256`x-get-resource' uses this as the first component of the instance class\n\
10257when requesting resource values.\n\
10258Emacs initially sets `x-resource-class' to \"Emacs\".\n\
10259\n\
10260Setting this variable permanently is not a reasonable thing to do,\n\
10261but binding this variable locally around a call to `x-get-resource'\n\
333b20bb 10262is a reasonable practice. See also the variable `x-resource-name'.");
498e9ac3
RS
10263 Vx_resource_class = build_string (EMACS_CLASS);
10264
ca0ecbf5 10265#if 0 /* This doesn't really do anything. */
d3b06468 10266 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
ca0ecbf5
RS
10267 "The shape of the pointer when not over text.\n\
10268This variable takes effect when you create a new frame\n\
10269or when you set the mouse color.");
af01ef26 10270#endif
01f1ba30
JB
10271 Vx_nontext_pointer_shape = Qnil;
10272
333b20bb
GM
10273 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
10274 "The shape of the pointer when Emacs is busy.\n\
10275This variable takes effect when you create a new frame\n\
10276or when you set the mouse color.");
10277 Vx_busy_pointer_shape = Qnil;
10278
10279 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
10280 "Non-zero means Emacs displays a busy cursor on window systems.");
10281 display_busy_cursor_p = 1;
10282
ca0ecbf5 10283#if 0 /* This doesn't really do anything. */
d3b06468 10284 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
ca0ecbf5
RS
10285 "The shape of the pointer when over the mode line.\n\
10286This variable takes effect when you create a new frame\n\
10287or when you set the mouse color.");
af01ef26 10288#endif
01f1ba30
JB
10289 Vx_mode_pointer_shape = Qnil;
10290
d3b06468 10291 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ca0ecbf5
RS
10292 &Vx_sensitive_text_pointer_shape,
10293 "The shape of the pointer when over mouse-sensitive text.\n\
10294This variable takes effect when you create a new frame\n\
10295or when you set the mouse color.");
10296 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 10297
01f1ba30
JB
10298 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
10299 "A string indicating the foreground color of the cursor box.");
10300 Vx_cursor_fore_pixel = Qnil;
10301
01f1ba30 10302 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
2d38195d
RS
10303 "Non-nil if no X window manager is in use.\n\
10304Emacs doesn't try to figure this out; this is always nil\n\
10305unless you set it to something else.");
10306 /* We don't have any way to find this out, so set it to nil
10307 and maybe the user would like to set it to t. */
10308 Vx_no_window_manager = Qnil;
1d3dac41 10309
942ea06d
KH
10310 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
10311 &Vx_pixel_size_width_font_regexp,
10312 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
10313\n\
dcc13cda 10314Since Emacs gets width of a font matching with this regexp from\n\
942ea06d
KH
10315PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
10316such a font. This is especially effective for such large fonts as\n\
10317Chinese, Japanese, and Korean.");
10318 Vx_pixel_size_width_font_regexp = Qnil;
10319
fcf431dc 10320 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
333b20bb
GM
10321 "Time after which cached images are removed from the cache.\n\
10322When an image has not been displayed this many seconds, remove it\n\
10323from the image cache. Value must be an integer or nil with nil\n\
10324meaning don't clear the cache.");
fcf431dc 10325 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb
GM
10326
10327 DEFVAR_LISP ("image-types", &Vimage_types,
10328 "List of supported image types.\n\
10329Each element of the list is a symbol for a supported image type.");
10330 Vimage_types = Qnil;
10331
1d3dac41 10332#ifdef USE_X_TOOLKIT
f1d238ef 10333 Fprovide (intern ("x-toolkit"));
1d3dac41 10334#endif
5b827abb
KH
10335#ifdef USE_MOTIF
10336 Fprovide (intern ("motif"));
10337#endif
01f1ba30 10338
01f1ba30 10339 defsubr (&Sx_get_resource);
333b20bb
GM
10340
10341 /* X window properties. */
10342 defsubr (&Sx_change_window_property);
10343 defsubr (&Sx_delete_window_property);
10344 defsubr (&Sx_window_property);
10345
85ffea93 10346#if 0
01f1ba30
JB
10347 defsubr (&Sx_draw_rectangle);
10348 defsubr (&Sx_erase_rectangle);
10349 defsubr (&Sx_contour_region);
10350 defsubr (&Sx_uncontour_region);
85ffea93 10351#endif
d0c9d219
RS
10352 defsubr (&Sx_display_color_p);
10353 defsubr (&Sx_display_grayscale_p);
8af1d7ca 10354 defsubr (&Sx_color_defined_p);
e12d55b2 10355 defsubr (&Sx_color_values);
9d317b2c 10356 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
10357 defsubr (&Sx_server_vendor);
10358 defsubr (&Sx_server_version);
10359 defsubr (&Sx_display_pixel_width);
10360 defsubr (&Sx_display_pixel_height);
10361 defsubr (&Sx_display_mm_width);
10362 defsubr (&Sx_display_mm_height);
10363 defsubr (&Sx_display_screens);
10364 defsubr (&Sx_display_planes);
10365 defsubr (&Sx_display_color_cells);
10366 defsubr (&Sx_display_visual_class);
10367 defsubr (&Sx_display_backing_store);
10368 defsubr (&Sx_display_save_under);
01567351 10369#if 0
9d04a87a
RS
10370 defsubr (&Sx_rebind_key);
10371 defsubr (&Sx_rebind_keys);
01f1ba30 10372 defsubr (&Sx_track_pointer);
01f1ba30
JB
10373 defsubr (&Sx_grab_pointer);
10374 defsubr (&Sx_ungrab_pointer);
01f1ba30 10375#endif
8af1d7ca 10376 defsubr (&Sx_parse_geometry);
f676886a 10377 defsubr (&Sx_create_frame);
06ef7355 10378#if 0
01f1ba30 10379 defsubr (&Sx_horizontal_line);
06ef7355 10380#endif
01f1ba30 10381 defsubr (&Sx_open_connection);
08a90d6a
RS
10382 defsubr (&Sx_close_connection);
10383 defsubr (&Sx_display_list);
01f1ba30 10384 defsubr (&Sx_synchronize);
942ea06d
KH
10385
10386 /* Setting callback functions for fontset handler. */
10387 get_font_info_func = x_get_font_info;
333b20bb
GM
10388
10389#if 0 /* This function pointer doesn't seem to be used anywhere.
10390 And the pointer assigned has the wrong type, anyway. */
942ea06d 10391 list_fonts_func = x_list_fonts;
333b20bb
GM
10392#endif
10393
942ea06d 10394 load_font_func = x_load_font;
bc1958c4 10395 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
10396 query_font_func = x_query_font;
10397 set_frame_fontset_func = x_set_font;
10398 check_window_system_func = check_x;
333b20bb
GM
10399
10400 /* Images. */
10401 Qxbm = intern ("xbm");
10402 staticpro (&Qxbm);
10403 QCtype = intern (":type");
10404 staticpro (&QCtype);
333b20bb
GM
10405 QCalgorithm = intern (":algorithm");
10406 staticpro (&QCalgorithm);
10407 QCheuristic_mask = intern (":heuristic-mask");
10408 staticpro (&QCheuristic_mask);
10409 QCcolor_symbols = intern (":color-symbols");
10410 staticpro (&QCcolor_symbols);
10411 QCdata = intern (":data");
10412 staticpro (&QCdata);
10413 QCascent = intern (":ascent");
10414 staticpro (&QCascent);
10415 QCmargin = intern (":margin");
10416 staticpro (&QCmargin);
10417 QCrelief = intern (":relief");
10418 staticpro (&QCrelief);
fcf431dc
GM
10419 Qpostscript = intern ("postscript");
10420 staticpro (&Qpostscript);
333b20bb
GM
10421 QCloader = intern (":loader");
10422 staticpro (&QCloader);
10423 QCbounding_box = intern (":bounding-box");
10424 staticpro (&QCbounding_box);
10425 QCpt_width = intern (":pt-width");
10426 staticpro (&QCpt_width);
10427 QCpt_height = intern (":pt-height");
10428 staticpro (&QCpt_height);
3ccff1e3
GM
10429 QCindex = intern (":index");
10430 staticpro (&QCindex);
9fb5e03d
GM
10431 QCuser_data = intern (":user-data");
10432 staticpro (&QCuser_data);
333b20bb
GM
10433 Qpbm = intern ("pbm");
10434 staticpro (&Qpbm);
10435
10436#if HAVE_XPM
10437 Qxpm = intern ("xpm");
10438 staticpro (&Qxpm);
10439#endif
10440
10441#if HAVE_JPEG
10442 Qjpeg = intern ("jpeg");
10443 staticpro (&Qjpeg);
10444#endif
10445
10446#if HAVE_TIFF
10447 Qtiff = intern ("tiff");
10448 staticpro (&Qtiff);
10449#endif
10450
10451#if HAVE_GIF
10452 Qgif = intern ("gif");
10453 staticpro (&Qgif);
10454#endif
10455
10456#if HAVE_PNG
10457 Qpng = intern ("png");
10458 staticpro (&Qpng);
10459#endif
10460
10461 defsubr (&Sclear_image_cache);
10462
10463#if GLYPH_DEBUG
10464 defsubr (&Simagep);
10465 defsubr (&Slookup_image);
10466#endif
10467
10468 /* Busy-cursor. */
10469 defsubr (&Sx_show_busy_cursor);
10470 defsubr (&Sx_hide_busy_cursor);
10471 busy_count = 0;
10472 inhibit_busy_cursor = 0;
10473
10474 defsubr (&Sx_show_tip);
10475 defsubr (&Sx_hide_tip);
10476 staticpro (&tip_timer);
10477 tip_timer = Qnil;
10478
10479#ifdef USE_MOTIF
10480 defsubr (&Sx_file_dialog);
10481#endif
10482}
10483
10484
10485void
10486init_xfns ()
10487{
10488 image_types = NULL;
10489 Vimage_types = Qnil;
10490
10491 define_image_type (&xbm_type);
10492 define_image_type (&gs_type);
10493 define_image_type (&pbm_type);
10494
10495#if HAVE_XPM
10496 define_image_type (&xpm_type);
10497#endif
10498
10499#if HAVE_JPEG
10500 define_image_type (&jpeg_type);
10501#endif
10502
10503#if HAVE_TIFF
10504 define_image_type (&tiff_type);
10505#endif
10506
10507#if HAVE_GIF
10508 define_image_type (&gif_type);
10509#endif
10510
10511#if HAVE_PNG
10512 define_image_type (&png_type);
10513#endif
01f1ba30
JB
10514}
10515
10516#endif /* HAVE_X_WINDOWS */