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